From 4a77c8a84fe921d754124c87e7a8f16e4f49523c Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Sat, 31 Jan 2015 02:30:40 +1100 Subject: [PATCH] matroska: Fix seeking past the end of the file in reverse mode. 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 | 54 ++++++++++++++++++++++--------------- gst/matroska/matroska-parse.c | 8 +++++- gst/matroska/matroska-read-common.c | 18 +++++++------ gst/matroska/matroska-read-common.h | 2 +- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 3356879..9eb7aed 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -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"); diff --git a/gst/matroska/matroska-parse.c b/gst/matroska/matroska-parse.c index 1eeef5c..9abd67f 100644 --- a/gst/matroska/matroska-parse.c +++ b/gst/matroska/matroska-parse.c @@ -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); diff --git a/gst/matroska/matroska-read-common.c b/gst/matroska/matroska-read-common.c index 51494a1..f2f1ee1 100644 --- a/gst/matroska/matroska-read-common.c +++ b/gst/matroska/matroska-read-common.c @@ -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); } } diff --git a/gst/matroska/matroska-read-common.h b/gst/matroska/matroska-read-common.h index 6495e83..de21026 100644 --- a/gst/matroska/matroska-read-common.h +++ b/gst/matroska/matroska-read-common.h @@ -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); -- 2.7.4