Files
AnyPS5/core/libs/tests/GuestAudiodec.cpp
T
hypermoistandClaude Opus 5.5 1bbec387aa fix(libSceAudiodec): report a decode error when FFmpeg cannot open an M4AAC layout
An ADTS header names its object type, sampling index and channel
configuration, and the decoder reopens FFmpeg with an AudioSpecificConfig
built from them. A layout FFmpeg refuses, such as the reserved sampling
index 13, threw out of sceAudiodecDecode into guest code. PPSA08427 ended
on such a throw after a few minutes on the title screen, on a build from
before the current layout handling.

- A reopen that FFmpeg refuses leaves the decoder without a context and
  the access unit is a decode error (M4AAC_RESULT_DECODE_ERROR,
  ERROR_API_FAIL); the raw layout search skips a refused layout.
- A decoder without a context decodes nothing until a header names a
  layout that opens; sceAudiodecClearContext leaves it as it is.
- The open failure names the codec, the AudioSpecificConfig and FFmpeg's
  error, and is logged on stderr.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 21:57:05 +13:00

496 lines
35 KiB
C++

#include "prx/libSceAudiodec/include/Api.hpp"
#include "SceTypes.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <numbers>
#include <stdexcept>
#include <vector>
static void Require(bool value) { if (!value) std::abort(); }
namespace {
const std::uint8_t AAC_ADTS[] = {
0xFF, 0xF1, 0x4C, 0x80, 0x0F, 0x9F, 0xFC, 0xDC, 0x00, 0x4C, 0x61, 0x76, 0x63, 0x36, 0x33, 0x2E, 0x31, 0x2E, 0x31, 0x30, 0x32, 0x00, 0x42, 0x4D,
0x9F, 0xFF, 0xFF, 0xE1, 0x40, 0xC9, 0xA1, 0xA2, 0xF4, 0x44, 0x23, 0x8E, 0xEA, 0x91, 0x95, 0xA9, 0x2E, 0xE5, 0xDC, 0x92, 0x3B, 0x65, 0xC0, 0xCE,
0xCF, 0x8E, 0x0C, 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0x59, 0x49, 0x61, 0xBC, 0xA3, 0x44, 0xEA, 0x53, 0xA7, 0x08, 0x22, 0x06, 0x36, 0x6C, 0xD9, 0xB0,
0x64, 0x48, 0xA5, 0x06, 0x36, 0x6C, 0x18, 0x19, 0x10, 0x30, 0x31, 0xB3, 0x66, 0xCD, 0x83, 0x22, 0x45, 0x29, 0xB3, 0x72, 0xCB, 0x14, 0x51, 0x45,
0x14, 0x51, 0x45, 0x14, 0x51, 0x45, 0x40, 0x37, 0xD1, 0x78, 0x8E, 0x3B, 0xAA, 0x46, 0x56, 0xA4, 0xBB, 0x97, 0x72, 0x48, 0xED, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0E, 0xFF, 0xF1, 0x4C, 0x80, 0x18, 0xFF, 0xFC, 0x21, 0x48, 0x6C, 0xFE, 0x7E, 0x7E, 0x7E, 0x47, 0x51, 0x4B, 0xAA, 0xC9, 0x71,
0x64, 0xB8, 0xB2, 0x5C, 0x3F, 0xFE, 0xD7, 0xFD, 0xFE, 0xB8, 0xD3, 0xBF, 0x5D, 0x7F, 0xFD, 0xFF, 0xFA, 0xFD, 0xFA, 0xE3, 0x8D, 0x7C, 0x7F, 0xFE,
0x4F, 0xFA, 0xFD, 0xFA, 0xE3, 0x8D, 0x7E, 0xFF, 0xFF, 0x5F, 0xFD, 0xBE, 0xFD, 0x71, 0xD7, 0x01, 0xB7, 0x49, 0xCD, 0xA0, 0x90, 0x90, 0x96, 0xAF,
0x1B, 0x1C, 0xBC, 0xFB, 0x50, 0x49, 0xFB, 0x71, 0x11, 0x44, 0x26, 0x28, 0x81, 0xA2, 0x53, 0x71, 0x2B, 0xE9, 0x11, 0x4E, 0x3E, 0x9C, 0xF1, 0x14,
0xE3, 0xE9, 0xF4, 0x88, 0xA7, 0x1F, 0x4F, 0xA5, 0x8B, 0x0C, 0x9E, 0x62, 0x69, 0x10, 0xD3, 0x20, 0xBE, 0x58, 0x4A, 0x6D, 0x72, 0x38, 0xAE, 0x2C,
0x4C, 0x51, 0x03, 0x44, 0xA6, 0xE2, 0x57, 0xD2, 0x22, 0x9C, 0x7D, 0x39, 0xE2, 0x29, 0xC7, 0xD3, 0xE9, 0x11, 0x4E, 0x3E, 0x9F, 0x42, 0x38, 0x42,
0x93, 0xE5, 0x39, 0x62, 0x28, 0xA2, 0x88, 0xA2, 0x8A, 0x28, 0xA3, 0x87, 0x6A, 0x1D, 0xE8, 0x77, 0xA1, 0xDE, 0x9F, 0xFF, 0x6B, 0xFE, 0xFF, 0x5C,
0x69, 0xDF, 0xAE, 0xBF, 0xFE, 0xFF, 0xFD, 0x7E, 0xFD, 0x70, 0x7F, 0x8F, 0xFF, 0xC9, 0xFF, 0x5F, 0xBF, 0x5C, 0x1F, 0xF3, 0xFF, 0xF5, 0xFF, 0xDB,
0xEF, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xF1, 0x4C, 0x80, 0x0B, 0xFF, 0xFC, 0x21, 0x77, 0x4F, 0xFF, 0xFF, 0xF0,
0x24, 0x0A, 0xFA, 0x67, 0x34, 0xD7, 0x8E, 0xF7, 0xBC, 0xFF, 0xB7, 0xFE, 0xFA, 0xFA, 0x74, 0xD5, 0xAE, 0xE3, 0xBE, 0x4B, 0x40, 0xEF, 0xBF, 0xBF,
0xBC, 0x2F, 0xFC, 0x7C, 0x7C, 0x66, 0x40, 0xF8, 0xF8, 0xF8, 0x03, 0xDF, 0xDE, 0x11, 0xF1, 0xF0, 0xD8, 0xCF, 0xEF, 0xA0, 0x64, 0xF8, 0x6C, 0x67,
0xF7, 0x84, 0x64, 0xF8, 0x6C, 0x67, 0xF7, 0x29, 0x01, 0xBE, 0x99, 0xCD, 0x35, 0xE3, 0xBD, 0xEF, 0x3F, 0xED, 0xFF, 0xBE, 0xBE, 0x9D, 0x35, 0x6B,
0xB8, 0xEF, 0x92, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xF1, 0x4C, 0x80, 0x0C, 0xFF, 0xFC, 0x21, 0x17, 0x4F, 0xFF, 0xFF, 0xF8, 0x26,
0x0A, 0x88, 0x5D, 0x20, 0xA5, 0x56, 0x67, 0x3F, 0xF6, 0xFF, 0xDF, 0xAE, 0x2E, 0xE5, 0xC9, 0x72, 0x48, 0xE9, 0x90, 0x31, 0xAF, 0x1A, 0xF1, 0xAF,
0xBA, 0xBE, 0xE5, 0xE0, 0x23, 0x2A, 0xCA, 0xBC, 0x6B, 0xC6, 0xBC, 0x6B, 0xC6, 0xBC, 0x6B, 0xC6, 0xBC, 0x6B, 0xC6, 0xB4, 0x69, 0x28, 0xA4, 0x46,
0x92, 0x8A, 0x44, 0x69, 0x28, 0xA4, 0x46, 0x91, 0x1D, 0x24, 0x69, 0x11, 0xA4, 0x47, 0x30, 0x38, 0xF0, 0xE9, 0x05, 0x2A, 0xB3, 0x39, 0xFF, 0xB7,
0xFE, 0xFD, 0x71, 0x77, 0x2E, 0x4B, 0x92, 0x1D, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0xFF, 0xF1, 0x4C, 0x80, 0x0C, 0xFF, 0xFC,
0x21, 0x17, 0x4F, 0xFF, 0xFF, 0xF8, 0x28, 0x59, 0xC4, 0xAD, 0x28, 0x99, 0x29, 0xAE, 0xF7, 0xF5, 0x6A, 0xB9, 0x2D, 0x25, 0xC7, 0x5C, 0x92, 0x02,
0x13, 0x42, 0x16, 0x62, 0x16, 0x67, 0x76, 0x6D, 0xDA, 0xA9, 0x9A, 0xBF, 0xE3, 0xC9, 0x27, 0x5E, 0x8A, 0xE4, 0xA6, 0x6A, 0xE4, 0xA5, 0x1C, 0x73,
0x35, 0x9B, 0x46, 0x6D, 0x19, 0xB4, 0x39, 0xA3, 0x36, 0x8C, 0xCD, 0x38, 0xD3, 0x8D, 0x66, 0x69, 0xC6, 0xB3, 0x68, 0xCD, 0xA3, 0x36, 0x8C, 0xDA,
0x33, 0x50, 0x8E, 0x34, 0xA2, 0x64, 0xA6, 0xBB, 0xDF, 0xD5, 0xAA, 0xE4, 0xB4, 0x97, 0x1D, 0x72, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C,
};
const std::uint8_t AAC_RAW_51[] = {
0x00, 0xDE, 0x34, 0xAC, 0xF1, 0x1D, 0x0C, 0x05, 0x89, 0xA2, 0x61, 0x40,
0xB4, 0x4A, 0x37, 0x8D, 0xFF, 0x7F, 0xFD, 0x3F, 0xCF, 0xFB, 0x79, 0xE7,
0xE3, 0xCE, 0x4C, 0x8B, 0x5D, 0xD5, 0xD5, 0x3F, 0xE9, 0x47, 0x6A, 0x5D,
0x69, 0xBA, 0xB1, 0x9A, 0x78, 0xAA, 0x3C, 0xD4, 0xF7, 0xA6, 0xD3, 0x13,
0xCC, 0x21, 0x93, 0x2B, 0x3E, 0x67, 0xDE, 0x74, 0x1A, 0xA3, 0xE7, 0x31,
0xE2, 0x47, 0xE8, 0x68, 0xFB, 0xD5, 0xF6, 0xB5, 0xFC, 0x57, 0xDE, 0x9E,
0x43, 0x6F, 0x3E, 0xF5, 0xF2, 0x1F, 0xBC, 0xFB, 0xC5, 0xBC, 0x53, 0x16,
0xE4, 0x57, 0xAC, 0x64, 0x14, 0xE6, 0x88, 0xAF, 0x66, 0xBA, 0x8C, 0x7A,
0x86, 0xF5, 0x8D, 0xC4, 0xA2, 0x36, 0x89, 0xE3, 0x21, 0xF9, 0xA5, 0x8A,
0xAF, 0xF0, 0xE5, 0x91, 0x2C, 0x15, 0xA2, 0x67, 0xF4, 0x97, 0xDA, 0x40,
0x0A, 0x00, 0x8A, 0x45, 0x7C, 0x92, 0xEA, 0x8F, 0x87, 0x56, 0xC2, 0x40,
0xE1, 0xA2, 0x23, 0x1E, 0x89, 0xE7, 0xBA, 0x61, 0xA3, 0xD5, 0xB9, 0x77,
0x27, 0x13, 0x73, 0x49, 0xE4, 0x98, 0x83, 0x3A, 0x25, 0x86, 0x3A, 0x10,
0x3D, 0x5C, 0xC8, 0xC0, 0x8F, 0xDB, 0x58, 0x50, 0xB0, 0xFB, 0x3F, 0x33,
0xAD, 0xE1, 0xD7, 0xC2, 0xF7, 0xB3, 0x98, 0xDF, 0x39, 0x87, 0xE2, 0x97,
0x34, 0xB4, 0x2A, 0x3A, 0xA0, 0x64, 0x0A, 0x80, 0x76, 0x84, 0xA6, 0x1D,
0x43, 0xF4, 0x0E, 0x12, 0x3E, 0xF2, 0xE2, 0x6A, 0x1F, 0x30, 0xA1, 0xD5,
0xE8, 0x0A, 0x22, 0x39, 0x9E, 0x44, 0xF3, 0xD1, 0x81, 0x6F, 0x49, 0x5A,
0x9C, 0x1F, 0x54, 0xB9, 0x2B, 0xB4, 0x73, 0xA3, 0x8D, 0x74, 0x6F, 0x87,
0x2D, 0x51, 0xCE, 0x3A, 0x39, 0xED, 0x38, 0x49, 0x55, 0x7C, 0x7D, 0xBE,
0xED, 0x65, 0x29, 0xAE, 0x3E, 0xBE, 0x70, 0xD1, 0x08, 0xD2, 0x1B, 0xEC,
0xF0, 0x66, 0x56, 0x8A, 0x03, 0xA9, 0x80, 0xE9, 0x5F, 0x2F, 0xFA, 0x7F,
0xF1, 0xFE, 0xFF, 0xED, 0xE7, 0x9F, 0x8F, 0x3C, 0xEB, 0x37, 0xAC, 0xEA,
0xD9, 0x75, 0x02, 0xD4, 0xDC, 0xDD, 0x45, 0xED, 0x9C, 0x2A, 0x83, 0x34,
0xF1, 0x54, 0xD2, 0x3F, 0xBD, 0x36, 0x98, 0x69, 0x87, 0x04, 0xAA, 0x5F,
0x99, 0xF7, 0x9D, 0x06, 0xA8, 0xF9, 0xCC, 0x78, 0x91, 0xFA, 0x1A, 0x3E,
0xF5, 0x7C, 0xD8, 0xF7, 0x9F, 0x7A, 0x79, 0x0D, 0xD5, 0x45, 0x5C, 0x55,
0x2A, 0x4A, 0xA0, 0x66, 0x59, 0xC6, 0x82, 0x89, 0x66, 0x0C, 0x65, 0xF5,
0xE1, 0xEA, 0xEE, 0xD9, 0x9E, 0x5F, 0x5B, 0xB4, 0xE0, 0x93, 0x0F, 0x11,
0xA2, 0x49, 0xC3, 0x2F, 0xC7, 0xA1, 0x6E, 0x1A, 0x81, 0xFF, 0x57, 0x7D,
0x6F, 0xC3, 0xAB, 0x61, 0x20, 0x70, 0xD1, 0x11, 0x8F, 0x44, 0xEB, 0x3C,
0xF4, 0x60, 0x59, 0xA4, 0xAD, 0x4E, 0x0F, 0x54, 0xB4, 0x5C, 0xDF, 0x67,
0x88, 0x68, 0xA0, 0x3A, 0x9F, 0x0E, 0x95, 0xF2, 0xFF, 0xB7, 0xFE, 0x3F,
0xDF, 0xFD, 0xBC, 0xF3, 0xF1, 0xE7, 0xBE, 0xB2, 0xA6, 0xFA, 0xBA, 0x49,
0x02, 0xD5, 0x6E, 0x6E, 0xA2, 0x61, 0xC2, 0xA8, 0x33, 0x4F, 0x15, 0x4D,
0x23, 0xFB, 0xD3, 0x69, 0x86, 0x6C, 0x70, 0x4A, 0xA5, 0xF9, 0x9F, 0x79,
0xD0, 0x6A, 0x8F, 0x9C, 0xC7, 0x89, 0x1F, 0xA1, 0xA3, 0xEF, 0x57, 0xCD,
0x2D, 0xE7, 0xEF, 0x4F, 0x21, 0xB7, 0x9F, 0x7A, 0xF9, 0x0F, 0xDE, 0x3B,
0xC5, 0xBC, 0x50, 0x0B, 0x33, 0xEB, 0x19, 0x05, 0x39, 0xA2, 0x2B, 0xD9,
0xAE, 0xA3, 0x1D, 0x81, 0xCC, 0x1B, 0xCC, 0x9C, 0xA3, 0x5F, 0x03, 0xE4,
0x96, 0xE6, 0xF8, 0xAC, 0xC0, 0x98, 0x22, 0xA8, 0x3E, 0x29, 0x7A, 0xC8,
0x30, 0xEA, 0xD8, 0x48, 0x1C, 0x34, 0x44, 0x63, 0xD1, 0x39, 0x18, 0xD2,
0x1B, 0xEC, 0xF1, 0x0D, 0x14, 0x07, 0x52, 0xE1, 0xD2, 0xBE, 0x5F, 0xF6,
0xFF, 0xC7, 0xFB, 0xFF, 0xB7, 0x9E, 0x7E, 0x3C, 0xF7, 0xD6, 0x54, 0xDF,
0x57, 0x49, 0x20, 0x5A, 0xAD, 0xCD, 0xD4, 0x4C, 0x6F, 0x85, 0x50, 0x66,
0x9E, 0x2A, 0x9A, 0x47, 0xF7, 0xA6, 0xD3, 0x0C, 0xD8, 0xE0, 0x95, 0x4B,
0xF3, 0x3E, 0xF3, 0xA0, 0xD5, 0x1F, 0x39, 0x8F, 0x12, 0x3F, 0x43, 0x47,
0xDE, 0xAF, 0x9A, 0x5B, 0xCF, 0xDE, 0x9E, 0x43, 0x6F, 0x3E, 0xF5, 0xF2,
0x1F, 0xBC, 0x77, 0x8B, 0x78, 0xA0, 0x16, 0x67, 0xD6, 0x32, 0x0A, 0x73,
0x44, 0x57, 0xB3, 0x5D, 0x46, 0x3B, 0x03, 0x98, 0x37, 0x99, 0x39, 0x46,
0xBE, 0x07, 0xC9, 0x2D, 0xCD, 0xF1, 0x59, 0x81, 0x30, 0x45, 0x50, 0x7C,
0x52, 0xF5, 0x90, 0x61, 0xD5, 0xB0, 0x90, 0x38, 0x68, 0x88, 0xC7, 0xA2,
0x7B, 0x9D, 0x3C, 0x6A, 0xE3, 0x56, 0xE9, 0x8F, 0x73, 0x3A, 0xA6, 0xFB,
0x3C, 0x43, 0x45, 0x01, 0xD4, 0xF8, 0x74, 0xAF, 0x97, 0xFD, 0xBF, 0xF1,
0xFE, 0xFF, 0xED, 0xE7, 0x9F, 0x8F, 0x3D, 0xF5, 0x95, 0x37, 0xD5, 0xD2,
0x48, 0x16, 0xAB, 0x73, 0x75, 0x13, 0x0E, 0x15, 0x41, 0x9A, 0x78, 0xAA,
0x69, 0x1F, 0xDE, 0x9B, 0x4C, 0x33, 0x63, 0x82, 0x55, 0x2F, 0xCC, 0xFB,
0xCE, 0x83, 0x54, 0x7C, 0xE6, 0x3C, 0x48, 0xFD, 0x0D, 0x1F, 0x7A, 0xBE,
0x69, 0x6F, 0x3F, 0x7A, 0x79, 0x0D, 0xBC, 0xFB, 0xD7, 0xC8, 0x7E, 0xF1,
0xDE, 0x2D, 0xE2, 0x80, 0x59, 0x9F, 0x58, 0xC8, 0x29, 0xCD, 0x11, 0x5E,
0xCD, 0x75, 0x18, 0xEC, 0x0E, 0x60, 0xDE, 0x64, 0xE5, 0x1A, 0xF8, 0x1F,
0x24, 0xB7, 0x37, 0xC5, 0x66, 0x04, 0xC1, 0x15, 0x41, 0xF1, 0x4B, 0xD6,
0x41, 0x87, 0x56, 0xC2, 0x40, 0xE1, 0xA2, 0x23, 0x1E, 0x89, 0xD8, 0x3B,
0x00, 0x6B, 0x1B, 0xED, 0x80, 0x8B, 0x8E, 0x4A, 0x30, 0x78, 0x0D, 0xAE,
0x19, 0x60, 0x33, 0x3A, 0x38,
};
const std::uint8_t MP3_MONO[] = {
0xFF, 0xFB, 0x14, 0xC4, 0x00, 0x00, 0x03, 0xB0, 0x21, 0x5E, 0xF4, 0x30, 0x80, 0x30, 0x98, 0x88, 0xA9, 0x83, 0x34, 0x70, 0x00, 0x18, 0x89, 0xCB,
0x20, 0x00, 0x3B, 0xBB, 0xB9, 0x9F, 0xD7, 0x0E, 0x06, 0x06, 0x06, 0x2C, 0x3E, 0xEF, 0x83, 0xE7, 0xF1, 0x00, 0x63, 0x83, 0xFD, 0x4E, 0xFC, 0xFF,
0x29, 0xE1, 0xF7, 0xD9, 0x87, 0x7E, 0xFF, 0x65, 0x9E, 0x21, 0xAF, 0x46, 0x58, 0xBB, 0x46, 0x58, 0xBA, 0x64, 0x40, 0x21, 0xB2, 0x6C, 0xFA, 0x6C,
0xF8, 0x42, 0x0E, 0x7C, 0x1E, 0x8F, 0x0D, 0xBF, 0x1B, 0x02, 0xBC, 0x24, 0x0D, 0x37, 0xCA, 0x9D, 0x52, 0xFD, 0x77, 0xE0, 0x16, 0xBA, 0x02, 0x04,
0xFF, 0xFB, 0x14, 0xC4, 0x03, 0x83, 0xC4, 0xE0, 0x2B, 0x28, 0x1D, 0xE4, 0x80, 0x20, 0x5D, 0x95, 0x60, 0x41, 0x70, 0x16, 0xC8, 0xD3, 0x02, 0x00,
0x2F, 0x12, 0x02, 0xD0, 0x40, 0x1D, 0x98, 0x4D, 0x06, 0x99, 0x84, 0xF2, 0x68, 0x98, 0xBF, 0x86, 0xD1, 0x84, 0xC8, 0x18, 0x2A, 0xA9, 0x79, 0x50,
0x85, 0xDE, 0x14, 0x88, 0x9A, 0xF8, 0x44, 0x02, 0xB0, 0x60, 0x62, 0x5E, 0x11, 0xE9, 0xDC, 0x18, 0x65, 0x8F, 0xFF, 0x7F, 0xFC, 0xB3, 0xF8, 0x58,
0xEF, 0xFF, 0xFF, 0xE1, 0x95, 0xF8, 0x44, 0x02, 0xB0, 0x60, 0x62, 0x5E, 0x11, 0xE9, 0xDC, 0x18, 0x65, 0x8F, 0xFF, 0x7F, 0xFC, 0xB3, 0xF8, 0x58,
0xFF, 0xFB, 0x14, 0xC4, 0x09, 0x83, 0xC2, 0xEC, 0xAB, 0x02, 0x0B, 0x80, 0xB6, 0x40, 0x5D, 0x95, 0x60, 0x41, 0x70, 0x16, 0xC8, 0xEF, 0xFF, 0xFF,
0xE1, 0x9F, 0x08, 0x80, 0x56, 0x0C, 0x0C, 0x4B, 0xC2, 0x3D, 0x3B, 0x83, 0x0C, 0xB1, 0xFF, 0xEF, 0xFF, 0x96, 0x7F, 0x0B, 0x1D, 0xFF, 0xFF, 0xFC,
0x31, 0xF8, 0x44, 0x02, 0xB0, 0x60, 0x62, 0x5E, 0x11, 0xE9, 0xDC, 0x18, 0x65, 0x8F, 0xFF, 0x7F, 0xFC, 0xB3, 0xF8, 0x58, 0xEF, 0xFF, 0xFF, 0xE1,
0x9F, 0x08, 0x80, 0x56, 0x0C, 0x0C, 0x4B, 0xC2, 0x3D, 0x3B, 0x83, 0x0C, 0xB1, 0xFF, 0xEF, 0xFF, 0x96, 0x7F, 0x0B, 0x1D, 0xFF, 0xFF, 0xFC, 0x31,
0xFF, 0xFB, 0x14, 0xC4, 0x17, 0x83, 0xC2, 0xEC, 0xAB, 0x02, 0x0B, 0x80, 0xB6, 0x40, 0x5D, 0x95, 0x60, 0x41, 0x70, 0x16, 0xC8, 0x96, 0x55, 0x8D,
0xBF, 0xE9, 0xD8, 0x50, 0x01, 0xA6, 0x17, 0x80, 0x34, 0x61, 0x00, 0x17, 0xC6, 0x15, 0x40, 0xD4, 0x61, 0x56, 0x25, 0x66, 0x3E, 0xA4, 0x92, 0x62,
0xC3, 0xED, 0x26, 0x23, 0xA5, 0x5C, 0x63, 0x10, 0x01, 0xC6, 0x0F, 0x20, 0x9E, 0x60, 0x62, 0x08, 0x26, 0x06, 0xE0, 0x12, 0xD6, 0x22, 0x02, 0x6C,
0x93, 0xC7, 0x04, 0x3E, 0xBF, 0xFE, 0xBF, 0xFF, 0x72, 0x62, 0x28, 0x22, 0xD1, 0x2F, 0xEF, 0xFD, 0xF1, 0x15, 0x09, 0x83, 0x08, 0x8C, 0x00, 0xFE,
0xFF, 0xFB, 0x14, 0xC4, 0x25, 0x80, 0x07, 0x74, 0x2D, 0x16, 0x15, 0xE7, 0x80, 0x00, 0xF2, 0x0C, 0xE8, 0x83, 0x36, 0xB0, 0x00, 0xC4, 0x42, 0x82,
0xC0, 0x86, 0x24, 0x2A, 0x02, 0x11, 0xFF, 0x02, 0x70, 0xF6, 0x07, 0x80, 0x9B, 0xCB, 0xCD, 0x0D, 0x00, 0x7C, 0x49, 0x1D, 0xBF, 0xD3, 0xDE, 0x3B,
0x52, 0x36, 0xFE, 0xFA, 0xF3, 0x66, 0xB5, 0x13, 0xDF, 0x06, 0x84, 0xA1, 0x2F, 0xCB, 0x05, 0x41, 0x5F, 0xF5, 0x2A, 0x4C, 0x41, 0x4D, 0x45, 0x34,
0x2E, 0x30, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xFF, 0xFB, 0x14, 0xC4, 0x0E, 0x83, 0xC0, 0x00, 0x01, 0xA4, 0x1C, 0x00, 0x00, 0x20, 0x00, 0x00, 0x34, 0x80, 0x00, 0x00, 0x04, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
};
const std::uint8_t HEAAC_V2_MONO[] = {
0xFF, 0xF1, 0x58, 0x40, 0x10, 0x02, 0x80, 0x01, 0x40, 0x22, 0x80, 0xA3, 0x6E, 0xEF, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4A, 0x80,
0x00, 0x06, 0xF5, 0x61, 0x0A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5E, 0xFF, 0xF1, 0x58, 0x40, 0x10, 0x02, 0x80, 0x01, 0x40, 0x42, 0x80, 0xA3, 0x78, 0x46, 0x81, 0x00,
0x00, 0x00, 0x00, 0x00, 0x38, 0x76, 0xE4, 0x89, 0xB5, 0x65, 0xE5, 0xDF, 0xFE, 0xB7, 0x32, 0x7C, 0x7F, 0xF0, 0x00, 0x06, 0xF4, 0xC1, 0x0A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5E, 0xFF, 0xF1, 0x58, 0x40, 0x18, 0xA2, 0x38, 0x01,
0x0A, 0x97, 0x98, 0xD8, 0x73, 0x75, 0x18, 0xBB, 0x6D, 0xCD, 0xA6, 0xE8, 0x7F, 0x09, 0xD5, 0xA0, 0x7E, 0x99, 0xC7, 0x42, 0xF2, 0x57, 0xBB, 0xC8,
0xAB, 0x51, 0x57, 0x0A, 0xBF, 0x56, 0x8A, 0x40, 0x48, 0xFB, 0xCC, 0xF1, 0xFF, 0x4E, 0x4C, 0x21, 0xEE, 0x7F, 0x10, 0xFD, 0xA6, 0xB4, 0xE2, 0xCC,
0x52, 0xA9, 0x38, 0x00, 0x00, 0xC4, 0x1A, 0x9A, 0xD2, 0x05, 0xE8, 0x94, 0xDB, 0xA5, 0x47, 0xFE, 0x92, 0xFC, 0x12, 0x41, 0x11, 0x08, 0x01, 0x22,
0x65, 0x54, 0x28, 0x24, 0x16, 0x72, 0xE9, 0xAA, 0xC7, 0x45, 0x33, 0xEC, 0x74, 0x13, 0xAC, 0x84, 0xD5, 0xD4, 0x95, 0xCB, 0x41, 0x9B, 0x55, 0x2D,
0xD5, 0xAC, 0x5C, 0xEF, 0xD4, 0x75, 0xF8, 0xD5, 0xCE, 0xC9, 0x64, 0xD9, 0xF5, 0x80, 0xD3, 0xD9, 0xAA, 0x5F, 0x1E, 0x45, 0x4F, 0xEA, 0x5F, 0xF8,
0xBF, 0x48, 0x1F, 0xAD, 0xDF, 0x0C, 0xE5, 0xF1, 0x7F, 0x65, 0xC0, 0x12, 0xFA, 0xBF, 0xE6, 0x40, 0x0D, 0xAA, 0xFD, 0x40, 0x02, 0x58, 0x64, 0xA4,
0x03, 0x2A, 0xC1, 0xAA, 0x79, 0x01, 0x6D, 0x37, 0x60, 0x78, 0x7B, 0x2B, 0x1B, 0x62, 0x6C, 0x87, 0xA7, 0xA2, 0xDB, 0x65, 0x00, 0xDE, 0x0F, 0xA0,
0x50, 0x00, 0x00, 0x00, 0x00, 0x01, 0xDB, 0x92, 0x26, 0xD5, 0x97, 0x97, 0x7F, 0xFA, 0xDC, 0xC9, 0xF1, 0xFF, 0xC0, 0x01, 0xC0, 0xFF, 0xF1, 0x58,
0x40, 0x15, 0x02, 0x10, 0x01, 0x3C, 0xF3, 0x08, 0xB6, 0xA1, 0x99, 0x0C, 0x42, 0x0A, 0xA1, 0x40, 0xF6, 0x05, 0x0A, 0x6C, 0x0B, 0xC0, 0x1F, 0x1F,
0x19, 0x9D, 0x15, 0x2A, 0x56, 0x97, 0x6C, 0x63, 0x88, 0xF4, 0x89, 0x13, 0x53, 0xA1, 0x9D, 0x8E, 0x9A, 0x93, 0x0C, 0x6A, 0x18, 0x0F, 0x2C, 0xCB,
0x53, 0xB3, 0x93, 0xA9, 0xA9, 0x32, 0x63, 0xC3, 0x0C, 0x07, 0xF0, 0xF1, 0x3C, 0x98, 0xB9, 0x6B, 0x75, 0xB0, 0x95, 0xAD, 0x62, 0xDC, 0xA4, 0xB4,
0x75, 0xE1, 0xAD, 0xE9, 0x64, 0x31, 0x51, 0x24, 0xAE, 0x6E, 0x20, 0xC0, 0x9D, 0x70, 0x25, 0x47, 0x1D, 0x67, 0x4D, 0x5C, 0xE1, 0xDA, 0x4E, 0x8A,
0x9E, 0xF9, 0xFA, 0x62, 0x16, 0xDA, 0x99, 0x9F, 0xD0, 0xDC, 0x7D, 0xBD, 0x5F, 0x31, 0x8B, 0xC2, 0xE8, 0xD0, 0xB8, 0xE5, 0xC6, 0xC0, 0x37, 0x8F,
0x68, 0xBC, 0x92, 0x4C, 0xD0, 0x00, 0x01, 0xFC, 0xFD, 0x43, 0xF2, 0xF5, 0xFF, 0x9F, 0xBF, 0xAD, 0x6D, 0x56, 0x0D, 0x3F, 0xF4, 0xA5, 0xD9, 0x17,
0xFF, 0x20, 0x02, 0x7C, 0x02, 0xCC, 0x8B, 0x26, 0x49, 0xFF, 0xFB, 0x9E, 0xA2, 0x00, 0x0F, 0xE4, 0xDF, 0xF0, 0x00, 0x00, 0x70,
};
const std::uint8_t HEAAC_STEREO[] = {
0xFF, 0xF1, 0x58, 0x80, 0x10, 0x02, 0xC0, 0x21, 0x21, 0x45, 0x00, 0x14, 0x50, 0x01, 0x46, 0xAD, 0xD5, 0x81, 0x75, 0x00, 0x00, 0x00, 0x1C, 0x60,
0x18, 0x0D, 0xEA, 0xC2, 0x14, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xBC, 0xFF, 0xF1, 0x58, 0x80, 0x1B, 0x62, 0x90, 0x21, 0x4A, 0xCC, 0x80, 0x1F, 0xEA, 0xFE, 0xBF, 0xC8,
0x87, 0x77, 0x07, 0x5B, 0x6B, 0x0A, 0xDA, 0x70, 0x6A, 0xC6, 0x8F, 0xE1, 0xE6, 0xC4, 0x36, 0x01, 0x48, 0xB1, 0x94, 0xF0, 0x67, 0x71, 0x13, 0x21,
0x28, 0xB0, 0x74, 0xC1, 0x02, 0x0B, 0xED, 0x1B, 0x75, 0xF2, 0x1D, 0x89, 0x8A, 0xFA, 0xCB, 0x17, 0x0D, 0x51, 0xAE, 0x81, 0x2D, 0xB3, 0x27, 0x07,
0x00, 0x69, 0x11, 0x1E, 0x51, 0x2E, 0x56, 0x4C, 0xD1, 0x9C, 0x39, 0x65, 0xED, 0x43, 0x53, 0x4E, 0x4E, 0x22, 0x8D, 0x5D, 0x48, 0x56, 0x50, 0x66,
0x75, 0x4B, 0x3D, 0x6B, 0x10, 0xE5, 0x38, 0x97, 0x8D, 0x5C, 0xEC, 0xCC, 0x6F, 0xDA, 0x1D, 0xD5, 0x99, 0x0C, 0xBD, 0x50, 0xDB, 0x92, 0xDE, 0x06,
0xD1, 0x0A, 0xE2, 0xD5, 0x32, 0x9C, 0xEA, 0x82, 0x1A, 0x30, 0x72, 0x92, 0xC1, 0x30, 0x88, 0xAC, 0x38, 0x15, 0xD9, 0xE7, 0x22, 0x5A, 0x97, 0x94,
0x0D, 0xE4, 0xFF, 0xFF, 0xFC, 0xC8, 0xD0, 0xEE, 0xDB, 0x60, 0x26, 0x6D, 0x11, 0x0D, 0x69, 0x10, 0x61, 0x63, 0xA7, 0xE7, 0xB7, 0x58, 0x11, 0x63,
0x29, 0xE0, 0xFB, 0xBD, 0x8E, 0x3C, 0x98, 0xBC, 0x01, 0x7E, 0x8F, 0x7B, 0xF7, 0xCB, 0x3A, 0xC2, 0xC0, 0xC2, 0xC2, 0xCB, 0x01, 0x1F, 0xA3, 0x94,
0xE8, 0x28, 0x44, 0x40, 0x52, 0x10, 0x42, 0x48, 0x0A, 0x94, 0x53, 0x9D, 0x57, 0xB0, 0x4B, 0x3E, 0x50, 0x80, 0xDF, 0xD2, 0x70, 0x30, 0x95, 0x33,
0x92, 0x2C, 0xAD, 0x9D, 0x59, 0x74, 0x83, 0xC0, 0x00, 0x00, 0x38, 0xFF, 0xF1, 0x58, 0x80, 0x16, 0xC2, 0x74, 0x21, 0x79, 0x08, 0x00, 0x87, 0xFF,
0xFF, 0xCF, 0x11, 0x6C, 0xCC, 0x21, 0x92, 0x14, 0x02, 0x80, 0xE8, 0x05, 0x50, 0x10, 0x50, 0x3F, 0xC7, 0xC6, 0x67, 0x50, 0xB0, 0xBB, 0x63, 0x1A,
0x77, 0x48, 0xF3, 0x0E, 0x0A, 0x02, 0x2F, 0xC6, 0xDA, 0xD2, 0xFA, 0xDA, 0x2D, 0x32, 0x15, 0x6E, 0xEE, 0xF0, 0x11, 0x7F, 0x0F, 0x13, 0xC9, 0x48,
0xEB, 0x84, 0x2D, 0x63, 0xAD, 0xAD, 0x61, 0xCA, 0x43, 0x5E, 0x1A, 0xDC, 0x31, 0x76, 0x4B, 0x9C, 0xBB, 0xD1, 0xF7, 0xD4, 0x84, 0xF0, 0x35, 0x83,
0x78, 0xEE, 0x95, 0x05, 0x2E, 0x61, 0x76, 0xDB, 0xE1, 0x68, 0xC9, 0x23, 0xA4, 0x1E, 0xAA, 0x71, 0xCA, 0x9A, 0xA5, 0xEE, 0x88, 0x0D, 0x0F, 0xE7,
0xFE, 0x55, 0x6D, 0x0F, 0x61, 0xA3, 0xAE, 0xEE, 0xF3, 0x08, 0xCB, 0x13, 0x08, 0x28, 0x0A, 0x1E, 0x28, 0x40, 0x70, 0xA0, 0xA7, 0x84, 0x14, 0x15,
0xF5, 0xD0, 0x50, 0x53, 0x51, 0x5F, 0x32, 0x89, 0xA8, 0xAC, 0x1F, 0x73, 0x62, 0xD1, 0x67, 0x53, 0x57, 0x86, 0x2C, 0x80, 0x44, 0xFB, 0xC2, 0xF4,
0xAF, 0x24, 0x93, 0x1D, 0x40, 0x00, 0xFF, 0x89, 0x36, 0xFF, 0xC6, 0x45, 0x23, 0x7F, 0xF0, 0x5B, 0xCC, 0x00, 0x00, 0x00, 0x03, 0x20, 0x0C, 0x01,
0x38,
};
constexpr std::int32_t errorApiFail = static_cast<std::int32_t>(0x807F0000);
constexpr std::int32_t errorInvalidType = static_cast<std::int32_t>(0x807F0001);
constexpr std::int32_t errorArg = static_cast<std::int32_t>(0x807F0002);
constexpr std::int32_t errorInvalidParamSize = static_cast<std::int32_t>(0x807F0004);
constexpr std::int32_t errorInvalidBsiInfoSize = static_cast<std::int32_t>(0x807F0005);
constexpr std::int32_t errorInvalidCtrlPointer = static_cast<std::int32_t>(0x807F0008);
constexpr std::int32_t errorInvalidAuInfoPointer = static_cast<std::int32_t>(0x807F000B);
constexpr std::int32_t errorInvalidHandle = static_cast<std::int32_t>(0x807F000F);
constexpr std::int32_t errorInvalidWordLength = static_cast<std::int32_t>(0x807F0010);
constexpr std::int32_t errorInvalidAuSize = static_cast<std::int32_t>(0x807F0011);
constexpr std::int32_t errorInvalidPcmSize = static_cast<std::int32_t>(0x807F0012);
constexpr std::int32_t errorInvalidConfigNumber = static_cast<std::int32_t>(0x807F0303);
constexpr std::int32_t errorInvalidAt9Config = static_cast<std::int32_t>(0x807F1000);
struct Streams {
AudiodecAuInfo au{sizeof(AudiodecAuInfo), nullptr, 0};
AudiodecPcmItem pcm{sizeof(AudiodecPcmItem), nullptr, 0};
std::vector<std::uint8_t> output = std::vector<std::uint8_t>(16384);
};
std::int32_t Decode(std::int32_t handle, AudiodecCtrl& ctrl, Streams& streams, const std::uint8_t* data, std::size_t size, std::uint32_t room = 16384) {
streams.au.p_au_addr = const_cast<std::uint8_t*>(data);
streams.au.ui_au_size = static_cast<std::uint32_t>(size);
streams.pcm.p_pcm_addr = streams.output.data();
streams.pcm.ui_pcm_size = room;
ctrl.pAuInfo = &streams.au;
ctrl.pPcmItem = &streams.pcm;
return sceAudiodecDecode(handle, &ctrl);
}
int ZeroCrossings(const std::int16_t* samples, std::size_t count, std::size_t stride) {
int crossings = 0;
for (std::size_t i = stride; i < count * stride; i += stride) crossings += (samples[i - stride] < 0) != (samples[i] < 0);
return crossings;
}
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};
AudiodecM4aacInfo info{sizeof(info), 0, 0, 0, 0};
AudiodecCtrl ctrl{&param, &info, nullptr, nullptr};
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 3);
Require(handle > 0 && info.ui_sampling_freq == 48000 && info.ui_number_of_channels == maxChannels);
Streams streams;
int crossings = 0;
for (std::size_t offset = 0, frame = 0; offset < sizeof(AAC_ADTS); offset += AdtsLength(AAC_ADTS + offset), ++frame) {
const std::size_t length = AdtsLength(AAC_ADTS + offset);
const std::uint8_t* data = adts ? AAC_ADTS + offset : AAC_ADTS + offset + 7;
const std::size_t size = adts ? sizeof(AAC_ADTS) - offset : length - 7;
Require(Decode(handle, ctrl, streams, data, size) == 0);
Require(streams.au.ui_au_size == (adts ? length : length - 7));
Require(streams.pcm.ui_pcm_size == 1024 * 2 * 2 && info.i_result == 0);
Require(info.ui_sampling_freq == 48000 && info.ui_number_of_channels == 2 && info.ui_heaac == 0);
if (frame == 2) crossings = ZeroCrossings(reinterpret_cast<const std::int16_t*>(streams.output.data()), 1024, 2);
}
Require(crossings >= 38 && crossings <= 46);
Require(Decode(handle, ctrl, streams, AAC_ADTS, sizeof(AAC_ADTS), 1024) == errorInvalidPcmSize);
if (adts) {
Require(Decode(handle, ctrl, streams, AAC_ADTS, 50) == errorApiFail && info.i_result == -5);
Require(Decode(handle, ctrl, streams, AAC_ADTS + 1, 50) == errorApiFail && info.i_result == -4);
}
Require(sceAudiodecClearContext(handle) == 0);
Require(sceAudiodecDeleteDecoder(handle) == 0);
}
void TestAacUnopenableLayout() {
AudiodecParamM4aac param{sizeof(param), 1, 1, 3, 2, 0};
AudiodecM4aacInfo info{sizeof(info), 0, 0, 0, 0};
AudiodecCtrl ctrl{&param, &info, nullptr, nullptr};
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 3);
Require(handle > 0);
Streams streams;
const std::size_t length = AdtsLength(AAC_ADTS);
std::vector<std::uint8_t> reserved(AAC_ADTS, AAC_ADTS + length);
reserved[2] = static_cast<std::uint8_t>((reserved[2] & 0xC3) | 13 << 2);
Require(Decode(handle, ctrl, streams, reserved.data(), reserved.size()) == errorApiFail && info.i_result == -4);
Require(streams.au.ui_au_size == 0 && streams.pcm.ui_pcm_size == 0);
Require(Decode(handle, ctrl, streams, reserved.data(), reserved.size()) == errorApiFail && info.i_result == -4);
Require(sceAudiodecClearContext(handle) == 0);
Require(Decode(handle, ctrl, streams, AAC_ADTS, length) == 0);
Require(streams.au.ui_au_size == length && streams.pcm.ui_pcm_size == 1024 * 2 * 2 && info.i_result == 0);
Require(sceAudiodecDeleteDecoder(handle) == 0);
}
void TestAacRaw51(std::uint32_t maxChannels) {
AudiodecParamM4aac param{sizeof(param), 1, 2, 3, maxChannels, 0};
AudiodecM4aacInfo info{sizeof(info), 0, 0, 0, 0};
AudiodecCtrl ctrl{&param, &info, nullptr, nullptr};
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 3);
Require(handle > 0 && info.ui_number_of_channels == maxChannels);
Streams streams;
Require(Decode(handle, ctrl, streams, AAC_RAW_51, sizeof(AAC_RAW_51)) == 0);
Require(streams.pcm.ui_pcm_size == 1024 * 6 * 2);
Require(info.ui_sampling_freq == 48000 && info.ui_number_of_channels == 6 && info.i_result == 0);
Require(sceAudiodecClearContext(handle) == 0);
Require(sceAudiodecDeleteDecoder(handle) == 0);
}
double UpperHalfEnergyShare(const std::int16_t* samples, std::size_t count, std::size_t stride) {
double upper = 0;
double total = 0;
for (std::size_t bin = 1; bin < count / 2; ++bin) {
double real = 0;
double imaginary = 0;
for (std::size_t i = 0; i < count; ++i) {
const double phase = 2 * std::numbers::pi * static_cast<double>(bin * i % count) / static_cast<double>(count);
real += samples[i * stride] * std::cos(phase);
imaginary += samples[i * stride] * std::sin(phase);
}
total += real * real + imaginary * imaginary;
if (bin >= count / 4) upper += real * real + imaginary * imaginary;
}
return upper / total;
}
void TestHeAac(const std::uint8_t* stream, std::size_t streamSize, std::uint32_t channels, bool adts, bool highEfficiency) {
AudiodecParamM4aac param{sizeof(param), 1, adts ? 1u : 2u, 6, channels, highEfficiency ? 1u : 0u};
AudiodecM4aacInfo info{sizeof(info), 0, 0, 0, 0};
AudiodecCtrl ctrl{&param, &info, nullptr, nullptr};
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 3);
Require(handle > 0);
Streams streams;
const std::uint32_t samples = highEfficiency ? 2048 : 1024;
const std::uint32_t room = samples * channels * 2;
for (std::size_t offset = 0; offset < streamSize; offset += AdtsLength(stream + offset)) {
const std::size_t length = AdtsLength(stream + offset);
Require(Decode(handle, ctrl, streams, adts ? stream + offset : stream + offset + 7, adts ? length : length - 7, room) == 0);
Require(streams.au.ui_au_size == (adts ? length : length - 7));
Require(streams.pcm.ui_pcm_size == room && info.i_result == 0);
Require(info.ui_sampling_freq == (highEfficiency ? 48000u : 24000u) && info.ui_number_of_channels == channels);
}
if (highEfficiency) {
Require(info.ui_heaac == 1);
Require(UpperHalfEnergyShare(reinterpret_cast<const std::int16_t*>(streams.output.data()), samples, channels) > 0.02);
}
Require(sceAudiodecDeleteDecoder(handle) == 0);
}
void TestMp3() {
AudiodecParamMp3 param{sizeof(param), 1};
AudiodecMp3Info info{};
info.ui_size = sizeof(info);
AudiodecCtrl ctrl{&param, &info, nullptr, nullptr};
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 2);
Require(handle > 0);
Streams streams;
std::size_t offset = 0;
int frames = 0;
float peak = 0;
while (offset < sizeof(MP3_MONO)) {
Require(Decode(handle, ctrl, streams, MP3_MONO + offset, sizeof(MP3_MONO) - offset) == 0);
Require(streams.au.ui_au_size == 144 * 32000 / 48000 + (MP3_MONO[offset + 2] >> 1 & 1));
Require(streams.pcm.ui_pcm_size == 1152 * 2);
Require(info.ui_header >> 21 == 0x7FF && info.uc_mode == 3 && info.i_result == 0);
for (std::size_t i = 0; i < 1152; ++i) peak = std::fmax(peak, std::fabs(reinterpret_cast<const std::int16_t*>(streams.output.data())[i] / 32768.0f));
offset += streams.au.ui_au_size;
++frames;
}
Require(offset == sizeof(MP3_MONO) && frames == 6 && peak > 0.1f && peak < 0.15f);
Require(Decode(handle, ctrl, streams, MP3_MONO, 10) == errorApiFail);
Require(Decode(handle, ctrl, streams, MP3_MONO + 1, 100) == errorApiFail);
Require(sceAudiodecDeleteDecoder(handle) == 0);
}
void TestAt9() {
AudiodecParamAt9 param{sizeof(param), 1, {0xFE, 0x72, 0x1F, 0xF0}};
AudiodecAt9Info info{};
info.ui_size = sizeof(info);
AudiodecCtrl ctrl{&param, &info, nullptr, nullptr};
const std::int32_t handle = sceAudiodecCreateDecoder(&ctrl, 1);
Require(handle > 0);
Require(info.ui_channel == 2 && info.ui_sampling_rate == 48000 && info.ui_frame_samples == 256);
Require(info.ui_super_frame_size == 1024 && info.ui_frames_in_super_frame == 4 && info.ui_bitrate == 384000);
Streams streams;
const std::vector<std::uint8_t> silence(1024);
Require(Decode(handle, ctrl, streams, silence.data(), 1023) == errorApiFail);
Require(Decode(handle, ctrl, streams, silence.data(), silence.size(), 4095) == errorInvalidPcmSize);
Require(Decode(handle, ctrl, streams, silence.data(), silence.size()) == errorApiFail);
Require(sceAudiodecDeleteDecoder(handle) == 0);
for (const std::int32_t wordSize : {0, 3, -1}) {
param.i_bw_pcm = wordSize;
Require(sceAudiodecCreateDecoder(&ctrl, 1) == errorInvalidWordLength);
}
param.i_bw_pcm = 2;
const std::int32_t floatHandle = sceAudiodecCreateDecoder(&ctrl, 1);
Require(floatHandle > 0 && sceAudiodecDeleteDecoder(floatHandle) == 0);
param.i_bw_pcm = 1;
param.ui_config_data[0] = 0xFD;
Require(sceAudiodecCreateDecoder(&ctrl, 1) == errorInvalidAt9Config);
}
}
int main() {
Require(sceAudiodecInitLibrary(0) == errorInvalidType);
Require(sceAudiodecInitLibrary(4) == errorInvalidType);
Require(sceAudiodecTermLibrary(0) == errorInvalidType);
Require(sceAudiodecTermLibrary(4) == errorInvalidType);
Require(sceAudiodecDeleteDecoder(0) == errorInvalidHandle);
Require(sceAudiodecDeleteDecoder(-1) == errorInvalidHandle);
Require(sceAudiodecClearContext(0) == errorInvalidHandle);
Require(sceAudiodecClearContext(-1) == errorInvalidHandle);
Require(sceAudiodecDecode(0, nullptr) == errorInvalidHandle);
Require(sceAudiodecDecode(-1, nullptr) == errorInvalidHandle);
AudiodecParamMp3 mp3{sizeof(mp3), 1};
AudiodecMp3Info mp3Info{};
mp3Info.ui_size = sizeof(mp3Info);
AudiodecCtrl ctrl{&mp3, &mp3Info, nullptr, nullptr};
Require(sceAudiodecCreateDecoder(&ctrl, 2) == errorArg);
for (std::uint32_t type = 1; type <= 3; ++type) Require(sceAudiodecInitLibrary(type) == 0);
Require(sceAudiodecCreateDecoder(nullptr, 2) == errorInvalidCtrlPointer);
Require(sceAudiodecCreateDecoder(&ctrl, 0) == errorInvalidType);
Require(sceAudiodecCreateDecoder(&ctrl, 5) == errorInvalidType);
mp3.ui_size = 12;
Require(sceAudiodecCreateDecoder(&ctrl, 2) == errorInvalidParamSize);
mp3.ui_size = sizeof(mp3);
mp3Info.ui_size = 16;
Require(sceAudiodecCreateDecoder(&ctrl, 2) == errorInvalidBsiInfoSize);
mp3Info.ui_size = sizeof(mp3Info);
for (const std::int32_t wordSize : {0, 2, 3, -1}) {
mp3.i_bw_pcm = wordSize;
Require(sceAudiodecCreateDecoder(&ctrl, 2) == errorInvalidWordLength);
}
mp3.i_bw_pcm = 1;
AudiodecParamM4aac aac{sizeof(aac), 1, 3, 3, 2, 0};
AudiodecM4aacInfo aacInfo{sizeof(aacInfo), 0, 0, 0, 0};
AudiodecCtrl aacCtrl{&aac, &aacInfo, nullptr, nullptr};
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == errorInvalidConfigNumber);
aac.ui_config_number = 1;
for (const std::int32_t wordSize : {0, 3, -1}) {
aac.i_bw_pcm = wordSize;
Require(sceAudiodecCreateDecoder(&aacCtrl, 3) == errorInvalidWordLength);
}
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);
Streams streams;
Require(sceAudiodecDecode(handle, &ctrl) == errorInvalidAuInfoPointer);
Require(Decode(handle, ctrl, streams, MP3_MONO, 0) == errorInvalidAuSize);
Require(Decode(handle, ctrl, streams, MP3_MONO, sizeof(MP3_MONO), 0) == errorInvalidPcmSize);
Require(Decode(handle + 1, ctrl, streams, MP3_MONO, sizeof(MP3_MONO)) == errorInvalidHandle);
Require(sceAudiodecDeleteDecoder(handle) == 0);
Require(sceAudiodecDeleteDecoder(handle) == errorInvalidHandle);
Require(sceAudiodecClearContext(handle) == errorInvalidHandle);
TestAac(true);
TestAac(false);
TestAac(false, 6);
TestAac(false, 8);
TestAacRaw51(6);
TestAacRaw51(8);
for (const bool adts : {true, false}) {
for (const bool highEfficiency : {true, false}) {
TestHeAac(HEAAC_V2_MONO, sizeof(HEAAC_V2_MONO), 1, adts, highEfficiency);
TestHeAac(HEAAC_STEREO, sizeof(HEAAC_STEREO), 2, adts, highEfficiency);
}
}
TestAacUnopenableLayout();
TestMp3();
TestAt9();
for (std::uint32_t type = 1; type <= 3; ++type) Require(sceAudiodecTermLibrary(type) == 0);
}