From e784f8bccb7ee0806d1768c2795e0fd8ac4d4812 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 17 Sep 2026 09:53:03 -0600 Subject: [PATCH] sceMpegbase: delay the colour conversion, as the hardware does sceMpegBaseCscAvc/CscAvcRange run on the DMACPLUS and take real time. A psmfplayer game re-blits the current video frame every render frame while it waits for the next, so an instant return here is a tight loop that never yields and starves the audio thread the playback clock is paced by - the whole A/V pipeline then deadlocks a few frames into the movie. SOCOM: Tactical Strike hung exactly this way running the real mpeg.prx; with the delay it plays. Same value and reason as our sceMpeg HLE's sceMpegAvcCsc. Co-Authored-By: Claude Opus 5 (1M context) --- Core/HLE/sceMpegbase.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Core/HLE/sceMpegbase.cpp b/Core/HLE/sceMpegbase.cpp index c0fdb1893b..49b29c99b9 100644 --- a/Core/HLE/sceMpegbase.cpp +++ b/Core/HLE/sceMpegbase.cpp @@ -340,8 +340,14 @@ static int MpegBaseCscRange(u32 bufferRGB, u32 cscAddr, int bufferWidth, // last frame the GE drew - the same notification our sceMpegAvcCsc HLE does. The pixel mode // numbering matches GEBufferFormat, as it does there. gpu->PerformWriteFormattedFromMemory(bufferRGB, destSize, bufferWidth, (GEBufferFormat)g_mpegBasePixelMode); - return hleLogDebug(Log::Mpeg, 0, "%dx%d at %d,%d -> %08x stride %d", - rangeWidth, rangeHeight, rangeX, rangeY, bufferRGB, bufferWidth); + // This runs on the DMACPLUS hardware and takes real time, and a caller running the real + // mpeg.prx leans on that. A psmfplayer game blits the current video frame every render frame + // while it waits for the next one to be ready, so returning instantly turns that into a tight + // loop that never yields and starves the audio thread - which is what paces playback - so the + // whole A/V pipeline deadlocks a few frames in. (SOCOM: Tactical Strike hangs exactly here.) + // Our sceMpeg HLE delays the equivalent sceMpegAvcCsc by the same amount for the same reason. + return hleDelayResult(hleLogDebug(Log::Mpeg, 0, "%dx%d at %d,%d -> %08x stride %d", + rangeWidth, rangeHeight, rangeX, rangeY, bufferRGB, bufferWidth), "mpegbase csc", 4000); } static int sceMpegBaseCscInit(int bufferWidth) {