use std::path::Path;
#[test]
#[ignore]
fn compare_nofilter() {
let bitstream = Path::new("/home/lilith/work/heic/libde265-src/testdata/girlshy.h265");
if !bitstream.exists() {
eprintln!("SKIP: girlshy.h265 not found");
return;
}
let ref_path = Path::new("/tmp/girlshy_nofilter.yuv");
if !ref_path.exists() {
eprintln!("SKIP: run dec265 --disable-deblocking --disable-sao first");
return;
}
let data = std::fs::read(bitstream).unwrap();
let mut decoder = heic::VideoDecoder::new(16);
decoder.disable_loop_filters = true;
let frames = decoder.decode_annex_b(&data).unwrap();
let ref_data = std::fs::read(ref_path).unwrap();
let w = 320u32; let h = 240u32;
let luma_size = (w * h) as usize;
let frame_size = luma_size + 2 * ((w / 2) * (h / 2)) as usize;
let filtered_ref = Path::new("/tmp/girlshy_ref.yuv");
if filtered_ref.exists() {
let fref_data = std::fs::read(filtered_ref).unwrap();
let fref_y: Vec<u16> = fref_data[..luma_size].iter().map(|&b| b as u16).collect();
let stride = frames[0].width as usize;
let mut exact = 0u32;
for y in 0..h as usize {
for x in 0..316usize {
if fref_y[y * w as usize + x] == frames[0].y_plane[y * stride + x] {
exact += 1;
}
}
}
let total = 316 * h;
eprintln!(
"Frame 0 sanity: our unfiltered vs dec265 FILTERED: {exact}/{total} ({:.1}%)",
100.0 * exact as f64 / total as f64
);
}
{
let ref_y: Vec<u16> = ref_data[..luma_size].iter().map(|&b| b as u16).collect();
let stride = frames[0].width as usize;
for y in 0..h as usize {
for x in 0..316usize {
let rv = ref_y[y * w as usize + x];
let ov = frames[0].y_plane[y * stride + x];
if rv != ov {
let d = ov as i32 - rv as i32;
eprintln!(
"First unfiltered I-frame diff: ({x},{y}) ours={ov} dec265={rv} diff={d:+}"
);
let bx = (x / 4) * 4;
let by = (y / 4) * 4;
for dy in 0..4 {
eprint!(" ");
for dx in 0..4 {
let gx = bx + dx;
let gy = by + dy;
let r = ref_y[gy * w as usize + gx];
let o = frames[0].y_plane[gy * stride + gx];
eprint!("{}({:+}) ", o, o as i32 - r as i32);
}
eprintln!();
}
break;
}
}
}
}
eprintln!("=== No-filter comparison (MC + residual only, cropped) ===");
let cw = 316u32; let compare_count = frames.len().min(ref_data.len() / frame_size).min(10);
for fi in 0..compare_count {
let ref_y: Vec<u16> = ref_data[fi * frame_size..fi * frame_size + luma_size]
.iter()
.map(|&b| b as u16)
.collect();
let stride = frames[fi].width as usize;
let mut exact = 0u32;
let mut max_diff = 0u16;
let mut sse = 0u64;
let mut count = 0u32;
for y in 0..h as usize {
for x in 0..cw as usize {
let rv = ref_y[y * w as usize + x];
let ov = frames[fi].y_plane[y * stride + x];
let d = (ov as i32 - rv as i32).unsigned_abs() as u16;
count += 1;
if d == 0 {
exact += 1;
} else {
max_diff = max_diff.max(d);
sse += d as u64 * d as u64;
}
}
}
let mse = sse as f64 / count as f64;
let psnr = if mse > 0.0 {
10.0 * (255.0 * 255.0 / mse).log10()
} else {
f64::INFINITY
};
eprintln!(
" Frame {fi}: PSNR={psnr:.1}dB, exact={exact}/{count} ({:.1}%), max_diff={max_diff}",
100.0 * exact as f64 / count as f64
);
}
}
#[test]
#[ignore]
fn trace_girlshy_p_frame_mvs() {
let bitstream = Path::new("/home/lilith/work/heic/libde265-src/testdata/girlshy.h265");
if !bitstream.exists() {
eprintln!("SKIP: girlshy.h265 not found");
return;
}
let data = std::fs::read(bitstream).unwrap();
let mut decoder = heic::VideoDecoder::new(16);
decoder.mv_trace_next_inter = true;
let _ = decoder.decode_annex_b(&data).unwrap();
}
#[test]
#[ignore]
fn compare_cabac_bins() {
let bitstream = Path::new("/home/lilith/work/heic/libde265-src/testdata/girlshy.h265");
if !bitstream.exists() {
eprintln!("SKIP: girlshy.h265 not found");
return;
}
let data = std::fs::read(bitstream).unwrap();
let mut decoder = heic::VideoDecoder::new(16);
decoder.mv_trace_next_inter = true; heic::cabac_bin_trace(200);
let _ = decoder.decode_annex_b(&data).unwrap();
}
#[test]
#[ignore]
fn trace_girlshy_frame1() {
let bitstream = Path::new("/home/lilith/work/heic/libde265-src/testdata/girlshy.h265");
if !bitstream.exists() {
eprintln!("SKIP: girlshy.h265 not found");
return;
}
let data = std::fs::read(bitstream).unwrap();
let mut decoder = heic::VideoDecoder::new(16);
let frames = decoder.decode_annex_b(&data).unwrap();
let ref_path = Path::new("/tmp/girlshy_ref.yuv");
if !ref_path.exists() {
eprintln!("SKIP: reference YUV not generated (run conformance test first)");
return;
}
let ref_data = std::fs::read(ref_path).unwrap();
let w = 316u32;
let h = 240u32;
let luma_size = (w * h) as usize;
let frame_size = luma_size + 2 * ((w / 2) * (h / 2)) as usize;
eprintln!("Decoded {} frames", frames.len());
let our_f0 = &frames[0];
let _ref_f0: Vec<u16> = ref_data[..luma_size].iter().map(|&b| b as u16).collect();
let our_f1 = &frames[1];
let ref_f1: Vec<u16> = ref_data[frame_size..frame_size + luma_size]
.iter()
.map(|&b| b as u16)
.collect();
eprintln!("\n=== Frame 0 (I) vs Frame 1 (inter) at (0,0) 8x8 block ===");
eprintln!("Legend: I=I-frame, R1=ref-frame1, O1=our-frame1, D=diff(O1-R1)");
let stride0 = our_f0.width as usize;
let stride1 = our_f1.width as usize;
for y in 0..8u32 {
eprint!(" y={y}: ");
for x in 0..8u32 {
let ref_idx = (y * w + x) as usize;
let our0_idx = y as usize * stride0 + x as usize;
let our1_idx = y as usize * stride1 + x as usize;
let i_val = our_f0.y_plane[our0_idx]; let r1_val = ref_f1[ref_idx]; let o1_val = our_f1.y_plane[our1_idx];
let diff = o1_val as i32 - r1_val as i32;
eprint!("I{i_val:3}/R{r1_val:3}/O{o1_val:3}({diff:+3}) ");
}
eprintln!();
}
if frames.len() > 4 && ref_data.len() >= 5 * frame_size {
let our_f4 = &frames[4];
let ref_f4: Vec<u16> = ref_data[4 * frame_size..4 * frame_size + luma_size]
.iter()
.map(|&b| b as u16)
.collect();
let stride4 = our_f4.width as usize;
eprintln!("\n=== Frame 4 (P, POC=4, refs I-frame only) at (0,0) 16x8 block ===");
for y in 0..8u32 {
eprint!(" y={y}: ");
for x in 0..16u32.min(w) {
let ref_idx = (y * w + x) as usize;
let our4_idx = y as usize * stride4 + x as usize;
let i_idx = y as usize * stride0 + x as usize;
let _i_val = our_f0.y_plane[i_idx];
let r4_val = ref_f4[ref_idx];
let o4_val = our_f4.y_plane[our4_idx];
let diff = o4_val as i32 - r4_val as i32;
eprint!("{o4_val:3}({diff:+3}) ");
}
eprintln!();
}
let mut first_exact_block = None;
let mut first_bad_block = None;
for by in 0..(h / 4) {
for bx in 0..(w / 4) {
let mut all_exact = true;
let mut all_bad = true;
for dy in 0..4u32 {
for dx in 0..4u32 {
let gy = by * 4 + dy;
let gx = bx * 4 + dx;
if gy < h && gx < w {
let ref_val = ref_f4[(gy * w + gx) as usize];
let our_val = our_f4.y_plane[gy as usize * stride4 + gx as usize];
if our_val != ref_val {
all_exact = false;
}
if our_val == ref_val {
all_bad = false;
}
}
}
}
if all_exact && first_exact_block.is_none() {
first_exact_block = Some((bx * 4, by * 4));
}
if all_bad && first_bad_block.is_none() {
first_bad_block = Some((bx * 4, by * 4));
}
}
}
eprintln!("\nFirst fully exact 4x4 block: {:?}", first_exact_block);
eprintln!("First fully wrong 4x4 block: {:?}", first_bad_block);
let mut first_diff_pos = None;
for y in 0..h {
for x in 0..w {
let ref_val = ref_f4[(y * w + x) as usize];
let our_val = our_f4.y_plane[y as usize * stride4 + x as usize];
if our_val != ref_val && first_diff_pos.is_none() {
first_diff_pos = Some((x, y, our_val, ref_val));
}
}
}
if let Some((x, y, ours, reference)) = first_diff_pos {
let diff = ours as i32 - reference as i32;
eprintln!(
"First differing pixel in frame 4: ({x},{y}) ours={ours} ref={reference} diff={diff:+}"
);
eprintln!(
" CTU ({},{}), local ({},{})",
x / 64,
y / 64,
x % 64,
y % 64
);
let bx = (x / 8) * 8;
let by = (y / 8) * 8;
eprintln!(" Surrounding 8x4 (ours/ref/diff):");
for dy in 0..4u32.min(h - by) {
eprint!(" ");
for dx in 0..8u32.min(w - bx) {
let gx = bx + dx;
let gy = by + dy;
let rv = ref_f4[(gy * w + gx) as usize];
let ov = our_f4.y_plane[gy as usize * stride4 + gx as usize];
let d = ov as i32 - rv as i32;
eprint!("{ov:3}({d:+3}) ");
}
eprintln!();
}
let iframe_val_at_34_0 = our_f0.y_plane[34];
eprintln!(" I-frame[34,0] = {iframe_val_at_34_0}");
eprintln!(" I-frame row 0, cols 30..40:");
eprint!(" ");
for cx in 30..40u32.min(our_f0.width) {
eprint!(" {:3}", our_f0.y_plane[cx as usize]);
}
eprintln!();
eprintln!("\n First 20 differing pixels in frame 4:");
let mut diff_count = 0;
for gy in 0..h {
for gx in 0..w {
let rv = ref_f4[(gy * w + gx) as usize];
let ov = our_f4.y_plane[gy as usize * stride4 + gx as usize];
if ov != rv {
let d = ov as i32 - rv as i32;
eprintln!(" ({gx},{gy}) ours={ov} ref={rv} diff={d:+}");
diff_count += 1;
if diff_count >= 20 {
break;
}
}
}
if diff_count >= 20 {
break;
}
}
}
eprintln!("\n=== MC reverse-engineering for frame 4 pixel (0,0) ===");
let our_val = our_f4.y_plane[0];
let ref_val = ref_f4[0];
eprintln!(
" Our: {our_val}, Ref: {ref_val}, I-frame: {}",
our_f0.y_plane[0]
);
eprintln!(" Zero MV uni-pred from I: {}", our_f0.y_plane[0]);
eprintln!(" I-frame 16x16 at (0,0):");
for y in 0..16u32 {
eprint!(" ");
for x in 0..16u32 {
eprint!("{:3} ", our_f0.y_plane[y as usize * stride0 + x as usize]);
}
eprintln!();
}
}
eprintln!("\n=== Expected MC outputs for pixel (0,0) ===");
let p00 = our_f0.y_plane[0] as i32;
let uni_pred = p00;
let bi_pred = (p00 * 64 + p00 * 64 + 64) >> 7;
eprintln!(" I-frame pixel: {p00}");
eprintln!(" Uni-pred (zero MV from I): {uni_pred}");
eprintln!(" Bi-pred (zero MV, both from I): {bi_pred}");
eprintln!(" Ref frame 1 pixel: {}", ref_f1[0]);
eprintln!(" Our frame 1 pixel: {}", our_f1.y_plane[0]);
eprintln!("\nRef frame count: {}", ref_data.len() / frame_size);
eprintln!("Our frame count: {}", frames.len());
for (i, f) in frames.iter().enumerate().take(3) {
eprintln!(
" Frame {i}: coded={}x{}, cropped={}x{}, crop=({},{},{},{})",
f.width,
f.height,
f.cropped_width(),
f.cropped_height(),
f.crop_left,
f.crop_right,
f.crop_top,
f.crop_bottom
);
}
let mut same_count = 0u32;
for i in 0..luma_size
.min(our_f0.y_plane.len())
.min(our_f1.y_plane.len())
{
if our_f0.y_plane[i] == our_f1.y_plane[i] {
same_count += 1;
}
}
eprintln!(
"\nFrame 0 vs Frame 1 identity check: {same_count}/{} same pixels ({:.1}%)",
luma_size,
100.0 * same_count as f64 / luma_size as f64
);
eprintln!("\n=== Per-frame Y-plane comparison (first 10 frames) ===");
let compare_count = frames.len().min(ref_data.len() / frame_size).min(10);
#[allow(clippy::needless_range_loop)]
for fi in 0..compare_count {
let ref_y_start = fi * frame_size;
let ref_y: Vec<u16> = ref_data[ref_y_start..ref_y_start + luma_size]
.iter()
.map(|&b| b as u16)
.collect();
let our_y = &frames[fi].y_plane;
let stride = frames[fi].width as usize;
let mut sse = 0u64;
let mut exact = 0u32;
let mut max_diff = 0u16;
let _cw = frames[fi].cropped_width() as usize;
let _ch = frames[fi].cropped_height() as usize;
for y in 0..h as usize {
for x in 0..w as usize {
let ref_val = ref_y[y * w as usize + x];
let our_val = our_y[y * stride + x];
let diff = (our_val as i32 - ref_val as i32).unsigned_abs() as u16;
if diff == 0 {
exact += 1;
} else {
max_diff = max_diff.max(diff);
sse += (diff as u64) * (diff as u64);
}
}
}
let mse = sse as f64 / luma_size as f64;
let psnr = if mse > 0.0 {
10.0 * (255.0 * 255.0 / mse).log10()
} else {
f64::INFINITY
};
eprintln!(
" Frame {fi}: PSNR={psnr:.1}dB, exact={exact}/{luma_size} ({:.1}%), max_diff={max_diff}",
100.0 * exact as f64 / luma_size as f64
);
}
}