From 398646411a1e1f5e03dbc636684e6852e05d8df0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 19:48:39 -0700 Subject: [PATCH 1/8] Properly handle atrac packets with multiple frames. This gets us decoding the start of a file and near loops way more correctly. --- Core/HLE/sceAtrac.cpp | 92 ++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 1e1f16271a..6d47be1c3d 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -127,11 +127,12 @@ struct Atrac { memset(&first, 0, sizeof(first)); memset(&second, 0, sizeof(second)); #ifdef USE_FFMPEG - pFormatCtx = 0; - pAVIOCtx = 0; - pCodecCtx = 0; - pSwrCtx = 0; - pFrame = 0; + pFormatCtx = nullptr; + pAVIOCtx = nullptr; + pCodecCtx = nullptr; + pSwrCtx = nullptr; + pFrame = nullptr; + packet = nullptr; audio_stream_index = 0; #endif // USE_FFMPEG atracContext = 0; @@ -274,6 +275,7 @@ struct Atrac { AVCodecContext *pCodecCtx; SwrContext *pSwrCtx; AVFrame *pFrame; + AVPacket *packet; int audio_stream_index; void ReleaseFFMPEGContext() { @@ -289,17 +291,37 @@ struct Atrac { avcodec_close(pCodecCtx); if (pFormatCtx) avformat_close_input(&pFormatCtx); - pFormatCtx = 0; - pAVIOCtx = 0; - pCodecCtx = 0; - pSwrCtx = 0; - pFrame = 0; + if (packet) + av_free_packet(packet); + delete packet; + pFormatCtx = nullptr; + pAVIOCtx = nullptr; + pCodecCtx = nullptr; + pSwrCtx = nullptr; + pFrame = nullptr; + packet = nullptr; } void SeekToSample(int sample) { s64 seek_pos = (s64)sample; av_seek_frame(pFormatCtx, audio_stream_index, seek_pos, 0); } + + bool FillPacket() { + if (packet->size > 0) { + return true; + } + do { + // This is double-free safe, so we just call it before each read and at the end. + av_free_packet(packet); + if (av_read_frame(pFormatCtx, packet) < 0) { + return false; + } + // We keep reading until we get the right stream index. + } while (packet->stream_index != audio_stream_index); + + return true; + } #endif // USE_FFMPEG }; @@ -641,25 +663,18 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 int forceseekSample = atrac->currentSample * 2 > atrac->endSample ? 0 : atrac->endSample; atrac->SeekToSample(forceseekSample); atrac->SeekToSample(atrac->currentSample == 0 ? 0 : atrac->currentSample + offsetSamples); - AVPacket packet; - av_init_packet(&packet); int got_frame = 0, avret; - while (av_read_frame(atrac->pFormatCtx, &packet) >= 0) { - if (packet.stream_index != atrac->audio_stream_index) { - av_free_packet(&packet); - continue; - } - + while (atrac->FillPacket()) { got_frame = 0; - int bytes_in_packet = packet.size; - avret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, &packet); + avret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, atrac->packet); if (avret == AVERROR_PATCHWELCOME) { ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); - // Let's try the next frame. + // Let's try the next packet. + atrac->packet->size = 0; + avret = 0; // TODO: Or actually, we should return a blank frame and pretend it worked. } else if (avret < 0) { ERROR_LOG(ME, "avcodec_decode_audio4: Error decoding audio %d", avret); - av_free_packet(&packet); atrac->failedDecode = true; // No need to free the packet if decode_audio4 fails. // Avoid getting stuck in a loop (Virtua Tennis) @@ -668,11 +683,9 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 *remains = 0; return ATRAC_ERROR_ALL_DATA_DECODED; } - // FFmpeg seems to return packet.size / 10. - // However, advancing the packet by this causes decode errors. Bug? - if (avret != packet.size && avret != packet.size / 10) { - ERROR_LOG_REPORT_ONCE(multipacket, ME, "WARNING: Remaining data in packet - we currently only decode one frame per packet"); - } + + atrac->packet->size -= avret; + atrac->packet->data += avret; if (got_frame) { // got a frame @@ -713,7 +726,6 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 } } } - av_free_packet(&packet); if (got_frame) { // We only want one frame per call, let's continue the next time. break; @@ -1239,6 +1251,10 @@ int __AtracSetContext(Atrac *atrac) { // alloc audio frame atrac->pFrame = av_frame_alloc(); + atrac->packet = new AVPacket; + av_init_packet(atrac->packet); + atrac->packet->data = nullptr; + atrac->packet->size = 0; // reinit decodePos, because ffmpeg had changed it. atrac->decodePos = 0; #endif @@ -1962,27 +1978,24 @@ int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedA atrac->SeekToSample(atrac->currentSample); if (!atrac->failedDecode) { - AVPacket packet; - av_init_packet(&packet); int got_frame, avret; - while (av_read_frame(atrac->pFormatCtx, &packet) >= 0) { - if (packet.stream_index != atrac->audio_stream_index) { - av_free_packet(&packet); - continue; - } - + while (atrac->FillPacket()) { got_frame = 0; - avret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, &packet); + avret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, atrac->packet); if (avret == AVERROR_PATCHWELCOME) { ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); - // Let's try the next frame. + // Let's try the next packet. + atrac->packet->size = 0; + avret = 0; } else if (avret < 0) { ERROR_LOG(ME, "atracID: %i, avcodec_decode_audio4: Error decoding audio %d", atracID, avret); - av_free_packet(&packet); atrac->failedDecode = true; break; } + atrac->packet->size -= avret; + atrac->packet->data += avret; + if (got_frame) { // got a frame int decoded = av_samples_get_buffer_size(NULL, atrac->pFrame->channels, @@ -1995,7 +2008,6 @@ int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedA ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); } } - av_free_packet(&packet); if (got_frame) break; } From 24ab84a0fe9ff9214709181cd5088dd71faf7e80 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 20:04:39 -0700 Subject: [PATCH 2/8] Centralize atrac frame decode logic. --- Core/HLE/sceAtrac.cpp | 87 ++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 42 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 6d47be1c3d..95dadbee5b 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -95,6 +95,12 @@ extern "C" { #endif // USE_FFMPEG +enum AtracDecodeResult { + ATDECODE_FAILED = -1, + ATDECODE_FEEDME = 0, + ATDECODE_GOTFRAME = 1, +}; + struct InputBuffer { u32 addr; u32 size; @@ -322,6 +328,26 @@ struct Atrac { return true; } + + AtracDecodeResult DecodePacket() { + int got_frame = 0; + int bytes_read = avcodec_decode_audio4(pCodecCtx, pFrame, &got_frame, packet); + if (bytes_read == AVERROR_PATCHWELCOME) { + ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); + // Let's try the next packet. + packet->size = 0; + // TODO: Or actually, should we return a blank frame and pretend it worked? + return ATDECODE_FEEDME; + } else if (bytes_read < 0) { + ERROR_LOG_REPORT(ME, "avcodec_decode_audio4: Error decoding audio %d / %08x", bytes_read, bytes_read); + failedDecode = true; + return ATDECODE_FAILED; + } + + packet->size -= bytes_read; + packet->data += bytes_read; + return got_frame ? ATDECODE_GOTFRAME : ATDECODE_FEEDME; + } #endif // USE_FFMPEG }; @@ -663,20 +689,11 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 int forceseekSample = atrac->currentSample * 2 > atrac->endSample ? 0 : atrac->endSample; atrac->SeekToSample(forceseekSample); atrac->SeekToSample(atrac->currentSample == 0 ? 0 : atrac->currentSample + offsetSamples); - int got_frame = 0, avret; + + AtracDecodeResult res = ATDECODE_FEEDME; while (atrac->FillPacket()) { - got_frame = 0; - avret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, atrac->packet); - if (avret == AVERROR_PATCHWELCOME) { - ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); - // Let's try the next packet. - atrac->packet->size = 0; - avret = 0; - // TODO: Or actually, we should return a blank frame and pretend it worked. - } else if (avret < 0) { - ERROR_LOG(ME, "avcodec_decode_audio4: Error decoding audio %d", avret); - atrac->failedDecode = true; - // No need to free the packet if decode_audio4 fails. + res = atrac->DecodePacket(); + if (res == ATDECODE_FAILED) { // Avoid getting stuck in a loop (Virtua Tennis) *SamplesNum = 0; *finish = 1; @@ -684,10 +701,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 return ATRAC_ERROR_ALL_DATA_DECODED; } - atrac->packet->size -= avret; - atrac->packet->data += avret; - - if (got_frame) { + if (res == ATDECODE_GOTFRAME) { // got a frame // Use a small buffer and keep overwriting it with file data constantly atrac->first.writableBytes += atrac->atracBytesPerFrame; @@ -700,7 +714,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 if (skipped > 0 && numSamples == 0) { // Wait for the next one. - got_frame = 0; + res = ATDECODE_FEEDME; } if (outbuf != NULL && numSamples != 0) { @@ -716,7 +730,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 atrac->pFrame->extended_data[0] + inbufOffset, atrac->pFrame->extended_data[1] + inbufOffset, }; - avret = swr_convert(atrac->pSwrCtx, &out, numSamples, inbuf, numSamples); + int avret = swr_convert(atrac->pSwrCtx, &out, numSamples, inbuf, numSamples); if (outbufPtr != 0) { u32 outBytes = numSamples * atrac->atracOutputChannels * sizeof(s16); CBreakPoints::ExecMemCheck(outbufPtr, true, outBytes, currentMIPS->pc); @@ -726,13 +740,13 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 } } } - if (got_frame) { + if (res == ATDECODE_GOTFRAME) { // We only want one frame per call, let's continue the next time. break; } } - if (!got_frame && atrac->currentSample < atrac->endSample) { + if (res != ATDECODE_GOTFRAME && atrac->currentSample < atrac->endSample) { // Never got a frame. We may have dropped a GHA frame or otherwise have a bug. // For now, let's try to provide an extra "frame" if possible so games don't infinite loop. numSamples = std::min((u32)atrac->endSample - (u32)atrac->currentSample, atracSamplesPerFrame); @@ -1978,37 +1992,26 @@ int sceAtracLowLevelDecode(int atracID, u32 sourceAddr, u32 sourceBytesConsumedA atrac->SeekToSample(atrac->currentSample); if (!atrac->failedDecode) { - int got_frame, avret; + AtracDecodeResult res; while (atrac->FillPacket()) { - got_frame = 0; - avret = avcodec_decode_audio4(atrac->pCodecCtx, atrac->pFrame, &got_frame, atrac->packet); - if (avret == AVERROR_PATCHWELCOME) { - ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); - // Let's try the next packet. - atrac->packet->size = 0; - avret = 0; - } else if (avret < 0) { - ERROR_LOG(ME, "atracID: %i, avcodec_decode_audio4: Error decoding audio %d", atracID, avret); - atrac->failedDecode = true; + res = atrac->DecodePacket(); + if (res == ATDECODE_FAILED) { break; } - atrac->packet->size -= avret; - atrac->packet->data += avret; - - if (got_frame) { + if (res == ATDECODE_GOTFRAME) { // got a frame - int decoded = av_samples_get_buffer_size(NULL, atrac->pFrame->channels, - atrac->pFrame->nb_samples, (AVSampleFormat)atrac->pFrame->format, 1); - u8* out = Memory::GetPointer(samplesAddr); + u8 *out = Memory::GetPointer(samplesAddr); numSamples = atrac->pFrame->nb_samples; - avret = swr_convert(atrac->pSwrCtx, &out, atrac->pFrame->nb_samples, - (const u8**)atrac->pFrame->extended_data, atrac->pFrame->nb_samples); + int avret = swr_convert(atrac->pSwrCtx, &out, numSamples, + (const u8**)atrac->pFrame->extended_data, numSamples); + u32 outBytes = numSamples * atrac->atracOutputChannels * sizeof(s16); + CBreakPoints::ExecMemCheck(samplesAddr, true, outBytes, currentMIPS->pc); if (avret < 0) { ERROR_LOG(ME, "swr_convert: Error while converting %d", avret); } } - if (got_frame) + if (res == ATDECODE_GOTFRAME) break; } } From 2f443f52a6a21bd0af0fdeaa1ba5737980e378df Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 20:05:08 -0700 Subject: [PATCH 3/8] Ensure we request s16 samples. We won't get these for atrac3+, but we should for atrac3 (seems to be the default anyway, but better to be clear.) --- Core/HLE/sceAtrac.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index 95dadbee5b..f41e3715b3 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -1255,6 +1255,7 @@ int __AtracSetContext(Atrac *atrac) { atrac->pCodecCtx->channel_layout = AV_CH_LAYOUT_MONO; // open codec + atrac->pCodecCtx->request_sample_fmt = AV_SAMPLE_FMT_S16; if ((ret = avcodec_open2(atrac->pCodecCtx, pCodec, NULL)) < 0) { ERROR_LOG(ME, "avcodec_open2: Cannot open audio decoder %d", ret); return -1; From f421453bf9e91e5439b4083e82731cbcd5bde809 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 21:32:07 -0700 Subject: [PATCH 4/8] Align samples even after a loop. This corrects the amount of audio after certain loops, but it doesn't seem to output the right data when this happens. Possibly, seeking isn't doing the right thing and resetting state that shouldn't be reset when a loop happens. Not sure... but it was already wrong before, this just reads the right amount of it. --- Core/HLE/sceAtrac.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index f41e3715b3..e56dd5a730 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -683,6 +683,12 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 // It seems like the PSP aligns the sample position to 0x800...? int offsetSamples = atrac->firstSampleoffset + firstOffsetExtra; int skipSamples = atrac->currentSample == 0 ? offsetSamples : 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; + } #ifdef USE_FFMPEG if (!atrac->failedDecode && (atrac->codecType == PSP_MODE_AT_3 || atrac->codecType == PSP_MODE_AT_3_PLUS) && atrac->pCodecCtx) { @@ -710,7 +716,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 numSamples = atrac->pFrame->nb_samples - skipped; // If we're at the end, clamp to samples we want. It always returns a full chunk. - numSamples = std::min((u32)atrac->endSample - (u32)atrac->currentSample, numSamples); + numSamples = std::min(maxSamples, numSamples); if (skipped > 0 && numSamples == 0) { // Wait for the next one. @@ -749,7 +755,7 @@ u32 _AtracDecodeData(int atracID, u8 *outbuf, u32 outbufPtr, u32 *SamplesNum, u3 if (res != ATDECODE_GOTFRAME && atrac->currentSample < atrac->endSample) { // Never got a frame. We may have dropped a GHA frame or otherwise have a bug. // For now, let's try to provide an extra "frame" if possible so games don't infinite loop. - numSamples = std::min((u32)atrac->endSample - (u32)atrac->currentSample, atracSamplesPerFrame); + numSamples = std::min(maxSamples, atracSamplesPerFrame); u32 outBytes = numSamples * atrac->atracOutputChannels * sizeof(s16); memset(outbuf, 0, outBytes); CBreakPoints::ExecMemCheck(outbufPtr, true, outBytes, currentMIPS->pc); @@ -1012,6 +1018,11 @@ u32 sceAtracGetNextSample(int atracID, u32 outNAddr) { if (atrac->currentSample == 0 && firstSamples != 0) { numSamples = firstSamples; } + u32 unalignedSamples = (skipSamples + atrac->currentSample) % atracSamplesPerFrame; + if (unalignedSamples != 0) { + // We're off alignment, possibly due to a loop. Force it back on. + numSamples = atracSamplesPerFrame - unalignedSamples; + } if (numSamples > atracSamplesPerFrame) numSamples = atracSamplesPerFrame; if (Memory::IsValidAddress(outNAddr)) From cf7e280185ee82ec0bf0a36009daed9355daa1cc Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 22:11:45 -0700 Subject: [PATCH 5/8] Attempt to ensure we don't decode partial frames. --- Core/HLE/sceAtrac.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index e56dd5a730..a48127710b 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -330,8 +330,33 @@ struct Atrac { } AtracDecodeResult DecodePacket() { + AVPacket tempPacket; + AVPacket *decodePacket = packet; + if (packet->size < (int)atracBytesPerFrame) { + // Whoops, we have a packet that is smaller than a frame. Let's meld a new one. + u32 initialSize = packet->size; + u32 needed = atracBytesPerFrame - initialSize; + av_init_packet(&tempPacket); + av_copy_packet(&tempPacket, packet); + av_grow_packet(&tempPacket, needed); + + // Okay, we're "out of data", let's get more. + packet->size = 0; + + if (FillPacket()) { + if (packet->size >= needed) { + memcpy(tempPacket.data + initialSize, packet->data, needed); + packet->size -= needed; + packet->data += needed; + } + } + } + int got_frame = 0; - int bytes_read = avcodec_decode_audio4(pCodecCtx, pFrame, &got_frame, packet); + int bytes_read = avcodec_decode_audio4(pCodecCtx, pFrame, &got_frame, decodePacket); + if (packet != decodePacket) { + av_free_packet(&tempPacket); + } if (bytes_read == AVERROR_PATCHWELCOME) { ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); // Let's try the next packet. From 72e8e6448fdd80cc6358cef161c192df5128aa12 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 22:17:25 -0700 Subject: [PATCH 6/8] Don't eat packet data when using a temp packet. --- Core/HLE/sceAtrac.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index a48127710b..b6b74baa49 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -360,7 +360,9 @@ struct Atrac { if (bytes_read == AVERROR_PATCHWELCOME) { ERROR_LOG(ME, "Unsupported feature in ATRAC audio."); // Let's try the next packet. - packet->size = 0; + if (packet == decodePacket) { + packet->size = 0; + } // TODO: Or actually, should we return a blank frame and pretend it worked? return ATDECODE_FEEDME; } else if (bytes_read < 0) { @@ -369,8 +371,10 @@ struct Atrac { return ATDECODE_FAILED; } - packet->size -= bytes_read; - packet->data += bytes_read; + if (packet == decodePacket) { + packet->size -= bytes_read; + packet->data += bytes_read; + } return got_frame ? ATDECODE_GOTFRAME : ATDECODE_FEEDME; } #endif // USE_FFMPEG From 50e4eded75eef83055305de62db4c24de9763f95 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 23:08:16 -0700 Subject: [PATCH 7/8] Actually use the temp packet. --- Core/HLE/sceAtrac.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index b6b74baa49..d69f858bd6 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -335,7 +335,7 @@ struct Atrac { if (packet->size < (int)atracBytesPerFrame) { // Whoops, we have a packet that is smaller than a frame. Let's meld a new one. u32 initialSize = packet->size; - u32 needed = atracBytesPerFrame - initialSize; + int needed = atracBytesPerFrame - initialSize; av_init_packet(&tempPacket); av_copy_packet(&tempPacket, packet); av_grow_packet(&tempPacket, needed); @@ -350,6 +350,7 @@ struct Atrac { packet->data += needed; } } + decodePacket = &tempPacket; } int got_frame = 0; From adef5bbe59517ae3dc85021b1317da00e26a90f7 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Fri, 3 Oct 2014 23:23:36 -0700 Subject: [PATCH 8/8] Discard packet data when seeking. --- Core/HLE/sceAtrac.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/HLE/sceAtrac.cpp b/Core/HLE/sceAtrac.cpp index d69f858bd6..46554ffbca 100644 --- a/Core/HLE/sceAtrac.cpp +++ b/Core/HLE/sceAtrac.cpp @@ -311,6 +311,8 @@ struct Atrac { void SeekToSample(int sample) { s64 seek_pos = (s64)sample; av_seek_frame(pFormatCtx, audio_stream_index, seek_pos, 0); + // Discard any pending packet data. + packet->size = 0; } bool FillPacket() {