1use std::fmt::Write as _;
4
5use crate::plan::{Plan, key_set};
6
7#[derive(Debug, Clone, PartialEq)]
9pub struct Diff {
10 pub segments: Vec<(usize, bool)>,
12 pub dropped: usize,
14 pub audio_changed: bool,
15}
16
17impl Diff {
18 pub fn new(old: &Plan, new: &Plan) -> Self {
19 let old_keys = key_set(old);
20 let new_keys = key_set(new);
21 Self {
22 segments: new
23 .segments
24 .iter()
25 .enumerate()
26 .map(|(i, s)| (i, !old_keys.contains(&s.key)))
27 .collect(),
28 dropped: old_keys.difference(&new_keys).count(),
29 audio_changed: old.audio.as_ref().map(|a| &a.key) != new.audio.as_ref().map(|a| &a.key),
30 }
31 }
32
33 pub fn render_count(&self) -> usize {
34 self.segments.iter().filter(|(_, r)| *r).count()
35 }
36
37 #[allow(clippy::cast_precision_loss)]
39 pub fn report(&self, new: &Plan, all: bool) -> String {
40 let mut out = String::new();
41 let secs = |f: i64| f as f64 / new.rate;
42 let mut render_frames = 0;
43 for &(i, render) in &self.segments {
44 let s = &new.segments[i];
45 if render {
46 render_frames += s.frames;
47 }
48 if render || all {
49 let t = secs(s.start);
50 let _ = writeln!(
51 out,
52 "{} {:>3}:{:06.3} {:>5}f {:<32} {}",
53 if render { '+' } else { '=' },
54 (t / 60.0).floor(),
55 t % 60.0,
56 s.frames,
57 s.name,
58 s.key.short()
59 );
60 }
61 }
62 let n = self.render_count();
63 let _ = writeln!(
64 out,
65 "{n} of {} segments render ({:.1} s of {:.1} s), {} old dropped; audio {}",
66 self.segments.len(),
67 secs(render_frames),
68 secs(new.frames()),
69 self.dropped,
70 if self.audio_changed {
71 "changed"
72 } else {
73 "same"
74 },
75 );
76 if n == 0 {
77 let _ = writeln!(
78 out,
79 "{}",
80 if self.audio_changed {
81 "picture unchanged: audio remux only (no video encode)"
82 } else {
83 "nothing to render"
84 }
85 );
86 }
87 out
88 }
89}