From d8fc77101dcf80a3643a00b3446dca1e390ce997 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 10 Aug 2023 15:33:00 +1000 Subject: Give codecs complete control of their input files --- src/codecs/include/codec.hpp | 46 ++++++++++++++++++++++++++++-------- src/codecs/include/foxenflac.hpp | 19 +++++++++++---- src/codecs/include/mad.hpp | 31 ++++++++++++------------ src/codecs/include/opus.hpp | 33 ++++++++++---------------- src/codecs/include/source_buffer.hpp | 37 +++++++++++++++++++++++++++++ src/codecs/include/vorbis.hpp | 32 +++++++++---------------- 6 files changed, 125 insertions(+), 73 deletions(-) create mode 100644 src/codecs/include/source_buffer.hpp (limited to 'src/codecs/include') 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 @@ -23,6 +23,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 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. */ @@ -63,32 +91,30 @@ class ICodec { struct OutputFormat { uint8_t num_channels; uint32_t sample_rate_hz; - std::optional duration_seconds; - std::optional 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 input) - -> Result = 0; + virtual auto OpenStream(std::shared_ptr input) + -> cpp::result = 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 input, - cpp::span output) - -> Result = 0; + virtual auto DecodeTo(cpp::span destination) + -> cpp::result = 0; - virtual auto SeekStream(cpp::span input, - std::size_t target_sample) -> Result = 0; + virtual auto SeekTo(size_t target_sample) -> cpp::result = 0; }; auto CreateCodecForType(StreamType type) -> std::optional; 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) -> Result override; - auto ContinueStream(cpp::span, cpp::span) - -> Result override; - auto SeekStream(cpp::span input, std::size_t target_sample) - -> Result override; + auto OpenStream(std::shared_ptr input) + -> cpp::result override; + + auto DecodeTo(cpp::span destination) + -> cpp::result override; + + auto SeekTo(std::size_t target_sample) -> cpp::result override; + + FoxenFlacDecoder(const FoxenFlacDecoder&) = delete; + FoxenFlacDecoder& operator=(const FoxenFlacDecoder&) = delete; private: + std::shared_ptr 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) -> Result override; + auto OpenStream(std::shared_ptr input) + -> cpp::result override; - /* - * Writes samples for the current frame. - */ - auto ContinueStream(cpp::span input, - cpp::span output) - -> Result override; + auto DecodeTo(cpp::span destination) + -> cpp::result override; - auto SeekStream(cpp::span input, std::size_t target_sample) - -> Result override; + auto SeekTo(std::size_t target_sample) -> cpp::result override; + + MadMp3Decoder(const MadMp3Decoder&) = delete; + MadMp3Decoder& operator=(const MadMp3Decoder&) = delete; private: auto GetVbrLength(const mad_header& header) -> std::optional; + auto GetBytesUsed() -> std::size_t; + + std::shared_ptr 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) -> Result override; - - /* - * Writes samples for the current frame. - */ - auto ContinueStream(cpp::span input, - cpp::span output) - -> Result override; - - auto SeekStream(cpp::span input, std::size_t target_sample) - -> Result override; - - auto ReadCallback() -> cpp::span; - auto AfterReadCallback(size_t bytes_read) -> void; + auto OpenStream(std::shared_ptr input) + -> cpp::result override; + + auto DecodeTo(cpp::span destination) + -> cpp::result override; + + auto SeekTo(std::size_t target_sample) -> cpp::result override; + + XiphOpusDecoder(const XiphOpusDecoder&) = delete; + XiphOpusDecoder& operator=(const XiphOpusDecoder&) = delete; private: + std::shared_ptr input_; OggOpusFile* opus_; - cpp::span 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 + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#pragma once + +#include +#include +#include + +#include "span.hpp" + +#include "codec.hpp" + +namespace codecs { + +class SourceBuffer { + public: + SourceBuffer(); + ~SourceBuffer(); + + auto Refill(IStream* src) -> bool; + auto AddBytes(std::function)> writer) -> void; + auto ConsumeBytes(std::function)> reader) -> void; + + SourceBuffer(const SourceBuffer&) = delete; + SourceBuffer& operator=(const SourceBuffer&) = delete; + + private: + const cpp::span 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) -> Result override; - - /* - * Writes samples for the current frame. - */ - auto ContinueStream(cpp::span input, - cpp::span output) - -> Result override; - - auto SeekStream(cpp::span input, std::size_t target_sample) - -> Result override; - - auto ReadCallback() -> cpp::span; - auto AfterReadCallback(size_t bytes_read) -> void; + auto OpenStream(std::shared_ptr input) + -> cpp::result override; + + auto DecodeTo(cpp::span destination) + -> cpp::result override; + + auto SeekTo(std::size_t target_sample) -> cpp::result override; + + TremorVorbisDecoder(const TremorVorbisDecoder&) = delete; + TremorVorbisDecoder& operator=(const TremorVorbisDecoder&) = delete; private: + std::shared_ptr input_; OggVorbis_File vorbis_; - cpp::span input_; - size_t pos_in_input_; }; } // namespace codecs -- cgit v1.2.3