use symphonia_core::errors::{decode_error, Result};
use symphonia_core::io::ReadBytes;
use crate::atoms::{Atom, AtomHeader};
#[derive(Debug)]
pub struct StscEntry {
pub first_chunk: u32,
pub first_sample: u32,
pub samples_per_chunk: u32,
pub sample_desc_index: u32,
}
#[derive(Debug)]
pub struct StscAtom {
header: AtomHeader,
pub entries: Vec<StscEntry>,
}
impl StscAtom {
pub fn find_entry_for_sample(&self, sample_num: u32) -> Option<&StscEntry> {
let mut left = 1;
let mut right = self.entries.len();
while left < right {
let mid = left + (right - left) / 2;
let entry = self.entries.get(mid).unwrap();
if entry.first_sample < sample_num {
left = mid + 1;
}
else {
right = mid;
}
}
self.entries.get(left - 1)
}
}
impl Atom for StscAtom {
fn header(&self) -> AtomHeader {
self.header
}
fn read<B: ReadBytes>(reader: &mut B, header: AtomHeader) -> Result<Self> {
let (_, _) = AtomHeader::read_extra(reader)?;
let entry_count = reader.read_be_u32()?;
let mut entries = Vec::with_capacity(entry_count as usize);
for _ in 0..entry_count {
entries.push(StscEntry {
first_chunk: reader.read_be_u32()? - 1,
first_sample: 0,
samples_per_chunk: reader.read_be_u32()?,
sample_desc_index: reader.read_be_u32()?,
});
}
if entry_count > 0 {
for i in 0..entry_count as usize - 1 {
if entries[i + 1].first_chunk < entries[i].first_chunk {
return decode_error("isomp4: stsc entry first chunk not monotonic");
}
if entries[i].samples_per_chunk == 0 {
return decode_error("isomp4: stsc entry has 0 samples per chunk");
}
let n = entries[i + 1].first_chunk - entries[i].first_chunk;
entries[i + 1].first_sample =
entries[i].first_sample + (n * entries[i].samples_per_chunk);
}
if entries[entry_count as usize - 1].samples_per_chunk == 0 {
return decode_error("isomp4: stsc entry has 0 samples per chunk");
}
}
Ok(StscAtom { header, entries })
}
}