summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog45
-rw-r--r--ext/flac/gstflacdec.c4
-rw-r--r--gst/avi/gstavidemux.c538
-rw-r--r--gst/avi/gstavidemux.h7
-rw-r--r--gst/flx/gstflxdec.c34
5 files changed, 502 insertions, 126 deletions
diff --git a/ChangeLog b/ChangeLog
index 75b76db6..a38fdd04 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,48 @@
+2004-09-29 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
+
+ * ext/flac/gstflacdec.c: (gst_flacdec_src_query):
+ Only return true if we actually filled something in. Prevents
+ player applications from showing a random length for flac files.
+ * gst-libs/gst/riff/riff-read.c: (gst_riff_read_class_init),
+ (gst_riff_read_use_event), (gst_riff_read_handle_event),
+ (gst_riff_read_seek), (gst_riff_read_skip), (gst_riff_read_strh),
+ (gst_riff_read_strf_vids_with_data),
+ (gst_riff_read_strf_auds_with_data), (gst_riff_read_strf_iavs):
+ OK, ok, so I implemented event handling. Apparently it's normal
+ that we receive random events at random points without asking
+ for it.
+ * gst/avi/gstavidemux.c: (gst_avi_demux_reset),
+ (gst_avi_demux_src_convert), (gst_avi_demux_handle_src_query),
+ (gst_avi_demux_handle_src_event), (gst_avi_demux_stream_index),
+ (gst_avi_demux_sync), (gst_avi_demux_stream_scan),
+ (gst_avi_demux_massage_index), (gst_avi_demux_stream_header),
+ (gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry),
+ (gst_avi_demux_stream_data), (gst_avi_demux_loop):
+ * gst/avi/gstavidemux.h:
+ Implement non-lineair chunk handling and subchunk processing.
+ The first solves playback of AVI files where the audio and video
+ data of individual buffers that we read are not synchronized.
+ This should not happen according to the wonderful AVI specs, but
+ of course it does happen in reality. It is also a prerequisite for
+ the second. Subchunk processing allows us to cut chunks in small
+ pieces and process each of these pieces separately. This is
+ required because I've seen several AVI files with incredibly large
+ audio chunks, even some files with only one audio chunk for the
+ whole file. This allows for proper playback including seeking.
+ This patch is supposed to fix all AVI A/V sync issues.
+ * gst/flx/gstflxdec.c: (gst_flxdec_class_init),
+ (flx_decode_chunks), (flx_decode_color), (gst_flxdec_loop):
+ Work.
+ * gst/modplug/gstmodplug.cc:
+ Proper return value setting for the query() function.
+ * gst/playback/gstplaybasebin.c: (setup_source):
+ Being in non-playing state (after, e.g., EOS) is not necessarily
+ a bad thing. Allow for that. This fixes playback of short files.
+ They don't actually playback fully now, because the clock already
+ runs. This means that small files (<500kB) with a small length
+ (<2sec) will still not or barely play. Other files, such as mod
+ or flx, will work correctly, however.
+
2004-09-28 Wim Taymans <wim@fluendo.com>
* ext/speex/gstspeex.c: (plugin_init):
diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c
index ace9a4b8..40313317 100644
--- a/ext/flac/gstflacdec.c
+++ b/ext/flac/gstflacdec.c
@@ -700,12 +700,12 @@ gst_flacdec_src_query (GstPad * pad, GstQueryType type,
else
samples = flacdec->stream_samples;
- gst_pad_convert (flacdec->srcpad,
+ res = gst_pad_convert (flacdec->srcpad,
GST_FORMAT_DEFAULT, samples, format, value);
break;
}
case GST_QUERY_POSITION:
- gst_pad_convert (flacdec->srcpad,
+ res = gst_pad_convert (flacdec->srcpad,
GST_FORMAT_DEFAULT, flacdec->total_samples, format, value);
break;
default:
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index 5a006e26..dd06e141 100644
--- a/gst/avi/gstavidemux.c
+++ b/gst/avi/gstavidemux.c
@@ -177,6 +177,7 @@ gst_avi_demux_reset (GstAviDemux * avi)
avi->index_entries = NULL;
}
avi->index_size = 0;
+ avi->current_entry = 0;
avi->num_frames = 0;
avi->us_per_frame = 0;
@@ -310,8 +311,7 @@ gst_avi_demux_src_convert (GstPad * pad,
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_BYTES:
- *dest_value = src_value * stream->strh->rate /
- (stream->strh->scale * GST_SECOND);
+ *dest_value = src_value * stream->bitrate / GST_SECOND;
break;
case GST_FORMAT_DEFAULT:
*dest_value = src_value * stream->strh->rate /
@@ -325,7 +325,7 @@ gst_avi_demux_src_convert (GstPad * pad,
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_TIME:
- *dest_value = ((gfloat) src_value) * GST_SECOND / stream->strh->rate;
+ *dest_value = ((gfloat) src_value) * GST_SECOND / stream->bitrate;
break;
default:
res = FALSE;
@@ -386,9 +386,12 @@ gst_avi_demux_handle_src_query (GstPad * pad,
res = FALSE;
break;
case GST_FORMAT_DEFAULT:
- if (stream->strh->type == GST_RIFF_FCC_auds)
- *value = stream->strh->length * stream->strh->samplesize;
- else if (stream->strh->type == GST_RIFF_FCC_vids)
+ if (stream->strh->type == GST_RIFF_FCC_auds) {
+ if (!stream->strh->samplesize)
+ *value = stream->total_frames;
+ else
+ *value = stream->total_bytes / stream->strh->samplesize;
+ } else if (stream->strh->type == GST_RIFF_FCC_vids)
*value = stream->strh->length;
else
res = FALSE;
@@ -402,20 +405,23 @@ gst_avi_demux_handle_src_query (GstPad * pad,
switch (*format) {
case GST_FORMAT_TIME:
if (stream->strh->type == GST_RIFF_FCC_auds) {
- if (stream->strh->samplesize == 1 && stream->blockalign != 0) {
- *value = stream->current_byte * GST_SECOND /
- (stream->blockalign * stream->strh->rate);
+ if (!stream->strh->samplesize) {
+ *value = GST_SECOND * stream->current_frame *
+ stream->strh->scale / stream->strh->rate;
} else if (stream->bitrate != 0) {
*value = ((gfloat) stream->current_byte) * GST_SECOND /
stream->bitrate;
- } else if (stream->total_frames != 0) {
+ } else if (stream->total_frames != 0 && stream->total_bytes != 0) {
/* calculate timestamps based on video size */
guint64 len = demux->us_per_frame * demux->num_frames *
GST_USECOND;
- *value = len * stream->current_frame / stream->total_frames;
+ if (!stream->strh->samplesize)
+ *value = len * stream->current_frame / stream->total_frames;
+ else
+ *value = len * stream->current_byte / stream->total_bytes;
} else {
- *value = 0;
+ res = FALSE;
}
} else {
if (stream->strh->rate != 0) {
@@ -433,7 +439,7 @@ gst_avi_demux_handle_src_query (GstPad * pad,
case GST_FORMAT_DEFAULT:
if (stream->strh->samplesize &&
stream->strh->type == GST_RIFF_FCC_auds)
- *value = stream->current_byte * stream->strh->samplesize;
+ *value = stream->current_byte / stream->strh->samplesize;
else
*value = stream->current_frame;
break;
@@ -551,6 +557,9 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
avi_stream_context *stream;
+ if (!avi->index_entries)
+ return FALSE;
+
stream = gst_pad_get_element_private (pad);
switch (GST_EVENT_TYPE (event)) {
@@ -596,6 +605,9 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
avi->seek_offset = seek_entry->offset + avi->index_offset;
avi->last_seek = entry->ts;
+ avi->seek_flush =
+ (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH);
+ avi->seek_entry = entry->index_nr;
} else {
GST_DEBUG ("no index entry found for format=%d value=%"
G_GINT64_FORMAT, GST_EVENT_SEEK_FORMAT (event), desired_offset);
@@ -623,7 +635,7 @@ done:
* "Open" a RIFF file.
*/
-gboolean
+static gboolean
gst_avi_demux_stream_init (GstAviDemux * avi)
{
GstRiffRead *riff = GST_RIFF_READ (avi);
@@ -643,7 +655,7 @@ gst_avi_demux_stream_init (GstAviDemux * avi)
* Read 'avih' header.
*/
-gboolean
+static gboolean
gst_avi_demux_stream_avih (GstAviDemux * avi,
guint32 * flags, guint32 * streams)
{
@@ -1003,9 +1015,11 @@ gst_avi_demux_stream_odml (GstAviDemux * avi)
/*
* Seek to index, read it, seek back.
+ * Return value indicates if we can continue processing. It
+ * does not indicate if index-reading succeeded.
*/
-gboolean
+static gboolean
gst_avi_demux_stream_index (GstAviDemux * avi)
{
GstBuffer *buf = NULL;
@@ -1020,7 +1034,11 @@ gst_avi_demux_stream_index (GstAviDemux * avi)
length = gst_bytestream_length (riff->bs);
pos_before = gst_bytestream_tell (riff->bs);
- /* skip movi */
+ /* skip movi
+ *
+ * FIXME:
+ * - we want to add error handling here so we can recover.
+ */
if (!gst_riff_read_skip (riff))
return FALSE;
@@ -1079,7 +1097,7 @@ gst_avi_demux_stream_index (GstAviDemux * avi)
target->index_nr = i;
target->flags = entry.flags;
target->size = entry.size;
- target->offset = entry.offset;
+ target->offset = entry.offset + 8;
/* figure out if the index is 0 based or relative to the MOVI start */
if (i == 0) {
@@ -1102,11 +1120,16 @@ gst_avi_demux_stream_index (GstAviDemux * avi)
/* constant rate stream */
gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes, &format, &target->ts);
+ gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
+ stream->total_bytes + target->size, &format, &target->dur);
} else {
/* VBR stream */
gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames, &format, &target->ts);
+ gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
+ stream->total_frames + 1, &format, &target->dur);
}
+ target->dur -= target->ts;
stream->total_bytes += target->size;
stream->total_frames++;
@@ -1134,20 +1157,323 @@ end:
}
/*
+ * Sync to next data chunk.
+ */
+
+static gboolean
+gst_avi_demux_sync (GstAviDemux * avi, guint32 * ret_tag, gboolean prevent_eos)
+{
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint32 tag;
+ guint64 length = gst_bytestream_length (riff->bs);
+
+ if (gst_bytestream_tell (riff->bs) + 12 >= length)
+ return FALSE;
+
+ /* peek first (for the end of this 'list/movi' section) */
+ if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
+ return FALSE;
+
+ /* if we're at top-level, we didn't read the 'movi'
+ * list tag yet. This can also be 'AVIX' in case of
+ * openDML-2.0 AVI files. Lastly, it might be idx1,
+ * in which case we skip it so we come at EOS. */
+ while (g_list_length (riff->level) < 2) {
+ if (gst_bytestream_tell (riff->bs) + 12 >= length)
+ return FALSE;
+
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+
+ switch (tag) {
+ case GST_RIFF_TAG_LIST:
+ if (!(tag = gst_riff_peek_list (riff)))
+ return FALSE;
+
+ switch (tag) {
+ case GST_RIFF_LIST_AVIX:
+ case GST_RIFF_LIST_movi:
+ if (!gst_riff_read_list (riff, &tag))
+ return FALSE;
+ /* we're now going to read buffers! */
+ break;
+
+ default:
+ GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " before AVI data",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ break;
+ }
+
+ break;
+
+ default:
+ GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " before AVI data",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_idx1:
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ break;
+ }
+ }
+
+ /* And then, we get the data */
+ if (gst_bytestream_tell (riff->bs) + 12 >= length)
+ return FALSE;
+
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+
+ /* Support for rec-list files */
+ switch (tag) {
+ case GST_RIFF_TAG_LIST:
+ if (!(tag = gst_riff_peek_list (riff)))
+ return FALSE;
+ if (tag == GST_RIFF_rec) {
+ /* Simply skip the list */
+ if (!gst_riff_read_list (riff, &tag))
+ return FALSE;
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ }
+ break;
+
+ case GST_RIFF_TAG_JUNK:
+ gst_riff_read_skip (riff);
+ return FALSE;
+ }
+
+ if (ret_tag)
+ *ret_tag = tag;
+
+ return TRUE;
+}
+
+/*
* Scan the file for all chunks to "create" a new index.
+ * Return value indicates if we can continue reading the stream. It
+ * does not say anything about whether we created an index.
*/
-gboolean
+static gboolean
gst_avi_demux_stream_scan (GstAviDemux * avi)
{
- //GstRiffRead *riff = GST_RIFF_READ (avi);
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ gst_avi_index_entry *entry;
+ avi_stream_context *stream;
+ guint64 pos = gst_bytestream_tell (riff->bs);
+ guint32 tag;
+ GstEvent *event;
+
+ /* FIXME:
+ * - implement non-seekable source support.
+ */
+
+ GST_LOG_OBJECT (avi, "Creating index");
+
+ while (gst_avi_demux_sync (avi, &tag, TRUE)) {
+ gint stream_nr = CHUNKID_TO_STREAMNR (tag);
+ guint8 *data;
+ GstFormat format = GST_FORMAT_TIME;
+
+ if (stream_nr < 0 || stream_nr >= avi->num_streams)
+ goto next;
+ stream = &avi->stream[stream_nr];
+
+ /* get chunk size */
+ if (gst_bytestream_peek_bytes (riff->bs, &data, 8) != 8)
+ goto next;
- /* FIXME */
+ /* increase allocated size for index */
+ if (avi->index_size % 256 == 0) {
+ avi->index_entries = g_renew (gst_avi_index_entry,
+ avi->index_entries, avi->index_size + 256);
+ }
+ entry = &avi->index_entries[avi->index_size];
+
+ /* fill in */
+ entry->index_nr = avi->index_size++;
+ entry->stream_nr = stream_nr;
+ entry->flags = 0;
+ entry->offset = gst_bytestream_tell (riff->bs) + 8;
+ entry->size = GST_READ_UINT32_LE (&data[4]);
+
+ /* timestamps */
+ if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
+ /* constant rate stream */
+ gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
+ stream->total_bytes, &format, &entry->ts);
+ gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
+ stream->total_bytes + entry->size, &format, &entry->dur);
+ } else {
+ /* VBR stream */
+ gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
+ stream->total_frames, &format, &entry->ts);
+ gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
+ stream->total_frames + 1, &format, &entry->dur);
+ }
+ entry->dur -= entry->ts;
+
+ /* stream position */
+ entry->bytes_before = stream->total_bytes;
+ stream->total_bytes += entry->size;
+ entry->frames_before = stream->total_frames;
+ stream->total_frames++;
+
+ next:
+ if (!gst_riff_read_skip (riff))
+ break;
+ }
+
+ avi->index_offset = 0;
+
+ /* seek back */
+ if (!(event = gst_riff_read_seek (riff, pos)))
+ return FALSE;
+ gst_event_unref (event);
+
+ GST_LOG_OBJECT (avi, "index created, %d items", avi->index_size);
return TRUE;
}
/*
+ * Massage index.
+ * We're going to go over each entry in the index and finetune
+ * some things we don't like about AVI. For example, a single
+ * chunk might be too long. Also, individual streams might be
+ * out-of-sync. In the first case, we cut the chunk in several
+ * smaller pieces. In the second case, we re-order chunk reading
+ * order. The end result should be a smoother playing AVI.
+ */
+
+static void
+gst_avi_demux_massage_index (GstAviDemux * avi)
+{
+ gst_avi_index_entry *entry;
+ avi_stream_context *stream;
+ gint i;
+
+ /* init frames */
+ for (i = 0; i < avi->num_streams; i++) {
+ stream = &avi->stream[i];
+ if (stream->strh->type == GST_RIFF_FCC_vids)
+ stream->delay = stream->strh->init_frames * GST_SECOND *
+ stream->strh->scale / stream->strh->rate;
+ else
+ stream->delay = GST_SECOND * stream->strh->init_frames *
+ stream->strh->length / (stream->total_frames * stream->bitrate);
+ }
+ for (i = 0; i < avi->index_size; i++) {
+ entry = &avi->index_entries[i];
+
+ if (entry->stream_nr >= avi->num_streams)
+ continue;
+
+ stream = &avi->stream[entry->stream_nr];
+ entry->ts += stream->delay;
+ }
+
+ /* cut chunks in small (seekable) pieces */
+ for (i = 0; i < avi->index_size; i++) {
+ entry = &avi->index_entries[i];
+
+ if (entry->stream_nr >= avi->num_streams)
+ continue;
+
+#define MAX_DURATION (GST_SECOND / 4)
+
+ /* check for max duration of a single buffer. I suppose that
+ * the allocation of index entries could be improved. */
+ stream = &avi->stream[entry->stream_nr];
+ if (entry->dur > MAX_DURATION && stream->strh->type == GST_RIFF_FCC_auds) {
+ guint32 ideal_size = stream->bitrate / 10;
+ gst_avi_index_entry *entries;
+ gint old_size, n, num_added;
+
+ /* copy index */
+ old_size = entry->size;
+ num_added = (entry->size - 1) / ideal_size;
+ avi->index_size += num_added;
+ entries = g_malloc (sizeof (gst_avi_index_entry) * avi->index_size);
+ memcpy (entries, avi->index_entries,
+ sizeof (gst_avi_index_entry) * (entry->index_nr + 1));
+ if (entry->index_nr < avi->index_size - num_added - 1) {
+ memcpy (&entries[entry->index_nr + 1 + num_added],
+ &avi->index_entries[entry->index_nr + 1],
+ (avi->index_size - num_added - entry->index_nr - 1) *
+ sizeof (gst_avi_index_entry));
+ for (n = entry->index_nr + 1 + num_added; n < avi->index_size; n++) {
+ entries[n].index_nr += num_added;
+ if (entries[n].stream_nr == entry->stream_nr)
+ entries[n].frames_before += num_added;
+ }
+ }
+
+ /* new sized index chunks */
+ for (n = entry->index_nr; n < entry->index_nr + num_added + 1; n++) {
+ if (old_size >= ideal_size) {
+ entries[n].size = ideal_size;
+ old_size -= ideal_size;
+ } else
+ entries[n].size = old_size;
+
+ entries[n].dur = GST_SECOND * entries[n].size / stream->bitrate;
+ if (n != entry->index_nr) {
+ memcpy (&entries[n], &entries[n - 1], sizeof (gst_avi_index_entry));
+ entries[n].index_nr++;
+ entries[n].ts += entries[n - 1].dur;
+ entries[n].offset += entries[n - 1].size;
+ entries[n].bytes_before += entries[n - 1].size;
+ entries[n].frames_before++;
+
+ i++;
+ }
+ }
+
+ /* set new pointer */
+ g_free (avi->index_entries);
+ avi->index_entries = entries;
+ }
+ }
+
+ /* re-order for time */
+ for (i = 1; i < avi->index_size; i++) {
+ entry = &avi->index_entries[i];
+
+ if (entry->stream_nr >= avi->num_streams)
+ continue;
+
+ /* check whether to rearrange according to time */
+ while (i > 0 && avi->index_entries[i - 1].stream_nr < avi->num_streams &&
+ (entry->ts < avi->index_entries[i - 1].ts ||
+ (entry->ts == avi->index_entries[i - 1].ts &&
+ entry->stream_nr < avi->index_entries[i - 1].stream_nr))) {
+ gst_avi_index_entry prev_entry;
+
+ /* move around */
+ memcpy (&prev_entry, &avi->index_entries[i - 1],
+ sizeof (gst_avi_index_entry));
+ entry->index_nr--;
+ memcpy (&avi->index_entries[i - 1], entry, sizeof (gst_avi_index_entry));
+ memcpy (entry, &prev_entry, sizeof (gst_avi_index_entry));
+ entry->index_nr++;
+
+ /* update pointer */
+ entry = &avi->index_entries[i - 1];
+ i--;
+ }
+ }
+}
+
+/*
* Read full AVI headers.
*/
@@ -1280,10 +1606,12 @@ gst_avi_demux_stream_header (GstAviDemux * avi)
if (flags & GST_RIFF_AVIH_HASINDEX) {
if (!gst_avi_demux_stream_index (avi))
return FALSE;
- } else {
+ }
+ if (!avi->index_size) {
if (!gst_avi_demux_stream_scan (avi))
return FALSE;
}
+ gst_avi_demux_massage_index (avi);
return TRUE;
}
@@ -1295,23 +1623,24 @@ gst_avi_demux_stream_header (GstAviDemux * avi)
static gboolean
gst_avi_demux_handle_seek (GstAviDemux * avi)
{
- GstRiffRead *riff = GST_RIFF_READ (avi);
guint i;
GstEvent *event;
/* FIXME: if we seek in an openDML file, we will have multiple
* primary levels. Seeking in between those will cause havoc. */
- if (!(event = gst_riff_read_seek (riff, avi->seek_offset)))
- return FALSE;
- gst_event_unref (event);
+ avi->current_entry = avi->seek_entry;
for (i = 0; i < avi->num_streams; i++) {
avi_stream_context *stream = &avi->stream[i];
if (GST_PAD_IS_USABLE (stream->pad)) {
+ if (avi->seek_flush) {
+ event = gst_event_new (GST_EVENT_FLUSH);
+ gst_pad_push (stream->pad, GST_DATA (event));
+ }
event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
- avi->last_seek + stream->delay, NULL);
+ avi->last_seek, NULL);
gst_pad_push (stream->pad, GST_DATA (event));
}
}
@@ -1319,6 +1648,74 @@ gst_avi_demux_handle_seek (GstAviDemux * avi)
return TRUE;
}
+static gboolean
+gst_avi_demux_process_next_entry (GstAviDemux * avi)
+{
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ gboolean processed;
+
+ for (processed = FALSE; !processed;) {
+ if (avi->current_entry >= avi->index_size) {
+ gst_bytestream_seek (riff->bs, 0, GST_SEEK_METHOD_END);
+
+ /* get eos */
+ gst_riff_peek_tag (GST_RIFF_READ (avi), &avi->level_up);
+ gst_pad_event_default (avi->sinkpad, gst_event_new (GST_EVENT_EOS));
+ processed = TRUE;
+ } else {
+ GstBuffer *buf;
+ guint got;
+ gst_avi_index_entry *entry = &avi->index_entries[avi->current_entry++];
+ avi_stream_context *stream;
+
+ if (entry->stream_nr >= avi->num_streams) {
+ continue;
+ }
+
+ stream = &avi->stream[entry->stream_nr];
+
+ if (GST_PAD_IS_USABLE (stream->pad) && entry->size > 0) {
+ guint64 needed_off = entry->offset + avi->index_offset, pos;
+ guint32 remain;
+
+ pos = gst_bytestream_tell (riff->bs);
+ gst_bytestream_get_status (riff->bs, &remain, NULL);
+ if (pos <= needed_off && needed_off - pos <= remain) {
+ gst_bytestream_flush_fast (riff->bs, needed_off - pos);
+ } else {
+ GstEvent *event;
+
+ event = gst_riff_read_seek (riff, needed_off);
+ if (event)
+ gst_event_unref (event);
+ else {
+ GST_ELEMENT_ERROR (avi, RESOURCE, READ, (NULL), (NULL));
+ return FALSE;
+ }
+ }
+ if (!(buf = gst_riff_read_element_data (riff, entry->size, &got))) {
+ return FALSE;
+ }
+ if (entry->flags & GST_RIFF_IF_KEYFRAME) {
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
+ }
+ GST_BUFFER_TIMESTAMP (buf) = entry->ts;
+ GST_BUFFER_DURATION (buf) = entry->dur;
+ GST_DEBUG_OBJECT (avi, "Processing buffer of size %d and time %"
+ GST_TIME_FORMAT " on pad %s",
+ GST_BUFFER_SIZE (buf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
+ gst_pad_get_name (stream->pad));
+ gst_pad_push (stream->pad, GST_DATA (buf));
+ processed = TRUE;
+ }
+ stream->current_frame++;
+ stream->current_byte += entry->size;
+ }
+ }
+
+ return TRUE;
+}
+
/*
* Read data.
*/
@@ -1329,7 +1726,6 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
GstRiffRead *riff = GST_RIFF_READ (avi);
guint32 tag;
guint stream_nr;
- gst_avi_index_entry *entry;
if (avi->seek_offset != (guint64) - 1) {
if (!gst_avi_demux_handle_seek (avi))
@@ -1337,80 +1733,16 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
avi->seek_offset = (guint64) - 1;
}
- /* peek first (for the end of this 'list/movi' section) */
- if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
- return FALSE;
-
- /* if we're at top-level, we didn't read the 'movi'
- * list tag yet. This can also be 'AVIX' in case of
- * openDML-2.0 AVI files. Lastly, it might be idx1,
- * in which case we skip it so we come at EOS. */
- while (g_list_length (riff->level) < 2) {
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
-
- switch (tag) {
- case GST_RIFF_TAG_LIST:
- if (!(tag = gst_riff_peek_list (riff)))
- return FALSE;
-
- switch (tag) {
- case GST_RIFF_LIST_AVIX:
- case GST_RIFF_LIST_movi:
- if (!gst_riff_read_list (riff, &tag))
- return FALSE;
- /* we're now going to read buffers! */
- break;
-
- default:
- GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " before AVI data",
- GST_FOURCC_ARGS (tag));
- /* fall-through */
-
- case GST_RIFF_TAG_JUNK:
- if (!gst_riff_read_skip (riff))
- return FALSE;
- break;
- }
-
- break;
-
- default:
- GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " before AVI data",
- GST_FOURCC_ARGS (tag));
- /* fall-through */
-
- case GST_RIFF_TAG_idx1:
- case GST_RIFF_TAG_JUNK:
- if (!gst_riff_read_skip (riff))
- return FALSE;
- break;
- }
+ /* if we have a avi->index_entries[], we don't want to read
+ * the stream linearly, but seek to the next ts/index_entry. */
+ if (avi->index_entries != NULL) {
+ return gst_avi_demux_process_next_entry (avi);
}
- /* And then, we get the data */
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ if (!gst_avi_demux_sync (avi, &tag, FALSE))
return FALSE;
-
- /* Support for rec-list files */
- switch (tag) {
- case GST_RIFF_TAG_LIST:
- if (!(tag = gst_riff_peek_list (riff)))
- return FALSE;
- if (tag == GST_RIFF_rec) {
- /* Simply skip the list */
- if (!gst_riff_read_list (riff, &tag))
- return FALSE;
- if (!(tag = gst_riff_peek_tag (riff, NULL)))
- return FALSE;
- }
- break;
-
- case GST_RIFF_TAG_JUNK:
- return gst_riff_read_skip (riff);
- }
-
stream_nr = CHUNKID_TO_STREAMNR (tag);
+
if (stream_nr < 0 || stream_nr >= avi->num_streams) {
/* recoverable */
g_warning ("Invalid stream ID %d (" GST_FOURCC_FORMAT ")",
@@ -1429,14 +1761,6 @@ gst_avi_demux_stream_data (GstAviDemux * avi)
/* get time of this buffer */
stream = &avi->stream[stream_nr];
- entry = gst_avi_demux_index_next (avi, stream_nr,
- stream->current_entry + 1, 0);
- if (entry) {
- stream->current_entry = entry->index_nr;
- if (entry->flags & GST_RIFF_IF_KEYFRAME) {
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
- }
- }
format = GST_FORMAT_TIME;
gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &next_ts);
@@ -1487,7 +1811,7 @@ gst_avi_demux_loop (GstElement * element)
if (!gst_avi_demux_stream_header (avi))
return;
avi->state = GST_AVI_DEMUX_MOVI;
- /* fall-through */
+ break;
case GST_AVI_DEMUX_MOVI:
if (!gst_avi_demux_stream_data (avi))
diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h
index 51e785f9..47dd7015 100644
--- a/gst/avi/gstavidemux.h
+++ b/gst/avi/gstavidemux.h
@@ -47,9 +47,9 @@ G_BEGIN_DECLS
typedef struct {
gint index_nr;
gint stream_nr;
- guint64 ts;
+ guint64 ts, dur;
guint32 flags;
- guint32 offset;
+ guint64 offset;
gint size;
guint64 bytes_before;
guint32 frames_before;
@@ -100,6 +100,7 @@ typedef struct _GstAviDemux {
gst_avi_index_entry *index_entries;
guint index_size;
guint64 index_offset;
+ guint current_entry;
/* streams */
guint num_streams;
@@ -114,6 +115,8 @@ typedef struct _GstAviDemux {
/* seeking */
guint64 seek_offset;
guint64 last_seek;
+ gint seek_entry;
+ gboolean seek_flush;
} GstAviDemux;
typedef struct _GstAviDemuxClass {
diff --git a/gst/flx/gstflxdec.c b/gst/flx/gstflxdec.c
index b2694962..3323ca0a 100644
--- a/gst/flx/gstflxdec.c
+++ b/gst/flx/gstflxdec.c
@@ -28,6 +28,9 @@
#define JIFFIE (GST_SECOND/70)
+GST_DEBUG_CATEGORY_STATIC (flxdec_debug);
+#define GST_CAT_DEFAULT flxdec_debug
+
/* flx element information */
static GstElementDetails flxdec_details = {
"FLX Decoder",
@@ -133,6 +136,8 @@ gst_flxdec_class_init (GstFlxDecClass * klass)
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ GST_DEBUG_CATEGORY_INIT (flxdec_debug, "flxdec", 0, "FLX video decoder");
+
gobject_class->set_property = gst_flxdec_set_property;
gobject_class->get_property = gst_flxdec_get_property;
@@ -206,9 +211,8 @@ flx_decode_chunks (GstFlxDec * flxdec, gulong count, gchar * data, gchar * dest)
break;
default:
- g_print ("GstFlxDec: Unimplented chunk type: 0x%02x size: %d\n",
+ GST_WARNING ("Unimplented chunk type: 0x%02x size: %d - skipping",
hdr->id, hdr->size);
- g_print ("GstFlxDec: Skipping...\n");
data += rndalign (hdr->size) - FlxFrameChunkSize;
break;
}
@@ -228,7 +232,7 @@ flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
data += 2;
indx = 0;
- g_print ("GstFlxDec: cmap packs: %d\n", packs);
+ GST_LOG ("GstFlxDec: cmap packs: %d", packs);
while (packs--) {
/* color map index + skip count */
indx += *data++;
@@ -238,7 +242,7 @@ flx_decode_color (GstFlxDec * flxdec, guchar * data, guchar * dest, gint scale)
if (count == 0)
count = 256;
- g_print ("GstFlxDec: cmap count: %d (indx: %d)\n", count, indx);
+ GST_LOG ("GstFlxDec: cmap count: %d (indx: %d)\n", count, indx);
flx_set_palette_vector (flxdec->converter, indx, count, data, scale);
data += (count * 3);
@@ -449,7 +453,7 @@ gst_flxdec_loop (GstElement * element)
databuf = flx_get_data (flxdec, FlxHeaderSize);
if (!databuf) {
- g_print ("empty buffer\n");
+ GST_LOG ("empty buffer");
return;
}
@@ -470,12 +474,12 @@ gst_flxdec_loop (GstElement * element)
}
- g_print ("GstFlxDec: size : %d\n", flxh->size);
- g_print ("GstFlxDec: frames : %d\n", flxh->frames);
- g_print ("GstFlxDec: width : %d\n", flxh->width);
- g_print ("GstFlxDec: height : %d\n", flxh->height);
- g_print ("GstFlxDec: depth : %d\n", flxh->depth);
- g_print ("GstFlxDec: speed : %d\n", flxh->speed);
+ GST_LOG ("size : %d\n", flxh->size);
+ GST_LOG ("frames : %d\n", flxh->frames);
+ GST_LOG ("width : %d\n", flxh->width);
+ GST_LOG ("height : %d\n", flxh->height);
+ GST_LOG ("depth : %d\n", flxh->depth);
+ GST_LOG ("speed : %d\n", flxh->speed);
flxdec->next_time = 0;
@@ -496,10 +500,10 @@ gst_flxdec_loop (GstElement * element)
flx_colorspace_converter_new (flxh->width, flxh->height);
if (flxh->type == FLX_MAGICHDR_FLC || flxh->type == FLX_MAGICHDR_FLX) {
- g_print ("GstFlxDec: (FLC) aspect_dx : %d\n", flxh->aspect_dx);
- g_print ("GstFlxDec: (FLC) aspect_dy : %d\n", flxh->aspect_dy);
- g_print ("GstFlxDec: (FLC) oframe1 : 0x%08x\n", flxh->oframe1);
- g_print ("GstFlxDec: (FLC) oframe2 : 0x%08x\n", flxh->oframe2);
+ GST_LOG ("(FLC) aspect_dx : %d\n", flxh->aspect_dx);
+ GST_LOG ("(FLC) aspect_dy : %d\n", flxh->aspect_dy);
+ GST_LOG ("(FLC) oframe1 : 0x%08x\n", flxh->oframe1);
+ GST_LOG ("(FLC) oframe2 : 0x%08x\n", flxh->oframe2);
}
flxdec->size = (flxh->width * flxh->height);