Seek backwards by force decoding, align seeks.

It seems like we can only (safely) seek to sample boundaries, which makes
sense.  Also, we get wrong data unless we "warm" it by seeking from 0, it
seems like.

This makes looping produce correct data.  Fixes #6970.
This commit is contained in:
Unknown W. Brackets committed 2015-02-01 15:13:50 -08:00
1 parent da6375d89d
commit 97fd19f8cd
1 file changed
+44 -14
+44 -14
View File
@@ -313,11 +313,45 @@ struct Atrac {
packet = nullptr;
}
void SeekToSample(int sample) {
s64 seek_pos = (s64)sample;
av_seek_frame(pFormatCtx, audio_stream_index, seek_pos, 0);
void ForceSeekToSample(int sample) {
av_seek_frame(pFormatCtx, audio_stream_index, sample + 0x200000, 0);
av_seek_frame(pFormatCtx, audio_stream_index, sample, 0);
avcodec_flush_buffers(pCodecCtx);
// Discard any pending packet data.
packet->size = 0;
currentSample = sample;
}
void SeekToSample(int sample) {
const u32 atracSamplesPerFrame = (codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
// Discard any pending packet data.
packet->size = 0;
// Some kind of header size?
const u32 firstOffsetExtra = codecType == PSP_CODEC_AT3PLUS ? 368 : 69;
// It seems like the PSP aligns the sample position to 0x800...?
const u32 offsetSamples = firstSampleoffset + firstOffsetExtra;
const u32 unalignedSamples = (offsetSamples + sample) % atracSamplesPerFrame;
int seekFrame = sample + offsetSamples - unalignedSamples;
if (sample < currentSample) {
// "Seeking" by reading frames seems to work much better.
av_seek_frame(pFormatCtx, audio_stream_index, 0, AVSEEK_FLAG_BACKWARD);
avcodec_flush_buffers(pCodecCtx);
for (int i = 0; i < seekFrame; i += atracSamplesPerFrame) {
while (FillPacket() && DecodePacket() == ATDECODE_FEEDME) {
continue;
}
}
} else {
av_seek_frame(pFormatCtx, audio_stream_index, seekFrame, 0);
avcodec_flush_buffers(pCodecCtx);
}
currentSample = sample;
}
bool FillPacket() {
@@ -829,19 +863,18 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3
u32 firstOffsetExtra = atrac->codecType == PSP_CODEC_AT3PLUS ? 368 : 69;
// It seems like the PSP aligns the sample position to 0x800...?
int offsetSamples = atrac->firstSampleoffset + firstOffsetExtra;
int skipSamples = atrac->currentSample == 0 ? offsetSamples : 0;
int skipSamples = 0;
u32 maxSamples = atrac->endSample - atrac->currentSample;
u32 unalignedSamples = (offsetSamples + atrac->currentSample) % atracSamplesPerFrame;
if (unalignedSamples != 0) {
// We're off alignment, possibly due to a loop. Force it back on.
maxSamples = atracSamplesPerFrame - unalignedSamples;
skipSamples = unalignedSamples;
}
#ifdef USE_FFMPEG
if (!atrac->failedDecode && (atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) {
int forceseekSample = atrac->currentSample * 2 > atrac->endSample ? 0 : atrac->endSample;
atrac->SeekToSample(forceseekSample);
atrac->SeekToSample(atrac->currentSample == 0 ? 0 : atrac->currentSample + offsetSamples);
atrac->SeekToSample(atrac->currentSample);
AtracDecodeResult res = ATDECODE_FEEDME;
while (atrac->FillPacket()) {
@@ -918,7 +951,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3
int finishFlag = 0;
if (atrac->loopNum != 0 && (atrac->currentSample > atrac->loopEndSample ||
(numSamples == 0 && atrac->first.size >= atrac->first.filesize))) {
atrac->currentSample = atrac->loopStartSample;
atrac->SeekToSample(atrac->loopStartSample);
if (atrac->loopNum > 0)
atrac->loopNum --;
} else if (atrac->currentSample >= atrac->endSample ||
@@ -1288,13 +1321,13 @@ static u32 sceAtracResetPlayPosition(int atracID, int sample, int bytesWrittenFi
INFO_LOG(ME, "sceAtracResetPlayPosition(%i, %i, %i, %i)", atracID, sample, bytesWrittenFirstBuf, bytesWrittenSecondBuf);
if (bytesWrittenFirstBuf > 0)
sceAtracAddStreamData(atracID, bytesWrittenFirstBuf);
atrac->currentSample = sample;
#ifdef USE_FFMPEG
if ((atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) {
atrac->SeekToSample(sample);
} else
#endif // USE_FFMPEG
{
atrac->currentSample = sample;
atrac->decodePos = atrac->getDecodePosBySample(sample);
}
}
@@ -2120,9 +2153,7 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo
}
int numSamples = 0;
int forceseekSample = 0x200000;
atrac->SeekToSample(forceseekSample);
atrac->SeekToSample(atrac->currentSample);
atrac->ForceSeekToSample(atrac->currentSample);
if (!atrac->failedDecode) {
AtracDecodeResult res;
@@ -2152,12 +2183,11 @@ static int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesCo
atrac->currentSample += numSamples;
numSamples = (atrac->codecType == PSP_MODE_AT_3_PLUS ? ATRAC3PLUS_MAX_SAMPLES : ATRAC3_MAX_SAMPLES);
Memory::Write_U32(numSamples * sizeof(s16) * atrac->atracOutputChannels, sampleBytesAddr);
atrac->SeekToSample(atrac->currentSample);
if (atrac->decodePos >= atrac->first.size) {
atrac->first.writableBytes = atrac->atracBytesPerFrame;
atrac->first.size = atrac->firstSampleoffset;
atrac->currentSample = 0;
atrac->ForceSeekToSample(0);
}
else
atrac->first.writableBytes = 0;