#![cfg(test)]
#![allow(
clippy::unwrap_used,
clippy::expect_used,
reason = "test modules may unwrap"
)]
use super::*;
struct Writer {
bytes: Vec<u8>,
buf: u8,
n: u8,
}
impl Writer {
const fn new() -> Self {
Self {
bytes: Vec::new(),
buf: 0,
n: 0,
}
}
fn bit(&mut self, b: bool) {
self.buf = (self.buf << 1) | u8::from(b);
self.n += 1;
if self.n == 8 {
self.bytes.push(self.buf);
self.buf = 0;
self.n = 0;
}
}
fn bits(&mut self, value: u32, n: u32) {
for i in (0..n).rev() {
self.bit((value >> i) & 1 == 1);
}
}
fn finish(mut self) -> Vec<u8> {
while self.n != 0 {
self.bit(false);
}
self.bytes
}
}
fn base_seq() -> SequenceHeader {
SequenceHeader {
seq_profile: 0,
use_128x128_superblock: false,
enable_order_hint: false,
order_hint_bits: 0,
frame_width_bits_minus_1: 5,
frame_height_bits_minus_1: 5,
max_frame_width_minus_1: 63,
max_frame_height_minus_1: 63,
seq_force_screen_content_tools: 0,
seq_force_integer_mv: 2,
color_range: false,
matrix_coefficients: 2,
chroma_sample_position: 0,
separate_uv_delta_q: false,
}
}
fn build_frame_header(base_q_idx: u8, segmentation_enabled: bool) -> Vec<u8> {
let mut w = Writer::new();
w.bit(false); w.bits(0, 2); w.bit(true); w.bit(true); w.bit(false); w.bit(false);
w.bit(true);
w.bits(u32::from(base_q_idx), 8);
w.bit(false); w.bit(false); w.bit(false); w.bit(false);
w.bit(segmentation_enabled);
if !segmentation_enabled {
if base_q_idx > 0 {
w.bit(false); }
let coded_lossless = base_q_idx == 0;
if !coded_lossless {
w.bits(0, 6); w.bits(0, 6); w.bits(0, 3); w.bit(false); w.bit(false); }
w.bit(false); }
w.finish()
}
#[test]
fn accepted_frame_header_not_lossless_round_trips() {
let seq = base_seq();
let bytes = build_frame_header(32, false);
let fh = FrameHeader::parse(&bytes, &seq).unwrap();
assert_eq!(fh.frame_width_minus1, 63);
assert_eq!(fh.frame_height_minus1, 63);
assert_eq!(fh.order_hint, 0);
assert!(fh.disable_cdf_update);
assert!(fh.disable_frame_end_update_cdf);
assert!(!fh.allow_screen_content_tools);
assert!(!fh.allow_intrabc);
assert_eq!(fh.tile_info.sb_cols, 1);
assert_eq!(fh.tile_info.sb_rows, 1);
assert_eq!(fh.quantization.base_q_idx, 32);
assert_eq!(fh.quantization.delta_q_y_dc, 0);
assert!(!fh.quantization.using_qmatrix);
assert!(!fh.delta_q_present);
assert!(!fh.coded_lossless);
assert_eq!(fh.loop_filter.level, [0, 0]);
assert_eq!(fh.loop_filter.ref_deltas, DEFAULT_REF_DELTAS);
assert_eq!(fh.tx_mode, 1); assert!(!fh.reduced_tx_set);
}
#[test]
fn accepted_frame_header_lossless_skips_loop_filter_and_tx_mode_bits() {
let seq = base_seq();
let bytes = build_frame_header(0, false);
let fh = FrameHeader::parse(&bytes, &seq).unwrap();
assert!(fh.coded_lossless);
assert!(!fh.delta_q_present); assert_eq!(fh.loop_filter.level, [0, 0]);
assert_eq!(fh.loop_filter.ref_deltas, DEFAULT_REF_DELTAS);
assert_eq!(fh.tx_mode, 0); }
#[test]
fn rejects_segmentation_enabled() {
let seq = base_seq();
let bytes = build_frame_header(32, true);
assert_eq!(
FrameHeader::parse(&bytes, &seq),
Err(DecodeError::Unsupported)
);
}
#[test]
fn rejects_show_existing_frame() {
let seq = base_seq();
assert_eq!(
FrameHeader::parse(&[0b1000_0000], &seq),
Err(DecodeError::Unsupported)
);
}
#[test]
fn rejects_non_key_frame_type() {
let seq = base_seq();
assert_eq!(
FrameHeader::parse(&[0b0010_0000], &seq),
Err(DecodeError::Unsupported)
);
}
#[test]
fn rejects_non_shown_frame() {
let seq = base_seq();
assert_eq!(
FrameHeader::parse(&[0b0000_0000], &seq),
Err(DecodeError::Unsupported)
);
}
#[test]
fn truncated_input_is_invalid() {
let seq = base_seq();
assert_eq!(
FrameHeader::parse(&[], &seq),
Err(DecodeError::InvalidInput)
);
}