ext/flac/gstflacdec.c: Only return true if we actually filled something in. Prevents player applications from showing...

Original commit message from CVS:
* 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.
This commit is contained in:
Ronald S. Bultje 2004-09-29 09:45:40 +00:00
parent d737e1dbc4
commit ea118a8d64
5 changed files with 504 additions and 128 deletions

View file

@ -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):

View file

@ -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:

View file

@ -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,19 +1157,322 @@ end:
}
/*
* Scan the file for all chunks to "create" a new index.
* Sync to next data chunk.
*/
gboolean
gst_avi_demux_stream_scan (GstAviDemux * avi)
static gboolean
gst_avi_demux_sync (GstAviDemux * avi, guint32 * ret_tag, gboolean prevent_eos)
{
//GstRiffRead *riff = GST_RIFF_READ (avi);
GstRiffRead *riff = GST_RIFF_READ (avi);
guint32 tag;
guint64 length = gst_bytestream_length (riff->bs);
/* FIXME */
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.
*/
static gboolean
gst_avi_demux_stream_scan (GstAviDemux * 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;
/* 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))

View file

@ -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 {

View file

@ -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);