Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force Display Capture #148

Merged
merged 5 commits into from
Oct 14, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions Classes/Recorders/LibObsRecorder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -258,33 +258,42 @@ public override async Task<bool> StartRecording() {
}
}

// SETUP NEW VIDEO SOURCE
// - Create a source for the game_capture in channel 0
IntPtr videoSourceSettings = obs_data_create();
obs_data_set_string(videoSourceSettings, "capture_mode", IsFullscreen(windowHandle) ? "any_fullscreen" : "window");
obs_data_set_string(videoSourceSettings, "window", windowClassNameId);
videoSources.TryAdd("gameplay", obs_source_create("game_capture", "gameplay", videoSourceSettings, IntPtr.Zero));
obs_data_release(videoSourceSettings);

// SETUP VIDEO ENCODER
string encoder = SettingsService.Settings.captureSettings.encoder;
string rateControl = SettingsService.Settings.captureSettings.rateControl;
string fileFormat = SettingsService.Settings.captureSettings.fileFormat.format;
videoEncoders.TryAdd(encoder, GetVideoEncoder(encoder, rateControl, fileFormat));
obs_encoder_set_video(videoEncoders[encoder], obs_get_video());
obs_set_output_source(0, videoSources["gameplay"]);

// attempt to wait for game_capture source to hook first
retryAttempt = 0;
Logger.WriteLine($"Waiting for successful graphics hook for [{windowClassNameId}]...");
while (signalGCHookSuccess == false && retryAttempt < Math.Min(maxRetryAttempts + signalGCHookAttempt, 30)) {
await Task.Delay(retryInterval);
retryAttempt++;
if (session.ForceDisplayCapture == false) {
// SETUP NEW VIDEO SOURCE
// - Create a source for the game_capture in channel 0
IntPtr videoSourceSettings = obs_data_create();
obs_data_set_string(videoSourceSettings, "capture_mode", IsFullscreen(windowHandle) ? "any_fullscreen" : "window");
obs_data_set_string(videoSourceSettings, "window", windowClassNameId);
videoSources.TryAdd("gameplay", obs_source_create("game_capture", "gameplay", videoSourceSettings, IntPtr.Zero));
obs_data_release(videoSourceSettings);

// SETUP VIDEO ENCODER
videoEncoders.TryAdd(encoder, GetVideoEncoder(encoder, rateControl, fileFormat));
obs_encoder_set_video(videoEncoders[encoder], obs_get_video());
obs_set_output_source(0, videoSources["gameplay"]);

// attempt to wait for game_capture source to hook first
retryAttempt = 0;
Logger.WriteLine($"Waiting for successful graphics hook for [{windowClassNameId}]...");
while (signalGCHookSuccess == false && retryAttempt < Math.Min(maxRetryAttempts + signalGCHookAttempt, 30)) {
await Task.Delay(retryInterval);
retryAttempt++;
}
}
else {
videoEncoders.TryAdd(encoder, GetVideoEncoder(encoder, rateControl, fileFormat));
obs_encoder_set_video(videoEncoders[encoder], obs_get_video());
}
signalGCHookAttempt = 0;

if (signalGCHookSuccess == false) {
Logger.WriteLine($"Unable to get graphics hook for [{windowClassNameId}] after {retryAttempt} attempts");
if (session.ForceDisplayCapture == false) {
Logger.WriteLine($"Unable to get graphics hook for [{windowClassNameId}] after {retryAttempt} attempts");
}

Process process;

Expand Down
26 changes: 17 additions & 9 deletions Classes/Services/DetectionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static class DetectionService {
static readonly string gameDetectionsFile = Path.Join(GetCfgFolder(), "gameDetections.json");
static readonly string nonGameDetectionsFile = Path.Join(GetCfgFolder(), "nonGameDetections.json");
private static Dictionary<string, string> drivePaths = new();
private static List<string> classBlacklist = new() { "splashscreen", "launcher", "cheat", "sdl_app", "console" };
private static List<string> classBlacklist = new() { "splashscreen", "launcher", "cheat", "console" };
private static List<string> classWhitelist = new() { "unitywndclass", "unrealwindow", "riotwindowclass" };
public static bool IsStarted { get; internal set; }

Expand Down Expand Up @@ -235,6 +235,13 @@ public static void LoadDetections() {

public static JsonElement[] DownloadDetections(string dlPath, string file) {
var result = "[]";

#if DEBUG
dlPath = Path.Join(Directory.GetParent(Environment.CurrentDirectory).Parent.Parent.FullName, @"Resources/detections/", file);
Logger.WriteLine($"Debug: Using {file} from Resources folder instead.");
return JsonDocument.Parse(File.ReadAllText(dlPath)).RootElement.EnumerateArray().ToArray();
#endif

try {
// check if current file sha matches remote or not, if it does, we are already up-to-date
if (File.Exists(dlPath)) {
Expand Down Expand Up @@ -371,7 +378,8 @@ public static bool AutoDetectGame(int processId, string executablePath, nint win
$"[{className}]" +
$"[{executablePath}]"
);
RecordingService.SetCurrentSession(processId, windowHandle, gameTitle, executablePath);
bool forceDisplayCapture = gameDetection.forceDisplayCapture;
RecordingService.SetCurrentSession(processId, windowHandle, gameTitle, executablePath, forceDisplayCapture);
if (allowed) RecordingService.StartRecording();
}
return isGame;
Expand All @@ -384,11 +392,11 @@ public static bool HasBadWordInClassName(IntPtr windowHandle) {
return windowHandle == IntPtr.Zero;
}

public static (bool isGame, string gameTitle) IsMatchedGame(string exeFile) {
public static (bool isGame, bool forceDisplayCapture, string gameTitle) IsMatchedGame(string exeFile) {
foreach (var game in SettingsService.Settings.detectionSettings.whitelist) {
if (game.gameExe == exeFile) return (true, game.gameName);
if (game.gameExe == exeFile) return (true, false, game.gameName);
}
if (SettingsService.Settings.captureSettings.recordingMode == "whitelist") return (false, "Whitelist Mode");
if (SettingsService.Settings.captureSettings.recordingMode == "whitelist") return (false, false, "Whitelist Mode");

try {
for (int x = 0; x < gameDetectionsJson.Length; x++) {
Expand All @@ -411,14 +419,14 @@ public static (bool isGame, string gameTitle) IsMatchedGame(string exeFile) {
exePattern = exePatterns[z].Split('/').Last();
if (exePatterns[z].Length > 0 && Regex.IsMatch(exeFile, "^" + exePattern + "$", RegexOptions.IgnoreCase)) {
Logger.WriteLine($"Regex Matched: input=\"{exeFile}\", pattern=\"^{exePattern}\"$");
return (true, gameDetectionsJson[x].GetProperty("title").ToString());
return (true, gameDetectionsJson[x].GetProperty("force_display_capture").GetBoolean(), gameDetectionsJson[x].GetProperty("title").ToString());
}
}
}
else {
if (Regex.IsMatch(exeFile, exePattern, RegexOptions.IgnoreCase)) {
Logger.WriteLine($"Regex Matched: input=\"{exeFile}\", pattern=\"{exePattern}\"");
return (true, gameDetectionsJson[x].GetProperty("title").ToString());
return (true, gameDetectionsJson[x].GetProperty("force_display_capture").GetBoolean(), gameDetectionsJson[x].GetProperty("title").ToString());
}
}
}
Expand All @@ -431,8 +439,8 @@ public static (bool isGame, string gameTitle) IsMatchedGame(string exeFile) {

// TODO: also parse Epic games/Origin games
if (exeFile.Replace("\\", "/").Contains("/steamapps/common/"))
return (true, Regex.Split(exeFile.Replace("\\", "/"), "/steamapps/common/", RegexOptions.IgnoreCase)[1].Split('/')[0]);
return (false, "Game Unknown");
return (true, false, Regex.Split(exeFile.Replace("\\", "/"), "/steamapps/common/", RegexOptions.IgnoreCase)[1].Split('/')[0]);
return (false, false, "Game Unknown");
}

public static bool IsMatchedNonGame(string executablePath) {
Expand Down
8 changes: 5 additions & 3 deletions Classes/Services/RecordingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@ public class Session {
public nint WindowHandle { get; internal set; }
public string GameTitle { get; internal set; }
public string Exe { get; internal set; }
public Session(int _Pid, nint _WindowHandle, string _GameTitle, string _Exe = null) {
public bool ForceDisplayCapture { get; internal set; }
public Session(int _Pid, nint _WindowHandle, string _GameTitle, string _Exe = null, bool _ForceDisplayCapture = false) {
Pid = _Pid;
WindowHandle = _WindowHandle;
GameTitle = _GameTitle;
Exe = _Exe;
ForceDisplayCapture = _ForceDisplayCapture;
}
}

Expand All @@ -46,8 +48,8 @@ public static async void Start(Type type) {
await Task.Run(() => DetectionService.CheckAlreadyRunningPrograms());
}

public static void SetCurrentSession(int _Pid, nint _WindowHandle, string _GameTitle, string exeFile) {
currentSession = new Session(_Pid, _WindowHandle, _GameTitle, exeFile);
public static void SetCurrentSession(int _Pid, nint _WindowHandle, string _GameTitle, string exeFile, bool forceDisplayCapture = false) {
currentSession = new Session(_Pid, _WindowHandle, _GameTitle, exeFile, forceDisplayCapture);
}

public static Session GetCurrentSession() {
Expand Down
Loading