const HEVC_NAL_HEADER_LEN: usize = 2;
const NAL_TYPE_AP: u8 = 48;
const NAL_TYPE_FU: u8 = 49;
const NAL_TYPE_VPS: u8 = 32;
const NAL_TYPE_SPS: u8 = 33;
const NAL_TYPE_PPS: u8 = 34;
const NAL_TYPE_IRAP_LOW: u8 = 16;
const NAL_TYPE_IRAP_HIGH: u8 = 23;
const NAL_TYPE_VCL_HIGH: u8 = 31;
const AUD_NAL: [u8; 3] = [0x46, 0x01, 0x50];
const ANNEXB_START_CODE: [u8; 4] = [0x00, 0x00, 0x00, 0x01];
const MAX_REORDER_BUFFER: usize = 128;
#[inline]
fn nal_type(nal_header_byte0: u8) -> u8 {
(nal_header_byte0 >> 1) & 0x3f
}
#[inline]
fn is_irap(t: u8) -> bool {
(NAL_TYPE_IRAP_LOW..=NAL_TYPE_IRAP_HIGH).contains(&t)
}
#[inline]
fn is_vcl(t: u8) -> bool {
t <= NAL_TYPE_VCL_HIGH
}
#[derive(Debug, Default)]
pub struct HevcDepacketizer {
reorder: std::collections::BTreeMap<u16, (u32, Vec<u8>)>,
next_seq: Option<u16>,
last_ts: Option<u32>,
fu_buffer: Vec<u8>,
fu_active: bool,
vps: Option<Vec<u8>>,
sps: Option<Vec<u8>>,
pps: Option<Vec<u8>>,
params_emitted_since_irap: bool,
out: Vec<u8>,
}
impl HevcDepacketizer {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, seq: u16, timestamp: u32, payload: &[u8]) {
if self.next_seq.is_none() {
self.next_seq = Some(seq);
}
if let Some(next) = self.next_seq
&& seq_less_than(seq, next)
{
return;
}
self.reorder.insert(seq, (timestamp, payload.to_vec()));
self.drain_in_order();
if self.reorder.len() > MAX_REORDER_BUFFER
&& let Some((&lowest, _)) = self.reorder.iter().next()
{
self.reset_fu();
self.next_seq = Some(lowest);
self.drain_in_order();
}
}
fn drain_in_order(&mut self) {
while let Some(next) = self.next_seq {
let Some((ts, payload)) = self.reorder.remove(&next) else {
break;
};
if let Some(prev) = self.last_ts
&& prev != ts
{
self.write_annexb(&AUD_NAL);
}
self.last_ts = Some(ts);
self.process_payload(&payload);
self.next_seq = Some(next.wrapping_add(1));
}
}
fn process_payload(&mut self, payload: &[u8]) {
if payload.len() < HEVC_NAL_HEADER_LEN {
return;
}
match nal_type(payload[0]) {
NAL_TYPE_AP => self.process_aggregation(payload),
NAL_TYPE_FU => self.process_fragmentation(payload),
_ => {
self.reset_fu();
self.emit_nal(payload);
}
}
}
fn process_aggregation(&mut self, payload: &[u8]) {
self.reset_fu();
let mut off = HEVC_NAL_HEADER_LEN; while off + 2 <= payload.len() {
let size = u16::from_be_bytes([payload[off], payload[off + 1]]) as usize;
off += 2;
let Some(nal) = payload.get(off..off + size) else {
break; };
self.emit_nal(nal);
off += size;
}
}
fn process_fragmentation(&mut self, payload: &[u8]) {
if payload.len() < HEVC_NAL_HEADER_LEN + 1 {
return;
}
let fu_header = payload[2];
let start = fu_header & 0x80 != 0;
let end = fu_header & 0x40 != 0;
let fu_type = fu_header & 0x3f;
let fragment = &payload[3..];
if start {
let b0 = (payload[0] & 0x81) | (fu_type << 1);
let b1 = payload[1];
self.fu_buffer.clear();
self.fu_buffer.push(b0);
self.fu_buffer.push(b1);
self.fu_buffer.extend_from_slice(fragment);
self.fu_active = true;
} else if self.fu_active {
self.fu_buffer.extend_from_slice(fragment);
} else {
return;
}
if end && self.fu_active {
let nal = std::mem::take(&mut self.fu_buffer);
self.fu_active = false;
self.emit_nal(&nal);
}
}
fn emit_nal(&mut self, nal: &[u8]) {
if nal.len() < HEVC_NAL_HEADER_LEN {
return;
}
let t = nal_type(nal[0]);
match t {
NAL_TYPE_VPS => {
self.vps = Some(nal.to_vec());
self.params_emitted_since_irap = true;
}
NAL_TYPE_SPS => {
self.sps = Some(nal.to_vec());
self.params_emitted_since_irap = true;
}
NAL_TYPE_PPS => {
self.pps = Some(nal.to_vec());
self.params_emitted_since_irap = true;
}
_ => {}
}
if is_irap(t) && !self.params_emitted_since_irap {
let sets: Vec<Vec<u8>> = [self.vps.clone(), self.sps.clone(), self.pps.clone()]
.into_iter()
.flatten()
.collect();
for set in sets {
self.write_annexb(&set);
}
self.params_emitted_since_irap = true;
}
if is_vcl(t) && !is_irap(t) {
self.params_emitted_since_irap = false;
}
self.write_annexb(nal);
}
fn write_annexb(&mut self, nal: &[u8]) {
self.out.extend_from_slice(&ANNEXB_START_CODE);
self.out.extend_from_slice(nal);
}
fn reset_fu(&mut self) {
self.fu_buffer.clear();
self.fu_active = false;
}
pub fn take_output(&mut self) -> Vec<u8> {
std::mem::take(&mut self.out)
}
pub fn has_parameter_sets(&self) -> bool {
self.vps.is_some() && self.sps.is_some() && self.pps.is_some()
}
}
#[inline]
fn seq_less_than(a: u16, b: u16) -> bool {
let diff = b.wrapping_sub(a);
diff != 0 && diff < 0x8000
}