use crate::anchor::TimeAnchor;
use crate::convert::{scte35_to_daterange, scte35_to_emsg, EmsgConfig};
use crate::daterange::DateRange;
use crate::error::{Error, Result};
use crate::event::{MediaTime, TimedEvent};
use alloc::vec::Vec;
use dvb_common::traits::Parse;
use scte35_splice::SpliceInfoSection;
pub const PTS_WRAP: u64 = 1 << 33;
#[derive(Debug, Default)]
pub struct Timeline {
anchor: Option<TimeAnchor>,
last_pts: Option<u64>,
epoch: u64,
}
impl Timeline {
pub fn new() -> Self {
Self::default()
}
pub fn with_anchor(anchor: TimeAnchor) -> Self {
Timeline {
anchor: Some(anchor),
last_pts: None,
epoch: 0,
}
}
pub fn set_anchor(&mut self, anchor: TimeAnchor) {
self.anchor = Some(anchor);
}
pub fn push_scte35(&mut self, bytes: &[u8]) -> Result<TimedEvent> {
let section = SpliceInfoSection::parse(bytes)?;
let mut ev = TimedEvent::from_scte35(§ion, bytes)?;
if let Some(MediaTime(pts33)) = ev.at {
let abs = unroll_pts(&mut self.last_pts, &mut self.epoch, pts33);
ev.at = Some(MediaTime(abs));
}
Ok(ev)
}
pub fn to_daterange(&self, ev: &TimedEvent) -> Result<DateRange> {
let anchor = self.anchor.as_ref().ok_or(Error::MissingAnchor)?;
scte35_to_daterange(ev, anchor)
}
pub fn to_emsg(&self, ev: &TimedEvent, cfg: &EmsgConfig) -> Result<Vec<u8>> {
match &ev.source {
crate::event::SourcePayload::Scte35 { raw } => scte35_to_emsg(raw, cfg),
crate::event::SourcePayload::Emsg { .. } => Err(Error::AttrParse(
alloc::string::String::from("event is not SCTE-35-sourced"),
)),
}
}
}
pub(crate) fn unroll_pts(last_pts: &mut Option<u64>, epoch: &mut u64, pts33: u64) -> u64 {
if let Some(prev) = *last_pts {
if pts33 + (PTS_WRAP / 2) < prev {
*epoch += 1;
}
}
*last_pts = Some(pts33);
*epoch * PTS_WRAP + pts33
}
#[cfg(test)]
mod tests {
use super::*;
fn splice_2002() -> alloc::vec::Vec<u8> {
let hex = "FC302100000000000000FFF01005000007D27FEF7F7E0020F580C0000000000088B9661D";
(0..hex.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap())
.collect()
}
#[test]
fn push_scte35_returns_event() {
let mut tl = Timeline::new();
let ev = tl.push_scte35(&splice_2002()).unwrap();
assert_eq!(ev.id, Some(2002));
}
#[test]
fn to_daterange_without_anchor_errors() {
let tl = Timeline::new();
let ev = Timeline::new().push_scte35(&splice_2002()).unwrap();
assert!(matches!(
tl.to_daterange(&ev),
Err(crate::Error::MissingAnchor)
));
}
#[test]
fn wrap_unroll_adds_one_epoch() {
assert_eq!(
unroll_pts(&mut Some((1u64 << 33) - 10), &mut 0u64, 5),
5 + (1u64 << 33)
);
}
#[test]
fn wrap_unroll_forward_delta_keeps_epoch() {
let (mut last, mut epoch) = (Some(1_000u64), 0u64);
assert_eq!(unroll_pts(&mut last, &mut epoch, 2_000), 2_000);
assert_eq!(epoch, 0);
let (mut last2, mut epoch2) = (None, 0u64);
assert_eq!(unroll_pts(&mut last2, &mut epoch2, 42), 42);
assert_eq!(epoch2, 0);
}
}