use broadcast_common::Parse;
use transmux::SegmentIndexBox;
use super::AddressError;
use crate::error::Unsupported;
use broadcast_dash::ByteRange;
const REFERENCE_TYPE_SIDX: u8 = 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct IndexedSegment {
pub time: u64,
pub duration: u64,
pub range: ByteRange,
pub starts_with_sap: bool,
}
pub fn anchor_after(index_range: &ByteRange) -> Result<u64, AddressError> {
index_range
.last
.and_then(|l| l.checked_add(1))
.ok_or(AddressError::Unsupported(Unsupported::OpenEndedRange))
}
pub fn parse_index(bytes: &[u8]) -> Result<SegmentIndexBox, AddressError> {
SegmentIndexBox::parse(bytes).map_err(|e| AddressError::Sidx(e.to_string()))
}
pub fn segments(sidx: &SegmentIndexBox, anchor: u64) -> Result<Vec<IndexedSegment>, AddressError> {
let mut offset = anchor
.checked_add(sidx.first_offset)
.ok_or(AddressError::Overflow)?;
let mut time = sidx.earliest_presentation_time;
let mut out = Vec::with_capacity(sidx.references.len());
for r in &sidx.references {
if r.reference_type == REFERENCE_TYPE_SIDX {
return Err(AddressError::Unsupported(Unsupported::HierarchicalSidx));
}
if r.referenced_size == 0 {
time = time
.checked_add(u64::from(r.subsegment_duration))
.ok_or(AddressError::Overflow)?;
continue;
}
let size = u64::from(r.referenced_size);
let last = offset
.checked_add(size)
.and_then(|e| e.checked_sub(1))
.ok_or(AddressError::Overflow)?;
let duration = u64::from(r.subsegment_duration);
out.push(IndexedSegment {
time,
duration,
range: ByteRange::new(offset, last),
starts_with_sap: r.starts_with_sap != 0,
});
offset = last.checked_add(1).ok_or(AddressError::Overflow)?;
time = time.checked_add(duration).ok_or(AddressError::Overflow)?;
}
Ok(out)
}