diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffer/video.c | 24 | ||||
| -rw-r--r-- | src/codec/ffmpeg/common.c | 21 | ||||
| -rw-r--r-- | src/codec/ffmpeg/common.h | 7 | ||||
| -rw-r--r-- | src/render/queue_libplacebo.c | 2 | ||||
| -rw-r--r-- | src/render/renderer_libplacebo.c | 2 | ||||
| -rw-r--r-- | src/screen/screen.c | 12 | ||||
| -rw-r--r-- | src/screen/view.c | 4 | ||||
| -rw-r--r-- | src/screen/view.h | 20 |
8 files changed, 77 insertions, 15 deletions
diff --git a/src/buffer/video.c b/src/buffer/video.c index 0e9795f..f7d5e98 100644 --- a/src/buffer/video.c +++ b/src/buffer/video.c @@ -44,9 +44,22 @@ bool camu_video_buffer_init(struct camu_video_buffer *buf, struct camu_clock *cl atomic_store(bool)(&buf->ref, false, AL_ATOMIC_RELAXED); #endif buf->view.mode = CAMU_VIEW_NONE; + // Rotation can be informed by the codec, we need to pass that information along. + buf->view.rotation = CAMU_VIEW_ROTATION_0; return true; } +#ifdef CAMU_HAVE_FFMPEG +static inline u8 rotation_from_displaymatrix(const s32 *matrix) +{ + f64 rotation = av_display_rotation_get(matrix); + if (!isnan(rotation) && rotation != 0.0) { + return camu_view_normalize_rotation((s32)(4.5 - rotation / 90.0)); + } + return CAMU_VIEW_ROTATION_0; +} +#endif + bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_codec_stream *stream, struct camu_renderer *renderer) { @@ -75,6 +88,11 @@ bool camu_video_buffer_configure(struct camu_video_buffer *buf, struct camu_code buf->weighted_first_read = true; log_info("Stream: %s (%ux%u) VIDEO %.3ffps.", format_name, fmt->width, fmt->height, av_q2d(frame_rate)); } + // https://code.videolan.org/videolan/libplacebo/-/blob/a7a18af88ff0a17c04840dcb3246047bb6b46df3/src/include/libplacebo/utils/libav_internal.h#L870 + const u8 *side_data = camu_ff_get_stream_side_data(stream->av.stream, AV_PKT_DATA_DISPLAYMATRIX); + if (side_data) { + buf->view.rotation = rotation_from_displaymatrix((const s32 *)side_data); + } break; } #endif @@ -132,12 +150,16 @@ static bool push_av_frame_internal(struct camu_video_buffer *buf, AVFrame *frame AVStream *stream = buf->stream->av.stream; f64 pts = frame->best_effort_timestamp * av_q2d(stream->time_base); f64 base_pts = atomic_load(f64)(&buf->pts, AL_ATOMIC_ACQUIRE); - f64 duration = camu_ff_frame_duration(frame) * av_q2d(stream->time_base); + f64 duration = camu_ff_get_frame_duration(frame) * av_q2d(stream->time_base); if (!buf->is_static && frame_is_late(buf->clock, base_pts, pts, duration)) { log_trace("Discarding late frame with PTS %f.", pts); return false; } if (base_pts == -1.0) atomic_store(f64)(&buf->pts, pts, AL_ATOMIC_RELEASE); + const u8 *side_data = camu_ff_get_frame_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); + if (side_data) { + buf->view.rotation = rotation_from_displaymatrix((const s32 *)side_data); + } if (buf->fmt.scaler_needed) { if (!buf->scaler->scale(buf->scaler, (const u8 **)frame->data, frame->linesize)) { return false; diff --git a/src/codec/ffmpeg/common.c b/src/codec/ffmpeg/common.c index 59f59b7..5e10bcb 100644 --- a/src/codec/ffmpeg/common.c +++ b/src/codec/ffmpeg/common.c @@ -7,7 +7,7 @@ #include "common.h" -s64 camu_ff_frame_duration(AVFrame *frame) +s64 camu_ff_get_frame_duration(AVFrame *frame) { #if LIBAVUTIL_VERSION_INT >= AV_VERSION_INT(57, 30, 100) return frame->duration; @@ -16,6 +16,25 @@ s64 camu_ff_frame_duration(AVFrame *frame) #endif } +// https://code.videolan.org/videolan/libplacebo/-/blob/a7a18af88ff0a17c04840dcb3246047bb6b46df3/src/include/libplacebo/utils/libav_internal.h#L854 +const u8 *camu_ff_get_stream_side_data(const AVStream *stream, enum AVPacketSideDataType type) +{ +#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(60, 15, 100) + AVCodecParameters *codecpar = stream->codecpar; + const AVPacketSideData *side_data = av_packet_side_data_get(codecpar->coded_side_data, + codecpar->nb_coded_side_data, type); + return side_data ? side_data->data : NULL; +#else + return av_stream_get_side_data(stream, type, NULL); +#endif +} + +const u8 *camu_ff_get_frame_side_data(AVFrame *frame, enum AVFrameSideDataType type) +{ + AVFrameSideData *side_data = av_frame_get_side_data(frame, type); + return side_data ? side_data->data : NULL; +} + static __thread struct { char buf[AL_LOG_MESSAGE_SIZE]; size_t pos; diff --git a/src/codec/ffmpeg/common.h b/src/codec/ffmpeg/common.h index c40a38d..b49ce88 100644 --- a/src/codec/ffmpeg/common.h +++ b/src/codec/ffmpeg/common.h @@ -2,11 +2,16 @@ #include <al/types.h> #include <libavutil/frame.h> +#include <libavutil/display.h> +#include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #define camu_ff_longest_name(desc) ((desc)->long_name ? (desc)->long_name : (desc)->name) -s64 camu_ff_frame_duration(AVFrame *frame); +s64 camu_ff_get_frame_duration(AVFrame *frame); + +const u8 *camu_ff_get_stream_side_data(const AVStream *stream, enum AVPacketSideDataType type); +const u8 *camu_ff_get_frame_side_data(AVFrame *frame, enum AVFrameSideDataType type); // userdata, level, fmt, args void camu_ff_set_log_callback(void (*callback)(void *, int, const char *, va_list)); diff --git a/src/render/queue_libplacebo.c b/src/render/queue_libplacebo.c index f666560..2e9c984 100644 --- a/src/render/queue_libplacebo.c +++ b/src/render/queue_libplacebo.c @@ -399,7 +399,7 @@ static void queue_lp_push_av_frame(struct camu_frame_queue *queue, AVFrame *fram frame->opaque = lq; pl_queue_push(lq->queue, &(struct pl_source_frame){ .pts = pts, - .duration = camu_ff_frame_duration(frame) * av_q2d(stream->time_base), + .duration = camu_ff_get_frame_duration(frame) * av_q2d(stream->time_base), .map = map_av_frame, .unmap = unmap_av_frame, .discard = discard_av_frame, diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c index 6ddb972..d6f95a8 100644 --- a/src/render/renderer_libplacebo.c +++ b/src/render/renderer_libplacebo.c @@ -483,7 +483,7 @@ static bool renderer_lp_render(struct camu_renderer *renderer, struct camu_scree target->crop.y0 += video->view.y_offset; target->crop.x1 += video->view.x_offset; target->crop.y1 += video->view.y_offset; - target->rotation = video->view.rotation; + target->rotation = mix.frames[0]->rotation - video->view.rotation; /* //lr->params.color_map_params = pl_color_map_params(.inverse_tone_mapping = true); if () { diff --git a/src/screen/screen.c b/src/screen/screen.c index 21715a6..c0527c3 100644 --- a/src/screen/screen.c +++ b/src/screen/screen.c @@ -670,14 +670,12 @@ static void add_buffer_internal(struct camu_screen *scr, struct camu_video_buffe struct camu_video_format *fmt = &buf->fmt.req; if (buf->view.mode != CAMU_VIEW_NONE) { video.view = buf->view; -#if 0 - } else if (scr->videos.count > 0) { - video.view = al_array_last(scr->videos).view; - video.view.width = fmt->width; - video.view.height = fmt->height; -#endif } else { - camu_view_init(&video.view, fmt->width, fmt->height); + u8 rotation = buf->view.rotation; + if (rotation != CAMU_VIEW_ROTATION_0) { + log_info("Buffer has initial rotation of %s degrees.", camu_view_rotation_name(rotation)); + } + camu_view_init(&video.view, fmt->width, fmt->height, rotation); } camu_view_calculate(&video.view, scr->width, scr->height); al_array_push(scr->videos, video); diff --git a/src/screen/view.c b/src/screen/view.c index 81d19a9..fadc81c 100644 --- a/src/screen/view.c +++ b/src/screen/view.c @@ -19,10 +19,10 @@ #define VIEW_ON_ITS_SIDE(view) \ (view->rotation % CAMU_VIEW_ROTATION_180 == CAMU_VIEW_ROTATION_90) -void camu_view_init(struct camu_view *view, u32 width, u32 height) +void camu_view_init(struct camu_view *view, u32 width, u32 height, u8 rotation) { view->mode = CAMU_DEFAULT_VIEW; - view->rotation = CAMU_VIEW_ROTATION_0; + view->rotation = rotation; view->width = width; view->height = height; view->zindex = 0; diff --git a/src/screen/view.h b/src/screen/view.h index 5fd86c0..ae6a357 100644 --- a/src/screen/view.h +++ b/src/screen/view.h @@ -40,7 +40,25 @@ struct camu_view { f64 fov; }; -void camu_view_init(struct camu_view *view, u32 width, u32 height); +static inline const char *camu_view_rotation_name(u8 rotation) +{ + switch (rotation) { + case CAMU_VIEW_ROTATION_0: return "0"; + case CAMU_VIEW_ROTATION_90: return "90"; + case CAMU_VIEW_ROTATION_180: return "180"; + case CAMU_VIEW_ROTATION_270: return "270"; + case CAMU_VIEW_ROTATION_360: return "360"; + } + al_assert_and_return(""); +} + +// This handles wrapping backwards for negative numbers. +static inline u8 camu_view_normalize_rotation(s32 rotation) +{ + return (u8)((rotation % CAMU_VIEW_ROTATION_360 + CAMU_VIEW_ROTATION_360) % CAMU_VIEW_ROTATION_360); +} + +void camu_view_init(struct camu_view *view, u32 width, u32 height, u8 rotation); void camu_view_calculate(struct camu_view *view, u32 window_width, u32 window_height); bool camu_view_zoom_simple(struct camu_view *view, u32 window_width, u32 window_height, f64 x, f64 y, f64 v); bool camu_view_pan_simple(struct camu_view *view, u32 window_width, u32 window_height, f64 dx, f64 dy); |