matroskademux: Improve/optimize seeking

First of all a keyframe seek should be done to the
keyframe right before the requested position and not
to the keyframe that is nearest to the requested position.

Use per track index arrays and use our new binary search function
from core to speed up the search.
This commit is contained in:
Sebastian Dröge 2009-05-11 15:36:46 +02:00
parent 27c57e3e15
commit e4909b37eb
2 changed files with 57 additions and 51 deletions

View file

@ -271,6 +271,9 @@ gst_matroska_track_free (GstMatroskaTrackContext * track)
if (track->pending_tags) if (track->pending_tags)
gst_tag_list_free (track->pending_tags); gst_tag_list_free (track->pending_tags);
if (track->index_table)
g_array_free (track->index_table, TRUE);
g_free (track); g_free (track);
} }
@ -1932,60 +1935,40 @@ gst_matroska_demux_handle_src_query (GstPad * pad, GstQuery * query)
return ret; return ret;
} }
static gint
gst_matroska_index_seek_find (GstMatroskaIndex * i1, GstClockTime * time,
gpointer user_data)
{
if (i1->time < *time)
return -1;
else if (i1->time > *time)
return 1;
else
return 0;
}
static GstMatroskaIndex * static GstMatroskaIndex *
gst_matroskademux_do_index_seek (GstMatroskaDemux * demux, guint track, gst_matroskademux_do_index_seek (GstMatroskaDemux * demux,
gint64 seek_pos, gint64 segment_stop, gboolean keyunit) GstMatroskaTrackContext * track, gint64 seek_pos, gint64 segment_stop,
gboolean keyunit)
{ {
GstMatroskaIndex *entry = NULL; GstMatroskaIndex *entry = NULL;
guint n; GArray *index;
if (!demux->index || !demux->index->len) if (!demux->index || !demux->index->len)
return NULL; return NULL;
/* find entry just before or at the requested position */ /* find entry just before or at the requested position */
for (n = 0; n < demux->index->len; n++) { if (track && track->index_table)
GstMatroskaIndex *index; index = track->index_table;
else
index = demux->index;
index = &g_array_index (demux->index, GstMatroskaIndex, n); entry =
gst_util_array_binary_search (index->data, index->len,
if (index->time <= seek_pos && ((track && index->track == track) || !track)) sizeof (GstMatroskaIndex),
entry = index; (GCompareDataFunc) gst_matroska_index_seek_find, GST_SEARCH_MODE_BEFORE,
else &seek_pos, NULL);
break;
}
if (keyunit) {
/* find index entry closest to the requested position.
* n contains the index of the GstMatroskaIndex after
* entry
*/
if (entry && n < demux->index->len) {
GstMatroskaIndex *index;
GstClockTimeDiff d_this, d_entry;
do {
index = &g_array_index (demux->index, GstMatroskaIndex, n);
} while (n++ < demux->index->len && ((track && index->track == track)
|| !track));
d_entry = GST_CLOCK_DIFF (entry->time, seek_pos);
if (d_entry < 0)
d_entry = -d_entry;
d_this = GST_CLOCK_DIFF (index->time, seek_pos);
if (d_this < 0)
d_this = -d_this;
if (d_this < d_entry &&
(index->time < segment_stop || segment_stop == -1)) {
entry = index;
}
}
}
if (entry == NULL && track)
entry = gst_matroskademux_do_index_seek (demux, 0,
seek_pos, segment_stop, keyunit);
return entry; return entry;
} }
@ -2054,12 +2037,10 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
gint64 cur, stop; gint64 cur, stop;
gint64 segment_start, segment_stop; gint64 segment_start, segment_stop;
gint i; gint i;
guint track = 0; GstMatroskaTrackContext *track = NULL;
if (pad) { if (pad)
GstMatroskaTrackContext *context = gst_pad_get_element_private (pad); track = gst_pad_get_element_private (pad);
track = context->num;
}
gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur,
&stop_type, &stop); &stop_type, &stop);
@ -2079,7 +2060,7 @@ gst_matroska_demux_handle_seek_event (GstMatroskaDemux * demux,
/* check sanity before we start flushing and all that */ /* check sanity before we start flushing and all that */
if (cur_type == GST_SEEK_TYPE_SET) { if (cur_type == GST_SEEK_TYPE_SET) {
GST_OBJECT_LOCK (demux); GST_OBJECT_LOCK (demux);
if (!gst_matroskademux_do_index_seek (demux, 0, cur, -1, FALSE)) { if (!gst_matroskademux_do_index_seek (demux, track, cur, -1, FALSE)) {
GST_DEBUG_OBJECT (demux, "No matching seek entry in index"); GST_DEBUG_OBJECT (demux, "No matching seek entry in index");
GST_OBJECT_UNLOCK (demux); GST_OBJECT_UNLOCK (demux);
return FALSE; return FALSE;
@ -2605,6 +2586,7 @@ gst_matroska_demux_parse_index (GstMatroskaDemux * demux)
GstEbmlRead *ebml = GST_EBML_READ (demux); GstEbmlRead *ebml = GST_EBML_READ (demux);
guint32 id; guint32 id;
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
guint i;
if (demux->index) if (demux->index)
g_array_free (demux->index, TRUE); g_array_free (demux->index, TRUE);
@ -2649,6 +2631,28 @@ gst_matroska_demux_parse_index (GstMatroskaDemux * demux)
/* Sort index by time, smallest time first, for easier searching */ /* Sort index by time, smallest time first, for easier searching */
g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare); g_array_sort (demux->index, (GCompareFunc) gst_matroska_index_compare);
/* Now sort the track specific index entries into their own arrays */
for (i = 0; i < demux->index->len; i++) {
GstMatroskaIndex *idx = &g_array_index (demux->index, GstMatroskaIndex, i);
gint track_num;
GstMatroskaTrackContext *ctx;
if (idx->track == 0)
continue;
track_num = gst_matroska_demux_stream_from_num (demux, idx->track);
if (track_num == -1)
continue;
ctx = g_ptr_array_index (demux->src, track_num);
if (ctx->index_table == NULL)
ctx->index_table =
g_array_sized_new (FALSE, FALSE, sizeof (GstMatroskaIndex), 128);
g_array_append_vals (ctx->index_table, idx, 1);
}
demux->index_parsed = TRUE; demux->index_parsed = TRUE;
return ret; return ret;

View file

@ -465,6 +465,8 @@ struct _GstMatroskaTrackContext {
guint index; guint index;
GstFlowReturn last_flow; GstFlowReturn last_flow;
GArray *index_table;
/* some often-used info */ /* some often-used info */
gchar *codec_id, *codec_name, *name, *language; gchar *codec_id, *codec_name, *name, *language;
gpointer codec_priv; gpointer codec_priv;