diff options
Diffstat (limited to 'src/codecs/include')
| -rw-r--r-- | src/codecs/include/codec.hpp | 60 | ||||
| -rw-r--r-- | src/codecs/include/foxenflac.hpp | 38 | ||||
| -rw-r--r-- | src/codecs/include/mad.hpp | 24 | ||||
| -rw-r--r-- | src/codecs/include/stbvorbis.hpp | 42 | ||||
| -rw-r--r-- | src/codecs/include/types.hpp | 2 |
5 files changed, 134 insertions, 32 deletions
diff --git a/src/codecs/include/codec.hpp b/src/codecs/include/codec.hpp index 31c67e13..4b5ab47f 100644 --- a/src/codecs/include/codec.hpp +++ b/src/codecs/include/codec.hpp @@ -21,48 +21,58 @@ namespace codecs { +/* + * Common interface to be implemented by all audio decoders. + */ class ICodec { public: virtual ~ICodec() {} + /* Errors that may be returned by codecs. */ + enum class Error { + // Indicates that more data is required before this codec can finish its + // operation. E.g. the input buffer ends with a truncated frame. + kOutOfInput, + // Indicates that the data within the input buffer is fatally malformed. + kMalformedData, + + kInternalError, + }; + + /* + * Alias for more readable return types. All codec methods, success or + * failure, should also return the number of bytes they consumed. + */ + template <typename T> + using Result = std::pair<std::size_t, cpp::result<T, Error>>; + struct OutputFormat { uint8_t num_channels; uint8_t bits_per_sample; uint32_t sample_rate_hz; }; - virtual auto GetOutputFormat() -> std::optional<OutputFormat> = 0; - - enum ProcessingError { MALFORMED_DATA }; - - virtual auto SetInput(cpp::span<const std::byte> input) -> 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. + * Decodes metadata or headers from the given input stream, and returns the + * format for the samples that will be decoded from it. */ - virtual auto GetInputPosition() -> std::size_t = 0; + virtual auto BeginStream(cpp::span<const std::byte> input) + -> Result<OutputFormat> = 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<bool, ProcessingError> = 0; + struct OutputInfo { + std::size_t bytes_written; + bool is_finished_writing; + }; /* * 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(cpp::span<std::byte> output) - -> std::pair<std::size_t, bool> = 0; + virtual auto ContinueStream(cpp::span<const std::byte> input, + cpp::span<std::byte> output) + -> Result<OutputInfo> = 0; + + virtual auto SeekStream(cpp::span<const std::byte> input, + std::size_t target_sample) -> Result<void> = 0; }; auto CreateCodecForType(StreamType type) -> std::optional<ICodec*>; diff --git a/src/codecs/include/foxenflac.hpp b/src/codecs/include/foxenflac.hpp new file mode 100644 index 00000000..cce1b762 --- /dev/null +++ b/src/codecs/include/foxenflac.hpp @@ -0,0 +1,38 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <optional> +#include <string> +#include <utility> + +#include "foxen/flac.h" +#include "span.hpp" + +#include "codec.hpp" + +namespace codecs { + +class FoxenFlacDecoder : public ICodec { + public: + FoxenFlacDecoder(); + ~FoxenFlacDecoder(); + + auto BeginStream(cpp::span<const std::byte>) -> Result<OutputFormat> override; + auto ContinueStream(cpp::span<const std::byte>, cpp::span<std::byte>) + -> Result<OutputInfo> override; + auto SeekStream(cpp::span<const std::byte> input, std::size_t target_sample) + -> Result<void> override; + + private: + fx_flac_t* flac_; +}; + +} // namespace codecs diff --git a/src/codecs/include/mad.hpp b/src/codecs/include/mad.hpp index 5ba4db84..e1c479bf 100644 --- a/src/codecs/include/mad.hpp +++ b/src/codecs/include/mad.hpp @@ -24,12 +24,22 @@ class MadMp3Decoder : public ICodec { MadMp3Decoder(); ~MadMp3Decoder(); - auto GetOutputFormat() -> std::optional<OutputFormat> override; - auto SetInput(cpp::span<const std::byte> input) -> void override; - auto GetInputPosition() -> std::size_t override; - auto ProcessNextFrame() -> cpp::result<bool, ProcessingError> override; - auto WriteOutputSamples(cpp::span<std::byte> output) - -> std::pair<std::size_t, bool> override; + /* + * Returns the output format for the next frame in the stream. MP3 streams + * may represent multiple distinct tracks, with different bitrates, and so we + * handle the stream only on a frame-by-frame basis. + */ + auto BeginStream(cpp::span<const std::byte>) -> Result<OutputFormat> override; + + /* + * Writes samples for the current frame. + */ + auto ContinueStream(cpp::span<const std::byte> input, + cpp::span<std::byte> output) + -> Result<OutputInfo> override; + + auto SeekStream(cpp::span<const std::byte> input, std::size_t target_sample) + -> Result<void> override; private: mad_stream stream_; @@ -37,6 +47,8 @@ class MadMp3Decoder : public ICodec { mad_synth synth_; int current_sample_; + + auto GetInputPosition() -> std::size_t; }; } // namespace codecs diff --git a/src/codecs/include/stbvorbis.hpp b/src/codecs/include/stbvorbis.hpp new file mode 100644 index 00000000..045e264e --- /dev/null +++ b/src/codecs/include/stbvorbis.hpp @@ -0,0 +1,42 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <cstddef> +#include <cstdint> +#include <memory> +#include <optional> +#include <string> +#include <utility> + +#include "stb_vorbis.h" + +#include "codec.hpp" + +namespace codecs { + +class StbVorbisDecoder : public ICodec { + public: + StbVorbisDecoder(); + ~StbVorbisDecoder(); + + auto BeginStream(cpp::span<const std::byte>) -> Result<OutputFormat> override; + auto ContinueStream(cpp::span<const std::byte>, cpp::span<std::byte>) + -> Result<OutputInfo> override; + auto SeekStream(cpp::span<const std::byte> input, std::size_t target_sample) + -> Result<void> override; + + private: + stb_vorbis* vorbis_; + + int current_sample_; + int num_channels_; + int num_samples_; + float** samples_array_; +}; + +} // namespace codecs diff --git a/src/codecs/include/types.hpp b/src/codecs/include/types.hpp index 61d36a28..3dfc1da9 100644 --- a/src/codecs/include/types.hpp +++ b/src/codecs/include/types.hpp @@ -13,7 +13,7 @@ namespace codecs { enum class StreamType { kMp3, kPcm, - kOgg, + kVorbis, kFlac, }; |
