Skip to main content

me_snap_ab/
me_snap_ab.rs

1// Dev/test target, not shipped: a panic here IS the diagnostic (that is what an
2// assertion is). The workspace's unwrap/expect/panic denials exist to keep them
3// off the decoder's untrusted-input path, so they are relaxed for this file.
4#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
5// Dev tools also accumulate fields and helpers kept for the NEXT investigation;
6// dead code here is a scratchpad, not a defect.
7#![allow(dead_code, unused)]
8#![allow(clippy::unnecessary_unwrap, clippy::zombie_processes)]
9//! Interleaved A/B of the integer-pel diamond-centre snap (`tune_me_snap`).
10//!
11//! Both arms in ONE process, alternating pass by pass, best-of-N — this box drifts
12//! ~20% run to run, far more than the effect.
13//!
14//! ```text
15//! cargo run --release -p rusty_h264-encoder --example me_snap_ab -- <clip.yuv> <w>x<h>
16//! ```
17use rusty_h264_common::YuvFrame;
18use rusty_h264_encoder::{Encoder, EncoderConfig, Preset};
19
20fn load(path: &str, w: usize, h: usize, n: usize) -> Vec<YuvFrame> {
21    let raw = std::fs::read(path).expect("clip");
22    let fsz = w * h * 3 / 2;
23    raw.chunks_exact(fsz).take(n).map(|c| {
24        let mut fr = YuvFrame::black(w, h);
25        fr.y.copy_from_slice(&c[..w * h]);
26        fr.u.copy_from_slice(&c[w * h..w * h + w * h / 4]);
27        fr.v.copy_from_slice(&c[w * h + w * h / 4..]);
28        fr
29    }).collect()
30}
31
32fn main() {
33    let a: Vec<String> = std::env::args().skip(1).collect();
34    let (w, h) = a[1].split_once('x').unwrap();
35    let (w, h): (usize, usize) = (w.parse().unwrap(), h.parse().unwrap());
36    let frames = load(&a[0], w, h, std::env::var("RS_FRAMES").ok().and_then(|v| v.parse().ok()).unwrap_or(60));
37    let preset = match std::env::var("RS_PRESET").unwrap_or_default().as_str() {
38        "fast" => Preset::Fast, "quality" => Preset::Quality, _ => Preset::Balanced,
39    };
40    let arm_off: u32 = std::env::var("RS_ARM_OFF").ok().and_then(|v| v.parse().ok()).unwrap_or(0);
41    let arm_on: u32 = std::env::var("RS_ARM_ON").ok().and_then(|v| v.parse().ok()).unwrap_or(3);
42    let run = |on: bool| {
43        let m = if on { arm_on } else { arm_off };
44        let mut cfg = EncoderConfig::new(w, h);
45        cfg.qp = std::env::var("RS_QP").ok().and_then(|v| v.parse().ok()).unwrap_or(27);
46        cfg.gop_size = 30;
47        cfg.preset = preset;
48        cfg.tune_me_snap = m & 1 != 0;
49        cfg.tune_me_subpel_iter = m & 2 != 0;
50        let mut enc = Encoder::new(cfg).expect("enc");
51        let t = std::time::Instant::now();
52        let mut b = 0usize;
53        for f in &frames { b += enc.encode(f).len(); }
54        (t.elapsed().as_secs_f64(), b)
55    };
56    let mut best = [f64::MAX; 2];
57    let mut bytes = [0usize; 2];
58    for pass in 0..10 {
59        let arm = pass % 2;
60        let (t, b) = run(arm == 1);
61        if t < best[arm] { best[arm] = t; }
62        bytes[arm] = b;
63    }
64    let px = (w * h * frames.len()) as f64;
65    println!("arm {arm_off} -> {arm_on} — {} {w}x{h} {} frames {preset:?}", a[0], frames.len());
66    println!("  off : {:>7.1} ms  {:>6.2} Mpx/s  {:>9} bytes", best[0]*1e3, px/best[0]/1e6, bytes[0]);
67    println!("  on  : {:>7.1} ms  {:>6.2} Mpx/s  {:>9} bytes", best[1]*1e3, px/best[1]/1e6, bytes[1]);
68    println!("  speed {:>6.3}x   size {:>+6.2}%", best[0]/best[1],
69             100.0*(bytes[1] as f64/bytes[0] as f64 - 1.0));
70}