From: Robert Swain Date: Fri, 4 Dec 2009 14:13:12 +0000 (+0100) Subject: avidemux: Push mode seeking support X-Git-Tag: RELEASE-0.10.19~84 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3e1ed0c727b3bfd9885ecef24e51294be11e48ad;p=platform%2Fupstream%2Fgst-plugins-good.git avidemux: Push mode seeking support --- diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c index d5c4c2b..3df2670 100644 --- a/gst/avi/gstavidemux.c +++ b/gst/avi/gstavidemux.c @@ -1,6 +1,7 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen * Copyright (C) <2006> Nokia Corporation (contact ) + * Copyright (C) <2009-2010> STEricsson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -104,6 +105,10 @@ static void gst_avi_demux_set_index (GstElement * element, GstIndex * index); static GstIndex *gst_avi_demux_get_index (GstElement * element); static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element, GstStateChange transition); +static void gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi); +static void gst_avi_demux_get_buffer_info (GstAviDemux * avi, + GstAviStream * stream, guint entry_n, GstClockTime * timestamp, + GstClockTime * ts_end, guint64 * offset, guint64 * offset_end); static void gst_avi_demux_parse_idit (GstAviDemux * avi, GstBuffer * buf); @@ -659,6 +664,70 @@ gst_avi_demux_seek_streams (GstAviDemux * avi, guint64 offset, gboolean before) return min; } +static guint +gst_avi_demux_index_entry_offset_search (GstAviIndexEntry * entry, + guint64 * offset) +{ + if (entry->offset < *offset) + return -1; + else if (entry->offset > *offset) + return 1; + return 0; +} + +static guint64 +gst_avi_demux_seek_streams_index (GstAviDemux * avi, guint64 offset, + gboolean before) +{ + GstAviStream *stream; + GstAviIndexEntry *entry; + gint i; + gint64 val, min = offset; + guint index; + + for (i = 0; i < avi->num_streams; i++) { + stream = &avi->stream[i]; + + entry = + gst_util_array_binary_search (stream->index, stream->idx_n, + sizeof (GstAviIndexEntry), + (GCompareDataFunc) gst_avi_demux_index_entry_offset_search, + before ? GST_SEARCH_MODE_BEFORE : GST_SEARCH_MODE_AFTER, &offset, NULL); + + if (entry) + index = entry - stream->index; + + if (before) { + if (entry) { + GST_DEBUG_OBJECT (avi, + "stream %d, previous entry at %" G_GUINT64_FORMAT, i, val); + val = stream->index[index].offset; + if (val < min) + min = val; + } + continue; + } + + if (!entry) { + GST_DEBUG_OBJECT (avi, "no position for stream %d, assuming at start", i); + stream->current_entry = 0; + stream->current_total = 0; + continue; + } + + val = stream->index[index].offset; + GST_DEBUG_OBJECT (avi, "stream %d, next entry at %" G_GUINT64_FORMAT, i, + val); + + gst_avi_demux_get_buffer_info (avi, stream, index, (GstClockTime *) & val, + NULL, NULL, NULL); + stream->current_total = val; + stream->current_entry = index; + } + + return min; +} + #define GST_AVI_SEEK_PUSH_DISPLACE (4 * GST_SECOND) static gboolean @@ -678,7 +747,6 @@ gst_avi_demux_handle_sink_event (GstPad * pad, GstEvent * event) gint64 start, stop, time, offset = 0; gboolean update; GstSegment segment; - GstIndexEntry *entry; /* some debug output */ gst_segment_init (&segment, GST_FORMAT_UNDEFINED); @@ -702,31 +770,53 @@ gst_avi_demux_handle_sink_event (GstPad * pad, GstEvent * event) goto exit; } - if (!avi->element_index) { - GST_WARNING_OBJECT (avi, "no index data, forcing EOS"); - goto eos; - } + if (avi->have_index) { + GstAviIndexEntry *entry; + guint index; + /* FIXME, this code assumes the main stream with keyframes is stream 0, + * which is mostly correct... */ + GstAviStream *stream = &avi->stream[avi->main_stream]; + + /* find the index for start bytes offset, calculate the corresponding + * time and (reget?) start offset in bytes */ + entry = gst_util_array_binary_search (stream->index, + stream->idx_n, sizeof (GstAviIndexEntry), + (GCompareDataFunc) gst_avi_demux_index_entry_offset_search, + GST_SEARCH_MODE_BEFORE, &start, NULL); + + if (entry == NULL) { + index = 0; + } else { + index = entry - stream->index; + } - /* Let's check if we have an index entry for this position */ - entry = gst_index_get_assoc_entry (avi->element_index, avi->index_id, - GST_INDEX_LOOKUP_AFTER, GST_ASSOCIATION_FLAG_NONE, - GST_FORMAT_BYTES, start); + start = stream->index[index].offset; + gst_avi_demux_get_buffer_info (avi, stream, index, + (GstClockTime *) & time, NULL, NULL, NULL); + } else if (avi->element_index) { + GstIndexEntry *entry; + + /* Let's check if we have an index entry for this position */ + entry = gst_index_get_assoc_entry (avi->element_index, avi->index_id, + GST_INDEX_LOOKUP_AFTER, GST_ASSOCIATION_FLAG_NONE, + GST_FORMAT_BYTES, start); + + /* we can not go where we have not yet been before ... */ + if (!entry) { + GST_WARNING_OBJECT (avi, "insufficient index data, forcing EOS"); + goto eos; + } - /* we can not go where we have not yet been before ... */ - if (!entry) { - GST_WARNING_OBJECT (avi, "insufficient index data, forcing EOS"); + gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time); + gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &start); + } else { + GST_WARNING_OBJECT (avi, "no index data, forcing EOS"); goto eos; } offset = start; - gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time); - gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &start); stop = GST_CLOCK_TIME_NONE; - /* compensate for slack */ - if (time) - time += GST_AVI_SEEK_PUSH_DISPLACE; - /* set up segment and send downstream */ gst_segment_set_newsegment_full (&avi->segment, update, rate, arate, GST_FORMAT_TIME, time, stop, time); @@ -742,15 +832,16 @@ gst_avi_demux_handle_sink_event (GstPad * pad, GstEvent * event) /* adjust state for streaming thread accordingly */ avi->offset = offset; - gst_avi_demux_seek_streams (avi, offset, FALSE); + if (avi->have_index) + gst_avi_demux_seek_streams_index (avi, offset, FALSE); + else + gst_avi_demux_seek_streams (avi, offset, FALSE); /* set up streaming thread */ avi->offset = offset; avi->todrop = start - offset; exit: - /* in any case, clear leftover in current segment, if any */ - gst_adapter_clear (avi->adapter); gst_event_unref (event); res = TRUE; break; @@ -1471,51 +1562,77 @@ out_of_mem: } } -#if 0 +/* + * Create and push a flushing seek event upstream + */ +static gboolean +avi_demux_do_push_seek (GstAviDemux * demux, guint64 offset) +{ + GstEvent *event; + gboolean res = 0; + + GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset); + + event = + gst_event_new_seek (1.0, GST_FORMAT_BYTES, + GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset, + GST_SEEK_TYPE_NONE, -1); + + res = gst_pad_push_event (demux->sinkpad, event); + + if (res) + demux->offset = offset; + return res; +} + /* * Read AVI index when streaming */ -static void +static gboolean gst_avi_demux_read_subindexes_push (GstAviDemux * avi) { guint32 tag = 0, size; GstBuffer *buf = NULL; - gint i, n; GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams); - for (n = 0; n < avi->num_streams; n++) { - GstAviStream *stream = &avi->stream[n]; + if (avi->odml_subidxs[avi->odml_subidx] != avi->offset) + return FALSE; - for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) { - if (!gst_avi_demux_peek_chunk (avi, &tag, &size)) - continue; - else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10, - '0' + stream->num % 10)) && - (tag != GST_MAKE_FOURCC ('0' + stream->num / 10, - '0' + stream->num % 10, 'i', 'x'))) { - GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")", - GST_FOURCC_ARGS (tag)); - continue; - } + if (!gst_avi_demux_peek_chunk (avi, &tag, &size)) + return TRUE; - avi->offset += 8 + GST_ROUND_UP_2 (size); + if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + avi->odml_stream / 10, + '0' + avi->odml_stream % 10)) && + (tag != GST_MAKE_FOURCC ('0' + avi->odml_stream / 10, + '0' + avi->odml_stream % 10, 'i', 'x'))) { + GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")", + GST_FOURCC_ARGS (tag)); + return FALSE; + } - buf = gst_buffer_new (); - GST_BUFFER_DATA (buf) = gst_adapter_take (avi->adapter, size); - GST_BUFFER_SIZE (buf) = size; + avi->offset += 8 + GST_ROUND_UP_2 (size); + /* flush chunk header so we get just the 'size' payload data */ + gst_adapter_flush (avi->adapter, 8); + buf = gst_adapter_take_buffer (avi->adapter, size); - if (!gst_avi_demux_parse_subindex (avi, stream, buf)) - continue; - } + if (!gst_avi_demux_parse_subindex (avi, &avi->stream[avi->odml_stream], buf)) + return FALSE; - g_free (stream->indexes); - stream->indexes = NULL; + if (avi->odml_subidxs[++avi->odml_subidx] == GST_BUFFER_OFFSET_NONE) { + avi->odml_subidx = 0; + if (++avi->odml_stream < avi->num_streams) { + avi->odml_subidxs = avi->stream[avi->odml_stream].indexes; + } else { + /* get stream stats now */ + avi->have_index = gst_avi_demux_do_index_stats (avi); + + return TRUE; + } } - /* get stream stats now */ - avi->have_index = gst_avi_demux_do_index_stats (avi); + + return avi_demux_do_push_seek (avi, avi->odml_subidxs[avi->odml_subidx]); } -#endif /* * Read AVI index @@ -2543,6 +2660,89 @@ zero_index: } /* + * gst_avi_demux_stream_index_push: + * @avi: avi demuxer object. + * + * Read index. + */ +static void +gst_avi_demux_stream_index_push (GstAviDemux * avi) +{ + guint64 offset = avi->idx1_offset; + GstBuffer *buf; + guint32 tag; + guint32 size; + + GST_DEBUG ("demux stream index at offset %" G_GUINT64_FORMAT, offset); + + /* get chunk information */ + if (!gst_avi_demux_peek_chunk (avi, &tag, &size)) + return; + + /* check tag first before blindly trying to read 'size' bytes */ + if (tag == GST_RIFF_TAG_LIST) { + /* this is the movi tag */ + GST_DEBUG_OBJECT (avi, "skip LIST chunk, size %" G_GUINT32_FORMAT, + (8 + GST_ROUND_UP_2 (size))); + avi->idx1_offset = offset + 8 + GST_ROUND_UP_2 (size); + /* issue seek to allow chain function to handle it and return! */ + avi_demux_do_push_seek (avi, avi->idx1_offset); + return; + } + + if (tag != GST_RIFF_TAG_idx1) + goto no_index; + + GST_DEBUG ("index found at offset %" G_GUINT64_FORMAT, offset); + + /* flush chunk header */ + gst_adapter_flush (avi->adapter, 8); + /* read chunk payload */ + buf = gst_adapter_take_buffer (avi->adapter, size); + if (!buf) + goto pull_failed; + /* advance offset */ + offset += 8 + GST_ROUND_UP_2 (size); + + GST_DEBUG ("will parse index chunk size %u for tag %" + GST_FOURCC_FORMAT, GST_BUFFER_SIZE (buf), GST_FOURCC_ARGS (tag)); + + avi->offset = avi->first_movi_offset - 8; + gst_avi_demux_parse_index (avi, buf); + +#ifndef GST_DISABLE_GST_DEBUG + /* debug our indexes */ + { + gint i; + GstAviStream *stream; + + for (i = 0; i < avi->num_streams; i++) { + stream = &avi->stream[i]; + GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes", + i, stream->idx_n, stream->total_bytes); + } + } +#endif + return; + + /* ERRORS */ +pull_failed: + { + GST_DEBUG_OBJECT (avi, + "taking data from adapter failed: pos=%" G_GUINT64_FORMAT " size=%u", + offset, size); + return; + } +no_index: + { + GST_WARNING_OBJECT (avi, + "No index data (idx1) after movi chunk, but %" GST_FOURCC_FORMAT, + GST_FOURCC_ARGS (tag)); + return; + } +} + +/* * gst_avi_demux_peek_tag: * * Returns the tag and size of the next chunk @@ -2978,7 +3178,10 @@ gst_avi_demux_stream_header_push (GstAviDemux * avi) switch (ltag) { case GST_RIFF_LIST_movi: gst_adapter_flush (avi->adapter, 12); + if (!avi->first_movi_offset) + avi->first_movi_offset = avi->offset; avi->offset += 12; + avi->idx1_offset = avi->offset + size - 4; goto skipping_done; case GST_RIFF_LIST_INFO: GST_DEBUG ("Found INFO chunk"); @@ -3656,6 +3859,9 @@ gst_avi_demux_move_stream (GstAviDemux * avi, GstAviStream * stream, GST_TIME_ARGS (stream->current_timestamp), GST_TIME_ARGS (stream->current_ts_end), stream->current_offset, stream->current_offset_end); + + GST_DEBUG_OBJECT (avi, "Seeking to offset %" G_GUINT64_FORMAT, + stream->index[index].offset); } /* @@ -3887,102 +4093,181 @@ no_format: } } +/* + * Handle seek event. + */ static gboolean -gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, - GstEvent * event) +avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event) { gdouble rate; GstFormat format; GstSeekFlags flags; - GstSeekType cur_type, stop_type; + GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type; gint64 cur, stop; - gboolean res; - gint64 byte_cur; - gint64 time = 0; - GstIndexEntry *entry; + gboolean keyframe; + GstAviStream *stream; + guint index; + guint n, str_num; + guint64 min_offset; - GST_DEBUG_OBJECT (avi, "doing push-based seek"); + /* check we have the index */ + if (!avi->have_index) { + GST_DEBUG_OBJECT (avi, "no seek index built, seek aborted."); + return FALSE; + } else { + GST_DEBUG_OBJECT (avi, "doing push-based seek with event"); + } gst_event_parse_seek (event, &rate, &format, &flags, &cur_type, &cur, &stop_type, &stop); - if (stop_type != GST_SEEK_TYPE_NONE) - goto unsupported_seek; - stop = -1; + if (format != GST_FORMAT_TIME) { + GstFormat fmt = GST_FORMAT_TIME; + gboolean res = TRUE; - /* only forward streaming and seeking is possible */ - if (rate <= 0) - goto unsupported_seek; + if (cur_type != GST_SEEK_TYPE_NONE) + res = gst_pad_query_convert (pad, format, cur, &fmt, &cur); + if (res && stop_type != GST_SEEK_TYPE_NONE) + res = gst_pad_query_convert (pad, format, stop, &fmt, &stop); + if (!res) { + GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted."); + return FALSE; + } - /* only TIME */ - if (format != GST_FORMAT_TIME) - goto unsupported_format; + format = fmt; + } + GST_DEBUG_OBJECT (avi, + "seek requested: rate %g cur %" GST_TIME_FORMAT " stop %" + GST_TIME_FORMAT, rate, GST_TIME_ARGS (cur), GST_TIME_ARGS (stop)); + /* FIXME: can we do anything with rate!=1.0 */ - /* not really advisable otherwise */ - if ((flags & GST_SEEK_FLAG_FLUSH) == 0) - goto unsupported_seek; + keyframe = !!(flags & GST_SEEK_FLAG_KEY_UNIT); - /* should have index, let's check anyway */ - if (!avi->element_index) - goto abort_seek; + GST_DEBUG_OBJECT (avi, "seek to: %" GST_TIME_FORMAT + " keyframe seeking:%d", GST_TIME_ARGS (cur), keyframe); - /* find reasonable corresponding BYTE position - * note that we have no keyframe info in push mode whatsoever, - * so we can not cater for related stuff in any way */ + /* FIXME, this code assumes the main stream with keyframes is stream 0, + * which is mostly correct... */ + str_num = avi->main_stream; + stream = &avi->stream[avi->main_stream]; - /* some slack aiming for a keyframe */ - if (cur < GST_AVI_SEEK_PUSH_DISPLACE) - cur = 0; - else - cur -= GST_AVI_SEEK_PUSH_DISPLACE; + /* get the entry index for the requested position */ + index = gst_avi_demux_index_for_time (avi, stream, cur); + GST_DEBUG_OBJECT (avi, "Got entry %u", index); - entry = gst_index_get_assoc_entry (avi->element_index, avi->index_id, - GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_TIME, cur); + /* check if we are already on a keyframe */ + if (!ENTRY_IS_KEYFRAME (&stream->index[index])) { + GST_DEBUG_OBJECT (avi, "not keyframe, searching back"); + /* now go to the previous keyframe, this is where we should start + * decoding from. */ + index = gst_avi_demux_index_prev (avi, stream, index, TRUE); + GST_DEBUG_OBJECT (avi, "previous keyframe at %u", index); + } + + gst_avi_demux_get_buffer_info (avi, stream, index, + &stream->current_timestamp, &stream->current_ts_end, + &stream->current_offset, &stream->current_offset_end); - if (!entry) - goto abort_seek; + min_offset = stream->current_offset; + for (n = 0; n < avi->num_streams; n++) { + GstAviStream *str = &avi->stream[n]; + guint idx; + guint64 off; - gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &byte_cur); - gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time); + if (n == avi->main_stream) + continue; - GST_DEBUG_OBJECT (avi, "found index entry for %" GST_TIME_FORMAT - " at %" GST_TIME_FORMAT ", located at offset %" G_GINT64_FORMAT, - GST_TIME_ARGS (cur), GST_TIME_ARGS (time), byte_cur); + /* get the entry index for the requested position */ + idx = gst_avi_demux_index_for_time (avi, str, stream->current_timestamp); + GST_DEBUG_OBJECT (avi, "Got entry %u", idx); + + /* check if we are already on a keyframe */ + if (!ENTRY_IS_KEYFRAME (&str->index[idx])) { + GST_DEBUG_OBJECT (avi, "not keyframe, searching back"); + /* now go to the previous keyframe, this is where we should start + * decoding from. */ + idx = gst_avi_demux_index_prev (avi, str, idx, TRUE); + GST_DEBUG_OBJECT (avi, "previous keyframe at %u", idx); + } - /* adjust offset to be in each stream's region */ - byte_cur = gst_avi_demux_seek_streams (avi, byte_cur, TRUE); + gst_avi_demux_get_buffer_info (avi, str, idx, NULL, NULL, &off, NULL); + if (off < min_offset) { + GST_DEBUG_OBJECT (avi, + "Found an earlier offset at %" G_GUINT64_FORMAT ", str %u", off, n); + min_offset = off; + str_num = n; + stream = str; + index = idx; + } + } - /* let's not try push seeking if target and entry are too far apart */ - if (cur - time > 30 * GST_SECOND) - goto abort_seek; + gst_avi_demux_get_buffer_info (avi, stream, index, + &stream->current_timestamp, &stream->current_ts_end, + &stream->current_offset, &stream->current_offset_end); - GST_DEBUG_OBJECT (avi, "Pushing BYTE seek rate %g, " - "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur, - stop); - /* BYTE seek event */ - event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur, - stop_type, stop); - res = gst_pad_push_event (avi->sinkpad, event); + GST_DEBUG_OBJECT (avi, "Moved to str %u, idx %u, ts %" GST_TIME_FORMAT + ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT + ", off_end %" G_GUINT64_FORMAT, str_num, index, + GST_TIME_ARGS (stream->current_timestamp), + GST_TIME_ARGS (stream->current_ts_end), stream->current_offset, + stream->current_offset_end); - return res; + GST_DEBUG_OBJECT (avi, "Seeking to offset %" G_GUINT64_FORMAT, + stream->index[index].offset); - /* ERRORS */ -abort_seek: - { - GST_DEBUG_OBJECT (avi, "could not determine byte position to seek to, " - "seek aborted."); - return FALSE; - } -unsupported_seek: - { - GST_DEBUG_OBJECT (avi, "unsupported seek, seek aborted."); + if (!avi_demux_do_push_seek (avi, + stream->index[index].offset - (avi->stream[0].indexes ? 8 : 0))) { + GST_DEBUG_OBJECT (avi, "seek event failed!"); return FALSE; } -unsupported_format: - { - GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted."); - return FALSE; + + return TRUE; +} + +/* + * Handle whether we can perform the seek event or if we have to let the chain + * function handle seeks to build the seek indexes first. + */ +static gboolean +gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, + GstEvent * event) +{ + /* check for having parsed index already */ + if (!avi->have_index) { + guint64 offset; + + /* handle the seek event in the chain function */ + avi->state = GST_AVI_DEMUX_SEEK; + + /* copy the event */ + if (avi->event_seek) + gst_event_unref (avi->event_seek); + avi->event_seek = gst_event_ref (event); + + if (!avi->building_index) { + avi->building_index = 1; + if (avi->stream[0].indexes) { + avi->odml_stream = 0; + avi->odml_subidxs = avi->stream[avi->odml_stream].indexes; + offset = avi->odml_subidxs[0]; + } else { + offset = avi->idx1_offset; + } + + /* seek to the first subindex or legacy index */ + GST_INFO_OBJECT (avi, + "Seeking to legacy index/first subindex at %" G_GUINT64_FORMAT, + offset); + return avi_demux_do_push_seek (avi, offset); + } + + /* FIXME: we have to always return true so that we don't block the seek + * thread. + * Note: maybe it is OK to return true if we're still building the index */ + return TRUE; } + + return avi_demux_handle_seek_push (avi, pad, event); } /* @@ -4762,6 +5047,9 @@ gst_avi_demux_chain (GstPad * pad, GstBuffer * buf) avi->stream[i].discont = TRUE; } + if (GST_BUFFER_IS_DISCONT (buf)) + gst_adapter_clear (avi->adapter); + GST_DEBUG ("Store %d bytes in adapter", GST_BUFFER_SIZE (buf)); gst_adapter_push (avi->adapter, buf); @@ -4788,6 +5076,35 @@ gst_avi_demux_chain (GstPad * pad, GstBuffer * buf) } res = gst_avi_demux_stream_data (avi); break; + case GST_AVI_DEMUX_SEEK: + res = GST_FLOW_OK; + + /* obtain and parse indexes */ + if (avi->stream[0].indexes && !gst_avi_demux_read_subindexes_push (avi)) { + /* seek in subindex read function failed */ + res = GST_FLOW_ERROR; + break; + } + if (!avi->stream[0].indexes && !avi->have_index + && avi->avih->flags & GST_RIFF_AVIH_HASINDEX) + gst_avi_demux_stream_index_push (avi); + + if (avi->have_index) { + /* use the indexes now to construct nice durations */ + gst_avi_demux_calculate_durations_from_index (avi); + } else { + /* still parsing indexes */ + break; + } + + /* calculate and perform seek */ + if (!avi_demux_handle_seek_push (avi, avi->sinkpad, avi->event_seek)) { + GST_WARNING ("Push mode seek failed"); + res = GST_FLOW_ERROR; + } + gst_event_unref (avi->event_seek); + avi->state = GST_AVI_DEMUX_MOVI; + break; default: GST_ELEMENT_ERROR (avi, STREAM, FAILED, (NULL), ("Illegal internal state")); diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h index 4bd8330..18768a9 100644 --- a/gst/avi/gstavidemux.h +++ b/gst/avi/gstavidemux.h @@ -129,6 +129,7 @@ typedef enum { GST_AVI_DEMUX_START, GST_AVI_DEMUX_HEADER, GST_AVI_DEMUX_MOVI, + GST_AVI_DEMUX_SEEK, } GstAviDemuxState; typedef enum { @@ -189,6 +190,15 @@ typedef struct _GstAviDemux { GstIndex *element_index; gint index_id; gboolean seekable; + + guint64 first_movi_offset; + guint64 idx1_offset; /* offset in file of list/chunk after movi */ + GstEvent *event_seek; + + gboolean building_index; + guint odml_stream; + guint odml_subidx; + guint64 *odml_subidxs; } GstAviDemux; typedef struct _GstAviDemuxClass {