onix 0.2.0

Decode image files using V4L2
Documentation
use onix::Onix;
use std::fs::File;
use std::io::{Read, Write};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    env_logger::init();

    let args: Vec<_> = std::env::args().collect();
    if args.len() != 7 {
        eprintln!(
            "Usage: {} <image.raw> <width> <height> <format> <compression-quality> <output.jpeg>",
            args[0]
        );
        std::process::exit(1);
    }

    let mut input = std::fs::File::open(&args[1])?;
    let width: u32 = args[2].parse()?;
    let height: u32 = args[3].parse()?;

    let format = match args[4].as_str() {
        "YUYV" => onix::DrmFormats::YUYV,
        "UYVY" => onix::DrmFormats::UYVY,
        "NV12" => onix::DrmFormats::NM12,
        "YU12" => onix::DrmFormats::YM12,
        format => panic!("Unknown format {format}"),
    };

    let compression_quality: i32 = args[5].parse()?;

    // Encode our JPEG using V4L2.
    let decoder = Onix::find_devices()
        .expect("Unable to find a V4L2 M2M decoder corresponding to our criteria");
    let mut encoder = decoder
        .jpeg_encoder()
        .expect("No available JPEG encoder on this system");

    println!(
        "Encoding with {} ({})",
        encoder.video_path().display(),
        encoder.video_querycap()?.driver(),
    );

    // Prepare the encoding, and receive the two buffers.
    let mut image = encoder
        .prepare(width, height, format, compression_quality)
        .expect("Unable to encode to JPEG");

    // Read our input file into the buffers.
    match format {
        onix::DrmFormats::YUYV | onix::DrmFormats::UYVY => {
            let buf = image.out_mut();
            let size = width as usize * height as usize;
            let map = encoder.mmap(buf, 0)?;
            input.read_exact(&mut map.as_mut_slice()[..size])?;
            buf.set_bytesused(0, size);
        }
        onix::DrmFormats::NM12 => {
            let buf = image.out_mut();
            let size = width as usize * height as usize;
            {
                let map = encoder.mmap(buf, 0)?;
                input.read_exact(&mut map.as_mut_slice()[..size])?;
                buf.set_bytesused(0, size);
            }
            {
                let map = encoder.mmap(buf, 1)?;
                input.read_exact(&mut map.as_mut_slice()[..size / 2])?;
                buf.set_bytesused(1, size / 2);
            }
        }
        onix::DrmFormats::YM12 => {
            let buf = image.out_mut();
            let size = width as usize * height as usize;
            {
                let map = encoder.mmap(buf, 0)?;
                input.read_exact(&mut map.as_mut_slice()[..size])?;
                buf.set_bytesused(0, size);
            }
            {
                let map = encoder.mmap(buf, 1)?;
                input.read_exact(&mut map.as_mut_slice()[..size / 4])?;
                buf.set_bytesused(1, size / 4);
            }
            {
                let map = encoder.mmap(buf, 2)?;
                input.read_exact(&mut map.as_mut_slice()[..size / 4])?;
                buf.set_bytesused(2, size / 4);
            }
        }
        _ => panic!("TODO: Add support for format {format}"),
    }

    encoder
        .queue(&mut image)
        .expect("Error while queuing buffers");
    encoder
        .dequeue(&mut image)
        .expect("Error while dequeuing buffers");
    encoder.stop().expect("Error while stopping the encoding");

    {
        let buf = image.cap_mut();
        let map = encoder.mmap(buf, 0)?;
        let mut output = File::create(&args[6])?;
        let slice = &map.as_slice()[..buf.bytesused(0) as usize];
        output.write_all(slice)?;
    }

    Ok(())
}