diff options
-rw-r--r-- | ChangeLog | 45 | ||||
-rw-r--r-- | ext/flac/gstflacdec.c | 4 | ||||
-rw-r--r-- | gst/avi/gstavidemux.c | 538 | ||||
-rw-r--r-- | gst/avi/gstavidemux.h | 7 | ||||
-rw-r--r-- | gst/flx/gstflxdec.c | 34 |
5 files changed, 502 insertions, 126 deletions
@@ -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); |