summaryrefslogtreecommitdiffstats
path: root/ext/flac
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@collabora.co.uk>2009-03-09 17:14:12 +0100
committerWim Taymans <wim.taymans@collabora.co.uk>2009-03-09 17:14:12 +0100
commit8f8e035cd5794658a359d7233fe67f48f5d77b2c (patch)
tree3c3c1c157804a44687adf0231dcf1b4979cba11f /ext/flac
parentaf7aaef37ac5521e12684192507653741e85d812 (diff)
flacdec: don't lose the first buffer after a seek
The flacdec API calls the write callback when performing a seek. We cannot yet push out a buffer at that time so we must keep it and push it out later. Flush out the upstream part of the pipeline when doing a seek. Fixes #574275.
Diffstat (limited to 'ext/flac')
-rw-r--r--ext/flac/gstflacdec.c74
-rw-r--r--ext/flac/gstflacdec.h1
2 files changed, 48 insertions, 27 deletions
diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c
index 9d88309d..adc4f355 100644
--- a/ext/flac/gstflacdec.c
+++ b/ext/flac/gstflacdec.c
@@ -331,6 +331,10 @@ gst_flac_dec_reset_decoders (GstFlacDec * flacdec)
gst_tag_list_free (flacdec->tags);
flacdec->tags = NULL;
}
+ if (flacdec->pending) {
+ gst_buffer_unref (flacdec->pending);
+ flacdec->pending = NULL;
+ }
flacdec->segment.last_stop = 0;
flacdec->offset = 0;
@@ -1090,6 +1094,17 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
flacdec->tags = NULL;
}
+ if (flacdec->pending) {
+ GST_DEBUG_OBJECT (flacdec,
+ "pushing pending samples at offset %" G_GINT64_FORMAT " (%"
+ GST_TIME_FORMAT " + %" GST_TIME_FORMAT ")",
+ GST_BUFFER_OFFSET (flacdec->pending),
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (flacdec->pending)),
+ GST_TIME_ARGS (GST_BUFFER_DURATION (flacdec->pending)));
+ gst_pad_push (flacdec->srcpad, flacdec->pending);
+ flacdec->pending = NULL;
+ }
+
ret = gst_pad_alloc_buffer_and_set_caps (flacdec->srcpad,
flacdec->segment.last_stop, samples * channels * (width / 8),
GST_PAD_CAPS (flacdec->srcpad), &outbuf);
@@ -1153,16 +1168,18 @@ gst_flac_dec_write (GstFlacDec * flacdec, const FLAC__Frame * frame,
GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
if (flacdec->discont) {
+ GST_DEBUG_OBJECT (flacdec, "marking discont");
outbuf = gst_buffer_make_metadata_writable (outbuf);
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
flacdec->discont = FALSE;
}
ret = gst_pad_push (flacdec->srcpad, outbuf);
+ GST_DEBUG_OBJECT (flacdec, "returned %s", gst_flow_get_name (ret));
} else {
GST_DEBUG_OBJECT (flacdec,
"not pushing %d samples at offset %" G_GINT64_FORMAT
" (in seek)", samples, GST_BUFFER_OFFSET (outbuf));
- gst_buffer_unref (outbuf);
+ gst_buffer_replace (&flacdec->pending, outbuf);
ret = GST_FLOW_OK;
}
@@ -1928,6 +1945,7 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
/* flushing seek, clear the pipeline of stuff, we need a newsegment after
* this. */
GST_DEBUG_OBJECT (flacdec, "flushing");
+ gst_pad_push_event (flacdec->sinkpad, gst_event_new_flush_start ());
gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_start ());
} else {
/* non flushing seek, pause the task */
@@ -1941,25 +1959,34 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
* downstream in PAUSED, for example */
GST_PAD_STREAM_LOCK (flacdec->sinkpad);
- /* operate on segment copy until we know the seek worked. The idea is that
- * when the seek fails, we want to continue with what we were doing without
- * having the segment being updated. */
+ /* save a segment copy until we know the seek worked. The idea is that
+ * when the seek fails, we want to restore with what we were doing. */
segment = flacdec->segment;
/* update the segment with the seek values, last_stop will contain the new
* position we should seek to */
- gst_segment_set_seek (&segment, rate, GST_FORMAT_DEFAULT,
+ gst_segment_set_seek (&flacdec->segment, rate, GST_FORMAT_DEFAULT,
seek_flags, start_type, start, stop_type, stop, &only_update);
GST_DEBUG_OBJECT (flacdec,
"configured segment: [%" G_GINT64_FORMAT "-%" G_GINT64_FORMAT
"] = [%" GST_TIME_FORMAT "-%" GST_TIME_FORMAT "]",
- segment.start, segment.stop,
- GST_TIME_ARGS (segment.start * GST_SECOND / flacdec->sample_rate),
- GST_TIME_ARGS (segment.stop * GST_SECOND / flacdec->sample_rate));
+ flacdec->segment.start, flacdec->segment.stop,
+ GST_TIME_ARGS (flacdec->segment.start * GST_SECOND /
+ flacdec->sample_rate),
+ GST_TIME_ARGS (flacdec->segment.stop * GST_SECOND /
+ flacdec->sample_rate));
GST_DEBUG_OBJECT (flacdec, "performing seek to sample %" G_GINT64_FORMAT,
- segment.last_stop);
+ flacdec->segment.last_stop);
+
+ /* flush sinkpad again because we need to pull and push buffers while doing
+ * the seek */
+ if (flush) {
+ GST_DEBUG_OBJECT (flacdec, "flushing stop");
+ gst_pad_push_event (flacdec->sinkpad, gst_event_new_flush_stop ());
+ gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_stop ());
+ }
/* mark ourselves as seeking because the above lines will trigger some
* callbacks that need to behave differently when seeking */
@@ -1968,18 +1995,19 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
seek_ok =
#ifdef LEGACY_FLAC
FLAC__seekable_stream_decoder_seek_absolute (flacdec->seekable_decoder,
- segment.last_stop);
+ flacdec->segment.last_stop);
#else
FLAC__stream_decoder_seek_absolute (flacdec->seekable_decoder,
- segment.last_stop);
+ flacdec->segment.last_stop);
#endif
flacdec->seeking = FALSE;
if (!seek_ok) {
- /* seek failed, segment was not updated and we start streaming again with
- * the previous segment values */
GST_WARNING_OBJECT (flacdec, "seek failed");
+ /* seek failed, restore the segment and start streaming again with
+ * the previous segment values */
+ flacdec->segment = segment;
} else if (!flush && flacdec->running) {
/* we are running the current segment and doing a non-flushing seek,
* close the segment first based on the last_stop. */
@@ -1987,10 +2015,10 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
" to %" G_GINT64_FORMAT, segment.start, segment.last_stop);
/* convert the old segment values to time to close the old segment */
- start = gst_util_uint64_scale_int (flacdec->segment.start, GST_SECOND,
+ start = gst_util_uint64_scale_int (segment.start, GST_SECOND,
flacdec->sample_rate);
last_stop =
- gst_util_uint64_scale_int (flacdec->segment.last_stop, GST_SECOND,
+ gst_util_uint64_scale_int (segment.last_stop, GST_SECOND,
flacdec->sample_rate);
/* queue the segment for sending in the stream thread, start and time are
@@ -1999,13 +2027,12 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
gst_event_unref (flacdec->close_segment);
flacdec->close_segment =
gst_event_new_new_segment_full (TRUE,
- flacdec->segment.rate, flacdec->segment.applied_rate, GST_FORMAT_TIME,
+ segment.rate, segment.applied_rate, GST_FORMAT_TIME,
start, last_stop, start);
}
if (seek_ok) {
- /* seek succeeded, copy new segment values */
- flacdec->segment = segment;
+ /* seek succeeded, flacdec->segment contains the new positions */
GST_DEBUG_OBJECT (flacdec, "seek successful");
}
@@ -2026,7 +2053,7 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
flacdec->sample_rate);
/* notify start of new segment when we were asked to do so. */
- if (segment.flags & GST_SEEK_FLAG_SEGMENT) {
+ if (flacdec->segment.flags & GST_SEEK_FLAG_SEGMENT) {
/* last_stop contains the position we start from */
gst_element_post_message (GST_ELEMENT (flacdec),
gst_message_new_segment_start (GST_OBJECT (flacdec),
@@ -2046,17 +2073,10 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event)
gst_event_unref (flacdec->start_segment);
flacdec->start_segment =
gst_event_new_new_segment_full (FALSE,
- segment.rate, segment.applied_rate, GST_FORMAT_TIME,
+ flacdec->segment.rate, flacdec->segment.applied_rate, GST_FORMAT_TIME,
last_stop, stop, last_stop);
}
- /* prepare for streaming again, start with a flush stop when we issued a flush
- * start before. */
- if (flush) {
- GST_DEBUG_OBJECT (flacdec, "flushing stop");
- gst_pad_push_event (flacdec->srcpad, gst_event_new_flush_stop ());
- }
-
/* we'll generate a discont on the next buffer */
flacdec->discont = TRUE;
/* the task is running again now */
diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h
index 100c4e0b..1b706bca 100644
--- a/ext/flac/gstflacdec.h
+++ b/ext/flac/gstflacdec.h
@@ -74,6 +74,7 @@ struct _GstFlacDec {
* samples/audio frames (DEFAULT format) */
gboolean running;
gboolean discont;
+ GstBuffer *pending; /* pending buffer, produced in seek */
GstEvent *close_segment;
GstEvent *start_segment;
GstTagList *tags;