#[cfg(test)]
mod h26x_reader_test;
use bytes::{BufMut, BytesMut};
use shared::error::{Error, Result};
use std::fmt;
use std::io::Read;
const NAL_PREFIX_3BYTES: [u8; 3] = [0, 0, 1];
const NAL_PREFIX_4BYTES: [u8; 4] = [0, 0, 0, 1];
struct ReadBuffer {
buffer: Box<[u8]>,
read_end: usize,
filled_end: usize,
}
impl ReadBuffer {
fn new(capacity: usize) -> ReadBuffer {
Self {
buffer: vec![0u8; capacity].into_boxed_slice(),
read_end: 0,
filled_end: 0,
}
}
#[inline]
fn in_buffer(&self) -> usize {
self.filled_end - self.read_end
}
fn consume(&mut self, consume: usize) -> &[u8] {
debug_assert!(self.read_end + consume <= self.filled_end);
let result = &self.buffer[self.read_end..][..consume];
self.read_end += consume;
result
}
pub(crate) fn fill_buffer(&mut self, reader: &mut impl Read) -> Result<()> {
debug_assert_eq!(self.read_end, self.filled_end);
self.read_end = 0;
self.filled_end = reader.read(&mut self.buffer)?;
Ok(())
}
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum H264NalUnitType {
#[default]
Unspecified = 0,
CodedSliceNonIdr = 1,
CodedSliceDataPartitionA = 2,
CodedSliceDataPartitionB = 3,
CodedSliceDataPartitionC = 4,
CodedSliceIdr = 5,
SEI = 6,
SPS = 7,
PPS = 8,
AUD = 9,
EndOfSequence = 10,
EndOfStream = 11,
Filler = 12,
SpsExt = 13,
CodedSliceAux = 19,
Reserved,
}
impl fmt::Display for H264NalUnitType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
H264NalUnitType::Unspecified => "Unspecified",
H264NalUnitType::CodedSliceNonIdr => "CodedSliceNonIdr",
H264NalUnitType::CodedSliceDataPartitionA => "CodedSliceDataPartitionA",
H264NalUnitType::CodedSliceDataPartitionB => "CodedSliceDataPartitionB",
H264NalUnitType::CodedSliceDataPartitionC => "CodedSliceDataPartitionC",
H264NalUnitType::CodedSliceIdr => "CodedSliceIdr",
H264NalUnitType::SEI => "SEI",
H264NalUnitType::SPS => "SPS",
H264NalUnitType::PPS => "PPS",
H264NalUnitType::AUD => "AUD",
H264NalUnitType::EndOfSequence => "EndOfSequence",
H264NalUnitType::EndOfStream => "EndOfStream",
H264NalUnitType::Filler => "Filler",
H264NalUnitType::SpsExt => "SpsExt",
H264NalUnitType::CodedSliceAux => "NalUnitTypeCodedSliceAux",
_ => "Reserved",
};
write!(f, "{}({})", s, *self as u8)
}
}
impl From<u8> for H264NalUnitType {
fn from(v: u8) -> Self {
match v {
0 => H264NalUnitType::Unspecified,
1 => H264NalUnitType::CodedSliceNonIdr,
2 => H264NalUnitType::CodedSliceDataPartitionA,
3 => H264NalUnitType::CodedSliceDataPartitionB,
4 => H264NalUnitType::CodedSliceDataPartitionC,
5 => H264NalUnitType::CodedSliceIdr,
6 => H264NalUnitType::SEI,
7 => H264NalUnitType::SPS,
8 => H264NalUnitType::PPS,
9 => H264NalUnitType::AUD,
10 => H264NalUnitType::EndOfSequence,
11 => H264NalUnitType::EndOfStream,
12 => H264NalUnitType::Filler,
13 => H264NalUnitType::SpsExt,
19 => H264NalUnitType::CodedSliceAux,
_ => H264NalUnitType::Reserved,
}
}
}
pub struct H264NAL {
pub picture_order_count: u32,
pub forbidden_zero_bit: bool,
pub ref_idc: u8,
pub unit_type: H264NalUnitType,
pub data: BytesMut,
}
impl H264NAL {
pub fn new(data: BytesMut) -> Self {
H264NAL {
picture_order_count: 0,
forbidden_zero_bit: false,
ref_idc: 0,
unit_type: H264NalUnitType::Unspecified,
data,
}
}
pub fn parse_header(&mut self) {
let first_byte = self.data[0];
self.forbidden_zero_bit = ((first_byte & 0x80) >> 7) == 1; self.ref_idc = (first_byte & 0x60) >> 5; self.unit_type = H264NalUnitType::from(first_byte & 0x1F); }
}
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub enum H265NalUnitType {
#[default]
TrailN = 0,
TrailR = 1,
TsaN = 2,
TsaR = 3,
StsaN = 4,
StsaR = 5,
RadlN = 6,
RadlR = 7,
RaslN = 8,
RaslR = 9,
BlaN = 16,
BlaR = 17,
BlaRadl = 18,
Idr = 19,
IdrNlp = 20,
Cra = 21,
VPS = 32,
SPS = 33,
PPS = 34,
AUD = 35,
EOS = 36,
EOB = 37,
FD = 38,
PrefixSEI = 39,
SuffixSEI = 40,
Reserved,
}
impl fmt::Display for H265NalUnitType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match *self {
H265NalUnitType::TrailN => "TrailN",
H265NalUnitType::TrailR => "TrailR",
H265NalUnitType::TsaN => "TsaN",
H265NalUnitType::TsaR => "TsaR",
H265NalUnitType::StsaN => "StsaN",
H265NalUnitType::StsaR => "StsaR",
H265NalUnitType::RadlN => "RadlN",
H265NalUnitType::RadlR => "RadlR",
H265NalUnitType::RaslN => "RaslN",
H265NalUnitType::RaslR => "RaslR",
H265NalUnitType::BlaN => "BlaN",
H265NalUnitType::BlaR => "BlaR",
H265NalUnitType::BlaRadl => "BlaRadl",
H265NalUnitType::Idr => "Idr",
H265NalUnitType::IdrNlp => "IdrNlp",
H265NalUnitType::Cra => "Cra",
H265NalUnitType::VPS => "VPS",
H265NalUnitType::SPS => "SPS",
H265NalUnitType::PPS => "PPS",
H265NalUnitType::AUD => "AUD",
H265NalUnitType::EOS => "EOS",
H265NalUnitType::EOB => "EOB",
H265NalUnitType::FD => "FD",
H265NalUnitType::PrefixSEI => "PrefixSEI",
H265NalUnitType::SuffixSEI => "SuffixSEI",
_ => "Reserved",
};
write!(f, "{}({})", s, *self as u8)
}
}
impl From<u8> for H265NalUnitType {
fn from(v: u8) -> Self {
match v {
0 => H265NalUnitType::TrailN,
1 => H265NalUnitType::TrailR,
2 => H265NalUnitType::TsaN,
3 => H265NalUnitType::TsaR,
4 => H265NalUnitType::StsaN,
5 => H265NalUnitType::StsaR,
6 => H265NalUnitType::RadlN,
7 => H265NalUnitType::RadlR,
8 => H265NalUnitType::RaslN,
9 => H265NalUnitType::RaslR,
16 => H265NalUnitType::BlaN,
17 => H265NalUnitType::BlaR,
18 => H265NalUnitType::BlaRadl,
19 => H265NalUnitType::Idr,
20 => H265NalUnitType::IdrNlp,
21 => H265NalUnitType::Cra,
32 => H265NalUnitType::VPS,
33 => H265NalUnitType::SPS,
34 => H265NalUnitType::PPS,
35 => H265NalUnitType::AUD,
36 => H265NalUnitType::EOS,
37 => H265NalUnitType::EOB,
38 => H265NalUnitType::FD,
39 => H265NalUnitType::PrefixSEI,
40 => H265NalUnitType::SuffixSEI,
_ => H265NalUnitType::Reserved,
}
}
}
pub struct H265NAL {
pub forbidden_zero_bit: bool,
pub unit_type: H265NalUnitType,
pub nuh_layer_id: u8,
pub nuh_temporal_id_plus1: u8,
pub data: BytesMut,
}
impl H265NAL {
pub fn new(data: BytesMut) -> Self {
H265NAL {
forbidden_zero_bit: false,
unit_type: H265NalUnitType::TrailN,
nuh_layer_id: 0,
nuh_temporal_id_plus1: 0,
data,
}
}
pub fn parse_header(&mut self) {
if self.data.len() < 2 {
return;
}
let first_byte = self.data[0];
let second_byte = self.data[1];
self.forbidden_zero_bit = ((first_byte & 0x80) >> 7) == 1; let nal_unit_type = (first_byte & 0x7E) >> 1; self.unit_type = H265NalUnitType::from(nal_unit_type);
let nuh_layer_id_msb = (first_byte & 0x01) << 5; let nuh_layer_id_lsb = (second_byte & 0xF8) >> 3; self.nuh_layer_id = nuh_layer_id_msb | nuh_layer_id_lsb;
self.nuh_temporal_id_plus1 = second_byte & 0x07; }
}
pub enum H26xNAL {
H264(H264NAL),
H265(H265NAL),
}
impl H26xNAL {
pub fn data(&self) -> &BytesMut {
match self {
H26xNAL::H264(nal) => &nal.data,
H26xNAL::H265(nal) => &nal.data,
}
}
}
pub struct H26xReader<R: Read> {
reader: R,
is_hevc: bool,
buffer: ReadBuffer,
nal_prefix_parsed: bool,
count_of_consecutive_zero_bytes: usize,
nal_buffer: BytesMut,
}
impl<R: Read> H26xReader<R> {
pub fn new(reader: R, capacity: usize, is_hevc: bool) -> H26xReader<R> {
H26xReader {
reader,
is_hevc,
nal_prefix_parsed: false,
buffer: ReadBuffer::new(capacity),
count_of_consecutive_zero_bytes: 0,
nal_buffer: BytesMut::new(),
}
}
fn read4(&mut self) -> Result<([u8; 4], usize)> {
let mut result = [0u8; 4];
let mut result_filled = 0;
loop {
let in_buffer = self.buffer.in_buffer();
if in_buffer + result_filled >= 4 {
let consume = 4 - result_filled;
result[result_filled..].copy_from_slice(self.buffer.consume(consume));
return Ok((result, 4));
}
result[result_filled..][..in_buffer].copy_from_slice(self.buffer.consume(in_buffer));
result_filled += in_buffer;
self.buffer.fill_buffer(&mut self.reader)?;
if self.buffer.in_buffer() == 0 {
return Ok((result, result_filled));
}
}
}
fn read1(&mut self) -> Result<Option<u8>> {
if self.buffer.in_buffer() == 0 {
self.buffer.fill_buffer(&mut self.reader)?;
if self.buffer.in_buffer() == 0 {
return Ok(None);
}
}
Ok(Some(self.buffer.consume(1)[0]))
}
fn bit_stream_starts_with_prefix(&mut self) -> Result<usize> {
let (prefix_buffer, n) = self.read4()?;
if n == 0 {
return Err(Error::ErrIoEOF);
}
if n < 3 {
return Err(if self.is_hevc {
Error::ErrDataIsNotH265Stream
} else {
Error::ErrDataIsNotH264Stream
});
}
let nal_prefix3bytes_found = NAL_PREFIX_3BYTES[..] == prefix_buffer[..3];
if n == 3 {
if nal_prefix3bytes_found {
return Err(Error::ErrIoEOF);
}
return Err(if self.is_hevc {
Error::ErrDataIsNotH265Stream
} else {
Error::ErrDataIsNotH264Stream
});
}
if nal_prefix3bytes_found {
self.nal_buffer.put_u8(prefix_buffer[3]);
return Ok(3);
}
let nal_prefix4bytes_found = NAL_PREFIX_4BYTES[..] == prefix_buffer;
if nal_prefix4bytes_found {
Ok(4)
} else {
Err(if self.is_hevc {
Error::ErrDataIsNotH265Stream
} else {
Error::ErrDataIsNotH264Stream
})
}
}
pub fn next_nal(&mut self) -> Result<H26xNAL> {
if !self.nal_prefix_parsed {
self.bit_stream_starts_with_prefix()?;
self.nal_prefix_parsed = true;
}
loop {
let Some(read_byte) = self.read1()? else {
break;
};
let nal_found = self.process_byte(read_byte);
if nal_found {
if self.is_hevc {
if !self.nal_buffer.is_empty() {
let nal_unit_type = H265NalUnitType::from((self.nal_buffer[0] & 0x7E) >> 1);
if nal_unit_type == H265NalUnitType::PrefixSEI
|| nal_unit_type == H265NalUnitType::SuffixSEI
{
self.nal_buffer.clear();
continue;
} else {
break;
}
}
} else {
let nal_unit_type = H264NalUnitType::from(self.nal_buffer[0] & 0x1F);
if nal_unit_type == H264NalUnitType::SEI {
self.nal_buffer.clear();
continue;
} else {
break;
}
}
}
self.nal_buffer.put_u8(read_byte);
}
if self.nal_buffer.is_empty() {
return Err(Error::ErrIoEOF);
}
if self.is_hevc {
let mut nal = H265NAL::new(self.nal_buffer.split());
nal.parse_header();
Ok(H26xNAL::H265(nal))
} else {
let mut nal = H264NAL::new(self.nal_buffer.split());
nal.parse_header();
Ok(H26xNAL::H264(nal))
}
}
fn process_byte(&mut self, read_byte: u8) -> bool {
let mut nal_found = false;
match read_byte {
0 => {
self.count_of_consecutive_zero_bytes += 1;
}
1 => {
if self.count_of_consecutive_zero_bytes >= 2 {
let count_of_consecutive_zero_bytes_in_prefix =
if self.count_of_consecutive_zero_bytes > 2 {
3
} else {
2
};
let nal_unit_length =
self.nal_buffer.len() - count_of_consecutive_zero_bytes_in_prefix;
if nal_unit_length > 0 {
let _ = self.nal_buffer.split_off(nal_unit_length);
nal_found = true;
}
}
self.count_of_consecutive_zero_bytes = 0;
}
_ => {
self.count_of_consecutive_zero_bytes = 0;
}
}
nal_found
}
}