summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/buffer/video.c24
-rw-r--r--src/codec/ffmpeg/common.c21
-rw-r--r--src/codec/ffmpeg/common.h7
-rw-r--r--src/render/queue_libplacebo.c2
-rw-r--r--src/render/renderer_libplacebo.c2
-rw-r--r--src/screen/screen.c12
-rw-r--r--src/screen/view.c4
-rw-r--r--src/screen/view.h20
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);