From 222c810b07ffc635fc7908d121e97e4d65ccc5c8 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Fri, 2 Dec 2022 13:39:00 +1100 Subject: fix build errors --- src/codecs/CMakeLists.txt | 6 +- src/codecs/codec.cpp | 5 +- src/codecs/include/codec.hpp | 70 ++++++++++-------- src/codecs/include/mad.hpp | 20 ++++-- src/codecs/mad.cpp | 166 +++++++++++++++++++------------------------ 5 files changed, 137 insertions(+), 130 deletions(-) (limited to 'src/codecs') diff --git a/src/codecs/CMakeLists.txt b/src/codecs/CMakeLists.txt index 4a8918ae..4f89f370 100644 --- a/src/codecs/CMakeLists.txt +++ b/src/codecs/CMakeLists.txt @@ -1,6 +1,8 @@ idf_component_register( SRCS "codec.cpp" "mad.cpp" - INCLUDE_DIRS "include") + INCLUDE_DIRS "include" + REQUIRES "result") -target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) add_dependencies("${COMPONENT_LIB}" libmad) +target_compile_options("${COMPONENT_LIB}" PRIVATE ${EXTRA_WARNINGS}) +target_include_directories("${COMPONENT_LIB}" PRIVATE "${LIBMAD_INCLUDE}") diff --git a/src/codecs/codec.cpp b/src/codecs/codec.cpp index db8d69b9..2a66b5f1 100644 --- a/src/codecs/codec.cpp +++ b/src/codecs/codec.cpp @@ -1,10 +1,13 @@ #include "codec.hpp" +#include +#include "mad.hpp" + namespace codecs { auto CreateCodecForExtension(std::string extension) -> cpp::result, CreateCodecError> { - return cpp::fail(UNKNOWN_EXTENSION); + return std::make_unique(); // TODO. } } // namespace codecs diff --git a/src/codecs/include/codec.hpp b/src/codecs/include/codec.hpp index 8e82bd71..764b63fc 100644 --- a/src/codecs/include/codec.hpp +++ b/src/codecs/include/codec.hpp @@ -1,18 +1,17 @@ #pragma once #include + #include #include +#include +#include +#include #include "result.hpp" namespace codecs { -enum CreateCodecError { UNKNOWN_EXTENSION }; - -auto CreateCodecForFile(const std::string& extension) - -> cpp::result, CreateCodecError>; - class ICodec { public: virtual ~ICodec() {} @@ -22,39 +21,48 @@ class ICodec { struct OutputFormat { uint8_t num_channels; uint8_t bits_per_sample; - int sample_rate_hz; + uint32_t sample_rate_hz; }; virtual auto GetOutputFormat() -> OutputFormat = 0; - enum ProcessingError {}; - - struct Result { - bool need_more_input; - /* - * For need_more_input, this is how far we got in the input buffer - * before we were unable to process more data. Any remaining data in the - * buffer should be moved to the start before the next call. - */ - std::size_t input_processed; - - bool flush_output; - /* - * For flush_output, this is how far we got in the output buffer before - * we ran out of space for samples. The caller should flush this many - * bytes downstream. - */ - std::size_t output_written; - }; + enum ProcessingError { MALFORMED_DATA }; virtual auto ResetForNewStream() -> void = 0; - virtual auto SetInput(uint8_t* buffer, std::size_t length) = 0; - virtual auto Process(uint8_t* output, std::size_t output_length) - -> cpp::result = 0; - - virtual auto GetOutputProcessed() -> std::size_t; - = 0; + virtual auto SetInput(uint8_t* buffer, std::size_t length) -> void = 0; + + /* + * Returns the codec's next read position within the input buffer. If the + * codec is out of usable data, but there is still some data left in the + * stream, that data should be prepended to the next input buffer. + */ + virtual auto GetInputPosition() -> std::size_t = 0; + + /* + * Read one frame (or equivalent discrete chunk) from the input, and + * synthesize output samples for it. + * + * Returns true if we are out of usable data from the input stream, or false + * otherwise. + */ + virtual auto ProcessNextFrame() -> cpp::result = 0; + + /* + * Writes PCM samples to the given output buffer. + * + * Returns the number of bytes that were written, and true if all of the + * samples synthesized from the last call to `ProcessNextFrame` have been + * written. If this returns false, then this method should be called again + * after flushing the output buffer. + */ + virtual auto WriteOutputSamples(uint8_t* output, std::size_t output_length) + -> std::pair = 0; }; +enum CreateCodecError { UNKNOWN_EXTENSION }; + +auto CreateCodecForFile(const std::string& extension) + -> cpp::result, CreateCodecError>; + } // namespace codecs diff --git a/src/codecs/include/mad.hpp b/src/codecs/include/mad.hpp index 241ea6c3..aa24f3c9 100644 --- a/src/codecs/include/mad.hpp +++ b/src/codecs/include/mad.hpp @@ -1,5 +1,11 @@ #pragma once +#include +#include +#include + +#include "mad.h" + #include "codec.hpp" namespace codecs { @@ -9,10 +15,14 @@ class MadMp3Decoder : public ICodec { MadMp3Decoder(); ~MadMp3Decoder(); - auto ProcessInput(Result* res, uint8_t* input, std::size_t input_len) -> void; - auto WriteOutputSamples(Result* res, - uint8_t* output, - std::size_t output_length) -> void; + auto CanHandleFile(const std::string& path) -> bool override; + auto GetOutputFormat() -> OutputFormat override; + auto ResetForNewStream() -> void override; + auto SetInput(uint8_t* buffer, std::size_t length) -> void override; + auto GetInputPosition() -> std::size_t override; + auto ProcessNextFrame() -> cpp::result override; + auto WriteOutputSamples(uint8_t* output, std::size_t output_length) + -> std::pair override; private: mad_stream stream_; @@ -22,7 +32,7 @@ class MadMp3Decoder : public ICodec { mad_header header_; bool has_decoded_header_; - int current_sample_ = -1; + int current_sample_; }; } // namespace codecs diff --git a/src/codecs/mad.cpp b/src/codecs/mad.cpp index c918e849..4afc9a77 100644 --- a/src/codecs/mad.cpp +++ b/src/codecs/mad.cpp @@ -1,8 +1,11 @@ #include "mad.hpp" + #include #include "mad.h" +#include "codec.hpp" + namespace codecs { static int32_t scaleTo24Bits(mad_fixed_t sample) { @@ -32,118 +35,99 @@ MadMp3Decoder::~MadMp3Decoder() { mad_header_finish(&header_); } -auto MadMp3Decoder::CanHandleExtension(std::string extension) -> bool { - return extension == "mp3"; +auto MadMp3Decoder::CanHandleFile(const std::string& path) -> bool { + return true; // TODO. } -auto GetOutputFormat() -> OutputFormat { +auto MadMp3Decoder::GetOutputFormat() -> OutputFormat { return OutputFormat{ - .num_channels = synth_.pcm.channels, + .num_channels = static_cast(synth_.pcm.channels), .bits_per_sample = 24, .sample_rate_hz = synth_.pcm.samplerate, }; } -auto MadMp3Decoder::Process(uint8_t* input, - std::size_t input_len, - uint8_t* output, - std::size_t output_length) - -> cpp::result { - Result res { - .need_more_input = false, .input_processed = 0, .flush_output = false, - .output_written = 0, - } - while (true) { - // Only process more of the input if we're done sending off the - // samples for the previous frame. - if (current_sample_ == -1) { - ProcessInput(&res, input, input_len); - } +auto MadMp3Decoder::ResetForNewStream() -> void { + has_decoded_header_ = false; +} - // Write PCM samples to the output buffer. This always needs to be - // done, even if we ran out of input, so that we don't keep the last - // few samples buffered if the input stream has actually finished. - WriteOutputSamples(&res, output, output_length); +auto MadMp3Decoder::SetInput(uint8_t* buffer, std::size_t length) -> void { + mad_stream_buffer(&stream_, buffer, length); +} - if (res.need_more_input || res.flush_output) { - return res; - } - } +auto MadMp3Decoder::GetInputPosition() -> std::size_t { + return stream_.next_frame - stream_.buffer; +} - auto MadMp3Decoder::ProcessInput(Result * res, uint8_t * input, - std::size_t input_len) - ->void { - if (input != stream_.buffer) { - mad_stream_buffer(&stream_, input, input_len); - } +auto MadMp3Decoder::ProcessNextFrame() -> cpp::result { + if (!has_decoded_header_) { + // The header of any given frame should be representative of the + // entire stream, so only need to read it once. + mad_header_decode(&header_, &stream_); + has_decoded_header_ = true; - if (!has_decoded_header_) { - // The header of any given frame should be representative of the - // entire stream, so only need to read it once. - mad_header_decode(&header_, &stream); - has_decoded_header_ = true; + // TODO: Use the info in the header for something. I think the + // duration will help with seeking? + } - // TODO: Use the info in the header for something. I think the - // duration will help with seeking? + // Whatever was last synthesized is now invalid, so ensure we don't try to + // send it. + current_sample_ = -1; + + // Decode the next frame. To signal errors, this returns -1 and + // stashes an error code in the stream structure. + if (mad_frame_decode(&frame_, &stream_) < 0) { + if (MAD_RECOVERABLE(stream_.error)) { + // Recoverable errors are usually malformed parts of the stream. + // We can recover from them by just retrying the decode. + return false; } - // Decode the next frame. To signal errors, this returns -1 and - // stashes an error code in the stream structure. - if (mad_frame_decode(&frame_, &stream_) < 0) { - if (MAD_RECOVERABLE(stream_.error)) { - // Recoverable errors are usually malformed parts of the stream. - // We can recover from them by just retrying the decode. - continue; - } - - if (stream_.error = MAD_ERROR_BUFLEN) { - // The decoder ran out of bytes before it completed a frame. We - // need to return back to the caller to give us more data. Note - // that there might still be some unused data in the input, so we - // should calculate that amount and return it. - size_t remaining_bytes = stream.bufend - stream_.next_frame; - return remaining_bytes; - } - - // The error is unrecoverable. Give up. - return cpp::fail(MALFORMED_DATA); + if (stream_.error == MAD_ERROR_BUFLEN) { + // The decoder ran out of bytes before it completed a frame. We + // need to return back to the caller to give us more data. + return true; } - // We've successfully decoded a frame! - // Now we need to synthesize PCM samples based on the frame, and send - // them downstream. - mad_synth_frame(&synth_, &frame_); - up_to_sample = 0; + // The error is unrecoverable. Give up. + return cpp::fail(MALFORMED_DATA); } - auto MadMp3Decoder::WriteOutputSamples(Result * res, uint8_t * output, - std::size_t output_length) - ->void { - size_t output_byte = 0; - // First ensure that we actually have some samples to send off. - if (current_sample_ < 0) { - return; - } - res->flush_output = true; - - while (current_sample_ < synth_.pcm.length) { - if (output_byte + (3 * synth_.pcm.channels) >= output_length) { - res->output_written = output_byte; - return; - } - - for (int channel = 0; channel < synth_.pcm.channels; channel++) { - uint32_t sample_24 = scaleTo24Bits(synth_.pcm.samples[channel][sample]); - output[output_byte++] = (sample_24 >> 0) & 0xff; - output[output_byte++] = (sample_24 >> 8) & 0xff; - output[output_byte++] = (sample_24 >> 16) & 0xff; - } - current_sample_++; + // We've successfully decoded a frame! + // Now we need to synthesize PCM samples based on the frame, and send + // them downstream. + mad_synth_frame(&synth_, &frame_); + current_sample_ = 0; + return false; +} + +auto MadMp3Decoder::WriteOutputSamples(uint8_t* output, + std::size_t output_length) + -> std::pair { + size_t output_byte = 0; + // First ensure that we actually have some samples to send off. + if (current_sample_ < 0) { + return std::make_pair(output_byte, true); + } + + while (current_sample_ < synth_.pcm.length) { + if (output_byte + (3 * synth_.pcm.channels) >= output_length) { + return std::make_pair(output_byte, false); } - // We wrote everything! Reset, ready for the next frame. - current_sample_ = -1; - res->output_written = output_byte; + for (int channel = 0; channel < synth_.pcm.channels; channel++) { + uint32_t sample_24 = + scaleTo24Bits(synth_.pcm.samples[channel][current_sample_]); + output[output_byte++] = (sample_24 >> 0) & 0xff; + output[output_byte++] = (sample_24 >> 8) & 0xff; + output[output_byte++] = (sample_24 >> 16) & 0xff; + } + current_sample_++; } + // We wrote everything! Reset, ready for the next frame. + current_sample_ = -1; + return std::make_pair(output_byte, true); +} + } // namespace codecs -- cgit v1.2.3