#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum NalType {
TrailN = 0,
TrailR = 1,
TsaN = 2,
TsaR = 3,
StsaN = 4,
StsaR = 5,
RadlN = 6,
RadlR = 7,
RaslN = 8,
RaslR = 9,
RsvVclN10 = 10,
RsvVclR11 = 11,
RsvVclN12 = 12,
RsvVclR13 = 13,
RsvVclN14 = 14,
RsvVclR15 = 15,
BlaWLp = 16,
BlaWRadl = 17,
BlaNLp = 18,
IdrWRadl = 19,
IdrNLp = 20,
CraNut = 21,
RsvIrapVcl22 = 22,
RsvIrapVcl23 = 23,
RsvVcl24 = 24,
RsvVcl25 = 25,
RsvVcl26 = 26,
RsvVcl27 = 27,
RsvVcl28 = 28,
RsvVcl29 = 29,
RsvVcl30 = 30,
RsvVcl31 = 31,
Vps = 32,
Sps = 33,
Pps = 34,
Aud = 35,
Eos = 36,
Eob = 37,
Fd = 38,
PrefixSei = 39,
SuffixSei = 40,
Other(u8),
}
impl NalType {
pub fn from_id(v: u8) -> Self {
use NalType::*;
match v & 0x3f {
0 => TrailN,
1 => TrailR,
2 => TsaN,
3 => TsaR,
4 => StsaN,
5 => StsaR,
6 => RadlN,
7 => RadlR,
8 => RaslN,
9 => RaslR,
10 => RsvVclN10,
11 => RsvVclR11,
12 => RsvVclN12,
13 => RsvVclR13,
14 => RsvVclN14,
15 => RsvVclR15,
16 => BlaWLp,
17 => BlaWRadl,
18 => BlaNLp,
19 => IdrWRadl,
20 => IdrNLp,
21 => CraNut,
22 => RsvIrapVcl22,
23 => RsvIrapVcl23,
24 => RsvVcl24,
25 => RsvVcl25,
26 => RsvVcl26,
27 => RsvVcl27,
28 => RsvVcl28,
29 => RsvVcl29,
30 => RsvVcl30,
31 => RsvVcl31,
32 => Vps,
33 => Sps,
34 => Pps,
35 => Aud,
36 => Eos,
37 => Eob,
38 => Fd,
39 => PrefixSei,
40 => SuffixSei,
o => Other(o),
}
}
pub fn id(self) -> u8 {
match self {
NalType::Other(v) => v,
t => t.discriminant(),
}
}
fn discriminant(self) -> u8 {
use NalType::*;
match self {
TrailN => 0,
TrailR => 1,
TsaN => 2,
TsaR => 3,
StsaN => 4,
StsaR => 5,
RadlN => 6,
RadlR => 7,
RaslN => 8,
RaslR => 9,
RsvVclN10 => 10,
RsvVclR11 => 11,
RsvVclN12 => 12,
RsvVclR13 => 13,
RsvVclN14 => 14,
RsvVclR15 => 15,
BlaWLp => 16,
BlaWRadl => 17,
BlaNLp => 18,
IdrWRadl => 19,
IdrNLp => 20,
CraNut => 21,
RsvIrapVcl22 => 22,
RsvIrapVcl23 => 23,
RsvVcl24 => 24,
RsvVcl25 => 25,
RsvVcl26 => 26,
RsvVcl27 => 27,
RsvVcl28 => 28,
RsvVcl29 => 29,
RsvVcl30 => 30,
RsvVcl31 => 31,
Vps => 32,
Sps => 33,
Pps => 34,
Aud => 35,
Eos => 36,
Eob => 37,
Fd => 38,
PrefixSei => 39,
SuffixSei => 40,
Other(v) => v,
}
}
pub fn is_vcl(self) -> bool {
self.id() < 32
}
pub fn is_irap(self) -> bool {
(16..=23).contains(&self.id())
}
pub fn is_idr(self) -> bool {
matches!(self, NalType::IdrWRadl | NalType::IdrNLp)
}
pub fn is_bla(self) -> bool {
matches!(self, NalType::BlaWLp | NalType::BlaWRadl | NalType::BlaNLp)
}
pub fn is_cra(self) -> bool {
self == NalType::CraNut
}
pub fn is_rasl(self) -> bool {
matches!(self, NalType::RaslN | NalType::RaslR)
}
pub fn is_radl(self) -> bool {
matches!(self, NalType::RadlN | NalType::RadlR)
}
pub fn is_sub_layer_non_ref(self) -> bool {
let id = self.id();
id <= 14 && id % 2 == 0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NalHeader {
pub nal_type: NalType,
pub layer_id: u8,
pub temporal_id: u8,
}
impl NalHeader {
pub fn parse(nal: &[u8]) -> Option<Self> {
let b0 = *nal.first()?;
let b1 = *nal.get(1)?;
if b0 & 0x80 != 0 {
return None; }
let tid_plus1 = b1 & 0x07;
if tid_plus1 == 0 {
return None;
}
Some(NalHeader {
nal_type: NalType::from_id((b0 >> 1) & 0x3f),
layer_id: ((b0 & 1) << 5) | (b1 >> 3),
temporal_id: tid_plus1 - 1,
})
}
}
#[derive(Debug, Clone, Default)]
pub struct Rbsp {
pub data: Vec<u8>,
pub epb_pos: Vec<usize>,
}
impl Rbsp {
pub fn escaped_to_rbsp(&self, escaped: usize) -> usize {
let removed = self.epb_pos.iter().take_while(|&&p| p < escaped).count();
escaped - removed
}
}
pub fn unescape(ebsp: &[u8]) -> Rbsp {
let mut out = Vec::with_capacity(ebsp.len());
let mut epb_pos = Vec::new();
let mut zeros = 0usize;
let mut i = 0;
while i < ebsp.len() {
let b = ebsp[i];
if zeros >= 2 && b == 0x03 {
epb_pos.push(i);
zeros = 0;
i += 1;
continue;
}
out.push(b);
zeros = if b == 0 { zeros + 1 } else { 0 };
i += 1;
}
Rbsp { data: out, epb_pos }
}
pub fn escape_into(rbsp: &[u8], out: &mut Vec<u8>) {
let mut zeros = 0usize;
for &b in rbsp {
if zeros >= 2 && b <= 0x03 {
out.push(0x03);
zeros = 0;
}
out.push(b);
zeros = if b == 0 { zeros + 1 } else { 0 };
}
}
pub fn split_annex_b(stream: &[u8]) -> Vec<&[u8]> {
let mut nals = Vec::new();
let mut prev: Option<usize> = None;
let mut i = 0;
while let Some(w) = stream.get(i..i + 3) {
if w[0] == 0 && w[1] == 0 && w[2] == 1 {
if let Some(s) = prev {
let mut end = i;
while end > s && stream[end - 1] == 0 {
end -= 1;
}
if end > s {
nals.push(&stream[s..end]);
}
}
prev = Some(i + 3);
i += 3;
} else {
i += 1;
}
}
if let Some(s) = prev {
let mut end = stream.len();
while end > s && stream[end - 1] == 0 {
end -= 1;
}
if end > s {
nals.push(&stream[s..end]);
}
}
nals
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn header_fields() {
let h = NalHeader::parse(&[0x42, 0x01]).unwrap();
assert_eq!(h.nal_type, NalType::Sps);
assert_eq!(h.layer_id, 0);
assert_eq!(h.temporal_id, 0);
let h = NalHeader::parse(&[0x02, 0x03]).unwrap();
assert_eq!(h.nal_type, NalType::TrailR);
assert_eq!(h.temporal_id, 2);
assert!(NalHeader::parse(&[0x82, 0x01]).is_none());
assert!(NalHeader::parse(&[0x02, 0x00]).is_none());
}
#[test]
fn type_roundtrip() {
for v in 0..64u8 {
assert_eq!(NalType::from_id(v).id(), v);
}
assert!(NalType::CraNut.is_irap());
assert!(NalType::IdrNLp.is_irap());
assert!(!NalType::TrailR.is_irap());
assert!(NalType::TrailN.is_sub_layer_non_ref());
assert!(!NalType::TrailR.is_sub_layer_non_ref());
assert!(NalType::RaslN.is_sub_layer_non_ref());
}
#[test]
fn unescape_records_positions() {
let rbsp = [0u8, 0, 1, 5, 0, 0, 0, 9];
let mut esc = Vec::new();
escape_into(&rbsp, &mut esc);
assert_eq!(esc, vec![0, 0, 3, 1, 5, 0, 0, 3, 0, 9]);
let r = unescape(&esc);
assert_eq!(r.data, rbsp);
assert_eq!(r.epb_pos, vec![2, 7]);
assert_eq!(r.escaped_to_rbsp(0), 0);
assert_eq!(r.escaped_to_rbsp(3), 2);
assert_eq!(r.escaped_to_rbsp(9), 7);
}
#[test]
fn split_strips_start_codes_and_zero_padding() {
let s = [0, 0, 0, 1, 0x42, 1, 0xAA, 0, 0, 1, 0x44, 1, 0xBB, 0, 0];
let n = split_annex_b(&s);
assert_eq!(n, vec![&[0x42u8, 1, 0xAA][..], &[0x44u8, 1, 0xBB][..]]);
}
}