use crate::budgets::MemoryBudgets;
use crate::error::{AacError, MalformedKind, Result, UnsupportedFeature};
use crate::isomp4::frag::{Fmp4Init, FragResolver};
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub(super) enum Phase {
#[default]
Init,
Boxes,
Moof { start: u64, end: u64, next: u64 },
Mdat,
Skip(u64),
Drain,
}
#[derive(Default)]
pub(crate) struct Fmp4Push {
pub(super) phase: Phase,
pub(super) init: Option<Fmp4Init>,
pub(super) res: FragResolver,
pub(super) asc: Option<(u8, u8, u32, u8)>,
pub(super) frag: Vec<(u64, u32)>,
pub(super) frag_idx: usize,
pub(super) mdat_end: u64,
pub(super) skip_left: usize,
pub(super) skip0: usize,
pub(super) play_left: Option<usize>,
}
impl Fmp4Push {
pub(crate) fn reset(&mut self) {
self.phase = Phase::Init;
self.init = None;
self.res.reset();
self.asc = None;
self.frag.clear();
self.frag_idx = 0;
self.mdat_end = 0;
self.skip_left = 0;
self.skip0 = 0;
self.play_left = None;
}
}
pub(super) fn peek_box(buf: &[u8], pos: usize) -> Result<Option<(u64, u64, [u8; 4])>> {
let Some(hdr) = buf.get(pos..pos + 8) else {
return Ok(None);
};
let size32 = u64::from(u32::from_be_bytes([hdr[0], hdr[1], hdr[2], hdr[3]]));
let typ = [hdr[4], hdr[5], hdr[6], hdr[7]];
let (size, head) = match size32 {
1 => {
let Some(ext) = buf.get(pos + 8..pos + 16) else {
return Ok(None);
};
let arr: [u8; 8] = ext
.try_into()
.map_err(|_| AacError::Malformed(MalformedKind::Syntax))?;
(u64::from_be_bytes(arr), 16)
}
0 => {
return Err(AacError::Unsupported(UnsupportedFeature::FragmentedMp4(
"a box without a declared size is not supported on push",
)));
}
s => (s, 8),
};
if size < head {
return Err(AacError::Malformed(MalformedKind::Syntax));
}
Ok(Some((size, head, typ)))
}
pub(super) fn fence_box(mem: &MemoryBudgets, size: u64) -> Result<()> {
mem.check_index(1, size).map(|_| ()).map_err(AacError::from)
}
pub(super) fn checked_end(start: u64, size: u64) -> Result<u64> {
start
.checked_add(size)
.ok_or(AacError::Malformed(MalformedKind::Syntax))
}