mirror of
https://github.com/valmojr/armatak.git
synced 2026-06-13 15:23:28 +00:00
refactored video stream handler to handle RTSP feed on linux with multiple OS data, avoinding DRY
This commit is contained in:
@@ -16,6 +16,56 @@ lazy_static! {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
const CREATE_NO_WINDOW: u32 = 0x08000000;
|
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<Result<(), String>>,
|
||||||
|
) {
|
||||||
|
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(
|
pub fn start_stream(
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
address: String,
|
address: String,
|
||||||
@@ -24,52 +74,15 @@ pub fn start_stream(
|
|||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
) -> &'static str {
|
) -> &'static str {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||||
{
|
{
|
||||||
let (stop_tx, stop_rx): (Sender<()>, Receiver<()>) = mpsc::channel();
|
let (stop_tx, stop_rx) = mpsc::channel();
|
||||||
let (status_tx, status_rx): (Sender<Result<(), String>>, Receiver<Result<(), String>>) = mpsc::channel();
|
let (status_tx, status_rx) = mpsc::channel();
|
||||||
|
|
||||||
let rtsp_url = if username.is_empty() || password.is_empty() {
|
let rtsp_url = build_rtsp_url(&address, &port, &stream_path, &username, &password);
|
||||||
format!("rtsp://{}:{}/{}", address, port, stream_path)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
"rtsp://{}:{}@{}:{}/{}",
|
|
||||||
username, password, address, port, stream_path
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
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() {
|
match STREAM_CTRL.lock() {
|
||||||
Ok(mut lock) => *lock = Some(stop_tx),
|
Ok(mut lock) => *lock = Some(stop_tx),
|
||||||
Err(e) => {
|
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<Result<(), String>>, Receiver<Result<(), String>>) = 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)) {
|
match status_rx.recv_timeout(Duration::from_secs(2)) {
|
||||||
Ok(Ok(())) => {
|
Ok(Ok(())) => {
|
||||||
let _ = ctx.callback_null("VIDEO", "FFmpeg started successfully");
|
let _ = ctx.callback_null("VIDEO", "FFmpeg started successfully");
|
||||||
@@ -210,4 +147,4 @@ pub fn stop_stream(ctx: Context) -> &'static str {
|
|||||||
"lock error"
|
"lock error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user