mpeg2dec: drop B-frame on open gop
authorStéphane Cerveau <scerveau@collabora.com>
Wed, 28 Jul 2021 09:49:16 +0000 (11:49 +0200)
committerStéphane Cerveau <scerveau@collabora.com>
Thu, 29 Jul 2021 15:03:24 +0000 (17:03 +0200)
Enhance open gop detection to drop B-frame which are invalid
before the first reference frame.

In stream such
gst-integration-testsuites/medias/defaults/mxf/op2b-mpeg2-wave_hd.mxf,
the two first frames must be dropped as we detect an open GOP situation
but in another media, such as http://col.la/1920X1080IXDCAMEX5MIN, the
first frames should not be dropped as we are in a closed GOP situation.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-ugly/-/merge_requests/84>

ext/mpeg2dec/gstmpeg2dec.c

index 8f6ae84..12b3cac 100644 (file)
@@ -967,6 +967,8 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
   GstVideoCodecFrame *frame;
   const mpeg2_picture_t *picture;
   gboolean key_frame = FALSE;
+  gboolean bidirect_frame = FALSE;
+  gboolean closed_gop = FALSE;
 
   GST_DEBUG_OBJECT (mpeg2dec,
       "fbuf:%p display_picture:%p current_picture:%p fbuf->id:%d",
@@ -981,6 +983,9 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
     goto no_frame;
   picture = info->display_picture;
   key_frame = (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_I;
+  bidirect_frame =
+      (picture->flags & PIC_MASK_CODING_TYPE) == PIC_FLAG_CODING_TYPE_B;
+  closed_gop = (info->gop->flags & GOP_FLAG_CLOSED_GOP);
 
   GST_DEBUG_OBJECT (mpeg2dec, "picture flags: %d, type: %d, keyframe: %d",
       picture->flags, picture->flags & PIC_MASK_CODING_TYPE, key_frame);
@@ -999,11 +1004,14 @@ handle_slice (GstMpeg2dec * mpeg2dec, const mpeg2_info_t * info)
     return ret;
   }
 
+  /* Skip B-frames if GOP is not closed and waiting for the first keyframe. */
   if (mpeg2dec->discont_state != MPEG2DEC_DISC_NONE) {
-    GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, discont state %d",
-        mpeg2dec->discont_state);
-    ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (mpeg2dec), frame);
-    return ret;
+    if (bidirect_frame && !closed_gop) {
+      GST_DEBUG_OBJECT (mpeg2dec, "dropping buffer, discont state %d",
+          mpeg2dec->discont_state);
+      ret = gst_video_decoder_drop_frame (GST_VIDEO_DECODER (mpeg2dec), frame);
+      return ret;
+    }
   }
 
   /* do cropping if the target region is smaller than the input one */