pub mod bitstream;
pub mod tables;
pub mod sps;
pub mod slice;
pub mod cavlc;
#[cfg(feature = "h264-encoder")]
pub mod cavlc_writer;
#[cfg(feature = "h264-encoder")]
pub mod cavlc_size;
pub mod macroblock;
pub mod transform;
pub mod intra_pred;
pub mod intra_pred_8x8;
pub mod reconstruct;
pub mod mv;
pub mod fingerprint;
#[cfg(feature = "h264-encoder")]
pub mod cabac;
#[cfg(feature = "h264-encoder")]
pub mod encoder;
#[cfg(feature = "h264-encoder")]
pub mod stego;
use std::fmt;
#[derive(Debug, Clone)]
pub enum H264Error {
UnexpectedEof,
InvalidNalHeader,
InvalidParameterSet(String),
Unsupported(String),
CavlcError(String),
}
impl fmt::Display for H264Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::UnexpectedEof => write!(f, "unexpected end of H.264 data"),
Self::InvalidNalHeader => write!(f, "invalid NAL unit header"),
Self::InvalidParameterSet(s) => write!(f, "invalid parameter set: {s}"),
Self::Unsupported(s) => write!(f, "unsupported H.264 feature: {s}"),
Self::CavlcError(s) => write!(f, "CAVLC decode error: {s}"),
}
}
}
impl std::error::Error for H264Error {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NalType(pub u8);
impl NalType {
pub const SLICE: Self = Self(1);
pub const SLICE_DPA: Self = Self(2);
pub const SLICE_DPB: Self = Self(3);
pub const SLICE_DPC: Self = Self(4);
pub const SLICE_IDR: Self = Self(5);
pub const SEI: Self = Self(6);
pub const SPS: Self = Self(7);
pub const PPS: Self = Self(8);
pub const AUD: Self = Self(9);
pub const END_SEQ: Self = Self(10);
pub const END_STREAM: Self = Self(11);
pub const FILLER: Self = Self(12);
pub const SPS_EXT: Self = Self(13);
pub fn is_vcl(self) -> bool {
self.0 >= 1 && self.0 <= 5
}
pub fn is_idr(self) -> bool {
self.0 == 5
}
pub fn is_slice(self) -> bool {
self.0 >= 1 && self.0 <= 5
}
}
impl fmt::Display for NalType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let name = match self.0 {
1 => "SLICE",
2 => "SLICE_DPA",
3 => "SLICE_DPB",
4 => "SLICE_DPC",
5 => "IDR",
6 => "SEI",
7 => "SPS",
8 => "PPS",
9 => "AUD",
10 => "END_SEQ",
11 => "END_STREAM",
12 => "FILLER",
13 => "SPS_EXT",
n => return write!(f, "NAL({n})"),
};
write!(f, "{name}")
}
}
#[derive(Debug, Clone)]
pub struct NalUnit {
pub nal_type: NalType,
pub nal_ref_idc: u8,
pub rbsp: Vec<u8>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn nal_type_is_vcl() {
assert!(!NalType(0).is_vcl());
assert!(NalType::SLICE.is_vcl());
assert!(NalType::SLICE_IDR.is_vcl());
assert!(!NalType::SPS.is_vcl());
assert!(!NalType::PPS.is_vcl());
assert!(!NalType::SEI.is_vcl());
}
#[test]
fn nal_type_is_idr() {
assert!(NalType::SLICE_IDR.is_idr());
assert!(!NalType::SLICE.is_idr());
assert!(!NalType::SPS.is_idr());
}
#[test]
fn nal_type_display() {
assert_eq!(format!("{}", NalType::SPS), "SPS");
assert_eq!(format!("{}", NalType::SLICE_IDR), "IDR");
assert_eq!(format!("{}", NalType(99)), "NAL(99)");
}
#[test]
fn error_display() {
let e = H264Error::UnexpectedEof;
assert!(format!("{e}").contains("unexpected"));
let e = H264Error::CavlcError("bad block".into());
assert!(format!("{e}").contains("bad block"));
}
}