diff --git a/CMakeLists.txt b/CMakeLists.txt index adff454b8..df2a48fbc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -296,6 +296,8 @@ set(AJM_LIB src/core/libraries/ajm/ajm.cpp src/core/libraries/ajm/ajm_instance.h src/core/libraries/ajm/ajm_mp3.cpp src/core/libraries/ajm/ajm_mp3.h + src/core/libraries/ajm/ajm_m4aac.cpp + src/core/libraries/ajm/ajm_m4aac.h ) set(AUDIO_LIB src/core/libraries/audio/audioin.cpp diff --git a/src/core/libraries/ajm/ajm_instance.cpp b/src/core/libraries/ajm/ajm_instance.cpp index 01b1d2b21..55f9df86d 100644 --- a/src/core/libraries/ajm/ajm_instance.cpp +++ b/src/core/libraries/ajm/ajm_instance.cpp @@ -3,6 +3,7 @@ #include "core/libraries/ajm/ajm_at9.h" #include "core/libraries/ajm/ajm_instance.h" +#include "core/libraries/ajm/ajm_m4aac.h" #include "core/libraries/ajm/ajm_mp3.h" #include @@ -47,6 +48,11 @@ AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_fl AjmMp3CodecFlags(flags.codec)); break; } + case AjmCodecType::M4aacDec: { + m_codec = std::make_unique(AjmFormatEncoding(flags.format), + AjmM4aacCodecFlags(flags.codec)); + break; + } default: UNREACHABLE_MSG("Unimplemented codec type {}", magic_enum::enum_name(codec_type)); } diff --git a/src/core/libraries/ajm/ajm_m4aac.cpp b/src/core/libraries/ajm/ajm_m4aac.cpp new file mode 100644 index 000000000..da2b43475 --- /dev/null +++ b/src/core/libraries/ajm/ajm_m4aac.cpp @@ -0,0 +1,44 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "core/libraries/ajm/ajm_error.h" +#include "core/libraries/ajm/ajm_m4aac.h" +#include "core/libraries/error_codes.h" + +extern "C" { +#include +#include +#include +} + +#include "common/support/avdec.h" + +namespace Libraries::Ajm { +AjmM4aacDecoder::AjmM4aacDecoder(AjmFormatEncoding format, AjmM4aacCodecFlags flags) + : m_format(format), m_flags(flags), m_codec(avcodec_find_decoder(AV_CODEC_ID_AAC)), + m_codec_context(avcodec_alloc_context3(m_codec)), m_parser(av_parser_init(m_codec->id)) { + int ret = avcodec_open2(m_codec_context, m_codec, nullptr); + ASSERT_MSG(ret >= 0, "Could not open m_codec"); +} +AjmM4aacDecoder::~AjmM4aacDecoder() { + swr_free(&m_swr_context); + av_parser_close(m_parser); + avcodec_free_context(&m_codec_context); +} +void AjmM4aacDecoder::Reset() {} +void AjmM4aacDecoder::GetInfo(void* out_info) const {} +AjmSidebandFormat AjmM4aacDecoder::GetFormat() const { + return AjmSidebandFormat(); +} +u32 AjmM4aacDecoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const { + return u32(); +} +std::tuple AjmM4aacDecoder::ProcessData(std::span& input, SparseOutputBuffer& output, + AjmInstanceGapless& gapless) { + return std::tuple(); +} +AVFrame* AjmM4aacDecoder::ConvertAudioFrame(AVFrame* frame) { + return nullptr; +} +} // namespace Libraries::Ajm \ No newline at end of file diff --git a/src/core/libraries/ajm/ajm_m4aac.h b/src/core/libraries/ajm/ajm_m4aac.h new file mode 100644 index 000000000..3c7507d8c --- /dev/null +++ b/src/core/libraries/ajm/ajm_m4aac.h @@ -0,0 +1,59 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" +#include "core/libraries/ajm/ajm_instance.h" + +extern "C" { +#include +struct SwrContext; +} + +namespace Libraries::Ajm { + +enum AjmM4aacCodecFlags : u32 { + SbrDecode = 1 << 0, + NodelayOutput = 1 << 8, + InterleaveOrderExtlExtrLsRs = 1 << 16, + InterleaveOrderLsRsExtlExtr = 1 << 24 +}; +DECLARE_ENUM_FLAG_OPERATORS(AjmM4aacCodecFlags) + +class AjmM4aacDecoder : public AjmCodec { +public: + explicit AjmM4aacDecoder(AjmFormatEncoding format, AjmM4aacCodecFlags flags); + ~AjmM4aacDecoder() override; + + void Reset() override; + void Initialize(const void* buffer, u32 buffer_size) override {} + void GetInfo(void* out_info) const override; + AjmSidebandFormat GetFormat() const override; + u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override; + std::tuple ProcessData(std::span& input, SparseOutputBuffer& output, + AjmInstanceGapless& gapless) override; + +private: + template + size_t WriteOutputPCM(AVFrame* frame, SparseOutputBuffer& output, u32 skipped_samples, + u32 max_pcm) { + std::span pcm_data(reinterpret_cast(frame->data[0]), + frame->nb_samples * frame->ch_layout.nb_channels); + pcm_data = pcm_data.subspan(skipped_samples * frame->ch_layout.nb_channels); + return output.Write(pcm_data.subspan(0, std::min(u32(pcm_data.size()), max_pcm))); + } + + AVFrame* ConvertAudioFrame(AVFrame* frame); + + const AjmFormatEncoding m_format; + const AjmM4aacCodecFlags m_flags; + const AVCodec* m_codec = nullptr; + AVCodecContext* m_codec_context = nullptr; + AVCodecParserContext* m_parser = nullptr; + SwrContext* m_swr_context = nullptr; + std::optional m_header; + u32 m_frame_samples = 0; +}; + +} // namespace Libraries::Ajm