use crate::{Error, Mp4Parser, ParsedBox, Result};
use std::sync::{Arc, Mutex};
#[derive(Clone)]
pub struct Range {
pub end: u64,
pub start: u64,
}
pub fn parse(data: &[u8], sidx_offset: u64) -> Result<Vec<Range>> {
let references = Arc::new(Mutex::new(Vec::new()));
let references_c = references.clone();
Mp4Parser::default()
.full_box(
"sidx",
Arc::new(move |mut _box| {
*references_c.lock().unwrap() = parse_sidx(&mut _box, sidx_offset)?;
Ok(())
}),
)
.parse(data, None, None)?;
let references = references.lock().unwrap().to_vec();
Ok(references)
}
fn parse_sidx(_box: &mut ParsedBox, sidx_offset: u64) -> Result<Vec<Range>> {
if _box.version.is_none() {
return Err(Error::new(
"SIDX is a full box and should have a valid version.",
));
}
let reader = &mut _box.reader;
let version = _box.version.unwrap();
let mut references = Vec::new();
reader
.skip(4)
.map_err(|_| Error::new_read("SIDX box skip reference ID (32 bits)."))?;
let timescale = reader
.read_u32()
.map_err(|_| Error::new_read("SIDX box timescale (u32)."))?;
if timescale == 0 {
return Err(Error::new("SIDX box has invalid timescale."));
}
let _earliest_presentation_time;
let first_offset;
if version == 0 {
_earliest_presentation_time = reader
.read_u32()
.map_err(|_| Error::new_read("SIDX box earliest presentation time (u32)."))?
as u64;
first_offset = reader
.read_u32()
.map_err(|_| Error::new_read("SIDX box first offset (u32)."))?
as u64;
} else {
_earliest_presentation_time = reader
.read_u64()
.map_err(|_| Error::new_read("SIDX box earliest presentation time (u64)."))?;
first_offset = reader
.read_u64()
.map_err(|_| Error::new_read("SIDX box first offset (u64)."))?;
}
reader
.skip(2)
.map_err(|_| Error::new_read("SIDX box skip reserved (16 bits)."))?;
let reference_count = reader
.read_u16()
.map_err(|_| Error::new_read("SIDX box reference count (u16)."))?;
let mut start_byte = sidx_offset + _box.size as u64 + first_offset;
for _ in 0..reference_count {
let chunk = reader
.read_u32()
.map_err(|_| Error::new_read("SIDX box chunk (u32)."))?;
let reference_type = (chunk & 0x80000000) >> 31;
let reference_size = chunk & 0x7FFFFFFF;
let _subsegment_duration = reader
.read_u32()
.map_err(|_| Error::new_read("SIDX box subsegment duration (u32)."))?;
reader
.skip(4)
.map_err(|_| Error::new_read("SIDX box skip (32 bits)."))?;
if reference_type == 1 {
return Err(Error::new("hierarchical SIDXs are not supported."));
}
references.push(Range {
end: start_byte + reference_size as u64 - 1,
start: start_byte,
});
start_byte += reference_size as u64;
}
_box.parser.stop();
Ok(references)
}