diff --git a/src/decoder/plugins/FlacCommon.cxx b/src/decoder/plugins/FlacCommon.cxx index dbe5dfde4..33f728a67 100644 --- a/src/decoder/plugins/FlacCommon.cxx +++ b/src/decoder/plugins/FlacCommon.cxx @@ -24,33 +24,10 @@ #include "config.h" #include "FlacCommon.hxx" #include "FlacMetadata.hxx" -#include "FlacPcm.hxx" -#include "FlacDomain.hxx" -#include "CheckAudioFormat.hxx" #include "util/Error.hxx" +#include "util/ConstBuffer.hxx" #include "Log.hxx" -static SampleFormat -flac_sample_format(unsigned bits_per_sample) -{ - switch (bits_per_sample) { - case 8: - return SampleFormat::S8; - - case 16: - return SampleFormat::S16; - - case 24: - return SampleFormat::S24_P32; - - case 32: - return SampleFormat::S32; - - default: - return SampleFormat::UNDEFINED; - } -} - bool FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample, unsigned channels, FLAC__uint64 total_frames) @@ -58,25 +35,15 @@ FlacDecoder::Initialize(unsigned sample_rate, unsigned bits_per_sample, assert(!initialized); assert(!unsupported); - auto sample_format = flac_sample_format(bits_per_sample); - if (sample_format == SampleFormat::UNDEFINED) { - FormatWarning(flac_domain, "Unsupported FLAC bit depth: %u", - bits_per_sample); - unsupported = true; - return false; - } - ::Error error; - if (!audio_format_init_checked(audio_format, - sample_rate, - sample_format, - channels, error)) { + if (!pcm_import.Open(sample_rate, bits_per_sample, + channels, error)) { LogError(error); unsupported = true; return false; } - frame_size = audio_format.GetFrameSize(); + const auto audio_format = pcm_import.GetAudioFormat(); const auto duration = total_frames > 0 ? SignedSongTime::FromScale(total_frames, @@ -174,18 +141,13 @@ FlacDecoder::OnWrite(const FLAC__Frame &frame, if (!initialized && !OnFirstFrame(frame.header)) return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - size_t buffer_size = frame.header.blocksize * frame_size; - void *data = buffer.Get(buffer_size); - - flac_convert(data, frame.header.channels, - audio_format.format, buf, - frame.header.blocksize); + const auto data = pcm_import.Import(buf, frame.header.blocksize); unsigned bit_rate = nbytes * 8 * frame.header.sample_rate / (1000 * frame.header.blocksize); auto cmd = decoder_data(*GetDecoder(), GetInputStream(), - data, buffer_size, + data.data, data.size, bit_rate); switch (cmd) { case DecoderCommand::NONE: diff --git a/src/decoder/plugins/FlacCommon.hxx b/src/decoder/plugins/FlacCommon.hxx index eb23e6955..b8da9440f 100644 --- a/src/decoder/plugins/FlacCommon.hxx +++ b/src/decoder/plugins/FlacCommon.hxx @@ -25,19 +25,12 @@ #define MPD_FLAC_COMMON_HXX #include "FlacInput.hxx" +#include "FlacPcm.hxx" #include "../DecoderAPI.hxx" -#include "pcm/PcmBuffer.hxx" #include struct FlacDecoder : public FlacInput { - PcmBuffer buffer; - - /** - * The size of one frame in the output buffer. - */ - unsigned frame_size; - /** * Has decoder_initialized() been called yet? */ @@ -48,11 +41,7 @@ struct FlacDecoder : public FlacInput { */ bool unsupported = false; - /** - * The validated audio format of the FLAC file. This - * attribute is defined if "initialized" is true. - */ - AudioFormat audio_format; + FlacPcmImport pcm_import; /** * End of last frame's position within the stream. This is @@ -62,7 +51,6 @@ struct FlacDecoder : public FlacInput { Tag tag; - FlacDecoder(Decoder &_decoder, InputStream &_input_stream) :FlacInput(_input_stream, &_decoder) {} diff --git a/src/decoder/plugins/FlacPcm.cxx b/src/decoder/plugins/FlacPcm.cxx index a848aa4d4..f1e3e3a37 100644 --- a/src/decoder/plugins/FlacPcm.cxx +++ b/src/decoder/plugins/FlacPcm.cxx @@ -19,9 +19,54 @@ #include "config.h" #include "FlacPcm.hxx" +#include "FlacDomain.hxx" +#include "CheckAudioFormat.hxx" +#include "util/Error.hxx" +#include "util/ConstBuffer.hxx" #include +static SampleFormat +flac_sample_format(unsigned bits_per_sample) +{ + switch (bits_per_sample) { + case 8: + return SampleFormat::S8; + + case 16: + return SampleFormat::S16; + + case 24: + return SampleFormat::S24_P32; + + case 32: + return SampleFormat::S32; + + default: + return SampleFormat::UNDEFINED; + } +} + +bool +FlacPcmImport::Open(unsigned sample_rate, unsigned bits_per_sample, + unsigned channels, Error &error) +{ + auto sample_format = flac_sample_format(bits_per_sample); + if (sample_format == SampleFormat::UNDEFINED) { + error.Format(flac_domain, "Unsupported FLAC bit depth: %u", + bits_per_sample); + return false; + } + + if (!audio_format_init_checked(audio_format, + sample_rate, + sample_format, + channels, error)) + return false; + + return true; +} + template static void FlacImportStereo(T *dest, const FLAC__int32 *const src[], size_t n_frames) @@ -53,30 +98,41 @@ FlacImport(T *dest, const FLAC__int32 *const src[], size_t n_frames, FlacImportAny(dest, src, n_frames, n_channels); } -void -flac_convert(void *dest, - unsigned int num_channels, SampleFormat sample_format, - const FLAC__int32 *const buf[], - size_t n_frames) +template +static ConstBuffer +FlacImport(PcmBuffer &buffer, const FLAC__int32 *const src[], size_t n_frames, + unsigned n_channels) { - switch (sample_format) { + size_t n_samples = n_frames * n_channels; + size_t dest_size = n_samples * sizeof(T); + T *dest = (T *)buffer.Get(dest_size); + FlacImport(dest, src, n_frames, n_channels); + return {dest, dest_size}; +} + +ConstBuffer +FlacPcmImport::Import(const FLAC__int32 *const src[], size_t n_frames) +{ + switch (audio_format.format) { case SampleFormat::S16: - FlacImport((int16_t *)dest, buf, n_frames, num_channels); - break; + return FlacImport(buffer, src, n_frames, + audio_format.channels); case SampleFormat::S24_P32: case SampleFormat::S32: - FlacImport((int32_t *)dest, buf, n_frames, num_channels); - break; + return FlacImport(buffer, src, n_frames, + audio_format.channels); case SampleFormat::S8: - FlacImport((int8_t *)dest, buf, n_frames, num_channels); - break; + return FlacImport(buffer, src, n_frames, + audio_format.channels); case SampleFormat::FLOAT: case SampleFormat::DSD: case SampleFormat::UNDEFINED: - assert(false); - gcc_unreachable(); + break; } + + assert(false); + gcc_unreachable(); } diff --git a/src/decoder/plugins/FlacPcm.hxx b/src/decoder/plugins/FlacPcm.hxx index dd7a0eddd..d40d08362 100644 --- a/src/decoder/plugins/FlacPcm.hxx +++ b/src/decoder/plugins/FlacPcm.hxx @@ -20,16 +20,37 @@ #ifndef MPD_FLAC_PCM_HXX #define MPD_FLAC_PCM_HXX +#include "check.h" +#include "pcm/PcmBuffer.hxx" #include "AudioFormat.hxx" #include -#include +class Error; +template struct ConstBuffer; -void -flac_convert(void *dest, - unsigned int num_channels, SampleFormat sample_format, - const FLAC__int32 *const buf[], - size_t n_frames); +/** + * This class imports libFLAC PCM data into a PCM format supported by + * MPD. + */ +class FlacPcmImport { + PcmBuffer buffer; + + AudioFormat audio_format; + +public: + /** + * @return false on error + */ + bool Open(unsigned sample_rate, unsigned bits_per_sample, + unsigned channels, Error &error); + + const AudioFormat &GetAudioFormat() const { + return audio_format; + } + + ConstBuffer Import(const FLAC__int32 *const src[], + size_t n_frames); +}; #endif