#![forbid(unsafe_code)]
use bytes::Bytes;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Av1cOut {
pub av1c: Option<Bytes>,
}
#[must_use]
pub fn to_av1c(data: &[u8]) -> Av1cOut {
let Some(seq_header) = find_sequence_header_obu(data) else {
return Av1cOut { av1c: None };
};
let mut out = Vec::with_capacity(4 + seq_header.len());
out.push(0x81); out.extend_from_slice(&[0, 0, 0]); out.extend_from_slice(seq_header);
Av1cOut {
av1c: Some(Bytes::from(out)),
}
}
fn find_sequence_header_obu(data: &[u8]) -> Option<&[u8]> {
let mut pos = 0usize;
while pos < data.len() {
let header_byte = data[pos];
if header_byte & 0x80 != 0 {
return None;
}
let obu_type = (header_byte >> 3) & 0x0f;
let extension_flag = header_byte & 0x04 != 0;
let has_size_field = header_byte & 0x02 != 0;
if !has_size_field {
return None;
}
let header_len = if extension_flag { 2 } else { 1 };
let (obu_size, leb_len) = read_leb128(data.get(pos + header_len..)?)?;
let total_len = header_len.checked_add(leb_len)?.checked_add(obu_size)?;
let obu_end = pos.checked_add(total_len)?;
let obu = data.get(pos..obu_end)?;
if obu_type == 1 {
return Some(obu);
}
pos = obu_end;
}
None
}
fn read_leb128(data: &[u8]) -> Option<(usize, usize)> {
let mut value: u64 = 0;
for (i, &byte) in data.iter().enumerate().take(8) {
value |= u64::from(byte & 0x7f) << (i * 7);
if byte & 0x80 == 0 {
return usize::try_from(value).ok().map(|v| (v, i + 1));
}
}
None
}
#[cfg(test)]
#[path = "av1_tests.rs"]
mod tests;