diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 7bf9e7fa45..9aae6db15b 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -147,7 +147,7 @@ struct InputBuffer { struct Atrac; int __AtracSetContext(Atrac *atrac); -void _AtracGenerateContext(Atrac *atrac); +static void _AtracWriteContextToPSPMem(Atrac *atrac); struct AtracLoopInfo { int cuePointID; @@ -419,7 +419,7 @@ struct Atrac { InputBuffer first_; InputBuffer second_; - PSPPointer context_; + PSPPointer context_; void ForceSeekToSample(int sample) { if (decoder_) { @@ -511,22 +511,31 @@ struct AtracResetBufferInfo { const int PSP_NUM_ATRAC_IDS = 6; static bool atracInited = true; -static Atrac *atracIDs[PSP_NUM_ATRAC_IDS]; -static u32 atracIDTypes[PSP_NUM_ATRAC_IDS]; +static Atrac *atracContexts[PSP_NUM_ATRAC_IDS]; +static u32 atracContextTypes[PSP_NUM_ATRAC_IDS]; static int atracLibVersion = 0; static u32 atracLibCrc = 0; void __AtracInit() { + _assert_(sizeof(SceAtracContext) == 256); + atracInited = true; - memset(atracIDs, 0, sizeof(atracIDs)); + memset(atracContexts, 0, sizeof(atracContexts)); // Start with 2 of each in this order. - atracIDTypes[0] = PSP_MODE_AT_3_PLUS; - atracIDTypes[1] = PSP_MODE_AT_3_PLUS; - atracIDTypes[2] = PSP_MODE_AT_3; - atracIDTypes[3] = PSP_MODE_AT_3; - atracIDTypes[4] = 0; - atracIDTypes[5] = 0; + atracContextTypes[0] = PSP_MODE_AT_3_PLUS; + atracContextTypes[1] = PSP_MODE_AT_3_PLUS; + atracContextTypes[2] = PSP_MODE_AT_3; + atracContextTypes[3] = PSP_MODE_AT_3; + atracContextTypes[4] = 0; + atracContextTypes[5] = 0; +} + +void __AtracShutdown() { + for (size_t i = 0; i < ARRAY_SIZE(atracContexts); ++i) { + delete atracContexts[i]; + atracContexts[i] = nullptr; + } } void __AtracLoadModule(int version, u32 crc) { @@ -542,16 +551,16 @@ void __AtracDoState(PointerWrap &p) { Do(p, atracInited); for (int i = 0; i < PSP_NUM_ATRAC_IDS; ++i) { - bool valid = atracIDs[i] != NULL; + bool valid = atracContexts[i] != nullptr; Do(p, valid); if (valid) { - Do(p, atracIDs[i]); + Do(p, atracContexts[i]); } else { - delete atracIDs[i]; - atracIDs[i] = NULL; + delete atracContexts[i]; + atracContexts[i] = nullptr; } } - DoArray(p, atracIDTypes, PSP_NUM_ATRAC_IDS); + DoArray(p, atracContextTypes, PSP_NUM_ATRAC_IDS); if (s < 2) { atracLibVersion = 0; atracLibCrc = 0; @@ -562,18 +571,11 @@ void __AtracDoState(PointerWrap &p) { } } -void __AtracShutdown() { - for (size_t i = 0; i < ARRAY_SIZE(atracIDs); ++i) { - delete atracIDs[i]; - atracIDs[i] = NULL; - } -} - static Atrac *getAtrac(int atracID) { if (atracID < 0 || atracID >= PSP_NUM_ATRAC_IDS) { - return NULL; + return nullptr; } - Atrac *atrac = atracIDs[atracID]; + Atrac *atrac = atracContexts[atracID]; if (atrac && atrac->context_.IsValid()) { // Read in any changes from the game to the context. @@ -586,27 +588,24 @@ static Atrac *getAtrac(int atracID) { } static int createAtrac(Atrac *atrac) { - for (int i = 0; i < (int)ARRAY_SIZE(atracIDs); ++i) { - if (atracIDTypes[i] == atrac->codecType_ && atracIDs[i] == 0) { - atracIDs[i] = atrac; + for (int i = 0; i < (int)ARRAY_SIZE(atracContexts); ++i) { + if (atracContextTypes[i] == atrac->codecType_ && atracContexts[i] == 0) { + atracContexts[i] = atrac; atrac->atracID_ = i; return i; } } - return ATRAC_ERROR_NO_ATRACID; } static int deleteAtrac(int atracID) { if (atracID >= 0 && atracID < PSP_NUM_ATRAC_IDS) { - if (atracIDs[atracID] != nullptr) { - delete atracIDs[atracID]; - atracIDs[atracID] = nullptr; - + if (atracContexts[atracID] != nullptr) { + delete atracContexts[atracID]; + atracContexts[atracID] = nullptr; return 0; } } - return ATRAC_ERROR_BAD_ATRACID; } @@ -921,7 +920,7 @@ u32 _AtracAddStreamData(int atracID, u32 bufPtr, u32 bytesToAdd) { atrac->first_.fileoffset += addbytes; if (atrac->context_.IsValid()) { // refresh context_ - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); } return 0; } @@ -1042,7 +1041,7 @@ static u32 sceAtracAddStreamData(int atracID, u32 bytesToAdd) { if (atrac->bufferState_ == ATRAC_STATUS_HALFWAY_BUFFER) atrac->bufferState_ = ATRAC_STATUS_ALL_DATA_LOADED; if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); } } @@ -1078,7 +1077,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 *finish = 1; if (atrac->context_.IsValid()) { // refresh context_ - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); } return ATRAC_ERROR_ALL_DATA_DECODED; } @@ -1198,7 +1197,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 *remains = atrac->RemainingFrames(); if (atrac->context_.IsValid()) { // refresh context_ - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); } return 0; } @@ -1212,12 +1211,12 @@ static u32 sceAtracDecodeData(int atracID, u32 outAddr, u32 numSamplesAddr, u32 int ret = _AtracDecodeData(atracID, Memory::GetPointerWrite(outAddr), outAddr, &numSamples, &finish, &remains); if (ret != (int)ATRAC_ERROR_BAD_ATRACID && ret != (int)ATRAC_ERROR_NO_DATA) { if (Memory::IsValidAddress(numSamplesAddr)) - Memory::Write_U32(numSamples, numSamplesAddr); + Memory::WriteUnchecked_U32(numSamples, numSamplesAddr); if (Memory::IsValidAddress(finishFlagAddr)) - Memory::Write_U32(finish, finishFlagAddr); + Memory::WriteUnchecked_U32(finish, finishFlagAddr); // On error, no remaining frame value is written. if (ret == 0 && Memory::IsValidAddress(remainAddr)) - Memory::Write_U32(remains, remainAddr); + Memory::WriteUnchecked_U32(remains, remainAddr); } DEBUG_LOG(ME, "%08x=sceAtracDecodeData(%i, %08x, %08x[%08x], %08x[%08x], %08x[%d])", ret, atracID, outAddr, numSamplesAddr, numSamples, @@ -1636,7 +1635,7 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi } if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); } return hleDelayResult(hleLogSuccessInfoI(ME, 0), "reset play pos", 3000); } @@ -1793,7 +1792,7 @@ static u32 sceAtracSetData(int atracID, u32 buffer, u32 bufferSize) { return ret; } - if (atrac->codecType_ != atracIDTypes[atracID]) { + if (atrac->codecType_ != atracContextTypes[atracID]) { // TODO: Should this not change the buffer size? return hleReportError(ME, ATRAC_ERROR_WRONG_CODECTYPE, "atracID uses different codec type than data"); } @@ -1871,20 +1870,20 @@ static u32 sceAtracSetLoopNum(int atracID, int loopNum) { atrac->loopEndSample_ = atrac->endSample_ + atrac->firstSampleOffset_ + atrac->FirstOffsetExtra(); } if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); } return hleLogSuccessI(ME, 0); } static int sceAtracReinit(int at3Count, int at3plusCount) { for (int i = 0; i < PSP_NUM_ATRAC_IDS; ++i) { - if (atracIDs[i] != NULL) { + if (atracContexts[i] != nullptr) { ERROR_LOG_REPORT(ME, "sceAtracReinit(%d, %d): cannot reinit while IDs in use", at3Count, at3plusCount); return SCE_KERNEL_ERROR_BUSY; } } - memset(atracIDTypes, 0, sizeof(atracIDTypes)); + memset(atracContextTypes, 0, sizeof(atracContextTypes)); int next = 0; int space = PSP_NUM_ATRAC_IDS; @@ -1900,13 +1899,13 @@ static int sceAtracReinit(int at3Count, int at3plusCount) { for (int i = 0; i < at3plusCount; ++i) { space -= 2; if (space >= 0) { - atracIDTypes[next++] = PSP_MODE_AT_3_PLUS; + atracContextTypes[next++] = PSP_MODE_AT_3_PLUS; } } for (int i = 0; i < at3Count; ++i) { space -= 1; if (space >= 0) { - atracIDTypes[next++] = PSP_MODE_AT_3; + atracContextTypes[next++] = PSP_MODE_AT_3; } } @@ -1929,7 +1928,7 @@ static int sceAtracGetOutputChannel(int atracID, u32 outputChanPtr) { return err; } if (Memory::IsValidAddress(outputChanPtr)) { - Memory::Write_U32(atrac->outputChannels_, outputChanPtr); + Memory::WriteUnchecked_U32(atrac->outputChannels_, outputChanPtr); return hleLogSuccessI(ME, 0); } else { return hleLogError(ME, 0, "invalid address"); @@ -2065,13 +2064,15 @@ static int sceAtracSetAA3DataAndGetID(u32 buffer, u32 bufferSize, u32 fileSize, return _AtracSetData(atracID, buffer, bufferSize, bufferSize, true); } +// Used by SasAudio's AT3 integration. int _AtracGetIDByContext(u32 contextAddr) { int atracID = (int)Memory::Read_U32(contextAddr + 0xfc); return atracID; } -void _AtracGenerateContext(Atrac *atrac) { - SceAtracId *context = atrac->context_; +void _AtracWriteContextToPSPMem(Atrac *atrac) { + // context points into PSP memory. + SceAtracContext *context = atrac->context_; context->info.buffer = atrac->first_.addr; context->info.bufferByte = atrac->bufferMaxSize_; context->info.secondBuffer = atrac->second_.addr; @@ -2102,7 +2103,7 @@ void _AtracGenerateContext(Atrac *atrac) { u8 *buf = (u8 *)context; *(u32_le *)(buf + 0xfc) = atrac->atracID_; - NotifyMemInfo(MemBlockFlags::WRITE, atrac->context_.ptr, sizeof(SceAtracId), "AtracContext"); + NotifyMemInfo(MemBlockFlags::WRITE, atrac->context_.ptr, sizeof(SceAtracContext), "AtracContext"); } static u32 _sceAtracGetContextAddress(int atracID) { @@ -2113,17 +2114,17 @@ static u32 _sceAtracGetContextAddress(int atracID) { } if (!atrac->context_.IsValid()) { // allocate a new context_ - u32 contextsize = 256; - atrac->context_ = kernelMemory.Alloc(contextsize, false, StringFromFormat("AtracCtx/%d", atracID).c_str()); + u32 contextSize = sizeof(SceAtracContext); + // Note that Alloc can increase contextSize to the "grain" size. + atrac->context_ = kernelMemory.Alloc(contextSize, false, StringFromFormat("AtracCtx/%d", atracID).c_str()); if (atrac->context_.IsValid()) - Memory::Memset(atrac->context_.ptr, 0, 256, "AtracContextClear"); - + Memory::Memset(atrac->context_.ptr, 0, contextSize, "AtracContextClear"); WARN_LOG(ME, "%08x=_sceAtracGetContextAddress(%i): allocated new context", atrac->context_.ptr, atracID); } else WARN_LOG(ME, "%08x=_sceAtracGetContextAddress(%i)", atrac->context_.ptr, atracID); if (atrac->context_.IsValid()) - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); return atrac->context_.ptr; } @@ -2147,27 +2148,6 @@ static const At3HeaderMap at3HeaderMap[] = { { 0x00C0, 2, 1 }, // 66 kbps stereo }; -static bool initAT3Decoder(Atrac *atrac) { - atrac->bitrate_ = (atrac->bytesPerFrame_ * 352800) / 1000; - atrac->bitrate_ = (atrac->bitrate_ + 511) >> 10; - atrac->jointStereo_ = false; - - // See if we can match the actual jointStereo value. - for (size_t i = 0; i < ARRAY_SIZE(at3HeaderMap); ++i) { - if (at3HeaderMap[i].Matches(atrac)) { - atrac->jointStereo_ = at3HeaderMap[i].jointStereo; - return true; - } - } - return false; -} - -static void initAT3plusDecoder(Atrac *atrac) { - atrac->bitrate_ = (atrac->bytesPerFrame_ * 352800) / 1000; - atrac->bitrate_ = ((atrac->bitrate_ >> 11) + 8) & 0xFFFFFFF0; - atrac->jointStereo_ = false; -} - static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { Atrac *atrac = getAtrac(atracID); if (!atrac) { @@ -2195,12 +2175,26 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { const char *channelName = atrac->channels_ == 1 ? "mono" : "stereo"; if (atrac->codecType_ == PSP_MODE_AT_3) { - if (!initAT3Decoder(atrac)) { + atrac->bitrate_ = (atrac->bytesPerFrame_ * 352800) / 1000; + atrac->bitrate_ = (atrac->bitrate_ + 511) >> 10; + atrac->jointStereo_ = false; + + // See if we can match the actual jointStereo value. + bool found = false; + for (size_t i = 0; i < ARRAY_SIZE(at3HeaderMap); ++i) { + if (at3HeaderMap[i].Matches(atrac)) { + atrac->jointStereo_ = at3HeaderMap[i].jointStereo; + found = true; + } + } + if (!found) { ERROR_LOG_REPORT(ME, "AT3 header map lacks entry for bpf: %i channels: %i", atrac->bytesPerFrame_, atrac->channels_); // TODO: Should we return an error code for these values? } } else if (atrac->codecType_ == PSP_MODE_AT_3_PLUS) { - initAT3plusDecoder(atrac); + atrac->bitrate_ = (atrac->bytesPerFrame_ * 352800) / 1000; + atrac->bitrate_ = ((atrac->bitrate_ >> 11) + 8) & 0xFFFFFFF0; + atrac->jointStereo_ = false; } atrac->dataOff_ = 0; @@ -2211,7 +2205,7 @@ static int sceAtracLowLevelInitDecoder(int atracID, u32 paramsAddr) { int ret = __AtracSetContext(atrac); if (atrac->context_.IsValid()) { - _AtracGenerateContext(atrac); + _AtracWriteContextToPSPMem(atrac); } if (ret < 0) { diff --git a/Core/HLE/sceAtrac.h b/Core/HLE/sceAtrac.h index cc2c14e943..344f8c26f4 100644 --- a/Core/HLE/sceAtrac.h +++ b/Core/HLE/sceAtrac.h @@ -77,7 +77,7 @@ struct SceAtracIdInfo { u8 unk[56]; }; -struct SceAtracId { +struct SceAtracContext { // size 128 SceAudiocodecCodec codec; // size 128 diff --git a/Core/HW/Atrac3Standalone.cpp b/Core/HW/Atrac3Standalone.cpp index 2b2ec92f3c..b109effd44 100644 --- a/Core/HW/Atrac3Standalone.cpp +++ b/Core/HW/Atrac3Standalone.cpp @@ -46,7 +46,7 @@ public: return codecOpen_; } - void FlushBuffers() { + void FlushBuffers() override { if (at3Ctx_) { atrac3_flush_buffers(at3Ctx_); } diff --git a/Core/HW/SimpleAudioDec.cpp b/Core/HW/SimpleAudioDec.cpp index a6555b8095..abf7722d1d 100644 --- a/Core/HW/SimpleAudioDec.cpp +++ b/Core/HW/SimpleAudioDec.cpp @@ -55,7 +55,9 @@ extern "C" { // AAC decoder candidates: // * https://github.com/mstorsjo/fdk-aac/tree/master - +// h.264 decoder candidates: +// * https://github.com/meerkat-cv/h264_decoder +// * https://github.com/shengbinmeng/ffmpeg-h264-dec // minimp3-based decoder. class MiniMp3Audio : public AudioDecoder { @@ -93,10 +95,11 @@ private: }; // FFMPEG-based decoder. TODO: Replace with individual codecs. -class SimpleAudio : public AudioDecoder { +// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13 +class FFmpegAudioDecoder : public AudioDecoder { public: - SimpleAudio(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2); - ~SimpleAudio(); + FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz = 44100, int channels = 2); + ~FFmpegAudioDecoder(); bool Decode(const uint8_t* inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) override; bool IsOK() const override { @@ -142,7 +145,7 @@ AudioDecoder *CreateAudioDecoder(PSPAudioType audioType, int sampleRateHz, int c return CreateAtrac3PlusAudio(channels, blockAlign); default: // Only AAC falls back to FFMPEG now. - return new SimpleAudio(audioType, sampleRateHz, channels); + return new FFmpegAudioDecoder(audioType, sampleRateHz, channels); } } @@ -165,7 +168,7 @@ static int GetAudioCodecID(int audioType) { #endif // USE_FFMPEG } -SimpleAudio::SimpleAudio(PSPAudioType audioType, int sampleRateHz, int channels) +FFmpegAudioDecoder::FFmpegAudioDecoder(PSPAudioType audioType, int sampleRateHz, int channels) : audioType(audioType), sample_rate_(sampleRateHz), channels_(channels) { #ifdef USE_FFMPEG @@ -205,7 +208,7 @@ SimpleAudio::SimpleAudio(PSPAudioType audioType, int sampleRateHz, int channels) #endif // USE_FFMPEG } -bool SimpleAudio::OpenCodec(int block_align) { +bool FFmpegAudioDecoder::OpenCodec(int block_align) { #ifdef USE_FFMPEG // Some versions of FFmpeg require this set. May be set in SetExtraData(), but optional. // When decoding, we decode by packet, so we know the size. @@ -226,7 +229,7 @@ bool SimpleAudio::OpenCodec(int block_align) { #endif // USE_FFMPEG } -void SimpleAudio::SetChannels(int channels) { +void FFmpegAudioDecoder::SetChannels(int channels) { if (channels_ == channels) { // Do nothing, already set. return; @@ -243,7 +246,7 @@ void SimpleAudio::SetChannels(int channels) { #endif } -SimpleAudio::~SimpleAudio() { +FFmpegAudioDecoder::~FFmpegAudioDecoder() { #ifdef USE_FFMPEG swr_free(&swrCtx_); av_frame_free(&frame_); @@ -261,7 +264,7 @@ SimpleAudio::~SimpleAudio() { } // Decodes a single input frame. -bool SimpleAudio::Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) { +bool FFmpegAudioDecoder::Decode(const uint8_t *inbuf, int inbytes, int *inbytesConsumed, uint8_t *outbuf, int *outbytes) { #ifdef USE_FFMPEG if (!codecOpen_) { OpenCodec(inbytes); @@ -368,7 +371,7 @@ void AudioClose(AudioDecoder **ctx) { #endif // USE_FFMPEG } -void AudioClose(SimpleAudio **ctx) { +void AudioClose(FFmpegAudioDecoder **ctx) { #ifdef USE_FFMPEG delete *ctx; *ctx = 0; @@ -408,10 +411,6 @@ AuCtx::~AuCtx() { } size_t AuCtx::FindNextMp3Sync() { - if (decoder->GetAudioType() != PSP_CODEC_MP3) { - return 0; - } - for (size_t i = 0; i < sourcebuff.size() - 2; ++i) { if ((sourcebuff[i] & 0xFF) == 0xFF && (sourcebuff[i + 1] & 0xC0) == 0xC0) { return i; @@ -432,7 +431,10 @@ u32 AuCtx::AuDecode(u32 pcmAddr) { // Decode a single frame in sourcebuff and output into PCMBuf. if (!sourcebuff.empty()) { // FFmpeg doesn't seem to search for a sync for us, so let's do that. - int nextSync = (int)FindNextMp3Sync(); + int nextSync = 0; + if (decoder->GetAudioType() == PSP_CODEC_MP3) { + nextSync = (int)FindNextMp3Sync(); + } int inbytesConsumed = 0; decoder->Decode(&sourcebuff[nextSync], (int)sourcebuff.size() - nextSync, &inbytesConsumed, outbuf, &outpcmbufsize); @@ -546,18 +548,18 @@ u32 AuCtx::AuGetInfoToAddStreamData(u32 bufPtr, u32 sizePtr, u32 srcPosPtr) { // we can recharge AuBuf from its beginning if (readsize != 0) { if (Memory::IsValidAddress(bufPtr)) - Memory::Write_U32(AuBuf + offset, bufPtr); + Memory::WriteUnchecked_U32(AuBuf + offset, bufPtr); if (Memory::IsValidAddress(sizePtr)) - Memory::Write_U32(readsize, sizePtr); + Memory::WriteUnchecked_U32(readsize, sizePtr); if (Memory::IsValidAddress(srcPosPtr)) - Memory::Write_U32(readPos, srcPosPtr); + Memory::WriteUnchecked_U32(readPos, srcPosPtr); } else { if (Memory::IsValidAddress(bufPtr)) - Memory::Write_U32(0, bufPtr); + Memory::WriteUnchecked_U32(0, bufPtr); if (Memory::IsValidAddress(sizePtr)) - Memory::Write_U32(0, sizePtr); + Memory::WriteUnchecked_U32(0, sizePtr); if (Memory::IsValidAddress(srcPosPtr)) - Memory::Write_U32(0, srcPosPtr); + Memory::WriteUnchecked_U32(0, srcPosPtr); } // Just for old save states. diff --git a/Core/HW/SimpleAudioDec.h b/Core/HW/SimpleAudioDec.h index d000850133..904b8f927f 100644 --- a/Core/HW/SimpleAudioDec.h +++ b/Core/HW/SimpleAudioDec.h @@ -20,11 +20,8 @@ #include "Core/HW/MediaEngine.h" #include "Core/HLE/sceAudio.h" -// Wraps FFMPEG for audio decoding in a nice interface. // Decodes packet by packet - does NOT demux. -// Based on http://ffmpeg.org/doxygen/trunk/doc_2examples_2decoding_encoding_8c-example.html#_a13 - // audioType enum PSPAudioType { PSP_CODEC_AT3PLUS = 0x00001000,