From 04dcaeae1d4cf44d474faede3ab70ea76e23a481 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 4 Jun 2016 18:02:55 -0700 Subject: [PATCH] Mpeg: Move, rather than resetting, packetsAvail. When we've got garbage data, this has to stay incorrect. Without this, Megaman X gets confused when playing its video (because it enqueues garbage packets.) See #3318. --- Core/HLE/sceMpeg.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Core/HLE/sceMpeg.cpp b/Core/HLE/sceMpeg.cpp index 7eaa56b38a..76378048fe 100644 --- a/Core/HLE/sceMpeg.cpp +++ b/Core/HLE/sceMpeg.cpp @@ -1078,6 +1078,8 @@ static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs); } + s32 beforeAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048; + // We stored the video stream id here in sceMpegGetAvcAu(). ctx->mediaengine->setVideoStream(avcAu.esBuffer); @@ -1103,7 +1105,14 @@ static u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr } else { ctx->avc.avcFrameStatus = 0; } - ringbuffer->packetsAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048; + s32 afterAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048; + // Don't actually reset avail, we only change it by what was decoded. + // Garbage frames can cause this to be incorrect, but some games expect that. + if (mpegLibVersion <= 0x0103) { + ringbuffer->packetsAvail += afterAvail - beforeAvail; + } else { + ringbuffer->packetsAvail = afterAvail; + } avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp; @@ -1247,6 +1256,8 @@ static int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initA return hleDelayResult(ERROR_MPEG_AVC_DECODE_FATAL, "mpeg buffer empty", avcEmptyDelayMs); } + s32 beforeAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048; + // We stored the video stream id here in sceMpegGetAvcAu(). ctx->mediaengine->setVideoStream(avcAu.esBuffer); @@ -1258,10 +1269,17 @@ static int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initA // Don't draw here, we'll draw in the Csc func. ctx->avc.avcFrameStatus = 1; ctx->videoFrameCount++; - }else { + } else { ctx->avc.avcFrameStatus = 0; } - ringbuffer->packetsAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048; + s32 afterAvail = ringbuffer->packets - ctx->mediaengine->getRemainSize() / 2048; + // Don't actually reset avail, we only change it by what was decoded. + // Garbage frames can cause this to be incorrect, but some games expect that. + if (mpegLibVersion <= 0x0103) { + ringbuffer->packetsAvail += afterAvail - beforeAvail; + } else { + ringbuffer->packetsAvail = afterAvail; + } avcAu.pts = ctx->mediaengine->getVideoTimeStamp() + ctx->mpegFirstTimestamp;