//! Writes test data to a video output device. //! //! Uses the [`std::io::Write`] implementation of [`linuxvideo::VideoOutputDevice`]. use std::{ env, io::Write, path::Path, thread, time::{Duration, Instant}, }; use anyhow::{anyhow, bail}; use itertools::Itertools; use linuxvideo::{ format::{PixFormat, PixelFormat}, CapabilityFlags, Device, }; const WIDTH: u32 = 1920; const HEIGHT: u32 = 1080; const PIXFMT: PixelFormat = PixelFormat::ABGR32; const RED: [u8; 4] = [0, 0, 0xff, 0xff]; const GREEN: [u8; 4] = [0, 0xff, 0, 0xff]; const BLUE: [u8; 4] = [0xff, 0, 0, 0xff]; const TRANSPARENT: [u8; 4] = [0, 0xff, 0xff, 120]; fn main() -> anyhow::Result<()> { let mut args = env::args_os().skip(1); let path = args .next() .ok_or_else(|| anyhow!("usage: write "))?; let device = Device::open(Path::new(&path))?; if !device .capabilities()? .device_capabilities() .contains(CapabilityFlags::VIDEO_OUTPUT) { bail!("cannot write data: selected device does not support `VIDEO_OUTPUT` capability"); } let mut output = device.video_output(PixFormat::new(WIDTH, HEIGHT, PIXFMT))?; let fmt = output.format(); println!("set format: {:?}", fmt); if fmt.pixel_format() != PIXFMT { bail!("driver does not support the requested parameters"); } let mut image = (0..fmt.height()) .cartesian_product(0..fmt.width()) .flat_map(|(y, x)| { if x == y { RED } else if x < 5 || x > fmt.width() - 5 { GREEN } else if y < 5 || y > fmt.height() - 5 { BLUE } else { TRANSPARENT } }) .collect::>(); assert_eq!( image.len(), fmt.width() as usize * fmt.height() as usize * 4 ); assert!(image.len() <= fmt.size_image() as usize); image.resize(fmt.size_image() as usize, 0xff); println!("output started"); let mut frames = 0; let mut time = Instant::now(); loop { output.write(&image)?; frames += 1; print!("."); std::io::stdout().flush().ok(); if time.elapsed() >= Duration::from_secs(1) { println!(" {} FPS", frames); time = Instant::now(); frames = 0; } // This can run at 170000 FPS, so sleep a bit to limit that. thread::sleep(Duration::from_millis(5)); } }