tsdemux: Handle PES headers bigger than a mpeg-ts packet
authorEdward Hervey <edward@centricular.com>
Fri, 4 Mar 2022 13:17:47 +0000 (14:17 +0100)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 4 Mar 2022 15:14:31 +0000 (15:14 +0000)
While the actual PES header parser could notify us that it needed more data, we
would never actually act on it.

This commit will accumulate incoming packets in such situation and re-attempt
the header parsing.

Fixes #1027

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

subprojects/gst-plugins-bad/gst/mpegtsdemux/tsdemux.c

index fb19acf..73e1c06 100644 (file)
@@ -172,6 +172,10 @@ struct _TSDemuxStream
   /* Output data */
   PendingPacketState state;
 
+  /* PES header being reconstructed (optional, allocated) */
+  guint8 *pending_header_data;
+  guint pending_header_size;
+
   /* Data being reconstructed (allocated) */
   guint8 *data;
 
@@ -2144,6 +2148,9 @@ gst_ts_demux_stream_flush (TSDemuxStream * stream, GstTSDemux * tsdemux,
 
   g_free (stream->data);
   stream->data = NULL;
+  g_free (stream->pending_header_data);
+  stream->pending_header_data = NULL;
+  stream->pending_header_size = 0;
   stream->state = PENDING_PACKET_EMPTY;
   stream->expected_size = 0;
   stream->allocated_size = 0;
@@ -2598,9 +2605,26 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream,
 
   GST_MEMDUMP ("Header buffer", data, MIN (length, 32));
 
+  if (G_UNLIKELY (stream->pending_header_data)) {
+    /* Accumulate with previous header if present */
+    stream->pending_header_data =
+        g_realloc (stream->pending_header_data,
+        stream->pending_header_size + length);
+    memcpy (stream->pending_header_data + stream->pending_header_size, data,
+        length);
+    data = stream->pending_header_data;
+    length = stream->pending_header_size + length;
+  }
+
   parseres = mpegts_parse_pes_header (data, length, &header);
-  if (G_UNLIKELY (parseres == PES_PARSING_NEED_MORE))
-    goto discont;
+
+  if (G_UNLIKELY (parseres == PES_PARSING_NEED_MORE)) {
+    /* This can happen if PES header is bigger than a packet. */
+    if (!stream->pending_header_data)
+      stream->pending_header_data = g_memdup2 (data, length);
+    stream->pending_header_size = length;
+    return;
+  }
   if (G_UNLIKELY (parseres == PES_PARSING_BAD)) {
     GST_WARNING ("Error parsing PES header. pid: 0x%x stream_type: 0x%x",
         stream->stream.pid, stream->stream.stream_type);
@@ -2660,9 +2684,20 @@ gst_ts_demux_parse_pes_header (GstTSDemux * demux, TSDemuxStream * stream,
 
   stream->state = PENDING_PACKET_BUFFER;
 
+  if (stream->pending_header_data) {
+    g_free (stream->pending_header_data);
+    stream->pending_header_data = NULL;
+    stream->pending_header_size = 0;
+  }
+
   return;
 
 discont:
+  if (stream->pending_header_data) {
+    g_free (stream->pending_header_data);
+    stream->pending_header_data = NULL;
+    stream->pending_header_size = 0;
+  }
   stream->state = PENDING_PACKET_DISCONT;
   return;
 }
@@ -2699,6 +2734,10 @@ gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream,
           g_free (stream->data);
           stream->data = NULL;
         }
+        if (G_UNLIKELY (stream->pending_header_data)) {
+          g_free (stream->pending_header_data);
+          stream->pending_header_data = NULL;
+        }
         stream->state = PENDING_PACKET_HEADER;
       } else {
         GST_ELEMENT_WARNING_WITH_DETAILS (demux, STREAM, DEMUX,
@@ -2754,6 +2793,10 @@ gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream,
         g_free (stream->data);
         stream->data = NULL;
       }
+      if (G_UNLIKELY (stream->pending_header_data)) {
+        g_free (stream->pending_header_data);
+        stream->pending_header_data = NULL;
+      }
       stream->continuity_counter = CONTINUITY_UNSET;
       break;
     }