#![cfg(feature = "h264-encoder")]
mod common;
use common::h264_oracle::{decode_via_ffmpeg_with_format, system_has_ffmpeg};
use phasm_core::{transcode_yuv_to_baseline_cavlc_h264, BaselineTranscodeConfig};
fn psnr(a: &[u8], b: &[u8]) -> f64 {
let n = a.len().min(b.len());
if n == 0 {
return f64::INFINITY;
}
let mut sse: f64 = 0.0;
for i in 0..n {
let d = a[i] as i32 - b[i] as i32;
sse += (d * d) as f64;
}
let mse = sse / (n as f64);
if mse == 0.0 {
return f64::INFINITY;
}
10.0 * (255.0_f64 * 255.0 / mse).log10()
}
fn load_real_world(name: &str) -> Vec<u8> {
std::fs::read(format!("test-vectors/video/h264/real-world/{name}"))
.unwrap_or_else(|_| panic!("missing test vector: {name}"))
}
#[test]
fn real_world_transcode_baseline_cavlc_32x32_psnr_at_qp26() {
if !system_has_ffmpeg() {
eprintln!("skipping — ffmpeg not installed");
return;
}
let pixels = load_real_world("img4138_32x32_f1.yuv");
let cfg = BaselineTranscodeConfig::defaults(32, 32, 1);
let bytes = transcode_yuv_to_baseline_cavlc_h264(&pixels, cfg)
.expect("transcode_yuv_to_baseline_cavlc_h264 must succeed on real-world clip");
let result = decode_via_ffmpeg_with_format(&bytes, Some("h264"))
.expect("ffmpeg must decode the produced Annex-B");
let y_size = (32 * 32) as usize;
let luma_psnr = psnr(&pixels[..y_size], &result.decoded_yuv[..y_size]);
assert!(
luma_psnr >= 25.0,
"real-world 32×32 luma PSNR {luma_psnr:.1} dB < 25.0 functional floor",
);
}
#[test]
fn real_world_transcode_baseline_cavlc_64x48_5frames_psnr_at_qp26() {
if !system_has_ffmpeg() {
eprintln!("skipping — ffmpeg not installed");
return;
}
let pixels = load_real_world("img4138_64x48_f5.yuv");
let cfg = BaselineTranscodeConfig::defaults(64, 48, 5);
let bytes = transcode_yuv_to_baseline_cavlc_h264(&pixels, cfg)
.expect("transcode 5-frame real-world clip");
let result = decode_via_ffmpeg_with_format(&bytes, Some("h264"))
.expect("ffmpeg decode 64×48×5");
let y_size_per_frame = (64 * 48) as usize;
let i_psnr = psnr(&pixels[..y_size_per_frame], &result.decoded_yuv[..y_size_per_frame]);
assert!(
i_psnr >= 25.0,
"real-world 64×48 I-frame luma PSNR {i_psnr:.1} dB < 25.0 functional floor",
);
}
#[test]
fn real_world_transcode_baseline_cavlc_128x80_10frames_psnr() {
if !system_has_ffmpeg() {
eprintln!("skipping — ffmpeg not installed");
return;
}
let pixels = load_real_world("img4138_128x80_f10.yuv");
let cfg = BaselineTranscodeConfig::defaults(128, 80, 10);
let bytes = transcode_yuv_to_baseline_cavlc_h264(&pixels, cfg)
.expect("transcode 10-frame real-world clip");
let result = decode_via_ffmpeg_with_format(&bytes, Some("h264"))
.expect("ffmpeg decode 128×80×10");
let y_size_per_frame = (128 * 80) as usize;
let i_psnr = psnr(&pixels[..y_size_per_frame], &result.decoded_yuv[..y_size_per_frame]);
assert!(
i_psnr >= 25.0,
"real-world 128×80 I-frame luma PSNR {i_psnr:.1} dB < 25.0 functional floor",
);
}
#[test]
fn real_world_transcode_emits_baseline_profile() {
let pixels = load_real_world("img4138_32x32_f1.yuv");
let cfg = BaselineTranscodeConfig::defaults(32, 32, 1);
let bytes = transcode_yuv_to_baseline_cavlc_h264(&pixels, cfg).unwrap();
let sps_payload = find_first_nal(&bytes, 7)
.expect("SPS NAL must be present in transcode output");
let profile_idc = sps_payload[0];
assert_eq!(
profile_idc, 66,
"Phase E Q1: transcode must emit Baseline profile (profile_idc=66, got {profile_idc})",
);
assert!(
find_first_nal(&bytes, 8).is_some(),
"PPS NAL must be present",
);
}
#[test]
fn real_world_transcode_emits_cavlc_entropy() {
let pixels = load_real_world("img4138_32x32_f1.yuv");
let cfg = BaselineTranscodeConfig::defaults(32, 32, 1);
let bytes = transcode_yuv_to_baseline_cavlc_h264(&pixels, cfg).unwrap();
let pps = find_first_nal(&bytes, 8).expect("PPS NAL");
assert!(
is_cavlc_pps(pps),
"Phase E Q1: transcode must emit CAVLC entropy (entropy_coding_mode_flag=0)",
);
}
fn find_first_nal(bytes: &[u8], nal_type: u8) -> Option<&[u8]> {
let mut i = 0;
while i + 4 < bytes.len() {
let is_start4 = bytes[i] == 0 && bytes[i + 1] == 0 && bytes[i + 2] == 0 && bytes[i + 3] == 1;
let (start_len, nal_offset) = if is_start4 {
(4, i + 4)
} else if i + 3 < bytes.len()
&& bytes[i] == 0 && bytes[i + 1] == 0 && bytes[i + 2] == 1
{
(3, i + 3)
} else {
i += 1;
continue;
};
let _ = start_len;
if nal_offset >= bytes.len() {
return None;
}
let header = bytes[nal_offset];
let nut = header & 0x1F;
if nut == nal_type {
let mut j = nal_offset + 1;
while j + 2 < bytes.len() {
if bytes[j] == 0 && bytes[j + 1] == 0
&& (bytes[j + 2] == 1 || (bytes[j + 2] == 0 && j + 3 < bytes.len() && bytes[j + 3] == 1))
{
break;
}
j += 1;
}
return Some(&bytes[nal_offset + 1..j.min(bytes.len())]);
}
i = nal_offset + 1;
}
None
}
fn is_cavlc_pps(pps: &[u8]) -> bool {
let mut br = BitReader::new(pps);
let _ = br.read_ue(); let _ = br.read_ue(); let entropy = br.read_bit();
entropy == 0
}
struct BitReader<'a> {
bytes: &'a [u8],
bit_idx: usize,
}
impl<'a> BitReader<'a> {
fn new(bytes: &'a [u8]) -> Self {
Self { bytes, bit_idx: 0 }
}
fn read_bit(&mut self) -> u32 {
let byte = self.bit_idx / 8;
let bit = 7 - (self.bit_idx % 8);
self.bit_idx += 1;
if byte >= self.bytes.len() {
return 0;
}
((self.bytes[byte] >> bit) & 1) as u32
}
fn read_ue(&mut self) -> u32 {
let mut zeros = 0u32;
while self.read_bit() == 0 && zeros < 32 {
zeros += 1;
}
let mut suffix = 0u32;
for _ in 0..zeros {
suffix = (suffix << 1) | self.read_bit();
}
(1u32 << zeros) - 1 + suffix
}
}