matroskademux: extract cluster prevsize if available
authorTim-Philipp Müller <tim@centricular.com>
Wed, 18 Jan 2017 10:27:38 +0000 (10:27 +0000)
committerTim-Philipp Müller <tim@centricular.com>
Mon, 27 Aug 2018 21:00:53 +0000 (23:00 +0200)
This is useful for reverse playback/trickmodes
without an index, and will also be useful in the
seek handler if we need to scan back to find a cluster
that starts with a keyframe.

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

gst/matroska/matroska-demux.c
gst/matroska/matroska-demux.h

index fb78329..8241104 100644 (file)
@@ -306,6 +306,8 @@ gst_matroska_demux_reset (GstElement * element)
   demux->to_time = GST_CLOCK_TIME_NONE;
   demux->cluster_time = GST_CLOCK_TIME_NONE;
   demux->cluster_offset = 0;
+  demux->cluster_prevsize = 0;
+  demux->seen_cluster_prevsize = FALSE;
   demux->next_cluster_offset = 0;
   demux->stream_last_time = GST_CLOCK_TIME_NONE;
   demux->last_cluster_offset = 0;
@@ -4659,6 +4661,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
       break;
     case GST_MATROSKA_READ_STATE_SCANNING:
       if (id != GST_MATROSKA_ID_CLUSTER &&
+          id != GST_MATROSKA_ID_PREVSIZE &&
           id != GST_MATROSKA_ID_CLUSTERTIMECODE) {
         if (demux->common.start_resync_offset != -1) {
           /* we need to skip byte per byte if we are scanning for a new cluster
@@ -4742,6 +4745,7 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
           }
           demux->cluster_time = GST_CLOCK_TIME_NONE;
           demux->cluster_offset = demux->common.offset;
+          demux->cluster_prevsize = 0;
           if (G_UNLIKELY (!demux->seek_first && demux->seek_block)) {
             GST_DEBUG_OBJECT (demux, "seek target block %" G_GUINT64_FORMAT
                 " not found in Cluster, trying next Cluster's first block instead",
@@ -4873,8 +4877,18 @@ gst_matroska_demux_parse_id (GstMatroskaDemux * demux, guint32 id,
             GST_OBJECT_UNLOCK (demux);
           }
           break;
+        case GST_MATROSKA_ID_PREVSIZE:{
+          guint64 num;
+
+          GST_READ_CHECK (gst_matroska_demux_take (demux, read, &ebml));
+          if ((ret = gst_ebml_read_uint (&ebml, &id, &num)) != GST_FLOW_OK)
+            goto parse_failed;
+          GST_LOG_OBJECT (demux, "ClusterPrevSize: %" G_GUINT64_FORMAT, num);
+          demux->cluster_prevsize = num;
+          demux->seen_cluster_prevsize = TRUE;
+          break;
+        }
         case GST_MATROSKA_ID_POSITION:
-        case GST_MATROSKA_ID_PREVSIZE:
         case GST_MATROSKA_ID_ENCRYPTEDBLOCK:
         case GST_MATROSKA_ID_SILENTTRACKS:
           GST_DEBUG_OBJECT (demux,
@@ -5245,6 +5259,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstObject * parent,
       demux->common.segment.position = GST_CLOCK_TIME_NONE;
       demux->cluster_time = GST_CLOCK_TIME_NONE;
       demux->cluster_offset = 0;
+      demux->cluster_prevsize = 0;
       demux->need_segment = TRUE;
       demux->segment_seqnum = gst_event_get_seqnum (event);
       /* but keep some of the upstream segment */
@@ -5297,6 +5312,7 @@ gst_matroska_demux_handle_sink_event (GstPad * pad, GstObject * parent,
       demux->common.segment.duration = dur;
       demux->cluster_time = GST_CLOCK_TIME_NONE;
       demux->cluster_offset = 0;
+      demux->cluster_prevsize = 0;
       GST_OBJECT_UNLOCK (demux);
       /* fall-through */
     }
index 2fe248b..1e0826f 100644 (file)
@@ -84,6 +84,7 @@ typedef struct _GstMatroskaDemux {
   /* some state saving */
   GstClockTime             cluster_time;
   guint64                  cluster_offset;
+  guint64                  cluster_prevsize;       /* 0 if unknown */
   guint64                  first_cluster_offset;
   guint64                  next_cluster_offset;
   GstClockTime             requested_seek_time;
@@ -105,6 +106,15 @@ typedef struct _GstMatroskaDemux {
   GArray                  *seek_index;
   gint                     seek_entry;
 
+  gboolean                 seen_cluster_prevsize;  /* We track this because the
+                                                    * first cluster won't have
+                                                    * this set, so we can't just
+                                                    * check cluster_prevsize to
+                                                    * determine if it's there
+                                                    * or not. We assume if one
+                                                    * cluster has it, all but
+                                                    * the first will have it. */
+
   /* gap handling */
   guint64                  max_gap_time;