#[cfg(feature = "demux")]
mod tests {
use vtome::{Compositor, Output, OutputLayer, Frame, PixelFormat, ColorSpace};
use vtome::geometry::Rect;
use std::time::Duration;
use std::path::Path;
fn test_checkerboard(width: u32, height: u32, frame_num: u32) -> Frame {
let block_size = 32;
let mut data = vec![0u8; (width * height * 4) as usize];
for y in 0..height {
for x in 0..width {
let block_x = x / block_size;
let block_y = y / block_size;
let is_white = (block_x + block_y) % 2 == 0;
let color = if is_white { 255u8 } else { 0u8 };
let idx = ((y * width + x) * 4) as usize;
data[idx] = color;
data[idx + 1] = color;
data[idx + 2] = color;
data[idx + 3] = 255;
}
}
Frame::packed(
width,
height,
PixelFormat::Rgba8,
ColorSpace::srgb(),
Duration::from_millis(frame_num as u64 * 41),
data,
)
.expect("valid frame")
}
#[test]
#[ignore]
fn h264_file_decodes_and_produces_frames() {
let file_path = "tests/data/test_h264.mp4";
if !Path::new(file_path).exists() {
eprintln!("Skipping: {} not found (generate with ffmpeg)", file_path);
eprintln!(" ffmpeg -f lavfi -i testsrc=s=1920x1080:d=1 -pix_fmt yuv420p -c:v libx264 -preset fast {}", file_path);
return;
}
let demuxer = match vtome::open_media(file_path) {
Ok(d) => d,
Err(e) => {
eprintln!("Failed to open {}: {}", file_path, e);
panic!("demux failed");
}
};
let info = demuxer.info();
let video = info.video().expect("must have video track");
let encoding = video.encoding.expect("video track must have encoding");
assert_eq!(encoding, vtome::Encoding::H264);
assert!(video.width > 0 && video.height > 0);
let config = vtome::decode::DecoderConfig {
encoding,
width: video.width,
height: video.height,
bit_depth: video.bit_depth,
color: video.color,
extra_data: video.extra_data.clone(),
};
let decoder = match vtome::decode::open(&config) {
Ok(d) => d,
Err(e) => {
eprintln!("No H.264 decoder available: {}", e);
eprintln!("Enable --features decode-platform or ensure VideoToolbox FFI is implemented");
return;
}
};
assert!(decoder.is_hardware(), "Expected hardware H.264 decoder");
assert_eq!(decoder.encoding(), encoding);
}
#[test]
fn multi_source_composition() {
let mut comp = Compositor::new();
let mut output = Output::new(1920, 1080)
.with_background_color([0.1, 0.1, 0.1, 1.0]);
let layer1 = OutputLayer::new("video_a", Rect::new(0.0, 0.0, 960.0, 1080.0))
.with_z_index(0)
.with_opacity(1.0);
let layer2 = OutputLayer::new("video_b", Rect::new(960.0, 0.0, 960.0, 1080.0))
.with_z_index(1)
.with_opacity(0.8);
output.add_layers(vec![layer1, layer2]);
comp.add_output(output);
let result = comp.advance(Duration::from_millis(41));
assert!(result.is_ok());
assert_eq!(comp.output_count(), 1);
let out = comp.get_output(0).unwrap();
assert_eq!(out.width, 1920);
assert_eq!(out.height, 1080);
assert_eq!(out.layers.len(), 2);
assert_eq!(out.layers[0].z_index, 0);
assert_eq!(out.layers[0].opacity, 1.0);
assert_eq!(out.layers[1].z_index, 1);
assert_eq!(out.layers[1].opacity, 0.8);
}
#[test]
fn compositor_frame_queuing() {
let frames: Vec<Frame> = (0..10)
.map(|i| test_checkerboard(1920, 1080, i))
.collect();
for (i, frame) in frames.iter().enumerate() {
assert_eq!(frame.width(), 1920);
assert_eq!(frame.height(), 1080);
assert_eq!(frame.format(), PixelFormat::Rgba8);
let expected_pts = Duration::from_millis((i as u64) * 41);
assert_eq!(frame.pts(), expected_pts);
}
}
#[test]
fn pipeline_structure_validation() {
let mut comp = Compositor::new();
let mut output = Output::new(1920, 1080);
let layer = OutputLayer::new("test_video", Rect::new(0.0, 0.0, 1920.0, 1080.0));
output.add_layer(layer);
comp.add_output(output);
assert_eq!(comp.source_count(), 0);
assert_eq!(comp.output_count(), 1);
let result = comp.advance(Duration::from_millis(41));
assert!(result.is_ok(), "Should handle empty source list gracefully");
let result = comp.render_output(0);
assert!(result.is_ok(), "Should render output without sources");
}
#[test]
fn e2e_test_documentation() {
println!("E2E tests require test video files. Generate them with:");
println!(" mkdir -p tests/data");
println!(" ffmpeg -f lavfi -i testsrc=s=1920x1080:d=2 \\");
println!(" -pix_fmt yuv420p -c:v libx264 -preset fast tests/data/test_h264.mp4");
}
}
#[cfg(not(feature = "demux"))]
fn main() {
eprintln!("E2E playback tests require --features demux");
}