use crate::error::DecodeError;
#[derive(Clone, Copy)]
pub(crate) struct Nal<'a> {
pub(crate) nal_type: u8,
pub(crate) bytes: &'a [u8],
}
impl<'a> Nal<'a> {
#[inline]
fn parse(bytes: &'a [u8]) -> Option<Self> {
if bytes.len() < 2 {
return None;
}
let nal_type = (bytes[0] >> 1) & 0x3f;
Some(Nal { nal_type, bytes })
}
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub(crate) enum Framing {
AnnexB,
Length(u8),
}
pub(crate) fn detect_framing(data: &[u8]) -> Framing {
if starts_with_start_code(data) {
Framing::AnnexB
} else {
Framing::Length(4)
}
}
#[inline]
fn starts_with_start_code(d: &[u8]) -> bool {
d.len() >= 3
&& d[0] == 0
&& d[1] == 0
&& (d[2] == 1 || (d.len() >= 4 && d[2] == 0 && d[3] == 1))
}
pub(crate) fn for_each_nal<'a, F>(
data: &'a [u8],
framing: Framing,
mut f: F,
) -> Result<(), DecodeError>
where
F: FnMut(Nal<'a>) -> Result<(), DecodeError>,
{
match framing {
Framing::AnnexB => for_each_annexb(data, f),
Framing::Length(sz) => {
let mut pos = 0usize;
let sz = sz as usize;
while pos + sz <= data.len() {
let mut len = 0usize;
for k in 0..sz {
len = (len << 8) | data[pos + k] as usize;
}
pos += sz;
if len == 0 || pos + len > data.len() {
break;
}
if let Some(n) = Nal::parse(&data[pos..pos + len]) {
f(n)?;
}
pos += len;
}
Ok(())
}
}
}
fn for_each_annexb<'a, F>(data: &'a [u8], mut f: F) -> Result<(), DecodeError>
where
F: FnMut(Nal<'a>) -> Result<(), DecodeError>,
{
let mut starts: Vec<(usize, usize)> = Vec::new(); let mut i = 0usize;
while i + 3 <= data.len() {
if data[i] == 0 && data[i + 1] == 0 {
if data[i + 2] == 1 {
starts.push((i + 3, 3));
i += 3;
continue;
} else if i + 4 <= data.len() && data[i + 2] == 0 && data[i + 3] == 1 {
starts.push((i + 4, 4));
i += 4;
continue;
}
}
i += 1;
}
for k in 0..starts.len() {
let (s, _) = starts[k];
let end = if k + 1 < starts.len() {
starts[k + 1].0 - starts[k + 1].1
} else {
data.len()
};
if s < end
&& let Some(n) = Nal::parse(trim_trailing_zeros(&data[s..end]))
{
f(n)?;
}
}
Ok(())
}
#[inline]
fn trim_trailing_zeros(b: &[u8]) -> &[u8] {
let mut end = b.len();
while end > 2 && b[end - 1] == 0 {
end -= 1;
}
&b[..end]
}
pub(crate) mod nal {
pub(crate) const RASL_N: u8 = 8;
pub(crate) const RASL_R: u8 = 9;
pub(crate) const RADL_N: u8 = 6;
pub(crate) const RADL_R: u8 = 7;
pub(crate) const BLA_W_LP: u8 = 16;
pub(crate) const BLA_N_LP: u8 = 18;
pub(crate) const IDR_W_RADL: u8 = 19;
pub(crate) const IDR_N_LP: u8 = 20;
pub(crate) const CRA_NUT: u8 = 21;
pub(crate) const SPS: u8 = 33;
pub(crate) const PPS: u8 = 34;
#[inline]
pub(crate) fn is_vcl(t: u8) -> bool {
t <= 31
}
#[inline]
pub(crate) fn is_irap(t: u8) -> bool {
(16..=23).contains(&t)
}
#[inline]
pub(crate) fn is_idr(t: u8) -> bool {
t == IDR_W_RADL || t == IDR_N_LP
}
#[inline]
pub(crate) fn is_bla(t: u8) -> bool {
(BLA_W_LP..=BLA_N_LP).contains(&t)
}
#[inline]
pub(crate) fn is_cra(t: u8) -> bool {
t == CRA_NUT
}
#[inline]
pub(crate) fn is_rasl(t: u8) -> bool {
t == RASL_N || t == RASL_R
}
#[inline]
pub(crate) fn is_radl(t: u8) -> bool {
t == RADL_N || t == RADL_R
}
#[inline]
pub(crate) fn is_sub_layer_non_ref(t: u8) -> bool {
t <= 14 && (t).is_multiple_of(2)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn splits_annexb_4byte() {
let data = [
0, 0, 0, 1, 0x40, 0x01, 0xaa, 0, 0, 1, 0x42, 0x01, 0xbb, ];
let mut got = Vec::new();
for_each_nal(&data, Framing::AnnexB, |n| {
got.push(n.nal_type);
Ok(())
})
.unwrap();
assert_eq!(got, vec![32, 33]);
}
#[test]
fn splits_length_prefixed() {
let data = [
0, 0, 0, 3, 0x26, 0x01, 0xcc, 0, 0, 0, 3, 0x28, 0x01, 0xdd,
];
let mut got = Vec::new();
for_each_nal(&data, Framing::Length(4), |n| {
got.push(n.nal_type);
Ok(())
})
.unwrap();
assert_eq!(got, vec![19, 20]);
}
#[test]
fn detects_framing() {
assert!(matches!(detect_framing(&[0, 0, 1, 0x40]), Framing::AnnexB));
assert!(matches!(
detect_framing(&[0, 0, 0, 5, 0x40]),
Framing::Length(4)
));
}
}