diff --git a/CMakeLists.txt b/CMakeLists.txt index 04534ec26..d28e657cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -275,6 +275,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.cpp b/src/core/libraries/ajm/ajm.cpp index 83620250b..ccad2622d 100644 --- a/src/core/libraries/ajm/ajm.cpp +++ b/src/core/libraries/ajm/ajm.cpp @@ -59,7 +59,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobControlBufferRa(void* p_buffer, u32 instance_id void* p_sideband_output, size_t sideband_output_size, void* p_return_address) { - return BatchJobControlBufferRa(p_buffer, instance_id, flags, p_sideband_input, + return BatchJobControlBufferRa(p_buffer, instance_id & 0x3FFF, flags, p_sideband_input, sideband_input_size, p_sideband_output, sideband_output_size, p_return_address); } @@ -75,7 +75,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunBufferRa(void* p_buffer, u32 instance_id, u6 void* p_data_output, size_t data_output_size, void* p_sideband_output, size_t sideband_output_size, void* p_return_address) { - return BatchJobRunBufferRa(p_buffer, instance_id, flags, p_data_input, data_input_size, + return BatchJobRunBufferRa(p_buffer, instance_id & 0x3FFF, flags, p_data_input, data_input_size, p_data_output, data_output_size, p_sideband_output, sideband_output_size, p_return_address); } @@ -85,7 +85,7 @@ void* PS4_SYSV_ABI sceAjmBatchJobRunSplitBufferRa( size_t num_data_input_buffers, const AjmBuffer* p_data_output_buffers, size_t num_data_output_buffers, void* p_sideband_output, size_t sideband_output_size, void* p_return_address) { - return BatchJobRunSplitBufferRa(p_buffer, instance_id, flags, p_data_input_buffers, + return BatchJobRunSplitBufferRa(p_buffer, instance_id & 0x3FFF, flags, p_data_input_buffers, num_data_input_buffers, p_data_output_buffers, num_data_output_buffers, p_sideband_output, sideband_output_size, p_return_address); @@ -144,9 +144,8 @@ int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* p_context_id) { return ORBIS_OK; } -int PS4_SYSV_ABI sceAjmInstanceCodecType() { - LOG_ERROR(Lib_Ajm, "(STUBBED) called"); - return ORBIS_OK; +int PS4_SYSV_ABI sceAjmInstanceCodecType(u32 instance) { + return instance >> 0xe; } int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context_id, AjmCodecType codec_type, @@ -170,7 +169,7 @@ int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context_id, u32 instance_id) { return ORBIS_AJM_ERROR_INVALID_CONTEXT; } - return it->second->InstanceDestroy(instance_id); + return it->second->InstanceDestroy(instance_id & 0x3FFF); } int PS4_SYSV_ABI sceAjmInstanceExtend() { diff --git a/src/core/libraries/ajm/ajm.h b/src/core/libraries/ajm/ajm.h index 2c529cd4b..466dbd209 100644 --- a/src/core/libraries/ajm/ajm.h +++ b/src/core/libraries/ajm/ajm.h @@ -217,7 +217,7 @@ int PS4_SYSV_ABI sceAjmDecMp3ParseFrame(const u8* stream, u32 stream_size, int p AjmDecMp3ParseFrame* frame); int PS4_SYSV_ABI sceAjmFinalize(); int PS4_SYSV_ABI sceAjmInitialize(s64 reserved, u32* out_context); -int PS4_SYSV_ABI sceAjmInstanceCodecType(); +int PS4_SYSV_ABI sceAjmInstanceCodecType(u32 instance); int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmInstanceFlags flags, u32* instance); int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance); diff --git a/src/core/libraries/ajm/ajm_context.cpp b/src/core/libraries/ajm/ajm_context.cpp index 0e2915f32..65dad1ddb 100644 --- a/src/core/libraries/ajm/ajm_context.cpp +++ b/src/core/libraries/ajm/ajm_context.cpp @@ -169,7 +169,7 @@ s32 AjmContext::InstanceCreate(AjmCodecType codec_type, AjmInstanceFlags flags, if (!opt_index.has_value()) { return ORBIS_AJM_ERROR_OUT_OF_RESOURCES; } - *out_instance = opt_index.value(); + *out_instance = (static_cast(codec_type) << 14) | opt_index.value(); LOG_INFO(Lib_Ajm, "instance = {}", *out_instance); return ORBIS_OK; diff --git a/src/core/libraries/ajm/ajm_instance.cpp b/src/core/libraries/ajm/ajm_instance.cpp index c4ea395b9..35694ff3a 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..2bb53ee73 --- /dev/null +++ b/src/core/libraries/ajm/ajm_m4aac.cpp @@ -0,0 +1,47 @@ +// 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..bcef963da --- /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