#![forbid(unsafe_code)]
use crate::DecodeError;
pub(super) const OBU_SEQUENCE_HEADER: u8 = 1;
#[allow(
dead_code,
reason = "exercised by obu_tests.rs and documents the OBU type table; av1.rs's \
push_packet dispatch handles OBU_TEMPORAL_DELIMITER via its wildcard arm \
(identical no-op body to every other ignored OBU type, so clippy::match_same_arms \
forbids a separate named arm) rather than by name"
)]
pub(super) const OBU_TEMPORAL_DELIMITER: u8 = 2;
pub(super) const OBU_FRAME_HEADER: u8 = 3;
pub(super) const OBU_TILE_GROUP: u8 = 4;
pub(super) const OBU_FRAME: u8 = 6;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct Obu<'a> {
pub(super) obu_type: u8,
pub(super) payload: &'a [u8],
}
pub(super) fn read_leb128(data: &[u8]) -> Result<(u64, usize), DecodeError> {
let mut value: u64 = 0;
for i in 0..8usize {
let byte = *data.get(i).ok_or(DecodeError::InvalidInput)?;
value |= u64::from(byte & 0x7f) << (i * 7);
if byte & 0x80 == 0 {
return Ok((value, i + 1));
}
}
Err(DecodeError::InvalidInput)
}
pub(super) fn split_obus(data: &[u8]) -> Result<Vec<Obu<'_>>, DecodeError> {
let mut obus = Vec::new();
let mut offset = 0usize;
while offset < data.len() {
let header_byte = *data.get(offset).ok_or(DecodeError::InvalidInput)?;
if header_byte & 0x80 != 0 {
return Err(DecodeError::InvalidInput);
}
let obu_type = (header_byte >> 3) & 0b1111;
let obu_extension_flag = (header_byte >> 2) & 1;
let obu_has_size_field = (header_byte >> 1) & 1;
if obu_extension_flag != 0 {
return Err(DecodeError::Unsupported);
}
if obu_has_size_field == 0 {
return Err(DecodeError::Unsupported);
}
let after_header = offset.checked_add(1).ok_or(DecodeError::InvalidInput)?;
let size_field = data.get(after_header..).ok_or(DecodeError::InvalidInput)?;
let (size, size_len) = read_leb128(size_field)?;
let payload_start = after_header
.checked_add(size_len)
.ok_or(DecodeError::InvalidInput)?;
let size = usize::try_from(size).map_err(|_| DecodeError::InvalidInput)?;
let payload_end = payload_start
.checked_add(size)
.ok_or(DecodeError::InvalidInput)?;
let payload = data
.get(payload_start..payload_end)
.ok_or(DecodeError::InvalidInput)?;
obus.push(Obu { obu_type, payload });
offset = payload_end;
}
Ok(obus)
}
#[cfg(test)]
#[path = "obu_tests.rs"]
mod tests;