gst/avi/gstavidemux.*: Some cleanups, prepare to use GstSegment.

Original commit message from CVS:
* gst/avi/gstavidemux.c: (gst_avi_demux_reset),
(gst_avi_demux_index_next), (gst_avi_demux_handle_src_query),
(gst_avi_demux_handle_src_event), (gst_avi_demux_parse_subindex),
(gst_avi_demux_parse_stream), (gst_avi_demux_parse_index),
(gst_avi_demux_stream_index), (gst_avi_demux_stream_scan),
(gst_avi_demux_massage_index),
(gst_avi_demux_calculate_durations_from_index),
(gst_avi_demux_push_event), (gst_avi_demux_stream_header),
(gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry),
(gst_avi_demux_loop):
* gst/avi/gstavidemux.h:
Some cleanups, prepare to use GstSegment.
Fix error in entry walking code.
Fix VBR detection.
Smarter timestamp calculation code.
Uniform error/eos handling.
This commit is contained in:
Wim Taymans 2006-05-12 18:04:22 +00:00
parent 26c9baa830
commit 50d7e0f6bb
3 changed files with 179 additions and 145 deletions

View file

@ -1,3 +1,22 @@
2006-05-12 Wim Taymans <wim@fluendo.com>
* gst/avi/gstavidemux.c: (gst_avi_demux_reset),
(gst_avi_demux_index_next), (gst_avi_demux_handle_src_query),
(gst_avi_demux_handle_src_event), (gst_avi_demux_parse_subindex),
(gst_avi_demux_parse_stream), (gst_avi_demux_parse_index),
(gst_avi_demux_stream_index), (gst_avi_demux_stream_scan),
(gst_avi_demux_massage_index),
(gst_avi_demux_calculate_durations_from_index),
(gst_avi_demux_push_event), (gst_avi_demux_stream_header),
(gst_avi_demux_handle_seek), (gst_avi_demux_process_next_entry),
(gst_avi_demux_loop):
* gst/avi/gstavidemux.h:
Some cleanups, prepare to use GstSegment.
Fix error in entry walking code.
Fix VBR detection.
Smarter timestamp calculation code.
Uniform error/eos handling.
2006-05-12 Michael Smith <msmith@fluendo.com> 2006-05-12 Michael Smith <msmith@fluendo.com>
* gst/wavparse/gstwavparse.c: (gst_wavparse_fmt), * gst/wavparse/gstwavparse.c: (gst_wavparse_fmt),

View file

@ -218,25 +218,25 @@ gst_avi_demux_reset (GstAviDemux * avi)
gst_event_unref (avi->seek_event); gst_event_unref (avi->seek_event);
avi->seek_event = NULL; avi->seek_event = NULL;
avi->segment_rate = 1.0; gst_segment_init (&avi->segment, GST_FORMAT_TIME);
avi->segment_flags = 0;
avi->segment_start = -1;
avi->segment_stop = -1;
} }
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)
{ {
gint i; gint i;
gst_avi_index_entry *entry = NULL; gst_avi_index_entry *result = NULL;
for (i = start; i < avi->index_size; i++) { for (i = start; i < avi->index_size; i++) {
entry = &avi->index_entries[i]; gst_avi_index_entry *entry = &avi->index_entries[i];
if (entry->stream_nr == stream_nr)
if (entry->stream_nr == stream_nr) {
result = entry;
break; break;
}
} }
return entry; return result;
} }
static gst_avi_index_entry * static gst_avi_index_entry *
@ -401,23 +401,25 @@ gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query)
gint64 pos = 0; gint64 pos = 0;
if (stream->strh->type == GST_RIFF_FCC_auds) { if (stream->strh->type == GST_RIFF_FCC_auds) {
if (!stream->strh->samplesize) { if (!stream->is_vbr) {
/* CBR */
pos = gst_util_uint64_scale_int ((gint64) stream->current_frame * pos = gst_util_uint64_scale_int ((gint64) stream->current_frame *
stream->strh->scale, GST_SECOND, stream->strh->rate); stream->strh->scale, GST_SECOND, stream->strh->rate);
} else if (stream->strf.auds->av_bps != 0) { } else if (stream->strf.auds->av_bps != 0) {
/* VBR */
pos = gst_util_uint64_scale_int (stream->current_byte, GST_SECOND, pos = gst_util_uint64_scale_int (stream->current_byte, GST_SECOND,
stream->strf.auds->av_bps); stream->strf.auds->av_bps);
} else if (stream->total_frames != 0 && stream->total_bytes != 0) { } else if (stream->total_frames != 0 && stream->total_bytes != 0) {
/* calculate timestamps based on video size */ /* calculate timestamps based on percentage of length */
guint64 xlen = demux->avih->us_frame * guint64 xlen = demux->avih->us_frame *
demux->avih->tot_frames * GST_USECOND; demux->avih->tot_frames * GST_USECOND;
if (!stream->strh->samplesize) if (stream->is_vbr)
pos = gst_util_uint64_scale_int (xlen, stream->current_frame,
stream->total_frames);
else
pos = gst_util_uint64_scale_int (xlen, stream->current_byte, pos = gst_util_uint64_scale_int (xlen, stream->current_byte,
stream->total_bytes); stream->total_bytes);
else
pos = gst_util_uint64_scale_int (xlen, stream->current_frame,
stream->total_frames);
} else { } else {
res = FALSE; res = FALSE;
} }
@ -535,13 +537,13 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
switch (start_type) { switch (start_type) {
case GST_SEEK_TYPE_CUR: case GST_SEEK_TYPE_CUR:
tstart = avi->segment_start + tstart; tstart = avi->segment.start + tstart;
break; break;
case GST_SEEK_TYPE_END: case GST_SEEK_TYPE_END:
tstart = duration + tstart; tstart = duration + tstart;
break; break;
case GST_SEEK_TYPE_NONE: case GST_SEEK_TYPE_NONE:
tstart = avi->segment_start; tstart = avi->segment.start;
update_start = FALSE; update_start = FALSE;
break; break;
case GST_SEEK_TYPE_SET: case GST_SEEK_TYPE_SET:
@ -551,13 +553,13 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
switch (stop_type) { switch (stop_type) {
case GST_SEEK_TYPE_CUR: case GST_SEEK_TYPE_CUR:
tstop = avi->segment_stop + tstop; tstop = avi->segment.stop + tstop;
break; break;
case GST_SEEK_TYPE_END: case GST_SEEK_TYPE_END:
tstop = duration + tstop; tstop = duration + tstop;
break; break;
case GST_SEEK_TYPE_NONE: case GST_SEEK_TYPE_NONE:
tstop = avi->segment_stop; tstop = avi->segment.stop;
update_stop = FALSE; update_stop = FALSE;
break; break;
case GST_SEEK_TYPE_SET: case GST_SEEK_TYPE_SET:
@ -566,10 +568,10 @@ gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
tstop = CLAMP (tstop, 0, duration); tstop = CLAMP (tstop, 0, duration);
/* now store the values */ /* now store the values */
avi->segment_rate = rate; avi->segment.rate = rate;
avi->segment_flags = flags; avi->segment.flags = flags;
avi->segment_start = tstart; avi->segment.start = tstart;
avi->segment_stop = tstop; avi->segment.stop = tstop;
gst_avi_demux_handle_seek (avi, update_start || update_stop); gst_avi_demux_handle_seek (avi, update_start || update_stop);
break; break;
@ -832,7 +834,6 @@ gst_avi_demux_parse_subindex (GstElement * element,
gst_avi_index_entry *entries, *entry; gst_avi_index_entry *entries, *entry;
GList *entries_list = NULL; GList *entries_list = NULL;
GstFormat format = GST_FORMAT_TIME; GstFormat format = GST_FORMAT_TIME;
gint64 tmp;
/* check size */ /* check size */
if (buf == NULL) if (buf == NULL)
@ -862,6 +863,8 @@ gst_avi_demux_parse_subindex (GstElement * element,
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;
entry = &entries[x]; entry = &entries[x];
if (GST_BUFFER_SIZE (buf) < 24 + bpe * (x + 1)) if (GST_BUFFER_SIZE (buf) < 24 + bpe * (x + 1))
@ -876,30 +879,26 @@ gst_avi_demux_parse_subindex (GstElement * element,
entry->stream_nr = stream->num; entry->stream_nr = stream->num;
/* timestamps */ /* timestamps */
if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) { entry->ts = stream->total_time;
/* constant rate stream */ if (stream->is_vbr) {
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES, /* VBR get next timestamp */
stream->total_bytes, &format, &tmp); gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
entry->ts = tmp; stream->total_frames + 1, &format, &next_ts);
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes + entry->size, &format, &tmp);
entry->dur = tmp;
} else { } else {
/* VBR stream */ /* CBR get next timestamp */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_frames, &format, &tmp); stream->total_bytes + entry->size, &format, &next_ts);
entry->ts = tmp;
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames + 1, &format, &tmp);
entry->dur = tmp;
} }
entry->dur -= entry->ts; /* duration is next - current */
entry->dur = next_ts - entry->ts;
/* stream position */ /* stream position */
entry->bytes_before = stream->total_bytes; entry->bytes_before = stream->total_bytes;
stream->total_bytes += entry->size;
entry->frames_before = stream->total_frames; entry->frames_before = stream->total_frames;
stream->total_bytes += entry->size;
stream->total_frames++; stream->total_frames++;
stream->total_time = next_ts;
entries_list = g_list_prepend (entries_list, entry); entries_list = g_list_prepend (entries_list, entry);
} }
@ -1020,6 +1019,7 @@ gst_avi_demux_parse_stream (GstElement * element, GstBuffer * buf)
} else if (!gst_riff_parse_strh (element, sub, &stream->strh)) } else if (!gst_riff_parse_strh (element, sub, &stream->strh))
goto fail; goto fail;
/* read strf */ /* read strf */
if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub) || if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub) ||
tag != GST_RIFF_TAG_strf) { tag != GST_RIFF_TAG_strf) {
@ -1033,14 +1033,19 @@ gst_avi_demux_parse_stream (GstElement * element, GstBuffer * buf)
switch (stream->strh->type) { switch (stream->strh->type) {
case GST_RIFF_FCC_vids: case GST_RIFF_FCC_vids:
stream->is_vbr = TRUE;
res = gst_riff_parse_strf_vids (element, sub, res = gst_riff_parse_strf_vids (element, sub,
&stream->strf.vids, &stream->extradata); &stream->strf.vids, &stream->extradata);
break; break;
case GST_RIFF_FCC_auds: case GST_RIFF_FCC_auds:
res = gst_riff_parse_strf_auds (element, sub, stream->is_vbr = (stream->strh->samplesize == 0)
&stream->strf.auds, &stream->extradata); && stream->strh->scale > 1;
res =
gst_riff_parse_strf_auds (element, sub, &stream->strf.auds,
&stream->extradata);
break; break;
case GST_RIFF_FCC_iavs: case GST_RIFF_FCC_iavs:
stream->is_vbr = TRUE;
res = gst_riff_parse_strf_iavs (element, sub, res = gst_riff_parse_strf_iavs (element, sub,
&stream->strf.iavs, &stream->extradata); &stream->strf.iavs, &stream->extradata);
break; break;
@ -1319,7 +1324,7 @@ gst_avi_demux_parse_index (GstElement * element,
gint stream_nr; gint stream_nr;
gst_avi_index_entry *target; gst_avi_index_entry *target;
GstFormat format; GstFormat format;
gint64 ts; 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);
@ -1354,43 +1359,41 @@ gst_avi_demux_parse_index (GstElement * element,
avi->index_offset = 0; avi->index_offset = 0;
} }
target->bytes_before = stream->total_bytes;
target->frames_before = stream->total_frames;
format = GST_FORMAT_TIME; format = GST_FORMAT_TIME;
if (stream->strh->type == GST_RIFF_FCC_auds) { if (stream->strh->type == GST_RIFF_FCC_auds) {
/* all audio frames are keyframes */ /* all audio frames are keyframes */
target->flags |= GST_RIFF_IF_KEYFRAME; target->flags |= GST_RIFF_IF_KEYFRAME;
} }
if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) { /* timestamps */
target->ts = stream->total_time;
if (stream->is_vbr) {
/* VBR stream next timestamp */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames + 1, &format, &next_ts);
} else {
/* constant rate stream */ /* constant rate stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes, &format, &ts); stream->total_bytes + target->size, &format, &next_ts);
target->ts = ts;
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes + target->size, &format, &ts);
target->dur = ts;
} else {
/* VBR stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames, &format, &ts);
target->ts = ts;
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames + 1, &format, &ts);
target->dur = ts;
} }
target->dur -= target->ts; /* duration is next - current */
target->dur = next_ts - target->ts;
/* stream position */
target->bytes_before = stream->total_bytes;
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++;
GST_DEBUG_OBJECT (avi, GST_DEBUG_OBJECT (avi,
"Adding index entry %d (%d) flags %08x for stream %d of size %u " "Adding index entry %d (%d), flags %08x, stream %d, size %u "
"at offset %" G_GUINT64_FORMAT " and time %" GST_TIME_FORMAT, ", offset %" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT ", dur %"
GST_TIME_FORMAT,
target->index_nr, stream->total_frames - 1, target->flags, target->index_nr, stream->total_frames - 1, target->flags,
target->stream_nr, target->size, target->offset, target->stream_nr, target->size, target->offset,
GST_TIME_ARGS (target->ts)); GST_TIME_ARGS (target->ts), GST_TIME_ARGS (target->dur));
entries_list = g_list_prepend (entries_list, target); entries_list = g_list_prepend (entries_list, target);
n++; n++;
@ -1448,8 +1451,10 @@ 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, %"
i, stream->total_frames, stream->total_bytes); GST_TIME_FORMAT " time",
i, stream->total_frames, stream->total_bytes,
GST_TIME_ARGS (stream->total_time));
} }
return; return;
@ -1743,17 +1748,8 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
entry->size = size; entry->size = size;
/* timestamps */ /* timestamps */
if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) { format = GST_FORMAT_TIME;
format = GST_FORMAT_TIME; if (stream->is_vbr) {
/* 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;
} else {
format = GST_FORMAT_TIME;
/* VBR stream */ /* VBR stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames, &format, &tmpts); stream->total_frames, &format, &tmpts);
@ -1761,6 +1757,14 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames + 1, &format, &tmpdur); stream->total_frames + 1, &format, &tmpdur);
entry->dur = 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; entry->dur -= entry->ts;
@ -1809,18 +1813,18 @@ gst_avi_demux_stream_scan (GstAviDemux * avi,
entry->size = GST_READ_UINT32_LE (&data[4]); entry->size = GST_READ_UINT32_LE (&data[4]);
/* timestamps */ /* timestamps */
if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) { if (stream->is_vbr) {
/* constant rate stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes, &format, &entry->ts);
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes + entry->size, &format, &entry->dur);
} else {
/* VBR stream */ /* VBR stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames, &format, &entry->ts); stream->total_frames, &format, &entry->ts);
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT, gst_avi_demux_src_convert (stream->pad, GST_FORMAT_DEFAULT,
stream->total_frames + 1, &format, &entry->dur); stream->total_frames + 1, &format, &entry->dur);
} else {
/* constant rate stream */
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes, &format, &entry->ts);
gst_avi_demux_src_convert (stream->pad, GST_FORMAT_BYTES,
stream->total_bytes + entry->size, &format, &entry->dur);
} }
entry->dur -= entry->ts; entry->dur -= entry->ts;
@ -2020,8 +2024,10 @@ 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, %" G_GUINT64_FORMAT " bytes", i, GST_LOG_OBJECT (avi, "Stream %d, %d frames, %" G_GUINT64_FORMAT " bytes, %"
avi->stream[i].total_frames, avi->stream[i].total_bytes); GST_TIME_FORMAT " time", i,
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");
@ -2031,37 +2037,40 @@ 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;
GstClockTime end_time = GST_CLOCK_TIME_NONE; GstClockTime end_time;
gint stream, i; gint stream, i;
/* we assume all streams start at a timestamp of 0 for now */ /* we assume all streams start at a timestamp of 0 for now */
for (stream = 0; stream < avi->num_streams; ++stream) { for (stream = 0; stream < avi->num_streams; stream++) {
end_time = GST_CLOCK_TIME_NONE;
i = 0; i = 0;
while ((entry = gst_avi_demux_index_next (avi, stream, i))) { while ((entry = gst_avi_demux_index_next (avi, stream, i))) {
end_time = entry->ts + entry->dur; end_time = entry->ts + entry->dur;
++i; i++;
} }
if (GST_CLOCK_TIME_IS_VALID (end_time)) { if (GST_CLOCK_TIME_IS_VALID (end_time)) {
avi->stream[stream].idx_duration = end_time;
GST_INFO ("Stream %d duration according to index: %" GST_TIME_FORMAT, GST_INFO ("Stream %d duration according to index: %" GST_TIME_FORMAT,
stream, GST_TIME_ARGS (avi->stream[stream].idx_duration)); stream, GST_TIME_ARGS (end_time));
avi->stream[stream].idx_duration = end_time;
} }
} }
} }
static gboolean static gboolean
gst_avi_demux_send_event (GstAviDemux * avi, GstEvent * event) gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event)
{ {
gint i; gint i;
gboolean result = TRUE;
for (i = 0; i < avi->num_streams; i++) { for (i = 0; i < avi->num_streams; i++) {
avi_stream_context *stream = &avi->stream[i]; avi_stream_context *stream = &avi->stream[i];
gst_event_ref (event); gst_event_ref (event);
gst_pad_push_event (stream->pad, event); result &= gst_pad_push_event (stream->pad, event);
} }
gst_event_unref (event); gst_event_unref (event);
return TRUE;
return result;
} }
/* /*
@ -2230,6 +2239,7 @@ done:
gst_avi_demux_stream_scan (avi, &index, &alloc); gst_avi_demux_stream_scan (avi, &index, &alloc);
} }
/* this is a fatal error */
if (!index) if (!index)
goto no_index; goto no_index;
@ -2237,16 +2247,16 @@ done:
gst_avi_demux_calculate_durations_from_index (avi); gst_avi_demux_calculate_durations_from_index (avi);
/* send initial discont */ /* send initial discont */
avi->segment_start = 0; avi->segment.start = 0;
avi->segment_stop = avi->segment.stop =
gst_util_uint64_scale_int ((gint64) avi->stream[0].strh->scale * gst_util_uint64_scale_int ((gint64) avi->stream[0].strh->scale *
avi->stream[0].strh->length, GST_SECOND, avi->stream[0].strh->rate); avi->stream[0].strh->length, GST_SECOND, avi->stream[0].strh->rate);
GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, avi->segment_stop); GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, avi->segment.stop);
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, avi->segment_stop, avi->segment_start); avi->segment.start, avi->segment.stop, avi->segment.start);
/* at this point we know all the streams and we can signal the no more /* at this point we know all the streams and we can signal the no more
* pads signal */ * pads signal */
@ -2321,19 +2331,16 @@ gst_avi_demux_handle_seek (GstAviDemux * avi, gboolean update)
{ {
GstClockTime start_time; GstClockTime start_time;
gboolean flush, keyframe; gboolean flush, keyframe;
guint stream;
gst_avi_index_entry *entry; gst_avi_index_entry *entry;
/* FIXME: if we seek in an openDML file, we will have multiple /* FIXME: if we seek in an openDML file, we will have multiple
* primary levels. Seeking in between those will cause havoc. */ * primary levels. Seeking in between those will cause havoc. */
flush = avi->segment_flags & GST_SEEK_FLAG_FLUSH; flush = avi->segment.flags & GST_SEEK_FLAG_FLUSH;
keyframe = avi->segment_flags & GST_SEEK_FLAG_KEY_UNIT; keyframe = avi->segment.flags & GST_SEEK_FLAG_KEY_UNIT;
if (flush) { if (flush) {
for (stream = avi->num_streams; stream--;) gst_avi_demux_push_event (avi, gst_event_new_flush_start ());
gst_pad_push_event (avi->stream[stream].pad,
gst_event_new_flush_start ());
gst_pad_push_event (avi->sinkpad, gst_event_new_flush_start ()); gst_pad_push_event (avi->sinkpad, gst_event_new_flush_start ());
} else } else
gst_pad_pause_task (avi->sinkpad); gst_pad_pause_task (avi->sinkpad);
@ -2342,7 +2349,7 @@ gst_avi_demux_handle_seek (GstAviDemux * avi, gboolean update)
/* fill current_entry according to flags and update */ /* fill current_entry according to flags and update */
if (update) { if (update) {
entry = gst_avi_demux_index_entry_for_time (avi, 0, avi->segment_start, entry = gst_avi_demux_index_entry_for_time (avi, 0, avi->segment.start,
(guint32) GST_RIFF_IF_KEYFRAME); (guint32) GST_RIFF_IF_KEYFRAME);
if (entry) { if (entry) {
GST_DEBUG_OBJECT (avi, GST_DEBUG_OBJECT (avi,
@ -2354,30 +2361,29 @@ gst_avi_demux_handle_seek (GstAviDemux * avi, gboolean update)
} else { } else {
GST_WARNING_OBJECT (avi, GST_WARNING_OBJECT (avi,
"Couldn't find AviIndexEntry for time:%" GST_TIME_FORMAT, "Couldn't find AviIndexEntry for time:%" GST_TIME_FORMAT,
GST_TIME_ARGS (avi->segment_start)); GST_TIME_ARGS (avi->segment.start));
} }
} }
GST_DEBUG_OBJECT (avi, "seek: %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT GST_DEBUG_OBJECT (avi, "seek: %" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
" keyframe seeking:%d update:%d", GST_TIME_ARGS (avi->segment_start), " keyframe seeking:%d update:%d", GST_TIME_ARGS (avi->segment.start),
GST_TIME_ARGS (avi->segment_stop), keyframe, update); GST_TIME_ARGS (avi->segment.stop), keyframe, update);
if (keyframe) if (keyframe)
start_time = avi->index_entries[avi->current_entry].ts; start_time = avi->index_entries[avi->current_entry].ts;
else else
start_time = avi->segment_start; start_time = avi->segment.start;
avi->seek_event = gst_event_new_new_segment avi->seek_event = gst_event_new_new_segment
(!update, avi->segment_rate, GST_FORMAT_TIME, (!update, avi->segment.rate, GST_FORMAT_TIME,
start_time, avi->segment_stop, start_time); start_time, avi->segment.stop, start_time);
if (flush) { if (flush) {
for (stream = avi->num_streams; stream--;) gst_avi_demux_push_event (avi, gst_event_new_flush_start ());
gst_pad_push_event (avi->stream[stream].pad, gst_event_new_flush_stop ());
gst_pad_push_event (avi->sinkpad, gst_event_new_flush_stop ()); gst_pad_push_event (avi->sinkpad, gst_event_new_flush_stop ());
} }
if (avi->segment_flags & GST_SEEK_FLAG_SEGMENT) { if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (avi), gst_element_post_message (GST_ELEMENT (avi),
gst_message_new_segment_start (GST_OBJECT (avi), GST_FORMAT_TIME, gst_message_new_segment_start (GST_OBJECT (avi), GST_FORMAT_TIME,
start_time)); start_time));
@ -2481,11 +2487,11 @@ gst_avi_demux_process_next_entry (GstAviDemux * avi)
if ((entry->flags & GST_RIFF_IF_KEYFRAME) if ((entry->flags & GST_RIFF_IF_KEYFRAME)
&& GST_CLOCK_TIME_IS_VALID (entry->ts) && GST_CLOCK_TIME_IS_VALID (entry->ts)
&& GST_CLOCK_TIME_IS_VALID (avi->segment_stop) && GST_CLOCK_TIME_IS_VALID (avi->segment.stop)
&& (entry->ts > avi->segment_stop)) { && (entry->ts > avi->segment.stop)) {
GST_LOG_OBJECT (avi, "Found keyframe after segment," GST_LOG_OBJECT (avi, "Found keyframe after segment,"
" setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")", " setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")",
GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (avi->segment_stop)); GST_TIME_ARGS (entry->ts), GST_TIME_ARGS (avi->segment.stop));
goto eos; goto eos;
} }
@ -2514,6 +2520,7 @@ gst_avi_demux_process_next_entry (GstAviDemux * avi)
} }
if (!(entry->flags & GST_RIFF_IF_KEYFRAME)) if (!(entry->flags & GST_RIFF_IF_KEYFRAME))
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
GST_BUFFER_TIMESTAMP (buf) = entry->ts; GST_BUFFER_TIMESTAMP (buf) = entry->ts;
GST_BUFFER_DURATION (buf) = entry->dur; GST_BUFFER_DURATION (buf) = entry->dur;
gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad)); gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
@ -2539,15 +2546,9 @@ gst_avi_demux_process_next_entry (GstAviDemux * avi)
return GST_FLOW_OK; return GST_FLOW_OK;
eos: eos:
/* handle end-of-stream/segment */ {
if (avi->segment_flags & GST_SEEK_FLAG_SEGMENT) return GST_FLOW_UNEXPECTED;
gst_element_post_message }
(GST_ELEMENT (avi),
gst_message_new_segment_done (GST_OBJECT (avi), GST_FORMAT_TIME,
avi->segment_stop));
else
gst_avi_demux_send_event (avi, gst_event_new_eos ());
return GST_FLOW_WRONG_STATE;
} }
/* /*
@ -2644,7 +2645,7 @@ gst_avi_demux_loop (GstPad * pad)
break; break;
case GST_AVI_DEMUX_MOVI: case GST_AVI_DEMUX_MOVI:
if (avi->seek_event) { if (avi->seek_event) {
gst_avi_demux_send_event (avi, avi->seek_event); gst_avi_demux_push_event (avi, avi->seek_event);
avi->seek_event = NULL; avi->seek_event = NULL;
} }
if ((res = gst_avi_demux_stream_data (avi)) != GST_FLOW_OK) { if ((res = gst_avi_demux_stream_data (avi)) != GST_FLOW_OK) {
@ -2658,24 +2659,37 @@ gst_avi_demux_loop (GstPad * pad)
if (gst_avi_demux_all_source_pads_unlinked (avi)) { if (gst_avi_demux_all_source_pads_unlinked (avi)) {
GST_DEBUG_OBJECT (avi, "all source pads unlinked, pausing"); GST_DEBUG_OBJECT (avi, "all source pads unlinked, pausing");
res = GST_FLOW_NOT_LINKED;
goto pause; goto pause;
} }
return; return;
pause: pause:
GST_LOG_OBJECT (avi, "pausing task"); {
gst_pad_pause_task (avi->sinkpad); GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res));
if (GST_FLOW_IS_FATAL (res)) { gst_pad_pause_task (avi->sinkpad);
guint stream = avi->num_streams; if (GST_FLOW_IS_FATAL (res) || (res == GST_FLOW_NOT_LINKED)) {
gboolean push_eos = TRUE;
/* for fatal errors we post an error message */ if (res == GST_FLOW_UNEXPECTED) {
GST_ELEMENT_ERROR (avi, STREAM, FAILED, /* handle end-of-stream/segment */
(_("Internal data stream error.")), if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
("streaming stopped, reason %s", gst_flow_get_name (res))); gst_element_post_message
while (stream--) { (GST_ELEMENT (avi),
if (avi->stream[stream].pad) gst_message_new_segment_done (GST_OBJECT (avi), GST_FORMAT_TIME,
gst_pad_push_event (avi->stream[stream].pad, gst_event_new_eos ()); 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 ());
}
} }
} }
} }

View file

@ -81,6 +81,10 @@ typedef struct {
/* stream length */ /* stream length */
guint64 total_bytes; guint64 total_bytes;
guint32 total_frames; guint32 total_frames;
guint64 total_time;
/* VBR indicator */
gboolean is_vbr;
/* stream length according to index */ /* stream length according to index */
GstClockTime idx_duration; GstClockTime idx_duration;
@ -119,13 +123,10 @@ typedef struct _GstAviDemux {
/* some stream info for length */ /* some stream info for length */
gst_riff_avih *avih; gst_riff_avih *avih;
/* seeking */ /* seeking in TIME */
gdouble segment_rate; GstSegment segment;
GstSeekFlags segment_flags;
/* in GST_FORMAT_TIME */
gint64 segment_start;
gint64 segment_stop;
GstEvent *seek_event; GstEvent *seek_event;
} GstAviDemux; } GstAviDemux;
typedef struct _GstAviDemuxClass { typedef struct _GstAviDemuxClass {