use crate::buf::BufRange;
use crate::inputs::{Input as _, Split};
pub const ANNEX_B_START_CODE: [u8; 4] = [0, 0, 0, 1];
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum Framing {
#[default]
FourByteLength,
AnnexB,
}
#[derive(Debug)]
pub(super) struct TolerantBitReader<'a, R> {
pub(super) inner: R,
pub(super) has_extra_trailing_data: &'a mut bool,
}
impl<R: h264_reader::rbsp::BitRead> h264_reader::rbsp::BitRead for TolerantBitReader<'_, R> {
fn read_ue(&mut self, name: &'static str) -> Result<u32, h264_reader::rbsp::BitReaderError> {
self.inner.read_ue(name)
}
fn read_se(&mut self, name: &'static str) -> Result<i32, h264_reader::rbsp::BitReaderError> {
self.inner.read_se(name)
}
fn read_bool(&mut self, name: &'static str) -> Result<bool, h264_reader::rbsp::BitReaderError> {
self.inner.read_bool(name)
}
fn skip(
&mut self,
bit_count: u32,
name: &'static str,
) -> Result<(), h264_reader::rbsp::BitReaderError> {
self.inner.skip(bit_count, name)
}
fn read<U: h264_reader::rbsp::Numeric>(
&mut self,
bit_count: u32,
name: &'static str,
) -> Result<U, h264_reader::rbsp::BitReaderError> {
self.inner.read(bit_count, name)
}
fn read_to<V: h264_reader::rbsp::Primitive>(
&mut self,
name: &'static str,
) -> Result<V, h264_reader::rbsp::BitReaderError> {
self.inner.read_to(name)
}
fn has_more_rbsp_data(
&mut self,
name: &'static str,
) -> Result<bool, h264_reader::rbsp::BitReaderError> {
self.inner.has_more_rbsp_data(name)
}
fn finish_rbsp(self) -> Result<(), h264_reader::rbsp::BitReaderError> {
match self.inner.finish_rbsp() {
Ok(()) => Ok(()),
Err(h264_reader::rbsp::BitReaderError::RemainingData) => {
*self.has_extra_trailing_data = true;
Ok(())
}
Err(e) => Err(e),
}
}
fn finish_sei_payload(self) -> Result<(), h264_reader::rbsp::BitReaderError> {
self.inner.finish_sei_payload()
}
}
pub(crate) trait U8Array: Default + Copy + AsMut<[u8]> {
const LEN: usize;
}
impl<const N: usize> U8Array for [u8; N]
where
Self: Default,
{
const LEN: usize = N;
}
pub(crate) trait NalHandler {
type HeaderArray: U8Array;
fn start(&mut self, header: Self::HeaderArray) -> Result<(), String>;
fn piece(&mut self, piece: BufRange) -> Result<(), String>;
fn end(&mut self) -> Result<(), String>;
}
#[derive(Debug)]
pub(super) enum AnnexBScanner<A: U8Array> {
Pre {
cur: A,
bytes_read: u8,
},
Mid(Mid),
}
impl<A: U8Array> Default for AnnexBScanner<A> {
fn default() -> Self {
Self::Pre {
cur: A::default(),
bytes_read: 0,
}
}
}
#[derive(Debug, Default)]
pub(crate) struct Mid {
seen_three_zeros: bool,
deferred: Option<Deferred>,
}
#[derive(Debug)]
struct Deferred {
start_pos: u64,
body_len: u16,
second_zero_pos: Option<u64>,
}
impl Deferred {
#[cold]
fn flush(self, including_zeros: bool, handler: &mut impl NalHandler) -> Result<(), String> {
if !including_zeros {
if self.body_len > 0 {
handler.piece(BufRange {
pos: self.start_pos,
len: self.body_len,
})?;
}
return Ok(());
}
if self.second_zero_pos == Some(self.start_pos + u64::from(self.body_len) + 1) {
return handler.piece(BufRange {
pos: self.start_pos,
len: self.body_len + 2,
});
}
handler.piece(BufRange {
pos: self.start_pos,
len: self.body_len + 1,
})?;
if let Some(pos) = self.second_zero_pos {
handler.piece(BufRange { pos, len: 1 })?;
}
Ok(())
}
}
impl<A: U8Array> AnnexBScanner<A> {
pub(super) fn scan<H: NalHandler<HeaderArray = A>>(
&mut self,
mut pos: u64,
mut data: Split,
end: bool,
handler: &mut H,
) -> Result<(), String> {
debug_assert!(data.len() <= usize::from(u16::MAX));
'nal: loop {
let mid = match self {
AnnexBScanner::Pre { cur, bytes_read } => {
let header_len = A::LEN;
while usize::from(*bytes_read) < header_len {
if let Some(next) = data.peek_byte() {
cur.as_mut()[*bytes_read as usize] = next;
data.advance(1);
pos += 1;
*bytes_read += 1;
} else if end && *bytes_read > 0 {
return Err("incomplete NAL header at end of payload".into());
} else {
return Ok(());
}
}
handler.start(*cur)?;
*self = AnnexBScanner::Mid(Default::default());
match self {
AnnexBScanner::Mid(mid) => mid,
_ => unreachable!(),
}
}
AnnexBScanner::Mid(mid) => mid,
};
let mut cur_pos = pos;
let mut cur = data;
'body_byte: while let Some(next_byte) = cur.peek_byte() {
if mid.seen_three_zeros {
match next_byte {
0 => {
cur.advance(1);
cur_pos += 1;
continue 'body_byte;
}
1 => {
mid.seen_three_zeros = false;
handler.end()?;
cur.advance(1);
cur_pos += 1;
data = cur;
pos = cur_pos;
*self = Self::default();
continue 'nal;
}
_ => {
return Err(format!("invalid sequence 00 00 00 {next_byte:02x}"));
}
}
}
if let Some(mut deferred) = mid.deferred.take() {
match next_byte {
0 if deferred.second_zero_pos.is_none() => {
deferred.second_zero_pos = Some(cur_pos);
mid.deferred = Some(deferred);
cur.advance(1);
cur_pos += 1;
continue 'body_byte;
}
0 => {
deferred.flush(false, handler)?;
mid.seen_three_zeros = true;
cur.advance(1);
cur_pos += 1;
data = cur;
pos = cur_pos;
continue 'body_byte;
}
1 if deferred.second_zero_pos.is_some() => {
deferred.flush(false, handler)?;
handler.end()?;
cur.advance(1);
pos = cur_pos + 1;
data = cur;
*self = Self::default();
continue 'nal;
}
2 if deferred.second_zero_pos.is_some() => {
return Err("invalid sequence 00 00 02".into());
}
_ => {
if deferred.start_pos == pos {
} else if deferred.second_zero_pos.is_some_and(|p| p == pos) {
deferred.second_zero_pos.take();
deferred.flush(true, handler)?;
} else {
deferred.flush(true, handler)?;
}
}
}
}
debug_assert!(mid.deferred.is_none());
match cur.find_byte(0) {
Some(j) => {
debug_assert!(mid.deferred.is_none());
mid.deferred = Some(Deferred {
start_pos: pos,
body_len: (cur_pos + crate::to_u64(j) - pos) as u16,
second_zero_pos: None,
});
cur.advance(j + 1);
cur_pos += crate::to_u64(j + 1);
}
None => {
let len = data.len();
if !data.is_empty() {
handler.piece(BufRange {
pos,
len: len as u16,
})?;
}
break 'body_byte;
}
}
}
if end {
if let Some(deferred) = mid.deferred.take() {
deferred.flush(false, handler)?;
}
handler.end()?;
*self = Self::default();
}
return Ok(());
}
}
}