qtdemux: fix seeking in fragmented file without mfra random access info
authorMark Nauwelaerts <mnauw@users.sourceforge.net>
Wed, 19 Jul 2017 09:27:32 +0000 (11:27 +0200)
committerMark Nauwelaerts <mnauw@users.sourceforge.net>
Wed, 19 Jul 2017 16:35:49 +0000 (18:35 +0200)
... which no longer worked due to unconditionally clearing sample info and
ending up in inconsistent state.  Let's tread a bit more carefully and also
allow for the old seek handling that resorts to scanning if no mfra info
is available.

gst/isomp4/qtdemux.c

index 5679036..85ed89e 100644 (file)
@@ -4816,9 +4816,15 @@ gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
    * (FIXME: doesn't seem to work so well with ismv and wmv, as no parser; the
    * tfra entries tells us which trun/sample the key unit is in, but we don't
    * make use of this additional information at the moment) */
-  if (qtdemux->fragmented) {
+  if (qtdemux->fragmented && !qtdemux->fragmented_seek_pending) {
     stream->to_sample = G_MAXUINT32;
     return TRUE;
+  } else {
+    /* well, it will be taken care of below */
+    qtdemux->fragmented_seek_pending = FALSE;
+    /* FIXME ideally the do_fragmented_seek can be done right here,
+     * rather than at loop level
+     * (which might even allow handling edit lists in a fragmented file) */
   }
 
   /* We don't need to look for a sample in push-based */
@@ -5604,6 +5610,8 @@ gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
 
   g_assert (qtdemux->n_streams > 0);
 
+  /* first see if we can determine where to go to using mfra,
+   * before we start clearing things */
   for (i = 0; i < qtdemux->n_streams; i++) {
     const QtDemuxRandomAccessEntry *entry;
     QtDemuxStream *stream;
@@ -5611,24 +5619,6 @@ gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
 
     stream = qtdemux->streams[i];
 
-    g_free (stream->samples);
-    stream->samples = NULL;
-    stream->n_samples = 0;
-    stream->stbl_index = -1;    /* no samples have yet been parsed */
-    stream->sample_index = -1;
-
-    if (stream->protection_scheme_info) {
-      /* Clear out any old cenc crypto info entries as we'll move to a new moof */
-      if (stream->protection_scheme_type == FOURCC_cenc) {
-        QtDemuxCencSampleSetInfo *info =
-            (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
-        if (info->crypto_info) {
-          g_ptr_array_free (info->crypto_info, TRUE);
-          info->crypto_info = NULL;
-        }
-      }
-    }
-
     if (stream->ra_entries == NULL)
       continue;
 
@@ -5654,11 +5644,37 @@ gst_qtdemux_do_fragmented_seek (GstQTDemux * qtdemux)
       best_entry = entry;
   }
 
+  /* no luck, will handle seek otherwise */
   if (best_entry == NULL) {
     GST_OBJECT_UNLOCK (qtdemux);
     return FALSE;
   }
 
+  /* ok, now we can prepare for processing as of located moof */
+  for (i = 0; i < qtdemux->n_streams; i++) {
+    QtDemuxStream *stream;
+
+    stream = qtdemux->streams[i];
+
+    g_free (stream->samples);
+    stream->samples = NULL;
+    stream->n_samples = 0;
+    stream->stbl_index = -1;    /* no samples have yet been parsed */
+    stream->sample_index = -1;
+
+    if (stream->protection_scheme_info) {
+      /* Clear out any old cenc crypto info entries as we'll move to a new moof */
+      if (stream->protection_scheme_type == FOURCC_cenc) {
+        QtDemuxCencSampleSetInfo *info =
+            (QtDemuxCencSampleSetInfo *) stream->protection_scheme_info;
+        if (info->crypto_info) {
+          g_ptr_array_free (info->crypto_info, TRUE);
+          info->crypto_info = NULL;
+        }
+      }
+    }
+  }
+
   GST_INFO_OBJECT (qtdemux, "seek to %" GST_TIME_FORMAT ", best fragment "
       "moof offset: %" G_GUINT64_FORMAT ", ts %" GST_TIME_FORMAT,
       GST_TIME_ARGS (qtdemux->streams[0]->time_position),
@@ -5694,9 +5710,12 @@ gst_qtdemux_loop_state_movie (GstQTDemux * qtdemux)
 
   if (qtdemux->fragmented_seek_pending) {
     GST_INFO_OBJECT (qtdemux, "pending fragmented seek");
-    gst_qtdemux_do_fragmented_seek (qtdemux);
-    GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
-    qtdemux->fragmented_seek_pending = FALSE;
+    if (gst_qtdemux_do_fragmented_seek (qtdemux)) {
+      GST_INFO_OBJECT (qtdemux, "fragmented seek done!");
+      qtdemux->fragmented_seek_pending = FALSE;
+    } else {
+      GST_INFO_OBJECT (qtdemux, "fragmented seek still pending");
+    }
   }
 
   /* Figure out the next stream sample to output, min_time is expressed in