matroska: Fix seeking past the end of the file in reverse mode.
authorJan Schmidt <jan@centricular.com>
Fri, 30 Jan 2015 15:30:40 +0000 (02:30 +1100)
committerJan Schmidt <jan@centricular.com>
Fri, 30 Jan 2015 19:15:44 +0000 (06:15 +1100)
Snap to the end of the file when seeking past the end in reverse mode,
and also fix GST_SEEK_TYPE_END and GST_SEEK_TYPE_NONE handling
for the stop position by always seeking on a segment in stream time

gst/matroska/matroska-demux.c
gst/matroska/matroska-parse.c
gst/matroska/matroska-read-common.c
gst/matroska/matroska-read-common.h

index 3356879..9eb7aed 100644 (file)
@@ -1873,10 +1873,15 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
   gboolean update = TRUE;
   gboolean pad_locked = FALSE;
   guint32 seqnum;
+  GstSearchMode snap_dir;
+
+  g_return_val_if_fail (event != NULL, FALSE);
 
   if (pad)
     track = gst_pad_get_element_private (pad);
 
+  GST_DEBUG_OBJECT (demux, "Have seek %" GST_PTR_FORMAT, event);
+
   gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
       &stop_type, &stop);
   seqnum = gst_event_get_seqnum (event);
@@ -1899,25 +1904,29 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
     seeksegment.duration = GST_CLOCK_TIME_NONE;
   }
 
-  if (event) {
-    GST_DEBUG_OBJECT (demux, "configuring seek");
-    gst_segment_do_seek (&seeksegment, rate, format, flags,
-        cur_type, cur, stop_type, stop, &update);
-    /* compensate for clip start time, but only for SET seeks,
-     * otherwise it is already part of the segments */
-    if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) {
-      if (cur_type == GST_SEEK_TYPE_SET) {
-        if (rate > 0.0)
-          seeksegment.position += demux->stream_start_time;
-        seeksegment.start += demux->stream_start_time;
-      }
-      if (stop_type == GST_SEEK_TYPE_SET
-          && GST_CLOCK_TIME_IS_VALID (seeksegment.stop)) {
-        if (rate < 0.0)
-          seeksegment.position += demux->stream_start_time;
-        seeksegment.stop += demux->stream_start_time;
-      }
-    }
+  GST_DEBUG_OBJECT (demux, "configuring seek");
+  /* Subtract stream_start_time so we always seek on a segment
+   * in stream time */
+  if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) {
+    seeksegment.start -= demux->stream_start_time;
+    seeksegment.position -= demux->stream_start_time;
+    if (GST_CLOCK_TIME_IS_VALID (seeksegment.stop))
+      seeksegment.stop -= demux->stream_start_time;
+    else
+      seeksegment.stop = seeksegment.duration;
+  }
+
+  gst_segment_do_seek (&seeksegment, rate, format, flags,
+      cur_type, cur, stop_type, stop, &update);
+
+  /* Restore the clip timestamp offset */
+  if (GST_CLOCK_TIME_IS_VALID (demux->stream_start_time)) {
+    seeksegment.position += demux->stream_start_time;
+    seeksegment.start += demux->stream_start_time;
+    if (!GST_CLOCK_TIME_IS_VALID (seeksegment.stop))
+      seeksegment.stop = seeksegment.duration;
+    if (GST_CLOCK_TIME_IS_VALID (seeksegment.stop))
+      seeksegment.stop += demux->stream_start_time;
   }
 
   /* restore segment duration (if any effect),
@@ -1938,12 +1947,15 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
   /* check sanity before we start flushing and all that */
   snap_next = after && !before;
   if (seeksegment.rate < 0)
-    snap_next = !snap_next;
+    snap_dir = snap_next ? GST_SEARCH_MODE_BEFORE : GST_SEARCH_MODE_AFTER;
+  else
+    snap_dir = snap_next ? GST_SEARCH_MODE_AFTER : GST_SEARCH_MODE_BEFORE;
+
   GST_OBJECT_LOCK (demux);
   track = gst_matroska_read_common_get_seek_track (&demux->common, track);
   if ((entry = gst_matroska_read_common_do_index_seek (&demux->common, track,
               seeksegment.position, &demux->seek_index, &demux->seek_entry,
-              snap_next)) == NULL) {
+              snap_dir)) == NULL) {
     /* pull mode without index can scan later on */
     if (demux->streaming) {
       GST_DEBUG_OBJECT (demux, "No matching seek entry in index");
index 1eeef5c..9abd67f 100644 (file)
@@ -1221,6 +1221,7 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
   GstMatroskaTrackContext *track = NULL;
   GstSegment seeksegment = { 0, };
   gboolean update;
+  GstSearchMode snap_dir;
 
   if (pad)
     track = gst_pad_get_element_private (pad);
@@ -1248,11 +1249,16 @@ gst_matroska_parse_handle_seek_event (GstMatroskaParse * parse,
 
   GST_DEBUG_OBJECT (parse, "New segment %" GST_SEGMENT_FORMAT, &seeksegment);
 
+  if (seeksegment.rate < 0)
+    snap_dir = GST_SEARCH_MODE_AFTER;
+  else
+    snap_dir = GST_SEARCH_MODE_BEFORE;
+
   /* check sanity before we start flushing and all that */
   GST_OBJECT_LOCK (parse);
   if ((entry = gst_matroska_read_common_do_index_seek (&parse->common, track,
               seeksegment.position, &parse->seek_index, &parse->seek_entry,
-              FALSE)) == NULL) {
+              snap_dir)) == NULL) {
     /* pull mode without index can scan later on */
     GST_DEBUG_OBJECT (parse, "No matching seek entry in index");
     GST_OBJECT_UNLOCK (parse);
index 51494a1..f2f1ee1 100644 (file)
@@ -375,30 +375,32 @@ gst_matroska_index_seek_find (GstMatroskaIndex * i1, GstClockTime * time,
 GstMatroskaIndex *
 gst_matroska_read_common_do_index_seek (GstMatroskaReadCommon * common,
     GstMatroskaTrackContext * track, gint64 seek_pos, GArray ** _index,
-    gint * _entry_index, gboolean next)
+    gint * _entry_index, GstSearchMode snap_dir)
 {
   GstMatroskaIndex *entry = NULL;
   GArray *index;
 
-  if (!common->index || !common->index->len)
-    return NULL;
-
   /* find entry just before or at the requested position */
   if (track && track->index_table)
     index = track->index_table;
   else
     index = common->index;
 
+  if (!index || !index->len)
+    return NULL;
+
   entry =
       gst_util_array_binary_search (index->data, index->len,
       sizeof (GstMatroskaIndex),
-      (GCompareDataFunc) gst_matroska_index_seek_find,
-      next ? GST_SEARCH_MODE_AFTER : GST_SEARCH_MODE_BEFORE, &seek_pos, NULL);
+      (GCompareDataFunc) gst_matroska_index_seek_find, snap_dir, &seek_pos,
+      NULL);
 
   if (entry == NULL) {
-    if (next) {
-      return NULL;
+    if (snap_dir == GST_SEARCH_MODE_AFTER) {
+      /* Can only happen with a reverse seek past the end */
+      entry = &g_array_index (index, GstMatroskaIndex, index->len - 1);
     } else {
+      /* Can only happen with a forward seek before the start */
       entry = &g_array_index (index, GstMatroskaIndex, 0);
     }
   }
index 6495e83..de21026 100644 (file)
@@ -110,7 +110,7 @@ gint gst_matroska_index_seek_find (GstMatroskaIndex * i1, GstClockTime * time,
     gpointer user_data);
 GstMatroskaIndex * gst_matroska_read_common_do_index_seek (
     GstMatroskaReadCommon * common, GstMatroskaTrackContext * track, gint64
-    seek_pos, GArray ** _index, gint * _entry_index, gboolean next);
+    seek_pos, GArray ** _index, gint * _entry_index, GstSearchMode snap_dir);
 void gst_matroska_read_common_found_global_tag (GstMatroskaReadCommon * common,
     GstElement * el, GstTagList * taglist);
 gint64 gst_matroska_read_common_get_length (GstMatroskaReadCommon * common);