pito_codecs/filter/
fps.rs1use crate::media::{Error, Frame, Result, TimeBase};
2
3#[derive(Debug, Clone)]
4pub struct FpsConverter {
5 num: u32,
6 den: u32,
7 held: Option<(Frame, i64)>,
8 next: Option<i64>,
9}
10
11impl FpsConverter {
12 pub fn new(num: u32, den: u32) -> Result<Self> {
13 if num == 0 || den == 0 {
14 return Err(Error::Invalid(format!("frame rate {num}/{den}")));
15 }
16 Ok(FpsConverter {
17 num,
18 den,
19 held: None,
20 next: None,
21 })
22 }
23
24 pub fn time_base(&self) -> TimeBase {
25 TimeBase::new(self.den, self.num)
26 }
27
28 fn slot(&self, frame: &Frame) -> i64 {
29 let a = frame.pts as i128 * frame.time_base.num as i128 * self.num as i128;
30 let b = frame.time_base.den as i128 * self.den as i128;
31 if b == 0 {
32 return 0;
33 }
34 (2 * a + b).div_euclid(2 * b) as i64
35 }
36
37 pub fn push(&mut self, frame: Frame) -> Vec<Frame> {
38 let slot = self.slot(&frame);
39 let mut out = Vec::new();
40 if let Some((held, at)) = self.held.take() {
41 self.emit(held, at, slot, &mut out);
42 }
43 self.held = Some((frame, slot));
44 out
45 }
46
47 pub fn flush(&mut self) -> Vec<Frame> {
48 let mut out = Vec::new();
49 if let Some((held, at)) = self.held.take() {
50 let first = self.next.map_or(at, |n| n.max(at));
51 self.emit(held, at, first + 1, &mut out);
52 }
53 out
54 }
55
56 fn emit(&mut self, frame: Frame, at: i64, until: i64, out: &mut Vec<Frame>) {
57 let first = self.next.map_or(at, |n| n.max(at));
58 if until <= first {
59 return;
60 }
61 let tb = self.time_base();
62 for slot in first..until - 1 {
63 let mut f = frame.clone();
64 f.pts = slot;
65 f.time_base = tb;
66 out.push(f);
67 }
68 let mut f = frame;
69 f.pts = until - 1;
70 f.time_base = tb;
71 out.push(f);
72 self.next = Some(until);
73 }
74}