From a1ade54aaca2599a038418bbc5fbad911c0e99d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 23 Oct 2026 12:08:10 +0200 Subject: [PATCH] UMD Video: Boot the XMB for a video disc however it's started The game list already did, but booting a video disc any other way (the command line, a file association, dropping it on a running game, headless) tried it as a game and failed. The loader now swaps in vshmain.prx with the disc mounted and auto-start on whenever it identifies a UMD Video disc and the installed firmware can play it. GetUmdVideoVSHPath() moves from the UI to Core/Util/PSARUnpack. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/System.cpp | 17 +++++++++++++++++ Core/Util/PSARUnpack.cpp | 9 +++++++++ Core/Util/PSARUnpack.h | 2 ++ UI/MainScreen.cpp | 9 --------- UI/MainScreen.h | 3 --- docs/VSHBootInvestigation.md | 5 +++-- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/Core/System.cpp b/Core/System.cpp index f4996d99a4..cdffa2f4e3 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -823,6 +823,23 @@ bool PSP_InitStart(const CoreParameter &coreParam) { IdentifiedFileType fileType; FileLoader *loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename), &fileType, errorString); + // UMD Video only plays in the XMB, so however it was asked for, boot that with the disc in + // the drive and auto-start on. Without a firmware that can, CPU_Init says what's needed. + if (fileType == IdentifiedFileType::PSP_UMD_VIDEO_ISO) { + const Path vshmain = GetUmdVideoVSHPath(); + if (!vshmain.empty()) { + INFO_LOG(Log::Loader, "UMD Video: booting the XMB (%s) to play %s", vshmain.c_str(), filename.c_str()); + delete loadedFile; + g_CoreParameter.mountIso = filename; + g_CoreParameter.fileToStart = vshmain; + if (!g_CoreParameter.umdAutoboot) { + g_CoreParameter.umdAutoboot = true; + } + filename = vshmain; + loadedFile = ResolveFileLoaderTarget(ConstructFileLoader(filename), &fileType, errorString); + } + } + if (System_GetPropertyBool(SYSPROP_ENOUGH_RAM_FOR_FULL_ISO)) { if (g_Config.bCacheFullIsoInRam) { switch (fileType) { diff --git a/Core/Util/PSARUnpack.cpp b/Core/Util/PSARUnpack.cpp index 71db0d54db..91962f0dde 100644 --- a/Core/Util/PSARUnpack.cpp +++ b/Core/Util/PSARUnpack.cpp @@ -1365,6 +1365,15 @@ bool FirmwareVersionPlaysUmdVideo(std::string_view version) { return FirmwareVersionSupportsVSH(version) && FirmwareVersionToInt(version) >= FirmwareVersionToInt(UMD_VIDEO_MIN_FIRMWARE); } +Path GetUmdVideoVSHPath() { + InstalledFirmwareInfo info; + ReadInstalledFirmwareInfo(g_Config.nandRootDirectory, &info, false); + if (!info.hasVsh || !FirmwareVersionPlaysUmdVideo(info.version)) { + return Path(); + } + return g_Config.nandRootDirectory / "flash0/vsh/module/vshmain.prx"; +} + std::string BundledUpdateInfo::Describe() const { if (!present) { return std::string(); diff --git a/Core/Util/PSARUnpack.h b/Core/Util/PSARUnpack.h index 19ae34b655..6662ba489e 100644 --- a/Core/Util/PSARUnpack.h +++ b/Core/Util/PSARUnpack.h @@ -189,6 +189,8 @@ bool FirmwareVersionSupportsVSH(std::string_view version); bool FirmwareVersionPlaysUmdVideo(std::string_view version); // The oldest firmware that does. extern const char *const UMD_VIDEO_MIN_FIRMWARE; +// vshmain.prx, if the installed firmware's XMB can play UMD Video discs. Empty otherwise. +Path GetUmdVideoVSHPath(); // Installs a firmware into the NAND directory. Two firmwares can't be merged - a file the new one // doesn't have would linger and still get loaded - so this replaces rather than overlays. diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index 2586ec7cb0..c84b55b8b2 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -62,15 +62,6 @@ bool MainScreen::showHomebrewTab = false; -Path GetUmdVideoVSHPath() { - InstalledFirmwareInfo info; - ReadInstalledFirmwareInfo(g_Config.nandRootDirectory, &info, false); - if (!info.hasVsh || !FirmwareVersionPlaysUmdVideo(info.version)) { - return Path(); - } - return g_Config.nandRootDirectory / "flash0/vsh/module/vshmain.prx"; -} - static void LaunchInEmuScreen(ScreenManager *screenManager, Screen *currentScreen, EmuScreen *emuScreen) { if (currentScreen) { screenManager->cancelScreensAbove(currentScreen); diff --git a/UI/MainScreen.h b/UI/MainScreen.h index 3ed60f3094..bf6f6dc4f3 100644 --- a/UI/MainScreen.h +++ b/UI/MainScreen.h @@ -136,6 +136,3 @@ private: }; void LaunchBuyGold(ScreenManager *screenManager); - -// vshmain.prx, if the installed firmware's XMB can play UMD Video discs. Empty otherwise. -Path GetUmdVideoVSHPath(); diff --git a/docs/VSHBootInvestigation.md b/docs/VSHBootInvestigation.md index d3d44716b1..b6f61d8c85 100644 --- a/docs/VSHBootInvestigation.md +++ b/docs/VSHBootInvestigation.md @@ -55,8 +55,9 @@ Two separate things: from our Media Engine HLE (per-picture SEI records, keyframe flags, field conversion in `sceMpegBaseCscAvc`) is in pspautotests `video/mpeg/avcdetail` and `video/mpeg/cscavc`. - Picking a UMD Video disc in the game list boots the XMB with the disc in the drive and UMD - auto-start forced on (`CoreParameter::umdAutoboot`), so it goes straight to the disc's menu. That + Booting a UMD Video disc (from the game list, the command line or anywhere else) boots the XMB + with the disc in the drive and UMD auto-start forced on (`CoreParameter::umdAutoboot`), so it + goes straight to the disc's menu. The swap happens in `PSP_InitStart`'s loader thread. That needs firmware 2.71 or later: 1.50, 2.00 and 2.60 crash in `video_plugin`/paf as soon as the disc is in, and 2.50 refuses it, claiming the system software is version "." (all measured with Bourne Supremacy). A disc with both a game and video asks which one; for video the XMB comes up