#![cfg(test)]
#![allow(
clippy::unwrap_used,
clippy::expect_used,
reason = "test modules may unwrap"
)]
use super::*;
use crate::vulkan::dpb::DpbSlot;
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 finish(mut self) -> Vec<u8> {
while self.nbits != 0 {
self.push_bit(0);
}
self.bytes
}
}
fn write_profile_tier_level(writer: &mut BitWriter, profile_idc: u32, level_idc: u32) {
writer.write_bits(0, 2); writer.push_bit(0); writer.write_bits(profile_idc, 5); writer.write_bits(0, 32); writer.push_bit(1); writer.push_bit(0); writer.push_bit(1); writer.push_bit(1); writer.write_bits(0, 32); writer.write_bits(0, 12); writer.write_bits(level_idc, 8); }
fn build_sps_rbsp(max_num_ref_frames_minus1: u32, width: u32, height: u32) -> Vec<u8> {
let mut writer = BitWriter::new();
writer.write_bits(0, 4); writer.write_bits(0, 3); writer.push_bit(1); write_profile_tier_level(&mut writer, 1, 60); writer.write_ue(0); writer.write_ue(1); writer.write_ue(width); writer.write_ue(height); writer.push_bit(0); writer.write_ue(0); writer.write_ue(0); writer.write_ue(0); writer.push_bit(1); writer.write_ue(max_num_ref_frames_minus1); writer.write_ue(0); writer.write_ue(0); writer.write_ue(0); writer.write_ue(2); writer.write_ue(0); writer.write_ue(3); writer.write_ue(3); writer.write_ue(3); writer.push_bit(0); writer.push_bit(1); writer.push_bit(1); writer.push_bit(0); writer.write_ue(0); writer.push_bit(0); writer.push_bit(1); writer.push_bit(0); writer.finish()
}
#[test]
fn sps_parse_extracts_expected_fields() {
let rbsp = build_sps_rbsp(1, 64, 16);
let sps = HevcSps::parse(&rbsp).unwrap();
assert_eq!(sps.pic_width_in_luma_samples, 64);
assert_eq!(sps.pic_height_in_luma_samples, 16);
assert_eq!(sps.log2_max_pic_order_cnt_lsb, 4);
assert_eq!(sps.max_dec_pic_buffering, 2);
assert_eq!(sps.log2_min_cb_size, 3);
assert_eq!(sps.log2_diff_max_min_cb_size, 2);
assert_eq!(sps.log2_min_tb_size, 2);
assert_eq!(sps.log2_diff_max_min_tb_size, 3);
assert_eq!(sps.general_profile_idc, 1);
assert_eq!(sps.general_level_idc, 60);
assert!(sps.amp_enabled_flag);
assert!(sps.sample_adaptive_offset_enabled_flag);
assert!(sps.sps_temporal_mvp_enabled_flag);
assert!(!sps.strong_intra_smoothing_enabled_flag);
}
#[test]
fn sps_parse_rejects_multiple_sub_layers() {
let mut writer = BitWriter::new();
writer.write_bits(0, 4); writer.write_bits(1, 3); let rbsp = writer.finish();
let err = HevcSps::parse(&rbsp).unwrap_err();
assert!(matches!(err, HevcParamError::Unsupported { .. }));
}
#[test]
fn sps_parse_rejects_nonzero_short_term_rps_count() {
let mut writer = BitWriter::new();
writer.write_bits(0, 4);
writer.write_bits(0, 3);
writer.push_bit(1);
write_profile_tier_level(&mut writer, 1, 60);
writer.write_ue(0); writer.write_ue(1); writer.write_ue(64); writer.write_ue(16); writer.push_bit(0); writer.write_ue(0);
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(1);
writer.write_ue(1);
writer.write_ue(0);
writer.write_ue(0);
writer.write_ue(0);
writer.write_ue(2);
writer.write_ue(0);
writer.write_ue(3);
writer.write_ue(3);
writer.write_ue(3);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.write_ue(1); let rbsp = writer.finish();
let err = HevcSps::parse(&rbsp).unwrap_err();
assert!(matches!(err, HevcParamError::Unsupported { .. }));
}
#[test]
fn pps_parse_extracts_expected_fields() {
let mut writer = BitWriter::new();
writer.write_ue(0); writer.write_ue(0); writer.push_bit(0); writer.push_bit(1); writer.write_bits(2, 3); writer.push_bit(0); writer.push_bit(0); writer.write_ue(0); writer.write_ue(0); writer.write_ue(0); writer.push_bit(0); writer.push_bit(0); writer.push_bit(0); writer.write_ue(0); writer.write_ue(0); writer.push_bit(0); writer.push_bit(0); writer.push_bit(0); writer.push_bit(0); writer.push_bit(0); writer.push_bit(0); let rbsp = writer.finish();
let pps = HevcPps::parse(&rbsp).unwrap();
assert!(pps.output_flag_present_flag);
assert_eq!(pps.num_extra_slice_header_bits, 2);
assert_eq!(pps.num_ref_idx_l0_default_active, 1);
assert_eq!(pps.init_qp, 26);
}
#[test]
fn pps_parse_rejects_tiles_enabled() {
let mut writer = BitWriter::new();
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(0);
writer.push_bit(0);
writer.write_bits(0, 3);
writer.push_bit(0);
writer.push_bit(0);
writer.write_ue(0);
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(1); let rbsp = writer.finish();
let err = HevcPps::parse(&rbsp).unwrap_err();
assert!(matches!(err, HevcParamError::Unsupported { .. }));
}
#[test]
fn pps_parse_rejects_wpp_entropy_coding_sync() {
let mut writer = BitWriter::new();
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(0);
writer.push_bit(0);
writer.write_bits(0, 3);
writer.push_bit(0);
writer.push_bit(0);
writer.write_ue(0);
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.write_ue(0);
writer.write_ue(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0);
writer.push_bit(0); writer.push_bit(1); let rbsp = writer.finish();
let err = HevcPps::parse(&rbsp).unwrap_err();
assert!(matches!(err, HevcParamError::Unsupported { .. }));
}
#[test]
fn vps_parse_extracts_id() {
let rbsp = [0x30u8, 0x00]; let vps = HevcVps::parse(&rbsp).unwrap();
assert_eq!(vps.vps_video_parameter_set_id, 3);
}
#[test]
fn nal_unit_parse_extracts_header_fields() {
let first = (33u8) << 1;
let second = 0x1u8;
let data = [first, second, 0xAB, 0xCD];
let nal = HevcNalUnit::parse(&data).unwrap();
assert!(matches!(nal.unit_type, HevcNalUnitType::Sps));
assert_eq!(nal.nuh_layer_id, 0);
assert_eq!(nal.temporal_id, 0);
assert_eq!(nal.rbsp, vec![0xAB, 0xCD]);
}
#[test]
fn nal_unit_parse_rejects_nonzero_layer_id() {
let first = (33u8) << 1 | 0x1; let second = 0x1u8;
let data = [first, second];
let err = HevcNalUnit::parse(&data).unwrap_err();
assert!(matches!(err, HevcParamError::Unsupported { .. }));
}
#[test]
fn reference_info_from_slot_carries_poc_and_reference_flag() {
let slot = DpbSlot::new_reference(0, 0, 7);
let info = reference_info_from_slot(&slot);
assert_eq!(info.PicOrderCntVal, 7);
assert_eq!(info.flags.unused_for_reference(), 0);
assert_eq!(info.flags.used_for_long_term_reference(), 0);
}