Atrac: Match PSP on reset of streaming data.

This attempts to match the sizes and positions requested by the PSP
firmware APIs.  The two functions have to match: if they don't, it will
start reading incorrect data.
This commit is contained in:
Unknown W. Brackets 2015-11-05 22:26:52 -08:00
parent 4511407506
commit 696cb6649e

View File

@ -59,6 +59,8 @@
#define ATRAC_ERROR_SECOND_BUFFER_NEEDED 0x80630012
#define ATRAC_ERROR_INCORRECT_READ_SIZE 0x80630013
#define ATRAC_ERROR_BAD_SAMPLE 0x80630015
#define ATRAC_ERROR_BAD_FIRST_RESET_SIZE 0x80630016
#define ATRAC_ERROR_BAD_SECOND_RESET_SIZE 0x80630017
#define ATRAC_ERROR_ADD_DATA_IS_TOO_BIG 0x80630018
#define ATRAC_ERROR_NOT_MONO 0x80630019
#define ATRAC_ERROR_NO_LOOP_INFORMATION 0x80630021
@ -1086,6 +1088,57 @@ static u32 sceAtracEndEntry() {
return 0;
}
static void AtracGetResetBufferInfo(Atrac *atrac, AtracResetBufferInfo *bufferInfo, int sample) {
if (atrac->bufferState == ATRAC_STATUS_ALL_DATA_LOADED) {
bufferInfo->first.writePosPtr = atrac->first.addr;
// Everything is loaded, so nothing needs to be read.
bufferInfo->first.writableBytes = 0;
bufferInfo->first.minWriteBytes = 0;
bufferInfo->first.filePos = 0;
} else if (atrac->bufferState == ATRAC_STATUS_HALFWAY_BUFFER) {
// Here the message is: you need to read at least this many bytes to get to that position.
// This is because we're filling the buffer start to finish, not streaming.
bufferInfo->first.writePosPtr = atrac->first.addr + atrac->first.size;
bufferInfo->first.writableBytes = atrac->first.filesize - atrac->first.size;
int minWriteBytes = atrac->getFileOffsetBySample(sample) - atrac->first.size;
if (minWriteBytes > 0) {
bufferInfo->first.minWriteBytes = minWriteBytes;
} else {
bufferInfo->first.minWriteBytes = 0;
}
bufferInfo->first.filePos = atrac->first.size;
atrac->first.writableBytes = bufferInfo->first.writableBytes;
} else {
// This is without the sample offset. The file offset also includes the previous batch of samples?
const int atracSamplesPerFrame = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
int sampleFileOffset = atrac->getFileOffsetBySample(sample - atrac->firstSampleoffset - atracSamplesPerFrame);
// Update the writable bytes. When streaming, this is just the number of bytes until the end.
const u32 bufSizeAligned = (atrac->atracBufSize / atrac->atracBytesPerFrame) * atrac->atracBytesPerFrame;
const int needsMoreFrames = atrac->codecType == PSP_CODEC_AT3PLUS ? 368 : 69;
bufferInfo->first.writePosPtr = atrac->first.addr;
bufferInfo->first.writableBytes = std::min(atrac->first.filesize - sampleFileOffset, bufSizeAligned);
if (((sample + atrac->firstSampleoffset) % atracSamplesPerFrame) > needsMoreFrames) {
// Not clear why, but it seems it wants a bit extra in case the sample is late?
bufferInfo->first.minWriteBytes = atrac->atracBytesPerFrame * 3;
if ((u32)sample < (u32)atrac->firstSampleoffset) {
sampleFileOffset -= atrac->atracBytesPerFrame;
}
} else {
bufferInfo->first.minWriteBytes = atrac->atracBytesPerFrame * 2;
}
bufferInfo->first.filePos = sampleFileOffset;
}
// It seems like this is always the same as the first buffer's pos, weirdly.
bufferInfo->second.writePosPtr = atrac->first.addr;
bufferInfo->second.writableBytes = atrac->second.writableBytes;
bufferInfo->second.minWriteBytes = atrac->second.neededBytes;
bufferInfo->second.filePos = atrac->second.fileoffset;
}
static u32 sceAtracGetBufferInfoForResetting(int atracID, int sample, u32 bufferInfoAddr) {
auto bufferInfo = PSPPointer<AtracResetBufferInfo>::Create(bufferInfoAddr);
@ -1099,32 +1152,9 @@ static u32 sceAtracGetBufferInfoForResetting(int atracID, int sample, u32 buffer
} else if ((u32)sample + atrac->firstSampleoffset > (u32)atrac->endSample + atrac->firstSampleoffset) {
return hleLogWarning(ME, ATRAC_ERROR_BAD_SAMPLE, "invalid sample position");
} else {
int Sampleoffset = atrac->getFileOffsetBySample(sample);
int minWritebytes = std::max(Sampleoffset - (int)atrac->first.size, 0);
// Reset temp buf for adding more stream data and set full filled buffer
atrac->first.writableBytes = std::min(atrac->first.filesize - atrac->first.size, atrac->atracBufSize);
atrac->first.offset = 0;
// minWritebytes should not be bigger than writeablebytes
minWritebytes = std::min(minWritebytes, (int)atrac->first.writableBytes);
AtracGetResetBufferInfo(atrac, bufferInfo, sample);
// If we've already loaded everything, the answer is 0.
if (atrac->first.size >= atrac->first.filesize) {
Sampleoffset = 0;
}
bufferInfo->first.writePosPtr = atrac->first.addr;
bufferInfo->first.writableBytes = atrac->first.writableBytes;
bufferInfo->first.minWriteBytes = minWritebytes;
bufferInfo->first.filePos = Sampleoffset;
// TODO: It seems like this is always the same as the first buffer's pos?
bufferInfo->second.writePosPtr = atrac->first.addr;
bufferInfo->second.writableBytes = atrac->second.writableBytes;
bufferInfo->second.minWriteBytes = atrac->second.neededBytes;
bufferInfo->second.filePos = atrac->second.fileoffset;
INFO_LOG(ME, "0=sceAtracGetBufferInfoForResetting(%i, %i, %08x)",atracID, sample, bufferInfoAddr);
return 0;
return hleLogSuccessInfoI(ME, 0);
}
}
@ -1416,10 +1446,52 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi
} else if ((u32)sample + atrac->firstSampleoffset > (u32)atrac->endSample + atrac->firstSampleoffset) {
return hleLogWarning(ME, ATRAC_ERROR_BAD_SAMPLE, "invalid sample position");
} else {
INFO_LOG(ME, "sceAtracResetPlayPosition(%i, %i, %i, %i)", atracID, sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf);
if (bytesWrittenFirstBuf > 0) {
atrac->first.fileoffset = atrac->getFileOffsetBySample(sample);
sceAtracAddStreamData(atracID, bytesWrittenFirstBuf);
// Reuse the same calculation as before.
AtracResetBufferInfo bufferInfo;
AtracGetResetBufferInfo(atrac, &bufferInfo, sample);
if ((u32)bytesWrittenFirstBuf < bufferInfo.first.minWriteBytes || (u32)bytesWrittenFirstBuf > bufferInfo.first.writableBytes) {
return hleLogError(ME, ATRAC_ERROR_BAD_FIRST_RESET_SIZE, "first byte count not in valid range");
}
if ((u32)bytesWrittenSecondBuf < bufferInfo.second.minWriteBytes || (u32)bytesWrittenSecondBuf > bufferInfo.second.writableBytes) {
return hleLogError(ME, ATRAC_ERROR_BAD_SECOND_RESET_SIZE, "second byte count not in valid range");
}
if (atrac->bufferState == ATRAC_STATUS_ALL_DATA_LOADED) {
// Always adds zero bytes.
} else if (atrac->bufferState == ATRAC_STATUS_HALFWAY_BUFFER) {
// Okay, it's a valid number of bytes. Let's set them up.
if (bytesWrittenFirstBuf != 0) {
// TODO: We should just use the buffer in PSP RAM.
Memory::Memcpy(atrac->data_buf + atrac->first.size, atrac->first.addr + atrac->first.size, bytesWrittenFirstBuf);
atrac->first.fileoffset += bytesWrittenFirstBuf;
atrac->first.size += bytesWrittenFirstBuf;
atrac->first.writableBytes -= bytesWrittenFirstBuf;
atrac->first.offset += bytesWrittenFirstBuf;
}
// Did we transition to a full buffer?
if (atrac->first.size >= atrac->first.filesize) {
atrac->first.size = atrac->first.filesize;
if (atrac->bufferState == ATRAC_STATUS_HALFWAY_BUFFER)
atrac->bufferState = ATRAC_STATUS_ALL_DATA_LOADED;
}
} else {
if (bufferInfo.first.filePos > atrac->first.filesize) {
return hleDelayResult(hleLogError(ME, ATRAC_ERROR_API_FAIL, "invalid file position"), "reset play pos", 200);
}
// Move the offset to the specified position.
atrac->first.fileoffset = bufferInfo.first.filePos;
if (bytesWrittenFirstBuf != 0) {
// TODO: We should just use the buffer in PSP RAM.
Memory::Memcpy(atrac->data_buf + atrac->first.fileoffset, atrac->first.addr, bytesWrittenFirstBuf);
atrac->first.fileoffset += bytesWrittenFirstBuf;
}
atrac->first.size = atrac->first.fileoffset;
atrac->first.writableBytes = bufferInfo.first.writableBytes - bytesWrittenFirstBuf;
atrac->first.offset = bytesWrittenFirstBuf;
}
#ifdef USE_FFMPEG
if ((atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) {