1use crate::error::{Error, Result};
10use broadcast_common::{Parse, Serialize};
11
12pub const TICKS_PER_SECOND: u64 = 90_000;
14
15pub const PTS_MODULUS: u64 = 1 << 33;
18
19pub const PTS_MAX: u64 = PTS_MODULUS - 1;
21
22pub const DURATION_40_MAX: u64 = (1 << 40) - 1;
25
26#[must_use]
31pub fn ticks_to_duration(ticks: u64) -> core::time::Duration {
32 let nanos = (ticks as u128) * 1_000_000_000 / (TICKS_PER_SECOND as u128);
33 core::time::Duration::from_nanos(nanos as u64)
35}
36
37#[must_use]
41pub fn duration_to_ticks(d: core::time::Duration, max: u64) -> Option<u64> {
42 let nanos = d.as_nanos();
43 let ticks = nanos * (TICKS_PER_SECOND as u128) / 1_000_000_000;
44 if ticks > max as u128 {
45 None
46 } else {
47 Some(ticks as u64)
48 }
49}
50
51#[must_use]
54pub fn pts_add_wrapping(pts_time: u64, pts_adjustment: u64) -> u64 {
55 (pts_time.wrapping_add(pts_adjustment)) % PTS_MODULUS
56}
57
58#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
63#[cfg_attr(feature = "serde", derive(serde::Serialize))]
64pub struct SpliceTime {
65 pub pts_time: Option<u64>,
68}
69
70impl SpliceTime {
71 pub const LEN_WITH_TIME: usize = 5;
74 pub const LEN_NO_TIME: usize = 1;
76
77 #[must_use]
79 pub fn with_pts(pts_time: u64) -> Self {
80 Self {
81 pts_time: Some(pts_time & PTS_MAX),
82 }
83 }
84
85 #[must_use]
87 pub fn pts_time_duration(&self) -> Option<core::time::Duration> {
88 self.pts_time.map(ticks_to_duration)
89 }
90
91 pub fn set_pts_time_duration(&mut self, d: core::time::Duration) -> Result<()> {
94 let ticks = duration_to_ticks(d, PTS_MAX).ok_or(Error::InvalidValue {
95 field: "splice_time.pts_time",
96 reason: "duration exceeds 33-bit 90 kHz range",
97 })?;
98 self.pts_time = Some(ticks);
99 Ok(())
100 }
101}
102
103impl<'a> Parse<'a> for SpliceTime {
104 type Error = Error;
105 fn parse(bytes: &'a [u8]) -> Result<Self> {
106 if bytes.is_empty() {
107 return Err(Error::BufferTooShort {
108 need: 1,
109 have: 0,
110 what: "splice_time",
111 });
112 }
113 let time_specified = bytes[0] & 0x80 != 0;
114 if time_specified {
115 if bytes.len() < Self::LEN_WITH_TIME {
116 return Err(Error::BufferTooShort {
117 need: Self::LEN_WITH_TIME,
118 have: bytes.len(),
119 what: "splice_time pts_time",
120 });
121 }
122 let pts = ((u64::from(bytes[0] & 0x01)) << 32)
124 | (u64::from(bytes[1]) << 24)
125 | (u64::from(bytes[2]) << 16)
126 | (u64::from(bytes[3]) << 8)
127 | u64::from(bytes[4]);
128 Ok(Self {
129 pts_time: Some(pts),
130 })
131 } else {
132 Ok(Self { pts_time: None })
133 }
134 }
135}
136
137impl Serialize for SpliceTime {
138 type Error = Error;
139 fn serialized_len(&self) -> usize {
140 match self.pts_time {
141 Some(_) => Self::LEN_WITH_TIME,
142 None => Self::LEN_NO_TIME,
143 }
144 }
145
146 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
147 let need = self.serialized_len();
148 if buf.len() < need {
149 return Err(Error::OutputBufferTooSmall {
150 need,
151 have: buf.len(),
152 });
153 }
154 match self.pts_time {
155 Some(pts) => {
156 let pts = pts & PTS_MAX;
157 buf[0] = 0x80 | 0x7E | ((pts >> 32) as u8 & 0x01);
159 buf[1] = (pts >> 24) as u8;
160 buf[2] = (pts >> 16) as u8;
161 buf[3] = (pts >> 8) as u8;
162 buf[4] = pts as u8;
163 }
164 None => {
165 buf[0] = 0x7F;
167 }
168 }
169 Ok(need)
170 }
171}
172
173#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize))]
176pub struct BreakDuration {
177 pub auto_return: bool,
180 pub duration: u64,
182}
183
184impl BreakDuration {
185 pub const LEN: usize = 5;
188
189 #[must_use]
191 pub fn duration_value(&self) -> core::time::Duration {
192 ticks_to_duration(self.duration)
193 }
194
195 pub fn set_duration_value(&mut self, d: core::time::Duration) -> Result<()> {
198 self.duration = duration_to_ticks(d, PTS_MAX).ok_or(Error::InvalidValue {
199 field: "break_duration.duration",
200 reason: "duration exceeds 33-bit 90 kHz range",
201 })?;
202 Ok(())
203 }
204}
205
206impl<'a> Parse<'a> for BreakDuration {
207 type Error = Error;
208 fn parse(bytes: &'a [u8]) -> Result<Self> {
209 if bytes.len() < Self::LEN {
210 return Err(Error::BufferTooShort {
211 need: Self::LEN,
212 have: bytes.len(),
213 what: "break_duration",
214 });
215 }
216 let auto_return = bytes[0] & 0x80 != 0;
217 let duration = ((u64::from(bytes[0] & 0x01)) << 32)
218 | (u64::from(bytes[1]) << 24)
219 | (u64::from(bytes[2]) << 16)
220 | (u64::from(bytes[3]) << 8)
221 | u64::from(bytes[4]);
222 Ok(Self {
223 auto_return,
224 duration,
225 })
226 }
227}
228
229impl Serialize for BreakDuration {
230 type Error = Error;
231 fn serialized_len(&self) -> usize {
232 Self::LEN
233 }
234
235 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
236 if buf.len() < Self::LEN {
237 return Err(Error::OutputBufferTooSmall {
238 need: Self::LEN,
239 have: buf.len(),
240 });
241 }
242 let d = self.duration & PTS_MAX;
243 buf[0] = (u8::from(self.auto_return) << 7) | 0x7E | ((d >> 32) as u8 & 0x01);
245 buf[1] = (d >> 24) as u8;
246 buf[2] = (d >> 16) as u8;
247 buf[3] = (d >> 8) as u8;
248 buf[4] = d as u8;
249 Ok(Self::LEN)
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn ticks_duration_round_trip_exact() {
259 assert_eq!(
261 ticks_to_duration(90_000),
262 core::time::Duration::from_secs(1)
263 );
264 assert_eq!(
265 duration_to_ticks(core::time::Duration::from_secs(1), PTS_MAX),
266 Some(90_000)
267 );
268 }
269
270 #[test]
271 fn duration_to_ticks_rejects_over_range() {
272 let over = core::time::Duration::from_secs(95_444);
275 assert_eq!(duration_to_ticks(over, PTS_MAX), None);
276 assert_eq!(
278 duration_to_ticks(core::time::Duration::from_secs(95_443), PTS_MAX),
279 Some(95_443 * TICKS_PER_SECOND)
280 );
281 }
282
283 #[test]
284 fn pts_add_wraps_at_2pow33() {
285 assert_eq!(pts_add_wrapping(PTS_MAX, 1), 0);
287 assert_eq!(pts_add_wrapping(PTS_MAX, PTS_MAX), PTS_MAX - 1);
289 assert_eq!(pts_add_wrapping(10, 20), 30);
291 }
292
293 #[test]
294 fn splice_time_round_trip_with_and_without_pts() {
295 for st in [
296 SpliceTime::with_pts(0x1_2345_6789 & PTS_MAX),
297 SpliceTime::default(),
298 ] {
299 let bytes = st.to_bytes();
300 let back = SpliceTime::parse(&bytes).unwrap();
301 assert_eq!(st, back);
302 assert_eq!(back.to_bytes(), bytes);
303 }
304 }
305
306 #[test]
307 fn splice_time_max_pts_round_trips() {
308 let st = SpliceTime::with_pts(PTS_MAX);
309 let bytes = st.to_bytes();
310 assert_eq!(SpliceTime::parse(&bytes).unwrap().pts_time, Some(PTS_MAX));
311 }
312
313 #[test]
314 fn break_duration_round_trip() {
315 let bd = BreakDuration {
316 auto_return: true,
317 duration: PTS_MAX,
318 };
319 let bytes = bd.to_bytes();
320 let back = BreakDuration::parse(&bytes).unwrap();
321 assert_eq!(bd, back);
322 assert_eq!(back.to_bytes(), bytes);
323 }
324
325 #[test]
326 fn break_duration_decoded_accessor() {
327 let mut bd = BreakDuration::default();
328 bd.set_duration_value(core::time::Duration::from_secs(60))
329 .unwrap();
330 assert_eq!(bd.duration, 60 * 90_000);
331 assert_eq!(bd.duration_value(), core::time::Duration::from_secs(60));
332 }
333}