summaryrefslogtreecommitdiff
path: root/src/codecs
diff options
context:
space:
mode:
Diffstat (limited to 'src/codecs')
-rw-r--r--src/codecs/CMakeLists.txt4
-rw-r--r--src/codecs/codec.cpp4
-rw-r--r--src/codecs/dr_flac.cpp115
-rw-r--r--src/codecs/include/codec.hpp4
-rw-r--r--src/codecs/include/dr_flac.hpp (renamed from src/codecs/include/miniflac.hpp)23
-rw-r--r--src/codecs/include/mad.hpp4
-rw-r--r--src/codecs/include/opus.hpp4
-rw-r--r--src/codecs/include/source_buffer.hpp1
-rw-r--r--src/codecs/include/vorbis.hpp4
-rw-r--r--src/codecs/include/wav.hpp4
-rw-r--r--src/codecs/mad.cpp51
-rw-r--r--src/codecs/miniflac.cpp181
-rw-r--r--src/codecs/opus.cpp14
-rw-r--r--src/codecs/source_buffer.cpp5
-rw-r--r--src/codecs/vorbis.cpp14
-rw-r--r--src/codecs/wav.cpp11
16 files changed, 198 insertions, 245 deletions
diff --git a/src/codecs/CMakeLists.txt b/src/codecs/CMakeLists.txt
index 1ef4bb2d..b6481bd1 100644
--- a/src/codecs/CMakeLists.txt
+++ b/src/codecs/CMakeLists.txt
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-only
idf_component_register(
- SRCS "codec.cpp" "mad.cpp" "miniflac.cpp" "opus.cpp" "vorbis.cpp"
+ SRCS "dr_flac.cpp" "codec.cpp" "mad.cpp" "opus.cpp" "vorbis.cpp"
"source_buffer.cpp" "sample.cpp" "wav.cpp"
INCLUDE_DIRS "include"
- REQUIRES "result" "span" "libmad" "miniflac" "tremor" "opusfile" "memory" "util"
+ REQUIRES "result" "span" "libmad" "drflac" "tremor" "opusfile" "memory" "util"
"komihash")
target_compile_options("${COMPONENT_LIB}" PRIVATE ${EXTRA_WARNINGS})
diff --git a/src/codecs/codec.cpp b/src/codecs/codec.cpp
index 7bc591aa..a51c40d6 100644
--- a/src/codecs/codec.cpp
+++ b/src/codecs/codec.cpp
@@ -10,7 +10,7 @@
#include <optional>
#include "mad.hpp"
-#include "miniflac.hpp"
+#include "dr_flac.hpp"
#include "opus.hpp"
#include "types.hpp"
#include "vorbis.hpp"
@@ -42,7 +42,7 @@ auto CreateCodecForType(StreamType type) -> std::optional<ICodec*> {
case StreamType::kVorbis:
return new TremorVorbisDecoder();
case StreamType::kFlac:
- return new MiniFlacDecoder();
+ return new DrFlacDecoder();
case StreamType::kOpus:
return new XiphOpusDecoder();
case StreamType::kWav:
diff --git a/src/codecs/dr_flac.cpp b/src/codecs/dr_flac.cpp
new file mode 100644
index 00000000..2f9acf8c
--- /dev/null
+++ b/src/codecs/dr_flac.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2023 jacqueline <me@jacqueline.id.au>
+ *
+ * SPDX-License-Identifier: GPL-3.0-only
+ */
+
+#include "dr_flac.hpp"
+
+#include <cstdint>
+#include <cstdlib>
+
+#include "codec.hpp"
+#include "dr_flac.h"
+#include "esp_heap_caps.h"
+#include "esp_log.h"
+#include "result.hpp"
+#include "sample.hpp"
+
+namespace codecs {
+
+[[maybe_unused]] static const char kTag[] = "flac";
+
+static void* onMalloc(size_t sz, void* pUserData) {
+ return heap_caps_malloc(sz, MALLOC_CAP_SPIRAM);
+}
+
+static void* onRealloc(void* p, size_t sz, void* pUserData) {
+ return heap_caps_realloc(p, sz, MALLOC_CAP_SPIRAM);
+}
+
+static void onFree(void* p, void* pUserData) {
+ heap_caps_free(p);
+}
+
+static drflac_allocation_callbacks kAllocCallbacks{
+ .pUserData = nullptr,
+ .onMalloc = onMalloc,
+ .onRealloc = onRealloc,
+ .onFree = onFree,
+};
+
+static size_t readProc(void* pUserData, void* pBufferOut, size_t bytesToRead) {
+ IStream* stream = reinterpret_cast<IStream*>(pUserData);
+ ssize_t res =
+ stream->Read({reinterpret_cast<std::byte*>(pBufferOut), bytesToRead});
+ return res < 0 ? 0 : res;
+}
+
+static drflac_bool32 seekProc(void* pUserData,
+ int offset,
+ drflac_seek_origin origin) {
+ IStream* stream = reinterpret_cast<IStream*>(pUserData);
+ if (!stream->CanSeek()) {
+ return DRFLAC_FALSE;
+ }
+
+ IStream::SeekFrom seek_from;
+ switch (origin) {
+ case drflac_seek_origin_start:
+ seek_from = IStream::SeekFrom::kStartOfStream;
+ break;
+ case drflac_seek_origin_current:
+ seek_from = IStream::SeekFrom::kCurrentPosition;
+ break;
+ default:
+ return DRFLAC_FALSE;
+ }
+ stream->SeekTo(offset, seek_from);
+
+ // FIXME: Detect falling off the end of the file.
+ return DRFLAC_TRUE;
+}
+
+DrFlacDecoder::DrFlacDecoder() : input_(), flac_() {}
+
+DrFlacDecoder::~DrFlacDecoder() {
+ if (flac_) {
+ drflac_free(flac_, &kAllocCallbacks);
+ }
+}
+
+auto DrFlacDecoder::OpenStream(std::shared_ptr<IStream> input, uint32_t offset)
+ -> cpp::result<OutputFormat, Error> {
+ input_ = input;
+
+ flac_ = drflac_open(readProc, seekProc, input_.get(), &kAllocCallbacks);
+ if (!flac_) {
+ return cpp::fail(Error::kMalformedData);
+ }
+
+ if (offset && !drflac_seek_to_pcm_frame(flac_, offset * flac_->sampleRate)) {
+ return cpp::fail(Error::kMalformedData);
+ }
+
+ OutputFormat format{
+ .num_channels = static_cast<uint8_t>(flac_->channels),
+ .sample_rate_hz = static_cast<uint32_t>(flac_->sampleRate),
+ .total_samples = flac_->totalPCMFrameCount * flac_->channels,
+ };
+ return format;
+}
+
+auto DrFlacDecoder::DecodeTo(cpp::span<sample::Sample> output)
+ -> cpp::result<OutputInfo, Error> {
+ size_t frames_to_read = output.size() / flac_->channels / 2;
+
+ auto frames_written = drflac_read_pcm_frames_s16(
+ flac_, output.size() / flac_->channels, output.data());
+
+ return OutputInfo{
+ .samples_written = static_cast<size_t>(frames_written * flac_->channels),
+ .is_stream_finished = frames_written < frames_to_read};
+}
+
+} // namespace codecs
diff --git a/src/codecs/include/codec.hpp b/src/codecs/include/codec.hpp
index 8aa391b6..e48e3c58 100644
--- a/src/codecs/include/codec.hpp
+++ b/src/codecs/include/codec.hpp
@@ -117,7 +117,7 @@ class ICodec {
* Decodes metadata or headers from the given input stream, and returns the
* format for the samples that will be decoded from it.
*/
- virtual auto OpenStream(std::shared_ptr<IStream> input)
+ virtual auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset)
-> cpp::result<OutputFormat, Error> = 0;
struct OutputInfo {
@@ -130,8 +130,6 @@ class ICodec {
*/
virtual auto DecodeTo(cpp::span<sample::Sample> destination)
-> cpp::result<OutputInfo, Error> = 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/miniflac.hpp b/src/codecs/include/dr_flac.hpp
index d57b08a3..547876f4 100644
--- a/src/codecs/include/miniflac.hpp
+++ b/src/codecs/include/dr_flac.hpp
@@ -6,7 +6,6 @@
#pragma once
-#include <sys/_stdint.h>
#include <cstddef>
#include <cstdint>
#include <memory>
@@ -14,7 +13,7 @@
#include <string>
#include <utility>
-#include "miniflac.h"
+#include "dr_flac.h"
#include "sample.hpp"
#include "source_buffer.hpp"
#include "span.hpp"
@@ -23,29 +22,23 @@
namespace codecs {
-class MiniFlacDecoder : public ICodec {
+class DrFlacDecoder : public ICodec {
public:
- MiniFlacDecoder();
- ~MiniFlacDecoder();
+ DrFlacDecoder();
+ ~DrFlacDecoder();
- auto OpenStream(std::shared_ptr<IStream> input)
+ auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset)
-> 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;
-
- MiniFlacDecoder(const MiniFlacDecoder&) = delete;
- MiniFlacDecoder& operator=(const MiniFlacDecoder&) = delete;
+ DrFlacDecoder(const DrFlacDecoder&) = delete;
+ DrFlacDecoder& operator=(const DrFlacDecoder&) = delete;
private:
std::shared_ptr<IStream> input_;
- SourceBuffer buffer_;
-
- std::unique_ptr<miniflac_t> flac_;
- std::array<int32_t*, 2> samples_by_channel_;
- std::optional<size_t> current_sample_;
+ drflac *flac_;
};
} // namespace codecs
diff --git a/src/codecs/include/mad.hpp b/src/codecs/include/mad.hpp
index 813aa86d..ead0b2a2 100644
--- a/src/codecs/include/mad.hpp
+++ b/src/codecs/include/mad.hpp
@@ -26,14 +26,12 @@ class MadMp3Decoder : public ICodec {
MadMp3Decoder();
~MadMp3Decoder();
- auto OpenStream(std::shared_ptr<IStream> input)
+ auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset)
-> 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;
-
MadMp3Decoder(const MadMp3Decoder&) = delete;
MadMp3Decoder& operator=(const MadMp3Decoder&) = delete;
diff --git a/src/codecs/include/opus.hpp b/src/codecs/include/opus.hpp
index 45b1b07a..de2f7131 100644
--- a/src/codecs/include/opus.hpp
+++ b/src/codecs/include/opus.hpp
@@ -26,14 +26,12 @@ class XiphOpusDecoder : public ICodec {
XiphOpusDecoder();
~XiphOpusDecoder();
- auto OpenStream(std::shared_ptr<IStream> input)
+ auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset)
-> 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;
diff --git a/src/codecs/include/source_buffer.hpp b/src/codecs/include/source_buffer.hpp
index d0d7635a..7834834d 100644
--- a/src/codecs/include/source_buffer.hpp
+++ b/src/codecs/include/source_buffer.hpp
@@ -24,6 +24,7 @@ class 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;
+ auto Empty() -> void;
SourceBuffer(const SourceBuffer&) = delete;
SourceBuffer& operator=(const SourceBuffer&) = delete;
diff --git a/src/codecs/include/vorbis.hpp b/src/codecs/include/vorbis.hpp
index b96a0407..3cf0f9ce 100644
--- a/src/codecs/include/vorbis.hpp
+++ b/src/codecs/include/vorbis.hpp
@@ -26,14 +26,12 @@ class TremorVorbisDecoder : public ICodec {
TremorVorbisDecoder();
~TremorVorbisDecoder();
- auto OpenStream(std::shared_ptr<IStream> input)
+ auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset)
-> 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;
diff --git a/src/codecs/include/wav.hpp b/src/codecs/include/wav.hpp
index 896976dd..40138968 100644
--- a/src/codecs/include/wav.hpp
+++ b/src/codecs/include/wav.hpp
@@ -31,14 +31,12 @@ class WavDecoder : public ICodec {
WavDecoder();
~WavDecoder();
- auto OpenStream(std::shared_ptr<IStream> input)
+ auto OpenStream(std::shared_ptr<IStream> input,uint32_t offset)
-> 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;
-
WavDecoder(const WavDecoder&) = delete;
WavDecoder& operator=(const WavDecoder&) = delete;
diff --git a/src/codecs/mad.cpp b/src/codecs/mad.cpp
index f36636a1..e44e9922 100644
--- a/src/codecs/mad.cpp
+++ b/src/codecs/mad.cpp
@@ -44,6 +44,7 @@ MadMp3Decoder::MadMp3Decoder()
mad_frame_init(frame_.get());
mad_synth_init(synth_.get());
}
+
MadMp3Decoder::~MadMp3Decoder() {
mad_stream_finish(stream_.get());
mad_frame_finish(frame_.get());
@@ -58,7 +59,7 @@ auto MadMp3Decoder::GetBytesUsed() -> std::size_t {
}
}
-auto MadMp3Decoder::OpenStream(std::shared_ptr<IStream> input)
+auto MadMp3Decoder::OpenStream(std::shared_ptr<IStream> input, uint32_t offset)
-> cpp::result<OutputFormat, ICodec::Error> {
input_ = input;
@@ -113,6 +114,45 @@ auto MadMp3Decoder::OpenStream(std::shared_ptr<IStream> input)
auto cbr_length = input->Size().value() / (header.bitrate / 8);
output.total_samples = cbr_length * output.sample_rate_hz * channels;
}
+
+ mad_timer_t timer;
+ mad_timer_reset(&timer);
+ bool need_refill = false;
+ bool seek_err = false;
+
+ while (mad_timer_count(timer, MAD_UNITS_SECONDS) < offset) {
+ if (seek_err) {
+ return cpp::fail(ICodec::Error::kMalformedData);
+ }
+
+ if (need_refill && buffer_.Refill(input_.get())) {
+ return cpp::fail(ICodec::Error::kMalformedData);
+ }
+ need_refill = false;
+
+ buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t {
+ mad_stream_buffer(stream_.get(),
+ reinterpret_cast<const unsigned char*>(buf.data()),
+ buf.size());
+
+ while (mad_header_decode(&header, stream_.get()) < 0) {
+ if (MAD_RECOVERABLE(stream_->error)) {
+ continue;
+ }
+ if (stream_->error == MAD_ERROR_BUFLEN) {
+ need_refill = true;
+ return GetBytesUsed();
+ }
+ // The error is unrecoverable. Give up.
+ seek_err = true;
+ return 0;
+ }
+
+ mad_timer_add(&timer, header.duration);
+ return GetBytesUsed();
+ });
+ }
+
return output;
}
@@ -190,11 +230,6 @@ auto MadMp3Decoder::DecodeTo(cpp::span<sample::Sample> output)
.is_stream_finished = is_eos_};
}
-auto MadMp3Decoder::SeekTo(std::size_t target_sample)
- -> cpp::result<void, Error> {
- return {};
-}
-
auto MadMp3Decoder::SkipID3Tags(IStream& stream) -> void {
// First check that the file actually does start with ID3 tags.
std::array<std::byte, 3> magic_buf{};
@@ -222,8 +257,8 @@ auto MadMp3Decoder::SkipID3Tags(IStream& stream) -> void {
}
/*
- * Implementation taken from SDL_mixer and modified. Original is zlib-licensed,
- * copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
+ * Implementation taken from SDL_mixer and modified. Original is
+ * zlib-licensed, copyright (C) 1997-2022 Sam Lantinga <slouken@libsdl.org>
*/
auto MadMp3Decoder::GetVbrLength(const mad_header& header)
-> std::optional<uint32_t> {
diff --git a/src/codecs/miniflac.cpp b/src/codecs/miniflac.cpp
deleted file mode 100644
index 74eafb3b..00000000
--- a/src/codecs/miniflac.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright 2023 jacqueline <me@jacqueline.id.au>
- *
- * SPDX-License-Identifier: GPL-3.0-only
- */
-
-#include "miniflac.hpp"
-
-#include <cstdint>
-#include <cstdlib>
-
-#include "esp_heap_caps.h"
-#include "esp_log.h"
-#include "miniflac.h"
-#include "result.hpp"
-#include "sample.hpp"
-
-namespace codecs {
-
-[[maybe_unused]] static const char kTag[] = "flac";
-
-static constexpr size_t kMaxFrameSize = 4608;
-
-MiniFlacDecoder::MiniFlacDecoder()
- : input_(),
- buffer_(),
- flac_(reinterpret_cast<miniflac_t*>(
- heap_caps_malloc(sizeof(miniflac_t),
- MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT))),
- current_sample_() {
- miniflac_init(flac_.get(), MINIFLAC_CONTAINER_UNKNOWN);
- for (int i = 0; i < samples_by_channel_.size(); i++) {
- uint32_t caps;
- if (i == 0) {
- caps = MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL;
- } else {
- // FIXME: We can *almost* fit two channels into internal ram, but we're a
- // few KiB shy of being able to do it safely.
- caps = MALLOC_CAP_SPIRAM;
- }
- samples_by_channel_[i] = reinterpret_cast<int32_t*>(
- heap_caps_malloc(kMaxFrameSize * sizeof(int32_t), caps));
- }
-}
-
-MiniFlacDecoder::~MiniFlacDecoder() {
- for (int i = 0; i < samples_by_channel_.size(); i++) {
- heap_caps_free(samples_by_channel_[i]);
- }
-}
-
-auto MiniFlacDecoder::OpenStream(std::shared_ptr<IStream> input)
- -> cpp::result<OutputFormat, Error> {
- input_ = input;
-
- MINIFLAC_RESULT res;
- auto read_until_result = [&](auto fn) {
- while (true) {
- bool eof = buffer_.Refill(input_.get());
- buffer_.ConsumeBytes(fn);
- if (res == MINIFLAC_CONTINUE && !eof) {
- continue;
- }
- break;
- }
- };
-
- uint32_t sample_rate = 0;
-
- read_until_result([&](cpp::span<std::byte> buf) -> size_t {
- uint32_t bytes_used = 0;
- res = miniflac_streaminfo_sample_rate(
- flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()),
- buf.size_bytes(), &bytes_used, &sample_rate);
- return bytes_used;
- });
-
- if (res != MINIFLAC_OK) {
- return cpp::fail(Error::kMalformedData);
- }
-
- uint8_t channels = 0;
-
- read_until_result([&](cpp::span<std::byte> buf) -> size_t {
- uint32_t bytes_used = 0;
- res = miniflac_streaminfo_channels(
- flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()),
- buf.size_bytes(), &bytes_used, &channels);
- return bytes_used;
- });
-
- if (res != MINIFLAC_OK) {
- return cpp::fail(Error::kMalformedData);
- }
-
- uint64_t total_samples = 0;
-
- read_until_result([&](cpp::span<std::byte> buf) -> size_t {
- uint32_t bytes_used = 0;
- res = miniflac_streaminfo_total_samples(
- flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()),
- buf.size_bytes(), &bytes_used, &total_samples);
- return bytes_used;
- });
-
- if (res != MINIFLAC_OK) {
- return cpp::fail(Error::kMalformedData);
- }
-
- if (channels == 0 || channels > 2) {
- return cpp::fail(Error::kMalformedData);
- }
-
- OutputFormat format{
- .num_channels = static_cast<uint8_t>(channels),
- .sample_rate_hz = static_cast<uint32_t>(sample_rate),
- .total_samples = total_samples * channels,
- };
-
- return format;
-}
-
-auto MiniFlacDecoder::DecodeTo(cpp::span<sample::Sample> output)
- -> cpp::result<OutputInfo, Error> {
- bool is_eof = false;
-
- if (!current_sample_) {
- MINIFLAC_RESULT res = MINIFLAC_CONTINUE;
- while (res == MINIFLAC_CONTINUE && !is_eof) {
- is_eof = buffer_.Refill(input_.get());
- buffer_.ConsumeBytes([&](cpp::span<std::byte> buf) -> size_t {
- // FIXME: We should do a miniflac_sync first, in order to check that
- // our sample buffers have enough space for the next frame.
- uint32_t bytes_read = 0;
- res = miniflac_decode(
- flac_.get(), reinterpret_cast<const uint8_t*>(buf.data()),
- buf.size_bytes(), &bytes_read, samples_by_channel_.data());
- return bytes_read;
- });
- }
-
- if (res == MINIFLAC_OK) {
- current_sample_ = 0;
- } else if (is_eof) {
- return OutputInfo{
- .samples_written = 0,
- .is_stream_finished = true,
- };
- } else {
- return cpp::fail(Error::kMalformedData);
- }
- }
-
- size_t samples_written = 0;
- if (current_sample_) {
- while (*current_sample_ < flac_->frame.header.block_size) {
- if (samples_written + flac_->frame.header.channels >= output.size()) {
- // We can't fit the next full PCM frame into the buffer.
- return OutputInfo{.samples_written = samples_written,
- .is_stream_finished = false};
- }
-
- for (int channel = 0; channel < flac_->frame.header.channels; channel++) {
- output[samples_written++] =
- sample::FromSigned(samples_by_channel_[channel][*current_sample_],
- flac_->frame.header.bps);
- }
- (*current_sample_)++;
- }
- }
-
- current_sample_.reset();
- return OutputInfo{.samples_written = samples_written,
- .is_stream_finished = samples_written == 0 && is_eof};
-}
-
-auto MiniFlacDecoder::SeekTo(size_t target) -> cpp::result<void, Error> {
- return {};
-}
-
-} // namespace codecs
diff --git a/src/codecs/opus.cpp b/src/codecs/opus.cpp
index e4917a33..a5220c4b 100644
--- a/src/codecs/opus.cpp
+++ b/src/codecs/opus.cpp
@@ -78,7 +78,8 @@ XiphOpusDecoder::~XiphOpusDecoder() {
}
}
-auto XiphOpusDecoder::OpenStream(std::shared_ptr<IStream> input)
+auto XiphOpusDecoder::OpenStream(std::shared_ptr<IStream> input,
+ uint32_t offset)
-> cpp::result<OutputFormat, Error> {
input_ = input;
@@ -128,6 +129,10 @@ auto XiphOpusDecoder::OpenStream(std::shared_ptr<IStream> input)
length = l * 2;
}
+ if (offset && op_pcm_seek(opus_, offset * 48000) != 0) {
+ return cpp::fail(Error::kInternalError);
+ }
+
return OutputFormat{
.num_channels = 2,
.sample_rate_hz = 48000,
@@ -151,11 +156,4 @@ auto XiphOpusDecoder::DecodeTo(cpp::span<sample::Sample> output)
};
}
-auto XiphOpusDecoder::SeekTo(size_t target) -> cpp::result<void, Error> {
- if (op_pcm_seek(opus_, target) != 0) {
- return cpp::fail(Error::kInternalError);
- }
- return {};
-}
-
} // namespace codecs
diff --git a/src/codecs/source_buffer.cpp b/src/codecs/source_buffer.cpp
index 3b455038..0a986bc3 100644
--- a/src/codecs/source_buffer.cpp
+++ b/src/codecs/source_buffer.cpp
@@ -74,4 +74,9 @@ auto SourceBuffer::ConsumeBytes(
}
}
+auto SourceBuffer::Empty() -> void {
+ offset_of_bytes_ = 0;
+ bytes_in_buffer_ = 0;
+}
+
} // namespace codecs
diff --git a/src/codecs/vorbis.cpp b/src/codecs/vorbis.cpp
index 7fb53f1b..9131451b 100644
--- a/src/codecs/vorbis.cpp
+++ b/src/codecs/vorbis.cpp
@@ -77,7 +77,8 @@ TremorVorbisDecoder::~TremorVorbisDecoder() {
ov_clear(vorbis_.get());
}
-auto TremorVorbisDecoder::OpenStream(std::shared_ptr<IStream> input)
+auto TremorVorbisDecoder::OpenStream(std::shared_ptr<IStream> input,
+ uint32_t offset)
-> cpp::result<OutputFormat, Error> {
int res = ov_open_callbacks(input.get(), vorbis_.get(), NULL, 0, kCallbacks);
if (res < 0) {
@@ -117,6 +118,10 @@ auto TremorVorbisDecoder::OpenStream(std::shared_ptr<IStream> input)
length = l * info->channels;
}
+ if (offset && ov_time_seek(vorbis_.get(), offset * 1000) != 0) {
+ return cpp::fail(Error::kInternalError);
+ }
+
return OutputFormat{
.num_channels = static_cast<uint8_t>(info->channels),
.sample_rate_hz = static_cast<uint32_t>(info->rate),
@@ -145,11 +150,4 @@ auto TremorVorbisDecoder::DecodeTo(cpp::span<sample::Sample> output)
};
}
-auto TremorVorbisDecoder::SeekTo(size_t target) -> cpp::result<void, Error> {
- if (ov_pcm_seek(vorbis_.get(), target) != 0) {
- return cpp::fail(Error::kInternalError);
- }
- return {};
-}
-
} // namespace codecs
diff --git a/src/codecs/wav.cpp b/src/codecs/wav.cpp
index a67f3ff4..143a7a4b 100644
--- a/src/codecs/wav.cpp
+++ b/src/codecs/wav.cpp
@@ -84,7 +84,7 @@ WavDecoder::WavDecoder() : input_(), buffer_() {}
WavDecoder::~WavDecoder() {}
-auto WavDecoder::OpenStream(std::shared_ptr<IStream> input)
+auto WavDecoder::OpenStream(std::shared_ptr<IStream> input,uint32_t offset)
-> cpp::result<OutputFormat, Error> {
input_ = input;
@@ -199,8 +199,10 @@ auto WavDecoder::OpenStream(std::shared_ptr<IStream> input)
return cpp::fail(Error::kUnsupportedFormat);
}
+ int64_t data_offset = offset * samples_per_second * bytes_per_sample_;
+
// Seek track to start of data
- input->SeekTo(data_chunk_index + 8, IStream::SeekFrom::kStartOfStream);
+ input->SeekTo(data_chunk_index + 8 + data_offset, IStream::SeekFrom::kStartOfStream);
output_format_ = {.num_channels = (uint8_t)num_channels_,
.sample_rate_hz = samples_per_second,
@@ -241,14 +243,11 @@ auto WavDecoder::DecodeTo(cpp::span<sample::Sample> output)
return samples_written * bytes_per_sample_;
});
+
return OutputInfo{.samples_written = samples_written,
.is_stream_finished = samples_written == 0 && is_eof};
}
-auto WavDecoder::SeekTo(size_t target) -> cpp::result<void, Error> {
- return {};
-}
-
auto codecs::WavDecoder::GetFormat() const -> uint16_t {
if (wave_format_ == kWaveFormatExtensible) {
return subformat_;