avi: add support for ODML indexes again

This commit is contained in:
Wim Taymans 2009-09-23 12:56:07 +02:00 committed by Wim Taymans
parent ceb7d66e25
commit 7b9b8343ba

View file

@ -995,7 +995,117 @@ too_small:
} }
} }
#if 0 /* add an entry to the index of a stream. @num should be an estimate of the
* total amount of index entries for all streams and is used to dynamically
* allocate memory for the index entries. */
static inline gboolean
gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
guint num, GstAviIndexEntry * entry)
{
/* ensure index memory */
if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) {
/* we need to make some more room */
if (stream->idx_max == 0) {
/* initial size guess, assume each stream has an equal amount of entries,
* overshoot with at least 8K */
stream->idx_max =
(num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
} else {
stream->idx_max += 8192 / sizeof (GstAviIndexEntry);
GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "expanded index to %u",
stream->idx_max);
}
stream->index = g_try_renew (GstAviIndexEntry, stream->index,
stream->idx_max);
if (G_UNLIKELY (!stream->index))
return FALSE;
}
/* update stream stats and total size */
entry->total = stream->total_bytes;
stream->total_bytes += entry->size;
if (stream->strh->type == GST_RIFF_FCC_auds) {
gint blockalign = stream->strf.auds->blockalign;
if (blockalign > 0)
stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign);
else
stream->total_blocks++;
}
if (ENTRY_IS_KEYFRAME (entry))
stream->n_keyframes++;
/* and add */
GST_LOG_OBJECT (avi,
"Adding stream %u, index entry %d, kf %d, size %u "
", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream->num,
stream->idx_n, ENTRY_IS_KEYFRAME (entry), entry->size, entry->offset,
entry->total);
stream->index[stream->idx_n++] = *entry;
return TRUE;
}
/* collect and debug stats about the indexes for all streams.
* This method is also responsible for filling in the stream duration
* as measured by the amount of index entries. */
static void
gst_avi_demux_do_index_stats (GstAviDemux * avi)
{
guint i;
#ifndef GST_DISABLE_GST_DEBUG
guint total_idx = 0, total_max = 0;
#endif
/* get stream stats now */
for (i = 0; i < avi->num_streams; i++) {
GstAviIndexEntry *entry;
GstAviStream *stream;
guint64 total;
if (G_UNLIKELY (!(stream = &avi->stream[i])))
continue;
if (G_UNLIKELY (!stream->strh))
continue;
if (G_UNLIKELY (!stream->index || stream->idx_n == 0))
continue;
entry = &stream->index[stream->idx_n - 1];
total = entry->total + entry->size;
/* calculate duration */
if (stream->is_vbr) {
/* VBR stream next timestamp */
if (stream->strh->type == GST_RIFF_FCC_auds) {
stream->idx_duration =
avi_stream_convert_frames_to_time_unchecked (stream, total);
} else {
stream->idx_duration =
avi_stream_convert_frames_to_time_unchecked (stream, stream->idx_n);
}
} else {
/* constant rate stream */
stream->idx_duration = avi_stream_convert_bytes_to_time_unchecked (stream,
total);
}
#ifndef GST_DISABLE_GST_DEBUG
total_idx += stream->idx_n;
total_max += stream->idx_max;
#endif
GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, "
"%5u keyframes, entry size = %2u, total size = %10u, allocated %10u",
i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n,
stream->n_keyframes, (guint) sizeof (GstAviIndexEntry),
(guint) (stream->idx_n * sizeof (GstAviIndexEntry)),
(guint) (stream->idx_max * sizeof (GstAviIndexEntry)));
}
#ifndef GST_DISABLE_GST_DEBUG
total_idx *= sizeof (GstAviIndexEntry);
total_max *= sizeof (GstAviIndexEntry);
#endif
GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted",
total_max, total_idx, total_max - total_idx);
}
/* /*
* gst_avi_demux_parse_subindex: * gst_avi_demux_parse_subindex:
* @avi: Avi object * @avi: Avi object
@ -1008,36 +1118,32 @@ too_small:
* found. * found.
* *
* Reads superindex (openDML-2 spec stuff) from the provided data. * Reads superindex (openDML-2 spec stuff) from the provided data.
* The buffer will be discarded after use.
* The buffer should contain a GST_RIFF_TAG_ix?? chunk. * The buffer should contain a GST_RIFF_TAG_ix?? chunk.
* *
* Returns: TRUE on success, FALSE otherwise. Errors are fatal, we * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we
* throw an error, caller should bail out asap. * throw an error, caller should bail out asap.
*/ */
static gboolean static gboolean
gst_avi_demux_parse_subindex (GstAviDemux * avi, gst_avi_demux_parse_subindex (GstAviDemux * avi, GstAviStream * stream,
GstBuffer * buf, GstAviStream * stream, GList ** _entries_list) GstBuffer * buf)
{ {
guint8 *data = GST_BUFFER_DATA (buf); guint8 *data;
guint16 bpe; guint16 bpe;
guint32 num, i; guint32 num, i;
guint64 baseoff; guint64 baseoff;
gst_avi_index_entry *entries, *entry;
GList *entries_list = NULL;
guint size; guint size;
#ifndef GST_DISABLE_GST_DEBUG if (!buf)
gulong _nr_keyframes = 0; return TRUE;
#endif
*_entries_list = NULL; size = GST_BUFFER_SIZE (buf);
size = buf ? GST_BUFFER_SIZE (buf) : 0;
/* check size */ /* check size */
if (size < 24) if (size < 24)
goto too_small; goto too_small;
data = GST_BUFFER_DATA (buf);
/* We don't support index-data yet */ /* We don't support index-data yet */
if (data[3] & 0x80) if (data[3] & 0x80)
goto not_implemented; goto not_implemented;
@ -1059,94 +1165,36 @@ gst_avi_demux_parse_subindex (GstAviDemux * avi,
/* If there's nothing, just return ! */ /* If there's nothing, just return ! */
if (num == 0) if (num == 0)
return TRUE; goto empty_index;
if (!(entries = g_try_new (gst_avi_index_entry, num)))
goto out_of_mem;
GST_INFO_OBJECT (avi, "Parsing subindex, nr_entries = %6d", num); GST_INFO_OBJECT (avi, "Parsing subindex, nr_entries = %6d", num);
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
gint64 next_ts; GstAviIndexEntry entry;
entry = &entries[i];
if (size < 24 + bpe * (i + 1)) if (size < 24 + bpe * (i + 1))
break; break;
/* fill in */ /* fill in offset and size. offset contains the keyframe flag in the
entry->offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]); * upper bit*/
entry->size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]); entry.offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]);
entry->flags = entry.size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]);
(entry->size & 0x80000000) ? 0 : GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; /* handle flags */
entry->size &= ~0x80000000;
entry->index_nr = i;
entry->stream_nr = stream->num;
if (stream->strh->type == GST_RIFF_FCC_auds) { if (stream->strh->type == GST_RIFF_FCC_auds) {
/* all audio frames are keyframes */ /* all audio frames are keyframes */
entry->flags |= GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME; ENTRY_SET_KEYFRAME (&entry);
}
#ifndef GST_DISABLE_GST_DEBUG
if (entry->flags & GST_AVI_INDEX_ENTRY_FLAG_KEYFRAME)
_nr_keyframes++;
#endif
/* stream duration unknown, now we can calculate it */
if (stream->idx_duration == -1)
stream->idx_duration = 0;
/* timestamps */
entry->ts = stream->idx_duration;
if (stream->is_vbr) {
/* VBR stream next timestamp */
if (stream->strh->type == GST_RIFF_FCC_auds) {
next_ts = avi_stream_convert_frames_to_time_unchecked (stream,
stream->total_blocks + 1);
} else {
next_ts = avi_stream_convert_frames_to_time_unchecked (stream,
stream->idx_n + 1);
}
} else { } else {
/* CBR get next timestamp */ /* else read flags */
next_ts = avi_stream_convert_bytes_to_time_unchecked (stream, entry.flags = (entry.size & 0x80000000) ? 0 : GST_AVI_KEYFRAME;
stream->total_bytes + entry->size);
} }
/* duration is next - current */ entry.size &= ~0x80000000;
entry->dur = next_ts - entry->ts;
/* stream position */ /* and add */
entry->bytes_before = stream->total_bytes; if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
entry->frames_before = stream->idx_n; goto out_of_mem;
stream->total_bytes += entry->size;
stream->idx_n++;
if (stream->strh->type == GST_RIFF_FCC_auds) {
if (stream->strf.auds->blockalign > 0)
stream->total_blocks +=
(entry->size + stream->strf.auds->blockalign -
1) / stream->strf.auds->blockalign;
else
stream->total_blocks++;
}
stream->idx_duration = next_ts;
entries_list = g_list_prepend (entries_list, entry);
} }
GST_INFO_OBJECT (avi, "Parsed index, %6u/%6u entries, %5lu keyframes, "
"entry size = %2u, total size = %10d", i, num, _nr_keyframes,
(gint) sizeof (gst_avi_index_entry),
(gint) (i * sizeof (gst_avi_index_entry)));
gst_buffer_unref (buf); gst_buffer_unref (buf);
if (i > 0) {
*_entries_list = g_list_reverse (entries_list);
} else {
g_free (entries);
}
return TRUE; return TRUE;
/* ERRORS */ /* ERRORS */
@ -1154,8 +1202,7 @@ too_small:
{ {
GST_ERROR_OBJECT (avi, GST_ERROR_OBJECT (avi,
"Not enough data to parse subindex (%d available, 24 needed)", size); "Not enough data to parse subindex (%d available, 24 needed)", size);
if (buf) gst_buffer_unref (buf);
gst_buffer_unref (buf);
return TRUE; /* continue */ return TRUE; /* continue */
} }
not_implemented: not_implemented:
@ -1165,33 +1212,35 @@ not_implemented:
gst_buffer_unref (buf); gst_buffer_unref (buf);
return FALSE; return FALSE;
} }
empty_index:
{
GST_DEBUG_OBJECT (avi, "the index is empty");
gst_buffer_unref (buf);
return TRUE;
}
out_of_mem: out_of_mem:
{ {
GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL), GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
("Cannot allocate memory for %u*%u=%u bytes", ("Cannot allocate memory for %u*%u=%u bytes",
(guint) sizeof (gst_avi_index_entry), num, (guint) sizeof (GstAviIndexEntry), num,
(guint) sizeof (gst_avi_index_entry) * num)); (guint) sizeof (GstAviIndexEntry) * num));
gst_buffer_unref (buf); gst_buffer_unref (buf);
return FALSE; return FALSE;
} }
} }
#endif
#if 0 #if 0
/* /*
* Read AVI index when streaming * Read AVI index when streaming
*/ */
static void static void
gst_avi_demux_read_subindexes_push (GstAviDemux * avi, gst_avi_demux_read_subindexes_push (GstAviDemux * avi)
GList ** index, GList ** alloc_list)
{ {
GList *list = NULL;
guint32 tag = 0, size; guint32 tag = 0, size;
GstBuffer *buf = NULL; GstBuffer *buf = NULL;
gint i, n; gint i, n;
GST_DEBUG_OBJECT (avi, "gst_avi_demux_read_subindexes_push for %d streams", GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
avi->num_streams);
for (n = 0; n < avi->num_streams; n++) { for (n = 0; n < avi->num_streams; n++) {
GstAviStream *stream = &avi->stream[n]; GstAviStream *stream = &avi->stream[n];
@ -1214,43 +1263,37 @@ gst_avi_demux_read_subindexes_push (GstAviDemux * avi,
GST_BUFFER_DATA (buf) = gst_adapter_take (avi->adapter, size); GST_BUFFER_DATA (buf) = gst_adapter_take (avi->adapter, size);
GST_BUFFER_SIZE (buf) = size; GST_BUFFER_SIZE (buf) = size;
if (!gst_avi_demux_parse_subindex (avi, buf, stream, &list)) if (!gst_avi_demux_parse_subindex (avi, stream, buf))
continue; continue;
if (list) {
GST_DEBUG_OBJECT (avi, " adding %d entries", g_list_length (list));
*alloc_list = g_list_append (*alloc_list, list->data);
*index = g_list_concat (*index, list);
}
} }
g_free (stream->indexes); g_free (stream->indexes);
stream->indexes = NULL; stream->indexes = NULL;
} }
GST_DEBUG_OBJECT (avi, "index %s", ((*index) ? "!= 0" : "== 0")); /* get stream stats now */
gst_avi_demux_do_index_stats (avi);
avi->have_index = TRUE;
} }
#endif #endif
#if 0
/* /*
* Read AVI index * Read AVI index
*/ */
static void static void
gst_avi_demux_read_subindexes_pull (GstAviDemux * avi, gst_avi_demux_read_subindexes_pull (GstAviDemux * avi)
GList ** index, GList ** alloc_list)
{ {
GList *list = NULL;
guint32 tag; guint32 tag;
GstBuffer *buf; GstBuffer *buf;
gint i, n; gint i, n;
GST_DEBUG_OBJECT (avi, "gst_avi_demux_read_subindexes_pull for %d streams", GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
avi->num_streams);
for (n = 0; n < avi->num_streams; n++) { for (n = 0; n < avi->num_streams; n++) {
GstAviStream *stream = &avi->stream[n]; GstAviStream *stream = &avi->stream[n];
for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) { for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
if (gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad, if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi), avi->sinkpad,
&stream->indexes[i], &tag, &buf) != GST_FLOW_OK) &stream->indexes[i], &tag, &buf) != GST_FLOW_OK)
continue; continue;
else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10, else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
@ -1265,23 +1308,18 @@ gst_avi_demux_read_subindexes_pull (GstAviDemux * avi,
continue; continue;
} }
if (!gst_avi_demux_parse_subindex (avi, buf, stream, &list)) if (!gst_avi_demux_parse_subindex (avi, stream, buf))
continue; continue;
if (list) {
GST_DEBUG_OBJECT (avi, " adding %5d entries, total %2d %5d",
g_list_length (list), g_list_length (*alloc_list),
g_list_length (*index));
*alloc_list = g_list_append (*alloc_list, list->data);
*index = g_list_concat (*index, list);
}
} }
g_free (stream->indexes); g_free (stream->indexes);
stream->indexes = NULL; stream->indexes = NULL;
} }
GST_DEBUG_OBJECT (avi, "index %s", ((*index) ? "!= 0" : "== 0")); /* get stream stats now */
gst_avi_demux_do_index_stats (avi);
avi->have_index = TRUE;
} }
#endif
/* /*
* gst_avi_demux_riff_parse_vprp: * gst_avi_demux_riff_parse_vprp:
@ -2046,117 +2084,6 @@ gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream,
} }
} }
/* collect and debug stats about the indexes for all streams.
* This method is also responsible for filling in the stream duration
* as measured by the amount of index entries. */
static void
gst_avi_demux_do_index_stats (GstAviDemux * avi)
{
guint i;
#ifndef GST_DISABLE_GST_DEBUG
guint total_idx = 0, total_max = 0;
#endif
/* get stream stats now */
for (i = 0; i < avi->num_streams; i++) {
GstAviIndexEntry *entry;
GstAviStream *stream;
guint64 total;
if (G_UNLIKELY (!(stream = &avi->stream[i])))
continue;
if (G_UNLIKELY (!stream->strh))
continue;
if (G_UNLIKELY (!stream->index || stream->idx_n == 0))
continue;
entry = &stream->index[stream->idx_n - 1];
total = entry->total + entry->size;
/* calculate duration */
if (stream->is_vbr) {
/* VBR stream next timestamp */
if (stream->strh->type == GST_RIFF_FCC_auds) {
stream->idx_duration =
avi_stream_convert_frames_to_time_unchecked (stream, total);
} else {
stream->idx_duration =
avi_stream_convert_frames_to_time_unchecked (stream, stream->idx_n);
}
} else {
/* constant rate stream */
stream->idx_duration = avi_stream_convert_bytes_to_time_unchecked (stream,
total);
}
#ifndef GST_DISABLE_GST_DEBUG
total_idx += stream->idx_n;
total_max += stream->idx_max;
#endif
GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, "
"%5u keyframes, entry size = %2u, total size = %10u, allocated %10u",
i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n,
stream->n_keyframes, (guint) sizeof (GstAviIndexEntry),
(guint) (stream->idx_n * sizeof (GstAviIndexEntry)),
(guint) (stream->idx_max * sizeof (GstAviIndexEntry)));
}
#ifndef GST_DISABLE_GST_DEBUG
total_idx *= sizeof (GstAviIndexEntry);
total_max *= sizeof (GstAviIndexEntry);
#endif
GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted",
total_max, total_idx, total_max - total_idx);
}
/* add an entry to the index of a stream. @num should be an estimate of the
* total amount of index entries for all streams and is used to dynamically
* allocate memory for the index entries. */
static inline gboolean
gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
guint num, GstAviIndexEntry * entry)
{
/* ensure index memory */
if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) {
/* we need to make some more room */
if (stream->idx_max == 0) {
/* initial size guess, assume each stream has an equal amount of entries,
* overshoot with at least 8K */
stream->idx_max =
(num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
} else {
stream->idx_max += 8192 / sizeof (GstAviIndexEntry);
GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "expanded index to %u",
stream->idx_max);
}
stream->index = g_try_renew (GstAviIndexEntry, stream->index,
stream->idx_max);
if (G_UNLIKELY (!stream->index))
return FALSE;
}
/* update stream stats and total size */
entry->total = stream->total_bytes;
stream->total_bytes += entry->size;
if (stream->strh->type == GST_RIFF_FCC_auds) {
gint blockalign = stream->strf.auds->blockalign;
if (blockalign > 0)
stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign);
else
stream->total_blocks++;
}
if (ENTRY_IS_KEYFRAME (entry))
stream->n_keyframes++;
/* and add */
GST_LOG_OBJECT (avi,
"Adding stream %u, index entry %d, kf %d, size %u "
", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream->num,
stream->idx_n, ENTRY_IS_KEYFRAME (entry), entry->size, entry->offset,
entry->total);
stream->index[stream->idx_n++] = *entry;
return TRUE;
}
static inline GstAviStream * static inline GstAviStream *
gst_avi_demux_stream_for_id (GstAviDemux * avi, guint32 id) gst_avi_demux_stream_for_id (GstAviDemux * avi, guint32 id)
{ {
@ -2199,7 +2126,7 @@ gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf)
guint32 id; guint32 id;
if (!buf) if (!buf)
goto empty_list; return FALSE;
data = GST_BUFFER_DATA (buf); data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf); size = GST_BUFFER_SIZE (buf);
@ -2265,6 +2192,8 @@ gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf)
n++; n++;
} }
gst_buffer_unref (buf);
/* get stream stats now */ /* get stream stats now */
gst_avi_demux_do_index_stats (avi); gst_avi_demux_do_index_stats (avi);
@ -2281,6 +2210,7 @@ gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf)
empty_list: empty_list:
{ {
GST_DEBUG_OBJECT (avi, "empty index"); GST_DEBUG_OBJECT (avi, "empty index");
gst_buffer_unref (buf);
return FALSE; return FALSE;
} }
out_of_mem: out_of_mem:
@ -2289,6 +2219,7 @@ out_of_mem:
("Cannot allocate memory for %u*%u=%u bytes", ("Cannot allocate memory for %u*%u=%u bytes",
(guint) sizeof (GstAviIndexEntry), num, (guint) sizeof (GstAviIndexEntry), num,
(guint) sizeof (GstAviIndexEntry) * num)); (guint) sizeof (GstAviIndexEntry) * num));
gst_buffer_unref (buf);
return FALSE; return FALSE;
} }
} }
@ -2353,7 +2284,6 @@ gst_avi_demux_stream_index (GstAviDemux * avi)
GST_FOURCC_FORMAT, GST_BUFFER_SIZE (buf), GST_FOURCC_ARGS (tag)); GST_FOURCC_FORMAT, GST_BUFFER_SIZE (buf), GST_FOURCC_ARGS (tag));
gst_avi_demux_parse_index (avi, buf); gst_avi_demux_parse_index (avi, buf);
gst_buffer_unref (buf);
#ifndef GST_DISABLE_GST_DEBUG #ifndef GST_DISABLE_GST_DEBUG
/* debug our indexes */ /* debug our indexes */
@ -2492,7 +2422,7 @@ gst_avi_demux_stream_scan (GstAviDemux * avi)
GstFlowReturn res; GstFlowReturn res;
GstAviStream *stream; GstAviStream *stream;
GstFormat format; GstFormat format;
guint64 pos; guint64 pos = 0;
guint64 length; guint64 length;
gint64 tmplength; gint64 tmplength;
guint32 tag = 0; guint32 tag = 0;
@ -2501,8 +2431,7 @@ gst_avi_demux_stream_scan (GstAviDemux * avi)
/* FIXME: /* FIXME:
* - implement non-seekable source support. * - implement non-seekable source support.
*/ */
GST_DEBUG_OBJECT (avi, GST_DEBUG_OBJECT (avi, "Creating index");
"Creating index starting at offset %" G_GUINT64_FORMAT, pos);
/* get the size of the file */ /* get the size of the file */
format = GST_FORMAT_BYTES; format = GST_FORMAT_BYTES;
@ -3116,13 +3045,11 @@ skipping_done:
GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)", GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)",
avi->num_streams, avi->stream[0].indexes); avi->num_streams, avi->stream[0].indexes);
#if 0
/* create or read stream index (for seeking) */ /* create or read stream index (for seeking) */
if (avi->stream[0].indexes != NULL) { if (avi->stream[0].indexes != NULL) {
/* we read a super index already (gst_avi_demux_parse_superindex() ) */ /* we read a super index already (gst_avi_demux_parse_superindex() ) */
gst_avi_demux_read_subindexes_pull (avi, &index, &alloc); gst_avi_demux_read_subindexes_pull (avi);
} }
#endif
if (!avi->have_index) { if (!avi->have_index) {
if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX) if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX)
gst_avi_demux_stream_index (avi); gst_avi_demux_stream_index (avi);