sdvx: remove -sdvxdisablecams, simplify camera hook (#350)

## Link to GitHub Issue, if one exists
#345

## Description of change
Simplify camera hook in SDVX5/6. Camera hook will always be installed
and return 0 cameras.

Deprecate `-sdvxdisablecams` option as it is no longer needed as a
result of this change.

## Testing
Tested SDVX5 final, SDVX6 year 1, and a recent SDVX6 build.
This commit is contained in:
bicarus-dev
2025-08-09 03:01:10 -07:00
committed by GitHub
parent e79de3b117
commit 1ad45edd6e
5 changed files with 17 additions and 129 deletions
+6 -116
View File
@@ -14,134 +14,24 @@
#include <mfidl.h> #include <mfidl.h>
#include "avs/game.h" #include "avs/game.h"
#include "hooks/cfgmgr32hook.h"
#include "util/detour.h" #include "util/detour.h"
#include "util/memutils.h"
#include "util/utils.h" #include "util/utils.h"
static VTBL_TYPE(IMFActivate, GetAllocatedString) GetAllocatedString_orig = nullptr;
static decltype(MFEnumDeviceSources) *MFEnumDeviceSources_orig = nullptr;
namespace games::sdvx { namespace games::sdvx {
static std::wstring CAMERA0_ID;
static HRESULT WINAPI GetAllocatedString_hook(IMFActivate* This, REFGUID guidKey, LPWSTR *ppwszValue,
UINT32 *pcchLength) {
// call the original
HRESULT result = GetAllocatedString_orig(This, guidKey, ppwszValue, pcchLength);
// try first camera
wchar_t *pwc = nullptr;
if (CAMERA0_ID.length() == 23)
pwc = wcsstr(*ppwszValue, CAMERA0_ID.c_str());
// check if camera could be identified
if (pwc) {
// fake the USB IDs
pwc[4] = L'2';
pwc[5] = L'8';
pwc[6] = L'8';
pwc[7] = L'c';
pwc[13] = L'0';
pwc[14] = L'0';
pwc[15] = L'0';
pwc[16] = L'2';
pwc[21] = L'0';
pwc[22] = L'0';
}
// return original result
return result;
}
static void hook_camera(IMFActivate* camera, size_t no, std::wstring camera_id, std::string camera_instance) {
// don't hook if camera 0 is already hooked
if (CAMERA0_ID.length() > 0)
return;
// save the camera ID
CAMERA0_ID = camera_id;
// cfgmgr hook
CFGMGR32_HOOK_SETTING camera_setting;
camera_setting.device_instance = 0xDEADBEEF;
camera_setting.parent_instance = ~camera_setting.device_instance;
camera_setting.device_id = "USB\\VEN_1022&DEV_7908";
camera_setting.device_node_id = "USB\\VID_288C&PID_0002&MI_00\\?&????????&?&????";
if (camera_instance.length() == 17) {
for (int i = 0; i < 17; i++) {
camera_setting.device_node_id[28 + i] = camera_instance[i];
}
}
cfgmgr32hook_add(camera_setting);
// save original method for later use
if (GetAllocatedString_orig == nullptr) {
GetAllocatedString_orig = camera->lpVtbl->GetAllocatedString;
}
// hook allocated string method for camera identification
memutils::VProtectGuard camera_guard(camera->lpVtbl);
camera->lpVtbl->GetAllocatedString = GetAllocatedString_hook;
}
static HRESULT WINAPI MFEnumDeviceSources_hook(IMFAttributes *pAttributes, IMFActivate ***pppSourceActivate, static HRESULT WINAPI MFEnumDeviceSources_hook(IMFAttributes *pAttributes, IMFActivate ***pppSourceActivate,
UINT32 *pcSourceActivate) { UINT32 *pcSourceActivate) {
// call original function *pppSourceActivate = nullptr;
HRESULT result_orig = MFEnumDeviceSources_orig(pAttributes, pppSourceActivate, pcSourceActivate); *pcSourceActivate = 0;
log_misc("sdvx", "MFEnumDeviceSources_hook called, returning 0 cameras");
// check for capture devices return S_OK;
if (FAILED(result_orig) || !*pcSourceActivate) {
return result_orig;
}
// iterate cameras
size_t cam_hook_num = 0;
for (size_t cam_num = 0; cam_num < *pcSourceActivate && cam_hook_num < 1; cam_num++) {
// flip
size_t cam_num_flipped = cam_num;
// get camera link
IMFActivate *camera = (*pppSourceActivate)[cam_num_flipped];
LPWSTR camera_link_lpwstr;
UINT32 camera_link_length;
if (SUCCEEDED(camera->lpVtbl->GetAllocatedString(
camera,
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK,
&camera_link_lpwstr,
&camera_link_length))) {
// cut name to make ID
std::wstring camera_link_ws = std::wstring(camera_link_lpwstr);
std::wstring camera_id = camera_link_ws.substr(8, 23);
// get camera instance
std::string camera_link = ws2s(camera_link_ws);
std::string camera_instance = camera_link.substr(32, 17);
// hook the camera
hook_camera(camera, cam_hook_num, camera_id, camera_instance);
// increase camera hook number
cam_hook_num++;
}
}
// return result
return result_orig;
} }
void camera_init() { void camera_init() {
// camera media framework hook // camera media framework hook
MFEnumDeviceSources_orig = detour::iat_try( log_info("sdvx", "installing camera hooks...");
"MFEnumDeviceSources", MFEnumDeviceSources_hook, avs::game::DLL_INSTANCE); detour::iat_try("MFEnumDeviceSources", MFEnumDeviceSources_hook, avs::game::DLL_INSTANCE);
} }
} }
+6 -7
View File
@@ -39,7 +39,6 @@ namespace games::sdvx {
const char *ORIGINAL_ASIO_DEVICE_NAME = "XONAR SOUND CARD(64)"; const char *ORIGINAL_ASIO_DEVICE_NAME = "XONAR SOUND CARD(64)";
// settings // settings
bool DISABLECAMS = false;
bool NATIVETOUCH = false; bool NATIVETOUCH = false;
uint8_t DIGITAL_KNOB_SENS = 16; uint8_t DIGITAL_KNOB_SENS = 16;
SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM; SdvxOverlayPosition OVERLAY_POS = SDVX_OVERLAY_BOTTOM;
@@ -369,17 +368,17 @@ namespace games::sdvx {
winuser_hook_init(avs::game::DLL_INSTANCE); winuser_hook_init(avs::game::DLL_INSTANCE);
// hook camera // hook camera
if (!DISABLECAMS) { camera_init();
camera_init();
}
// RGB CAMERA error ignore // RGB CAMERA error ignore for SDVX5
if (!replace_pattern( // SDVX5: boot sequence triggers camera error if camera is not detected
// SDVX6: boots fine, but game title screen in attract loop will have camera error (cosmetic only)
if (replace_pattern(
avs::game::DLL_INSTANCE, avs::game::DLL_INSTANCE,
"418D480484C074218D51FD", "418D480484C074218D51FD",
"????????????9090??????", "????????????9090??????",
0, 0)) { 0, 0)) {
log_info("sdvx", "did not find matching signature for camera error patch"); log_info("sdvx", "applied camera error patch (sdvx5)");
} }
// remove log spam // remove log spam
-1
View File
@@ -17,7 +17,6 @@ namespace games::sdvx {
}; };
// settings // settings
extern bool DISABLECAMS;
extern bool NATIVETOUCH; extern bool NATIVETOUCH;
extern uint8_t DIGITAL_KNOB_SENS; extern uint8_t DIGITAL_KNOB_SENS;
extern std::optional<std::string> ASIO_DRIVER; extern std::optional<std::string> ASIO_DRIVER;
-3
View File
@@ -433,9 +433,6 @@ int main_implementation(int argc, char *argv[]) {
if (options[launcher::Options::LoadSoundVoltexModule].value_bool()) { if (options[launcher::Options::LoadSoundVoltexModule].value_bool()) {
attach_sdvx = true; attach_sdvx = true;
} }
if (options[launcher::Options::SDVXDisableCameras].value_bool()) {
games::sdvx::DISABLECAMS = true;
}
if (options[launcher::Options::SDVXNativeTouch].value_bool()) { if (options[launcher::Options::SDVXNativeTouch].value_bool()) {
games::sdvx::NATIVETOUCH = true; games::sdvx::NATIVETOUCH = true;
} }
+5 -2
View File
@@ -717,10 +717,13 @@ static const std::vector<OptionDefinition> OPTION_DEFINITIONS = {
.category = "Game Options (Advanced)", .category = "Game Options (Advanced)",
}, },
{ {
.title = "SDVX Disable Cameras", .title = "SDVX Disable Cameras (DEPRECATED - no longer needed)",
.name = "sdvxdisablecams", .name = "sdvxdisablecams",
.desc = "Disables cameras", .desc = "This option does nothing.\n\n"
"This option was used in the past to fix cameras in SDVX5 but this is no longer "
"needed as camera check will always be skipped with a built-in patch.",
.type = OptionType::Bool, .type = OptionType::Bool,
.hidden = true,
.game_name = "Sound Voltex", .game_name = "Sound Voltex",
.category = "Game Options", .category = "Game Options",
}, },