pub(super) fn read_avih_total_frames(hdrl: &[u8]) -> Option<u64> {
let mut pos = 0;
while pos + 8 <= hdrl.len() {
let fcc = &hdrl[pos..pos + 4];
let size = u32::from_le_bytes([hdrl[pos + 4], hdrl[pos + 5], hdrl[pos + 6], hdrl[pos + 7]])
as usize;
let body_start = pos + 8;
let body_end = body_start + size;
if body_end > hdrl.len() {
return None;
}
if fcc == b"avih" {
if size < 20 {
return None;
}
let body = &hdrl[body_start..body_end];
let total = u32::from_le_bytes([body[16], body[17], body[18], body[19]]);
return if total > 0 { Some(total as u64) } else { None };
}
pos = body_end + (body_end & 1);
}
None
}
pub(super) fn read_dmlh_total_frames(hdrl: &[u8]) -> Option<u64> {
let mut pos = 0;
while pos + 8 <= hdrl.len() {
let fcc = &hdrl[pos..pos + 4];
let size = u32::from_le_bytes([hdrl[pos + 4], hdrl[pos + 5], hdrl[pos + 6], hdrl[pos + 7]])
as usize;
let body_start = pos + 8;
let body_end = body_start + size;
if body_end > hdrl.len() {
return None;
}
if fcc == b"LIST" && size >= 4 && &hdrl[body_start..body_start + 4] == b"odml" {
let mut p = body_start + 4;
while p + 8 <= body_end {
let f = &hdrl[p..p + 4];
let s = u32::from_le_bytes([hdrl[p + 4], hdrl[p + 5], hdrl[p + 6], hdrl[p + 7]])
as usize;
let bs = p + 8;
let be = bs + s;
if be > body_end {
return None;
}
if f == b"dmlh" && s >= 4 {
let total =
u32::from_le_bytes([hdrl[bs], hdrl[bs + 1], hdrl[bs + 2], hdrl[bs + 3]]);
return if total > 0 { Some(total as u64) } else { None };
}
p = be + (be & 1);
}
return None;
}
pos = body_end + (body_end & 1);
}
None
}
pub(super) fn locate_stream_indx(
hdrl: &[u8],
target_stream_idx: u32,
) -> Option<Vec<(usize, usize)>> {
let mut stream_idx: u32 = 0;
let mut pos = 0;
while pos + 8 <= hdrl.len() {
let fcc = &hdrl[pos..pos + 4];
let size = u32::from_le_bytes([hdrl[pos + 4], hdrl[pos + 5], hdrl[pos + 6], hdrl[pos + 7]])
as usize;
let body_start = pos + 8;
let body_end = body_start + size;
if body_end > hdrl.len() {
return None;
}
if fcc == b"LIST" && size >= 4 && &hdrl[body_start..body_start + 4] == b"strl" {
if stream_idx == target_stream_idx {
return parse_indx_in_strl(&hdrl[body_start + 4..body_end]);
}
stream_idx += 1;
}
pos = body_end + (body_end & 1);
}
None
}
pub(super) fn parse_indx_in_strl(strl: &[u8]) -> Option<Vec<(usize, usize)>> {
let mut pos = 0;
while pos + 8 <= strl.len() {
let fcc = &strl[pos..pos + 4];
let size = u32::from_le_bytes([strl[pos + 4], strl[pos + 5], strl[pos + 6], strl[pos + 7]])
as usize;
let body_start = pos + 8;
let body_end = body_start + size;
if body_end > strl.len() {
return None;
}
if fcc == b"indx" {
return parse_indx_body(&strl[body_start..body_end]);
}
pos = body_end + (body_end & 1);
}
None
}
pub(super) fn parse_indx_body(body: &[u8]) -> Option<Vec<(usize, usize)>> {
if body.len() < 24 {
return None;
}
let longs_per_entry = u16::from_le_bytes([body[0], body[1]]);
let _index_sub_type = body[2];
let index_type = body[3];
let n_entries = u32::from_le_bytes([body[4], body[5], body[6], body[7]]) as usize;
if index_type != 0x00 {
return None;
}
if longs_per_entry != 4 {
return None;
} let entries_start = 24;
let mut refs = Vec::with_capacity(n_entries);
for i in 0..n_entries {
let off = entries_start + i * 16;
if off + 16 > body.len() {
break;
}
let qw_offset = u64::from_le_bytes([
body[off],
body[off + 1],
body[off + 2],
body[off + 3],
body[off + 4],
body[off + 5],
body[off + 6],
body[off + 7],
]);
let dw_size =
u32::from_le_bytes([body[off + 8], body[off + 9], body[off + 10], body[off + 11]]);
let off_us = qw_offset as usize;
refs.push((off_us, dw_size as usize));
}
Some(refs)
}
pub(super) fn parse_ix_chunk(
data: &[u8],
ix_header_off: usize,
_ix_size: usize,
prefix: &[u8; 2],
out: &mut Vec<(usize, usize)>,
) {
if ix_header_off + 8 > data.len() {
return;
}
let body_start = ix_header_off + 8;
let body_size = u32::from_le_bytes([
data[ix_header_off + 4],
data[ix_header_off + 5],
data[ix_header_off + 6],
data[ix_header_off + 7],
]) as usize;
let body_end = body_start.saturating_add(body_size).min(data.len());
if body_end < body_start + 24 {
return;
}
let body = &data[body_start..body_end];
let longs_per_entry = u16::from_le_bytes([body[0], body[1]]);
let _index_sub_type = body[2];
let index_type = body[3];
let n_entries = u32::from_le_bytes([body[4], body[5], body[6], body[7]]) as usize;
let chunk_id: [u8; 4] = body[8..12].try_into().unwrap();
let qw_base_offset = u64::from_le_bytes([
body[12], body[13], body[14], body[15], body[16], body[17], body[18], body[19],
]) as usize;
if index_type != 0x01 {
return;
} if longs_per_entry != 2 {
return;
}
if chunk_id[0] != prefix[0] || chunk_id[1] != prefix[1] {
return;
}
let kind = chunk_id[3];
if kind != b'c' && kind != b'b' {
return;
}
let entries_start = 24;
for i in 0..n_entries {
let off = entries_start + i * 8;
if off + 8 > body.len() {
break;
}
let dw_offset =
u32::from_le_bytes([body[off], body[off + 1], body[off + 2], body[off + 3]]) as usize;
let dw_size_raw =
u32::from_le_bytes([body[off + 4], body[off + 5], body[off + 6], body[off + 7]]);
let dw_size = (dw_size_raw & 0x7FFFFFFF) as usize;
let abs_off = qw_base_offset.saturating_add(dw_offset);
out.push((abs_off, dw_size));
}
}