mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-01-31 00:55:19 +01:00
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:
committed by
GitHub
parent
aa227cae57
commit
9a3e4ea56b
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
4
externals/CMakeLists.txt
vendored
4
externals/CMakeLists.txt
vendored
@@ -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
154
externals/aacdec/CMakeLists.txt
vendored
Normal 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
1
externals/aacdec/fdk-aac
vendored
Submodule
Submodule externals/aacdec/fdk-aac added at ee76460efb
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
194
src/core/libraries/ajm/ajm_aac.cpp
Normal file
194
src/core/libraries/ajm/ajm_aac.cpp
Normal 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
|
||||
73
src/core/libraries/ajm/ajm_aac.h
Normal file
73
src/core/libraries/ajm/ajm_aac.h
Normal 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
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user