From 5e61a8999fd7367cc02ff7f080d33d824af78474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 29 Sep 2016 15:35:01 +0300 Subject: [PATCH] avviddec: Use interlaced-mode=interleaved and set field-order if possible https://bugzilla.gnome.org/show_bug.cgi?id=771376 --- ext/libav/gstavviddec.c | 68 +++++++++++++++++++++++++++++++++++++---- ext/libav/gstavviddec.h | 3 ++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/ext/libav/gstavviddec.c b/ext/libav/gstavviddec.c index 604c8a3489..6ccb82ad42 100644 --- a/ext/libav/gstavviddec.c +++ b/ext/libav/gstavviddec.c @@ -433,6 +433,9 @@ gst_ffmpegviddec_set_format (GstVideoDecoder * decoder, ffmpegdec->pic_height = 0; ffmpegdec->pic_par_n = 0; ffmpegdec->pic_par_d = 0; + ffmpegdec->pic_interlaced = 0; + ffmpegdec->pic_field_order = 0; + ffmpegdec->pic_field_order_changed = FALSE; ffmpegdec->ctx_ticks = 0; ffmpegdec->ctx_time_n = 0; ffmpegdec->ctx_time_d = 0; @@ -881,12 +884,22 @@ no_frame: static gboolean picture_changed (GstFFMpegVidDec * ffmpegdec, AVFrame * picture) { + gint pic_field_order = 0; + + if (picture->interlaced_frame) { + if (picture->repeat_pict) + pic_field_order |= GST_VIDEO_BUFFER_FLAG_RFF; + if (picture->top_field_first) + pic_field_order |= GST_VIDEO_BUFFER_FLAG_TFF; + } + return !(ffmpegdec->pic_width == picture->width && ffmpegdec->pic_height == picture->height && ffmpegdec->pic_pix_fmt == picture->format && ffmpegdec->pic_par_n == picture->sample_aspect_ratio.num && ffmpegdec->pic_par_d == picture->sample_aspect_ratio.den - && ffmpegdec->pic_interlaced == picture->interlaced_frame); + && ffmpegdec->pic_interlaced == picture->interlaced_frame + && ffmpegdec->pic_field_order == pic_field_order); } static gboolean @@ -901,6 +914,15 @@ static gboolean update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context, AVFrame * picture) { + gint pic_field_order = 0; + + if (picture->interlaced_frame) { + if (picture->repeat_pict) + pic_field_order |= GST_VIDEO_BUFFER_FLAG_RFF; + if (picture->top_field_first) + pic_field_order |= GST_VIDEO_BUFFER_FLAG_TFF; + } + if (!picture_changed (ffmpegdec, picture) && !context_changed (ffmpegdec, context)) return FALSE; @@ -921,7 +943,21 @@ update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context, ffmpegdec->pic_height = picture->height; ffmpegdec->pic_par_n = picture->sample_aspect_ratio.num; ffmpegdec->pic_par_d = picture->sample_aspect_ratio.den; + + /* Remember if we have interlaced content and the field order changed + * at least once. If that happens, we must be interlaced-mode=mixed + */ + if (ffmpegdec->pic_field_order_changed || + (ffmpegdec->pic_field_order != pic_field_order && + ffmpegdec->pic_interlaced)) + ffmpegdec->pic_field_order_changed = TRUE; + + ffmpegdec->pic_field_order = pic_field_order; ffmpegdec->pic_interlaced = picture->interlaced_frame; + + if (!ffmpegdec->pic_interlaced) + ffmpegdec->pic_field_order_changed = FALSE; + ffmpegdec->ctx_ticks = context->ticks_per_frame; ffmpegdec->ctx_time_n = context->time_base.num; ffmpegdec->ctx_time_d = context->time_base.den; @@ -1032,13 +1068,27 @@ gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec, out_info = &ffmpegdec->output_state->info; /* set the interlaced flag */ - if (ffmpegdec->pic_interlaced) - out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED; - else - out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; - in_s = gst_caps_get_structure (ffmpegdec->input_state->caps, 0); + if (!gst_structure_has_field (in_s, "interlace-mode")) { + if (ffmpegdec->pic_interlaced) { + if (ffmpegdec->pic_field_order_changed || + (ffmpegdec->pic_field_order & GST_VIDEO_BUFFER_FLAG_RFF)) { + out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED; + } else { + out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_INTERLEAVED; + if ((ffmpegdec->pic_field_order & GST_VIDEO_BUFFER_FLAG_TFF)) + GST_VIDEO_INFO_FIELD_ORDER (out_info) = + GST_VIDEO_FIELD_ORDER_TOP_FIELD_FIRST; + else + GST_VIDEO_INFO_FIELD_ORDER (out_info) = + GST_VIDEO_FIELD_ORDER_BOTTOM_FIELD_FIRST; + } + } else { + out_info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE; + } + } + if (!gst_structure_has_field (in_s, "chroma-site")) { switch (context->chroma_sample_location) { case AVCHROMA_LOC_LEFT: @@ -1224,6 +1274,9 @@ negotiate_failed: ffmpegdec->pic_height = 0; ffmpegdec->pic_par_n = 0; ffmpegdec->pic_par_d = 0; + ffmpegdec->pic_interlaced = 0; + ffmpegdec->pic_field_order = 0; + ffmpegdec->pic_field_order_changed = FALSE; ffmpegdec->ctx_ticks = 0; ffmpegdec->ctx_time_n = 0; ffmpegdec->ctx_time_d = 0; @@ -1841,6 +1894,9 @@ gst_ffmpegviddec_stop (GstVideoDecoder * decoder) ffmpegdec->pic_height = 0; ffmpegdec->pic_par_n = 0; ffmpegdec->pic_par_d = 0; + ffmpegdec->pic_interlaced = 0; + ffmpegdec->pic_field_order = 0; + ffmpegdec->pic_field_order_changed = FALSE; ffmpegdec->ctx_ticks = 0; ffmpegdec->ctx_time_n = 0; ffmpegdec->ctx_time_d = 0; diff --git a/ext/libav/gstavviddec.h b/ext/libav/gstavviddec.h index 68faf9648b..1c4375f665 100644 --- a/ext/libav/gstavviddec.h +++ b/ext/libav/gstavviddec.h @@ -47,6 +47,9 @@ struct _GstFFMpegVidDec gint pic_par_n; gint pic_par_d; gint pic_interlaced; + /* GST_VIDEO_BUFFER_FLAG_RFF | GST_VIDEO_BUFFER_FLAG_TFF */ + gint pic_field_order; + gboolean pic_field_order_changed; /* current context */ gint ctx_ticks; gint ctx_time_d;