pesparse: Refactory secondary PES extension handling
authorEdward Hervey <edward@collabora.com>
Wed, 14 Aug 2013 11:41:37 +0000 (13:41 +0200)
committerEdward Hervey <edward@collabora.com>
Wed, 14 Aug 2013 11:41:37 +0000 (13:41 +0200)
Some streams had wrong values for the stream_id_extension, make sure
we only remember the valid ones.

For streams with PES_extension_field_length == 0, assume there's nothing
else.

For streams that state they have a TREF extension but don't have enough
data to store it, just assume it was produced by a non-compliant muxer
and skip the remaining data.

Only store remaining data in stream_id_extension_data instead of storing
data we already parse.

gst/mpegtsdemux/pesparse.c
gst/mpegtsdemux/pesparse.h

index ca1b990..e18f8ed 100644 (file)
@@ -256,7 +256,12 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
   /* PES extension */
   flags = *data++;
   length -= 1;
-  GST_DEBUG ("PES_extension_flag 0x%02x", flags);
+  GST_DEBUG ("PES_extension_flag: %s%s%s%s%s%s",
+      flags & 0x80 ? "PES_private_data " : "",
+      flags & 0x40 ? "pack_header_field " : "",
+      flags & 0x20 ? "program_packet_sequence_counter " : "",
+      flags & 0x10 ? "P-STD_buffer " : "",
+      flags & 0x01 ? "PES_extension_flag_2" : "", flags & 0xf1 ? "" : "<none>");
 
   if (flags & 0x80) {
     /* PES_private data */
@@ -292,7 +297,6 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
       goto need_more_data;
 
     val8 = *data++;
-    /* GRMBL, this is most often wrong */
     if (G_UNLIKELY ((val8 & 0x80) != 0x80))
       goto bad_sequence_marker1;
     res->program_packet_sequence_counter = val8 & 0x7f;
@@ -300,7 +304,6 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
         res->program_packet_sequence_counter);
 
     val8 = *data++;
-    /* GRMBL, this is most often wrong */
     if (G_UNLIKELY ((val8 & 0x80) != 0x80))
       goto bad_sequence_marker2;
     res->MPEG1_MPEG2_identifier = (val8 >> 6) & 0x1;
@@ -324,37 +327,52 @@ mpegts_parse_pes_header (const guint8 * data, gsize length, PESHeader * res)
     length -= 2;
   }
 
-  if (flags & 0x01) {
-    /* Extension flag 2 */
-    if (G_UNLIKELY (length < 1))
-      goto need_more_data;
+  /* jump if we don't have a PES 2nd extension */
+  if (!flags & 0x01)
+    goto stuffing_byte;
 
-    val8 = *data++;
-    length -= 1;
+  /* Extension flag 2 */
+  if (G_UNLIKELY (length < 1))
+    goto need_more_data;
 
-    if (!(val8 & 0x80))
-      goto bad_extension_marker_2;
+  val8 = *data++;
+  length -= 1;
 
-    res->extension_field_length = val8 & 0x7f;
-    if (G_UNLIKELY (length < res->extension_field_length))
-      goto need_more_data;
+  if (!(val8 & 0x80))
+    goto bad_extension_marker_2;
 
-    GST_LOG ("extension_field_length : %" G_GSIZE_FORMAT,
-        res->extension_field_length);
-
-    if (res->extension_field_length) {
-      flags = *data++;
-      /* Only valid if stream_id_extension_flag == 0x0 */
-      if (!(flags & 0x80)) {
-        res->stream_id_extension = flags & 0x7f;
-        GST_LOG ("stream_id_extension : 0x%02x", res->stream_id_extension);
-        res->stream_id_extension_data = data;
-        GST_MEMDUMP ("stream_id_extension_data",
-            res->stream_id_extension_data, res->extension_field_length);
-      } else {
-        GST_LOG ("tref_extension : %d", flags & 0x01);
-      }
-    }
+  res->extension_field_length = val8 & 0x7f;
+
+  /* Skip empty extensions */
+  if (G_UNLIKELY (res->extension_field_length == 0))
+    goto stuffing_byte;
+
+  if (G_UNLIKELY (length < res->extension_field_length))
+    goto need_more_data;
+
+  flags = *data++;
+  res->extension_field_length -= 1;
+
+  if (!(flags & 0x80)) {
+    /* Only valid if stream_id_extension_flag == 0x0 */
+    res->stream_id_extension = flags;
+    GST_LOG ("stream_id_extension : 0x%02x", res->stream_id_extension);
+  } else if (!(flags & 0x01)) {
+    /* Skip broken streams (that use stream_id_extension with highest bit set
+     * for example ...) */
+    if (G_UNLIKELY (res->extension_field_length < 5))
+      goto stuffing_byte;
+
+    GST_LOG ("TREF field present");
+    data += 5;
+    res->extension_field_length -= 5;
+  }
+
+  /* Extension field data */
+  if (res->extension_field_length) {
+    res->stream_id_extension_data = data;
+    GST_MEMDUMP ("stream_id_extension_data",
+        res->stream_id_extension_data, res->extension_field_length);
   }
 
 stuffing_byte:
index 694e802..1d7d870 100644 (file)
@@ -185,9 +185,11 @@ typedef struct {
   guint32      P_STD_buffer_size; /* P-STD buffer size in bytes (0 if invalid
                                    * or not present */
 
-  gsize                extension_field_length;
-  guint8       stream_id_extension; /* Only valid if stream_id == ID_EXTENDED_STREAM_ID */
-  const guint8*        stream_id_extension_data;
+  guint8       stream_id_extension; /* Public range (0x00 - 0x3f) only valid if stream_id == ID_EXTENDED_STREAM_ID
+                                     * Private range (0x40 - 0xff) can be present in any stream type */
+
+  gsize                extension_field_length;   /* Length of remaining extension field data */
+  const guint8*        stream_id_extension_data; /* Valid if extension_field_length != 0 */
 } PESHeader;
 
 G_GNUC_INTERNAL PESParsingResult mpegts_parse_pes_header (const guint8* data,