From c98315d486ad9052278de87054d1b2f795585eef Mon Sep 17 00:00:00 2001 From: Vladislav Mikhalin Date: Tue, 5 Nov 2024 09:40:34 +0300 Subject: [PATCH] refactored ajm --- src/core/libraries/ajm/ajm_at9.cpp | 7 +- src/core/libraries/ajm/ajm_at9.h | 4 +- src/core/libraries/ajm/ajm_instance.cpp | 5 +- src/core/libraries/ajm/ajm_instance.h | 6 +- src/core/libraries/ajm/ajm_mp3.cpp | 181 +++++++++--------------- src/core/libraries/ajm/ajm_mp3.h | 26 ++-- 6 files changed, 91 insertions(+), 138 deletions(-) diff --git a/src/core/libraries/ajm/ajm_at9.cpp b/src/core/libraries/ajm/ajm_at9.cpp index 441c0fbb4..07647c521 100644 --- a/src/core/libraries/ajm/ajm_at9.cpp +++ b/src/core/libraries/ajm/ajm_at9.cpp @@ -51,8 +51,9 @@ void AjmAt9Decoder::GetInfo(void* out_info) { info->next_frame_size = static_cast(m_handle)->Config.FrameBytes; } -u32 AjmAt9Decoder::ProcessFrame(std::span& in_buf, SparseOutputBuffer& output, - AjmSidebandGaplessDecode& gapless, u32 max_samples_per_channel) { +std::tuple AjmAt9Decoder::ProcessData(std::span& in_buf, SparseOutputBuffer& output, + AjmSidebandGaplessDecode& gapless, + u32 max_samples_per_channel) { int bytes_used = 0; u32 ret = Atrac9Decode(m_handle, in_buf.data(), m_pcm_buffer.data(), &bytes_used); ASSERT_MSG(ret == At9Status::ERR_SUCCESS, "Atrac9Decode failed ret = {:#x}", ret); @@ -84,7 +85,7 @@ u32 AjmAt9Decoder::ProcessFrame(std::span& in_buf, SparseOutputBuffer& outpu m_num_frames = 0; } - return (written / m_codec_info.channels) / sizeof(s16); + return {1, (written / m_codec_info.channels) / sizeof(s16)}; } } // namespace Libraries::Ajm diff --git a/src/core/libraries/ajm/ajm_at9.h b/src/core/libraries/ajm/ajm_at9.h index b0999ed0d..e89e69cec 100644 --- a/src/core/libraries/ajm/ajm_at9.h +++ b/src/core/libraries/ajm/ajm_at9.h @@ -26,8 +26,8 @@ struct AjmAt9Decoder final : AjmCodec { void Reset() override; void Initialize(const void* buffer, u32 buffer_size) override; void GetInfo(void* out_info) override; - u32 ProcessFrame(std::span& input, SparseOutputBuffer& output, - AjmSidebandGaplessDecode& gapless, u32 max_samples) override; + std::tuple ProcessData(std::span& input, SparseOutputBuffer& output, + AjmSidebandGaplessDecode& gapless, u32 max_samples) override; private: void* m_handle{}; diff --git a/src/core/libraries/ajm/ajm_instance.cpp b/src/core/libraries/ajm/ajm_instance.cpp index 89fcd2d9f..259fbc268 100644 --- a/src/core/libraries/ajm/ajm_instance.cpp +++ b/src/core/libraries/ajm/ajm_instance.cpp @@ -65,8 +65,9 @@ void AjmInstance::ExecuteJob(AjmJob& job) { const u32 samples_remain = m_gapless.total_samples != 0 ? m_gapless.total_samples - m_gapless_samples : std::numeric_limits::max(); - const auto nsamples = m_codec->ProcessFrame(in_buf, out_buf, m_gapless, samples_remain); - ++frames_decoded; + const auto [nframes, nsamples] = + m_codec->ProcessData(in_buf, out_buf, m_gapless, samples_remain); + frames_decoded += nframes; m_total_samples += nsamples; m_gapless_samples += nsamples; } diff --git a/src/core/libraries/ajm/ajm_instance.h b/src/core/libraries/ajm/ajm_instance.h index d8e9a6430..7c00c43ad 100644 --- a/src/core/libraries/ajm/ajm_instance.h +++ b/src/core/libraries/ajm/ajm_instance.h @@ -10,6 +10,7 @@ #include #include +#include namespace Libraries::Ajm { @@ -76,8 +77,9 @@ public: virtual void Initialize(const void* buffer, u32 buffer_size) = 0; virtual void Reset() = 0; virtual void GetInfo(void* out_info) = 0; - virtual u32 ProcessFrame(std::span& input, SparseOutputBuffer& output, - AjmSidebandGaplessDecode& gapless, u32 max_samples) = 0; + virtual std::tuple ProcessData(std::span& input, SparseOutputBuffer& output, + AjmSidebandGaplessDecode& gapless, + u32 max_samples) = 0; }; class AjmInstance { diff --git a/src/core/libraries/ajm/ajm_mp3.cpp b/src/core/libraries/ajm/ajm_mp3.cpp index 90a2c8232..542b31bee 100644 --- a/src/core/libraries/ajm/ajm_mp3.cpp +++ b/src/core/libraries/ajm/ajm_mp3.cpp @@ -54,136 +54,87 @@ AVFrame* ConvertAudioFrame(AVFrame* frame) { } AjmMp3Decoder::AjmMp3Decoder() { - codec = avcodec_find_decoder(AV_CODEC_ID_MP3); - ASSERT_MSG(codec, "MP3 codec not found"); - parser = av_parser_init(codec->id); - ASSERT_MSG(parser, "Parser not found"); + m_codec = avcodec_find_decoder(AV_CODEC_ID_MP3); + ASSERT_MSG(m_codec, "MP3 m_codec not found"); + m_parser = av_parser_init(m_codec->id); + ASSERT_MSG(m_parser, "Parser not found"); AjmMp3Decoder::Reset(); } AjmMp3Decoder::~AjmMp3Decoder() { - avcodec_free_context(&codec_context); - av_free(codec_context); + avcodec_free_context(&m_codec_context); } void AjmMp3Decoder::Reset() { - if (codec_context) { - avcodec_free_context(&codec_context); - av_free(codec_context); + if (m_codec_context) { + avcodec_free_context(&m_codec_context); } - codec_context = avcodec_alloc_context3(codec); - ASSERT_MSG(codec_context, "Could not allocate audio codec context"); - int ret = avcodec_open2(codec_context, codec, nullptr); - ASSERT_MSG(ret >= 0, "Could not open codec"); - // total_decoded_samples = 0; - // gapless_decoded_samples = 0; + m_codec_context = avcodec_alloc_context3(m_codec); + ASSERT_MSG(m_codec_context, "Could not allocate audio m_codec context"); + int ret = avcodec_open2(m_codec_context, m_codec, nullptr); + ASSERT_MSG(ret >= 0, "Could not open m_codec"); } -u32 AjmMp3Decoder::ProcessFrame(std::span& input, SparseOutputBuffer& output, - AjmSidebandGaplessDecode& gapless, u32 max_samples) { - // AVPacket* pkt = av_packet_alloc(); +void AjmMp3Decoder::GetInfo(void* out_info) { + auto* info = reinterpret_cast(out_info); +} - // size_t out_buffer_index = 0; - // std::span in_buf(input->buffer); - // std::span out_buf = output->buffers[out_buffer_index]; - // const auto should_decode = [&] { - // if (in_buf.empty() || out_buf.empty()) { - // return false; - // } - // if (gapless.total_samples != 0 && gapless.total_samples < gapless_decoded_samples) { - // return false; - // } - // return true; - // }; +std::tuple AjmMp3Decoder::ProcessData(std::span& in_buf, SparseOutputBuffer& output, + AjmSidebandGaplessDecode& gapless, + u32 max_samples) { + AVPacket* pkt = av_packet_alloc(); - // const auto write_output = [&](std::span pcm) { - // while (!pcm.empty()) { - // auto size = std::min(pcm.size() * sizeof(u16), out_buf.size()); - // std::memcpy(out_buf.data(), pcm.data(), size); - // pcm = pcm.subspan(size >> 1); - // out_buf = out_buf.subspan(size); - // if (out_buf.empty()) { - // out_buffer_index += 1; - // if (out_buffer_index >= output->buffers.size()) { - // return pcm.empty(); - // } - // out_buf = output->buffers[out_buffer_index]; - // } - // } - // return true; - // }; + int ret = av_parser_parse2(m_parser, m_codec_context, &pkt->data, &pkt->size, in_buf.data(), + in_buf.size(), AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); + ASSERT_MSG(ret >= 0, "Error while parsing {}", ret); + in_buf = in_buf.subspan(ret); - // while (should_decode()) { - // int ret = av_parser_parse2(parser, codec_context, &pkt->data, &pkt->size, in_buf.data(), - // in_buf.size(), AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0); - // ASSERT_MSG(ret >= 0, "Error while parsing {}", ret); - // in_buf = in_buf.subspan(ret); + u32 frames_decoded = 0; + u32 samples_decoded = 0; - // if (output->p_stream) { - // output->p_stream->input_consumed += ret; - // } - // if (pkt->size) { - // // Send the packet with the compressed data to the decoder - // pkt->pts = parser->pts; - // pkt->dts = parser->dts; - // pkt->flags = (parser->key_frame == 1) ? AV_PKT_FLAG_KEY : 0; - // ret = avcodec_send_packet(codec_context, pkt); - // ASSERT_MSG(ret >= 0, "Error submitting the packet to the decoder {}", ret); + if (pkt->size) { + // Send the packet with the compressed data to the decoder + pkt->pts = m_parser->pts; + pkt->dts = m_parser->dts; + pkt->flags = (m_parser->key_frame == 1) ? AV_PKT_FLAG_KEY : 0; + ret = avcodec_send_packet(m_codec_context, pkt); + ASSERT_MSG(ret >= 0, "Error submitting the packet to the decoder {}", ret); - // // Read all the output frames (in general there may be any number of them - // while (ret >= 0) { - // AVFrame* frame = av_frame_alloc(); - // ret = avcodec_receive_frame(codec_context, frame); - // if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { - // break; - // } else if (ret < 0) { - // UNREACHABLE_MSG("Error during decoding"); - // } - // if (frame->format != AV_SAMPLE_FMT_S16) { - // frame = ConvertAudioFrame(frame); - // } - // const auto size = frame->ch_layout.nb_channels * frame->nb_samples * sizeof(u16); - // if (gapless.skipped_samples < gapless.skip_samples) { - // gapless.skipped_samples += frame->nb_samples; - // if (gapless.skipped_samples > gapless.skip_samples) { - // const u32 nsamples = gapless.skipped_samples - gapless.skip_samples; - // const auto start = frame->nb_samples - nsamples; - // write_output({reinterpret_cast(frame->data[0]), - // nsamples * frame->ch_layout.nb_channels}); - // gapless.skipped_samples = gapless.skip_samples; - // total_decoded_samples += nsamples; - // if (gapless.total_samples != 0) { - // gapless_decoded_samples += nsamples; - // } - // } - // } else { - // write_output({reinterpret_cast(frame->data[0]), size >> 1}); - // total_decoded_samples += frame->nb_samples; - // if (gapless.total_samples != 0) { - // gapless_decoded_samples += frame->nb_samples; - // } - // } - // av_frame_free(&frame); - // if (output->p_stream) { - // output->p_stream->output_written += size; - // } - // if (output->p_mframe) { - // output->p_mframe->num_frames += 1; - // } - // } - // } - // } - // av_packet_free(&pkt); - // if (gapless.total_samples != 0 && gapless_decoded_samples >= gapless.total_samples) { - // if (flags.gapless_loop) { - // gapless.skipped_samples = 0; - // gapless_decoded_samples = 0; - // } - // } - // if (output->p_stream) { - // output->p_stream->total_decoded_samples = total_decoded_samples; - // } - return 0; + // Read all the output frames (in general there may be any number of them + while (ret >= 0) { + AVFrame* frame = av_frame_alloc(); + ret = avcodec_receive_frame(m_codec_context, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + break; + } else if (ret < 0) { + UNREACHABLE_MSG("Error during decoding"); + } + if (frame->format != AV_SAMPLE_FMT_S16) { + frame = ConvertAudioFrame(frame); + } + + frames_decoded += 1; + samples_decoded += frame->nb_samples; + const auto size = frame->ch_layout.nb_channels * frame->nb_samples * sizeof(u16); + std::span pcm_data(reinterpret_cast(frame->data[0]), size >> 1); + if (gapless.skipped_samples < gapless.skip_samples) { + const auto skipped_samples = std::min( + u32(frame->nb_samples), u32(gapless.skip_samples - gapless.skipped_samples)); + gapless.skipped_samples += skipped_samples; + pcm_data = pcm_data.subspan(skipped_samples * frame->ch_layout.nb_channels); + samples_decoded -= skipped_samples; + } + + const auto pcm_size = std::min(u32(pcm_data.size()), max_samples); + output.Write(pcm_data.subspan(0, pcm_size)); + + av_frame_free(&frame); + } + } + + av_packet_free(&pkt); + + return {frames_decoded, samples_decoded}; } int AjmMp3Decoder::ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl, diff --git a/src/core/libraries/ajm/ajm_mp3.h b/src/core/libraries/ajm/ajm_mp3.h index 2874f9077..d2acf7abc 100644 --- a/src/core/libraries/ajm/ajm_mp3.h +++ b/src/core/libraries/ajm/ajm_mp3.h @@ -3,7 +3,6 @@ #pragma once -#include #include "common/types.h" #include "core/libraries/ajm/ajm_instance.h" @@ -11,6 +10,8 @@ extern "C" { struct AVCodec; struct AVCodecContext; struct AVCodecParserContext; +struct AVFrame; +struct AVPacket; } namespace Libraries::Ajm { @@ -51,27 +52,24 @@ struct AjmSidebandDecMp3CodecInfo { u16 reserved[3]; }; -struct AjmDecMp3GetCodecInfoResult { - AjmSidebandResult result; - AjmSidebandDecMp3CodecInfo codec_info; -}; - -struct AjmMp3Decoder : public AjmCodec { - const AVCodec* codec = nullptr; - AVCodecContext* codec_context = nullptr; - AVCodecParserContext* parser = nullptr; - +class AjmMp3Decoder : public AjmCodec { +public: explicit AjmMp3Decoder(); ~AjmMp3Decoder() override; void Reset() override; void Initialize(const void* buffer, u32 buffer_size) override {} - void GetInfo(void* out_info) override {} - u32 ProcessFrame(std::span& input, SparseOutputBuffer& output, - AjmSidebandGaplessDecode& gapless, u32 max_samples) override; + void GetInfo(void* out_info) override; + std::tuple ProcessData(std::span& input, SparseOutputBuffer& output, + AjmSidebandGaplessDecode& gapless, u32 max_samples) override; static int ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl, AjmDecMp3ParseFrame* frame); + +private: + const AVCodec* m_codec = nullptr; + AVCodecContext* m_codec_context = nullptr; + AVCodecParserContext* m_parser = nullptr; }; } // namespace Libraries::Ajm