diff --git a/src/video_stream.rs b/src/video_stream.rs index d26d04a..e4e34b3 100644 --- a/src/video_stream.rs +++ b/src/video_stream.rs @@ -16,6 +16,56 @@ lazy_static! { #[cfg(target_os = "windows")] const CREATE_NO_WINDOW: u32 = 0x08000000; +fn build_rtsp_url(address: &str, port: &str, stream_path: &str, username: &str, password: &str) -> String { + if username.is_empty() || password.is_empty() { + format!("rtsp://{}:{}/{}", address, port, stream_path) + } else { + format!( + "rtsp://{}:{}@{}:{}/{}", + username, password, address, port, stream_path + ) + } +} + +#[cfg(any(target_os = "windows", target_os = "linux"))] +fn spawn_ffmpeg( + rtsp_url: String, + stop_rx: Receiver<()>, + status_tx: Sender>, +) { + thread::spawn(move || { + let mut cmd = Command::new("ffmpeg"); + cmd.args(&[ + "-f", + "gdigrab", + "-i", + "desktop", + "-f", + "rtsp", + "-rtsp_transport", + "tcp", + &rtsp_url, + ]); + + #[cfg(target_os = "windows")] + let child_result = cmd.creation_flags(CREATE_NO_WINDOW).spawn(); + + #[cfg(target_os = "linux")] + let child_result = cmd.spawn(); + + match child_result { + Ok(mut child) => { + let _ = status_tx.send(Ok(())); + let _ = stop_rx.recv(); + let _ = child.kill(); + } + Err(e) => { + let _ = status_tx.send(Err(format!("Failed to start FFmpeg: {}", e))); + } + } + }); +} + pub fn start_stream( ctx: Context, address: String, @@ -24,52 +74,15 @@ pub fn start_stream( username: String, password: String, ) -> &'static str { - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "windows", target_os = "linux"))] { - let (stop_tx, stop_rx): (Sender<()>, Receiver<()>) = mpsc::channel(); - let (status_tx, status_rx): (Sender>, Receiver>) = mpsc::channel(); + let (stop_tx, stop_rx) = mpsc::channel(); + let (status_tx, status_rx) = mpsc::channel(); - let rtsp_url = if username.is_empty() || password.is_empty() { - format!("rtsp://{}:{}/{}", address, port, stream_path) - } else { - format!( - "rtsp://{}:{}@{}:{}/{}", - username, password, address, port, stream_path - ) - }; + let rtsp_url = build_rtsp_url(&address, &port, &stream_path, &username, &password); - let rtsp_url_clone = rtsp_url.clone(); + spawn_ffmpeg(rtsp_url, stop_rx, status_tx); - thread::spawn(move || { - let mut cmd = Command::new("ffmpeg"); - cmd.args(&[ - "-f", - "gdigrab", - "-i", - "desktop", - "-f", - "rtsp", - "-rtsp_transport", - "tcp", - &rtsp_url_clone, - ]); - - // Try to spawn ffmpeg process - let child_result = cmd.spawn(); - - match child_result { - Ok(mut child) => { - let _ = status_tx.send(Ok(())); - if stop_rx.recv().is_err() {} - let _ = child.kill(); - } - Err(e) => { - let _ = status_tx.send(Err(format!("Failed to start FFmpeg: {}", e))); - } - } - }); - - // Save the stop channel match STREAM_CTRL.lock() { Ok(mut lock) => *lock = Some(stop_tx), Err(e) => { @@ -82,82 +95,6 @@ pub fn start_stream( } } - // Wait up to 2 seconds to see if ffmpeg started correctly - match status_rx.recv_timeout(Duration::from_secs(2)) { - Ok(Ok(())) => { - let _ = ctx.callback_null("VIDEO", "FFmpeg started successfully"); - "starting video stream" - } - Ok(Err(e)) => { - let _ = ctx.callback_data("VIDEO ERROR", "FFmpeg failed to start", e); - "ffmpeg failed to start" - } - Err(_) => { - let _ = ctx.callback_null("VIDEO ERROR", "FFmpeg did not respond in time"); - "ffmpeg did not respond" - } - } - } - - #[cfg(target_os = "windows")] - { - let (stop_tx, stop_rx): (Sender<()>, Receiver<()>) = mpsc::channel(); - let (status_tx, status_rx): (Sender>, Receiver>) = mpsc::channel(); - - let rtsp_url = if username.is_empty() || password.is_empty() { - format!("rtsp://{}:{}/{}", address, port, stream_path) - } else { - format!( - "rtsp://{}:{}@{}:{}/{}", - username, password, address, port, stream_path - ) - }; - - let rtsp_url_clone = rtsp_url.clone(); - - thread::spawn(move || { - let mut cmd = Command::new("ffmpeg"); - cmd.args(&[ - "-f", - "gdigrab", - "-i", - "desktop", - "-f", - "rtsp", - "-rtsp_transport", - "tcp", - &rtsp_url_clone, - ]); - - // Try to spawn ffmpeg process - let child_result = cmd.creation_flags(CREATE_NO_WINDOW).spawn(); - - match child_result { - Ok(mut child) => { - let _ = status_tx.send(Ok(())); - if stop_rx.recv().is_err() {} - let _ = child.kill(); - } - Err(e) => { - let _ = status_tx.send(Err(format!("Failed to start FFmpeg: {}", e))); - } - } - }); - - // Save the stop channel - match STREAM_CTRL.lock() { - Ok(mut lock) => *lock = Some(stop_tx), - Err(e) => { - let _ = ctx.callback_data( - "VIDEO ERROR", - "Failed to acquire lock for stream control", - e.to_string(), - ); - return "stream control lock error"; - } - } - - // Wait up to 2 seconds to see if ffmpeg started correctly match status_rx.recv_timeout(Duration::from_secs(2)) { Ok(Ok(())) => { let _ = ctx.callback_null("VIDEO", "FFmpeg started successfully"); @@ -210,4 +147,4 @@ pub fn stop_stream(ctx: Context) -> &'static str { "lock error" } } -} \ No newline at end of file +}