diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 3dccd9cb65..644b2e67b0 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -236,9 +236,9 @@ int InitContextFromTrackInfo(SceAtracContext *ctx, const TrackInfo *wave, u32 bu if ((ctx->info).codec != PSP_CODEC_AT3) { // At3plus // Configure the codec for the sample size, or whatever that data is. - (ctx->codec).unk40 = wave->sampleSizeMaybe; - (ctx->codec).unk48 = 0; - (ctx->codec).unk41 = wave->tailFlag; + (ctx->codec).fmt.at3.formatByte1 = wave->sampleSizeMaybe; + (ctx->codec).fmt.at3.at3Related = 0; + (ctx->codec).fmt.at3.formatByte2 = wave->tailFlag; return 0; } // At3. Set up the hardware codec (hopefully we can correctly support this in sceAudiocodec and thus sceAtrac LLE in the future) @@ -246,10 +246,10 @@ int InitContextFromTrackInfo(SceAtracContext *ctx, const TrackInfo *wave, u32 bu for (int counter = 4; counter >= 0; counter--) { if ((g_at3BitrateMeta[counter].sampleSize == (ctx->info).sampleSize) && ((int)g_at3BitrateMeta[counter].dataByte == wave->sampleSizeMaybe)) { - (ctx->codec).unk40 = (char)g_at3BitrateMeta[counter].jointStereo; - (ctx->codec).unk41 = 0; - (ctx->codec).unk42 = 0; - (ctx->codec).unk43 = 0; + (ctx->codec).fmt.at3.formatByte1 = (char)g_at3BitrateMeta[counter].jointStereo; + (ctx->codec).fmt.at3.formatByte2 = 0; + (ctx->codec).fmt.at3.unk2a = 0; + (ctx->codec).fmt.at3.unk2b = 0; return 0; } } diff --git a/Core/HLE/sceAudiocodec.cpp b/Core/HLE/sceAudiocodec.cpp index 9bcd2f2363..49782e5232 100644 --- a/Core/HLE/sceAudiocodec.cpp +++ b/Core/HLE/sceAudiocodec.cpp @@ -35,22 +35,49 @@ std::map g_audioDecoderContexts; static bool oldStateLoaded = false; static_assert(sizeof(SceAudiocodecCodec) == 128); +// Games allocate this structure and the ME writes into it, so every offset is load-bearing. +static_assert(offsetof(SceAudiocodecCodec, inBuf) == 0x18); +static_assert(offsetof(SceAudiocodecCodec, outBuf) == 0x20); +static_assert(offsetof(SceAudiocodecCodec, fmt) == 0x28); +static_assert(offsetof(SceAudiocodecCodec, fmt.at3.at3Related) == 0x30); +static_assert(offsetof(SceAudiocodecCodec, fmt.mp3.version) == 0x38); +static_assert(offsetof(SceAudiocodecCodec, fmt.mp3.bitrateIndex) == 0x44); +static_assert(offsetof(SceAudiocodecCodec, fmt.mp3.sampleRateIndex) == 0x48); +static_assert(offsetof(SceAudiocodecCodec, fmt.mp3.channelConfig) == 0x54); +static_assert(offsetof(SceAudiocodecCodec, allocMem) == 0x68); + +// Notes on the codec-specific fields, from watching games and from reading the firmware modules +// that drive this interface (avcodec.prx, libatrac3plus.prx, libmp3.prx). See the union in +// sceAudiocodec.h for the layout. +// +// A general point worth knowing: the hardware never needs an exact input frame size here. The +// only thing sceAudiocodecDecode does with the size is a cache writeback over inBuf before +// handing the frame to the ME, so every "size" the firmware computes or stores is an upper +// bound. // Atrac3+ (0x1000) frame sizes, and control bytes // // Bitrate Frame Size Byte 1 Byte 2 Channels // ----------------------------------------------------- // 48kbps 0x118 0x24 0x22 1? // This hits "Frame data doesn't match channel configuration". -// 64kbps 0x178 +// 64kbps 0x178 (0x2e implied by the formula below) // 96kbps? 0x230 0x28 0x45 2 // 128kbps 0x2E8 0x28 0x5c 2 // -// Seems like maybe the frame size is equal to "Byte 2" * 8 + 8 +// The frame size really is "Byte 2" * 8 + 8 - it holds for all three rows we have both numbers +// for, and libatrac3plus.prx writes 0x28/0x5c (the 128kbps row) into these two bytes at init as +// the worst case it sizes its EDRAM allocation against. So byte 2 is the hardware's own frame +// descriptor and reading it, as we do, is the right thing. // -// Known byte values. +// The channel guess below (bit 3 of byte 1) fits both data points we have and nothing else. // Atrac3 (0x1001) // +// The Media Engine only ever sees the first 0x68 bytes of this structure - me_wrapper.prx does +// sceKernelDcacheWritebackInvalidateRange(ctx, 0x68) before handing it over, and avcodec.prx +// validates the same range - so whatever the hardware uses to size an Atrac3 frame has to be in +// there. The only Atrac3-specific thing anything writes is the joint-stereo flag in byte 1. +// // Frame size data byte JointStereo? // ------------------------------------------------- // 0x180 0x04 0 @@ -58,24 +85,36 @@ static_assert(sizeof(SceAudiocodecCodec) == 128); // 0x0C0 0x0B 1 // 0x0C0 0x0E 0 // 0x098 0x0F 0 +// +// NOTE: sceAudiocodecDecode below hardcodes 384 (0x180) bytes per frame for Atrac3, which is only +// the first row. If a game ever drives Atrac3 through sceAudiocodec at one of the other sizes we +// will decode garbage. // AAC (0x1003) // ------------------------------------------------ // Sample rate is at offset 0x28. // srcBytesConsumed can be very small the first frames. // 0x1000 is always the frame size. +// The firmware sizes AAC from the bytes at 0x2c and 0x2d rather than from 0x28: input is +// 0x600 or 0x609, output 0x1000 or 0x2000, depending on those two. Consistent with the above. // MP3 (0x1002) // ------------------------------------------------ - +// The parameters live at 0x38 (MPEG version index: 0 = MPEG2, 1 = MPEG1, 2 = MPEG2.5), 0x44 +// (bitrate index) and 0x48 (sample rate index), and index the standard MPEG Layer III tables. +// sceAudiocodecInit presets 0x38 to 9999 meaning "not known yet", and GetInfo fills these in - +// which is why our GetInfo writes plausible values for a 128kbps 44.1kHz stereo stream. +// 0x54 is the channel configuration: libmp3.prx reads it as (value == 3) ? mono : stereo. +// 0x28 is not this frame's size - libmp3.prx writes 0x5A1 there once, the largest an MP3 frame +// can ever be. Output is 0x1200 bytes for MPEG1 (1152 samples) and 0x900 otherwise (576). void CalculateInputBytesAndChannelsAt3Plus(const SceAudiocodecCodec *ctx, int *inputBytes, int *channels) { *inputBytes = 0; *channels = 2; - int size = ctx->unk41 * 8 + 8; + int size = ctx->fmt.at3.formatByte2 * 8 + 8; // No idea if this is accurate, this is just a guess... - if (ctx->unk40 & 8) { + if (ctx->fmt.at3.formatByte1 & 8) { *channels = 2; } else { *channels = 1; @@ -93,6 +132,39 @@ void CalculateInputBytesAndChannelsAt3Plus(const SceAudiocodecCodec *ctx, int *i } } +// Atrac3 (0x1001). Unlike Atrac3+, the context doesn't carry a frame size - libatrac3plus.prx +// (and our mirror of it in AtracCtx2) writes only the joint-stereo flag into formatByte1 for +// Atrac3, so in general the size can't be recovered from the context alone. +// +// One case is unambiguous, though. Of the five frame sizes the hardware supports, exactly one is +// joint stereo (66kbps stereo, 0xC0 bytes), so that flag pins the size down by itself. Everything +// else falls back to the 132kbps stereo frame, which is what the old hardcoded 384 was. +static int Atrac3BytesPerFrameFromContext(const SceAudiocodecCodec *ctx, int *channels); + +// The MPEG sample rates, indexed by [version][sampleRateIndex] exactly as the hardware's own +// table in avcodec.prx does. Version is 0 = MPEG2, 1 = MPEG1, 2 = MPEG2.5. +static const int g_mpegSampleRates[3][4] = { + { 22050, 24000, 16000, 0 }, + { 44100, 48000, 32000, 0 }, + { 11025, 12000, 8000, 0 }, +}; + +// Returns 0 if the context doesn't describe a rate we recognize - which includes the common case +// where sceAudiocodecInit has run but GetInfo hasn't filled the fields in yet (version is 9999). +static int Mp3SampleRateFromContext(const SceAudiocodecCodec *ctx) { + const int version = ctx->fmt.mp3.version; + const int index = ctx->fmt.mp3.sampleRateIndex; + if (version < 0 || version >= 3 || index < 0 || index >= 4) { + return 0; + } + return g_mpegSampleRates[version][index]; +} + +// libmp3.prx reads the channel configuration this way. +static int Mp3ChannelsFromContext(const SceAudiocodecCodec *ctx) { + return ctx->fmt.mp3.channelConfig == 3 ? 1 : 2; +} + // find the audio decoder for corresponding ctxPtr in audioList static AudioDecoder *findDecoder(u32 ctxPtr) { auto it = g_audioDecoderContexts.find(ctxPtr); @@ -142,7 +214,7 @@ static int __AudioCodecInitCommon(u32 ctxPtr, int codec, bool mono) { // Initialize the codec memory. auto ctx = PSPPointer::Create(ctxPtr); - ctx->unk_init = 0x5100601; // Firmware version indicator? + ctx->magic = 0x5100601; ctx->err = 0; int bytesPerFrame = 0; @@ -156,7 +228,7 @@ static int __AudioCodecInitCommon(u32 ctxPtr, int codec, bool mono) { case PSP_CODEC_MP3: // Not seeing inited in Kurok (homebrew) // _dbg_assert_(ctx->inited == 1); - ctx->mp3_9999 = 9999; + ctx->fmt.mp3.version = 9999; break; case PSP_CODEC_AAC: // AAC / mp4 @@ -168,10 +240,9 @@ static int __AudioCodecInitCommon(u32 ctxPtr, int codec, bool mono) { break; case PSP_CODEC_AT3: { - // See AtracBase::CreateDecoder. Need to properly understand this one day.. - // - // TODO: How do we get the bytesPerFrame? - bytesPerFrame = 384; // TODO: Calculate from params. + // See AtracBase::CreateDecoder. The context only tells us whether the stream is joint + // stereo, which pins the frame size down in that one case - see the function. + bytesPerFrame = Atrac3BytesPerFrameFromContext(ctx, &channels); bool jointStereo = IsAtrac3StreamJointStereo(PSP_CODEC_AT3, bytesPerFrame, channels); // The only thing that changes are the jointStereo_ values. extraData[0] = 1; @@ -226,14 +297,23 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { CalculateInputBytesAndChannelsAt3Plus(ctx, &bytesPerFrame, &channels); break; case PSP_CODEC_MP3: - bytesPerFrame = ctx->srcBytesRead; + // Not srcBytesRead - that's an output field holding what the *previous* call consumed. + // The hardware uses the bound at 0x28, which the caller also guarantees is readable at + // inBuf (it does a cache writeback over exactly that range), so it's the safe length to + // hand a decoder that parses the frame header itself. + bytesPerFrame = ctx->fmt.mp3.maxFrameBytes; + if (bytesPerFrame <= 0) { + bytesPerFrame = ctx->srcBytesRead; + } + channels = Mp3ChannelsFromContext(ctx); + sampleRate = Mp3SampleRateFromContext(ctx); break; case PSP_CODEC_AAC: bytesPerFrame = ctx->srcBytesRead; - sampleRate = ctx->formatOutSamples; + sampleRate = ctx->fmt.aac.sampleRate; break; case PSP_CODEC_AT3: - bytesPerFrame = 384; + bytesPerFrame = Atrac3BytesPerFrameFromContext(ctx, &channels); break; } @@ -254,7 +334,7 @@ static int sceAudiocodecDecode(u32 ctxPtr, int codec) { int inDataConsumed = 0; int outSamples = 0; - DEBUG_LOG(Log::ME, "decoder. in: %08x out: %08x unk40: %02x unk41: %02x", ctx->inBuf, ctx->outBuf, ctx->unk40, ctx->unk41); + DEBUG_LOG(Log::ME, "decoder. in: %08x out: %08x format: %02x %02x", ctx->inBuf, ctx->outBuf, ctx->fmt.at3.formatByte1, ctx->fmt.at3.formatByte2); int16_t *outBuf = (int16_t *)Memory::GetPointerWriteOrException(ctx->outBuf); @@ -285,14 +365,14 @@ static int sceAudiocodecGetInfo(u32 ctxPtr, int codec) { // When this is called, the caller has written: // * inptr // * outptr - // * formatOutSamples = 0x5A1 + // * fmt.mp3.maxFrameBytes = 0x5A1 // Our response is written to a bunch of fields, but I really don't know much // about what the values are - this is handled internally in the ME. - ctx->mp3_3 = 3; - ctx->mp3_9 = 9; - ctx->mp3_0 = 0; - ctx->mp3_1 = 1; - ctx->mp3_1_first = 1; + ctx->fmt.mp3.unk3c = 3; + ctx->fmt.mp3.bitrateIndex = 9; + ctx->fmt.mp3.sampleRateIndex = 0; + ctx->fmt.mp3.unk60 = 1; + ctx->fmt.mp3.channelConfig = 1; break; } @@ -314,9 +394,9 @@ static int sceAudiocodecCheckNeedMem(u32 ctxPtr, int codec) { switch (codec) { case 0x1000: ctx->neededMem = 0x7bc0; - if (ctx->unk40 != 0x28 || ctx->unk41 != 0x5c) { + if (ctx->fmt.at3.formatByte1 != 0x28 || ctx->fmt.at3.formatByte2 != 0x5c) { ctx->err = 0x20f; - return hleLogError(Log::ME, SCE_AVCODEC_ERROR_INVALID_DATA, "Bad format values: %02x %02x", ctx->unk40, ctx->unk41); + return hleLogError(Log::ME, SCE_AVCODEC_ERROR_INVALID_DATA, "Bad format values: %02x %02x", ctx->fmt.at3.formatByte1, ctx->fmt.at3.formatByte2); } break; case 0x1001: @@ -327,12 +407,12 @@ static int sceAudiocodecCheckNeedMem(u32 ctxPtr, int codec) { break; case 0x1003: // Kosmodrones uses sceAudiocodec directly (no intermediate library). - INFO_LOG(Log::ME, "CheckNeedMem for codec %04x: format %02x %02x", codec, ctx->unk40, ctx->unk41); + INFO_LOG(Log::ME, "CheckNeedMem for codec %04x: format %02x %02x", codec, ctx->fmt.at3.formatByte1, ctx->fmt.at3.formatByte2); break; } ctx->err = 0; - ctx->unk_init = 0x5100601; + ctx->magic = 0x5100601; return hleLogWarning(Log::ME, 0, "%s", GetCodecName(codec)); } @@ -399,6 +479,22 @@ static const At3HeaderMap at3HeaderMap[] = { { 0x00C0, 2, 1 }, // 66 kbps stereo }; +static int Atrac3BytesPerFrameFromContext(const SceAudiocodecCodec *ctx, int *channels) { + // AtracCtx2 puts the joint-stereo flag here for Atrac3, mirroring libatrac3plus. + const bool jointStereo = (ctx->fmt.at3.formatByte1 & 1) != 0; + if (jointStereo) { + for (size_t i = 0; i < ARRAY_SIZE(at3HeaderMap); ++i) { + if (at3HeaderMap[i].jointStereo) { + *channels = at3HeaderMap[i].channels; + return at3HeaderMap[i].bytes; + } + } + } + // 132kbps stereo - by far the most common, and what we assumed unconditionally before. + *channels = 2; + return 0x180; +} + bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels) { if (codecType != PSP_CODEC_AT3) { // Well, might actually be, but it's not used in codec setup. diff --git a/Core/HLE/sceAudiocodec.h b/Core/HLE/sceAudiocodec.h index ac3aaf9c45..1da7067f31 100644 --- a/Core/HLE/sceAudiocodec.h +++ b/Core/HLE/sceAudiocodec.h @@ -21,66 +21,101 @@ class PointerWrap; -// audioType +// audioType. Every sceAudiocodec entry point validates these as "codec - 0x1000 < 6", so the +// range is exactly 0x1000..0x1005 - see avcodec.prx. enum PSPAudioType { PSP_CODEC_AT3PLUS = 0x00001000, PSP_CODEC_AT3 = 0x00001001, PSP_CODEC_MP3 = 0x00001002, PSP_CODEC_AAC = 0x00001003, // sceMp4 decodes this in an mp4 container + // 0x1004 is handled by parts of the firmware but it's ultimately rejected by the ME code. Never implemented. + PSP_CODEC_UNKNOWN_1004 = 0x00001004, PSP_CODEC_WMA = 0x00001005, }; +// The context the Media Engine works on. Games allocate this themselves and hand it over, so the +// layout is fixed - don't reorder anything here. +// +// Offsets 0x00..0x27 are identical for every codec, and sceVideocodec's context shares them too +// (mpeg.prx and videocodec_260.prx annotate the same fields), so this really is one ME "codec +// context" ABI. Everything from 0x28 on is per-codec, which is what the union models: each +// library writes a different set of fields there. struct SceAudiocodecCodec { - s32 unk_init; - s32 unk4; - s32 err; // 8 - s32 edramAddr; // c // presumably in ME memory? - s32 neededMem; // 10 // 0x102400 for Atrac3+ - s32 inited; // 14 - u32 inBuf; // 18 // Before decoding, set this to the start of the raw frame. - s32 srcBytesRead; // 1c - u32 outBuf; // 20 // This is where the decoded data is written. - s32 dstSamplesWritten; // 24 - // Probably, from here on out is a union with different fields for different codecs. - union { // offset 40 / 0x28 + u32 magic; // 0x00 set to 0x05100601 before every ME call + s32 unk4; // 0x04 + s32 err; // 0x08 + u32 edramAddr; // 0x0c in ME memory + s32 neededMem; // 0x10 0x102400 for Atrac3+ + s32 inited; // 0x14 + u32 inBuf; // 0x18 the raw frame to decode + s32 srcBytesRead; // 0x1c written by the decoder + u32 outBuf; // 0x20 where decoded PCM goes + s32 dstSamplesWritten; // 0x24 written by the decoder + + // Codec-specific, 0x28..0x67. + union { + // Atrac3plus and Atrac3. libatrac3plus.prx writes formatByte1/formatByte2 at init + // (0x28/0x5c for the worst case it sizes EDRAM against) and zeroes at3Related before + // every Atrac3plus decode. struct { - s8 unk40; // 28 format or looping related . Aka tailrelated - s8 unk41; // 29 format or looping related . Aka tailflag - s8 unk42; - s8 unk43; - }; - u32 formatOutSamples; - }; - union { // offset 44 / 0x2C + u8 formatByte1; // 0x28 bit 3 appears to mean stereo + u8 formatByte2; // 0x29 frame size in bytes = formatByte2 * 8 + 8 + u8 unk2a; // 0x2a + u8 unk2b; // 0x2b + u32 unk2c; // 0x2c + u32 at3Related; // 0x30 zeroed for Atrac3plus, left alone for Atrac3 + s32 unk34; // 0x34 + s32 unk38[12]; // 0x38..0x67 + } at3; + + // MP3. Field meanings are from avcodec.prx's frame-size calculator, which indexes the + // standard MPEG bitrate and sample-rate tables with them, and from libmp3.prx reading + // version and channelConfig back out. struct { - u8 unk44; - s8 unk45; - s8 unk46; - s8 unk47; - }; + // 0x28 libmp3.prx writes 0x5A1 here once at setup, and never per frame: it is the + // largest an MP3 frame can be (144 * 320000 / 32000 + 1 padding byte). The hardware + // only uses it as the length for a cache writeback over inBuf before handing the + // frame to the ME, so it is an upper bound rather than this frame's size. + u32 maxFrameBytes; + u32 unk2c; // 0x2c + s32 unk30; // 0x30 + s32 unk34; // 0x34 + // 0x38 MPEG version index: 0 = MPEG2, 1 = MPEG1, 2 = MPEG2.5. sceAudiocodecInit + // presets it to 9999 to mean "not known yet"; GetInfo fills it in. + s32 version; + // 0x3c Observed to be 3. avcodec's (unreachable) frame-size path treats this as the + // raw MPEG layer bits and only computes a size for 1 or 2, where 1 is Layer III - + // so 3 would fall through to its maximum-size fallback. Unexplained. + s32 unk3c; + s32 unk40; // 0x40 + s32 bitrateIndex; // 0x44 index into the MPEG Layer III bitrate table (9 = 128kbps) + s32 sampleRateIndex; // 0x48 0..2 within the version's rates (0 = 44100 for MPEG1) + s32 unk4c; // 0x4c + s32 unk50; // 0x50 + // 0x54 libmp3.prx reads this as: channels = (channelConfig == 3) ? 1 : 2. + s32 channelConfig; + s32 unk58; // 0x58 + s32 unk5c; // 0x5c + s32 unk60; // 0x60 + s32 unk64; // 0x64 + } mp3; + + // AAC. The hardware sizes its input from the byte at 0x2c and its output from the byte + // at 0x2d; the sample rate at 0x28 is our own observation from games. struct { - s16 unk44_16; - s16 unk46_16; - }; - u32 unk44_32; - }; - s32 unk48; // 30 Atrac3 (non-+) related. Zero with Atrac3+. - s32 unk52; // 34 - s32 mp3_9999; // 38 // unk56 - s32 mp3_3; // unk60 gets the value 3 - s32 unk64; // Atrac3+ size related - s32 mp3_9; - s32 mp3_0; - s32 unk76; - s32 unk80; - s32 mp3_1_first; - s32 unk88; - s32 unk92; - s32 mp3_1; - s32 unk100; - u32 allocMem; // 104 - // make sure the size is 128 - u8 unk[20]; + u32 sampleRate; // 0x28 + u8 unk2c; // 0x2c + u8 unk2d; // 0x2d + u8 unk2e; // 0x2e + u8 unk2f; // 0x2f + s32 unk30[14]; // 0x30..0x67 + } aac; + + u8 raw[0x40]; + } fmt; + + u32 allocMem; // 0x68 not hardware - where our GetEDRAM stores what it handed out + u8 unk[0x14]; // 0x6c }; void __AudioCodecInit();