mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-18 00:40:30 +02:00
Merge pull request #19054 from hrydgard/more-audio-dec-cleanup
More audio decoding cleanup, some optimization
This commit is contained in:
12 files changed
+213
-148
No files matched your search
@@ -29,6 +29,10 @@ charset = utf-8-bom
|
||||
[Windows/{aboutbox.rc,version.rc}]
|
||||
charset = utf-8
|
||||
|
||||
[ext/at3_standalone/**.{cpp,h}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[libretro/**.{cpp,h}]
|
||||
indent_style = space
|
||||
indent_size = 3
|
||||
|
||||
+75
-81
@@ -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<SceAtracId> context_;
|
||||
PSPPointer<SceAtracContext> 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) {
|
||||
|
||||
+1
-1
@@ -77,7 +77,7 @@ struct SceAtracIdInfo {
|
||||
u8 unk[56];
|
||||
};
|
||||
|
||||
struct SceAtracId {
|
||||
struct SceAtracContext {
|
||||
// size 128
|
||||
SceAudiocodecCodec codec;
|
||||
// size 128
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
return codecOpen_;
|
||||
}
|
||||
|
||||
void FlushBuffers() {
|
||||
void FlushBuffers() override {
|
||||
if (at3Ctx_) {
|
||||
atrac3_flush_buffers(at3Ctx_);
|
||||
}
|
||||
|
||||
+24
-22
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Notes
|
||||
//
|
||||
// Performance-wise, these are OK.
|
||||
// For Atrac3+, the bottleneck is two functions: decode_qu_spectra and ff_atrac3p_ipqf. At least the latter is quite SIMD-able.
|
||||
|
||||
// The full external API for the standalone Atrac3/3+ decoder.
|
||||
|
||||
struct ATRAC3Context;
|
||||
|
||||
@@ -140,7 +140,7 @@ static void imlt(ATRAC3Context *q, float *input, float *output, int odd_band)
|
||||
FFSWAP(float, input[i], input[255 - i]);
|
||||
}
|
||||
|
||||
q->mdct_ctx.imdct_calc(&q->mdct_ctx, output, input);
|
||||
imdct_calc(&q->mdct_ctx, output, input);
|
||||
|
||||
/* Perform windowing on the output. */
|
||||
vector_fmul(output, output, mdct_window, MDCT_SIZE);
|
||||
|
||||
@@ -25,6 +25,22 @@
|
||||
* DSP functions for ATRAC3+ decoder.
|
||||
*/
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
|
||||
|
||||
#include <emmintrin.h>
|
||||
|
||||
#elif PPSSPP_ARCH(ARM_NEON)
|
||||
|
||||
#if defined(_MSC_VER) && PPSSPP_ARCH(ARM64)
|
||||
#include <arm64_neon.h>
|
||||
#else
|
||||
#include <arm_neon.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -466,7 +482,7 @@ void ff_atrac3p_imdct(FFTContext *mdct_ctx, float *pIn,
|
||||
for (i = 0; i < ATRAC3P_SUBBAND_SAMPLES / 2; i++)
|
||||
FFSWAP(float, pIn[i], pIn[ATRAC3P_SUBBAND_SAMPLES - 1 - i]);
|
||||
|
||||
mdct_ctx->imdct_calc(mdct_ctx, pOut, pIn);
|
||||
imdct_calc(mdct_ctx, pOut, pIn);
|
||||
|
||||
/* Perform windowing on the output.
|
||||
* ATRAC3+ uses two different MDCT windows:
|
||||
@@ -612,24 +628,72 @@ void ff_atrac3p_ipqf(FFTContext *dct_ctx, Atrac3pIPQFChannelCtx *hist,
|
||||
idct_in[sb] = in[sb * ATRAC3P_SUBBAND_SAMPLES + s];
|
||||
|
||||
/* Calculate the sine and cosine part of the PQF using IDCT-IV */
|
||||
dct_ctx->imdct_half(dct_ctx, idct_out, idct_in);
|
||||
imdct_half(dct_ctx, idct_out, idct_in);
|
||||
|
||||
/* append the result to the history */
|
||||
const int hist_pos = hist->pos;
|
||||
for (i = 0; i < 8; i++) {
|
||||
hist->buf1[hist->pos][i] = idct_out[i + 8];
|
||||
hist->buf2[hist->pos][i] = idct_out[7 - i];
|
||||
hist->buf1[hist_pos][i] = idct_out[i + 8];
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
hist->buf2[hist_pos][i] = idct_out[7 - i];
|
||||
}
|
||||
|
||||
pos_now = hist->pos;
|
||||
pos_next = mod23_lut[pos_now + 2]; // pos_next = (pos_now + 1) % 23;
|
||||
|
||||
for (t = 0; t < ATRAC3P_PQF_FIR_LEN; t++) {
|
||||
const float *buf1 = hist->buf1[pos_now];
|
||||
const float *buf2 = hist->buf2[pos_next];
|
||||
const float *coeffs1 = ipqf_coeffs1[t];
|
||||
const float *coeffs2 = ipqf_coeffs2[t];
|
||||
|
||||
float *outp = out + s * 16;
|
||||
#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64)
|
||||
auto _mm_reverse = [](__m128 x) -> __m128 {
|
||||
return _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3));
|
||||
};
|
||||
_mm_storeu_ps(outp, _mm_add_ps(_mm_loadu_ps(outp), _mm_add_ps(
|
||||
_mm_mul_ps(_mm_loadu_ps(buf1), _mm_loadu_ps(coeffs1)),
|
||||
_mm_mul_ps(_mm_loadu_ps(buf2), _mm_loadu_ps(coeffs2)))));
|
||||
_mm_storeu_ps(outp + 4, _mm_add_ps(_mm_loadu_ps(outp + 4), _mm_add_ps(
|
||||
_mm_mul_ps(_mm_loadu_ps(buf1 + 4), _mm_loadu_ps(coeffs1 + 4)),
|
||||
_mm_mul_ps(_mm_loadu_ps(buf2 + 4), _mm_loadu_ps(coeffs2 + 4)))));
|
||||
|
||||
_mm_storeu_ps(outp + 8, _mm_add_ps(_mm_loadu_ps(outp + 8), _mm_add_ps(
|
||||
_mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf1 + 4)), _mm_loadu_ps(coeffs1 + 8)),
|
||||
_mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf2 + 4)), _mm_loadu_ps(coeffs2 + 8)))));
|
||||
_mm_storeu_ps(outp + 12, _mm_add_ps(_mm_loadu_ps(outp + 12), _mm_add_ps(
|
||||
_mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf1)), _mm_loadu_ps(coeffs1 + 12)),
|
||||
_mm_mul_ps(_mm_reverse(_mm_loadu_ps(buf2)), _mm_loadu_ps(coeffs2 + 12)))));
|
||||
#elif PPSSPP_ARCH(ARM_NEON)
|
||||
auto vreverseq_f32 = [](float32x4_t x) -> float32x4_t {
|
||||
float32x4_t rev = vrev64q_f32(x);
|
||||
float32x2_t high = vget_high_f32(rev); //{4,3}
|
||||
float32x2_t low = vget_low_f32(rev); //{1,2}
|
||||
return vcombine_f32(high, low); //{4,3,2,1}
|
||||
};
|
||||
vst1q_f32(outp, vaddq_f32(vld1q_f32(outp), vaddq_f32(
|
||||
vmulq_f32(vld1q_f32(buf1), vld1q_f32(coeffs1)),
|
||||
vmulq_f32(vld1q_f32(buf2), vld1q_f32(coeffs2)))));
|
||||
vst1q_f32(outp + 4, vaddq_f32(vld1q_f32(outp + 4), vaddq_f32(
|
||||
vmulq_f32(vld1q_f32(buf1 + 4), vld1q_f32(coeffs1 + 4)),
|
||||
vmulq_f32(vld1q_f32(buf2 + 4), vld1q_f32(coeffs2 + 4)))));
|
||||
|
||||
vst1q_f32(outp + 8, vaddq_f32(vld1q_f32(outp + 8), vaddq_f32(
|
||||
vmulq_f32(vreverseq_f32(vld1q_f32(buf1 + 4)), vld1q_f32(coeffs1 + 8)),
|
||||
vmulq_f32(vreverseq_f32(vld1q_f32(buf2 + 4)), vld1q_f32(coeffs2 + 8)))));
|
||||
vst1q_f32(outp + 12, vaddq_f32(vld1q_f32(outp + 12), vaddq_f32(
|
||||
vmulq_f32(vreverseq_f32(vld1q_f32(buf1)), vld1q_f32(coeffs1 + 12)),
|
||||
vmulq_f32(vreverseq_f32(vld1q_f32(buf2)), vld1q_f32(coeffs2 + 12)))));
|
||||
#else
|
||||
for (i = 0; i < 8; i++) {
|
||||
out[s * 16 + i + 0] += hist->buf1[pos_now][i] * ipqf_coeffs1[t][i] +
|
||||
hist->buf2[pos_next][i] * ipqf_coeffs2[t][i];
|
||||
out[s * 16 + i + 8] += hist->buf1[pos_now][7 - i] * ipqf_coeffs1[t][i + 8] +
|
||||
hist->buf2[pos_next][7 - i] * ipqf_coeffs2[t][i + 8];
|
||||
outp[i] += buf1[i] * coeffs1[i] + buf2[i] * coeffs2[i];
|
||||
}
|
||||
for (i = 0; i < 8; i++) {
|
||||
outp[i + 8] += buf1[7 - i] * coeffs1[i + 8] + buf2[7 - i] * coeffs2[i + 8];
|
||||
}
|
||||
#endif
|
||||
|
||||
pos_now = mod23_lut[pos_next + 2]; // pos_now = (pos_now + 2) % 23;
|
||||
pos_next = mod23_lut[pos_now + 2]; // pos_next = (pos_next + 2) % 23;
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#define AV_HAVE_FAST_UNALIGNED 0
|
||||
#define AV_INPUT_BUFFER_PADDING_SIZE 32
|
||||
|
||||
// TODO: This should work but doesn't??
|
||||
// #define BITSTREAM_READER_LE
|
||||
|
||||
#define LOCAL_ALIGNED(bits, type, name, subscript) type name subscript
|
||||
#define av_restrict
|
||||
#define av_alias
|
||||
|
||||
+13
-19
@@ -35,9 +35,9 @@
|
||||
|
||||
#define sqrthalf (float)M_SQRT1_2
|
||||
|
||||
void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void ff_mdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
|
||||
/* cos(2*pi*x/n) for 0<=x<=n/4, followed by its reverse */
|
||||
COSTABLE(16);
|
||||
@@ -71,8 +71,8 @@ static FFTSample * const av_cos_tabs[] = {
|
||||
av_cos_65536,
|
||||
};
|
||||
|
||||
static void fft_permute_c(FFTContext *s, FFTComplex *z);
|
||||
static void fft_calc_c(FFTContext *s, FFTComplex *z);
|
||||
void fft_permute(FFTContext *s, FFTComplex *z);
|
||||
void fft_calc(FFTContext *s, FFTComplex *z);
|
||||
|
||||
static int split_radix_permutation(int i, int n, int inverse)
|
||||
{
|
||||
@@ -130,11 +130,6 @@ int ff_fft_init(FFTContext *s, int nbits, int inverse)
|
||||
goto fail;
|
||||
s->inverse = inverse;
|
||||
|
||||
s->fft_permute = fft_permute_c;
|
||||
s->fft_calc = fft_calc_c;
|
||||
s->imdct_calc = ff_imdct_calc_c;
|
||||
s->imdct_half = ff_imdct_half_c;
|
||||
s->mdct_calc = ff_mdct_calc_c;
|
||||
for(j=4; j<=nbits; j++) {
|
||||
ff_init_ff_cos_tabs(j);
|
||||
}
|
||||
@@ -152,7 +147,7 @@ int ff_fft_init(FFTContext *s, int nbits, int inverse)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void fft_permute_c(FFTContext *s, FFTComplex *z)
|
||||
void fft_permute(FFTContext *s, FFTComplex *z)
|
||||
{
|
||||
int j, np;
|
||||
const uint16_t *revtab = s->revtab;
|
||||
@@ -315,12 +310,11 @@ static void (* const fft_dispatch[])(FFTComplex*) = {
|
||||
fft2048, fft4096, fft8192, fft16384, fft32768, fft65536,
|
||||
};
|
||||
|
||||
static void fft_calc_c(FFTContext *s, FFTComplex *z)
|
||||
void fft_calc(FFTContext *s, FFTComplex *z)
|
||||
{
|
||||
fft_dispatch[s->nbits-2](z);
|
||||
}
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -383,7 +377,7 @@ fail:
|
||||
* @param output N/2 samples
|
||||
* @param input N/2 samples
|
||||
*/
|
||||
void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
|
||||
void imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input)
|
||||
{
|
||||
int k, n8, n4, n2, n, j;
|
||||
const uint16_t *revtab = s->revtab;
|
||||
@@ -406,7 +400,7 @@ void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
|
||||
in1 += 2;
|
||||
in2 -= 2;
|
||||
}
|
||||
s->fft_calc(s, z);
|
||||
fft_calc(s, z);
|
||||
|
||||
/* post rotation + reordering */
|
||||
for (k = 0; k < n8; k++) {
|
||||
@@ -425,14 +419,14 @@ void ff_imdct_half_c(FFTContext *s, FFTSample *output, const FFTSample *input)
|
||||
* @param output N samples
|
||||
* @param input N/2 samples
|
||||
*/
|
||||
void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input)
|
||||
void imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input)
|
||||
{
|
||||
int k;
|
||||
int n = 1 << s->mdct_bits;
|
||||
int n2 = n >> 1;
|
||||
int n4 = n >> 2;
|
||||
|
||||
ff_imdct_half_c(s, output + n4, input);
|
||||
imdct_half(s, output + n4, input);
|
||||
|
||||
for (k = 0; k < n4; k++) {
|
||||
output[k] = -output[n2 - k - 1];
|
||||
@@ -445,7 +439,7 @@ void ff_imdct_calc_c(FFTContext *s, FFTSample *output, const FFTSample *input)
|
||||
* @param input N samples
|
||||
* @param out N/2 samples
|
||||
*/
|
||||
void ff_mdct_calc_c(FFTContext *s, FFTSample *out, const FFTSample *input)
|
||||
void mdct_calc(FFTContext *s, FFTSample *out, const FFTSample *input)
|
||||
{
|
||||
int i, j, n, n8, n4, n2, n3;
|
||||
FFTDouble re, im;
|
||||
@@ -473,7 +467,7 @@ void ff_mdct_calc_c(FFTContext *s, FFTSample *out, const FFTSample *input)
|
||||
CMUL(x[j].re, x[j].im, re, im, -tcos[n8 + i], tsin[n8 + i]);
|
||||
}
|
||||
|
||||
s->fft_calc(s, x);
|
||||
fft_calc(s, x);
|
||||
|
||||
/* post rotation */
|
||||
for (i = 0; i < n8; i++) {
|
||||
|
||||
+14
-12
@@ -57,21 +57,23 @@ struct FFTContext {
|
||||
/* pre/post rotation tables */
|
||||
FFTSample *tcos;
|
||||
FFTSample *tsin;
|
||||
/**
|
||||
* Do the permutation needed BEFORE calling fft_calc().
|
||||
*/
|
||||
void (*fft_permute)(struct FFTContext *s, FFTComplex *z);
|
||||
/**
|
||||
* Do a complex FFT with the parameters defined in ff_fft_init(). The
|
||||
* input data must be permuted before. No 1.0/sqrt(n) normalization is done.
|
||||
*/
|
||||
void (*fft_calc)(struct FFTContext *s, FFTComplex *z);
|
||||
void (*imdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void (*imdct_half)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void (*mdct_calc)(struct FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
|
||||
enum mdct_permutation_type mdct_permutation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Do the permutation needed BEFORE calling fft_calc().
|
||||
*/
|
||||
void fft_permute(struct FFTContext *s, FFTComplex *z);
|
||||
/**
|
||||
* Do a complex FFT with the parameters defined in ff_fft_init(). The
|
||||
* input data must be permuted before. No 1.0/sqrt(n) normalization is done.
|
||||
*/
|
||||
void fft_calc(struct FFTContext *s, FFTComplex *z);
|
||||
void imdct_calc(struct FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void imdct_half(struct FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
void mdct_calc(struct FFTContext *s, FFTSample *output, const FFTSample *input);
|
||||
|
||||
#define COSTABLE(size) \
|
||||
DECLARE_ALIGNED(32, FFTSample, av_cos_##size)[size/2]
|
||||
|
||||
|
||||
Reference in new issue
Block a user