137 lines
4.2 KiB
Rust
137 lines
4.2 KiB
Rust
//! Speed / efficiency measurements on ffmpeg-generated test sources (ignored by default):
|
|
//! `cargo test -p effectcraft-av1enc --test bench -- --ignored --nocapture`.
|
|
|
|
mod common;
|
|
|
|
use std::process::Command;
|
|
use std::time::Instant;
|
|
|
|
use common::*;
|
|
use effectcraft_av1enc::{Encoder, EncoderConfig, RateControl};
|
|
|
|
/// Raw 8-bit 4:2:0 frames of an ffmpeg lavfi source, or None without ffmpeg.
|
|
fn lavfi(src: &str, w: usize, h: usize, frames: usize) -> Option<Vec<Pic>> {
|
|
let out = std::env::temp_dir().join(format!("effectcraft-av1enc-bench-{}-{src}-{w}x{h}.yuv", std::process::id()));
|
|
let st = Command::new("ffmpeg")
|
|
.args(["-v", "error", "-y", "-f", "lavfi", "-i"])
|
|
.arg(format!("{src}=size={w}x{h}:rate=30"))
|
|
.args(["-frames:v", &frames.to_string(), "-pix_fmt", "yuv420p", "-f", "rawvideo"])
|
|
.arg(&out)
|
|
.status()
|
|
.ok()?;
|
|
if !st.success() {
|
|
return None;
|
|
}
|
|
let raw = std::fs::read(&out).ok()?;
|
|
let _ = std::fs::remove_file(&out);
|
|
let (cw, ch) = (w.div_ceil(2), h.div_ceil(2));
|
|
let fs = w * h + 2 * cw * ch;
|
|
Some(
|
|
raw.chunks_exact(fs)
|
|
.map(|f| Pic {
|
|
w,
|
|
h,
|
|
y: f[..w * h].iter().map(|&b| b as u16).collect(),
|
|
u: f[w * h..w * h + cw * ch].iter().map(|&b| b as u16).collect(),
|
|
v: f[w * h + cw * ch..].iter().map(|&b| b as u16).collect(),
|
|
})
|
|
.collect(),
|
|
)
|
|
}
|
|
|
|
fn run(name: &str, pics: &[Pic], rate: RateControl, keyint: u32) {
|
|
let (w, h) = (pics[0].w, pics[0].h);
|
|
let mut cfg = EncoderConfig::new(w as u32, h as u32, 30, 1);
|
|
cfg.rate = rate;
|
|
cfg.keyint = keyint;
|
|
let mut enc = Encoder::new(cfg).unwrap();
|
|
let mut bytes = 0;
|
|
let mut psnr_sum = 0.0;
|
|
let mut t_key = 0.0;
|
|
let mut t_inter = 0.0;
|
|
let mut sizes = Vec::new();
|
|
for p in pics {
|
|
let t = Instant::now();
|
|
let pkt = enc.encode(&p.frame());
|
|
let dt = t.elapsed().as_secs_f64();
|
|
if pkt.keyframe {
|
|
t_key += dt;
|
|
} else {
|
|
t_inter += dt;
|
|
}
|
|
bytes += pkt.data.len();
|
|
sizes.push(pkt.data.len());
|
|
let rec = enc.last_reconstruction().unwrap();
|
|
psnr_sum += psnr(&p.y, &rec[0], 8);
|
|
}
|
|
let n = pics.len() as f64;
|
|
let n_key = pics.len().div_ceil(keyint as usize) as f64;
|
|
eprintln!(
|
|
"{name} {w}x{h} {rate:?}: {:.0} kbit/s, PSNR-Y {:.2} dB, key {:.2} s/frame, inter {:.2} s/frame, sizes {:?}",
|
|
bytes as f64 * 8.0 * 30.0 / n / 1000.0,
|
|
psnr_sum / n,
|
|
t_key / n_key,
|
|
if n > n_key { t_inter / (n - n_key) } else { 0.0 },
|
|
&sizes[..sizes.len().min(6)]
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn bench_lavfi() {
|
|
if std::env::var("AV1ENC_BENCH_QUICK").is_err() {
|
|
let Some(pics) = lavfi("testsrc2", 1920, 1080, 6) else {
|
|
eprintln!("ffmpeg not available");
|
|
return;
|
|
};
|
|
run("testsrc2", &pics, RateControl::ConstantQ(100), 30);
|
|
}
|
|
if let Some(pics) = lavfi("mandelbrot", 640, 360, 20) {
|
|
for q in [40, 80, 120, 160] {
|
|
run("mandelbrot", &pics, RateControl::ConstantQ(q), 30);
|
|
}
|
|
run("mandelbrot", &pics, RateControl::Bitrate { kbps: 1000 }, 30);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn bench_intra() {
|
|
for src in ["mandelbrot", "sierpinski", "gradients"] {
|
|
let Some(pics) = lavfi(src, 640, 360, 4) else {
|
|
return;
|
|
};
|
|
for q in [40, 80, 120, 160] {
|
|
run(&format!("{src}-intra"), &pics, RateControl::ConstantQ(q), 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn bench_1080p_loop() {
|
|
let Some(pics) = lavfi("mandelbrot", 1920, 1080, 4) else {
|
|
return;
|
|
};
|
|
run("mandelbrot", &pics, RateControl::ConstantQ(120), 30);
|
|
run("mandelbrot", &pics, RateControl::ConstantQ(120), 30);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn bench_rate_control() {
|
|
let Some(pics) = lavfi("mandelbrot", 480, 272, 60) else {
|
|
eprintln!("ffmpeg not available");
|
|
return;
|
|
};
|
|
for kbps in [200, 600, 2000] {
|
|
run("mandelbrot", &pics, RateControl::Bitrate { kbps }, 30);
|
|
}
|
|
let Some(pics) = lavfi("testsrc2", 480, 272, 60) else {
|
|
return;
|
|
};
|
|
for kbps in [300, 3000] {
|
|
run("testsrc2", &pics, RateControl::Bitrate { kbps }, 60);
|
|
}
|
|
}
|