decoder/flac: refactor flac_convert() to class FlacPcmImport
This commit is contained in:
		| @@ -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<uint64_t>(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: | ||||
|   | ||||
| @@ -25,19 +25,12 @@ | ||||
| #define MPD_FLAC_COMMON_HXX | ||||
|  | ||||
| #include "FlacInput.hxx" | ||||
| #include "FlacPcm.hxx" | ||||
| #include "../DecoderAPI.hxx" | ||||
| #include "pcm/PcmBuffer.hxx" | ||||
|  | ||||
| #include <FLAC/stream_decoder.h> | ||||
|  | ||||
| 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) {} | ||||
|  | ||||
|   | ||||
| @@ -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 <assert.h> | ||||
|  | ||||
| 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<typename T> | ||||
| 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<typename T> | ||||
| static ConstBuffer<void> | ||||
| 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<void> | ||||
| 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<int16_t>(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<int32_t>(buffer, src, n_frames, | ||||
| 					   audio_format.channels); | ||||
|  | ||||
| 	case SampleFormat::S8: | ||||
| 		FlacImport((int8_t *)dest, buf, n_frames, num_channels); | ||||
| 		break; | ||||
| 		return FlacImport<int8_t>(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(); | ||||
| } | ||||
|   | ||||
| @@ -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 <FLAC/ordinals.h> | ||||
|  | ||||
| #include <stddef.h> | ||||
| class Error; | ||||
| template<typename T> 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<void> Import(const FLAC__int32 *const src[], | ||||
| 				 size_t n_frames); | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann