avdec_h265: Fix endless renegoation with alternate interlacing
authorNicolas Dufresne <nicolas.dufresne@collabora.com>
Wed, 26 Oct 2022 20:30:31 +0000 (16:30 -0400)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Thu, 27 Oct 2022 13:34:48 +0000 (13:34 +0000)
The picture parameter picture->top_field_first is reused in this mode
to signal the TOP fields. As a side effect, it will change every frame
and current code assumed that if this changes then a renegotiation is
needed. Fixed this by ignoring that change whenever we are decoding one field
only.

Fixes #1523

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3276>

subprojects/gst-libav/ext/libav/gstavviddec.c

index cccbb73..dd8c615 100644 (file)
@@ -98,7 +98,7 @@ static GstFlowReturn gst_ffmpegviddec_finish (GstVideoDecoder * decoder);
 static GstFlowReturn gst_ffmpegviddec_drain (GstVideoDecoder * decoder);
 
 static gboolean picture_changed (GstFFMpegVidDec * ffmpegdec,
-    AVFrame * picture);
+    AVFrame * picture, gboolean one_field);
 static gboolean context_changed (GstFFMpegVidDec * ffmpegdec,
     AVCodecContext * context);
 
@@ -1034,11 +1034,14 @@ no_frame:
 }
 
 static gboolean
-picture_changed (GstFFMpegVidDec * ffmpegdec, AVFrame * picture)
+picture_changed (GstFFMpegVidDec * ffmpegdec, AVFrame * picture,
+    gboolean one_field)
 {
   gint pic_field_order = 0;
 
-  if (picture->interlaced_frame) {
+  if (one_field) {
+    pic_field_order = ffmpegdec->pic_field_order;
+  } else if (picture->interlaced_frame) {
     if (picture->repeat_pict)
       pic_field_order |= GST_VIDEO_BUFFER_FLAG_RFF;
     if (picture->top_field_first)
@@ -1066,7 +1069,7 @@ context_changed (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context)
 
 static gboolean
 update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context,
-    AVFrame * picture)
+    AVFrame * picture, gboolean one_field)
 {
   gint pic_field_order = 0;
 
@@ -1077,7 +1080,7 @@ update_video_context (GstFFMpegVidDec * ffmpegdec, AVCodecContext * context,
       pic_field_order |= GST_VIDEO_BUFFER_FLAG_TFF;
   }
 
-  if (!picture_changed (ffmpegdec, picture)
+  if (!picture_changed (ffmpegdec, picture, one_field)
       && !context_changed (ffmpegdec, context))
     return FALSE;
 
@@ -1303,8 +1306,9 @@ gst_ffmpegviddec_negotiate (GstFFMpegVidDec * ffmpegdec,
   GstStructure *in_s;
   GstVideoInterlaceMode interlace_mode;
   gint caps_height;
+  gboolean one_field = ! !(flags & GST_VIDEO_BUFFER_FLAG_ONEFIELD);
 
-  if (!update_video_context (ffmpegdec, context, picture))
+  if (!update_video_context (ffmpegdec, context, picture, one_field))
     return TRUE;
 
   caps_height = ffmpegdec->pic_height;