Files
vid-repair/vid-repair-core/src/scan/decode.rs
2025-12-31 22:07:42 -05:00

73 lines
1.7 KiB
Rust

use std::io::{BufRead, BufReader};
use std::path::Path;
use std::process::{Command, Stdio};
use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
use anyhow::{Context, Result};
use crate::rules::RuleSet;
#[derive(Debug)]
pub struct DecodeOutput {
pub lines: Vec<String>,
pub early_stop: bool,
}
pub fn run_decode(path: &Path, ffmpeg_path: &str, ruleset: &RuleSet) -> Result<DecodeOutput> {
let mut child = Command::new(ffmpeg_path)
.arg("-v")
.arg("error")
.arg("-i")
.arg(path)
.arg("-f")
.arg("null")
.arg("-")
.stderr(Stdio::piped())
.stdout(Stdio::null())
.spawn()
.with_context(|| format!("Failed to run ffmpeg decode for {}", path.display()))?;
let stderr = child.stderr.take().context("Failed to capture ffmpeg stderr")?;
let reader = BufReader::new(stderr);
let early_stop = Arc::new(AtomicBool::new(false));
let early_stop_flag = early_stop.clone();
let mut lines = Vec::new();
for line in reader.lines() {
let line = line.unwrap_or_default();
if line.is_empty() {
continue;
}
lines.push(line.clone());
if should_stop(&line, ruleset) {
early_stop_flag.store(true, Ordering::SeqCst);
let _ = child.kill();
break;
}
}
let _ = child.wait();
Ok(DecodeOutput {
lines,
early_stop: early_stop.load(Ordering::SeqCst),
})
}
fn should_stop(line: &str, ruleset: &RuleSet) -> bool {
for rule in &ruleset.rules {
if !rule.rule.stop_scan {
continue;
}
if rule.patterns.iter().any(|re| re.is_match(line)) {
return true;
}
}
false
}