pub struct AvcC {
pub parameter_sets: Vec<u8>,
pub nal_length_size: usize,
}
const START: [u8; 4] = [0, 0, 0, 1];
#[must_use]
pub fn parse_avcc(extradata: &[u8]) -> Option<AvcC> {
if extradata.len() < 7 || extradata[0] != 1 {
return None;
}
let nal_length_size = (extradata[4] & 0x03) as usize + 1;
let mut out = Vec::new();
let mut i = 5usize;
let num_sps = (extradata[i] & 0x1F) as usize;
i += 1;
for _ in 0..num_sps {
if i + 2 > extradata.len() {
return None;
}
let n = u16::from_be_bytes([extradata[i], extradata[i + 1]]) as usize;
i += 2;
if i + n > extradata.len() {
return None;
}
out.extend_from_slice(&START);
out.extend_from_slice(&extradata[i..i + n]);
i += n;
}
if i >= extradata.len() {
return Some(AvcC {
parameter_sets: out,
nal_length_size,
});
}
let num_pps = extradata[i] as usize;
i += 1;
for _ in 0..num_pps {
if i + 2 > extradata.len() {
return None;
}
let n = u16::from_be_bytes([extradata[i], extradata[i + 1]]) as usize;
i += 2;
if i + n > extradata.len() {
return None;
}
out.extend_from_slice(&START);
out.extend_from_slice(&extradata[i..i + n]);
i += n;
}
Some(AvcC {
parameter_sets: out,
nal_length_size,
})
}
#[must_use]
pub fn to_annexb(data: &[u8], nal_length_size: usize) -> Option<Vec<u8>> {
if data.len() < nal_length_size {
return None;
}
let mut out = Vec::with_capacity(data.len() + 16);
let mut i = 0usize;
while i + nal_length_size <= data.len() {
let mut n = 0usize;
for b in &data[i..i + nal_length_size] {
n = (n << 8) | *b as usize;
}
i += nal_length_size;
if n == 0 || i + n > data.len() {
return None;
}
out.extend_from_slice(&START);
out.extend_from_slice(&data[i..i + n]);
i += n;
}
if i != data.len() {
return None;
}
Some(out)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_an_avcc_into_annexb_parameter_sets() {
let ed = vec![
1, 0x42, 0xC0, 0x1E, 0xFF, 0xE1, 0, 3, 0xAA, 0xBB, 0xCC, 1, 0, 2, 0xDD, 0xEE, ];
let c = parse_avcc(&ed).expect("avcC");
assert_eq!(c.nal_length_size, 4);
assert_eq!(
c.parameter_sets,
vec![0, 0, 0, 1, 0xAA, 0xBB, 0xCC, 0, 0, 0, 1, 0xDD, 0xEE]
);
}
#[test]
fn converts_length_prefixed_nals() {
let pkt = vec![0, 0, 0, 2, 0x11, 0x22, 0, 0, 0, 3, 0x33, 0x44, 0x55];
let got = to_annexb(&pkt, 4).expect("converted");
assert_eq!(
got,
vec![0, 0, 0, 1, 0x11, 0x22, 0, 0, 0, 1, 0x33, 0x44, 0x55]
);
}
#[test]
fn a_length_that_looks_like_a_start_code_still_converts() {
let n = 300usize;
let mut pkt = vec![0, 0, 1, (n & 0xFF) as u8]; pkt.extend(std::iter::repeat(0xAB).take(n));
let got = to_annexb(&pkt, 4).expect("must convert, not refuse");
assert_eq!(&got[..4], &[0, 0, 0, 1]);
assert_eq!(got.len(), 4 + n);
}
#[test]
fn refuses_a_length_that_overruns() {
let pkt = vec![0, 0, 0, 99, 0x11, 0x22];
assert!(to_annexb(&pkt, 4).is_none());
}
#[test]
fn empty_extradata_is_not_an_avcc() {
assert!(parse_avcc(&[]).is_none());
assert!(parse_avcc(&[0, 0, 0, 1, 0x67]).is_none());
}
}