#linux #v4l2 #video #v4l #ioctl

linux-video

Linux V4L2设备接口

2个版本

0.1.1 2023年8月5日
0.1.0 2023年5月22日

#756 in Unix API

Download history 30/week @ 2024-04-01 19/week @ 2024-05-13 359/week @ 2024-05-20 11/week @ 2024-05-27 35/week @ 2024-06-03 20/week @ 2024-06-10 2/week @ 2024-06-17 10/week @ 2024-06-24

67 每月下载量

MIT 许可证

240KB
6.5K SLoC

Linux V4L2 API for Rust

github crate docs MIT CI

这个crate旨在提供对Linux V4L2 API的无限制访问。

主要设计目标是安全性和开销之间的最佳平衡。实现方式比v4l更接近系统调用。接口类型封装内核类型以避免不必要的复制。

次要目标是提供原始API的全部功能集。

最终,这是我谦虚地尝试正确做事的努力。

Crates

使用示例

枚举设备

use linux_video::Device;

fn main() -> std::io::Result<()> {
    let mut devs = Device::list()?;

    while let Some(path) = devs.fetch_next()? {
        let dev = Device::open(&path)?;

        let caps = dev.capabilities()?;

        println!("path: {}, {caps}", path.display());
    }

    Ok(())
}

获取功能和控制

use linux_video::Device;

fn main() -> std::io::Result<()> {
    let dev = Device::open("/dev/video0")?;

    let caps = dev.capabilities()?;

    println!("Capabilities: {caps}");

    println!("Controls:");
    let mut controls = dev.controls(None);

    while let Some(ctrl) = controls.fetch_next()? {
        println!("  {ctrl}");

        if let Some(mut items) = dev.control_items(&ctrl) {
            while let Some(item) = items.fetch_next()? {
                println!("    {item}");
            }
        }
    }

    Ok(())
}

获取支持格式

use linux_video::{types::BufferType, Device};

fn main() -> std::io::Result<()> {
    let dev = Device::open("/dev/video0")?;

    let caps = dev.capabilities()?;

    for type_ in BufferType::ALL {
        if type_.is_supported(caps.capabilities()) {
            println!("{type_} formats:");
            let mut fmts = dev.formats(type_);

            if let Some(fmt) = fmts.fetch_next()? {
                println!("  {fmt}");

                if type_.content().is_video() {
                    let mut sizes = dev.sizes(fmt.pixel_format());

                    while let Some(size) = sizes.fetch_next()? {
                        println!("    {size}");

                        for size in size.sizes() {
                            println!("      {size}");
                            let mut intervals = dev.intervals(fmt.pixel_format(), size.width(), size.height());

                            while let Some(interval) = intervals.fetch_next()? {
                                println!("        {interval}");
                            }
                        }
                    }
                }
            }
        }
    }

    Ok(())
}

使用控制

use linux_video::{types::*, Device};

fn main() -> std::io::Result<()> {
    let dev = Device::open("/dev/video0")?;

    // Get control from device by identifier
    let contrast_ctrl = dev.control(CtrlId::Contrast)?;

    // Create a value for control
    let mut contrast = Value::from(&contrast_ctrl);

    // Get control value from device
    dev.get_control(&mut contrast)?;

    // Get reference to value data
    let contrast_value = contrast.try_ref::<i32>().unwrap();

    println!("Current contrast: {contrast_value:?}");

    // Set new value by reference
    *contrast.try_mut::<i32>().unwrap() = contrast_value + 10;

    println!("Updated contrast: {:?}", contrast.try_ref::<i32>().unwrap());

    // Set new control value to device
    dev.set_control(&contrast)?;

    Ok(())
}

捕获视频数据

use linux_video::{types::*, Device};

fn main() -> std::io::Result<()> {
    let dev = Device::open("/dev/video0")?;

    // Get current format
    let mut fmt = dev.format(BufferType::VideoOutput)?;
    println!("  {fmt}");

    // Start video capture stream
    let stream = dev.stream::<In, Mmap>(ContentType::Video, 4)?;

    let mut i = 0;
    while let Ok(buffer) = stream.next() {
        let buffer = buffer.lock();
        println!("#{i} {buffer}");

        // Get reference to frame buffer contents
        let _data: &[u8] = buffer.as_ref();

        i += 1;
        if i > 30 {
            break;
        }
    }

    Ok(())
}

输出视频数据

use linux_video::{types::*, Device};

fn main() -> std::io::Result<()> {
    let dev = Device::open("/dev/video0")?;

    // Get current format
    let mut fmt = dev.format(BufferType::VideoOutput)?;
    println!("  {fmt}");

    // Start video output stream
    let stream = dev.stream::<Out, Mmap>(ContentType::Video, 4)?;

    let mut i = 0;
    while let Ok(mut buffer) = stream.next() {
        let mut buffer = buffer.lock();
        println!("#{i} {buffer}");

        // Get reference to frame buffer contents
        let _data: &mut [u8] = buffer.as_mut();

        i += 1;
        if i > 30 {
            break;
        }
    }

    Ok(())
}

依赖关系

~6.5MB
~130K SLoC