1use std::process;
15
16use ff_analysis::KeyframeEnumerator;
17
18fn main() {
19 let mut args = std::env::args().skip(1);
20 let mut input = None::<String>;
21 let mut stream_index = None::<usize>;
22
23 while let Some(flag) = args.next() {
24 match flag.as_str() {
25 "--input" | "-i" => input = Some(args.next().unwrap_or_default()),
26 "--stream" | "-s" => {
27 let raw = args.next().unwrap_or_default();
28 stream_index = Some(raw.parse().unwrap_or_else(|_| {
29 eprintln!("Invalid stream index: {raw}");
30 process::exit(1);
31 }));
32 }
33 other => {
34 eprintln!("Unknown flag: {other}");
35 process::exit(1);
36 }
37 }
38 }
39
40 let input = input.unwrap_or_else(|| {
41 eprintln!("Usage: keyframes --input <video> [--stream <index>]");
42 process::exit(1);
43 });
44
45 println!("Enumerating keyframes in: {input}");
46 if let Some(idx) = stream_index {
47 println!("Stream index: {idx}");
48 } else {
49 println!("Stream: first video stream (default)");
50 }
51 println!();
52
53 let mut enumerator = KeyframeEnumerator::new(&input);
54 if let Some(idx) = stream_index {
55 enumerator = enumerator.stream_index(idx);
56 }
57
58 let keyframes = enumerator.run().unwrap_or_else(|e| {
59 eprintln!("Error: {e}");
60 process::exit(1);
61 });
62
63 println!("Found {} keyframe(s):", keyframes.len());
64
65 let display_count = keyframes.len().min(30);
67 for (i, ts) in keyframes.iter().take(display_count).enumerate() {
68 let h = ts.as_secs() / 3600;
69 let m = (ts.as_secs() % 3600) / 60;
70 let s = ts.as_secs() % 60;
71 let ms = ts.subsec_millis();
72 println!(" [{i:4}] {h:02}:{m:02}:{s:02}.{ms:03}");
73 }
74 if keyframes.len() > display_count {
75 println!(" … ({} more keyframes)", keyframes.len() - display_count);
76 }
77
78 if !keyframes.is_empty() {
79 let avg_interval_ms = keyframes
80 .windows(2)
81 .map(|w| w[1].saturating_sub(w[0]).as_millis())
82 .sum::<u128>()
83 .checked_div((keyframes.len() - 1) as u128)
84 .unwrap_or(0);
85 println!();
86 println!("Average keyframe interval: {avg_interval_ms} ms");
87 }
88}