74 lines
2.3 KiB
Rust
74 lines
2.3 KiB
Rust
use anyhow::{Context, Result, anyhow};
|
|
use std::sync::mpsc::Sender;
|
|
use tokio::io::{AsyncBufReadExt, BufReader};
|
|
use tokio::process::Command;
|
|
|
|
/// Executa o FFmpeg de forma assíncrona, capturando stderr em tempo real.
|
|
/// As linhas de saída são enviadas pelo canal `progress_tx` (std::sync::mpsc).
|
|
/// Um sinal enviado em `cancel_rx` encerra o processo imediatamente.
|
|
pub async fn run_ffmpeg_async(
|
|
args: Vec<String>,
|
|
progress_tx: Sender<String>,
|
|
cancel_rx: tokio::sync::oneshot::Receiver<()>,
|
|
) -> Result<()> {
|
|
let mut child = Command::new("ffmpeg")
|
|
.args(&args)
|
|
.stdin(std::process::Stdio::null())
|
|
.stderr(std::process::Stdio::piped())
|
|
.stdout(std::process::Stdio::null())
|
|
.spawn()
|
|
.context("Falha ao iniciar ffmpeg")?;
|
|
|
|
// Lê stderr em stream para exibir progresso em tempo real
|
|
if let Some(stderr) = child.stderr.take() {
|
|
let reader = BufReader::new(stderr);
|
|
let mut lines = reader.lines();
|
|
let tx = progress_tx.clone();
|
|
tokio::spawn(async move {
|
|
while let Ok(Some(line)) = lines.next_line().await {
|
|
let _ = tx.send(line);
|
|
}
|
|
});
|
|
}
|
|
|
|
tokio::select! {
|
|
result = child.wait() => {
|
|
let status = result.context("Erro ao aguardar ffmpeg")?;
|
|
if !status.success() {
|
|
return Err(anyhow!(
|
|
"FFmpeg encerrou com código de saída: {:?}",
|
|
status.code()
|
|
));
|
|
}
|
|
Ok(())
|
|
}
|
|
_ = cancel_rx => {
|
|
let _ = child.kill().await;
|
|
Err(anyhow!("Cancelado pelo usuário"))
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Verifica se um binário está disponível no PATH.
|
|
pub fn check_binary_available(binary: &str) -> Result<()> {
|
|
std::process::Command::new(binary)
|
|
.arg("-version")
|
|
.stdout(std::process::Stdio::null())
|
|
.stderr(std::process::Stdio::null())
|
|
.status()
|
|
.map_err(|_| {
|
|
anyhow!(
|
|
"'{}' não encontrado no PATH. Por favor, instale o FFmpeg.",
|
|
binary
|
|
)
|
|
})?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Verifica se ffmpeg e ffprobe estão disponíveis.
|
|
pub fn validate_dependencies() -> Result<()> {
|
|
check_binary_available("ffmpeg")?;
|
|
check_binary_available("ffprobe")?;
|
|
Ok(())
|
|
}
|