summaryrefslogtreecommitdiff
path: root/src/codecs/mad.cpp
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2024-02-28 21:21:23 +1100
committerjacqueline <me@jacqueline.id.au>2024-02-28 21:21:23 +1100
commit77145e56f4062cd060ee7fa0af9ad1a2e46df5b1 (patch)
tree76a1e6734cd92d47362f2c04b539f20b47492641 /src/codecs/mad.cpp
parentf54347794f45261e0c0fde1104a70d1063c77305 (diff)
downloadtangara-fw-77145e56f4062cd060ee7fa0af9ad1a2e46df5b1.tar.gz
basic working flac and mp3 seeking
flac impl is fairly slow as it doesn't use the seek tables; for some reason miniflac seems to get *really* upset if you seek the stream.
Diffstat (limited to 'src/codecs/mad.cpp')
-rw-r--r--src/codecs/mad.cpp46
1 files changed, 43 insertions, 3 deletions
diff --git a/src/codecs/mad.cpp b/src/codecs/mad.cpp
index 0617295f..b11821f0 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,uint32_t offset)
+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,uint32_t offset)
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;
}
@@ -222,8 +262,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> {