use std::collections::TryReserveError;
use mediadecode::{Timebase, Timestamp, demuxer::MeasuredEnd};
#[derive(Clone, Copy)]
enum Figure {
Unseen,
End(i64),
Unrepresentable,
}
#[derive(Clone, Copy)]
struct Slot {
figure: Figure,
exact: bool,
}
pub(crate) struct Measured {
ends: Vec<Slot>,
unbroken: bool,
walk_complete: bool,
}
impl Measured {
pub(crate) fn new(tracks: usize) -> Result<Self, TryReserveError> {
let mut ends = Vec::new();
ends.try_reserve_exact(tracks)?;
ends.resize(
tracks,
Slot {
figure: Figure::Unseen,
exact: true,
},
);
Ok(Self {
ends,
unbroken: true,
walk_complete: false,
})
}
pub(crate) fn observe(&mut self, track: usize, pts: Option<i64>, duration: i64) {
if self.walk_complete {
return;
}
let Some(slot) = self.ends.get_mut(track) else {
return;
};
let Some(pts) = pts else {
slot.exact = false;
return;
};
let end = if duration > 0 {
match pts.checked_add(duration) {
Some(end) => end,
None => {
slot.figure = Figure::Unrepresentable;
self.unbroken = false;
return;
}
}
} else {
slot.exact = false;
pts
};
slot.figure = match slot.figure {
Figure::Unseen => Figure::End(end),
Figure::End(seen) => Figure::End(seen.max(end)),
Figure::Unrepresentable => Figure::Unrepresentable,
};
}
pub(crate) fn end_of_file(&mut self) {
if self.unbroken {
self.walk_complete = true;
}
}
pub(crate) fn break_walk(&mut self) {
if self.walk_complete {
return;
}
self.unbroken = false;
}
pub(crate) fn get(&self, track: usize, timebase: Timebase) -> Option<MeasuredEnd> {
let slot = self.ends.get(track)?;
match slot.figure {
Figure::End(ticks) => Some(MeasuredEnd::new(
Timestamp::new(ticks, timebase),
self.walk_complete,
slot.exact,
)),
Figure::Unseen | Figure::Unrepresentable => None,
}
}
}
#[cfg(test)]
mod tests;