diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-08-10 15:33:00 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-08-10 15:33:00 +1000 |
| commit | d8fc77101dcf80a3643a00b3446dca1e390ce997 (patch) | |
| tree | 9e03881f3857c7b4c6a0b6e3a062947daecc69d1 /src/codecs/include | |
| parent | 67caeb6e3cda44205ba8fe783274b20dc7ea216e (diff) | |
| download | tangara-fw-d8fc77101dcf80a3643a00b3446dca1e390ce997.tar.gz | |
Give codecs complete control of their input files
Diffstat (limited to 'src/codecs/include')
| -rw-r--r-- | src/codecs/include/codec.hpp | 46 | ||||
| -rw-r--r-- | src/codecs/include/foxenflac.hpp | 19 | ||||
| -rw-r--r-- | src/codecs/include/mad.hpp | 31 | ||||
| -rw-r--r-- | src/codecs/include/opus.hpp | 33 | ||||
| -rw-r--r-- | src/codecs/include/source_buffer.hpp | 37 | ||||
| -rw-r--r-- | src/codecs/include/vorbis.hpp | 32 |
6 files changed, 125 insertions, 73 deletions
diff --git a/src/codecs/include/codec.hpp b/src/codecs/include/codec.hpp index 32ebef69..ece3d4fe 100644 --- a/src/codecs/include/codec.hpp +++ b/src/codecs/include/codec.hpp @@ -24,6 +24,34 @@ namespace codecs { /* + * Interface for an abstract source of file-like data. + */ +class IStream { + public: + IStream(StreamType t) : t_(t) {} + virtual ~IStream() {} + + auto type() -> StreamType { return t_; } + + virtual auto Read(cpp::span<std::byte> dest) -> ssize_t = 0; + + virtual auto CanSeek() -> bool = 0; + + enum class SeekFrom { + kStartOfStream, + kEndOfStream, + kCurrentPosition, + }; + + virtual auto SeekTo(int64_t destination, SeekFrom from) -> void = 0; + + virtual auto CurrentPosition() -> int64_t = 0; + + protected: + StreamType t_; +}; + +/* * Common interface to be implemented by all audio decoders. */ class ICodec { @@ -63,32 +91,30 @@ class ICodec { struct OutputFormat { uint8_t num_channels; uint32_t sample_rate_hz; - std::optional<uint32_t> duration_seconds; - std::optional<uint32_t> bits_per_second; + + bool operator==(const OutputFormat&) const = default; }; /* * Decodes metadata or headers from the given input stream, and returns the * format for the samples that will be decoded from it. */ - virtual auto BeginStream(cpp::span<const std::byte> input) - -> Result<OutputFormat> = 0; + virtual auto OpenStream(std::shared_ptr<IStream> input) + -> cpp::result<OutputFormat, Error> = 0; struct OutputInfo { std::size_t samples_written; - bool is_finished_writing; + bool is_stream_finished; }; /* * Writes PCM samples to the given output buffer. */ - virtual auto ContinueStream(cpp::span<const std::byte> input, - cpp::span<sample::Sample> output) - -> Result<OutputInfo> = 0; + virtual auto DecodeTo(cpp::span<sample::Sample> destination) + -> cpp::result<OutputInfo, Error> = 0; - virtual auto SeekStream(cpp::span<const std::byte> input, - std::size_t target_sample) -> Result<void> = 0; + virtual auto SeekTo(size_t target_sample) -> cpp::result<void, Error> = 0; }; auto CreateCodecForType(StreamType type) -> std::optional<ICodec*>; diff --git a/src/codecs/include/foxenflac.hpp b/src/codecs/include/foxenflac.hpp index abfa6d80..7522d967 100644 --- a/src/codecs/include/foxenflac.hpp +++ b/src/codecs/include/foxenflac.hpp @@ -15,6 +15,7 @@ #include "foxen/flac.h" #include "sample.hpp" +#include "source_buffer.hpp" #include "span.hpp" #include "codec.hpp" @@ -26,13 +27,21 @@ class FoxenFlacDecoder : public ICodec { FoxenFlacDecoder(); ~FoxenFlacDecoder(); - auto BeginStream(cpp::span<const std::byte>) -> Result<OutputFormat> override; - auto ContinueStream(cpp::span<const std::byte>, cpp::span<sample::Sample>) - -> Result<OutputInfo> override; - auto SeekStream(cpp::span<const std::byte> input, std::size_t target_sample) - -> Result<void> override; + auto OpenStream(std::shared_ptr<IStream> input) + -> cpp::result<OutputFormat, Error> override; + + auto DecodeTo(cpp::span<sample::Sample> destination) + -> cpp::result<OutputInfo, Error> override; + + auto SeekTo(std::size_t target_sample) -> cpp::result<void, Error> override; + + FoxenFlacDecoder(const FoxenFlacDecoder&) = delete; + FoxenFlacDecoder& operator=(const FoxenFlacDecoder&) = delete; private: + std::shared_ptr<IStream> input_; + SourceBuffer buffer_; + fx_flac_t* flac_; }; diff --git a/src/codecs/include/mad.hpp b/src/codecs/include/mad.hpp index b81e4acb..2a8813e9 100644 --- a/src/codecs/include/mad.hpp +++ b/src/codecs/include/mad.hpp @@ -14,6 +14,7 @@ #include "mad.h" #include "sample.hpp" +#include "source_buffer.hpp" #include "span.hpp" #include "codec.hpp" @@ -25,33 +26,31 @@ class MadMp3Decoder : public ICodec { MadMp3Decoder(); ~MadMp3Decoder(); - /* - * 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; + auto OpenStream(std::shared_ptr<IStream> input) + -> cpp::result<OutputFormat, Error> override; - /* - * Writes samples for the current frame. - */ - auto ContinueStream(cpp::span<const std::byte> input, - cpp::span<sample::Sample> output) - -> Result<OutputInfo> override; + auto DecodeTo(cpp::span<sample::Sample> destination) + -> cpp::result<OutputInfo, Error> override; - auto SeekStream(cpp::span<const std::byte> input, std::size_t target_sample) - -> Result<void> override; + auto SeekTo(std::size_t target_sample) -> cpp::result<void, Error> override; + + MadMp3Decoder(const MadMp3Decoder&) = delete; + MadMp3Decoder& operator=(const MadMp3Decoder&) = delete; private: auto GetVbrLength(const mad_header& header) -> std::optional<uint32_t>; + auto GetBytesUsed() -> std::size_t; + + std::shared_ptr<IStream> input_; + SourceBuffer buffer_; mad_stream stream_; mad_frame frame_; mad_synth synth_; int current_sample_; - - auto GetBytesUsed(std::size_t) -> std::size_t; + bool is_eof_; + bool is_eos_; }; } // namespace codecs diff --git a/src/codecs/include/opus.hpp b/src/codecs/include/opus.hpp index 051cd0b9..45b1b07a 100644 --- a/src/codecs/include/opus.hpp +++ b/src/codecs/include/opus.hpp @@ -26,30 +26,21 @@ class XiphOpusDecoder : public ICodec { XiphOpusDecoder(); ~XiphOpusDecoder(); - /* - * 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<sample::Sample> output) - -> Result<OutputInfo> override; - - auto SeekStream(cpp::span<const std::byte> input, std::size_t target_sample) - -> Result<void> override; - - auto ReadCallback() -> cpp::span<const std::byte>; - auto AfterReadCallback(size_t bytes_read) -> void; + auto OpenStream(std::shared_ptr<IStream> input) + -> cpp::result<OutputFormat, Error> override; + + auto DecodeTo(cpp::span<sample::Sample> destination) + -> cpp::result<OutputInfo, Error> override; + + auto SeekTo(std::size_t target_sample) -> cpp::result<void, Error> override; + + XiphOpusDecoder(const XiphOpusDecoder&) = delete; + XiphOpusDecoder& operator=(const XiphOpusDecoder&) = delete; private: + std::shared_ptr<IStream> input_; OggOpusFile* opus_; - cpp::span<const std::byte> input_; - size_t pos_in_input_; + uint8_t num_channels_; }; } // namespace codecs diff --git a/src/codecs/include/source_buffer.hpp b/src/codecs/include/source_buffer.hpp new file mode 100644 index 00000000..d0d7635a --- /dev/null +++ b/src/codecs/include/source_buffer.hpp @@ -0,0 +1,37 @@ +/* + * Copyright 2023 jacqueline <me@jacqueline.id.au> + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include <cstddef> +#include <cstdint> +#include <functional> + +#include "span.hpp" + +#include "codec.hpp" + +namespace codecs { + +class SourceBuffer { + public: + SourceBuffer(); + ~SourceBuffer(); + + auto Refill(IStream* src) -> bool; + auto AddBytes(std::function<size_t(cpp::span<std::byte>)> writer) -> void; + auto ConsumeBytes(std::function<size_t(cpp::span<std::byte>)> reader) -> void; + + SourceBuffer(const SourceBuffer&) = delete; + SourceBuffer& operator=(const SourceBuffer&) = delete; + + private: + const cpp::span<std::byte> buffer_; + size_t bytes_in_buffer_; + size_t offset_of_bytes_; +}; + +} // namespace codecs diff --git a/src/codecs/include/vorbis.hpp b/src/codecs/include/vorbis.hpp index ab15af19..2f93c37e 100644 --- a/src/codecs/include/vorbis.hpp +++ b/src/codecs/include/vorbis.hpp @@ -28,30 +28,20 @@ class TremorVorbisDecoder : public ICodec { TremorVorbisDecoder(); ~TremorVorbisDecoder(); - /* - * 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<sample::Sample> output) - -> Result<OutputInfo> override; - - auto SeekStream(cpp::span<const std::byte> input, std::size_t target_sample) - -> Result<void> override; - - auto ReadCallback() -> cpp::span<const std::byte>; - auto AfterReadCallback(size_t bytes_read) -> void; + auto OpenStream(std::shared_ptr<IStream> input) + -> cpp::result<OutputFormat, Error> override; + + auto DecodeTo(cpp::span<sample::Sample> destination) + -> cpp::result<OutputInfo, Error> override; + + auto SeekTo(std::size_t target_sample) -> cpp::result<void, Error> override; + + TremorVorbisDecoder(const TremorVorbisDecoder&) = delete; + TremorVorbisDecoder& operator=(const TremorVorbisDecoder&) = delete; private: + std::shared_ptr<IStream> input_; OggVorbis_File vorbis_; - cpp::span<const std::byte> input_; - size_t pos_in_input_; }; } // namespace codecs |
