tsdemux: Limit the maximum PES payload size
authorJan Schmidt <jan@centricular.com>
Fri, 28 Jun 2019 05:04:29 +0000 (15:04 +1000)
committerTim-Philipp Müller <tim@centricular.com>
Wed, 21 Aug 2019 19:09:50 +0000 (20:09 +0100)
PES packets with size 0 are unbounded, and
could therefore overflow the 32-bit size
accumulator.

Add a 32MB limit, which is larger than
any PES packet should ever get. If one does,
then output a 32MB chunk and continue.

gst/mpegtsdemux/tsdemux.c

index 64f9d0b..9f696f0 100644 (file)
 /* latency in nsecs */
 #define TS_LATENCY (700 * GST_MSECOND)
 
+/* Limit PES packet collection to a maximum of 32MB
+ * which is more than large enough to support an H264 frame at
+ * maximum profile/level/bitrate at 30fps or above.
+ * PES bigger than this limit will be output in buffers of
+ * up to this size */
+#define MAX_PES_PAYLOAD (32 * 1024 * 1024)
+
 GST_DEBUG_CATEGORY_STATIC (ts_demux_debug);
 #define GST_CAT_DEFAULT ts_demux_debug
 
@@ -2424,7 +2431,7 @@ gst_ts_demux_queue_data (GstTSDemux * demux, TSDemuxStream * stream,
       if (G_UNLIKELY (stream->current_size + size > stream->allocated_size)) {
         GST_LOG ("resizing buffer");
         do {
-          stream->allocated_size *= 2;
+          stream->allocated_size = MAX (8192, 2 * stream->allocated_size);
         } while (stream->current_size + size > stream->allocated_size);
         stream->data = g_realloc (stream->data, stream->allocated_size);
       }
@@ -3094,11 +3101,17 @@ gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream,
   }
 
 beach:
-  /* Reset everything */
-  GST_LOG ("Resetting to EMPTY, returning %s", gst_flow_get_name (res));
-  stream->state = PENDING_PACKET_EMPTY;
+  /* Reset the PES payload collection, but don't clear the state,
+   * we might want to keep collecting this PES */
+  GST_LOG ("Cleared PES data. returning %s", gst_flow_get_name (res));
+  if (stream->expected_size) {
+    if (stream->current_size > stream->expected_size)
+      stream->expected_size = 0;
+    else
+      stream->expected_size -= stream->current_size;
+  }
   stream->data = NULL;
-  stream->expected_size = 0;
+  stream->allocated_size = 0;
   stream->current_size = 0;
 
   return res;
@@ -3115,18 +3128,23 @@ gst_ts_demux_handle_packet (GstTSDemux * demux, TSDemuxStream * stream,
       FLAGS_CONTINUITY_COUNTER (packet->scram_afc_cc), packet->payload);
 
   if (G_UNLIKELY (packet->payload_unit_start_indicator) &&
-      FLAGS_HAS_PAYLOAD (packet->scram_afc_cc))
+      FLAGS_HAS_PAYLOAD (packet->scram_afc_cc)) {
     /* Flush previous data */
     res = gst_ts_demux_push_pending_data (demux, stream, NULL);
+    /* Tell the data collecting to expect this header */
+    stream->state = PENDING_PACKET_HEADER;
+  }
 
   if (packet->payload && (res == GST_FLOW_OK || res == GST_FLOW_NOT_LINKED)
       && stream->pad) {
     gst_ts_demux_queue_data (demux, stream, packet);
     GST_LOG ("current_size:%d, expected_size:%d",
         stream->current_size, stream->expected_size);
-    /* Finally check if the data we queued completes a packet */
-    if (stream->expected_size && stream->current_size == stream->expected_size) {
-      GST_LOG ("pushing complete packet");
+    /* Finally check if the data we queued completes a packet, or got too
+     * large and needs output now */
+    if ((stream->expected_size && stream->current_size >= stream->expected_size)
+        || (stream->current_size >= MAX_PES_PAYLOAD)) {
+      GST_LOG ("pushing packet of size %u", stream->current_size);
       res = gst_ts_demux_push_pending_data (demux, stream, NULL);
     }
   }