thread_bench/
thread_bench.rs1#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
5#![allow(dead_code, unused)]
8#![allow(clippy::unnecessary_unwrap, clippy::zombie_processes)]
9use rusty_h264_common::types::YuvFrame;
13use rusty_h264_encoder::{Encoder, EncoderConfig, Preset};
14
15fn read_y4m(path: &str, max: usize) -> (usize, usize, Vec<YuvFrame>) {
16 let raw = std::fs::read(path).unwrap();
17 let e = raw.iter().position(|&b| b == b'\n').unwrap();
18 let hdr = std::str::from_utf8(&raw[..e]).unwrap();
19 let (mut w, mut h) = (0usize, 0usize);
20 for t in hdr.split_whitespace() {
21 match t.as_bytes().first() {
22 Some(b'W') => w = t[1..].parse().unwrap(),
23 Some(b'H') => h = t[1..].parse().unwrap(),
24 _ => {}
25 }
26 }
27 let (ys, cs) = (w * h, (w / 2) * (h / 2));
28 let (mut f, mut p) = (Vec::new(), e + 1);
29 while f.len() < max {
30 let Some(r) = raw[p..].iter().position(|&b| b == b'\n') else { break };
31 p += r + 1;
32 if p + ys + 2 * cs > raw.len() { break }
33 f.push(YuvFrame { width: w, height: h, y: raw[p..p+ys].to_vec(), u: raw[p+ys..p+ys+cs].to_vec(), v: raw[p+ys+cs..p+ys+2*cs].to_vec() });
34 p += ys + 2 * cs;
35 }
36 (w, h, f)
37}
38
39fn main() {
40 let path = std::env::args().nth(1).unwrap();
41 let n: usize = std::env::var("TB_FRAMES").ok().and_then(|v| v.parse().ok()).unwrap_or(240);
42 let gop: u32 = std::env::var("TB_GOP").ok().and_then(|v| v.parse().ok()).unwrap_or(30);
43 let (w, h, frames) = read_y4m(&path, n);
44 for (pn, preset) in [("balanced", Preset::Balanced), ("quality", Preset::Quality)] {
45 let mut cfg = EncoderConfig::new(w, h);
46 cfg.qp = 27; cfg.gop_size = gop; cfg.preset = preset;
47 let mut seq_ms = f64::MAX; let mut seq_out = Vec::new();
49 for _ in 0..3 {
50 let mut enc = Encoder::new(cfg.clone()).unwrap();
51 let t = std::time::Instant::now();
52 let mut o = Vec::new();
53 for f in &frames { o.extend_from_slice(&enc.encode(f)); }
54 seq_ms = seq_ms.min(t.elapsed().as_secs_f64() * 1e3);
55 seq_out = o;
56 }
57 let mut par_ms = f64::MAX; let mut par_out = Vec::new();
58 for _ in 0..3 {
59 let enc = Encoder::new(cfg.clone()).unwrap();
60 let t = std::time::Instant::now();
61 let o: Vec<u8> = enc.encode_all(&frames).unwrap().concat();
62 par_ms = par_ms.min(t.elapsed().as_secs_f64() * 1e3);
63 par_out = o;
64 }
65 assert_eq!(seq_out, par_out, "seq != parallel — compression WOULD be compromised");
66 println!("{pn:<9} x{} gop{gop}: seq {seq_ms:.0} ms parallel {par_ms:.0} ms speedup {:.2}x (byte-identical ✓)", frames.len(), seq_ms / par_ms);
67 }
68}