use std::path::{Path, PathBuf};
use std::process::Command;
fn have(tool: &str) -> bool {
Command::new(tool)
.arg("-version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}
fn have_libvmaf() -> bool {
Command::new("ffmpeg")
.args(["-hide_banner", "-filters"])
.output()
.map(|o| String::from_utf8_lossy(&o.stdout).contains("libvmaf"))
.unwrap_or(false)
}
fn unique_dir() -> PathBuf {
let mut d = std::env::temp_dir();
d.push(format!("deepshrink-vmaf-it-{}", std::process::id()));
std::fs::create_dir_all(&d).expect("create temp dir");
d
}
fn generate_sample(dir: &Path) -> PathBuf {
let sample = dir.join("sample.mp4");
let status = Command::new("ffmpeg")
.args([
"-y",
"-hide_banner",
"-loglevel",
"error",
"-f",
"lavfi",
"-i",
"testsrc2=duration=3:size=640x480:rate=30",
"-c:v",
"libx264",
"-preset",
"veryfast",
"-b:v",
"3M",
"-pix_fmt",
"yuv420p",
])
.arg(&sample)
.status()
.expect("spawn ffmpeg");
assert!(status.success(), "ffmpeg failed to generate the sample");
sample
}
fn parse_json_vmaf(stdout: &str) -> Option<f64> {
let key = "\"vmaf\":";
let idx = stdout.rfind(key)? + key.len();
let tail = stdout[idx..].trim_start();
let end = tail.find([',', '}']).unwrap_or(tail.len());
tail[..end].trim().parse::<f64>().ok()
}
#[test]
fn vmaf_quality_mode_reports_score() {
if !have("ffmpeg") || !have("ffprobe") {
eprintln!("skipping: ffmpeg/ffprobe not found in PATH");
return;
}
if !have_libvmaf() {
eprintln!("skipping: this ffmpeg build has no libvmaf filter");
return;
}
let dir = unique_dir();
let sample = generate_sample(&dir);
let output = dir.join("sample.shrink.mp4");
let out = Command::new(env!("CARGO_BIN_EXE_deepshrink"))
.arg(&sample)
.args(["--vmaf", "90", "--json"])
.output()
.expect("run deepshrink");
assert!(
out.status.success(),
"deepshrink failed: {}",
String::from_utf8_lossy(&out.stderr)
);
assert!(output.exists(), "expected output was not written");
assert!(sample.exists(), "original was removed");
let stdout = String::from_utf8_lossy(&out.stdout);
let vmaf =
parse_json_vmaf(&stdout).unwrap_or_else(|| panic!("no vmaf in JSON output: {stdout:?}"));
assert!(
(60.0..=100.0).contains(&vmaf),
"VMAF {vmaf} outside the expected corridor"
);
let probe = Command::new("ffprobe")
.args([
"-v",
"error",
"-select_streams",
"v:0",
"-show_entries",
"stream=codec_name",
"-of",
"csv=p=0",
])
.arg(&output)
.output()
.expect("run ffprobe");
assert!(probe.status.success(), "ffprobe rejected the output");
let codec = String::from_utf8_lossy(&probe.stdout);
assert!(
codec.trim().starts_with("h264"),
"unexpected codec: {codec:?}"
);
let _ = std::fs::remove_dir_all(&dir);
}