73 lines
1.7 KiB
Rust
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
|
|
}
|