Skip to main content

me_oracle/
me_oracle.rs

1//! Is our motion search FINDING the best vector available to it?
2//!
3//! `enc-me` is 62% of encode and runs at x264-medium's cost per macroblock while
4//! delivering worse compression than x264-veryfast. That is either a SEARCH
5//! failure (we don't find the good vectors) or an efficiency failure elsewhere
6//! (we find them and lose the benefit downstream). This separates the two by
7//! pricing our chosen vector against an exhaustive +-24 full-pel search using the
8//! IDENTICAL cost function and sub-pel pass.
9//!
10//! ```text
11//! RFF_ME_ORACLE=1 cargo run --release -p rusty_h264-encoder --example me_oracle -- <clip.yuv> <w>x<h>
12//! ```
13use rusty_h264_common::YuvFrame;
14use rusty_h264_encoder::{Encoder, EncoderConfig, Preset};
15
16fn load(path: &str, w: usize, h: usize, n: usize) -> Vec<YuvFrame> {
17    let raw = std::fs::read(path).expect("clip");
18    let fsz = w * h * 3 / 2;
19    raw.chunks_exact(fsz)
20        .take(n)
21        .map(|c| {
22            let mut fr = YuvFrame::black(w, h);
23            fr.y.copy_from_slice(&c[..w * h]);
24            fr.u.copy_from_slice(&c[w * h..w * h + w * h / 4]);
25            fr.v.copy_from_slice(&c[w * h + w * h / 4..]);
26            fr
27        })
28        .collect()
29}
30
31fn main() {
32    let a: Vec<String> = std::env::args().skip(1).collect();
33    let (w, h) = a[1].split_once('x').unwrap();
34    let (w, h): (usize, usize) = (w.parse().unwrap(), h.parse().unwrap());
35    let nf: usize = std::env::var("RS_FRAMES").ok().and_then(|v| v.parse().ok()).unwrap_or(20);
36    let frames = load(&a[0], w, h, nf);
37
38    let preset = match std::env::var("RS_PRESET").unwrap_or_default().as_str() {
39        "fast" => Preset::Fast,
40        "quality" => Preset::Quality,
41        _ => Preset::Balanced,
42    };
43    let mut cfg = EncoderConfig::new(w, h);
44    cfg.qp = std::env::var("RS_QP").ok().and_then(|v| v.parse().ok()).unwrap_or(27);
45    cfg.gop_size = 30;
46    cfg.preset = preset;
47    let mut enc = Encoder::new(cfg).expect("encoder");
48    for f in &frames {
49        let _ = enc.encode(f);
50    }
51
52    let p: Vec<u64> = rusty_h264_encoder::ME_PROBE
53        .iter()
54        .map(|c| c.load(std::sync::atomic::Ordering::Relaxed))
55        .collect();
56    let (n, ours, oracle, worse, evals) = (p[0].max(1), p[1], p[2], p[3], p[4]);
57    let (oracle_sp, worse_sp) = (p[5], p[6]);
58    println!("ME oracle — {} ({w}x{h}, {} frames, {preset:?})\n", a[0], frames.len());
59    println!("  searches                {n}");
60    println!("  mean cost   ours        {:>10.1}", ours as f64 / n as f64);
61    println!("  mean cost   exhaustive  {:>10.1}", oracle as f64 / n as f64);
62    println!("  ---> we are {:>6.2}% above the achievable minimum",
63             100.0 * (ours as f64 - oracle as f64) / oracle as f64);
64    println!("  searches the oracle beat {:>9} ({:.1}%)", worse, 100.0 * worse as f64 / n as f64);
65    // the oracle's own 49x49 grid + 8 sub-pel probes are included in `evals`
66    println!("
67  + exhaustive SUB-PEL (all quarter-pel in +-3):");
68    println!("  mean cost   exhaustive  {:>10.1}", oracle_sp as f64 / n as f64);
69    println!("  ---> we are {:>6.2}% above the achievable minimum",
70             100.0 * (ours as f64 - oracle_sp as f64) / oracle_sp as f64);
71    println!("  searches it beat        {:>9} ({:.1}%)", worse_sp, 100.0 * worse_sp as f64 / n as f64);
72    let oracle_evals = 0;
73    println!("\n  cost() evals/search     {:>8.1}  (ours, oracle's {oracle_evals} excluded)",
74             evals as f64 / n as f64 - oracle_evals as f64);
75}