fix(audiodec): validate aac sizes and extended mode ranges

This commit is contained in:
boykopovar committed 2026-10-21 21:53:27 +03:00
1 parent fdcf961f5c
commit 8de11f73ee
3 files changed
+50 -4

No files matched your search

+14 -4
View File
@@ -1,6 +1,8 @@
#include <cstdint>
#include <cstddef>
#include <array>
#include <cstring>
#include <stdexcept>
#include <memory>
#include <mutex>
#include "SceTypes.hpp"
@@ -88,7 +90,7 @@ std::int32_t validateCtrl(const AudiodecCtrl* ctrl, std::uint32_t codecType) {
if (infoSize != sizeof(AudiodecMp3Info)) return ERROR_INVALID_BSI_INFO_SIZE;
break;
default:
if (paramSize < sizeof(AudiodecParamM4aac)) return ERROR_INVALID_PARAM_SIZE;
if (paramSize != sizeof(AudiodecParamM4aac) && paramSize != 28 && paramSize != 32) return ERROR_INVALID_PARAM_SIZE;
if (infoSize != sizeof(AudiodecM4aacInfo)) return ERROR_INVALID_BSI_INFO_SIZE;
break;
}
@@ -133,12 +135,20 @@ 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;
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_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;
if (param->ui_max_channels != 1 && param->ui_max_channels != 2 && param->ui_max_channels != 6 && param->ui_max_channels != 8) return ERROR_M4AAC_INVALID_MAX_CHANNELS;
if (param->ui_enable_heaac > 1 || (param->ui_enable_heaac == 1 && param->ui_max_channels > 2)) return ERROR_M4AAC_INVALID_ENABLE_HEAAC;
const std::uint32_t channels = 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, param->ui_enable_heaac == 1);
instance.channels = channels;
instance.sampleRate = sampleRate;
+34
View File
@@ -5,6 +5,7 @@
#include <cstdlib>
#include <cstring>
#include <numbers>
#include <stdexcept>
#include <vector>
extern "C" {
@@ -410,6 +411,39 @@ int main() {
aac.i_bw_pcm = 2;
const std::int32_t floatAac = sceAudiodecCreateDecoder(&aacCtrl, 3);
Require(floatAac > 0 && sceAudiodecDeleteDecoder(floatAac) == 0);
for (const std::uint32_t channels : {0u, 3u, 4u, 5u, 7u, 9u}) {
aac.ui_max_channels = channels;
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == static_cast<std::int32_t>(0x807F0304));
}
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};
aacCtrl.pParam = &extended;
for (const std::uint32_t size : {25u, 27u, 29u, 31u, 33u}) {
extended.base.ui_size = size;
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == errorInvalidParamSize);
}
for (const std::uint32_t size : {28u, 32u}) {
extended.base.ui_size = size;
extended.extensionMode = 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);
}
extended.outputMode = 3;
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == static_cast<std::int32_t>(0x807F0306));
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 2);
Require(handle > 0);
+2
View File
@@ -2,6 +2,8 @@
### 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.
- [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)