#![cfg(test)]
#![allow(
clippy::unwrap_used,
clippy::expect_used,
reason = "test modules may unwrap"
)]
use super::*;
fn sample_sps() -> Vec<u8> {
let mut sps = vec![0x42, 0x01]; sps.push(0x01); sps.push(0x60); sps.extend_from_slice(&[0x00, 0x00, 0x00, 0x00]); sps.extend_from_slice(&[0x90, 0x00, 0x00, 0x00, 0x00, 0x00]); sps.push(0x5a); sps.extend_from_slice(&[0xaa, 0xbb]); sps
}
#[test]
fn annex_b_converts_when_vps_sps_pps_present() {
let vps = [0x40u8, 0x01, 0x0c];
let sps = sample_sps();
let pps = [0x44u8, 0x01, 0xc0];
let mut annex = vec![0u8, 0, 0, 1];
annex.extend_from_slice(&vps);
annex.extend_from_slice(&[0, 0, 0, 1]);
annex.extend_from_slice(&sps);
annex.extend_from_slice(&[0, 0, 0, 1]);
annex.extend_from_slice(&pps);
let out = to_hvcc(&annex);
let hvcc = out.hvcc.expect("vps+sps+pps present");
assert_eq!(hvcc[0], 1); assert_eq!(hvcc[22], 3); }
#[test]
fn to_hvcc_passes_through_non_annex_b_input() {
let already_framed = [0u8, 0, 0, 3, 0x40, 0x01, 0x0c];
let out = to_hvcc(&already_framed);
assert!(out.hvcc.is_none());
assert_eq!(out.payload.as_ref(), &already_framed);
}
#[test]
fn build_hvcc_copies_byte_aligned_profile_tier_level_fields_when_nothing_is_escaped() {
let vps = [0x40u8, 0x01];
let sps = sample_sps();
let pps = [0x44u8, 0x01];
assert!(
!sps.windows(3).any(|w| w == [0x00, 0x00, 0x03]),
"this fixture must stay escape-free for the test to mean what it says"
);
let hvcc = build_hvcc(&vps, &sps, &pps);
assert_eq!(hvcc[1], sps[3]); assert_eq!(&hvcc[2..6], &sps[4..8]); assert_eq!(&hvcc[6..12], &sps[8..14]); assert_eq!(hvcc[12], sps[14]); }
fn real_nvidia_sps() -> Vec<u8> {
vec![
0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x5a, 0xa0, 0x05, 0x02, 0x01, 0xe1, ]
}
#[test]
fn build_hvcc_unescapes_a_real_encoder_sps() {
let vps = [0x40u8, 0x01, 0x0c];
let sps = real_nvidia_sps();
let pps = [0x44u8, 0x01, 0xc0];
let hvcc = build_hvcc(&vps, &sps, &pps);
assert_eq!(hvcc[0], 1, "configurationVersion");
assert_eq!(hvcc[1], 0x01, "general_profile_space/tier/profile_idc");
assert_eq!(
&hvcc[2..6],
&[0x60, 0x00, 0x00, 0x00],
"general_profile_compatibility_flags: the escape at RBSP byte 7 shifted this"
);
assert_eq!(
&hvcc[6..12],
&[0x90, 0x00, 0x00, 0x00, 0x00, 0x00],
"general_constraint_indicator_flags: three escapes fall inside this range"
);
assert_eq!(
hvcc[12], 0x5a,
"general_level_idc must survive as level 3.0, not read as 0"
);
assert_eq!(
hvcc[21], 0x0f,
"constantFrameRate=0 | numTemporalLayers=1 | temporalIdNested=1 | lengthSizeMinusOne=3"
);
assert_eq!(hvcc[22], 3, "numOfArrays: VPS, SPS, PPS");
}
#[test]
fn build_hvcc_stores_parameter_sets_still_escaped() {
let vps = [0x40u8, 0x01, 0x0c];
let sps = real_nvidia_sps();
let pps = [0x44u8, 0x01, 0xc0];
let hvcc = build_hvcc(&vps, &sps, &pps);
let config = parse_hevc_decoder_config(&hvcc).expect("valid hvcC record");
assert_eq!(config.sps, vec![Bytes::copy_from_slice(&sps)]);
assert_eq!(config.vps, vec![Bytes::copy_from_slice(&vps)]);
assert_eq!(config.pps, vec![Bytes::copy_from_slice(&pps)]);
}
#[test]
fn unescape_rbsp_removes_only_the_escape_byte() {
assert_eq!(
unescape_rbsp(&[0x42, 0x00, 0x00, 0x03, 0x01]),
vec![0x42, 0x00, 0x00, 0x01]
);
}
#[test]
fn unescape_rbsp_is_identity_without_escapes() {
let input = [0x42u8, 0x01, 0x60, 0x00, 0x01, 0xff];
assert_eq!(unescape_rbsp(&input), input.to_vec());
}
#[test]
fn unescape_rbsp_does_not_chain_one_escape_into_the_next() {
assert_eq!(
unescape_rbsp(&[0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x01]),
vec![0x00, 0x00, 0x00, 0x00, 0x01]
);
}
#[test]
fn temporal_layer_byte_reads_sub_layers_and_nesting_from_the_sps() {
let rbsp = [0x42u8, 0x01, 0b0000_0100];
assert_eq!(temporal_layer_byte(&rbsp), (3 << 3) | 0x03);
}
#[test]
fn temporal_layer_byte_falls_back_to_one_unnested_layer() {
assert_eq!(temporal_layer_byte(&[0x42, 0x01]), (1 << 3) | 0x03);
}
#[test]
fn parse_hevc_decoder_config_recovers_vps_sps_pps_from_to_hvcc_output() {
let vps = [0x40u8, 0x01, 0x0c];
let sps = sample_sps();
let pps = [0x44u8, 0x01, 0xc0];
let mut annex = vec![0u8, 0, 0, 1];
annex.extend_from_slice(&vps);
annex.extend_from_slice(&[0, 0, 0, 1]);
annex.extend_from_slice(&sps);
annex.extend_from_slice(&[0, 0, 0, 1]);
annex.extend_from_slice(&pps);
let hvcc_record = to_hvcc(&annex).hvcc.expect("vps+sps+pps present");
let config = parse_hevc_decoder_config(&hvcc_record).expect("valid hvcC record");
assert_eq!(config.nal_length_size, 4);
assert_eq!(config.vps, vec![Bytes::copy_from_slice(&vps)]);
assert_eq!(config.sps, vec![Bytes::copy_from_slice(&sps)]);
assert_eq!(config.pps, vec![Bytes::copy_from_slice(&pps)]);
}
#[test]
fn parse_hevc_decoder_config_rejects_truncated_record() {
assert!(parse_hevc_decoder_config(&[1, 0, 0, 0]).is_none());
}
#[test]
fn parse_hevc_decoder_config_rejects_wrong_version_byte() {
let mut record = vec![2u8];
record.extend_from_slice(&[0u8; 22]);
assert!(parse_hevc_decoder_config(&record).is_none());
}
#[test]
fn annex_b_sequence_header_concatenates_vps_sps_then_pps_with_start_codes() {
let config = HevcDecoderConfig {
nal_length_size: 4,
vps: vec![Bytes::copy_from_slice(&[0x40, 0x01])],
sps: vec![Bytes::copy_from_slice(&[0x42, 0xaa])],
pps: vec![Bytes::copy_from_slice(&[0x44, 0xbb])],
};
let header = annex_b_sequence_header(&config);
assert_eq!(
header.as_ref(),
&[
0, 0, 0, 1, 0x40, 0x01, 0, 0, 0, 1, 0x42, 0xaa, 0, 0, 0, 1, 0x44, 0xbb
]
);
}
#[test]
fn hvcc_payload_to_annex_b_inverts_to_hvcc_four_byte_lengths() {
let vps = [0x40u8, 0x01, 0x0c];
let sps = sample_sps();
let pps = [0x44u8, 0x01, 0xc0];
let mut annex = vec![0u8, 0, 0, 1];
annex.extend_from_slice(&vps);
annex.extend_from_slice(&[0, 0, 0, 1]);
annex.extend_from_slice(&sps);
annex.extend_from_slice(&[0, 0, 0, 1]);
annex.extend_from_slice(&pps);
let payload = to_hvcc(&annex).payload;
let back = hvcc_payload_to_annex_b(&payload, 4);
assert_eq!(back.as_ref(), &annex);
}
#[test]
fn hvcc_payload_to_annex_b_stops_cleanly_on_truncated_length() {
let truncated = [0u8, 0, 0];
let out = hvcc_payload_to_annex_b(&truncated, 4);
assert!(out.is_empty());
}