1use crate::{CoreError, SourceId};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub struct MediaTime {
11 ticks: i64,
12 timescale: u32,
13}
14
15impl Default for MediaTime {
16 fn default() -> Self {
17 Self {
18 ticks: 0,
19 timescale: 1,
20 }
21 }
22}
23
24impl MediaTime {
25 pub const fn new(ticks: i64, timescale: u32) -> Result<Self, CoreError> {
31 if timescale == 0 {
32 return Err(CoreError::InvalidMediaTime);
33 }
34 Ok(Self { ticks, timescale })
35 }
36
37 #[must_use]
39 pub const fn ticks(self) -> i64 {
40 self.ticks
41 }
42
43 #[must_use]
45 pub const fn timescale(self) -> u32 {
46 self.timescale
47 }
48
49 #[must_use]
51 pub fn as_nanos(self) -> i64 {
52 let ticks = i128::from(self.ticks);
53 let scale = i128::from(self.timescale);
54 let nanos = ticks
55 .saturating_mul(1_000_000_000)
56 .checked_div(scale)
57 .unwrap_or(0);
58 i64::try_from(nanos).unwrap_or(if nanos.is_positive() {
59 i64::MAX
60 } else {
61 i64::MIN
62 })
63 }
64
65 #[must_use]
67 pub fn duration_since_ns(self, earlier: Self) -> i64 {
68 self.as_nanos().saturating_sub(earlier.as_nanos())
69 }
70}
71
72#[derive(Clone, Copy, Debug, PartialEq)]
74pub struct FrameStamp {
75 pub source_id: SourceId,
77 pub frame_index: u64,
79 pub pts: MediaTime,
81 pub wall_clock_ns: Option<i64>,
83}
84
85impl FrameStamp {
86 #[must_use]
88 pub fn new(
89 source_id: SourceId,
90 frame_index: u64,
91 pts: MediaTime,
92 wall_clock_ns: Option<i64>,
93 ) -> Self {
94 Self {
95 source_id,
96 frame_index,
97 pts,
98 wall_clock_ns,
99 }
100 }
101}