mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
feat(libSceAudiodec): decode M4AAC with non-delay output enabled
The 28- and 32-byte M4AAC parameter blocks carry two fields at offsets 24 and 28 whose range errors fpPS4 names SCE_AUDIODEC_ERROR_M4AAC_INVALID_ENABLE_NONDELAY_OUTPUT (0x807F0305) and SCE_AUDIODEC_ERROR_M4AAC_INVALID_SURROUND_CHANNEL_INTERLEAVE_ORDER (0x807F0306). shadPS4's AJM AAC decoder outputs every decoded frame from the first one on when non-delay output is enabled, which is what the decoder here does, so a decoder created with non-delay output 1 is accepted and decodes as before. Surround channel interleave orders 1 and 2 still throw, now naming the order: no source says which order each value selects. Name both errors and test that every access unit yields its frame from the first one with non-delay output enabled.
This commit is contained in:
1 parent
f8f5b24b77
commit
b3b6178347
3 files changed
+32
-27
No files matched your search
@@ -6,6 +6,7 @@
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libSceAudiodec/src/Codecs.hpp"
|
||||
@@ -34,6 +35,8 @@ constexpr std::int32_t ERROR_M4AAC_INVALID_SAMPLING_FREQ = static_cast<std::int3
|
||||
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_M4AAC_INVALID_ENABLE_NONDELAY_OUTPUT = static_cast<std::int32_t>(0x807F0305);
|
||||
constexpr std::int32_t ERROR_M4AAC_INVALID_SURROUND_CHANNEL_INTERLEAVE_ORDER = static_cast<std::int32_t>(0x807F0306);
|
||||
constexpr std::int32_t ERROR_AT9_INVALID_CONFIG_DATA = static_cast<std::int32_t>(0x807F1000);
|
||||
|
||||
constexpr std::uint32_t TYPE_AT9 = 1;
|
||||
@@ -136,14 +139,14 @@ void fillMp3Info(AudiodecMp3Info* info, const Audiodec::Mp3Header& header) {
|
||||
}
|
||||
|
||||
std::int32_t createAac(const AudiodecParamM4aac* param, AudiodecM4aacInfo* info, Instance& instance) {
|
||||
std::uint32_t extensionMode = 0;
|
||||
std::uint32_t outputMode = 0;
|
||||
std::uint32_t enableNondelayOutput = 0;
|
||||
std::uint32_t surroundChannelInterleaveOrder = 0;
|
||||
const auto* bytes = reinterpret_cast<const std::byte*>(param);
|
||||
if (param->ui_size >= 28) std::memcpy(&extensionMode, bytes + 24, sizeof(extensionMode));
|
||||
if (extensionMode > 1) return static_cast<std::int32_t>(0x807F0305);
|
||||
if (param->ui_size == 32) std::memcpy(&outputMode, bytes + 28, sizeof(outputMode));
|
||||
if (outputMode > 2) return static_cast<std::int32_t>(0x807F0306);
|
||||
if (extensionMode != 0 || outputMode != 0) throw std::runtime_error("M4AAC extended decoding modes are not implemented");
|
||||
if (param->ui_size >= 28) std::memcpy(&enableNondelayOutput, bytes + 24, sizeof(enableNondelayOutput));
|
||||
if (enableNondelayOutput > 1) return ERROR_M4AAC_INVALID_ENABLE_NONDELAY_OUTPUT;
|
||||
if (param->ui_size == 32) std::memcpy(&surroundChannelInterleaveOrder, bytes + 28, sizeof(surroundChannelInterleaveOrder));
|
||||
if (surroundChannelInterleaveOrder > 2) return ERROR_M4AAC_INVALID_SURROUND_CHANNEL_INTERLEAVE_ORDER;
|
||||
if (surroundChannelInterleaveOrder != 0) throw std::runtime_error("M4AAC surround channel interleave order " + std::to_string(surroundChannelInterleaveOrder) + " is not implemented");
|
||||
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;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <numbers>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
static void Require(bool value) { if (!value) std::abort(); }
|
||||
@@ -231,8 +230,14 @@ std::size_t AdtsLength(const std::uint8_t* frame) {
|
||||
return static_cast<std::size_t>((frame[3] & 3) << 11 | frame[4] << 3 | frame[5] >> 5);
|
||||
}
|
||||
|
||||
void TestAac(bool adts, std::uint32_t maxChannels = 2) {
|
||||
AudiodecParamM4aac param{sizeof(param), 1, adts ? 1u : 2u, 3, maxChannels, 0};
|
||||
struct M4aacExtendedParam {
|
||||
AudiodecParamM4aac base;
|
||||
std::uint32_t enableNondelayOutput;
|
||||
std::uint32_t surroundChannelInterleaveOrder;
|
||||
};
|
||||
|
||||
void TestAac(bool adts, std::uint32_t maxChannels = 2, std::uint32_t paramSize = sizeof(AudiodecParamM4aac), std::uint32_t enableNondelayOutput = 0) {
|
||||
M4aacExtendedParam param{{paramSize, 1, adts ? 1u : 2u, 3, maxChannels, 0}, enableNondelayOutput, 0};
|
||||
AudiodecM4aacInfo info{sizeof(info), 0, 0, 0, 0};
|
||||
AudiodecCtrl ctrl{¶m, &info, nullptr, nullptr};
|
||||
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 3);
|
||||
@@ -419,11 +424,7 @@ int main() {
|
||||
aac.ui_max_channels = 6;
|
||||
aac.ui_enable_heaac = 1;
|
||||
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == static_cast<std::int32_t>(0x807F0302));
|
||||
struct ExtendedParam {
|
||||
AudiodecParamM4aac base;
|
||||
std::uint32_t extensionMode;
|
||||
std::uint32_t outputMode;
|
||||
} extended{{32, 1, 1, 3, 2, 0}, 0, 0};
|
||||
M4aacExtendedParam extended{{32, 1, 1, 3, 2, 0}, 0, 0};
|
||||
aacCtrl.pParam = &extended;
|
||||
for (const std::uint32_t size : {25u, 27u, 29u, 31u, 33u}) {
|
||||
extended.base.ui_size = size;
|
||||
@@ -431,19 +432,17 @@ int main() {
|
||||
}
|
||||
for (const std::uint32_t size : {28u, 32u}) {
|
||||
extended.base.ui_size = size;
|
||||
extended.extensionMode = 2;
|
||||
extended.enableNondelayOutput = 2;
|
||||
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == static_cast<std::int32_t>(0x807F0305));
|
||||
extended.extensionMode = 1;
|
||||
bool threw = false;
|
||||
try { sceAudiodecCreateDecoder(&aacCtrl, 3); }
|
||||
catch (const std::runtime_error&) { threw = true; }
|
||||
Require(threw);
|
||||
extended.extensionMode = 0;
|
||||
const auto extendedHandle = sceAudiodecCreateDecoder(&aacCtrl, 3);
|
||||
Require(extendedHandle > 0);
|
||||
Require(sceAudiodecDeleteDecoder(extendedHandle) == 0);
|
||||
for (const std::uint32_t enableNondelayOutput : {0u, 1u}) {
|
||||
extended.enableNondelayOutput = enableNondelayOutput;
|
||||
const auto extendedHandle = sceAudiodecCreateDecoder(&aacCtrl, 3);
|
||||
Require(extendedHandle > 0);
|
||||
Require(sceAudiodecDeleteDecoder(extendedHandle) == 0);
|
||||
}
|
||||
extended.enableNondelayOutput = 0;
|
||||
}
|
||||
extended.outputMode = 3;
|
||||
extended.surroundChannelInterleaveOrder = 3;
|
||||
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == static_cast<std::int32_t>(0x807F0306));
|
||||
|
||||
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 2);
|
||||
@@ -461,6 +460,9 @@ int main() {
|
||||
TestAac(false);
|
||||
TestAac(false, 6);
|
||||
TestAac(false, 8);
|
||||
TestAac(true, 2, 28, 1);
|
||||
TestAac(false, 2, 32, 1);
|
||||
TestAac(false, 8, 28, 1);
|
||||
TestAacRaw51(6);
|
||||
TestAacRaw51(8);
|
||||
for (const bool adts : {true, false}) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
### Unknown function info
|
||||
|
||||
- [M4AAC extended parameters](../../../core/libs/prx/libSceAudiodec/Export.cpp): 28-byte and 32-byte parameter variants add fields at offsets 24 and 28. Their accepted ranges are 0..1 and 0..2; nonzero modes throw until the corresponding decoder configuration is implemented. Zero extensions use the base decoding configuration.
|
||||
- [M4AAC extended parameters](../../../core/libs/prx/libSceAudiodec/Export.cpp): 28-byte and 32-byte parameter variants add fields at offsets 24 and 28, named by their range errors (`0x807F0305` `SCE_AUDIODEC_ERROR_M4AAC_INVALID_ENABLE_NONDELAY_OUTPUT`, `0x807F0306` `SCE_AUDIODEC_ERROR_M4AAC_INVALID_SURROUND_CHANNEL_INTERLEAVE_ORDER`, in fpPS4's `ps4_libsceaudiodec.pas`). Non-delay output 1 decodes every access unit to its own PCM from the first one on, as shadPS4's AJM AAC decoder does with `EnableNondelayOutput`; without that flag shadPS4 holds back the first 2 frames. Non-delay output 0 still decodes the same way, with no frame held back: no measurement shows whether the console delays it. Surround channel interleave orders 1 and 2 throw: shadPS4 names two AJM orders (`ExtlExtrLsRs`, `LsRsExtlExtr`) but uses neither, and no source says which value selects which order or which order 0 is.
|
||||
|
||||
- [sceAudiodecDecode](../../../core/libs/prx/libSceAudiodec/src/Codecs.cpp) (libSceAudiodec) - a raw M4AAC stream carries no channel configuration, so the decoder tries the mono/stereo configuration and then configurations 3 to 7 within `ui_max_channels` until one decodes the first access unit, and keeps that one. No reference documents how the library picks the layout (shadPS4 maps the channel count straight to the configuration; SharpProspero only describes the maximum). With the stereo configuration a mono raw stream decodes as 2 channels, so 2 is reported, not 1
|
||||
- [sceAudiodecDecode](../../../core/libs/prx/libSceAudiodec/src/Codecs.cpp) (libSceAudiodec) - the HE-AAC handling follows one console measurement of an HE-AAC v2 ADTS stream: SBR output at 48 kHz in one channel with `ui_enable_heaac` 1, the 24 kHz mono core with 0. Not measured: whether the console, like FFmpeg, decodes a stream without SBR data in its first access unit as AAC-LC with `ui_enable_heaac` 1, and what it reports in `ui_sampling_freq` and `ui_heaac` with `ui_enable_heaac` 0 (here the rate of the returned PCM and 0)
|
||||
|
||||
Reference in new issue
Block a user