qtdemux: Always check ctts for unreasonably large offsets
authorSebastian Dröge <sebastian@centricular.com>
Fri, 12 Nov 2021 10:46:56 +0000 (12:46 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 12 Nov 2021 17:51:03 +0000 (17:51 +0000)
If this happens then ignore the whole ctts. Previously we only did this
if the PTS/DTS shift was determined from the ctts instead of the cslg.

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

subprojects/gst-plugins-good/gst/isomp4/qtdemux.c

index 41ce6b2..1847f46 100644 (file)
@@ -9391,6 +9391,7 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
               &stream->ctts) ? TRUE : FALSE) == TRUE) {
     GstByteReader cslg = GST_BYTE_READER_INIT (NULL, 0);
     guint8 ctts_version;
+    gboolean checked_ctts = FALSE;
 
     /* copy atom data into a new buffer for later use */
     stream->ctts.data = g_memdup2 (stream->ctts.data, stream->ctts.size);
@@ -9445,6 +9446,8 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
       pos = gst_byte_reader_get_pos (&stream->ctts);
       num_entries = stream->n_composition_times;
 
+      checked_ctts = TRUE;
+
       stream->cslg_shift = 0;
 
       for (i = 0; i < num_entries; i++) {
@@ -9477,6 +9480,37 @@ qtdemux_stbl_init (GstQTDemux * qtdemux, QtDemuxStream * stream, GNode * stbl)
       /* reset the reader so we can generate sample table */
       gst_byte_reader_set_pos (&stream->ctts, pos);
     }
+
+    /* Check if ctts values are looking reasonable if that didn't happen above */
+    if (!checked_ctts) {
+      guint num_entries, pos;
+      gint i;
+
+      pos = gst_byte_reader_get_pos (&stream->ctts);
+      num_entries = stream->n_composition_times;
+
+      for (i = 0; i < num_entries; i++) {
+        gint32 offset;
+
+        gst_byte_reader_skip_unchecked (&stream->ctts, 4);
+        offset = gst_byte_reader_get_int32_be_unchecked (&stream->ctts);
+        /* HACK: if sample_offset is larger than 2 * duration, ignore the box.
+         * slightly inaccurate PTS could be more usable than corrupted one */
+        if (G_UNLIKELY ((ABS (offset) / 2) > stream->duration)) {
+          GST_WARNING_OBJECT (qtdemux,
+              "Ignore corrupted ctts, sample_offset %" G_GINT32_FORMAT
+              " larger than duration %" G_GUINT64_FORMAT,
+              offset, stream->duration);
+
+          stream->cslg_shift = 0;
+          stream->ctts_present = FALSE;
+          goto done;
+        }
+      }
+
+      /* reset the reader so we can generate sample table */
+      gst_byte_reader_set_pos (&stream->ctts, pos);
+    }
   } else {
     /* Ensure the cslg_shift value is consistent so we can use it
      * unconditionally to produce TS and Segment */