ajm: support for m4aac (#3880)

* ajm m4aac

* fix build on unix

* small tunes

* skip 2 frames if nodelay is not set, change to google repo
This commit is contained in:
Vladislav Mikhalin
2025-12-28 14:24:42 +03:00
committed by GitHub
parent aa227cae57
commit 9a3e4ea56b
16 changed files with 460 additions and 24 deletions

3
.gitmodules vendored
View File

@@ -120,3 +120,6 @@
[submodule "externals/miniz"]
path = externals/miniz
url = https://github.com/richgel999/miniz
[submodule "externals/aacdec/fdk-aac"]
path = externals/aacdec/fdk-aac
url = https://android.googlesource.com/platform/external/aac

View File

@@ -262,6 +262,8 @@ include_directories(src)
set(AJM_LIB src/core/libraries/ajm/ajm.cpp
src/core/libraries/ajm/ajm.h
src/core/libraries/ajm/ajm_aac.cpp
src/core/libraries/ajm/ajm_aac.h
src/core/libraries/ajm/ajm_at9.cpp
src/core/libraries/ajm/ajm_at9.h
src/core/libraries/ajm/ajm_batch.cpp
@@ -1085,7 +1087,7 @@ create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_mixer::SDL3_mixer pugixml::pugixml)
target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz)
target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz fdk-aac)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")

View File

@@ -258,6 +258,10 @@ if (WIN32)
add_subdirectory(ext-wepoll)
endif()
if (NOT TARGET fdk-aac)
add_subdirectory(aacdec)
endif()
#nlohmann json
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(json)

154
externals/aacdec/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,154 @@
# SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
set(AACDEC_SRC
fdk-aac/libAACdec/src/FDK_delay.cpp
fdk-aac/libAACdec/src/aac_ram.cpp
fdk-aac/libAACdec/src/aac_rom.cpp
fdk-aac/libAACdec/src/aacdec_drc.cpp
fdk-aac/libAACdec/src/aacdec_hcr.cpp
fdk-aac/libAACdec/src/aacdec_hcr_bit.cpp
fdk-aac/libAACdec/src/aacdec_hcrs.cpp
fdk-aac/libAACdec/src/aacdec_pns.cpp
fdk-aac/libAACdec/src/aacdec_tns.cpp
fdk-aac/libAACdec/src/aacdecoder.cpp
fdk-aac/libAACdec/src/aacdecoder_lib.cpp
fdk-aac/libAACdec/src/block.cpp
fdk-aac/libAACdec/src/channel.cpp
fdk-aac/libAACdec/src/channelinfo.cpp
fdk-aac/libAACdec/src/conceal.cpp
fdk-aac/libAACdec/src/ldfiltbank.cpp
fdk-aac/libAACdec/src/pulsedata.cpp
fdk-aac/libAACdec/src/rvlc.cpp
fdk-aac/libAACdec/src/rvlcbit.cpp
fdk-aac/libAACdec/src/rvlcconceal.cpp
fdk-aac/libAACdec/src/stereo.cpp
fdk-aac/libAACdec/src/usacdec_ace_d4t64.cpp
fdk-aac/libAACdec/src/usacdec_ace_ltp.cpp
fdk-aac/libAACdec/src/usacdec_acelp.cpp
fdk-aac/libAACdec/src/usacdec_fac.cpp
fdk-aac/libAACdec/src/usacdec_lpc.cpp
fdk-aac/libAACdec/src/usacdec_lpd.cpp
fdk-aac/libAACdec/src/usacdec_rom.cpp
)
set(FDK_SRC
fdk-aac/libFDK/src/FDK_bitbuffer.cpp
fdk-aac/libFDK/src/FDK_core.cpp
fdk-aac/libFDK/src/FDK_crc.cpp
fdk-aac/libFDK/src/FDK_decorrelate.cpp
fdk-aac/libFDK/src/FDK_hybrid.cpp
fdk-aac/libFDK/src/FDK_lpc.cpp
fdk-aac/libFDK/src/FDK_matrixCalloc.cpp
fdk-aac/libFDK/src/FDK_qmf_domain.cpp
fdk-aac/libFDK/src/FDK_tools_rom.cpp
fdk-aac/libFDK/src/FDK_trigFcts.cpp
fdk-aac/libFDK/src/autocorr2nd.cpp
fdk-aac/libFDK/src/dct.cpp
fdk-aac/libFDK/src/fft.cpp
fdk-aac/libFDK/src/fft_rad2.cpp
fdk-aac/libFDK/src/fixpoint_math.cpp
fdk-aac/libFDK/src/huff_nodes.cpp
fdk-aac/libFDK/src/mdct.cpp
fdk-aac/libFDK/src/nlc_dec.cpp
fdk-aac/libFDK/src/qmf.cpp
fdk-aac/libFDK/src/scale.cpp
)
set(SYS_SRC
fdk-aac/libSYS/src/genericStds.cpp
fdk-aac/libSYS/src/syslib_channelMapDescr.cpp
)
set(ARITHCODING_SRC
fdk-aac/libArithCoding/src/ac_arith_coder.cpp
)
set(MPEGTPDEC_SRC
fdk-aac/libMpegTPDec/src/tpdec_adif.cpp
fdk-aac/libMpegTPDec/src/tpdec_adts.cpp
fdk-aac/libMpegTPDec/src/tpdec_asc.cpp
fdk-aac/libMpegTPDec/src/tpdec_drm.cpp
fdk-aac/libMpegTPDec/src/tpdec_latm.cpp
fdk-aac/libMpegTPDec/src/tpdec_lib.cpp
)
set(SBRDEC_SRC
fdk-aac/libSBRdec/src/HFgen_preFlat.cpp
fdk-aac/libSBRdec/src/env_calc.cpp
fdk-aac/libSBRdec/src/env_dec.cpp
fdk-aac/libSBRdec/src/env_extr.cpp
fdk-aac/libSBRdec/src/hbe.cpp
fdk-aac/libSBRdec/src/huff_dec.cpp
fdk-aac/libSBRdec/src/lpp_tran.cpp
fdk-aac/libSBRdec/src/psbitdec.cpp
fdk-aac/libSBRdec/src/psdec.cpp
fdk-aac/libSBRdec/src/psdec_drm.cpp
fdk-aac/libSBRdec/src/psdecrom_drm.cpp
fdk-aac/libSBRdec/src/pvc_dec.cpp
fdk-aac/libSBRdec/src/sbr_deb.cpp
fdk-aac/libSBRdec/src/sbr_dec.cpp
fdk-aac/libSBRdec/src/sbr_ram.cpp
fdk-aac/libSBRdec/src/sbr_rom.cpp
fdk-aac/libSBRdec/src/sbrdec_drc.cpp
fdk-aac/libSBRdec/src/sbrdec_freq_sca.cpp
fdk-aac/libSBRdec/src/sbrdecoder.cpp
)
set(PCMUTILS_SRC
fdk-aac/libPCMutils/src/limiter.cpp
fdk-aac/libPCMutils/src/pcm_utils.cpp
fdk-aac/libPCMutils/src/pcmdmx_lib.cpp
)
set(DRCDEC_SRC
fdk-aac/libDRCdec/src/FDK_drcDecLib.cpp
fdk-aac/libDRCdec/src/drcDec_gainDecoder.cpp
fdk-aac/libDRCdec/src/drcDec_reader.cpp
fdk-aac/libDRCdec/src/drcDec_rom.cpp
fdk-aac/libDRCdec/src/drcDec_selectionProcess.cpp
fdk-aac/libDRCdec/src/drcDec_tools.cpp
fdk-aac/libDRCdec/src/drcGainDec_init.cpp
fdk-aac/libDRCdec/src/drcGainDec_preprocess.cpp
fdk-aac/libDRCdec/src/drcGainDec_process.cpp
)
set(SACDEC_SRC
fdk-aac/libSACdec/src/sac_bitdec.cpp
fdk-aac/libSACdec/src/sac_calcM1andM2.cpp
fdk-aac/libSACdec/src/sac_dec.cpp
fdk-aac/libSACdec/src/sac_dec_conceal.cpp
fdk-aac/libSACdec/src/sac_dec_lib.cpp
fdk-aac/libSACdec/src/sac_process.cpp
fdk-aac/libSACdec/src/sac_qmf.cpp
fdk-aac/libSACdec/src/sac_reshapeBBEnv.cpp
fdk-aac/libSACdec/src/sac_rom.cpp
fdk-aac/libSACdec/src/sac_smoothing.cpp
fdk-aac/libSACdec/src/sac_stp.cpp
fdk-aac/libSACdec/src/sac_tsd.cpp
)
add_library(fdk-aac
${AACDEC_SRC}
${FDK_SRC}
${SYS_SRC}
${ARITHCODING_SRC}
${MPEGTPDEC_SRC}
${SBRDEC_SRC}
${PCMUTILS_SRC}
${DRCDEC_SRC}
${SACDEC_SRC}
)
target_include_directories(fdk-aac
PUBLIC
fdk-aac/libAACdec/include
fdk-aac/libFDK/include
fdk-aac/libSYS/include
fdk-aac/libArithCoding/include
fdk-aac/libMpegTPDec/include
fdk-aac/libSBRdec/include
fdk-aac/libPCMutils/include
fdk-aac/libDRCdec/include
fdk-aac/libSACdec/include
)

1
externals/aacdec/fdk-aac vendored Submodule

View File

@@ -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;
AjmCodecType PS4_SYSV_ABI sceAjmInstanceCodecType(u32 instance_id) {
return static_cast<AjmCodecType>((instance_id >> 14) & 0x1F);
}
int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context_id, AjmCodecType codec_type,

View File

@@ -82,8 +82,6 @@ enum class AjmStatisticsFlags : u64 {
DECLARE_ENUM_FLAG_OPERATORS(AjmStatisticsFlags)
union AjmStatisticsJobFlags {
AjmStatisticsJobFlags(AjmJobFlags job_flags) : raw(job_flags.raw) {}
u64 raw;
struct {
u64 version : 3;
@@ -217,7 +215,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();
AjmCodecType PS4_SYSV_ABI sceAjmInstanceCodecType(u32 instance_id);
int PS4_SYSV_ABI sceAjmInstanceCreate(u32 context, AjmCodecType codec_type, AjmInstanceFlags flags,
u32* instance);
int PS4_SYSV_ABI sceAjmInstanceDestroy(u32 context, u32 instance);

View File

@@ -0,0 +1,194 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ajm.h"
#include "ajm_aac.h"
#include "ajm_result.h"
// using this internal header to manually configure the decoder in RAW mode
#include "externals/aacdec/fdk-aac/libAACdec/src/aacdecoder.h"
#include <aacdecoder_lib.h>
#include <magic_enum/magic_enum.hpp>
namespace Libraries::Ajm {
AjmAacDecoder::AjmAacDecoder(AjmFormatEncoding format, AjmAacCodecFlags flags, u32 channels)
: m_format(format), m_flags(flags), m_channels(channels), m_pcm_buffer(2048 * 8),
m_skip_frames(True(flags & AjmAacCodecFlags::EnableNondelayOutput) ? 0 : 2) {}
AjmAacDecoder::~AjmAacDecoder() {
aacDecoder_Close(m_decoder);
}
TRANSPORT_TYPE TransportTypeFromConfigType(ConfigType config_type) {
switch (config_type) {
case ConfigType::ADTS:
return TT_MP4_ADTS;
case ConfigType::RAW:
return TT_MP4_RAW;
default:
UNREACHABLE();
}
}
static UINT g_freq[] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000,
};
void AjmAacDecoder::Reset() {
if (m_decoder) {
aacDecoder_Close(m_decoder);
}
m_decoder = aacDecoder_Open(TransportTypeFromConfigType(m_init_params.config_type), 1);
if (m_init_params.config_type == ConfigType::RAW) {
// Manually configure the decoder
// Things may be incorrect due to limited documentation
CSAudioSpecificConfig asc{};
asc.m_aot = AOT_AAC_LC;
asc.m_samplingFrequency = g_freq[m_init_params.sampling_freq_type];
asc.m_samplingFrequencyIndex = m_init_params.sampling_freq_type;
asc.m_samplesPerFrame = 1024;
asc.m_epConfig = -1;
switch (m_channels) {
case 0:
asc.m_channelConfiguration = 2;
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
asc.m_channelConfiguration = m_channels;
break;
case 7:
asc.m_channelConfiguration = 11;
break;
case 8:
asc.m_channelConfiguration = 12; // 7, 12 or 14 ?
break;
default:
UNREACHABLE();
}
UCHAR changed = 1;
CAacDecoder_Init(m_decoder, &asc, AC_CM_ALLOC_MEM, &changed);
}
m_skip_frames = True(m_flags & AjmAacCodecFlags::EnableNondelayOutput) ? 0 : 2;
}
void AjmAacDecoder::Initialize(const void* buffer, u32 buffer_size) {
ASSERT(buffer_size == 8);
m_init_params = *reinterpret_cast<const InitializeParameters*>(buffer);
Reset();
}
void AjmAacDecoder::GetInfo(void* out_info) const {
auto* codec_info = reinterpret_cast<AjmSidebandDecM4aacCodecInfo*>(out_info);
*codec_info = {
.heaac = True(m_flags & AjmAacCodecFlags::EnableSbrDecode),
};
}
AjmSidebandFormat AjmAacDecoder::GetFormat() const {
const auto* const info = aacDecoder_GetStreamInfo(m_decoder);
return {
.num_channels = static_cast<u32>(info->numChannels),
.channel_mask = GetChannelMask(info->numChannels),
.sampl_freq = static_cast<u32>(info->sampleRate),
.sample_encoding = m_format, // AjmFormatEncoding
.bitrate = static_cast<u32>(info->bitRate),
};
}
u32 AjmAacDecoder::GetMinimumInputSize() const {
return 0;
}
u32 AjmAacDecoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const {
const auto* const info = aacDecoder_GetStreamInfo(m_decoder);
if (info->aacSamplesPerFrame <= 0) {
return 0;
}
const auto skip_samples = std::min<u32>(gapless.current.skip_samples, info->frameSize);
const auto samples =
gapless.init.total_samples != 0
? std::min<u32>(gapless.current.total_samples, info->frameSize - skip_samples)
: info->frameSize - skip_samples;
return samples * info->numChannels * GetPCMSize(m_format);
}
DecoderResult AjmAacDecoder::ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) {
DecoderResult result{};
// Discard the previous contents of the internal buffer and replace them with new ones
aacDecoder_SetParam(m_decoder, AAC_TPDEC_CLEAR_BUFFER, 1);
UCHAR* buffers[] = {input.data()};
const UINT sizes[] = {static_cast<UINT>(input.size())};
UINT valid = sizes[0];
aacDecoder_Fill(m_decoder, buffers, sizes, &valid);
auto ret = aacDecoder_DecodeFrame(m_decoder, reinterpret_cast<s16*>(m_pcm_buffer.data()),
m_pcm_buffer.size() / 2, 0);
switch (ret) {
case AAC_DEC_OK:
break;
case AAC_DEC_NOT_ENOUGH_BITS:
result.result = ORBIS_AJM_RESULT_PARTIAL_INPUT;
return result;
default:
LOG_ERROR(Lib_Ajm, "aacDecoder_DecodeFrame failed ret = {:#x}", static_cast<u32>(ret));
result.result = ORBIS_AJM_RESULT_CODEC_ERROR | ORBIS_AJM_RESULT_FATAL;
result.internal_result = ret;
return result;
}
const auto* const info = aacDecoder_GetStreamInfo(m_decoder);
auto bytes_used = info->numTotalBytes;
result.frames_decoded += 1;
input = input.subspan(bytes_used);
if (m_skip_frames > 0) {
--m_skip_frames;
return result;
}
u32 skip_samples = 0;
if (gapless.current.skip_samples > 0) {
skip_samples = std::min<u16>(info->frameSize, gapless.current.skip_samples);
gapless.current.skip_samples -= skip_samples;
}
const auto max_samples =
gapless.init.total_samples != 0 ? gapless.current.total_samples : info->aacSamplesPerFrame;
size_t pcm_written = 0;
switch (m_format) {
case AjmFormatEncoding::S16:
pcm_written = WriteOutputSamples<s16>(output, skip_samples * info->numChannels,
max_samples * info->numChannels);
break;
case AjmFormatEncoding::S32:
UNREACHABLE_MSG("NOT IMPLEMENTED");
break;
case AjmFormatEncoding::Float:
UNREACHABLE_MSG("NOT IMPLEMENTED");
break;
default:
UNREACHABLE();
}
result.samples_written = pcm_written / info->numChannels;
gapless.current.skipped_samples += info->frameSize - result.samples_written;
if (gapless.init.total_samples != 0) {
gapless.current.total_samples -= result.samples_written;
}
return result;
}
} // namespace Libraries::Ajm

View File

@@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/enum.h"
#include "common/types.h"
#include "core/libraries/ajm/ajm_instance.h"
#include <span>
#include <vector>
struct AAC_DECODER_INSTANCE;
namespace Libraries::Ajm {
enum ConfigType : u32 {
ADTS = 1,
RAW = 2,
};
enum AjmAacCodecFlags : u32 {
EnableSbrDecode = 1 << 0,
EnableNondelayOutput = 1 << 1,
SurroundChannelInterleaveOrderExtlExtrLsRs = 1 << 2,
SurroundChannelInterleaveOrderLsRsExtlExtr = 1 << 3,
};
DECLARE_ENUM_FLAG_OPERATORS(AjmAacCodecFlags)
struct AjmSidebandDecM4aacCodecInfo {
u32 heaac;
u32 reserved;
};
struct AjmAacDecoder final : AjmCodec {
explicit AjmAacDecoder(AjmFormatEncoding format, AjmAacCodecFlags flags, u32 channels);
~AjmAacDecoder() 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 GetMinimumInputSize() const override;
u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override;
DecoderResult ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
AjmInstanceGapless& gapless) override;
private:
struct InitializeParameters {
ConfigType config_type;
u32 sampling_freq_type;
};
template <class T>
size_t WriteOutputSamples(SparseOutputBuffer& output, u32 skipped_pcm, u32 max_pcm) {
std::span<T> pcm_data{reinterpret_cast<T*>(m_pcm_buffer.data()),
m_pcm_buffer.size() / sizeof(T)};
pcm_data = pcm_data.subspan(skipped_pcm);
const auto pcm_size = std::min(u32(pcm_data.size()), max_pcm);
return output.Write(pcm_data.subspan(0, pcm_size));
}
const AjmFormatEncoding m_format;
const AjmAacCodecFlags m_flags;
const u32 m_channels;
std::vector<u8> m_pcm_buffer;
u32 m_skip_frames = 0;
InitializeParameters m_init_params = {};
AAC_DECODER_INSTANCE* m_decoder = nullptr;
};
} // namespace Libraries::Ajm

View File

@@ -54,7 +54,7 @@ struct RIFFHeader {
};
static_assert(sizeof(RIFFHeader) == 12);
AjmAt9Decoder::AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags)
AjmAt9Decoder::AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags, u32)
: m_format(format), m_flags(flags), m_handle(Atrac9GetHandle()) {}
AjmAt9Decoder::~AjmAt9Decoder() {

View File

@@ -3,6 +3,7 @@
#pragma once
#include "common/enum.h"
#include "common/types.h"
#include "core/libraries/ajm/ajm_instance.h"
@@ -13,8 +14,6 @@
namespace Libraries::Ajm {
constexpr s32 ORBIS_AJM_DEC_AT9_MAX_CHANNELS = 8;
enum AjmAt9CodecFlags : u32 {
ParseRiffHeader = 1 << 0,
NonInterleavedOutput = 1 << 8,
@@ -29,7 +28,7 @@ struct AjmSidebandDecAt9CodecInfo {
};
struct AjmAt9Decoder final : AjmCodec {
explicit AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags);
explicit AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags, u32 channels);
~AjmAt9Decoder() override;
void Reset() override;

View File

@@ -165,7 +165,7 @@ AjmJob AjmStatisticsJobFromBatchBuffer(u32 instance_id, AjmBatchBuffer batch_buf
ASSERT(job_flags.has_value());
job.flags = job_flags.value();
AjmStatisticsJobFlags flags(job.flags);
AjmStatisticsJobFlags flags{.raw = job.flags.raw};
if (input_control_buffer.has_value()) {
AjmBatchBuffer input_batch(input_control_buffer.value());
if (True(flags.statistics_flags & AjmStatisticsFlags::Engine)) {

View File

@@ -18,7 +18,8 @@
namespace Libraries::Ajm {
static constexpr u32 ORBIS_AJM_WAIT_INFINITE = -1;
constexpr u32 ORBIS_AJM_WAIT_INFINITE = -1;
constexpr int INSTANCE_ID_MASK = 0x3FFF;
AjmContext::AjmContext() {
worker_thread = std::jthread([this](std::stop_token stop) { this->WorkerThread(stop); });
@@ -84,7 +85,7 @@ void AjmContext::ProcessBatch(u32 id, std::span<AjmJob> jobs) {
std::shared_ptr<AjmInstance> instance;
{
std::shared_lock lock(instances_mutex);
auto* p_instance = instances.Get(job.instance_id);
auto* p_instance = instances.Get(job.instance_id & INSTANCE_ID_MASK);
ASSERT_MSG(p_instance != nullptr, "Attempting to execute job on null instance");
instance = *p_instance;
}
@@ -176,15 +177,15 @@ 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 = opt_index.value() | (static_cast<u32>(codec_type) << 14);
LOG_INFO(Lib_Ajm, "instance = {}", *out_instance);
return ORBIS_OK;
}
s32 AjmContext::InstanceDestroy(u32 instance) {
s32 AjmContext::InstanceDestroy(u32 instance_id) {
std::unique_lock lock(instances_mutex);
if (!instances.Destroy(instance)) {
if (!instances.Destroy(instance_id & INSTANCE_ID_MASK)) {
return ORBIS_AJM_ERROR_INVALID_INSTANCE;
}
return ORBIS_OK;

View File

@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ajm_aac.h"
#include "ajm_at9.h"
#include "ajm_instance.h"
#include "ajm_mp3.h"
@@ -26,13 +27,18 @@ u8 GetPCMSize(AjmFormatEncoding format) {
AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_flags(flags) {
switch (codec_type) {
case AjmCodecType::At9Dec: {
m_codec = std::make_unique<AjmAt9Decoder>(AjmFormatEncoding(flags.format),
AjmAt9CodecFlags(flags.codec));
m_codec = std::make_unique<AjmAt9Decoder>(
AjmFormatEncoding(flags.format), AjmAt9CodecFlags(flags.codec), u32(flags.channels));
break;
}
case AjmCodecType::Mp3Dec: {
m_codec = std::make_unique<AjmMp3Decoder>(AjmFormatEncoding(flags.format),
AjmMp3CodecFlags(flags.codec));
m_codec = std::make_unique<AjmMp3Decoder>(
AjmFormatEncoding(flags.format), AjmMp3CodecFlags(flags.codec), u32(flags.channels));
break;
}
case AjmCodecType::M4aacDec: {
m_codec = std::make_unique<AjmAacDecoder>(
AjmFormatEncoding(flags.format), AjmAacCodecFlags(flags.codec), u32(flags.channels));
break;
}
default:

View File

@@ -105,7 +105,7 @@ AVFrame* AjmMp3Decoder::ConvertAudioFrame(AVFrame* frame) {
return new_frame;
}
AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags)
AjmMp3Decoder::AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags, u32)
: m_format(format), m_flags(flags), m_codec(avcodec_find_decoder(AV_CODEC_ID_MP3)),
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);
@@ -311,7 +311,8 @@ int AjmMp3Decoder::ParseMp3Header(const u8* p_begin, u32 stream_size, int parse_
BitReader reader(p_current);
if (header->protection_type == 0) {
reader.Skip(16); // crc = reader.Read<u16>(16);
// crc = reader.Read<u16>(16);
reader.Skip(16);
}
if (header->version == Mp3AudioVersion::V1) {

View File

@@ -3,6 +3,7 @@
#pragma once
#include "common/enum.h"
#include "common/types.h"
#include "core/libraries/ajm/ajm_instance.h"
@@ -63,7 +64,7 @@ struct AjmSidebandDecMp3CodecInfo {
class AjmMp3Decoder : public AjmCodec {
public:
explicit AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags);
explicit AjmMp3Decoder(AjmFormatEncoding format, AjmMp3CodecFlags flags, u32 channels);
~AjmMp3Decoder() override;
void Reset() override;