summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--src/decoder/_flac_common.c41
-rw-r--r--src/decoder/flac_decoder_plugin.c12
3 files changed, 53 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 5d0a736fd..fae16e339 100644
--- a/NEWS
+++ b/NEWS
@@ -23,6 +23,7 @@ ver 0.16 (20??/??/??)
- ffmpeg: convert metadata to generic format
- sndfile: new decoder plugin based on libsndfile
- flac: moved CUE sheet support to a playlist plugin
+ - flac: support streams without STREAMINFO block
- mikmod: sample rate is configurable
- mpg123: new decoder plugin based on libmpg123
- sidplay: support sub-tunes
diff --git a/src/decoder/_flac_common.c b/src/decoder/_flac_common.c
index 9a3449096..6e28792ec 100644
--- a/src/decoder/_flac_common.c
+++ b/src/decoder/_flac_common.c
@@ -161,16 +161,55 @@ void flac_error_common_cb(const char *plugin,
}
}
+/**
+ * This function attempts to call decoder_initialized() in case there
+ * was no STREAMINFO block. This is allowed for nonseekable streams,
+ * where the server sends us only a part of the file, without
+ * providing the STREAMINFO block from the beginning of the file
+ * (e.g. when seeking with SqueezeBox Server).
+ */
+static bool
+flac_got_first_frame(struct flac_data *data, const FLAC__FrameHeader *header)
+{
+ if (data->unsupported)
+ return false;
+
+ GError *error = NULL;
+ if (!audio_format_init_checked(&data->audio_format,
+ header->sample_rate,
+ flac_sample_format(header->bits_per_sample),
+ header->channels, &error)) {
+ g_warning("%s", error->message);
+ g_error_free(error);
+ data->unsupported = true;
+ return false;
+ }
+
+ data->frame_size = audio_format_frame_size(&data->audio_format);
+
+ decoder_initialized(data->decoder, &data->audio_format,
+ data->input_stream->seekable,
+ (float)data->total_frames /
+ (float)data->audio_format.sample_rate);
+
+ data->initialized = true;
+
+ return true;
+}
+
FLAC__StreamDecoderWriteStatus
flac_common_write(struct flac_data *data, const FLAC__Frame * frame,
const FLAC__int32 *const buf[],
FLAC__uint64 nbytes)
{
enum decoder_command cmd;
- size_t buffer_size = frame->header.blocksize * data->frame_size;
void *buffer;
unsigned bit_rate;
+ if (!data->initialized && !flac_got_first_frame(data, &frame->header))
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+ size_t buffer_size = frame->header.blocksize * data->frame_size;
buffer = pcm_buffer_get(&data->buffer, buffer_size);
flac_convert(buffer, frame->header.channels,
diff --git a/src/decoder/flac_decoder_plugin.c b/src/decoder/flac_decoder_plugin.c
index d139354b8..022ee7045 100644
--- a/src/decoder/flac_decoder_plugin.c
+++ b/src/decoder/flac_decoder_plugin.c
@@ -247,6 +247,18 @@ flac_decoder_initialize(struct flac_data *data, FLAC__StreamDecoder *sd,
return false;
}
+ if (data->initialized)
+ /* done */
+ return true;
+
+ if (data->input_stream->seekable)
+ /* allow the workaround below only for nonseekable
+ streams*/
+ return false;
+
+ /* no stream_info packet found; try to initialize the decoder
+ from the first frame header */
+ FLAC__stream_decoder_process_single(sd);
return data->initialized;
}