scenecut_probe/
scenecut_probe.rs1use rusty_h264_encoder::EncoderConfig;
10
11fn read_y4m(path: &str, max_frames: usize) -> (usize, usize, Vec<rusty_h264_common::types::YuvFrame>) {
12 let raw = std::fs::read(path).unwrap_or_else(|e| panic!("read {path}: {e}"));
13 let hdr_end = raw.iter().position(|&b| b == b'\n').expect("y4m header");
14 let hdr = std::str::from_utf8(&raw[..hdr_end]).expect("utf8 header");
15 let (mut w, mut h) = (0usize, 0usize);
16 for tok in hdr.split_whitespace() {
17 match tok.as_bytes().first() {
18 Some(b'W') => w = tok[1..].parse().expect("width"),
19 Some(b'H') => h = tok[1..].parse().expect("height"),
20 _ => {}
21 }
22 }
23 let (ys, cs) = (w * h, (w / 2) * (h / 2));
24 let mut frames = Vec::new();
25 let mut p = hdr_end + 1;
26 while frames.len() < max_frames {
27 let Some(rel) = raw[p..].iter().position(|&b| b == b'\n') else { break };
28 p += rel + 1;
29 if p + ys + 2 * cs > raw.len() {
30 break;
31 }
32 frames.push(rusty_h264_common::types::YuvFrame {
33 width: w,
34 height: h,
35 y: raw[p..p + ys].to_vec(),
36 u: raw[p + ys..p + ys + cs].to_vec(),
37 v: raw[p + ys + cs..p + ys + 2 * cs].to_vec(),
38 });
39 p += ys + 2 * cs;
40 }
41 (w, h, frames)
42}
43
44fn main() {
45 let mut args = std::env::args().skip(1);
46 let path = args.next().expect("clip");
47 let nframes: usize = args.next().and_then(|s| s.parse().ok()).unwrap_or(60);
48 let (w, h, frames) = read_y4m(&path, nframes);
49 let name = std::path::Path::new(&path).file_stem().unwrap().to_string_lossy().to_string();
50 let cfg = EncoderConfig::new(w, h); let ratios = rusty_h264_encoder::scene_cut_ratios(&cfg, &frames);
52 let max = ratios.iter().cloned().fold(0.0f64, f64::max);
53 let thresh = 1.0 - cfg.scenecut as f64 / 100.0;
54 let flat = ratios.iter().filter(|&&r| r >= thresh).count();
55 let mut spike = 0usize;
58 for i in 0..ratios.len() {
59 let base = match i {
60 0 => 1.0,
61 1 => ratios[0],
62 _ => ratios[i - 1].min(ratios[i - 2]),
63 };
64 if ratios[i] >= thresh && ratios[i] >= base + 0.25 {
65 spike += 1;
66 }
67 }
68 println!(
69 "{name:<24} pairs={} max_ratio={max:.3} flat@{thresh:.2}={flat} spike={spike}",
70 ratios.len()
71 );
72}