#![cfg(test)]
#![allow(
clippy::unwrap_used,
clippy::expect_used,
reason = "test modules may unwrap"
)]
use super::*;
struct BitWriter {
bytes: Vec<u8>,
cur: u8,
nbits: u8,
}
impl BitWriter {
fn new() -> Self {
Self {
bytes: Vec::new(),
cur: 0,
nbits: 0,
}
}
fn push_bit(&mut self, bit: u32) {
let bit_u8 = u8::from(bit & 1 == 1);
self.cur = (self.cur << 1) | bit_u8;
self.nbits += 1;
if self.nbits == 8 {
self.bytes.push(self.cur);
self.cur = 0;
self.nbits = 0;
}
}
fn write_bits(&mut self, value: u32, count: u32) {
for i in (0..count).rev() {
self.push_bit(value >> i);
}
}
fn write_ue(&mut self, value: u32) {
let code = value + 1;
let len = u32::BITS - code.leading_zeros();
for _ in 0..(len - 1) {
self.push_bit(0);
}
self.write_bits(code, len);
}
fn write_se(&mut self, value: i32) {
let magnitude = value.unsigned_abs();
let code = if value <= 0 {
magnitude * 2
} else {
magnitude * 2 - 1
};
self.write_ue(code);
}
fn finish(mut self) -> Vec<u8> {
while self.nbits != 0 {
self.push_bit(0);
}
self.bytes
}
}
#[test]
fn parse_extracts_common_fields_single_slice_group() {
let mut writer = BitWriter::new();
writer.write_ue(0); writer.write_ue(0); writer.push_bit(1); writer.push_bit(0); writer.write_ue(0); writer.write_ue(0); writer.write_ue(0); writer.push_bit(0); writer.write_bits(0, 2); writer.write_se(0); writer.write_se(0); writer.write_se(0); writer.push_bit(1); writer.push_bit(0); writer.push_bit(0);
let rbsp = writer.finish();
let pps = Pps::parse(&rbsp).unwrap();
assert_eq!(pps.pic_parameter_set_id, 0);
assert_eq!(pps.seq_parameter_set_id, 0);
assert!(pps.entropy_coding_mode);
assert_eq!(pps.num_ref_idx_l0_default_active, 1);
assert_eq!(pps.num_ref_idx_l1_default_active, 1);
assert_eq!(pps.pic_init_qp, 26);
assert_eq!(pps.chroma_qp_index_offset, 0);
assert!(pps.deblocking_filter_control_present);
assert!(!pps.constrained_intra_pred);
}
#[test]
fn parse_computes_plus_one_and_plus_26_offsets_correctly() {
let mut writer = BitWriter::new();
writer.write_ue(3); writer.write_ue(1); writer.push_bit(0); writer.push_bit(0); writer.write_ue(0); writer.write_ue(15); writer.write_ue(3); writer.push_bit(0); writer.write_bits(0, 2); writer.write_se(-5); writer.write_se(0); writer.write_se(0); writer.push_bit(0); writer.push_bit(1); writer.push_bit(0);
let rbsp = writer.finish();
let pps = Pps::parse(&rbsp).unwrap();
assert_eq!(pps.pic_parameter_set_id, 3);
assert_eq!(pps.seq_parameter_set_id, 1);
assert!(!pps.entropy_coding_mode);
assert_eq!(pps.num_ref_idx_l0_default_active, 16);
assert_eq!(pps.num_ref_idx_l1_default_active, 4);
assert_eq!(pps.pic_init_qp, 21);
assert!(!pps.deblocking_filter_control_present);
assert!(pps.constrained_intra_pred);
}
#[test]
fn parse_errors_on_multiple_slice_groups() {
let mut writer = BitWriter::new();
writer.write_ue(0); writer.write_ue(0); writer.push_bit(0); writer.push_bit(0); writer.write_ue(1);
let rbsp = writer.finish();
assert_eq!(Pps::parse(&rbsp), Err(H264Error::SliceGroupsUnsupported));
}
#[test]
fn parse_errors_on_empty_input() {
assert_eq!(Pps::parse(&[]), Err(H264Error::UnexpectedEof));
}
#[test]
fn parse_errors_on_truncated_input_mid_field() {
let mut writer = BitWriter::new();
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(0);
writer.push_bit(0);
let rbsp = writer.finish();
assert_eq!(Pps::parse(&rbsp), Err(H264Error::UnexpectedEof));
}