record-daemon: obs-context refactoring, gpu detection code
Some checks failed
record-daemon / Build, check and test (push) Failing after 48s
Some checks failed
record-daemon / Build, check and test (push) Failing after 48s
This commit is contained in:
13
record-daemon/Cargo.lock
generated
13
record-daemon/Cargo.lock
generated
@@ -2439,6 +2439,7 @@ dependencies = [
|
|||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"uuid",
|
"uuid",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
|
"winreg 0.56.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2548,7 +2549,7 @@ dependencies = [
|
|||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots 0.25.4",
|
"webpki-roots 0.25.4",
|
||||||
"winreg",
|
"winreg 0.50.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4525,6 +4526,16 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.56.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7d6f32a0ff4a9f6f01231eb2059cc85479330739333e0e58cadf03b6af2cca10"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.4",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen"
|
name = "wit-bindgen"
|
||||||
version = "0.51.0"
|
version = "0.51.0"
|
||||||
|
|||||||
@@ -77,7 +77,8 @@ signal-hook-tokio = { version = "0.4", features = ["futures-v0_3"] }
|
|||||||
|
|
||||||
# Windows-specific dependencies
|
# Windows-specific dependencies
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3", features = ["winuser"] }
|
winapi = { version = "0.3", features = ["winuser", "winreg", "winnt"] }
|
||||||
|
winreg = "0.56"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Testing utilities
|
# Testing utilities
|
||||||
|
|||||||
@@ -221,15 +221,11 @@ impl Daemon {
|
|||||||
|
|
||||||
/// Handle a game event.
|
/// Handle a game event.
|
||||||
async fn handle_game_event(&self, event: GameEvent) -> Result<()> {
|
async fn handle_game_event(&self, event: GameEvent) -> Result<()> {
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
info!("[EVENT_HANDLER] Game event received: {:?}", event);
|
info!("[EVENT_HANDLER] Game event received: {:?}", event);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Process state transitions
|
// Process state transitions
|
||||||
if let Some(transition) = self.state_machine.process_event(&event) {
|
if let Some(transition) = self.state_machine.process_event(&event) {
|
||||||
info!("[EVENT_HANDLER] State transition: {:?}", transition);
|
info!("[EVENT_HANDLER] State transition: {:?}", transition);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
self.state_machine.transition(transition.clone());
|
self.state_machine.transition(transition.clone());
|
||||||
|
|
||||||
@@ -240,22 +236,19 @@ impl Daemon {
|
|||||||
"[EVENT_HANDLER] GameStarted transition - game_id: {}, champion: {:?}",
|
"[EVENT_HANDLER] GameStarted transition - game_id: {}, champion: {:?}",
|
||||||
game_id, champion
|
game_id, champion
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// If already recording, stop the current recording first
|
// If already recording, stop the current recording first
|
||||||
if self.state_machine.is_recording() {
|
if self.state_machine.is_recording() {
|
||||||
info!(
|
info!(
|
||||||
"[EVENT_HANDLER] Stopping previous recording before starting new one"
|
"[EVENT_HANDLER] Stopping previous recording before starting new one"
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
if let Err(e) = self.stop_recording().await {
|
if let Err(e) = self.stop_recording().await {
|
||||||
warn!("[EVENT_HANDLER] Failed to stop previous recording: {}", e);
|
warn!("[EVENT_HANDLER] Failed to stop previous recording: {}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("[EVENT_HANDLER] Calling start_recording...");
|
info!("[EVENT_HANDLER] Calling start_recording...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Wrap the start_recording call to catch any panics
|
// Wrap the start_recording call to catch any panics
|
||||||
let start_result =
|
let start_result =
|
||||||
@@ -269,7 +262,7 @@ impl Daemon {
|
|||||||
"[EVENT_HANDLER] PANIC before start_recording: {:?}",
|
"[EVENT_HANDLER] PANIC before start_recording: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[EVENT_HANDLER] PANIC before start_recording: {:?}",
|
"[EVENT_HANDLER] PANIC before start_recording: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -278,20 +271,18 @@ impl Daemon {
|
|||||||
|
|
||||||
if let Err(e) = self.start_recording(game_id, champion.as_deref()).await {
|
if let Err(e) = self.start_recording(game_id, champion.as_deref()).await {
|
||||||
error!("[EVENT_HANDLER] Failed to start recording: {}", e);
|
error!("[EVENT_HANDLER] Failed to start recording: {}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
// Don't propagate error - keep daemon running
|
// Don't propagate error - keep daemon running
|
||||||
} else {
|
} else {
|
||||||
info!("[EVENT_HANDLER] start_recording completed successfully");
|
info!("[EVENT_HANDLER] start_recording completed successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StateTransition::GameEnded => {
|
StateTransition::GameEnded => {
|
||||||
info!("[EVENT_HANDLER] GameEnded transition");
|
info!("[EVENT_HANDLER] GameEnded transition");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
if let Err(e) = self.stop_recording().await {
|
if let Err(e) = self.stop_recording().await {
|
||||||
error!("[EVENT_HANDLER] Failed to stop recording: {}", e);
|
error!("[EVENT_HANDLER] Failed to stop recording: {}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
// Don't propagate error - keep daemon running
|
// Don't propagate error - keep daemon running
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -311,7 +302,7 @@ impl Daemon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("[EVENT_HANDLER] Event handling complete");
|
info!("[EVENT_HANDLER] Event handling complete");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,11 +491,10 @@ async fn main() -> Result<()> {
|
|||||||
// Create and run daemon
|
// Create and run daemon
|
||||||
let mut daemon = Daemon::new(settings);
|
let mut daemon = Daemon::new(settings);
|
||||||
|
|
||||||
// Handle shutdown signals
|
|
||||||
let shutdown_tx = daemon.shutdown_tx.clone();
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
|
// Handle shutdown signals
|
||||||
|
let shutdown_tx = daemon.shutdown_tx.clone();
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use signal_hook::consts::signal::*;
|
use signal_hook::consts::signal::*;
|
||||||
use signal_hook_tokio::Signals;
|
use signal_hook_tokio::Signals;
|
||||||
|
|||||||
@@ -294,11 +294,9 @@ impl EncoderCapability {
|
|||||||
///
|
///
|
||||||
/// This function checks the system for available GPU encoders.
|
/// This function checks the system for available GPU encoders.
|
||||||
pub fn detect_hardware_encoders() -> Vec<EncoderCapability> {
|
pub fn detect_hardware_encoders() -> Vec<EncoderCapability> {
|
||||||
use std::io::Write;
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
info!("[ENCODER_DETECT] Starting hardware encoder detection...");
|
info!("[ENCODER_DETECT] Starting hardware encoder detection...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let mut capabilities = Vec::new();
|
let mut capabilities = Vec::new();
|
||||||
|
|
||||||
@@ -322,7 +320,7 @@ pub fn detect_hardware_encoders() -> Vec<EncoderCapability> {
|
|||||||
// On Windows, check for NVIDIA first
|
// On Windows, check for NVIDIA first
|
||||||
// Try to load nvenc DLL
|
// Try to load nvenc DLL
|
||||||
info!("[ENCODER_DETECT] Checking for NVENC...");
|
info!("[ENCODER_DETECT] Checking for NVENC...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
if is_nvenc_available() {
|
if is_nvenc_available() {
|
||||||
info!("[ENCODER_DETECT] NVENC available");
|
info!("[ENCODER_DETECT] NVENC available");
|
||||||
capabilities.push(EncoderCapability::Nvenc);
|
capabilities.push(EncoderCapability::Nvenc);
|
||||||
@@ -332,7 +330,7 @@ pub fn detect_hardware_encoders() -> Vec<EncoderCapability> {
|
|||||||
|
|
||||||
// Check for AMD AMF
|
// Check for AMD AMF
|
||||||
info!("[ENCODER_DETECT] Checking for AMF...");
|
info!("[ENCODER_DETECT] Checking for AMF...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
if is_amf_available() {
|
if is_amf_available() {
|
||||||
info!("[ENCODER_DETECT] AMF available");
|
info!("[ENCODER_DETECT] AMF available");
|
||||||
capabilities.push(EncoderCapability::Amf);
|
capabilities.push(EncoderCapability::Amf);
|
||||||
@@ -342,7 +340,7 @@ pub fn detect_hardware_encoders() -> Vec<EncoderCapability> {
|
|||||||
|
|
||||||
// Check for Intel QuickSync
|
// Check for Intel QuickSync
|
||||||
info!("[ENCODER_DETECT] Checking for QuickSync...");
|
info!("[ENCODER_DETECT] Checking for QuickSync...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
if is_quicksync_available() {
|
if is_quicksync_available() {
|
||||||
info!("[ENCODER_DETECT] QuickSync available");
|
info!("[ENCODER_DETECT] QuickSync available");
|
||||||
capabilities.push(EncoderCapability::QuickSync);
|
capabilities.push(EncoderCapability::QuickSync);
|
||||||
@@ -356,31 +354,200 @@ pub fn detect_hardware_encoders() -> Vec<EncoderCapability> {
|
|||||||
capabilities.push(EncoderCapability::Software);
|
capabilities.push(EncoderCapability::Software);
|
||||||
|
|
||||||
info!("[ENCODER_DETECT] Detected encoders: {:?}", capabilities);
|
info!("[ENCODER_DETECT] Detected encoders: {:?}", capabilities);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
capabilities
|
capabilities
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GPU vendor type for encoder detection.
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
enum GpuVendor {
|
||||||
|
Nvidia,
|
||||||
|
Amd,
|
||||||
|
Intel,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Detect GPU vendors by querying Windows registry.
|
||||||
|
/// This is more reliable than checking for specific DLL paths.
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn detect_gpu_vendors() -> Vec<GpuVendor> {
|
||||||
|
use tracing::info;
|
||||||
|
use winreg::enums::HKEY_LOCAL_MACHINE;
|
||||||
|
use winreg::RegKey;
|
||||||
|
|
||||||
|
let mut vendors = Vec::new();
|
||||||
|
|
||||||
|
// Display adapter class GUID in Windows registry
|
||||||
|
const DISPLAY_ADAPTER_CLASS: &str =
|
||||||
|
r"SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}";
|
||||||
|
|
||||||
|
info!("[ENCODER_DETECT] Querying Windows registry for GPU vendors...");
|
||||||
|
|
||||||
|
// Open the display adapter class key
|
||||||
|
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||||
|
|
||||||
|
let class_key = match hklm.open_subkey(DISPLAY_ADAPTER_CLASS) {
|
||||||
|
Ok(key) => key,
|
||||||
|
Err(e) => {
|
||||||
|
info!(
|
||||||
|
"[ENCODER_DETECT] Failed to open display adapter registry key: {}",
|
||||||
|
e
|
||||||
|
);
|
||||||
|
return vendors;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enumerate subkeys (each subkey is a display adapter)
|
||||||
|
for subkey_name in class_key.enum_keys().filter_map(|k| k.ok()) {
|
||||||
|
if let Ok(adapter_key) = class_key.open_subkey(&subkey_name) {
|
||||||
|
// Read ProviderName
|
||||||
|
if let Ok(provider) = adapter_key.get_value::<String, _>("ProviderName") {
|
||||||
|
info!("[ENCODER_DETECT] Found GPU provider: {}", provider);
|
||||||
|
|
||||||
|
let provider_lower = provider.to_lowercase();
|
||||||
|
if provider_lower.contains("nvidia") && !vendors.contains(&GpuVendor::Nvidia) {
|
||||||
|
vendors.push(GpuVendor::Nvidia);
|
||||||
|
} else if (provider_lower.contains("amd")
|
||||||
|
|| provider_lower.contains("advanced micro devices")
|
||||||
|
|| provider_lower.contains("radeon"))
|
||||||
|
&& !vendors.contains(&GpuVendor::Amd)
|
||||||
|
{
|
||||||
|
vendors.push(GpuVendor::Amd);
|
||||||
|
} else if provider_lower.contains("intel") && !vendors.contains(&GpuVendor::Intel) {
|
||||||
|
vendors.push(GpuVendor::Intel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("[ENCODER_DETECT] Detected GPU vendors: {:?}", vendors);
|
||||||
|
vendors
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if NVIDIA NVENC is available.
|
/// Check if NVIDIA NVENC is available.
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn is_nvenc_available() -> bool {
|
fn is_nvenc_available() -> bool {
|
||||||
// Check for NVENC DLL
|
use tracing::info;
|
||||||
std::path::Path::new("C:\\Windows\\System32\\nvEncMFTH264.dll").exists()
|
use winreg::enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE};
|
||||||
|| std::path::Path::new("C:\\Windows\\System32\\nvEncMFTH265.dll").exists()
|
use winreg::RegKey;
|
||||||
|
|
||||||
|
// First check if NVIDIA GPU is present via registry
|
||||||
|
let vendors = detect_gpu_vendors();
|
||||||
|
if !vendors.contains(&GpuVendor::Nvidia) {
|
||||||
|
info!("[ENCODER_DETECT] No NVIDIA GPU detected via registry");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NVIDIA GPU found, now check for NVENC support
|
||||||
|
// NVENC is available on most modern NVIDIA GPUs (GTX 600+ and all RTX cards)
|
||||||
|
// We can verify by checking if nvEncAPI is loadable or by checking registry
|
||||||
|
|
||||||
|
// Check for NVENC capability in registry (NVIDIA stores encoder info here)
|
||||||
|
const NVENC_REGISTRY_PATH: &str = r"SOFTWARE\NVIDIA Corporation\Global\NvEnc";
|
||||||
|
|
||||||
|
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||||
|
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||||
|
|
||||||
|
// Try HKCU first
|
||||||
|
if hkcu.open_subkey(NVENC_REGISTRY_PATH).is_ok() {
|
||||||
|
info!("[ENCODER_DETECT] NVENC registry key found (HKCU)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try HKLM
|
||||||
|
if hklm.open_subkey(NVENC_REGISTRY_PATH).is_ok() {
|
||||||
|
info!("[ENCODER_DETECT] NVENC registry key found (HKLM)");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If NVIDIA GPU is present, assume NVENC is available
|
||||||
|
// Modern NVIDIA GPUs (GTX 600 series and newer) all have NVENC
|
||||||
|
// This is a reasonable fallback since the registry check might not work on all systems
|
||||||
|
info!("[ENCODER_DETECT] NVIDIA GPU detected, assuming NVENC available");
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if AMD AMF is available.
|
/// Check if AMD AMF is available.
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn is_amf_available() -> bool {
|
fn is_amf_available() -> bool {
|
||||||
// Check for AMF runtime
|
use tracing::info;
|
||||||
std::path::Path::new("C:\\Windows\\System32\\amdocl64.dll").exists()
|
use winreg::enums::HKEY_LOCAL_MACHINE;
|
||||||
|
use winreg::RegKey;
|
||||||
|
|
||||||
|
// Check if AMD GPU is present via registry
|
||||||
|
let vendors = detect_gpu_vendors();
|
||||||
|
if !vendors.contains(&GpuVendor::Amd) {
|
||||||
|
info!("[ENCODER_DETECT] No AMD GPU detected via registry");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AMD GPU found, check for AMF runtime
|
||||||
|
// AMF is available on modern AMD GPUs (RX 400+ and some older cards)
|
||||||
|
|
||||||
|
// Check for AMF runtime in registry
|
||||||
|
const AMF_REGISTRY_PATH: &str = r"SOFTWARE\AMD\AMF";
|
||||||
|
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||||
|
|
||||||
|
if hklm.open_subkey(AMF_REGISTRY_PATH).is_ok() {
|
||||||
|
info!("[ENCODER_DETECT] AMF registry key found");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: check for amdocl64.dll or amfrt64.dll in system
|
||||||
|
let system32 = std::env::var("SystemRoot").unwrap_or_else(|_| "C:\\Windows".to_string());
|
||||||
|
let amdocl_path = format!("{}\\System32\\amdocl64.dll", system32);
|
||||||
|
let amfrt_path = format!("{}\\System32\\amfrt64.dll", system32);
|
||||||
|
|
||||||
|
if std::path::Path::new(&amdocl_path).exists() || std::path::Path::new(&amfrt_path).exists() {
|
||||||
|
info!("[ENCODER_DETECT] AMF DLL found");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If AMD GPU is present, assume AMF is available on modern cards
|
||||||
|
info!("[ENCODER_DETECT] AMD GPU detected, assuming AMF available");
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if Intel QuickSync is available.
|
/// Check if Intel QuickSync is available.
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn is_quicksync_available() -> bool {
|
fn is_quicksync_available() -> bool {
|
||||||
// Check for Intel Media SDK
|
use tracing::info;
|
||||||
std::path::Path::new("C:\\Windows\\System32\\mfx64.dll").exists()
|
|
||||||
|
// Check if Intel GPU is present via registry
|
||||||
|
let vendors = detect_gpu_vendors();
|
||||||
|
if !vendors.contains(&GpuVendor::Intel) {
|
||||||
|
info!("[ENCODER_DETECT] No Intel GPU detected via registry");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intel GPU found, check for QuickSync (Intel Media SDK / oneVPL)
|
||||||
|
// QuickSync is available on Intel CPUs with integrated graphics (Sandy Bridge and newer)
|
||||||
|
|
||||||
|
// Check for Intel Media SDK or oneVPL
|
||||||
|
let system32 = std::env::var("SystemRoot").unwrap_or_else(|_| "C:\\Windows".to_string());
|
||||||
|
let mfx_path = format!("{}\\System32\\mfx64.dll", system32);
|
||||||
|
let vpl_path = format!("{}\\System32\\libmfx64.dll", system32);
|
||||||
|
|
||||||
|
if std::path::Path::new(&mfx_path).exists() || std::path::Path::new(&vpl_path).exists() {
|
||||||
|
info!("[ENCODER_DETECT] Intel Media SDK DLL found");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for oneVPL runtime
|
||||||
|
const VPL_REGISTRY_PATH: &str = r"SOFTWARE\Intel\oneVPL";
|
||||||
|
use winreg::enums::HKEY_LOCAL_MACHINE;
|
||||||
|
use winreg::RegKey;
|
||||||
|
let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);
|
||||||
|
|
||||||
|
if hklm.open_subkey(VPL_REGISTRY_PATH).is_ok() {
|
||||||
|
info!("[ENCODER_DETECT] oneVPL registry key found");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Intel GPU is present, assume QuickSync might be available
|
||||||
|
// Note: Not all Intel GPUs have QuickSync (some low-end chips don't)
|
||||||
|
info!("[ENCODER_DETECT] Intel GPU detected, assuming QuickSync available");
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the best available encoder capability.
|
/// Get the best available encoder capability.
|
||||||
|
|||||||
@@ -142,18 +142,16 @@ impl ObsContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
info!("[OBS_INIT] Starting OBS context initialization...");
|
info!("[OBS_INIT] Starting OBS context initialization...");
|
||||||
use std::io::Write;
|
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Pre-flight checks for OBS
|
// Pre-flight checks for OBS
|
||||||
self.preflight_checks()?;
|
self.preflight_checks()?;
|
||||||
|
|
||||||
// Detect best available encoder
|
// Detect best available encoder
|
||||||
info!("[OBS_INIT] Detecting best available encoder...");
|
info!("[OBS_INIT] Detecting best available encoder...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let encoder = best_available_encoder();
|
let encoder = best_available_encoder();
|
||||||
info!("[OBS_INIT] Detected encoder: {}", encoder.name());
|
info!("[OBS_INIT] Detected encoder: {}", encoder.name());
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
self.encoder_capability = Some(encoder);
|
self.encoder_capability = Some(encoder);
|
||||||
|
|
||||||
let (width, height) = self.video_settings.quality.resolution();
|
let (width, height) = self.video_settings.quality.resolution();
|
||||||
@@ -163,11 +161,10 @@ impl ObsContext {
|
|||||||
"[OBS_INIT] OBS video config: {}x{} @ {}fps",
|
"[OBS_INIT] OBS video config: {}x{} @ {}fps",
|
||||||
width, height, fps
|
width, height, fps
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Create startup info with video configuration
|
// Create startup info with video configuration
|
||||||
info!("[OBS_INIT] Creating OBS video info builder...");
|
info!("[OBS_INIT] Creating OBS video info builder...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let video_info = ObsVideoInfoBuilder::new()
|
let video_info = ObsVideoInfoBuilder::new()
|
||||||
.fps_num(fps)
|
.fps_num(fps)
|
||||||
.fps_den(1)
|
.fps_den(1)
|
||||||
@@ -177,10 +174,8 @@ impl ObsContext {
|
|||||||
.output_height(height)
|
.output_height(height)
|
||||||
.build();
|
.build();
|
||||||
info!("[OBS_INIT] OBS video info built successfully");
|
info!("[OBS_INIT] OBS video info built successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
info!("[OBS_INIT] Building OBS context with LibObsContext::builder()...");
|
info!("[OBS_INIT] Building OBS context with LibObsContext::builder()...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let compat = LibObsContext::check_version_compatibility();
|
let compat = LibObsContext::check_version_compatibility();
|
||||||
if !compat {
|
if !compat {
|
||||||
@@ -196,12 +191,12 @@ impl ObsContext {
|
|||||||
let context = match context_result {
|
let context = match context_result {
|
||||||
Ok(Ok(ctx)) => {
|
Ok(Ok(ctx)) => {
|
||||||
info!("[OBS_INIT] OBS context created successfully");
|
info!("[OBS_INIT] OBS context created successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
error!("[OBS_INIT] Failed to create OBS context: {:?}", e);
|
error!("[OBS_INIT] Failed to create OBS context: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::ObsInitError(format!(
|
return Err(RecordingError::ObsInitError(format!(
|
||||||
"Failed to create OBS context: {:?}",
|
"Failed to create OBS context: {:?}",
|
||||||
e
|
e
|
||||||
@@ -213,7 +208,7 @@ impl ObsContext {
|
|||||||
"[OBS_INIT] PANIC during OBS context creation: {:?}",
|
"[OBS_INIT] PANIC during OBS context creation: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[OBS_INIT] PANIC during OBS context creation: {:?}",
|
"[OBS_INIT] PANIC during OBS context creation: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -234,41 +229,34 @@ impl ObsContext {
|
|||||||
|
|
||||||
self.context = Some(context);
|
self.context = Some(context);
|
||||||
info!("[OBS_INIT] OBS context initialized successfully");
|
info!("[OBS_INIT] OBS context initialized successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pre-flight checks for OBS initialization.
|
/// Pre-flight checks for OBS initialization.
|
||||||
fn preflight_checks(&self) -> Result<()> {
|
fn preflight_checks(&self) -> Result<()> {
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
info!("[PREFLIGHT] Running OBS pre-flight checks...");
|
info!("[PREFLIGHT] Running OBS pre-flight checks...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Check for OBS installation directory
|
// Check for OBS installation directory
|
||||||
// libobs-bootstrapper typically extracts OBS to a specific location
|
// libobs-bootstrapper typically extracts OBS to a specific location
|
||||||
let obs_paths = self.get_obs_search_paths();
|
let obs_paths = self.get_obs_search_paths();
|
||||||
|
|
||||||
info!("[PREFLIGHT] OBS search paths: {:?}", obs_paths);
|
info!("[PREFLIGHT] OBS search paths: {:?}", obs_paths);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let mut obs_found = false;
|
let mut obs_found = false;
|
||||||
for path in &obs_paths {
|
for path in &obs_paths {
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
info!("[PREFLIGHT] Found OBS at: {:?}", path);
|
info!("[PREFLIGHT] Found OBS at: {:?}", path);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Check for plugins directory
|
// Check for plugins directory
|
||||||
let plugins_path = path.join("obs-plugins");
|
let plugins_path = path.join("obs-plugins");
|
||||||
if plugins_path.exists() {
|
if plugins_path.exists() {
|
||||||
info!("[PREFLIGHT] Found OBS plugins at: {:?}", plugins_path);
|
info!("[PREFLIGHT] Found OBS plugins at: {:?}", plugins_path);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Check for 64-bit plugins
|
// Check for 64-bit plugins
|
||||||
let plugins_64 = plugins_path.join("64bit");
|
let plugins_64 = plugins_path.join("64bit");
|
||||||
if plugins_64.exists() {
|
if plugins_64.exists() {
|
||||||
info!("[PREFLIGHT] Found 64-bit plugins at: {:?}", plugins_64);
|
info!("[PREFLIGHT] Found 64-bit plugins at: {:?}", plugins_64);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// List available plugins
|
// List available plugins
|
||||||
if let Ok(entries) = std::fs::read_dir(&plugins_64) {
|
if let Ok(entries) = std::fs::read_dir(&plugins_64) {
|
||||||
@@ -277,7 +265,6 @@ impl ObsContext {
|
|||||||
.filter_map(|e| e.file_name().to_str().map(|s| s.to_string()))
|
.filter_map(|e| e.file_name().to_str().map(|s| s.to_string()))
|
||||||
.collect();
|
.collect();
|
||||||
info!("[PREFLIGHT] Available plugins: {:?}", plugins);
|
info!("[PREFLIGHT] Available plugins: {:?}", plugins);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,14 +278,12 @@ impl ObsContext {
|
|||||||
warn!(
|
warn!(
|
||||||
"[PREFLIGHT] OBS installation not found in standard paths - this may cause issues"
|
"[PREFLIGHT] OBS installation not found in standard paths - this may cause issues"
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for display (required for capture)
|
// Check for display (required for capture)
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
{
|
{
|
||||||
info!("[PREFLIGHT] Checking for display availability...");
|
info!("[PREFLIGHT] Checking for display availability...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// On Windows, check if we have a display
|
// On Windows, check if we have a display
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
@@ -311,11 +296,10 @@ impl ObsContext {
|
|||||||
winapi::um::winuser::ReleaseDC(ptr::null_mut(), dc);
|
winapi::um::winuser::ReleaseDC(ptr::null_mut(), dc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("[PREFLIGHT] Pre-flight checks completed");
|
info!("[PREFLIGHT] Pre-flight checks completed");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -357,13 +341,10 @@ impl ObsContext {
|
|||||||
|
|
||||||
/// Start recording to the specified output path.
|
/// Start recording to the specified output path.
|
||||||
pub fn start_recording(&mut self, output_path: &Path) -> Result<()> {
|
pub fn start_recording(&mut self, output_path: &Path) -> Result<()> {
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"[START_REC] start_recording called with path: {:?}",
|
"[START_REC] start_recording called with path: {:?}",
|
||||||
output_path
|
output_path
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
if self.recording {
|
if self.recording {
|
||||||
warn!("[START_REC] Already recording, returning error");
|
warn!("[START_REC] Already recording, returning error");
|
||||||
@@ -372,25 +353,22 @@ impl ObsContext {
|
|||||||
|
|
||||||
if self.context.is_none() {
|
if self.context.is_none() {
|
||||||
info!("[START_REC] OBS context not initialized, initializing now...");
|
info!("[START_REC] OBS context not initialized, initializing now...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
self.initialize()?;
|
self.initialize()?;
|
||||||
info!("[START_REC] OBS initialization complete");
|
info!("[START_REC] OBS initialization complete");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let context = self.context.as_ref().ok_or_else(|| {
|
let context = self.context.as_ref().ok_or_else(|| {
|
||||||
error!("[START_REC] OBS not initialized after initialize()");
|
error!("[START_REC] OBS not initialized after initialize()");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::ObsInitError("OBS not initialized".to_string())
|
RecordingError::ObsInitError("OBS not initialized".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("[START_REC] Starting OBS recording to: {:?}", output_path);
|
info!("[START_REC] Starting OBS recording to: {:?}", output_path);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Get bitrate from encoder preset
|
// Get bitrate from encoder preset
|
||||||
let bitrate = self.video_settings.encoder_preset.effective_bitrate();
|
let bitrate = self.video_settings.encoder_preset.effective_bitrate();
|
||||||
info!("[START_REC] Using bitrate: {} kbps", bitrate);
|
info!("[START_REC] Using bitrate: {} kbps", bitrate);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Create output path
|
// Create output path
|
||||||
let path_str = output_path.to_string_lossy();
|
let path_str = output_path.to_string_lossy();
|
||||||
@@ -401,18 +379,17 @@ impl ObsContext {
|
|||||||
.encoder_capability
|
.encoder_capability
|
||||||
.unwrap_or_else(best_available_encoder);
|
.unwrap_or_else(best_available_encoder);
|
||||||
info!("[START_REC] Using encoder: {}", encoder.name());
|
info!("[START_REC] Using encoder: {}", encoder.name());
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Build the output based on encoder capability
|
// Build the output based on encoder capability
|
||||||
info!("[START_REC] Creating SimpleOutputBuilder...");
|
info!("[START_REC] Creating SimpleOutputBuilder...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let output_result = match encoder {
|
let output_result = match encoder {
|
||||||
EncoderCapability::Nvenc => {
|
EncoderCapability::Nvenc => {
|
||||||
info!("Building NVENC output...");
|
info!("Building NVENC output...");
|
||||||
SimpleOutputBuilder::new(context.clone(), ObsString::from("output"), obs_path)
|
SimpleOutputBuilder::new(context.clone(), ObsString::from("output"), obs_path)
|
||||||
.video_bitrate(bitrate)
|
.video_bitrate(bitrate)
|
||||||
.audio_bitrate(self.audio_settings.bitrate)
|
.audio_bitrate(self.audio_settings.bitrate)
|
||||||
.hardware_encoder(HardwareCodec::H264, HardwarePreset::Quality)
|
.hardware_encoder(HardwareCodec::H264, HardwarePreset::Speed)
|
||||||
.format(OutputFormat::Mpeg4)
|
.format(OutputFormat::Mpeg4)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
@@ -445,21 +422,19 @@ impl ObsContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
info!("[START_REC] Output build complete, checking for errors...");
|
info!("[START_REC] Output build complete, checking for errors...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let output = output_result.map_err(|e| {
|
let output = output_result.map_err(|e| {
|
||||||
error!("[START_REC] Failed to create output: {:?}", e);
|
error!("[START_REC] Failed to create output: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to create output: {:?}", e))
|
RecordingError::StartError(format!("Failed to create output: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("[START_REC] Output created successfully, setting up game capture...");
|
info!("[START_REC] Output created successfully, setting up game capture...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Set up game capture source
|
// Set up game capture source
|
||||||
self.setup_game_capture()?;
|
self.setup_game_capture()?;
|
||||||
|
|
||||||
info!("[START_REC] Game capture set up, starting output...");
|
info!("[START_REC] Game capture set up, starting output...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Start the output - wrap in catch_unwind as this may crash in native code
|
// Start the output - wrap in catch_unwind as this may crash in native code
|
||||||
let start_result =
|
let start_result =
|
||||||
@@ -468,18 +443,17 @@ impl ObsContext {
|
|||||||
match start_result {
|
match start_result {
|
||||||
Ok(Ok(())) => {
|
Ok(Ok(())) => {
|
||||||
info!("[START_REC] Output started successfully");
|
info!("[START_REC] Output started successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
error!("[START_REC] Failed to start output: {:?}", e);
|
error!("[START_REC] Failed to start output: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(
|
return Err(
|
||||||
RecordingError::StartError(format!("Failed to start output: {:?}", e)).into(),
|
RecordingError::StartError(format!("Failed to start output: {:?}", e)).into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Err(panic_info) => {
|
Err(panic_info) => {
|
||||||
error!("[START_REC] PANIC starting output: {:?}", panic_info);
|
error!("[START_REC] PANIC starting output: {:?}", panic_info);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!("[START_REC] PANIC starting output: {:?}", panic_info);
|
eprintln!("[START_REC] PANIC starting output: {:?}", panic_info);
|
||||||
return Err(RecordingError::StartError("Panic starting output".to_string()).into());
|
return Err(RecordingError::StartError("Panic starting output".to_string()).into());
|
||||||
}
|
}
|
||||||
@@ -490,23 +464,20 @@ impl ObsContext {
|
|||||||
self.recording = true;
|
self.recording = true;
|
||||||
|
|
||||||
info!("[START_REC] OBS recording started successfully");
|
info!("[START_REC] OBS recording started successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set up capture source with fallback from game capture to monitor capture.
|
/// Set up capture source with fallback from game capture to monitor capture.
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn setup_game_capture(&mut self) -> Result<()> {
|
fn setup_game_capture(&mut self) -> Result<()> {
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
info!("[CAPTURE] Setting up capture source...");
|
info!("[CAPTURE] Setting up capture source...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Try game capture first, fall back to monitor capture
|
// Try game capture first, fall back to monitor capture
|
||||||
match self.try_game_capture() {
|
match self.try_game_capture() {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!("[CAPTURE] Game capture set up successfully");
|
info!("[CAPTURE] Game capture set up successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -514,7 +485,7 @@ impl ObsContext {
|
|||||||
"[CAPTURE] Game capture failed: {}, falling back to monitor capture",
|
"[CAPTURE] Game capture failed: {}, falling back to monitor capture",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
self.setup_monitor_capture()
|
self.setup_monitor_capture()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -526,7 +497,6 @@ impl ObsContext {
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
info!("[CAPTURE] Setting up screen capture for Linux...");
|
info!("[CAPTURE] Setting up screen capture for Linux...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
self.setup_linux_screen_capture()
|
self.setup_linux_screen_capture()
|
||||||
}
|
}
|
||||||
@@ -536,35 +506,31 @@ impl ObsContext {
|
|||||||
fn try_game_capture(&mut self) -> Result<()> {
|
fn try_game_capture(&mut self) -> Result<()> {
|
||||||
use libobs_simple::sources::windows::{GameCaptureSourceBuilder, ObsGameCaptureMode};
|
use libobs_simple::sources::windows::{GameCaptureSourceBuilder, ObsGameCaptureMode};
|
||||||
use libobs_simple::sources::ObsSourceBuilder;
|
use libobs_simple::sources::ObsSourceBuilder;
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
info!("[GAME_CAPTURE] Attempting game capture setup...");
|
info!("[GAME_CAPTURE] Attempting game capture setup...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let context = self.context.as_mut().ok_or_else(|| {
|
let context = self.context.as_mut().ok_or_else(|| {
|
||||||
error!("[GAME_CAPTURE] OBS not initialized in setup_game_capture");
|
error!("[GAME_CAPTURE] OBS not initialized in setup_game_capture");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::ObsInitError("OBS not initialized".to_string())
|
RecordingError::ObsInitError("OBS not initialized".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Create a scene
|
// Create a scene
|
||||||
info!("[GAME_CAPTURE] Creating scene 'main'...");
|
info!("[GAME_CAPTURE] Creating scene 'main'...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let mut scene = context.scene("main", None).map_err(|e| {
|
let mut scene = context.scene("main", None).map_err(|e| {
|
||||||
error!("[GAME_CAPTURE] Failed to create scene: {:?}", e);
|
error!("[GAME_CAPTURE] Failed to create scene: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to create scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to create scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
info!("[GAME_CAPTURE] Scene created successfully");
|
info!("[GAME_CAPTURE] Scene created successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Build game capture source
|
// Build game capture source
|
||||||
info!("[GAME_CAPTURE] Getting OBS runtime...");
|
info!("[GAME_CAPTURE] Getting OBS runtime...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let runtime = context.runtime();
|
let runtime = context.runtime();
|
||||||
|
|
||||||
info!("[GAME_CAPTURE] Creating game capture source builder...");
|
info!("[GAME_CAPTURE] Creating game capture source builder...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Wrap game capture builder in catch_unwind as it may crash in native code
|
// Wrap game capture builder in catch_unwind as it may crash in native code
|
||||||
let builder_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let builder_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||||
@@ -574,7 +540,7 @@ impl ObsContext {
|
|||||||
let builder = match builder_result {
|
let builder = match builder_result {
|
||||||
Ok(Ok(b)) => {
|
Ok(Ok(b)) => {
|
||||||
info!("[GAME_CAPTURE] Game capture builder created");
|
info!("[GAME_CAPTURE] Game capture builder created");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
@@ -582,7 +548,7 @@ impl ObsContext {
|
|||||||
"[GAME_CAPTURE] Failed to create game capture builder: {:?}",
|
"[GAME_CAPTURE] Failed to create game capture builder: {:?}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::StartError(format!(
|
return Err(RecordingError::StartError(format!(
|
||||||
"Failed to create game capture builder: {:?}",
|
"Failed to create game capture builder: {:?}",
|
||||||
e
|
e
|
||||||
@@ -594,7 +560,7 @@ impl ObsContext {
|
|||||||
"[GAME_CAPTURE] PANIC creating game capture builder: {:?}",
|
"[GAME_CAPTURE] PANIC creating game capture builder: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[GAME_CAPTURE] PANIC creating game capture builder: {:?}",
|
"[GAME_CAPTURE] PANIC creating game capture builder: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -607,12 +573,10 @@ impl ObsContext {
|
|||||||
};
|
};
|
||||||
|
|
||||||
info!("[GAME_CAPTURE] Configuring game capture for League of Legends...");
|
info!("[GAME_CAPTURE] Configuring game capture for League of Legends...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Use "Any" mode to capture any fullscreen application
|
// Use "Any" mode to capture any fullscreen application
|
||||||
// This is the most reliable mode for games like League of Legends
|
// This is the most reliable mode for games like League of Legends
|
||||||
info!("[GAME_CAPTURE] Using 'Any' mode to capture fullscreen games...");
|
info!("[GAME_CAPTURE] Using 'Any' mode to capture fullscreen games...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Wrap source build in catch_unwind
|
// Wrap source build in catch_unwind
|
||||||
let source_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let source_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||||
@@ -622,7 +586,7 @@ impl ObsContext {
|
|||||||
let source = match source_result {
|
let source = match source_result {
|
||||||
Ok(Ok(s)) => {
|
Ok(Ok(s)) => {
|
||||||
info!("[GAME_CAPTURE] Game capture source created");
|
info!("[GAME_CAPTURE] Game capture source created");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
@@ -630,7 +594,7 @@ impl ObsContext {
|
|||||||
"[GAME_CAPTURE] Failed to create game capture source: {:?}",
|
"[GAME_CAPTURE] Failed to create game capture source: {:?}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::StartError(format!(
|
return Err(RecordingError::StartError(format!(
|
||||||
"Failed to create game capture source: {:?}",
|
"Failed to create game capture source: {:?}",
|
||||||
e
|
e
|
||||||
@@ -642,7 +606,7 @@ impl ObsContext {
|
|||||||
"[GAME_CAPTURE] PANIC creating game capture source: {:?}",
|
"[GAME_CAPTURE] PANIC creating game capture source: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[GAME_CAPTURE] PANIC creating game capture source: {:?}",
|
"[GAME_CAPTURE] PANIC creating game capture source: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -656,25 +620,24 @@ impl ObsContext {
|
|||||||
|
|
||||||
// Add source to scene using add_source
|
// Add source to scene using add_source
|
||||||
info!("[GAME_CAPTURE] Adding source to scene...");
|
info!("[GAME_CAPTURE] Adding source to scene...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
scene.add_source(source).map_err(|e| {
|
scene.add_source(source).map_err(|e| {
|
||||||
error!("[GAME_CAPTURE] Failed to add source to scene: {:?}", e);
|
error!("[GAME_CAPTURE] Failed to add source to scene: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to add source to scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to add source to scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
info!("[GAME_CAPTURE] Source added to scene");
|
info!("[GAME_CAPTURE] Source added to scene");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Set the scene as active
|
// Set the scene as active
|
||||||
info!("[GAME_CAPTURE] Setting scene as active on channel 0...");
|
info!("[GAME_CAPTURE] Setting scene as active on channel 0...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
scene.set_to_channel(0).map_err(|e| {
|
scene.set_to_channel(0).map_err(|e| {
|
||||||
error!("[GAME_CAPTURE] Failed to set scene: {:?}", e);
|
error!("[GAME_CAPTURE] Failed to set scene: {:?}", e);
|
||||||
RecordingError::StartError(format!("Failed to set scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to set scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("[GAME_CAPTURE] Game capture source configured successfully");
|
info!("[GAME_CAPTURE] Game capture source configured successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,41 +646,37 @@ impl ObsContext {
|
|||||||
fn setup_monitor_capture(&mut self) -> Result<()> {
|
fn setup_monitor_capture(&mut self) -> Result<()> {
|
||||||
use libobs_simple::sources::windows::MonitorCaptureSourceBuilder;
|
use libobs_simple::sources::windows::MonitorCaptureSourceBuilder;
|
||||||
use libobs_simple::sources::ObsSourceBuilder;
|
use libobs_simple::sources::ObsSourceBuilder;
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
info!("[MONITOR_CAPTURE] Setting up monitor capture as fallback...");
|
info!("[MONITOR_CAPTURE] Setting up monitor capture as fallback...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let context = self.context.as_mut().ok_or_else(|| {
|
let context = self.context.as_mut().ok_or_else(|| {
|
||||||
error!("[MONITOR_CAPTURE] OBS not initialized");
|
error!("[MONITOR_CAPTURE] OBS not initialized");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::ObsInitError("OBS not initialized".to_string())
|
RecordingError::ObsInitError("OBS not initialized".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Create a scene
|
// Create a scene
|
||||||
info!("[MONITOR_CAPTURE] Creating scene 'main'...");
|
info!("[MONITOR_CAPTURE] Creating scene 'main'...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let mut scene = context.scene("main", None).map_err(|e| {
|
let mut scene = context.scene("main", None).map_err(|e| {
|
||||||
error!("[MONITOR_CAPTURE] Failed to create scene: {:?}", e);
|
error!("[MONITOR_CAPTURE] Failed to create scene: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to create scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to create scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
info!("[MONITOR_CAPTURE] Scene created successfully");
|
info!("[MONITOR_CAPTURE] Scene created successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Get monitor info
|
// Get monitor info
|
||||||
info!("[MONITOR_CAPTURE] Detecting monitors...");
|
info!("[MONITOR_CAPTURE] Detecting monitors...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let monitors = display_info::DisplayInfo::all().map_err(|e| {
|
let monitors = display_info::DisplayInfo::all().map_err(|e| {
|
||||||
error!("[MONITOR_CAPTURE] Failed to get display info: {:?}", e);
|
error!("[MONITOR_CAPTURE] Failed to get display info: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to get display info: {:?}", e))
|
RecordingError::StartError(format!("Failed to get display info: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
if monitors.is_empty() {
|
if monitors.is_empty() {
|
||||||
error!("[MONITOR_CAPTURE] No monitors detected");
|
error!("[MONITOR_CAPTURE] No monitors detected");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::StartError("No monitors detected".to_string()).into());
|
return Err(RecordingError::StartError("No monitors detected".to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -727,11 +686,9 @@ impl ObsContext {
|
|||||||
"[MONITOR_CAPTURE] Using monitor: {}x{} at ({}, {})",
|
"[MONITOR_CAPTURE] Using monitor: {}x{} at ({}, {})",
|
||||||
primary_monitor.width, primary_monitor.height, primary_monitor.x, primary_monitor.y
|
primary_monitor.width, primary_monitor.height, primary_monitor.x, primary_monitor.y
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Build monitor capture source
|
// Build monitor capture source
|
||||||
info!("[MONITOR_CAPTURE] Creating monitor capture source builder...");
|
info!("[MONITOR_CAPTURE] Creating monitor capture source builder...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let builder_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let builder_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||||
MonitorCaptureSourceBuilder::new("monitor_capture", context.runtime().clone())
|
MonitorCaptureSourceBuilder::new("monitor_capture", context.runtime().clone())
|
||||||
@@ -740,7 +697,7 @@ impl ObsContext {
|
|||||||
let builder = match builder_result {
|
let builder = match builder_result {
|
||||||
Ok(Ok(b)) => {
|
Ok(Ok(b)) => {
|
||||||
info!("[MONITOR_CAPTURE] Monitor capture builder created");
|
info!("[MONITOR_CAPTURE] Monitor capture builder created");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
@@ -748,7 +705,7 @@ impl ObsContext {
|
|||||||
"[MONITOR_CAPTURE] Failed to create monitor capture builder: {:?}",
|
"[MONITOR_CAPTURE] Failed to create monitor capture builder: {:?}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::StartError(format!(
|
return Err(RecordingError::StartError(format!(
|
||||||
"Failed to create monitor capture builder: {:?}",
|
"Failed to create monitor capture builder: {:?}",
|
||||||
e
|
e
|
||||||
@@ -760,7 +717,7 @@ impl ObsContext {
|
|||||||
"[MONITOR_CAPTURE] PANIC creating monitor capture builder: {:?}",
|
"[MONITOR_CAPTURE] PANIC creating monitor capture builder: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[MONITOR_CAPTURE] PANIC creating monitor capture builder: {:?}",
|
"[MONITOR_CAPTURE] PANIC creating monitor capture builder: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -779,7 +736,7 @@ impl ObsContext {
|
|||||||
let source = match source_result {
|
let source = match source_result {
|
||||||
Ok(Ok(s)) => {
|
Ok(Ok(s)) => {
|
||||||
info!("[MONITOR_CAPTURE] Monitor capture source created");
|
info!("[MONITOR_CAPTURE] Monitor capture source created");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
@@ -787,7 +744,7 @@ impl ObsContext {
|
|||||||
"[MONITOR_CAPTURE] Failed to create monitor capture source: {:?}",
|
"[MONITOR_CAPTURE] Failed to create monitor capture source: {:?}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::StartError(format!(
|
return Err(RecordingError::StartError(format!(
|
||||||
"Failed to create monitor capture source: {:?}",
|
"Failed to create monitor capture source: {:?}",
|
||||||
e
|
e
|
||||||
@@ -799,7 +756,7 @@ impl ObsContext {
|
|||||||
"[MONITOR_CAPTURE] PANIC creating monitor capture source: {:?}",
|
"[MONITOR_CAPTURE] PANIC creating monitor capture source: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[MONITOR_CAPTURE] PANIC creating monitor capture source: {:?}",
|
"[MONITOR_CAPTURE] PANIC creating monitor capture source: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -813,25 +770,24 @@ impl ObsContext {
|
|||||||
|
|
||||||
// Add source to scene
|
// Add source to scene
|
||||||
info!("[MONITOR_CAPTURE] Adding source to scene...");
|
info!("[MONITOR_CAPTURE] Adding source to scene...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
scene.add_source(source).map_err(|e| {
|
scene.add_source(source).map_err(|e| {
|
||||||
error!("[MONITOR_CAPTURE] Failed to add source to scene: {:?}", e);
|
error!("[MONITOR_CAPTURE] Failed to add source to scene: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to add source to scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to add source to scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
info!("[MONITOR_CAPTURE] Source added to scene");
|
info!("[MONITOR_CAPTURE] Source added to scene");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Set the scene as active
|
// Set the scene as active
|
||||||
info!("[MONITOR_CAPTURE] Setting scene as active on channel 0...");
|
info!("[MONITOR_CAPTURE] Setting scene as active on channel 0...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
scene.set_to_channel(0).map_err(|e| {
|
scene.set_to_channel(0).map_err(|e| {
|
||||||
error!("[MONITOR_CAPTURE] Failed to set scene: {:?}", e);
|
error!("[MONITOR_CAPTURE] Failed to set scene: {:?}", e);
|
||||||
RecordingError::StartError(format!("Failed to set scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to set scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("[MONITOR_CAPTURE] Monitor capture source configured successfully");
|
info!("[MONITOR_CAPTURE] Monitor capture source configured successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -843,29 +799,26 @@ impl ObsContext {
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
info!("[LINUX_CAPTURE] Setting up Linux screen capture...");
|
info!("[LINUX_CAPTURE] Setting up Linux screen capture...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let context = self.context.as_mut().ok_or_else(|| {
|
let context = self.context.as_mut().ok_or_else(|| {
|
||||||
error!("[LINUX_CAPTURE] OBS not initialized");
|
error!("[LINUX_CAPTURE] OBS not initialized");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::ObsInitError("OBS not initialized".to_string())
|
RecordingError::ObsInitError("OBS not initialized".to_string())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Create a scene
|
// Create a scene
|
||||||
info!("[LINUX_CAPTURE] Creating scene 'main'...");
|
info!("[LINUX_CAPTURE] Creating scene 'main'...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
let mut scene = context.scene("main", None).map_err(|e| {
|
let mut scene = context.scene("main", None).map_err(|e| {
|
||||||
error!("[LINUX_CAPTURE] Failed to create scene: {:?}", e);
|
error!("[LINUX_CAPTURE] Failed to create scene: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to create scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to create scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
info!("[LINUX_CAPTURE] Scene created successfully");
|
info!("[LINUX_CAPTURE] Scene created successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Build screen capture source using LinuxGeneralScreenCaptureBuilder
|
// Build screen capture source using LinuxGeneralScreenCaptureBuilder
|
||||||
// This automatically uses X11 or PipeWire depending on the platform
|
// This automatically uses X11 or PipeWire depending on the platform
|
||||||
info!("[LINUX_CAPTURE] Creating screen capture source builder...");
|
info!("[LINUX_CAPTURE] Creating screen capture source builder...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
let builder_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
let builder_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
|
||||||
LinuxGeneralScreenCaptureBuilder::new("screen_capture", context.runtime().clone())
|
LinuxGeneralScreenCaptureBuilder::new("screen_capture", context.runtime().clone())
|
||||||
@@ -874,7 +827,7 @@ impl ObsContext {
|
|||||||
let builder = match builder_result {
|
let builder = match builder_result {
|
||||||
Ok(Ok(b)) => {
|
Ok(Ok(b)) => {
|
||||||
info!("[LINUX_CAPTURE] Screen capture builder created");
|
info!("[LINUX_CAPTURE] Screen capture builder created");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
@@ -882,7 +835,7 @@ impl ObsContext {
|
|||||||
"[LINUX_CAPTURE] Failed to create screen capture builder: {:?}",
|
"[LINUX_CAPTURE] Failed to create screen capture builder: {:?}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::StartError(format!(
|
return Err(RecordingError::StartError(format!(
|
||||||
"Failed to create screen capture builder: {:?}",
|
"Failed to create screen capture builder: {:?}",
|
||||||
e
|
e
|
||||||
@@ -894,7 +847,7 @@ impl ObsContext {
|
|||||||
"[LINUX_CAPTURE] PANIC creating screen capture builder: {:?}",
|
"[LINUX_CAPTURE] PANIC creating screen capture builder: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[LINUX_CAPTURE] PANIC creating screen capture builder: {:?}",
|
"[LINUX_CAPTURE] PANIC creating screen capture builder: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -913,7 +866,7 @@ impl ObsContext {
|
|||||||
let source = match source_result {
|
let source = match source_result {
|
||||||
Ok(Ok(s)) => {
|
Ok(Ok(s)) => {
|
||||||
info!("[LINUX_CAPTURE] Screen capture source created");
|
info!("[LINUX_CAPTURE] Screen capture source created");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(Err(e)) => {
|
||||||
@@ -921,7 +874,7 @@ impl ObsContext {
|
|||||||
"[LINUX_CAPTURE] Failed to create screen capture source: {:?}",
|
"[LINUX_CAPTURE] Failed to create screen capture source: {:?}",
|
||||||
e
|
e
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
return Err(RecordingError::StartError(format!(
|
return Err(RecordingError::StartError(format!(
|
||||||
"Failed to create screen capture source: {:?}",
|
"Failed to create screen capture source: {:?}",
|
||||||
e
|
e
|
||||||
@@ -933,7 +886,7 @@ impl ObsContext {
|
|||||||
"[LINUX_CAPTURE] PANIC creating screen capture source: {:?}",
|
"[LINUX_CAPTURE] PANIC creating screen capture source: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
);
|
);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[LINUX_CAPTURE] PANIC creating screen capture source: {:?}",
|
"[LINUX_CAPTURE] PANIC creating screen capture source: {:?}",
|
||||||
panic_info
|
panic_info
|
||||||
@@ -947,25 +900,24 @@ impl ObsContext {
|
|||||||
|
|
||||||
// Add source to scene
|
// Add source to scene
|
||||||
info!("[LINUX_CAPTURE] Adding source to scene...");
|
info!("[LINUX_CAPTURE] Adding source to scene...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
scene.add_source(source).map_err(|e| {
|
scene.add_source(source).map_err(|e| {
|
||||||
error!("[LINUX_CAPTURE] Failed to add source to scene: {:?}", e);
|
error!("[LINUX_CAPTURE] Failed to add source to scene: {:?}", e);
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
RecordingError::StartError(format!("Failed to add source to scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to add source to scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
info!("[LINUX_CAPTURE] Source added to scene");
|
info!("[LINUX_CAPTURE] Source added to scene");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
|
|
||||||
// Set the scene as active
|
// Set the scene as active
|
||||||
info!("[LINUX_CAPTURE] Setting scene as active on channel 0...");
|
info!("[LINUX_CAPTURE] Setting scene as active on channel 0...");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
scene.set_to_channel(0).map_err(|e| {
|
scene.set_to_channel(0).map_err(|e| {
|
||||||
error!("[LINUX_CAPTURE] Failed to set scene: {:?}", e);
|
error!("[LINUX_CAPTURE] Failed to set scene: {:?}", e);
|
||||||
RecordingError::StartError(format!("Failed to set scene: {:?}", e))
|
RecordingError::StartError(format!("Failed to set scene: {:?}", e))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
info!("[LINUX_CAPTURE] Screen capture source configured successfully");
|
info!("[LINUX_CAPTURE] Screen capture source configured successfully");
|
||||||
std::io::stderr().flush().ok();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user