#![allow(dead_code)]
use crate::nal::NalUnitType;
pub fn nal_header_byte(nal_ref_idc: u8, nal_unit_type: NalUnitType) -> u8 {
debug_assert!(nal_ref_idc <= 3);
let nut = nal_unit_type.as_u8() & 0x1F;
((nal_ref_idc & 0x3) << 5) | nut
}
pub fn insert_emulation_prevention(rbsp: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(rbsp.len() + rbsp.len() / 16);
let mut i = 0;
while i < rbsp.len() {
out.push(rbsp[i]);
if i + 2 < rbsp.len() && rbsp[i] == 0 && rbsp[i + 1] == 0 && rbsp[i + 2] <= 3 {
out.push(0);
out.push(0x03);
i += 2;
} else {
i += 1;
}
}
out
}
pub fn build_nal_unit(nal_ref_idc: u8, nal_unit_type: NalUnitType, rbsp: &[u8]) -> Vec<u8> {
let header_byte = nal_header_byte(nal_ref_idc, nal_unit_type);
let escaped = insert_emulation_prevention(rbsp);
let mut out = Vec::with_capacity(4 + 1 + escaped.len());
out.extend_from_slice(&[0x00, 0x00, 0x00, 0x01]);
out.push(header_byte);
out.extend_from_slice(&escaped);
out
}
pub fn build_filler_nal(ff_count: usize) -> Vec<u8> {
let mut rbsp = vec![0xFFu8; ff_count];
rbsp.push(0x80);
build_nal_unit(0, NalUnitType::FillerData, &rbsp)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nal::{parse_nal_unit, AnnexBSplitter, NalUnitType};
#[test]
fn header_byte_encodes_sps() {
assert_eq!(nal_header_byte(3, NalUnitType::Sps), 0x67);
}
#[test]
fn header_byte_encodes_idr() {
assert_eq!(nal_header_byte(3, NalUnitType::SliceIdr), 0x65);
}
#[test]
fn filler_nal_wire_shape_and_reparse() {
let nal = build_filler_nal(10);
assert_eq!(nal.len(), 16);
assert_eq!(&nal[..4], &[0, 0, 0, 1]);
assert_eq!(nal[4], 0x0C); assert!(nal[5..15].iter().all(|&b| b == 0xFF));
assert_eq!(nal[15], 0x80);
let mut split = AnnexBSplitter::new(&nal);
let raw = split.next().expect("one NAL");
let parsed = parse_nal_unit(raw).expect("parse");
assert_eq!(parsed.header.nal_unit_type, NalUnitType::FillerData);
assert!(split.next().is_none());
}
#[test]
fn no_emulation_byte_when_no_run() {
let rbsp = [0x00, 0x01, 0x02, 0x05];
assert_eq!(insert_emulation_prevention(&rbsp), rbsp);
}
#[test]
fn inserts_emulation_byte_before_00_00_01() {
let rbsp = [0x00, 0x00, 0x01];
assert_eq!(
insert_emulation_prevention(&rbsp),
vec![0x00, 0x00, 0x03, 0x01]
);
}
#[test]
fn inserts_emulation_byte_before_00_00_03() {
let rbsp = [0x00, 0x00, 0x03];
assert_eq!(
insert_emulation_prevention(&rbsp),
vec![0x00, 0x00, 0x03, 0x03]
);
}
#[test]
fn round_trip_through_annex_b_splitter_and_de_emulation() {
let rbsp_in: &[u8] = &[0x42, 0x00, 0x00, 0x01, 0xAA];
let nal = build_nal_unit(3, NalUnitType::Sps, rbsp_in);
assert_eq!(&nal[0..4], &[0x00, 0x00, 0x00, 0x01]);
assert_eq!(nal[4], 0x67);
let nals: Vec<_> = AnnexBSplitter::new(&nal).collect();
assert_eq!(nals.len(), 1);
let nu = parse_nal_unit(nals[0]).unwrap();
assert_eq!(nu.header.nal_unit_type, NalUnitType::Sps);
assert_eq!(nu.header.nal_ref_idc, 3);
assert_eq!(&*nu.rbsp, rbsp_in);
}
}