gst/avi/gstavidemux.*: More attempts to turn this into readable code.

Original commit message from CVS:
* gst/avi/gstavidemux.c: (gst_avi_demux_class_init),
(gst_avi_demux_init), (gst_avi_demux_finalize),
(gst_avi_demux_reset), (gst_avi_demux_index_last),
(gst_avi_demux_index_next), (gst_avi_demux_index_entry_for_time),
(gst_avi_demux_parse_subindex), (gst_avi_demux_parse_index),
(gst_avi_demux_stream_index), (gst_avi_demux_peek_tag),
(gst_avi_demux_next_data_buffer), (gst_avi_demux_stream_scan),
(gst_avi_demux_massage_index),
(gst_avi_demux_calculate_durations_from_index),
(gst_avi_demux_stream_header_pull), (gst_avi_demux_do_seek),
(gst_avi_demux_process_next_entry), (gst_avi_demux_loop),
(gst_avi_demux_chain), (gst_avi_demux_sink_activate),
(gst_avi_demux_change_state):
* gst/avi/gstavidemux.h:
More attempts to turn this into readable code.
Don't leak adapters.
Calculate duration according to index more efficiently.
Don't try to act like we drive the pipeline in chain mode.
This commit is contained in:
Wim Taymans 2006-08-25 16:21:37 +00:00
parent bccaea232b
commit bb82304826
3 changed files with 235 additions and 217 deletions

View File

@ -1,3 +1,24 @@
2006-08-25 Wim Taymans <wim@fluendo.com>
* gst/avi/gstavidemux.c: (gst_avi_demux_class_init),
(gst_avi_demux_init), (gst_avi_demux_finalize),
(gst_avi_demux_reset), (gst_avi_demux_index_last),
(gst_avi_demux_index_next), (gst_avi_demux_index_entry_for_time),
(gst_avi_demux_parse_subindex), (gst_avi_demux_parse_index),
(gst_avi_demux_stream_index), (gst_avi_demux_peek_tag),
(gst_avi_demux_next_data_buffer), (gst_avi_demux_stream_scan),
(gst_avi_demux_massage_index),
(gst_avi_demux_calculate_durations_from_index),
(gst_avi_demux_stream_header_pull), (gst_avi_demux_do_seek),
(gst_avi_demux_process_next_entry), (gst_avi_demux_loop),
(gst_avi_demux_chain), (gst_avi_demux_sink_activate),
(gst_avi_demux_change_state):
* gst/avi/gstavidemux.h:
More attempts to turn this into readable code.
Don't leak adapters.
Calculate duration according to index more efficiently.
Don't try to act like we drive the pipeline in chain mode.
2006-08-25 Wim Taymans <wim@fluendo.com> 2006-08-25 Wim Taymans <wim@fluendo.com>
* ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt): * ext/annodex/gstcmmlutils.c: (gst_cmml_clock_time_from_npt):

View File

@ -69,7 +69,7 @@ static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
static void gst_avi_demux_base_init (GstAviDemuxClass * klass); static void gst_avi_demux_base_init (GstAviDemuxClass * klass);
static void gst_avi_demux_class_init (GstAviDemuxClass * klass); static void gst_avi_demux_class_init (GstAviDemuxClass * klass);
static void gst_avi_demux_init (GstAviDemux * avi); static void gst_avi_demux_init (GstAviDemux * avi);
static void gst_avi_demux_dispose (GObject * object); static void gst_avi_demux_finalize (GObject * object);
static void gst_avi_demux_reset (GstAviDemux * avi); static void gst_avi_demux_reset (GstAviDemux * avi);
@ -172,7 +172,7 @@ gst_avi_demux_class_init (GstAviDemuxClass * klass)
parent_class = g_type_class_peek_parent (klass); parent_class = g_type_class_peek_parent (klass);
gobject_class->dispose = gst_avi_demux_dispose; gobject_class->finalize = gst_avi_demux_finalize;
gstelement_class->change_state = gst_avi_demux_change_state; gstelement_class->change_state = gst_avi_demux_change_state;
} }
@ -187,24 +187,21 @@ gst_avi_demux_init (GstAviDemux * avi)
gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad); gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
gst_pad_set_chain_function (avi->sinkpad, gst_avi_demux_chain); gst_pad_set_chain_function (avi->sinkpad, gst_avi_demux_chain);
gst_avi_demux_reset (avi); avi->adapter = gst_adapter_new ();
avi->index_entries = NULL; gst_avi_demux_reset (avi);
memset (&avi->stream, 0, sizeof (avi->stream));
} }
static void static void
gst_avi_demux_dispose (GObject * object) gst_avi_demux_finalize (GObject * object)
{ {
GstAviDemux *avi = GST_AVI_DEMUX (object); GstAviDemux *avi = GST_AVI_DEMUX (object);
GST_DEBUG ("AVI: Dispose"); GST_DEBUG ("AVI: finalize");
if (avi->adapter) {
g_object_unref (avi->adapter);
avi->adapter = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object); g_object_unref (avi->adapter);
G_OBJECT_CLASS (parent_class)->finalize (object);
} }
static void static void
@ -256,10 +253,26 @@ gst_avi_demux_reset (GstAviDemux * avi)
avi->got_tags = FALSE; avi->got_tags = FALSE;
avi->have_eos = FALSE; avi->have_eos = FALSE;
gst_adapter_clear (avi->adapter);
gst_segment_init (&avi->segment, GST_FORMAT_TIME); gst_segment_init (&avi->segment, GST_FORMAT_TIME);
} }
/* Index helper */ /* Index helper */
static gst_avi_index_entry *
gst_avi_demux_index_last (GstAviDemux * avi, gint stream_nr)
{
gint i;
gst_avi_index_entry *result = NULL;
for (i = avi->index_size - 1; i >= 0; i--) {
if (avi->index_entries[i].stream_nr == stream_nr) {
result = &avi->index_entries[i];
break;
}
}
return result;
}
static gst_avi_index_entry * static gst_avi_index_entry *
gst_avi_demux_index_next (GstAviDemux * avi, gint stream_nr, gint start) gst_avi_demux_index_next (GstAviDemux * avi, gint stream_nr, gint start)
@ -273,7 +286,6 @@ gst_avi_demux_index_next (GstAviDemux * avi, gint stream_nr, gint start)
break; break;
} }
} }
return result; return result;
} }
@ -291,7 +303,7 @@ gst_avi_demux_index_entry_for_time (GstAviDemux * avi,
do { do {
entry = gst_avi_demux_index_next (avi, stream_nr, i + 1); entry = gst_avi_demux_index_next (avi, stream_nr, i + 1);
if (!entry) if (!entry)
return last_entry; break;
i = entry->index_nr; i = entry->index_nr;
@ -902,6 +914,7 @@ gst_avi_demux_parse_subindex (GstElement * element,
baseoff = GST_READ_UINT64_LE (&data[12]); baseoff = GST_READ_UINT64_LE (&data[12]);
entries = g_new (gst_avi_index_entry, num); entries = g_new (gst_avi_index_entry, num);
for (x = 0; x < num; x++) { for (x = 0; x < num; x++) {
gint64 next_ts; gint64 next_ts;
@ -918,8 +931,12 @@ gst_avi_demux_parse_subindex (GstElement * element,
entry->index_nr = x; entry->index_nr = x;
entry->stream_nr = stream->num; entry->stream_nr = stream->num;
/* stream duration unknown, now we can calculate it */
if (stream->idx_duration == -1)
stream->idx_duration = 0;
/* timestamps */ /* timestamps */
entry->ts = stream->total_time; entry->ts = stream->idx_duration;
if (stream->is_vbr) { if (stream->is_vbr) {
/* VBR get next timestamp */ /* VBR get next timestamp */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
@ -938,7 +955,7 @@ gst_avi_demux_parse_subindex (GstElement * element,
stream->total_bytes += entry->size; stream->total_bytes += entry->size;
stream->total_frames++; stream->total_frames++;
stream->total_time = next_ts; stream->idx_duration = next_ts;
entries_list = g_list_prepend (entries_list, entry); entries_list = g_list_prepend (entries_list, entry);
} }
@ -1441,12 +1458,12 @@ gst_avi_demux_parse_index (GstAviDemux * avi,
GST_DEBUG ("Parsing index, %d entries", num); GST_DEBUG ("Parsing index, %d entries", num);
for (i = 0, n = 0; i < num; i++) { for (i = 0, n = 0; i < num; i++) {
gint64 next_ts;
gst_riff_index_entry entry, *_entry; gst_riff_index_entry entry, *_entry;
avi_stream_context *stream; avi_stream_context *stream;
gint stream_nr; gint stream_nr;
gst_avi_index_entry *target; gst_avi_index_entry *target;
GstFormat format; GstFormat format;
gint64 next_ts;
_entry = &((gst_riff_index_entry *) data)[i]; _entry = &((gst_riff_index_entry *) data)[i];
entry.id = GUINT32_FROM_LE (_entry->id); entry.id = GUINT32_FROM_LE (_entry->id);
@ -1487,8 +1504,12 @@ gst_avi_demux_parse_index (GstAviDemux * avi,
target->flags |= GST_RIFF_IF_KEYFRAME; target->flags |= GST_RIFF_IF_KEYFRAME;
} }
/* stream duration unknown, now we can calculate it */
if (stream->idx_duration == -1)
stream->idx_duration = 0;
/* timestamps */ /* timestamps */
target->ts = stream->total_time; target->ts = stream->idx_duration;
if (stream->is_vbr) { if (stream->is_vbr) {
/* VBR stream next timestamp */ /* VBR stream next timestamp */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
@ -1506,8 +1527,8 @@ gst_avi_demux_parse_index (GstAviDemux * avi,
target->frames_before = stream->total_frames; target->frames_before = stream->total_frames;
stream->total_bytes += target->size; stream->total_bytes += target->size;
stream->total_time = next_ts;
stream->total_frames++; stream->total_frames++;
stream->idx_duration = next_ts;
GST_DEBUG_OBJECT (avi, GST_DEBUG_OBJECT (avi,
"Adding index entry %d (%6u), flags %08x, stream %d, size %u " "Adding index entry %d (%6u), flags %08x, stream %d, size %u "
@ -1572,10 +1593,8 @@ gst_avi_demux_stream_index (GstAviDemux * avi,
avi_stream_context *stream; avi_stream_context *stream;
stream = &avi->stream[i]; stream = &avi->stream[i];
GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes, %" GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
GST_TIME_FORMAT " time", i, stream->total_frames, stream->total_bytes);
i, stream->total_frames, stream->total_bytes,
GST_TIME_ARGS (stream->total_time));
} }
return; return;
@ -1749,30 +1768,39 @@ gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag,
{ {
GstFlowReturn res = GST_FLOW_OK; GstFlowReturn res = GST_FLOW_OK;
GstBuffer *buf = NULL; GstBuffer *buf = NULL;
guint bufsize;
res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf); res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
if (res != GST_FLOW_OK) { if (res != GST_FLOW_OK)
GST_DEBUG_OBJECT (avi, "pull_ranged returned %s", gst_flow_get_name (res)); goto pull_failed;
goto beach;
}
if (GST_BUFFER_SIZE (buf) != 8) { bufsize = GST_BUFFER_SIZE (buf);
GST_DEBUG_OBJECT (avi, "got %d bytes which is <> 8 bytes", if (bufsize != 8)
(buf ? GST_BUFFER_SIZE (buf) : 0)); goto wrong_size;
gst_buffer_unref (buf);
return GST_FLOW_ERROR;
}
*tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)); *tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
*size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4); *size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
gst_buffer_unref (buf);
GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %" GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %"
G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag), G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag),
*size, offset + 8, offset + 8 + (gint64) * size); *size, offset + 8, offset + 8 + (gint64) * size);
done:
gst_buffer_unref (buf);
beach:
return res; return res;
/* ERRORS */
pull_failed:
{
GST_DEBUG_OBJECT (avi, "pull_ranged returned %s", gst_flow_get_name (res));
return res;
}
wrong_size:
{
GST_DEBUG_OBJECT (avi, "got %d bytes which is <> 8 bytes", bufsize);
res = GST_FLOW_ERROR;
goto done;
}
} }
/* /*
@ -1787,9 +1815,9 @@ gst_avi_demux_next_data_buffer (GstAviDemux * avi, guint64 * offset,
{ {
guint64 off = *offset; guint64 off = *offset;
guint siz; guint siz;
GstFlowReturn res = GST_FLOW_OK; GstFlowReturn res;
while (1) { do {
res = gst_avi_demux_peek_tag (avi, off, tag, &siz); res = gst_avi_demux_peek_tag (avi, off, tag, &siz);
if (res != GST_FLOW_OK) if (res != GST_FLOW_OK)
break; break;
@ -1800,7 +1828,8 @@ gst_avi_demux_next_data_buffer (GstAviDemux * avi, guint64 * offset,
*size = siz; *size = siz;
break; break;
} }
} } while (TRUE);
return res; return res;
} }
@ -1818,7 +1847,7 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
GstFlowReturn res; GstFlowReturn res;
gst_avi_index_entry *entry, *entries = NULL; gst_avi_index_entry *entry, *entries = NULL;
avi_stream_context *stream; avi_stream_context *stream;
GstFormat format = GST_FORMAT_BYTES; GstFormat format;
guint64 pos = avi->offset; guint64 pos = avi->offset;
guint64 length; guint64 length;
gint64 tmplength; gint64 tmplength;
@ -1829,10 +1858,10 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
/* FIXME: /* FIXME:
* - implement non-seekable source support. * - implement non-seekable source support.
*/ */
GST_LOG_OBJECT (avi, "Creating index %s existing index", GST_LOG_OBJECT (avi, "Creating index %s existing index",
(*index) ? "with" : "without"); (*index) ? "with" : "without");
format = GST_FORMAT_BYTES;
if (!gst_pad_query_peer_duration (avi->sinkpad, &format, &tmplength)) if (!gst_pad_query_peer_duration (avi->sinkpad, &format, &tmplength))
return FALSE; return FALSE;
@ -1844,75 +1873,78 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
if (entry->size & 1) if (entry->size & 1)
pos++; pos++;
if (pos < length) { if (pos >= length) {
GST_LOG_OBJECT (avi, "Incomplete index, seeking to last valid entry @ %" GST_LOG_OBJECT (avi, "Complete index, we're done");
G_GUINT64_FORMAT " of %" G_GUINT64_FORMAT " (%"
G_GUINT64_FORMAT "+%u)", pos, length, entry->offset, entry->size);
} else {
return TRUE; return TRUE;
} }
GST_LOG_OBJECT (avi, "Incomplete index, seeking to last valid entry @ %"
G_GUINT64_FORMAT " of %" G_GUINT64_FORMAT " (%"
G_GUINT64_FORMAT "+%u)", pos, length, entry->offset, entry->size);
} }
while (1) { while (1) {
gint stream_nr; gint stream_nr;
guint size; guint size;
gint64 tmpts, tmpdur; gint64 tmpts, tmpnextts;
if ((res = res = gst_avi_demux_next_data_buffer (avi, &pos, &tag, &size);
gst_avi_demux_next_data_buffer (avi, &pos, &tag, if (res != GST_FLOW_OK)
&size)) != GST_FLOW_OK)
break; break;
/* check valid stream */
stream_nr = CHUNKID_TO_STREAMNR (tag); stream_nr = CHUNKID_TO_STREAMNR (tag);
if (stream_nr >= 0 && stream_nr < avi->num_streams) { if (stream_nr < 0 || stream_nr >= avi->num_streams)
stream = &avi->stream[stream_nr]; goto next;
/* pre-allocate */ stream = &avi->stream[stream_nr];
if (index_size % 1024 == 0) {
entries = g_new (gst_avi_index_entry, 1024);
*alloc_list = g_list_prepend (*alloc_list, entries);
}
entry = &entries[index_size % 1024];
entry->index_nr = index_size++; /* pre-allocate */
entry->stream_nr = stream_nr; if (index_size % 1024 == 0) {
entry->flags = GST_RIFF_IF_KEYFRAME; entries = g_new (gst_avi_index_entry, 1024);
entry->offset = pos - avi->index_offset; *alloc_list = g_list_prepend (*alloc_list, entries);
entry->size = size;
/* timestamps */
format = GST_FORMAT_TIME;
if (stream->is_vbr) {
/* VBR stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames, &format, &tmpts);
entry->ts = tmpts;
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames + 1, &format, &tmpdur);
entry->dur = tmpdur;
} else {
/* constant rate stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes, &format, &tmpts);
entry->ts = tmpts;
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes + entry->size, &format, &tmpdur);
entry->dur = tmpdur;
}
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++;
list = g_list_prepend (list, entry);
GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %"
G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d",
index_size - 1, entry->frames_before, entry->offset,
GST_TIME_ARGS (entry->ts), entry->stream_nr);
} }
entry = &entries[index_size % 1024];
entry->index_nr = index_size++;
entry->stream_nr = stream_nr;
entry->flags = GST_RIFF_IF_KEYFRAME;
entry->offset = pos - avi->index_offset;
entry->size = size;
/* timestamps, get timestamps of two consecutive frames to calculate
* timestamp and duration. */
format = GST_FORMAT_TIME;
if (stream->is_vbr) {
/* VBR stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames, &format, &tmpts);
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames + 1, &format, &tmpnextts);
} else {
/* constant rate stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes, &format, &tmpts);
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes + entry->size, &format, &tmpnextts);
}
entry->ts = tmpts;
entry->dur = tmpnextts - tmpts;
/* stream position */
entry->bytes_before = stream->total_bytes;
stream->total_bytes += entry->size;
entry->frames_before = stream->total_frames;
stream->total_frames++;
stream->idx_duration = tmpnextts;
list = g_list_prepend (list, entry);
GST_DEBUG_OBJECT (avi, "Added index entry %d (in stream: %d), offset %"
G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT " for stream %d",
index_size - 1, entry->frames_before, entry->offset,
GST_TIME_ARGS (entry->ts), entry->stream_nr);
next:
/* update position */ /* update position */
pos += GST_ROUND_UP_2 (size); pos += GST_ROUND_UP_2 (size);
if (pos > length) { if (pos > length) {
@ -2144,12 +2176,6 @@ gst_avi_demux_massage_index (GstAviDemux * avi,
avi->index_entries[i].index_nr, entry->stream_nr, entry->size, avi->index_entries[i].index_nr, entry->stream_nr, entry->size,
entry->offset, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur)); entry->offset, GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (entry->dur));
} }
if (delay) {
for (i = 0; i < avi->num_streams; i++) {
stream = &avi->stream[i];
stream->total_time -= delay;
}
}
GST_LOG_OBJECT (avi, "Freeing original index list"); GST_LOG_OBJECT (avi, "Freeing original index list");
@ -2158,10 +2184,8 @@ gst_avi_demux_massage_index (GstAviDemux * avi,
g_list_free (list); g_list_free (list);
for (i = 0; i < avi->num_streams; i++) { for (i = 0; i < avi->num_streams; i++) {
GST_LOG_OBJECT (avi, "Stream %d, %d frames, %8" G_GUINT64_FORMAT " bytes, %" GST_LOG_OBJECT (avi, "Stream %d, %d frames, %8" G_GUINT64_FORMAT " bytes",
GST_TIME_FORMAT " time", i, i, avi->stream[i].total_frames, avi->stream[i].total_bytes);
avi->stream[i].total_frames, avi->stream[i].total_bytes,
GST_TIME_ARGS (avi->stream[i].total_time));
} }
GST_LOG_OBJECT (avi, "Index massaging done"); GST_LOG_OBJECT (avi, "Index massaging done");
@ -2171,36 +2195,33 @@ static void
gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi) gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi)
{ {
gst_avi_index_entry *entry; gst_avi_index_entry *entry;
gint stream, i; gint stream;
GstClockTime total; GstClockTime total;
total = GST_CLOCK_TIME_NONE; total = GST_CLOCK_TIME_NONE;
/* all streams start at a timestamp 0 */ /* all streams start at a timestamp 0 */
for (stream = 0; stream < avi->num_streams; stream++) { for (stream = 0; stream < avi->num_streams; stream++) {
GstClockTime duration = GST_CLOCK_TIME_NONE; GstClockTime duration, hduration;
GstClockTime hduration;
avi_stream_context *streamc = &avi->stream[stream]; avi_stream_context *streamc = &avi->stream[stream];
gst_riff_strh *strh = streamc->strh; gst_riff_strh *strh = streamc->strh;
/* get header duration */ /* get header duration */
hduration = gst_util_uint64_scale ((guint64) strh->length * hduration = gst_util_uint64_scale ((guint64) strh->length *
strh->scale, GST_SECOND, strh->rate); strh->scale, GST_SECOND, strh->rate);
GST_INFO ("Stream %d duration according to header: %" GST_TIME_FORMAT, GST_INFO ("Stream %d duration according to header: %" GST_TIME_FORMAT,
stream, GST_TIME_ARGS (hduration)); stream, GST_TIME_ARGS (hduration));
/* set duration for the stream */ /* set duration for the stream */
streamc->hdr_duration = hduration; streamc->hdr_duration = hduration;
/* never check the super index */ /* get last index entry to get duration */
if (!streamc->superindex) { if ((entry = gst_avi_demux_index_last (avi, stream)))
i = 0; duration = entry->ts + entry->dur;
/* run over index to get last duration */ else
while ((entry = gst_avi_demux_index_next (avi, stream, i))) { duration = GST_CLOCK_TIME_NONE;
duration = entry->ts + entry->dur;
i++;
}
}
streamc->idx_duration = duration; streamc->idx_duration = duration;
/* now pick a good duration */ /* now pick a good duration */
@ -2510,10 +2531,11 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
GList *index = NULL, *alloc = NULL; GList *index = NULL, *alloc = NULL;
guint offset = 4; guint offset = 4;
gint64 stop; gint64 stop;
GstElement *element = GST_ELEMENT_CAST (avi);
/* the header consists of a 'hdrl' LIST tag */ /* the header consists of a 'hdrl' LIST tag */
if ((res = gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad, res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
&avi->offset, &tag, &buf)) != GST_FLOW_OK) if (res != GST_FLOW_OK)
return res; return res;
else if (tag != GST_RIFF_TAG_LIST) else if (tag != GST_RIFF_TAG_LIST)
goto no_list; goto no_list;
@ -2529,8 +2551,10 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
/* Eat up */ /* Eat up */
gst_buffer_unref (buf); gst_buffer_unref (buf);
if ((res = gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad,
&avi->offset, &tag, &buf)) != GST_FLOW_OK) /* read new chunk */
res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
if (res != GST_FLOW_OK)
return res; return res;
else if (tag != GST_RIFF_TAG_LIST) else if (tag != GST_RIFF_TAG_LIST)
goto no_list; goto no_list;
@ -2539,31 +2563,38 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
} }
/* the hdrl starts with a 'avih' header */ /* the hdrl starts with a 'avih' header */
if (!gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, &sub) || if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub))
tag != GST_RIFF_TAG_avih)
goto no_avih; goto no_avih;
else if (!gst_avi_demux_parse_avih (GST_ELEMENT (avi), sub, &avi->avih)) else if (tag != GST_RIFF_TAG_avih)
goto no_avih;
else if (!gst_avi_demux_parse_avih (element, sub, &avi->avih))
goto invalid_avih; goto invalid_avih;
GST_DEBUG_OBJECT (avi, "AVI header ok, reading elemnts from header"); GST_DEBUG_OBJECT (avi, "AVI header ok, reading elemnts from header");
/* now, read the elements from the header until the end */ /* now, read the elements from the header until the end */
while (gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, &sub)) { while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
/* sub can be NULL on empty tags */ /* sub can be NULL on empty tags */
if (!sub) if (!sub)
continue; continue;
switch (tag) { switch (tag) {
case GST_RIFF_TAG_LIST: case GST_RIFF_TAG_LIST:
{
guint8 *data;
guint32 fourcc;
if (GST_BUFFER_SIZE (sub) < 4) if (GST_BUFFER_SIZE (sub) < 4)
goto next; goto next;
switch (GST_READ_UINT32_LE (GST_BUFFER_DATA (sub))) { data = GST_BUFFER_DATA (sub);
fourcc = GST_READ_UINT32_LE (data);
switch (fourcc) {
case GST_RIFF_LIST_strl: case GST_RIFF_LIST_strl:
if (!(gst_avi_demux_parse_stream (avi, sub))) { if (!(gst_avi_demux_parse_stream (avi, sub)))
GST_DEBUG_OBJECT (avi, "avi_demux_parse_stream failed"); goto parse_stream_failed;
return GST_FLOW_ERROR;
}
goto next; goto next;
case GST_RIFF_LIST_odml: case GST_RIFF_LIST_odml:
gst_avi_demux_parse_odml (avi, sub); gst_avi_demux_parse_odml (avi, sub);
@ -2571,12 +2602,13 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
default: default:
GST_WARNING_OBJECT (avi, GST_WARNING_OBJECT (avi,
"Unknown list %" GST_FOURCC_FORMAT " in AVI header", "Unknown list %" GST_FOURCC_FORMAT " in AVI header",
GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA (sub)))); GST_FOURCC_ARGS (fourcc));
/* fall-through */ /* fall-through */
case GST_RIFF_TAG_JUNK: case GST_RIFF_TAG_JUNK:
goto next; goto next;
} }
break; break;
}
default: default:
GST_WARNING_OBJECT (avi, GST_WARNING_OBJECT (avi,
"Unknown off %d tag %" GST_FOURCC_FORMAT " in AVI header", "Unknown off %d tag %" GST_FOURCC_FORMAT " in AVI header",
@ -2608,14 +2640,14 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
guint size; guint size;
guint32 tag, ltag; guint32 tag, ltag;
if ((res = gst_pad_pull_range (avi->sinkpad, avi->offset, res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
12, &buf)) != GST_FLOW_OK) { if (res != GST_FLOW_OK) {
GST_DEBUG_OBJECT (avi, "pull_ranged returned %s", GST_DEBUG_OBJECT (avi, "pull_ranged returned %s",
gst_flow_get_name (res)); gst_flow_get_name (res));
return res; return res;
} else if (GST_BUFFER_SIZE (buf) < 12) { } else if (GST_BUFFER_SIZE (buf) < 12) {
GST_DEBUG_OBJECT (avi, "got %d bytes which is less than 12 bytes", GST_DEBUG_OBJECT (avi, "got %d bytes which is less than 12 bytes",
(buf ? GST_BUFFER_SIZE (buf) : 0)); GST_BUFFER_SIZE (buf));
gst_buffer_unref (buf); gst_buffer_unref (buf);
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
@ -2630,20 +2662,22 @@ gst_avi_demux_stream_header_pull (GstAviDemux * avi)
case GST_RIFF_LIST_movi: case GST_RIFF_LIST_movi:
goto skipping_done; goto skipping_done;
case GST_RIFF_LIST_INFO: case GST_RIFF_LIST_INFO:
if ((res = gst_riff_read_chunk (GST_ELEMENT (avi), avi->sinkpad, res =
&avi->offset, &tag, &buf)) != GST_FLOW_OK) { gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag,
&buf);
if (res != GST_FLOW_OK) {
GST_DEBUG_OBJECT (avi, "read_chunk returned %s", GST_DEBUG_OBJECT (avi, "read_chunk returned %s",
gst_flow_get_name (res)); gst_flow_get_name (res));
return res; return res;
} else {
sub = gst_buffer_create_sub (buf, 4, GST_BUFFER_SIZE (buf) - 4);
gst_riff_parse_info (GST_ELEMENT (avi), sub, &avi->globaltags);
if (sub) {
gst_buffer_unref (sub);
sub = NULL;
}
gst_buffer_unref (buf);
} }
sub = gst_buffer_create_sub (buf, 4, GST_BUFFER_SIZE (buf) - 4);
gst_riff_parse_info (element, sub, &avi->globaltags);
if (sub) {
gst_buffer_unref (sub);
sub = NULL;
}
gst_buffer_unref (buf);
/* gst_riff_read_chunk() has already advanced avi->offset */ /* gst_riff_read_chunk() has already advanced avi->offset */
break; break;
default: default:
@ -2673,10 +2707,8 @@ skipping_done:
} }
/* this is a fatal error */ /* this is a fatal error */
if (!index) { if (!index)
GST_WARNING ("file without index");
goto no_index; goto no_index;
}
gst_avi_demux_massage_index (avi, index, alloc); gst_avi_demux_massage_index (avi, index, alloc);
gst_avi_demux_calculate_durations_from_index (avi); gst_avi_demux_calculate_durations_from_index (avi);
@ -2689,7 +2721,6 @@ skipping_done:
if (avi->seek_event) if (avi->seek_event)
gst_event_unref (avi->seek_event); gst_event_unref (avi->seek_event);
avi->seek_event = gst_event_new_new_segment avi->seek_event = gst_event_new_new_segment
(FALSE, avi->segment.rate, GST_FORMAT_TIME, (FALSE, avi->segment.rate, GST_FORMAT_TIME,
avi->segment.start, stop, avi->segment.start); avi->segment.start, stop, avi->segment.start);
@ -2702,6 +2733,11 @@ skipping_done:
return GST_FLOW_OK; return GST_FLOW_OK;
/* ERRORS */ /* ERRORS */
parse_stream_failed:
{
GST_DEBUG_OBJECT (avi, "avi_demux_parse_stream failed");
return GST_FLOW_ERROR;
}
no_list: no_list:
{ {
GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
@ -2744,6 +2780,7 @@ no_streams:
} }
no_index: no_index:
{ {
GST_WARNING ("file without index");
g_list_free (index); g_list_free (index);
g_list_foreach (alloc, (GFunc) g_free, NULL); g_list_foreach (alloc, (GFunc) g_free, NULL);
g_list_free (alloc); g_list_free (alloc);
@ -2812,7 +2849,6 @@ gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment)
* to the time of the keyframe. */ * to the time of the keyframe. */
seek_time = avi->index_entries[avi->current_entry].ts; seek_time = avi->index_entries[avi->current_entry].ts;
} }
segment->last_stop = seek_time; segment->last_stop = seek_time;
return TRUE; return TRUE;
@ -3043,10 +3079,9 @@ gst_avi_demux_process_next_entry (GstAviDemux * avi)
gboolean processed = FALSE; gboolean processed = FALSE;
avi_stream_context *stream; avi_stream_context *stream;
gst_avi_index_entry *entry; gst_avi_index_entry *entry;
GstBuffer *buf;
do { do {
GstBuffer *buf;
/* see if we are at the end */ /* see if we are at the end */
if (avi->current_entry >= avi->index_size) if (avi->current_entry >= avi->index_size)
goto eos; goto eos;
@ -3072,6 +3107,7 @@ gst_avi_demux_process_next_entry (GstAviDemux * avi)
goto eos_stop; goto eos_stop;
} }
/* skip empty entries */
if (entry->size == 0 || !stream->pad) { if (entry->size == 0 || !stream->pad) {
GST_DEBUG_OBJECT (avi, "Skipping entry %d (%d, %p)", GST_DEBUG_OBJECT (avi, "Skipping entry %d (%d, %p)",
avi->current_entry - 1, entry->size, stream->pad); avi->current_entry - 1, entry->size, stream->pad);
@ -3081,28 +3117,16 @@ gst_avi_demux_process_next_entry (GstAviDemux * avi)
/* pull in the data */ /* pull in the data */
res = gst_pad_pull_range (avi->sinkpad, entry->offset + res = gst_pad_pull_range (avi->sinkpad, entry->offset +
avi->index_offset, entry->size, &buf); avi->index_offset, entry->size, &buf);
if (res != GST_FLOW_OK) { if (res != GST_FLOW_OK)
GST_DEBUG_OBJECT (avi, goto pull_failed;
"pull range failed: pos=%" G_GUINT64_FORMAT " size=%d",
entry->offset + avi->index_offset, entry->size);
stream->last_flow = res;
goto beach;
}
/* check for short buffers, this is EOS as well */ /* check for short buffers, this is EOS as well */
if (GST_BUFFER_SIZE (buf) < entry->size) { if (GST_BUFFER_SIZE (buf) < entry->size)
GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT goto short_buffer;
", only got %d/%d bytes (truncated file?)", entry->offset +
avi->index_offset, GST_BUFFER_SIZE (buf), entry->size);
gst_buffer_unref (buf);
res = stream->last_flow = GST_FLOW_UNEXPECTED;
goto beach;
}
/* invert the picture if needed */ /* invert the picture if needed */
if (stream->strh->fcc_handler == GST_MAKE_FOURCC ('D', 'I', 'B', ' ')) { if (stream->strh->fcc_handler == GST_MAKE_FOURCC ('D', 'I', 'B', ' '))
buf = gst_avi_demux_invert (stream, buf); buf = gst_avi_demux_invert (stream, buf);
}
/* mark non-keyframes */ /* mark non-keyframes */
if (!(entry->flags & GST_RIFF_IF_KEYFRAME)) if (!(entry->flags & GST_RIFF_IF_KEYFRAME))
@ -3128,7 +3152,7 @@ gst_avi_demux_process_next_entry (GstAviDemux * avi)
res = stream->last_flow = gst_pad_push (stream->pad, buf); res = stream->last_flow = gst_pad_push (stream->pad, buf);
/* mark as processed, we increment the frame and byte counters then /* mark as processed, we increment the frame and byte counters then
* return the GstFlowReturn */ * leave the while loop and return the GstFlowReturn */
processed = TRUE; processed = TRUE;
next: next:
@ -3157,6 +3181,23 @@ eos_stop:
res = stream->last_flow = GST_FLOW_UNEXPECTED; res = stream->last_flow = GST_FLOW_UNEXPECTED;
goto beach; goto beach;
} }
pull_failed:
{
GST_DEBUG_OBJECT (avi,
"pull range failed: pos=%" G_GUINT64_FORMAT " size=%d",
entry->offset + avi->index_offset, entry->size);
stream->last_flow = res;
goto beach;
}
short_buffer:
{
GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT
", only got %d/%d bytes (truncated file?)", entry->offset +
avi->index_offset, GST_BUFFER_SIZE (buf), entry->size);
gst_buffer_unref (buf);
res = stream->last_flow = GST_FLOW_UNEXPECTED;
goto beach;
}
} }
/* /*
@ -3379,7 +3420,6 @@ gst_avi_demux_loop (GstPad * pad)
} }
/* process each index entry in turn */ /* process each index entry in turn */
res = gst_avi_demux_stream_data (avi); res = gst_avi_demux_stream_data (avi);
//res = gst_avi_demux_process_next_entry (avi);
break; break;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
@ -3439,14 +3479,14 @@ gst_avi_demux_chain (GstPad * pad, GstBuffer * buf)
case GST_AVI_DEMUX_START: case GST_AVI_DEMUX_START:
if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) { if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) {
GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res)); GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
goto pause; break;
} }
avi->state = GST_AVI_DEMUX_HEADER; avi->state = GST_AVI_DEMUX_HEADER;
/* fall-through */ /* fall-through */
case GST_AVI_DEMUX_HEADER: case GST_AVI_DEMUX_HEADER:
if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) { if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) {
GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res)); GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
goto pause; break;
} }
/* this gets done in gst_avi_demux_stream_header_push() /* this gets done in gst_avi_demux_stream_header_push()
avi->state = GST_AVI_DEMUX_MOVI; avi->state = GST_AVI_DEMUX_MOVI;
@ -3469,57 +3509,19 @@ gst_avi_demux_chain (GstPad * pad, GstBuffer * buf)
GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state, GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state,
gst_flow_get_name (res)); gst_flow_get_name (res));
/* Get Aggregated flow return */ /* Get Aggregated flow return as the final flow result. */
res = gst_avi_demux_aggregated_flow (avi);
if ((res != GST_FLOW_OK)
&& ((res = gst_avi_demux_aggregated_flow (avi)) != GST_FLOW_OK))
goto pause;
return res;
pause:
GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res));
gst_pad_pause_task (avi->sinkpad);
if (GST_FLOW_IS_FATAL (res) || (res == GST_FLOW_NOT_LINKED)) {
gboolean push_eos = TRUE;
if (res == GST_FLOW_UNEXPECTED) {
/* we completed the segment on EOS. */
avi->segment_running = FALSE;
/* handle end-of-stream/segment */
if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message
(GST_ELEMENT (avi),
gst_message_new_segment_done (GST_OBJECT (avi), GST_FORMAT_TIME,
avi->segment.stop));
push_eos = FALSE;
}
} else {
/* for fatal errors we post an error message */
GST_ELEMENT_ERROR (avi, STREAM, FAILED,
(_("Internal data stream error.")),
("streaming stopped, reason %s", gst_flow_get_name (res)));
}
if (push_eos) {
gst_avi_demux_push_event (avi, gst_event_new_eos ());
}
}
return res; return res;
} }
static gboolean static gboolean
gst_avi_demux_sink_activate (GstPad * sinkpad) gst_avi_demux_sink_activate (GstPad * sinkpad)
{ {
GstAviDemux *avidemux = GST_AVI_DEMUX (gst_pad_get_parent (sinkpad));
if (gst_pad_check_pull_range (sinkpad)) { if (gst_pad_check_pull_range (sinkpad)) {
avidemux->adapter = NULL;
gst_object_unref (avidemux);
return gst_pad_activate_pull (sinkpad, TRUE); return gst_pad_activate_pull (sinkpad, TRUE);
} else { } else {
GST_DEBUG ("going to push (streaming) mode"); GST_DEBUG ("going to push (streaming) mode");
avidemux->adapter = gst_adapter_new ();
gst_object_unref (avidemux);
return gst_pad_activate_push (sinkpad, TRUE); return gst_pad_activate_push (sinkpad, TRUE);
} }
} }
@ -3576,9 +3578,6 @@ gst_avi_demux_change_state (GstElement * element, GstStateChange transition)
switch (transition) { switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_avi_demux_reset (avi); gst_avi_demux_reset (avi);
if (avi->adapter) {
gst_adapter_clear (avi->adapter);
}
break; break;
default: default:
break; break;

View File

@ -85,8 +85,6 @@ typedef struct {
/* stream length */ /* stream length */
guint64 total_bytes; guint64 total_bytes;
guint32 total_frames; guint32 total_frames;
guint64 total_time;
/* stream length according to index */ /* stream length according to index */
GstClockTime idx_duration; GstClockTime idx_duration;
/* stream length according to header */ /* stream length according to header */