mpegvideoparse: look beyond start code before leaping
authorMark Nauwelaerts <mnauw@users.sourceforge.net>
Mon, 11 Nov 2013 15:15:00 +0000 (16:15 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Tue, 26 Nov 2013 11:45:47 +0000 (12:45 +0100)
In case more data than a start code alone is needed to decide whether
it ends a frame, arrange for more input data and decide when available.

Fixes https://bugzilla.gnome.org/show_bug.cgi?id=711627

gst/videoparsers/gstmpegvideoparse.c

index 1b2116fcecc54cbf4cf2dcec2d4c708b203524da..b02b10d7295146ecd92826c22f21aff3f77b0ebe 100644 (file)
@@ -461,18 +461,21 @@ parse_packet_extension (GstMpegvParse * mpvparse, GstMapInfo * info, guint off)
   }
 }
 
-/* caller guarantees at least start code in @buf at @off */
+/* caller guarantees at least start code in @buf at @off ( - 4)*/
 /* for off == 4 initial code; returns TRUE if code starts a frame
  * otherwise returns TRUE if code terminates preceding frame */
 static gboolean
 gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
-    GstMapInfo * info, gint off, GstMpegVideoPacket * packet)
+    GstMapInfo * info, gint off, GstMpegVideoPacket * packet,
+    gboolean * need_more)
 {
   gboolean ret = FALSE, checkconfig = TRUE;
 
   GST_LOG_OBJECT (mpvparse, "process startcode %x (%s) offset:%d", packet->type,
       picture_start_code_name (packet->type), off);
 
+  *need_more = FALSE;
+
   switch (packet->type) {
     case GST_MPEG_VIDEO_PACKET_PICTURE:
       GST_LOG_OBJECT (mpvparse, "startcode is PICTURE");
@@ -548,6 +551,7 @@ gst_mpegv_parse_process_sc (GstMpegvParse * mpvparse,
         && (mpvparse->config_flags & FLAG_SEQUENCE_EXT)
         && !mpvparse->sequenceext.progressive) {
       if (info->size - off < 2) {       /* we need at least two bytes to read the TSN */
+        *need_more = TRUE;
         ret = FALSE;
       } else {
         /* TSN is stored in first 10 bits */
@@ -591,6 +595,7 @@ gst_mpegv_parse_handle_frame (GstBaseParse * parse,
   GstMpegVideoPacket packet;
   guint8 *data;
   gint size;
+  gboolean need_more = FALSE;
   GstMapInfo map;
 
   update_frame_parsing_status (mpvparse, frame);
@@ -630,7 +635,7 @@ retry:
   /* note: initial start code is assumed at offset 0 by subsequent code */
 
   /* examine start code, see if it looks like an initial start code */
-  if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet)) {
+  if (gst_mpegv_parse_process_sc (mpvparse, &map, 4, &packet, &need_more)) {
     /* found sc */
     GST_LOG_OBJECT (mpvparse, "valid start code found");
     mpvparse->last_sc = 0;
@@ -660,22 +665,18 @@ next:
 
   GST_LOG_OBJECT (mpvparse, "next start code at %d", off);
   if (off < 0) {
-    /* if draining, take all */
-    if (GST_BASE_PARSE_DRAINING (parse)) {
-      GST_LOG_OBJECT (mpvparse, "draining, accepting all data");
-      off = size;
-      ret = TRUE;
-    } else {
-      GST_LOG_OBJECT (mpvparse, "need more data");
-      /* resume scan where we left it */
-      mpvparse->last_sc = size - 3;
-      /* request best next available */
-      off = G_MAXUINT;
-      goto exit;
-    }
+    off = size - 3;
+    goto need_more;
   } else {
     /* decide whether this startcode ends a frame */
-    ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet);
+    ret = gst_mpegv_parse_process_sc (mpvparse, &map, off + 4, &packet,
+        &need_more);
+    /* in rare cases, might need to peek past start code */
+    if (need_more) {
+      GST_LOG_OBJECT (mpvparse, "need more data (past start code");
+      ret = FALSE;
+      goto need_more;
+    }
   }
 
   if (!ret)
@@ -702,6 +703,21 @@ exit:
   }
 
   return flowret;
+
+need_more:
+  /* if draining, take all */
+  if (GST_BASE_PARSE_DRAINING (parse)) {
+    GST_LOG_OBJECT (mpvparse, "draining, accepting all data");
+    off = size;
+    ret = TRUE;
+  } else {
+    GST_LOG_OBJECT (mpvparse, "need more data");
+    /* resume scan where we left it */
+    mpvparse->last_sc = off;
+    /* request best next available */
+    off = G_MAXUINT;
+  }
+  goto exit;
 }
 
 static void