pub fn iter_nals(data: &[u8]) -> NalIter<'_> {
NalIter { data, pos: 0 }
}
pub struct NalIter<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> Iterator for NalIter<'a> {
type Item = &'a [u8];
fn next(&mut self) -> Option<&'a [u8]> {
let start = next_start_code(self.data, self.pos)?;
let nal_begin = start.0 + start.1;
let nal_end = match next_start_code(self.data, nal_begin) {
Some((off, _)) => off,
None => self.data.len(),
};
self.pos = nal_end;
if nal_begin >= nal_end {
return self.next();
}
Some(&self.data[nal_begin..nal_end])
}
}
pub fn next_start_code(data: &[u8], from: usize) -> Option<(usize, usize)> {
let mut i = from;
while i + 3 <= data.len() {
if data[i] == 0 && data[i + 1] == 0 && data[i + 2] == 1 {
if i > from && data[i - 1] == 0 {
return Some((i - 1, 4));
}
return Some((i, 3));
}
i += 1;
}
None
}
pub fn unescape_rbsp(nal: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(nal.len());
let mut zeros = 0;
for &b in nal {
if zeros >= 2 && b == 0x03 {
zeros = 0;
continue;
}
if b == 0 {
zeros += 1;
} else {
zeros = 0;
}
out.push(b);
}
out
}
pub fn conformance_dims(
width_luma: u32,
height_luma: u32,
chroma_format_idc: u32,
crop_left: u32,
crop_right: u32,
crop_top: u32,
crop_bottom: u32,
) -> (u32, u32) {
let (sub_w, sub_h) = match chroma_format_idc {
1 => (2, 2), 2 => (2, 1), _ => (1, 1), };
let width = width_luma.saturating_sub((crop_left + crop_right) * sub_w);
let height = height_luma.saturating_sub((crop_top + crop_bottom) * sub_h);
(width, height)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn iterates_three_and_four_byte_start_codes() {
let data = [0, 0, 0, 1, 9, 0xF0, 0, 0, 1, 7, 0x42];
let nals: Vec<&[u8]> = iter_nals(&data).collect();
assert_eq!(nals, vec![&[9u8, 0xF0][..], &[7u8, 0x42][..]]);
}
#[test]
fn unescape_removes_emulation_bytes() {
assert_eq!(unescape_rbsp(&[0, 0, 3, 1]), vec![0, 0, 1]);
assert_eq!(unescape_rbsp(&[0, 0, 3, 0, 0, 3, 2]), vec![0, 0, 0, 0, 2]);
}
#[test]
fn conformance_crop_420() {
assert_eq!(conformance_dims(1920, 1088, 1, 0, 0, 0, 4), (1920, 1080));
}
}