From 375976c847b80ab40ff30e1e5cef91ff12bddf50 Mon Sep 17 00:00:00 2001 From: Tim-Philipp Müller Date: Tue, 21 Jul 2009 19:46:55 +0100 Subject: flacdec: fix intermittent FLAC__STREAM_DECODER_ABORTED errors when seeking When seeking in a local flac file (ie. operating pull-based), the decoder would often just error out after the loop function sees a DECODER_ABORTED status. This, however, is the read callback's way of telling our loop function that pull_range failed and streaming should stop, in this case because of the flush-start event that the seek handler pushed upstream from the seeking thread. Handle this slightly better by storing the last flow return from pull_range, so the loop function can evaluate it properly when it encounters a DECODER_ABORTED and take the right action. Fixes #578612. --- ext/flac/gstflacdec.c | 36 +++++++++++++++++++++++++++++++----- ext/flac/gstflacdec.h | 2 ++ 2 files changed, 33 insertions(+), 5 deletions(-) (limited to 'ext/flac') diff --git a/ext/flac/gstflacdec.c b/ext/flac/gstflacdec.c index 3f9c75f4..4d047021 100644 --- a/ext/flac/gstflacdec.c +++ b/ext/flac/gstflacdec.c @@ -773,15 +773,25 @@ static FLAC__StreamDecoderReadStatus gst_flac_dec_read_seekable (const FLAC__StreamDecoder * decoder, FLAC__byte buffer[], size_t * bytes, void *client_data) { + GstFlowReturn flow; GstFlacDec *flacdec; - GstBuffer *buf; flacdec = GST_FLAC_DEC (client_data); - if (gst_pad_pull_range (flacdec->sinkpad, flacdec->offset, *bytes, - &buf) != GST_FLOW_OK) - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + flow = gst_pad_pull_range (flacdec->sinkpad, flacdec->offset, *bytes, &buf); + + GST_PAD_STREAM_LOCK (flacdec->sinkpad); + flacdec->pull_flow = flow; + GST_PAD_STREAM_UNLOCK (flacdec->sinkpad); + + if (G_UNLIKELY (flow != GST_FLOW_OK)) { + GST_INFO_OBJECT (flacdec, "pull_range flow: %s", gst_flow_get_name (flow)); + if (flow == GST_FLOW_UNEXPECTED) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + } GST_DEBUG_OBJECT (flacdec, "Read %d bytes at %" G_GUINT64_FORMAT, GST_BUFFER_SIZE (buf), flacdec->offset); @@ -1152,9 +1162,23 @@ analyze_state: goto eos_and_pause; } + /* gst_flac_dec_read_seekable() returned ABORTED */ + case FLAC__STREAM_DECODER_ABORTED: + { + GST_INFO_OBJECT (flacdec, "read aborted: last pull_range flow = %s", + gst_flow_get_name (flacdec->pull_flow)); + if (!GST_FLOW_IS_FATAL (flacdec->pull_flow)) { + /* it seems we need to flush the decoder here to reset the decoder + * state after the abort for FLAC__stream_decoder_seek_absolute() + * to work properly */ + GST_DEBUG_OBJECT (flacdec, "flushing decoder to reset decoder state"); + FLAC__stream_decoder_flush (flacdec->seekable_decoder); + goto pause; + } + /* fall through */ + } case FLAC__STREAM_DECODER_OGG_ERROR: case FLAC__STREAM_DECODER_SEEK_ERROR: - case FLAC__STREAM_DECODER_ABORTED: case FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR: case FLAC__STREAM_DECODER_UNINITIALIZED: default:{ @@ -1782,8 +1806,10 @@ gst_flac_dec_handle_seek_event (GstFlacDec * flacdec, GstEvent * event) * callbacks that need to behave differently when seeking */ flacdec->seeking = TRUE; + GST_LOG_OBJECT (flacdec, "calling seek_absolute"); seek_ok = FLAC__stream_decoder_seek_absolute (flacdec->seekable_decoder, flacdec->segment.last_stop); + GST_LOG_OBJECT (flacdec, "done with seek_absolute, seek_ok=%d", seek_ok); flacdec->seeking = FALSE; diff --git a/ext/flac/gstflacdec.h b/ext/flac/gstflacdec.h index a9daf3e9..e6a76bbb 100644 --- a/ext/flac/gstflacdec.h +++ b/ext/flac/gstflacdec.h @@ -74,6 +74,8 @@ struct _GstFlacDec { GstEvent *start_segment; GstTagList *tags; + GstFlowReturn pull_flow; /* last flow from pull_range */ /* STREAM_LOCK */ + GstFlowReturn last_flow; /* the last flow return received from either * gst_pad_push or gst_pad_buffer_alloc */ -- cgit