qtdemux: Parse per sample rather than all at once but build complete index when

seeking
This commit is contained in:
Robert Swain 2009-11-14 15:52:09 +01:00
parent 0c62109d20
commit 4025d7cbd7
2 changed files with 77 additions and 15 deletions

2
common

@ -1 +1 @@
Subproject commit 53a2485bb2a648f38767a310caebe1b2679f0cea Subproject commit 0702fe19e974bc4461b5cfeb5db0e80de00a84d3

View File

@ -386,6 +386,8 @@ static GstCaps *qtdemux_audio_caps (GstQTDemux * qtdemux,
static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux, static GstCaps *qtdemux_sub_caps (GstQTDemux * qtdemux,
QtDemuxStream * stream, guint32 fourcc, const guint8 * data, QtDemuxStream * stream, guint32 fourcc, const guint8 * data,
gchar ** codec_name); gchar ** codec_name);
static gboolean qtdemux_parse_samples (GstQTDemux * qtdemux,
QtDemuxStream * stream, guint32 n);
GType GType
gst_qtdemux_get_type (void) gst_qtdemux_get_type (void)
@ -732,7 +734,8 @@ find_func (QtDemuxSample * s1, guint64 * media_time, gpointer user_data)
return -1; return -1;
} }
/* find the index of the sample that includes the data for @media_time /* find the index of the sample that includes the data for @media_time using a
* binary search
* *
* Returns the index of the sample. * Returns the index of the sample.
*/ */
@ -755,6 +758,37 @@ gst_qtdemux_find_index (GstQTDemux * qtdemux, QtDemuxStream * str,
return index; return index;
} }
/* find the index of the sample that includes the data for @media_time using a
* linear search
*
* Returns the index of the sample.
*/
static guint32
gst_qtdemux_find_index_linear (GstQTDemux * qtdemux, QtDemuxStream * str,
guint64 media_time)
{
QtDemuxSample *result = str->samples;
guint32 index = 0;
if (media_time == result->timestamp)
return index;
result++;
while (index < str->n_samples - 1) {
if (index + 1 > str->stbl_index
&& !qtdemux_parse_samples (qtdemux, str, index + 1)) {
GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!", index + 1);
return -1;
}
if (media_time < result->timestamp)
break;
index++;
result++;
}
return index;
}
/* find the index of the keyframe needed to decode the sample at @index /* find the index of the keyframe needed to decode the sample at @index
* of stream @str. * of stream @str.
* *
@ -1218,9 +1252,21 @@ gst_qtdemux_handle_src_event (GstPad * pad, GstEvent * event)
{ {
gboolean res = TRUE; gboolean res = TRUE;
GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad)); GstQTDemux *qtdemux = GST_QTDEMUX (gst_pad_get_parent (pad));
guint i;
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
/* Build complete index for seeking */
for (i = 0; i < qtdemux->n_streams; i++) {
if (!qtdemux_parse_samples (qtdemux, qtdemux->streams[i],
qtdemux->streams[i]->n_samples - 1)) {
GST_LOG_OBJECT (qtdemux,
"Building complete index of stream %u for seeking failed!", i);
res = FALSE;
gst_event_unref (event);
break;
}
}
if (qtdemux->pullbased) { if (qtdemux->pullbased) {
res = gst_qtdemux_do_seek (qtdemux, pad, event); res = gst_qtdemux_do_seek (qtdemux, pad, event);
} else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) { } else if (qtdemux->state == QTDEMUX_STATE_MOVIE && qtdemux->n_streams) {
@ -1963,19 +2009,24 @@ gst_qtdemux_activate_segment (GstQTDemux * qtdemux, QtDemuxStream * stream,
/* and move to the keyframe before the indicated media time of the /* and move to the keyframe before the indicated media time of the
* segment */ * segment */
if (qtdemux->segment.rate >= 0) { if (qtdemux->segment.rate >= 0) {
index = gst_qtdemux_find_index (qtdemux, stream, start); index = gst_qtdemux_find_index_linear (qtdemux, stream, start);
stream->to_sample = stream->n_samples; stream->to_sample = stream->n_samples;
GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index, ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (start), index,
GST_TIME_ARGS (stream->samples[index].timestamp)); GST_TIME_ARGS (stream->samples[index].timestamp));
} else { } else {
index = gst_qtdemux_find_index (qtdemux, stream, stop); index = gst_qtdemux_find_index_linear (qtdemux, stream, stop);
stream->to_sample = index; stream->to_sample = index;
GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT GST_DEBUG_OBJECT (qtdemux, "moving data pointer to %" GST_TIME_FORMAT
", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index, ", index: %u, pts %" GST_TIME_FORMAT, GST_TIME_ARGS (stop), index,
GST_TIME_ARGS (stream->samples[index].timestamp)); GST_TIME_ARGS (stream->samples[index].timestamp));
} }
/* gst_qtdemux_parse_sample () called from gst_qtdemux_find_index_linear ()
* encountered an error and printed a message so we return appropriately */
if (index == -1)
return FALSE;
/* we're at the right spot */ /* we're at the right spot */
if (index == stream->sample_index) { if (index == stream->sample_index) {
GST_DEBUG_OBJECT (qtdemux, "we are at the right index"); GST_DEBUG_OBJECT (qtdemux, "we are at the right index");
@ -2055,12 +2106,24 @@ gst_qtdemux_prepare_current_sample (GstQTDemux * qtdemux,
/* now get the info for the sample we're at */ /* now get the info for the sample we're at */
sample = &stream->samples[stream->sample_index]; sample = &stream->samples[stream->sample_index];
if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
stream->sample_index);
return FALSE;
}
*timestamp = sample->timestamp + sample->pts_offset; *timestamp = sample->timestamp + sample->pts_offset;
*offset = sample->offset; *offset = sample->offset;
*size = sample->size; *size = sample->size;
*duration = sample->duration; *duration = sample->duration;
*keyframe = stream->all_keyframe || sample->keyframe; *keyframe = stream->all_keyframe || sample->keyframe;
/* update dummy segment duration */
if (stream->sample_index == stream->n_samples - 1 && stream->n_segments == 1) {
stream->segments[0].duration = stream->segments[0].stop_time =
stream->segments[0].media_stop = *timestamp + *duration;
}
return TRUE; return TRUE;
/* special cases */ /* special cases */
@ -2102,6 +2165,12 @@ gst_qtdemux_advance_sample (GstQTDemux * qtdemux, QtDemuxStream * stream)
/* get next sample */ /* get next sample */
sample = &stream->samples[stream->sample_index]; sample = &stream->samples[stream->sample_index];
if (!qtdemux_parse_samples (qtdemux, stream, stream->sample_index)) {
GST_LOG_OBJECT (qtdemux, "Parsing of index %u failed!",
stream->sample_index);
return;
}
/* see if we are past the segment */ /* see if we are past the segment */
if (G_UNLIKELY (sample->timestamp >= segment->media_stop)) if (G_UNLIKELY (sample->timestamp >= segment->media_stop))
goto next_segment; goto next_segment;
@ -4361,19 +4430,12 @@ done:
/* no segments, create one to play the complete trak */ /* no segments, create one to play the complete trak */
if (stream->n_segments == 0) { if (stream->n_segments == 0) {
GstClockTime stream_duration = 0; GstClockTime stream_duration =
gst_util_uint64_scale (stream->duration, GST_SECOND, stream->timescale);
if (stream->segments == NULL) if (stream->segments == NULL)
stream->segments = g_new (QtDemuxSegment, 1); stream->segments = g_new (QtDemuxSegment, 1);
/* samples know best */
if (stream->n_samples > 0) {
stream_duration =
stream->samples[stream->n_samples - 1].timestamp +
stream->samples[stream->n_samples - 1].pts_offset +
stream->samples[stream->n_samples - 1].duration;
}
stream->segments[0].time = 0; stream->segments[0].time = 0;
stream->segments[0].stop_time = stream_duration; stream->segments[0].stop_time = stream_duration;
stream->segments[0].duration = stream_duration; stream->segments[0].duration = stream_duration;
@ -5325,8 +5387,8 @@ qtdemux_parse_trak (GstQTDemux * qtdemux, GNode * trak)
} }
/* collect sample information */ /* collect sample information */
if (!qtdemux_stbl_init (qtdemux, stream, stbl) || if (!qtdemux_stbl_init (qtdemux, stream, stbl)
!qtdemux_parse_samples (qtdemux, stream, stream->n_samples - 1)) || !qtdemux_parse_samples (qtdemux, stream, 0))
goto samples_failed; goto samples_failed;
/* configure segments */ /* configure segments */