use super::sequence::Av1SequenceHeader;
use super::frame::parse_av1_frame_header;
pub(super) fn find_av1_obu(data: &[u8], target_type: u8) -> Option<&[u8]> {
find_av1_obu_with_offset(data, target_type).map(|(bytes, _)| bytes)
}
pub fn find_av1_obu_with_offset_pub(data: &[u8], target_type: u8) -> Option<(&[u8], usize)> {
find_av1_obu_with_offset(data, target_type)
}
pub(super) fn find_av1_obu_with_offset(data: &[u8], target_type: u8) -> Option<(&[u8], usize)> {
let mut i = 0;
while i < data.len() {
let header = data[i];
let obu_type = (header >> 3) & 0x0F;
let extension_flag = (header >> 2) & 0x01;
let has_size_field = (header >> 1) & 0x01;
i += 1;
if extension_flag == 1 {
i += 1;
}
if has_size_field == 0 {
return None;
}
let (size, leb_bytes) = read_leb128(&data[i..])?;
i += leb_bytes;
if obu_type == target_type {
let end = (i + size as usize).min(data.len());
return Some((&data[i..end], i));
}
i += size as usize;
}
None
}
fn read_leb128(data: &[u8]) -> Option<(u64, usize)> {
let mut value = 0u64;
for i in 0..8 {
if i >= data.len() {
return None;
}
let byte = data[i];
value |= ((byte & 0x7F) as u64) << (i * 7);
if byte & 0x80 == 0 {
return Some((value, i + 1));
}
}
None
}
pub fn av1_frame_header_offset(sample: &[u8]) -> Option<u32> {
let mut i = 0usize;
while i < sample.len() {
let header = sample[i];
let obu_type = (header >> 3) & 0x0F;
let extension_flag = (header >> 2) & 0x01;
let has_size_field = (header >> 1) & 0x01;
let mut p = i + 1;
if extension_flag == 1 {
p += 1;
}
let (size, leb) = if has_size_field == 1 {
let (s, n) = read_leb128(&sample[p..])?;
p += n;
(s as usize, n)
} else {
return None;
};
let _ = leb;
if obu_type == 3 || obu_type == 6 {
return Some(p as u32);
}
p += size;
i = p;
}
None
}
pub fn av1_tile_group_offset(sample: &[u8], seq: &Av1SequenceHeader) -> Option<u32> {
let mut i = 0usize;
while i < sample.len() {
let header = sample[i];
let obu_type = (header >> 3) & 0x0F;
let extension_flag = (header >> 2) & 0x01;
let has_size_field = (header >> 1) & 0x01;
let mut p = i + 1;
if extension_flag == 1 {
p += 1;
}
let size = if has_size_field == 1 {
let (s, n) = read_leb128(&sample[p..])?;
p += n;
s as usize
} else {
return None;
};
if obu_type == 4 {
return Some(p as u32);
}
p += size;
i = p;
}
let (_obu_bytes, payload_offset) = find_av1_obu_with_offset(sample, 6)?;
let hdr = parse_av1_frame_header(sample, seq)?;
Some(payload_offset as u32 + hdr.tile_group_offset_in_obu)
}
pub fn av1_tile_group_offset_fallback(sample: &[u8]) -> Option<u32> {
let mut i = 0usize;
while i < sample.len() {
let header = sample[i];
let obu_type = (header >> 3) & 0x0F;
let extension_flag = (header >> 2) & 0x01;
let has_size_field = (header >> 1) & 0x01;
let mut p = i + 1;
if extension_flag == 1 {
p += 1;
}
let size = if has_size_field == 1 {
let (s, n) = read_leb128(&sample[p..])?;
p += n;
s as usize
} else {
return None;
};
if obu_type == 4 {
return Some(p as u32);
}
p += size;
i = p;
}
av1_frame_header_offset(sample)
}