From 77145e56f4062cd060ee7fa0af9ad1a2e46df5b1 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Wed, 28 Feb 2024 21:21:23 +1100 Subject: 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. --- src/codecs/mad.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) (limited to 'src/codecs/mad.cpp') 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 input,uint32_t offset) +auto MadMp3Decoder::OpenStream(std::shared_ptr input, uint32_t offset) -> cpp::result { input_ = input; @@ -113,6 +114,45 @@ auto MadMp3Decoder::OpenStream(std::shared_ptr 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 buf) -> size_t { + mad_stream_buffer(stream_.get(), + reinterpret_cast(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 + * Implementation taken from SDL_mixer and modified. Original is + * zlib-licensed, copyright (C) 1997-2022 Sam Lantinga */ auto MadMp3Decoder::GetVbrLength(const mad_header& header) -> std::optional { -- cgit v1.2.3