mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
The field at 0x24 is a byte count, like srcBytesRead next to it, and sceAudiocodecGetOutputBytes describes the same quantity the same way (0x1200 for MPEG1 MP3). We were putting the sample count there, a quarter of the value, and libmp3.prx takes it as the length of the PCM to pass on. Renamed to dstBytesWritten so it reads like what it is. Nothing on our side consumed the field, so this only changes what the firmware modules see. mpeg.prx ignores it, which is why Atrac3+ playback was unaffected either way, but libatrac3plus.prx does read it. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
131 lines
5.4 KiB
C++
131 lines
5.4 KiB
C++
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official git repository and contact information can be found at
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
#pragma once
|
|
|
|
#include <map>
|
|
|
|
class PointerWrap;
|
|
|
|
// 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 {
|
|
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 dstBytesWritten; // 0x24 written by the decoder, in bytes like srcBytesRead
|
|
|
|
// 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 {
|
|
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 {
|
|
// 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 input frame size is 0x609 when unk2c is nonzero and 0x600 when it is zero, and
|
|
// the output size comes from unk2d (avcodec.prx decodeUtility); the sample rate at 0x28 is
|
|
// our own observation from games.
|
|
struct {
|
|
u32 sampleRate; // 0x28
|
|
u8 unk2c; // 0x2c selects the input frame size (see above)
|
|
u8 unk2d; // 0x2d selects the output size
|
|
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();
|
|
void __AudioCodecShutdown();
|
|
void Register_sceAudiocodec();
|
|
void __sceAudiocodecDoState(PointerWrap &p);
|
|
|
|
class AudioDecoder;
|
|
extern std::map<u32, AudioDecoder *> g_audioDecoderContexts;
|
|
|
|
bool IsAtrac3StreamJointStereo(int codecType, int bytesPerFrame, int channels);
|