AnyPS5/core/libs/prx/libSceAudiodec/Export.cpp

251 lines
12 KiB
C++

#include <cstdint>
#include <cstddef>
#include <array>
#include <memory>
#include <mutex>
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"
#include "prx/libSceAudiodec/src/Codecs.hpp"
namespace {
constexpr std::int32_t ERROR_API_FAIL = static_cast<std::int32_t>(0x807F0000);
constexpr std::int32_t ERROR_INVALID_TYPE = static_cast<std::int32_t>(0x807F0001);
constexpr std::int32_t ERROR_ARG = static_cast<std::int32_t>(0x807F0002);
constexpr std::int32_t ERROR_INVALID_PARAM_SIZE = static_cast<std::int32_t>(0x807F0004);
constexpr std::int32_t ERROR_INVALID_BSI_INFO_SIZE = static_cast<std::int32_t>(0x807F0005);
constexpr std::int32_t ERROR_INVALID_AU_INFO_SIZE = static_cast<std::int32_t>(0x807F0006);
constexpr std::int32_t ERROR_INVALID_PCM_ITEM_SIZE = static_cast<std::int32_t>(0x807F0007);
constexpr std::int32_t ERROR_INVALID_CTRL_POINTER = static_cast<std::int32_t>(0x807F0008);
constexpr std::int32_t ERROR_INVALID_PARAM_POINTER = static_cast<std::int32_t>(0x807F0009);
constexpr std::int32_t ERROR_INVALID_BSI_INFO_POINTER = static_cast<std::int32_t>(0x807F000A);
constexpr std::int32_t ERROR_INVALID_AU_INFO_POINTER = static_cast<std::int32_t>(0x807F000B);
constexpr std::int32_t ERROR_INVALID_PCM_ITEM_POINTER = static_cast<std::int32_t>(0x807F000C);
constexpr std::int32_t ERROR_INVALID_AU_POINTER = static_cast<std::int32_t>(0x807F000D);
constexpr std::int32_t ERROR_INVALID_PCM_POINTER = static_cast<std::int32_t>(0x807F000E);
constexpr std::int32_t ERROR_INVALID_HANDLE = static_cast<std::int32_t>(0x807F000F);
constexpr std::int32_t ERROR_INVALID_WORD_LENGTH = static_cast<std::int32_t>(0x807F0010);
constexpr std::int32_t ERROR_INVALID_AU_SIZE = static_cast<std::int32_t>(0x807F0011);
constexpr std::int32_t ERROR_INVALID_PCM_SIZE = static_cast<std::int32_t>(0x807F0012);
constexpr std::int32_t ERROR_M4AAC_INVALID_SAMPLING_FREQ = static_cast<std::int32_t>(0x807F0300);
constexpr std::int32_t ERROR_M4AAC_INVALID_ENABLE_HEAAC = static_cast<std::int32_t>(0x807F0302);
constexpr std::int32_t ERROR_M4AAC_INVALID_CONFIG_NUMBER = static_cast<std::int32_t>(0x807F0303);
constexpr std::int32_t ERROR_M4AAC_INVALID_MAX_CHANNELS = static_cast<std::int32_t>(0x807F0304);
constexpr std::int32_t ERROR_AT9_INVALID_CONFIG_DATA = static_cast<std::int32_t>(0x807F1000);
constexpr std::uint32_t TYPE_AT9 = 1;
constexpr std::uint32_t TYPE_MP3 = 2;
constexpr std::uint32_t TYPE_M4AAC = 3;
constexpr std::uint32_t M4AAC_CONFIG_ADTS = 1;
constexpr std::uint32_t M4AAC_CONFIG_RAW = 2;
constexpr std::int32_t M4AAC_RESULT_DECODE_ERROR = -4;
constexpr std::int32_t M4AAC_RESULT_INSUFFICIENT_DATA = -5;
static_assert(sizeof(AudiodecAuInfo) == 24 && sizeof(AudiodecPcmItem) == 24 && sizeof(AudiodecCtrl) == 32);
static_assert(sizeof(AudiodecParamAt9) == 12 && sizeof(AudiodecAt9Info) == 36);
static_assert(sizeof(AudiodecParamMp3) == 8 && sizeof(AudiodecMp3Info) == 20);
static_assert(sizeof(AudiodecParamM4aac) == 24 && sizeof(AudiodecM4aacInfo) == 20);
struct Instance {
std::uint32_t codecType = 0;
std::unique_ptr<Audiodec::Decoder> decoder;
Audiodec::At9Format at9{};
std::uint32_t channels = 0;
std::uint32_t sampleRate = 0;
};
std::mutex g_mutex;
std::array<std::uint32_t, 4> g_initialized{};
std::array<Instance, 64> g_instances{};
bool validType(std::uint32_t codecType) {
return codecType == TYPE_AT9 || codecType == TYPE_MP3 || codecType == TYPE_M4AAC;
}
std::int32_t wordSizeOf(const void* param) {
return static_cast<const AudiodecParamMp3*>(param)->i_bw_pcm;
}
std::int32_t validateWordSize(std::int32_t wordSize) {
if (wordSize == Audiodec::WORD_SIZE_16BIT || wordSize == Audiodec::WORD_SIZE_FLOAT) return 0;
if (wordSize == 0) NotImplemented_nid_no_patch("libSceAudiodec 24-bit PCM output");
return ERROR_INVALID_WORD_LENGTH;
}
std::int32_t validateCtrl(const AudiodecCtrl* ctrl, std::uint32_t codecType) {
if (!ctrl) return ERROR_INVALID_CTRL_POINTER;
if (!ctrl->pParam) return ERROR_INVALID_PARAM_POINTER;
if (!ctrl->pBsiInfo) return ERROR_INVALID_BSI_INFO_POINTER;
const std::uint32_t paramSize = *static_cast<const std::uint32_t*>(ctrl->pParam);
const std::uint32_t infoSize = *static_cast<const std::uint32_t*>(ctrl->pBsiInfo);
switch (codecType) {
case TYPE_AT9:
if (paramSize != sizeof(AudiodecParamAt9)) return ERROR_INVALID_PARAM_SIZE;
if (infoSize != sizeof(AudiodecAt9Info)) return ERROR_INVALID_BSI_INFO_SIZE;
break;
case TYPE_MP3:
if (paramSize != sizeof(AudiodecParamMp3)) return ERROR_INVALID_PARAM_SIZE;
if (infoSize != sizeof(AudiodecMp3Info)) return ERROR_INVALID_BSI_INFO_SIZE;
break;
default:
if (paramSize < sizeof(AudiodecParamM4aac)) return ERROR_INVALID_PARAM_SIZE;
if (infoSize != sizeof(AudiodecM4aacInfo)) return ERROR_INVALID_BSI_INFO_SIZE;
break;
}
return validateWordSize(wordSizeOf(ctrl->pParam));
}
std::int32_t validateBuffers(const AudiodecCtrl* ctrl) {
if (!ctrl->pAuInfo) return ERROR_INVALID_AU_INFO_POINTER;
if (!ctrl->pPcmItem) return ERROR_INVALID_PCM_ITEM_POINTER;
if (ctrl->pAuInfo->ui_size != sizeof(AudiodecAuInfo)) return ERROR_INVALID_AU_INFO_SIZE;
if (ctrl->pPcmItem->ui_size != sizeof(AudiodecPcmItem)) return ERROR_INVALID_PCM_ITEM_SIZE;
if (!ctrl->pAuInfo->p_au_addr) return ERROR_INVALID_AU_POINTER;
if (!ctrl->pPcmItem->p_pcm_addr) return ERROR_INVALID_PCM_POINTER;
if (ctrl->pAuInfo->ui_au_size == 0) return ERROR_INVALID_AU_SIZE;
if (ctrl->pPcmItem->ui_pcm_size == 0) return ERROR_INVALID_PCM_SIZE;
return 0;
}
void fillAt9Info(AudiodecAt9Info* info, const Audiodec::At9Format& format) {
const std::uint32_t superframeSamples = format.frameSamples * format.framesInSuperframe;
info->ui_channel = format.channels;
info->ui_bitrate = static_cast<std::uint32_t>(static_cast<std::uint64_t>(format.superframeSize) * 8 * format.sampleRate / superframeSamples);
info->ui_sampling_rate = format.sampleRate;
info->ui_super_frame_size = format.superframeSize;
info->ui_frames_in_super_frame = format.framesInSuperframe;
info->ui_next_frame_size = format.superframeSize;
info->ui_frame_samples = format.frameSamples;
info->i_result = 0;
}
void fillMp3Info(AudiodecMp3Info* info, const Audiodec::Mp3Header& header) {
info->ui_header = header.word;
info->uc_crc = header.crc;
info->uc_mode = header.mode;
info->uc_mode_extension = header.modeExtension;
info->uc_copyright = header.copyright;
info->uc_original = header.original;
info->uc_emphasis = header.emphasis;
info->uc_reserved[0] = 0;
info->uc_reserved[1] = 0;
info->i_result = 0;
}
std::int32_t createAac(const AudiodecParamM4aac* param, AudiodecM4aacInfo* info, Instance& instance) {
if (param->ui_config_number != M4AAC_CONFIG_ADTS && param->ui_config_number != M4AAC_CONFIG_RAW) return ERROR_M4AAC_INVALID_CONFIG_NUMBER;
const std::uint32_t sampleRate = Audiodec::AacSampleRate(param->ui_sampling_freq_index);
if (param->ui_config_number == M4AAC_CONFIG_RAW && sampleRate == 0) return ERROR_M4AAC_INVALID_SAMPLING_FREQ;
if (param->ui_max_channels > 8) return ERROR_M4AAC_INVALID_MAX_CHANNELS;
if (param->ui_enable_heaac > 1) return ERROR_M4AAC_INVALID_ENABLE_HEAAC;
const std::uint32_t channels = param->ui_max_channels == 0 ? 2 : param->ui_max_channels;
instance.decoder = Audiodec::CreateAac(param->i_bw_pcm, param->ui_config_number == M4AAC_CONFIG_ADTS, param->ui_sampling_freq_index, channels);
instance.channels = channels;
instance.sampleRate = sampleRate;
info->ui_sampling_freq = sampleRate;
info->ui_number_of_channels = channels;
info->ui_heaac = 0;
info->i_result = 0;
return 0;
}
Instance* find(std::int32_t handle) {
if (handle <= 0 || static_cast<std::size_t>(handle) > g_instances.size()) return nullptr;
Instance& instance = g_instances[static_cast<std::size_t>(handle - 1)];
return instance.decoder ? &instance : nullptr;
}
}
extern "C" {
int32_t APS5_VABI sceAudiodecInitLibrary(uint32_t codec_type) {
if (!validType(codec_type)) return ERROR_INVALID_TYPE;
std::lock_guard lock(g_mutex);
++g_initialized[codec_type];
return 0;
}
int32_t APS5_VABI sceAudiodecTermLibrary(uint32_t codec_type) {
if (!validType(codec_type)) return ERROR_INVALID_TYPE;
std::lock_guard lock(g_mutex);
if (g_initialized[codec_type] > 0) --g_initialized[codec_type];
return 0;
}
int32_t APS5_VABI sceAudiodecCreateDecoder(AudiodecCtrl* ctrl, uint32_t codec_type) {
if (!validType(codec_type)) return ERROR_INVALID_TYPE;
if (const std::int32_t result = validateCtrl(ctrl, codec_type); result != 0) return result;
std::lock_guard lock(g_mutex);
if (g_initialized[codec_type] == 0) return ERROR_ARG;
for (std::size_t i = 0; i < g_instances.size(); ++i) {
Instance& instance = g_instances[i];
if (instance.decoder) continue;
instance = {};
instance.codecType = codec_type;
if (codec_type == TYPE_AT9) {
const auto* param = static_cast<const AudiodecParamAt9*>(ctrl->pParam);
instance.decoder = Audiodec::CreateAt9(param->i_bw_pcm, param->ui_config_data, instance.at9);
if (!instance.decoder) return ERROR_AT9_INVALID_CONFIG_DATA;
fillAt9Info(static_cast<AudiodecAt9Info*>(ctrl->pBsiInfo), instance.at9);
} else if (codec_type == TYPE_MP3) {
instance.decoder = Audiodec::CreateMp3(static_cast<const AudiodecParamMp3*>(ctrl->pParam)->i_bw_pcm);
} else if (const std::int32_t result = createAac(static_cast<const AudiodecParamM4aac*>(ctrl->pParam), static_cast<AudiodecM4aacInfo*>(ctrl->pBsiInfo), instance); result != 0) {
instance = {};
return result;
}
return static_cast<int32_t>(i + 1);
}
return ERROR_API_FAIL;
}
int32_t APS5_VABI sceAudiodecDeleteDecoder(int32_t handle) {
std::lock_guard lock(g_mutex);
Instance* instance = find(handle);
if (!instance) return ERROR_INVALID_HANDLE;
*instance = {};
return 0;
}
int32_t APS5_VABI sceAudiodecClearContext(int32_t handle) {
std::lock_guard lock(g_mutex);
Instance* instance = find(handle);
if (!instance) return ERROR_INVALID_HANDLE;
instance->decoder->Reset();
return 0;
}
int32_t APS5_VABI sceAudiodecDecode(int32_t handle, AudiodecCtrl* ctrl) {
std::lock_guard lock(g_mutex);
Instance* instance = find(handle);
if (!instance) return ERROR_INVALID_HANDLE;
if (const std::int32_t result = validateCtrl(ctrl, instance->codecType); result != 0) return result;
if (const std::int32_t result = validateBuffers(ctrl); result != 0) return result;
const Audiodec::DecodeResult decoded = instance->decoder->Decode(static_cast<const std::uint8_t*>(ctrl->pAuInfo->p_au_addr), ctrl->pAuInfo->ui_au_size,
static_cast<std::uint8_t*>(ctrl->pPcmItem->p_pcm_addr), ctrl->pPcmItem->ui_pcm_size);
if (instance->codecType == TYPE_M4AAC) {
auto* info = static_cast<AudiodecM4aacInfo*>(ctrl->pBsiInfo);
info->i_result = decoded.status == Audiodec::DecodeStatus::InvalidData ? M4AAC_RESULT_DECODE_ERROR
: decoded.status == Audiodec::DecodeStatus::PartialInput ? M4AAC_RESULT_INSUFFICIENT_DATA : 0;
if (decoded.channels != 0) {
info->ui_sampling_freq = decoded.sampleRate;
info->ui_number_of_channels = decoded.channels;
info->ui_heaac = decoded.highEfficiency;
}
}
if (decoded.status == Audiodec::DecodeStatus::NotEnoughRoom) return ERROR_INVALID_PCM_SIZE;
if (decoded.status != Audiodec::DecodeStatus::Ok) {
ctrl->pAuInfo->ui_au_size = 0;
ctrl->pPcmItem->ui_pcm_size = 0;
return ERROR_API_FAIL;
}
if (instance->codecType == TYPE_MP3) fillMp3Info(static_cast<AudiodecMp3Info*>(ctrl->pBsiInfo), decoded.mp3);
if (instance->codecType == TYPE_AT9) fillAt9Info(static_cast<AudiodecAt9Info*>(ctrl->pBsiInfo), instance->at9);
ctrl->pAuInfo->ui_au_size = static_cast<std::uint32_t>(decoded.consumed);
ctrl->pPcmItem->ui_pcm_size = static_cast<std::uint32_t>(decoded.produced);
return 0;
}
}