#![forbid(unsafe_code)]
pub(super) struct RbspWriter {
bytes: Vec<u8>,
bit_buf: u8,
bit_count: u8,
}
impl RbspWriter {
pub(super) const fn new() -> Self {
Self {
bytes: Vec::new(),
bit_buf: 0,
bit_count: 0,
}
}
pub(super) fn write_bit(&mut self, bit: u8) {
self.bit_buf = (self.bit_buf << 1) | (bit & 1);
self.bit_count += 1;
if self.bit_count == 8 {
self.bytes.push(self.bit_buf);
self.bit_buf = 0;
self.bit_count = 0;
}
}
pub(super) fn write_bits(&mut self, value: u32, n: u8) {
for i in (0..n).rev() {
self.write_bit(u8::from((value >> i) & 1 == 1));
}
}
pub(super) fn write_zero_bits(&mut self, n: u32) {
for _ in 0..n {
self.write_bit(0);
}
}
pub(super) fn write_u8(&mut self, value: u8) {
self.write_bits(u32::from(value), 8);
}
pub(super) fn write_ue(&mut self, value: u32) {
let code = value + 1;
let bits = 32 - code.leading_zeros();
self.write_bits(0, u8::try_from(bits - 1).unwrap_or(31));
self.write_bits(code, u8::try_from(bits).unwrap_or(32));
}
pub(super) fn write_se(&mut self, value: i32) {
let code = if value <= 0 {
value.unsigned_abs() * 2
} else {
u32::try_from(value).unwrap_or(0) * 2 - 1
};
self.write_ue(code);
}
pub(super) fn rbsp_trailing_bits(&mut self) {
self.write_bit(1);
while self.bit_count != 0 {
self.write_bit(0);
}
}
pub(super) fn byte_align_zero(&mut self) {
while self.bit_count != 0 {
self.write_bit(0);
}
}
pub(super) fn finish(self) -> Vec<u8> {
self.bytes
}
}
pub(super) fn push_rbsp_with_emulation_prevention(out: &mut Vec<u8>, rbsp: &[u8]) {
let mut zero_run = 0u8;
for &b in rbsp {
if zero_run >= 2 && b <= 3 {
out.push(0x03);
zero_run = 0;
}
out.push(b);
zero_run = if b == 0 { zero_run + 1 } else { 0 };
}
}
const PROFILE_IDC_MAIN: u8 = 77;
fn write_sps(
w: &mut RbspWriter,
width_mbs_minus1: u32,
height_map_units_minus1: u32,
level_idc: u8,
) {
w.write_u8(PROFILE_IDC_MAIN);
w.write_bits(0, 8); w.write_u8(level_idc);
w.write_ue(0); w.write_ue(0); w.write_ue(2); w.write_ue(0); w.write_bit(0); w.write_ue(width_mbs_minus1);
w.write_ue(height_map_units_minus1);
w.write_bit(1); w.write_bit(1); w.write_bit(0); w.write_bit(0); w.rbsp_trailing_bits();
}
fn write_pps(w: &mut RbspWriter) {
w.write_ue(0); w.write_ue(0); w.write_bit(0); w.write_bit(0); w.write_ue(0); w.write_ue(0); w.write_ue(0); w.write_bit(0); w.write_bits(0, 2); w.write_se(0); w.write_se(0); w.write_se(0); w.write_bit(1); w.write_bit(0); w.write_bit(0); w.rbsp_trailing_bits();
}
fn annex_b_nal(nal_ref_idc: u8, nal_unit_type: u8, rbsp: &[u8]) -> Vec<u8> {
let header = (nal_ref_idc << 5) | nal_unit_type;
let mut out = Vec::with_capacity(rbsp.len() + rbsp.len() / 2 + 5);
out.extend_from_slice(&[0, 0, 0, 1, header]);
push_rbsp_with_emulation_prevention(&mut out, rbsp);
out
}
pub(super) fn build_h264_headers(
width_mbs_minus1: u32,
height_map_units_minus1: u32,
level_idc: u8,
) -> Vec<u8> {
let mut sps_w = RbspWriter::new();
write_sps(
&mut sps_w,
width_mbs_minus1,
height_map_units_minus1,
level_idc,
);
let sps_rbsp = sps_w.finish();
let mut pps_w = RbspWriter::new();
write_pps(&mut pps_w);
let pps_rbsp = pps_w.finish();
let mut out = annex_b_nal(3, 7, &sps_rbsp); out.extend(annex_b_nal(3, 8, &pps_rbsp)); out
}