Skip to main content

bframes_signals/
bframes_signals.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//! bframes-v2 gate fit harness: per-clip gate signals next to the measured
10//! B-frame BD truth (fixed3-vs-0 sign). Fit on the 12-clip table; the unused
11//! corpus clips are the HOLDOUTS (holdout-both-sides law).
12//!
13//!   cargo run --release -p rusty_h264-encoder --example bframes_signals -- <clip.y4m> [frames]
14
15use rusty_h264_encoder::EncoderConfig;
16
17fn read_y4m(path: &str, max_frames: usize) -> (usize, usize, Vec<rusty_h264_common::types::YuvFrame>) {
18    let raw = std::fs::read(path).unwrap_or_else(|e| panic!("read {path}: {e}"));
19    let hdr_end = raw.iter().position(|&b| b == b'\n').expect("y4m header");
20    let hdr = std::str::from_utf8(&raw[..hdr_end]).expect("utf8 header");
21    let (mut w, mut h) = (0usize, 0usize);
22    for tok in hdr.split_whitespace() {
23        match tok.as_bytes().first() {
24            Some(b'W') => w = tok[1..].parse().expect("width"),
25            Some(b'H') => h = tok[1..].parse().expect("height"),
26            _ => {}
27        }
28    }
29    let (ys, cs) = (w * h, (w / 2) * (h / 2));
30    let mut frames = Vec::new();
31    let mut p = hdr_end + 1;
32    while frames.len() < max_frames {
33        let Some(rel) = raw[p..].iter().position(|&b| b == b'\n') else { break };
34        p += rel + 1;
35        if p + ys + 2 * cs > raw.len() {
36            break;
37        }
38        frames.push(rusty_h264_common::types::YuvFrame {
39            width: w,
40            height: h,
41            y: raw[p..p + ys].to_vec(),
42            u: raw[p + ys..p + ys + cs].to_vec(),
43            v: raw[p + ys + cs..p + ys + 2 * cs].to_vec(),
44        });
45        p += ys + 2 * cs;
46    }
47    (w, h, frames)
48}
49
50fn main() {
51    let mut args = std::env::args().skip(1);
52    let path = args.next().expect("clip");
53    let nframes: usize = args.next().and_then(|s| s.parse().ok()).unwrap_or(30);
54    let (w, h, frames) = read_y4m(&path, nframes);
55    let name = std::path::Path::new(&path).file_stem().unwrap().to_string_lossy().to_string();
56    let cfg = EncoderConfig::new(w, h);
57    let (bi, gmc, mg, dc, screen, grain) = rusty_h264_encoder::bframes_gate_signals(&cfg, &frames);
58    println!(
59        "{name:<24} bi={bi:>7.3} gmc={gmc:>8.3} mgain={mg:.3} dcfrac={dc:.3} screen={} grain={}",
60        screen as u8, grain as u8
61    );
62}