yog_registry/videos/
clock.rs1use std::ops::Range;
5
6use super::VideoDef;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct Plan {
11 pub reset: bool,
13 pub frames: Range<u32>,
15}
16
17impl VideoDef {
18 #[must_use]
22 pub fn plan(&self, shown: Option<u32>, target: u32) -> Plan {
23 let target = target.min(self.frames().saturating_sub(1));
24 let key = self.keyframe_before(target);
25 match shown {
26 Some(s) if s == target => Plan {
27 reset: false,
28 frames: target..target,
29 },
30 Some(s) if s < target && key <= s => Plan {
31 reset: false,
32 frames: s + 1..target + 1,
33 },
34 _ => Plan {
35 reset: true,
36 frames: key..target + 1,
37 },
38 }
39 }
40}
41
42#[derive(Debug, Clone, Default, PartialEq)]
44pub struct Clock {
45 pub at: f64,
47 pub playing: bool,
48}
49
50impl Clock {
51 pub fn advance(&mut self, def: &VideoDef, dt: f64) -> u32 {
54 if self.playing {
55 self.at += dt;
56 }
57 let length = def.seconds();
58 if self.at >= length {
59 if def.looping && length > 0.0 {
60 self.at %= length;
61 } else {
62 self.at = length;
63 self.playing = false;
64 }
65 }
66 self.frame(def)
67 }
68
69 pub fn seek(&mut self, def: &VideoDef, seconds: f64) {
71 self.at = seconds.clamp(0.0, def.seconds());
72 }
73
74 #[must_use]
76 pub fn frame(&self, def: &VideoDef) -> u32 {
77 let last = def.frames().saturating_sub(1);
78 ((self.at / def.frame_seconds()) as u32).min(last)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 fn def(looping: bool) -> VideoDef {
88 VideoDef {
89 id: "m:v".into(),
90 width: 2,
91 height: 2,
92 fps_num: 10,
93 fps_den: 1,
94 sizes: vec![1; 10],
95 packets: vec![0; 10],
96 keyframes: vec![0, 5],
97 sound: None,
98 volume: 1.0,
99 looping,
100 }
101 }
102
103 #[test]
104 fn a_plan_goes_on_or_starts_at_the_keyframe_before() {
105 let v = def(false);
106 let plan = |shown, target| v.plan(shown, target);
107 assert_eq!(
108 plan(None, 3),
109 Plan {
110 reset: true,
111 frames: 0..4
112 }
113 );
114 assert_eq!(
115 plan(Some(1), 3),
116 Plan {
117 reset: false,
118 frames: 2..4
119 }
120 );
121 assert_eq!(plan(Some(3), 3).frames, 3..3);
122 assert_eq!(
123 plan(Some(3), 7),
124 Plan {
125 reset: true,
126 frames: 5..8
127 }
128 );
129 assert_eq!(
130 plan(Some(7), 2),
131 Plan {
132 reset: true,
133 frames: 0..3
134 }
135 );
136 assert_eq!(plan(None, 99).frames, 5..10);
137 }
138
139 #[test]
140 fn a_clock_loops_or_stops_at_the_end() {
141 let v = def(true);
142 let mut c = Clock {
143 at: 0.0,
144 playing: true,
145 };
146 assert_eq!(c.advance(&v, 0.35), 3);
147 assert_eq!(c.advance(&v, 0.8), 1, "wrapped round");
148 let v = def(false);
149 let mut c = Clock {
150 at: 0.9,
151 playing: true,
152 };
153 assert_eq!(c.advance(&v, 5.0), 9);
154 assert!(!c.playing);
155 c.seek(&v, -1.0);
156 assert_eq!(c.frame(&v), 0);
157 }
158}