qtdemux: fix reverse playback of fragmented media
authorThiago Santos <thiagoss@osg.samsung.com>
Sat, 23 May 2015 17:36:41 +0000 (14:36 -0300)
committerThiago Santos <thiagoss@osg.samsung.com>
Mon, 25 May 2015 11:46:18 +0000 (08:46 -0300)
qtdemux creates a samples array and gets the timestamps for buffers by
accumulating their durations. When doing reverse playback of fragments,
accumulating samples will lead to wrong timestamps as the timestamps
should go decreasing from fragment to fragment and the accumulation
will produce wrong results.

In this case, when receiving a discont for fragmented reverse playback,
the previous samples information should be flushed before new data
is processed.

gst/isomp4/qtdemux.c

index f50ff20..5adad74 100644 (file)
@@ -2150,6 +2150,28 @@ gst_qtdemux_stbl_free (QtDemuxStream * stream)
 }
 
 static void
+gst_qtdemux_stream_flush_samples_data (GstQTDemux * qtdemux,
+    QtDemuxStream * stream)
+{
+  g_free (stream->samples);
+  stream->samples = NULL;
+  g_free (stream->segments);
+  stream->segments = NULL;
+  gst_qtdemux_stbl_free (stream);
+
+  /* fragments */
+  g_free (stream->ra_entries);
+  stream->ra_entries = NULL;
+  stream->n_ra_entries = 0;
+
+  stream->sample_index = -1;
+  stream->stbl_index = -1;
+  stream->n_samples = 0;
+  stream->time_position = 0;
+  stream->segment_index = -1;
+}
+
+static void
 gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
 {
   if (stream->allocator)
@@ -2162,29 +2184,16 @@ gst_qtdemux_stream_clear (GstQTDemux * qtdemux, QtDemuxStream * stream)
     gst_memory_unref (stream->rgb8_palette);
     stream->rgb8_palette = NULL;
   }
-  g_free (stream->samples);
-  stream->samples = NULL;
-  g_free (stream->segments);
-  stream->segments = NULL;
+
   if (stream->pending_tags)
     gst_tag_list_unref (stream->pending_tags);
   stream->pending_tags = NULL;
   g_free (stream->redirect_uri);
   stream->redirect_uri = NULL;
-  /* free stbl sub-atoms */
-  gst_qtdemux_stbl_free (stream);
-  /* fragments */
-  g_free (stream->ra_entries);
-  stream->ra_entries = NULL;
-  stream->n_ra_entries = 0;
-
   stream->sent_eos = FALSE;
-  stream->segment_index = -1;
-  stream->time_position = 0;
-  stream->sample_index = -1;
-  stream->stbl_index = -1;
-  stream->n_samples = 0;
   stream->sparse = FALSE;
+
+  gst_qtdemux_stream_flush_samples_data (qtdemux, stream);
 }
 
 static void
@@ -5010,6 +5019,18 @@ gst_qtdemux_chain (GstPad * sinkpad, GstObject * parent, GstBuffer * inbuf)
     for (i = 0; i < demux->n_streams; i++) {
       demux->streams[i]->discont = TRUE;
     }
+
+    /* Reverse fragmented playback, need to flush all we have before
+     * consuming a new fragment.
+     * The samples array have the timestamps calculated by accumulating the
+     * durations but this won't work for reverse playback of fragments as
+     * the timestamps of a subsequent fragment should be smaller than the
+     * previously received one. */
+    if (demux->fragmented && demux->segment.rate < 0) {
+      gst_qtdemux_process_adapter (demux, TRUE);
+      for (i = 0; i < demux->n_streams; i++)
+        gst_qtdemux_stream_flush_samples_data (demux, demux->streams[i]);
+    }
   }
 
   gst_adapter_push (demux->adapter, inbuf);