Skip to main content

pito_codecs/filter/
fps.rs

1use 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}