pub(crate) const DISCONTINUITY_BACKSTEP_NS: i64 = 3_000_000_000;
pub(crate) const DISCONTINUITY_GAP_NS: i64 = 1_000_000;
pub(crate) struct TimelineContinuity {
pub(crate) offset_ns: i64,
pub(crate) prev_offset_ns: i64,
pub(crate) high_ns: Option<i64>,
}
impl TimelineContinuity {
pub(crate) fn new() -> Self {
Self {
offset_ns: 0,
prev_offset_ns: 0,
high_ns: None,
}
}
pub(crate) fn adjust(&mut self, raw_pts_ns: i64, drives_epoch: bool) -> i64 {
if !drives_epoch {
let mapped = raw_pts_ns.saturating_add(self.offset_ns);
if let Some(high) = self.high_ns {
if mapped > high + DISCONTINUITY_BACKSTEP_NS {
let prev_mapped = raw_pts_ns.saturating_add(self.prev_offset_ns);
if prev_mapped <= high && prev_mapped >= high - DISCONTINUITY_BACKSTEP_NS {
return prev_mapped;
}
}
}
return mapped;
}
let Some(high) = self.high_ns else {
let adj = raw_pts_ns.saturating_add(self.offset_ns);
self.high_ns = Some(adj);
return adj;
};
let adj = raw_pts_ns.saturating_add(self.offset_ns);
if adj < high - DISCONTINUITY_BACKSTEP_NS {
self.prev_offset_ns = self.offset_ns;
let bump = (high - adj).saturating_add(DISCONTINUITY_GAP_NS);
self.offset_ns = self.offset_ns.saturating_add(bump);
let adj2 = raw_pts_ns.saturating_add(self.offset_ns);
self.high_ns = Some(high.max(adj2));
adj2
} else {
self.high_ns = Some(high.max(adj));
adj
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const S: i64 = 1_000_000_000;
fn adj_video(tc: &mut TimelineContinuity, p: i64) -> i64 {
tc.adjust(p, true)
}
fn adj_other(tc: &mut TimelineContinuity, p: i64) -> i64 {
tc.adjust(p, false)
}
#[test]
fn continuity_rebases_clip_boundary_reset() {
let clip1: Vec<i64> = (0..=10).map(|i| i * S).collect(); let clip2: Vec<i64> = (0..=10).map(|i| i * S).collect(); let raw: Vec<i64> = clip1.iter().chain(clip2.iter()).copied().collect();
assert!(
raw.windows(2).any(|w| w[1] < w[0]),
"precondition: raw clip-reset sequence is non-monotonic"
);
let mut tc = TimelineContinuity::new();
let out: Vec<i64> = raw.iter().map(|&p| adj_video(&mut tc, p)).collect();
assert!(
out.windows(2).all(|w| w[1] >= w[0]),
"corrected timeline must be monotonic non-decreasing, got {out:?}"
);
assert_eq!(out[11], 10 * S + DISCONTINUITY_GAP_NS);
assert!(out[21] > 19 * S);
}
#[test]
fn continuity_preserves_bframe_reorder() {
let mut tc = TimelineContinuity::new();
let raw = [0i64, 125_000_000, 42_000_000, 83_000_000, 250_000_000];
let out: Vec<i64> = raw.iter().map(|&p| adj_video(&mut tc, p)).collect();
assert_eq!(out, raw, "B-frame reorder must pass through unchanged");
assert_eq!(tc.offset_ns, 0, "no rebase for sub-threshold reorder");
}
#[test]
fn continuity_preserves_forward_gap() {
let mut tc = TimelineContinuity::new();
let raw = [0i64, S, 2 * S + 500_000_000, 4 * S]; let out: Vec<i64> = raw.iter().map(|&p| adj_video(&mut tc, p)).collect();
assert_eq!(out, raw, "forward gap preserved verbatim");
assert_eq!(tc.offset_ns, 0, "no rebase on forward progression");
}
#[test]
fn single_clip_late_subtitle_does_not_inflate_offset() {
let mut tc = TimelineContinuity::new();
let mut max_out = i64::MIN;
for sec in 0..=60 {
let v = adj_video(&mut tc, sec * S);
max_out = max_out.max(v);
if sec % 7 == 0 && sec >= 7 {
let sub_raw = (sec - 5) * S;
let s = adj_other(&mut tc, sub_raw);
assert_eq!(s, sub_raw, "subtitle rides the current offset");
}
}
assert_eq!(
tc.offset_ns, 0,
"single-clip interleave must not ratchet offset (was {})",
tc.offset_ns
);
assert_eq!(tc.high_ns, Some(60 * S), "frontier tracks video only");
assert!(max_out <= 60 * S, "no timeline inflation, max={max_out}");
}
#[test]
fn dv_enhancement_layer_does_not_drive_epochs() {
let mut tc = TimelineContinuity::new();
let mut max_out = i64::MIN;
for sec in 0..=60 {
let bl = adj_video(&mut tc, sec * S);
let el_raw = if sec > 0 { (sec - 1) * S } else { 0 };
let el = adj_other(&mut tc, el_raw);
assert_eq!(el, el_raw, "EL rides current offset, true PTS preserved");
max_out = max_out.max(bl).max(el);
}
assert_eq!(
tc.offset_ns, 0,
"DV EL interleave must not ratchet offset (was {})",
tc.offset_ns
);
assert_eq!(tc.high_ns, Some(60 * S), "frontier tracks base video only");
assert!(max_out <= 60 * S, "no timeline inflation, max={max_out}");
}
#[test]
fn non_video_never_advances_frontier() {
let mut tc = TimelineContinuity::new();
adj_video(&mut tc, 0);
adj_video(&mut tc, 5 * S);
let frontier = tc.high_ns.unwrap();
let s = adj_other(&mut tc, 25 * S);
assert_eq!(s, 25 * S, "non-video maps under current offset");
assert_eq!(
tc.high_ns.unwrap(),
frontier,
"non-video must NOT advance the frontier"
);
let v = adj_video(&mut tc, 6 * S);
assert_eq!(v, 6 * S, "video continues normally, no false boundary");
assert_eq!(
tc.offset_ns, 0,
"no rebase triggered by the leading subtitle"
);
}
#[test]
fn continuity_large_clip_boundary_backjump_rebased() {
let mut tc = TimelineContinuity::new();
let clip1: Vec<i64> = (0..=780).map(|i| i * S).collect();
let clip2: Vec<i64> = (0..=120).map(|i| i * S).collect();
let mut last = i64::MIN;
let mut max = i64::MIN;
for &p in clip1.iter().chain(clip2.iter()) {
let a = adj_video(&mut tc, p);
assert!(
a >= last,
"rebased timeline must be monotonic, got {a} < {last}"
);
last = a;
max = max.max(a);
}
assert_eq!(tc.offset_ns, 780 * S + DISCONTINUITY_GAP_NS);
assert!(
(900 * S..901 * S).contains(&max),
"timeline must span ~900s (clip1+clip2), got {max}"
);
}
#[test]
fn non_video_straggler_remapped_to_seam_at_boundary() {
let mut tc = TimelineContinuity::new();
for i in 0..=600 {
adj_video(&mut tc, i * S);
}
let frontier = tc.high_ns.unwrap();
assert_eq!(frontier, 600 * S);
let c2 = adj_video(&mut tc, 0);
assert_eq!(c2, 600 * S + DISCONTINUITY_GAP_NS);
let straggler_raw = 599 * S + 500_000_000;
let straggler = adj_other(&mut tc, straggler_raw);
assert_eq!(
straggler, straggler_raw,
"straggler must remap to its seam position via the previous offset"
);
assert!(
straggler <= frontier,
"straggler must land at/below the frontier, got {straggler}"
);
assert_eq!(
tc.high_ns.unwrap(),
c2,
"straggler must not move the frontier"
);
let normal = adj_other(&mut tc, S);
assert_eq!(normal, S + 600 * S + DISCONTINUITY_GAP_NS);
}
#[test]
fn normal_new_epoch_frame_leading_frontier_is_not_clamped() {
let mut tc = TimelineContinuity::new();
for i in 0..=600 {
adj_video(&mut tc, i * S);
}
let frontier = tc.high_ns.unwrap();
assert_eq!(frontier, 600 * S);
let c2 = adj_video(&mut tc, 0);
assert_eq!(c2, 600 * S + DISCONTINUITY_GAP_NS);
let raw = 5 * S;
let out = adj_other(&mut tc, raw);
assert_eq!(
out,
raw + 600 * S + DISCONTINUITY_GAP_NS,
"a normal new-epoch frame leading the frontier by >3s must ride the \
current offset, not be clamped back into the previous clip"
);
assert!(
out > frontier,
"frame must stay in the new epoch (> frontier), got {out}"
);
}
}