mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-14 18:19:36 +01:00
UI: Play UMD Video discs in the XMB, straight from the game list
With firmware 2.71 or later installed, picking a UMD Video disc boots the XMB with the disc in the drive and UMD auto-start forced on for that boot, so the disc's menu comes up. Without one, the info screen saying UMD Video isn't supported shows as before. The info screen's Play does the same. A disc with both a game and video asks which to start. For the video, the XMB comes up with auto-start forced off, since auto-start runs the game. Older firmware can't play these: 1.50, 2.00 and 2.60 crash in video_plugin or paf with a video disc in the drive, and 2.50 refuses it. 2.71 through 6.61 reach Bourne Supremacy's menu. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
bf1f88d6e6
commit
d331bd6c8c
10 files changed
+105
-16
No files matched your search
@@ -17,6 +17,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "Common/File/Path.h"
|
||||
@@ -68,6 +69,8 @@ struct CoreParameter {
|
||||
|
||||
Path mountIso; // If non-empty, and fileToStart is an ELF or PBP, will mount this ISO in the background to umd1:.
|
||||
Path mountRoot; // If non-empty, and fileToStart is an ELF or PBP, mount this as host0:.
|
||||
// Overrides the VSH's "UMD auto-start" setting (bVshUmdAutoboot) for this boot.
|
||||
std::optional<bool> umdAutoboot;
|
||||
|
||||
Path nandRoot; // If non-empty, use this directory as the root above flash0:-flash3: (which are hosted in subdirectories flash0-flash3 of it).
|
||||
|
||||
|
||||
+9
-3
@@ -9,6 +9,7 @@
|
||||
#include "Common/Serialize/SerializeMap.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#define SYSTEM_REGISTRY "/system"
|
||||
#define REG_KEYNAME_SIZE 27
|
||||
@@ -61,9 +62,14 @@ struct KeyValue {
|
||||
const KeyValue *dirContents; // intValue is the count.
|
||||
// If set, an INT key reads this setting (as 0 or 1), even after the guest writes it: the VSH
|
||||
// rewrites every key with its default at each boot, since category_version is below its schema.
|
||||
const bool *boolSetting = nullptr;
|
||||
bool (*boolSetting)() = nullptr;
|
||||
};
|
||||
|
||||
static bool UmdAutoboot() {
|
||||
// Forced on when a UMD Video disc picked from the game list boots the XMB.
|
||||
return PSP_CoreParameter().umdAutoboot.value_or(g_Config.bVshUmdAutoboot);
|
||||
}
|
||||
|
||||
// Guest-written registry values (sceRegCreateKey / sceRegSetKeyValue), keyed by category path
|
||||
// (no leading slash, e.g. "DATA/FONT") then key name. The static dump above is read-only, but
|
||||
// plugins like CLANNAD's chfont.prx register their font by creating /DATA/FONT/PROPERTY/INFO18
|
||||
@@ -768,7 +774,7 @@ static const KeyValue tree_CONFIG_SYSTEM_CHARACTER_SET[] = {
|
||||
static const KeyValue tree_CONFIG_SYSTEM[] = {
|
||||
{ "owner_name", ValueType::STR, "P939", 5 },
|
||||
{ "backlight_brightness", ValueType::INT, "", (int)0x3 }, // decimal: 3
|
||||
{ "umd_autoboot", ValueType::INT, "", (int)0x1, nullptr, &g_Config.bVshUmdAutoboot }, // decimal: 1
|
||||
{ "umd_autoboot", ValueType::INT, "", (int)0x1, nullptr, &UmdAutoboot }, // decimal: 1
|
||||
{ "usb_charge", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
{ "umd_cache", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
{ "usb_auto_connect", ValueType::INT, "", (int)0x1 }, // decimal: 1
|
||||
@@ -1096,7 +1102,7 @@ static const MergedCategory &GetMergedCategory(const std::string &path) {
|
||||
|
||||
for (auto &kv : merged.keyvals) {
|
||||
if (kv.boolSetting) {
|
||||
kv.intValue = *kv.boolSetting ? 1 : 0;
|
||||
kv.intValue = kv.boolSetting() ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1356,6 +1356,13 @@ bool FirmwareVersionSupportsVSH(std::string_view version) {
|
||||
return FirmwareVersionToInt(version) >= 150;
|
||||
}
|
||||
|
||||
bool FirmwareVersionPlaysUmdVideo(std::string_view version) {
|
||||
// Measured by booting Bourne Supremacy with auto-start on: 2.71 through 6.61 reach its disc menu.
|
||||
// 1.50, 2.00 and 2.60 crash in video_plugin or paf as soon as the disc is in the drive, and
|
||||
// 2.50 says the system software (version ".") is too old for it.
|
||||
return FirmwareVersionSupportsVSH(version) && FirmwareVersionToInt(version) >= 271;
|
||||
}
|
||||
|
||||
std::string BundledUpdateInfo::Describe() const {
|
||||
if (!present) {
|
||||
return std::string();
|
||||
|
||||
@@ -185,6 +185,9 @@ int FirmwareVersionToInt(std::string_view version);
|
||||
// the module patches it needs are version-specific, so it won't get anywhere.
|
||||
bool FirmwareVersionSupportsVSH(std::string_view version);
|
||||
|
||||
// Whether that VSH's own player plays UMD Video discs.
|
||||
bool FirmwareVersionPlaysUmdVideo(std::string_view version);
|
||||
|
||||
// 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.
|
||||
//
|
||||
|
||||
+4
-2
@@ -161,8 +161,8 @@ void EmuScreen::SetPSPAnalog(int iInternalScreenRotation, int stick, float x, fl
|
||||
__CtrlSetAnalogXY(stick, x, y);
|
||||
}
|
||||
|
||||
EmuScreen::EmuScreen(const Path &filename, const Path &mountIso)
|
||||
: gamePath_(filename), mountIso_(mountIso) {
|
||||
EmuScreen::EmuScreen(const Path &filename, const Path &mountIso, std::optional<bool> umdAutoboot)
|
||||
: gamePath_(filename), mountIso_(mountIso), umdAutoboot_(umdAutoboot) {
|
||||
saveStateSlot_ = SaveState::GetCurrentSlot();
|
||||
g_controlMapper.AddListener(this);
|
||||
|
||||
@@ -322,6 +322,7 @@ void EmuScreen::ProcessGameBoot(const Path &filename) {
|
||||
coreParam.enableSound = g_Config.bEnableSound;
|
||||
coreParam.fileToStart = filename;
|
||||
coreParam.mountIso = mountIso_;
|
||||
coreParam.umdAutoboot = umdAutoboot_;
|
||||
coreParam.mountRoot = g_Config.mountRoot;
|
||||
coreParam.startBreak = !g_Config.bAutoRun;
|
||||
coreParam.headLess = false;
|
||||
@@ -620,6 +621,7 @@ void EmuScreen::sendMessage(UIMessage message, const char *value) {
|
||||
bootIsReset_ = false;
|
||||
gamePath_ = newGamePath;
|
||||
mountIso_.clear();
|
||||
umdAutoboot_.reset();
|
||||
}
|
||||
} else if (message == UIMessage::CONFIG_LOADED) {
|
||||
// In case we need to position touch controls differently.
|
||||
|
||||
+4
-1
@@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -42,7 +43,8 @@ struct ImGuiContext;
|
||||
class EmuScreen : public UIScreen, protected ControlListener {
|
||||
public:
|
||||
// mountIso, if set, is mounted on umd1: when filename is an ELF/PBP (like the VSH).
|
||||
EmuScreen(const Path &filename, const Path &mountIso = Path());
|
||||
// umdAutoboot overrides the VSH's UMD auto-start setting.
|
||||
EmuScreen(const Path &filename, const Path &mountIso = Path(), std::optional<bool> umdAutoboot = std::nullopt);
|
||||
~EmuScreen();
|
||||
|
||||
const char *tag() const override { return "Emu"; }
|
||||
@@ -109,6 +111,7 @@ private:
|
||||
bool bootIsReset_ = false;
|
||||
Path gamePath_;
|
||||
Path mountIso_;
|
||||
std::optional<bool> umdAutoboot_;
|
||||
|
||||
bool quit_ = false;
|
||||
std::string errorMessage_;
|
||||
|
||||
+10
-4
@@ -367,7 +367,7 @@ void GameScreen::CreateContentViews(UI::ViewGroup *parent) {
|
||||
LinearLayout *infoLayout = new LinearLayout(ORIENT_VERTICAL, new AnchorLayoutParams(10, 200, NONE, NONE));
|
||||
leftColumn->Add(infoLayout);
|
||||
|
||||
if (info_->fileType == IdentifiedFileType::PSP_UMD_VIDEO_ISO) {
|
||||
if (info_->fileType == IdentifiedFileType::PSP_UMD_VIDEO_ISO && GetUmdVideoVSHPath().empty()) {
|
||||
auto er = GetI18NCategory(I18NCat::ERRORS);
|
||||
leftColumn->Add(new NoticeView(NoticeLevel::INFO, er->T("PPSSPP doesn't support UMD Video."), ""));
|
||||
leftColumn->Add(new Choice(di->T("More info"), ImageID("I_LINK_OUT_QUESTION"), new LinearLayoutParams(WRAP_CONTENT, WRAP_CONTENT)))->OnClick.Add([](UI::EventParams &e) {
|
||||
@@ -553,10 +553,16 @@ void GameScreen::CreateSettingsViews(UI::ViewGroup *rightColumn) {
|
||||
rightColumnItems->SetSpacing(0.0f);
|
||||
rightColumn->Add(rightColumnItems);
|
||||
|
||||
if (!inGame_ && FileTypeIsPlayable(info_->fileType)) {
|
||||
// UMD Video plays in the XMB, with the disc in the drive.
|
||||
const Path vshPath = info_->fileType == IdentifiedFileType::PSP_UMD_VIDEO_ISO ? GetUmdVideoVSHPath() : Path();
|
||||
if (!inGame_ && (FileTypeIsPlayable(info_->fileType) || !vshPath.empty())) {
|
||||
Choice *play = rightColumnItems->Add(new Choice(ga->T("Play"), ImageID("I_PLAY")));
|
||||
play->OnClick.Add([this](UI::EventParams &e) {
|
||||
screenManager()->switchScreen(new EmuScreen(gamePath_));
|
||||
play->OnClick.Add([this, vshPath](UI::EventParams &e) {
|
||||
if (vshPath.empty()) {
|
||||
screenManager()->switchScreen(new EmuScreen(gamePath_));
|
||||
} else {
|
||||
screenManager()->switchScreen(new EmuScreen(vshPath, gamePath_, true));
|
||||
}
|
||||
});
|
||||
// The file is being read, and maybe about to be replaced.
|
||||
play->SetEnabled(!GamePacker::IsPacking(gamePath_));
|
||||
|
||||
+52
-6
@@ -58,9 +58,26 @@
|
||||
#include "Core/Util/DarwinFileSystemServices.h" // For the browser
|
||||
|
||||
#include "Core/HLE/sceUmd.h"
|
||||
#include "Core/Util/PSARUnpack.h"
|
||||
|
||||
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);
|
||||
}
|
||||
screenManager->switchScreen(emuScreen);
|
||||
}
|
||||
|
||||
static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, const Path &path) {
|
||||
if (GamePacker::IsPacking(path)) {
|
||||
// Can't play it while it's read (and maybe replaced), so show its progress instead.
|
||||
@@ -87,9 +104,41 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons
|
||||
|
||||
switch (info->fileType) {
|
||||
case IdentifiedFileType::PSP_UMD_VIDEO_ISO:
|
||||
// We show info about it.
|
||||
screenManager->push(new GameScreen(path, false));
|
||||
{
|
||||
// The XMB plays it, if there's one to boot. Otherwise we show info about it.
|
||||
const Path vshPath = GetUmdVideoVSHPath();
|
||||
if (vshPath.empty()) {
|
||||
screenManager->push(new GameScreen(path, false));
|
||||
} else {
|
||||
LaunchInEmuScreen(screenManager, currentScreen, new EmuScreen(vshPath, path, true));
|
||||
}
|
||||
return;
|
||||
}
|
||||
case IdentifiedFileType::PSP_ISO:
|
||||
{
|
||||
// A disc with both a game and video on it. The XMB would start the game by itself, so for
|
||||
// the video, it comes up without auto-start and the disc waits in the Video column.
|
||||
const Path vshPath = GetUmdVideoVSHPath();
|
||||
if (vshPath.empty()) {
|
||||
break;
|
||||
}
|
||||
std::unique_ptr<FileLoader> fileLoader(ConstructFileLoader(path));
|
||||
if (!fileLoader || !(DetectUmdDiscType(fileLoader.get()) & PSP_UMD_TYPE_VIDEO)) {
|
||||
break;
|
||||
}
|
||||
auto ga = GetI18NCategory(I18NCat::GAME);
|
||||
const std::vector<std::string> choices = { std::string(ga->T("Play game")), std::string(ga->T("Watch video in the XMB")) };
|
||||
UI::ListPopupScreen *popup = new UI::ListPopupScreen(ga->T("This disc has both a game and video"), choices, -1, [=](int choice) {
|
||||
if (choice == 0) {
|
||||
LaunchInEmuScreen(screenManager, currentScreen, new EmuScreen(path));
|
||||
} else if (choice == 1) {
|
||||
LaunchInEmuScreen(screenManager, currentScreen, new EmuScreen(vshPath, path, false));
|
||||
}
|
||||
});
|
||||
popup->SetChoiceIcons({ { 0, ImageID("I_PLAY") }, { 1, ImageID("I_UMD_VIDEO_ISO") } });
|
||||
screenManager->push(popup);
|
||||
return;
|
||||
}
|
||||
case IdentifiedFileType::PSP_SAVEDATA_DIRECTORY:
|
||||
{
|
||||
// Show the savedata popup, why not?
|
||||
@@ -114,11 +163,8 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (currentScreen) {
|
||||
screenManager->cancelScreensAbove(currentScreen);
|
||||
}
|
||||
// Otherwise let the EmuScreen take care of it, including error handling.
|
||||
screenManager->switchScreen(new EmuScreen(path));
|
||||
LaunchInEmuScreen(screenManager, currentScreen, new EmuScreen(path));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,3 +136,6 @@ private:
|
||||
};
|
||||
|
||||
void LaunchBuyGold(ScreenManager *screenManager);
|
||||
|
||||
// vshmain.prx, if the installed firmware's XMB can play UMD Video discs. Empty otherwise.
|
||||
Path GetUmdVideoVSHPath();
|
||||
@@ -54,6 +54,16 @@ Two separate things:
|
||||
and the Spider-Man 2 trailer on the EUR Video Demo Disc play with sound. What that player needed
|
||||
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
|
||||
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
|
||||
without auto-start, since auto-start runs the game. The disc type comes from the fourth field of
|
||||
`UMD_DATA.BIN` (`G`, `V`, `A`), and `PSP_GAME` without `SYSDIR/EBOOT.BIN` doesn't count: some video
|
||||
discs (Spider-Man) carry a `PSP_GAME` holding only a firmware update, and reporting those as game
|
||||
discs made the XMB say "The disc could not be read."
|
||||
- **It then asked whether the region matched and we didn't answer.** `sceIoDevctl` `0x01E18030` is
|
||||
the region check, and unusually it answers through the *return value* (1 matches, 0 doesn't)
|
||||
rather than an output buffer. It was unimplemented, so the VSH read the failure as a mismatch and
|
||||
|
||||
Reference in new issue
Block a user