From 535a835e5176a5f2d5e03776030bacbc3e19d604 Mon Sep 17 00:00:00 2001 From: James Almer Date: Wed, 8 Sep 2021 15:34:25 -0300 Subject: [PATCH] ffmpeg: use display matrix frame side data for autorotation And give it priority over stream side data when present. Fixes part of ticket #6945. Signed-off-by: James Almer --- fftools/cmdutils.c | 4 +--- fftools/cmdutils.h | 2 +- fftools/ffmpeg.c | 8 ++++++++ fftools/ffmpeg.h | 1 + fftools/ffmpeg_filter.c | 14 +++++++++++++- fftools/ffplay.c | 3 ++- 6 files changed, 26 insertions(+), 6 deletions(-) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 7e9c4299fa..ed3dcd31f4 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -2201,10 +2201,8 @@ void *grow_array(void *array, int elem_size, int *size, int new_size) return array; } -double get_rotation(AVStream *st) +double get_rotation(int32_t *displaymatrix) { - uint8_t* displaymatrix = av_stream_get_side_data(st, - AV_PKT_DATA_DISPLAYMATRIX, NULL); double theta = 0; if (displaymatrix) theta = -round(av_display_rotation_get((int32_t*) displaymatrix)); diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index 9caad01865..30f0b79725 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -648,6 +648,6 @@ void *grow_array(void *array, int elem_size, int *size, int new_size); char name[128];\ av_get_channel_layout_string(name, sizeof(name), 0, ch_layout); -double get_rotation(AVStream *st); +double get_rotation(int32_t *displaymatrix); #endif /* FFTOOLS_CMDUTILS_H */ diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index a9bb9d964d..5365f711e5 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -535,6 +535,7 @@ static void ffmpeg_cleanup(int ret) av_frame_free(&frame); } av_fifo_freep(&ifilter->frame_queue); + av_freep(&ifilter->displaymatrix); if (ist->sub2video.sub_queue) { while (av_fifo_size(ist->sub2video.sub_queue)) { AVSubtitle sub; @@ -2183,6 +2184,7 @@ static int ifilter_has_all_input_formats(FilterGraph *fg) static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) { FilterGraph *fg = ifilter->graph; + AVFrameSideData *sd; int need_reinit, ret, i; /* determine if the parameters for this input changed */ @@ -2207,6 +2209,12 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) (ifilter->hw_frames_ctx && ifilter->hw_frames_ctx->data != frame->hw_frames_ctx->data)) need_reinit = 1; + if (sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX)) { + if (!ifilter->displaymatrix || memcmp(sd->data, ifilter->displaymatrix, sizeof(int32_t) * 9)) + need_reinit = 1; + } else if (ifilter->displaymatrix) + need_reinit = 1; + if (need_reinit) { ret = ifilter_parameters_from_frame(ifilter, frame); if (ret < 0) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 1194bb0cae..30225e9ffe 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -258,6 +258,7 @@ typedef struct InputFilter { uint64_t channel_layout; AVBufferRef *hw_frames_ctx; + int32_t *displaymatrix; int eof; } InputFilter; diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 6b7b6ca1b3..a4c2de07da 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -757,7 +757,12 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter, last_filter = ifilter->filter; if (ist->autorotate) { - double theta = get_rotation(ist->st); + int32_t *displaymatrix = ifilter->displaymatrix; + double theta; + + if (!displaymatrix) + displaymatrix = (int32_t *)av_stream_get_side_data(ist->st, AV_PKT_DATA_DISPLAYMATRIX, NULL); + theta = get_rotation(displaymatrix); if (fabs(theta - 90) < 1.0) { ret = insert_filter(&last_filter, &pad_idx, "transpose", "clock"); @@ -1127,6 +1132,8 @@ fail: int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame) { + AVFrameSideData *sd; + av_buffer_unref(&ifilter->hw_frames_ctx); ifilter->format = frame->format; @@ -1139,6 +1146,11 @@ int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame) ifilter->channels = frame->channels; ifilter->channel_layout = frame->channel_layout; + av_freep(&ifilter->displaymatrix); + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_DISPLAYMATRIX); + if (sd) + ifilter->displaymatrix = av_memdup(sd->data, sizeof(int32_t) * 9); + if (frame->hw_frames_ctx) { ifilter->hw_frames_ctx = av_buffer_ref(frame->hw_frames_ctx); if (!ifilter->hw_frames_ctx) diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 46758b9f55..ccea0e4578 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -1925,7 +1925,8 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c } while (0) if (autorotate) { - double theta = get_rotation(is->video_st); + int32_t *displaymatrix = (int32_t *)av_stream_get_side_data(is->video_st, AV_PKT_DATA_DISPLAYMATRIX, NULL); + double theta = get_rotation(displaymatrix); if (fabs(theta - 90) < 1.0) { INSERT_FILT("transpose", "clock");