Code Monkey home page Code Monkey logo

libv4l-rs's Introduction

Safe video4linux (v4l) bindings

crates.io license Build Status

This crate provides safe bindings to the Video for Linux (V4L) stack. Modern device drivers will usually implement the v4l2 API while older ones may depend on the legacy v4l API. Such legacy devices may be used with this crate by choosing the libv4l feature for this crate.

Goals

This crate shall provide the v4l-sys package to enable full (but unsafe) access to libv4l*. On top of that, there will be a high level, more idiomatic API to use video capture devices in Linux.

There will be simple utility applications to list devices and capture frames. A minimalistic OpenGL/Vulkan viewer to display frames is planned for the future.

Changelog

See CHANGELOG.md

Dependencies

You have the choice between two dependencies (both provided by this crate internally):

  • libv4l-sys

    Link against the libv4l* stack including libv4l1, libv4l2, libv4lconvert. This has the advantage of emulating common capture formats such as RGB3 in userspace through libv4lconvert and more. However, some features like userptr buffers are not supported in libv4l.

  • v4l2-sys

    Use only the Linux kernel provided v4l2 API provided by videodev2.h. You get support for all v4l2 features such as userptr buffers, but may need to do format conversion yourself if you require e.g. RGB/BGR buffers which may not be supported by commodity devices such as webcams.

Enable either the libv4l or the v4l2 backend by choosing the it as feature for this crate.

Usage

Below you can find a quick example usage of this crate. It introduces the basics necessary to do frame capturing from a streaming device (e.g. webcam).

use v4l::buffer::Type;
use v4l::io::mmap::Stream;
use v4l::io::traits::CaptureStream;
use v4l::video::Capture;
use v4l::Device;
use v4l::FourCC;

fn main() {
    // Create a new capture device with a few extra parameters
    let mut dev = Device::new(0).expect("Failed to open device");

    // Let's say we want to explicitly request another format
    let mut fmt = dev.format().expect("Failed to read format");
    fmt.width = 1280;
    fmt.height = 720;
    fmt.fourcc = FourCC::new(b"YUYV");
    let fmt = dev.set_format(&fmt).expect("Failed to write format");

    // The actual format chosen by the device driver may differ from what we
    // requested! Print it out to get an idea of what is actually used now.
    println!("Format in use:\n{}", fmt);

    // Now we'd like to capture some frames!
    // First, we need to create a stream to read buffers from. We choose a
    // mapped buffer stream, which uses mmap to directly access the device
    // frame buffer. No buffers are copied nor allocated, so this is actually
    // a zero-copy operation.

    // To achieve the best possible performance, you may want to use a
    // UserBufferStream instance, but this is not supported on all devices,
    // so we stick to the mapped case for this example.
    // Please refer to the rustdoc docs for a more detailed explanation about
    // buffer transfers.

    // Create the stream, which will internally 'allocate' (as in map) the
    // number of requested buffers for us.
    let mut stream = Stream::with_buffers(&mut dev, Type::VideoCapture, 4)
        .expect("Failed to create buffer stream");

    // At this point, the stream is ready and all buffers are setup.
    // We can now read frames (represented as buffers) by iterating through
    // the stream. Once an error condition occurs, the iterator will return
    // None.
    loop {
        let (buf, meta) = stream.next().unwrap();
        println!(
            "Buffer size: {}, seq: {}, timestamp: {}",
            buf.len(),
            meta.sequence,
            meta.timestamp
        );

        // To process the captured data, you can pass it somewhere else.
        // If you want to modify the data or extend its lifetime, you have to
        // copy it. This is a best-effort tradeoff solution that allows for
        // zero-copy readers while enforcing a full clone of the data for
        // writers.
    }
}

Have a look at the provided examples for more sample applications.

libv4l-rs's People

Contributors

apbr avatar berysaidi avatar cmdrmoozy avatar dependabot[bot] avatar dflemstr avatar dmitrysamoylov avatar donkeyteethux avatar fdlg avatar katyo avatar marijns95 avatar mijoharas avatar nvarner avatar raymanfx avatar roughack avatar rytec-nl avatar sigmasd avatar spebern avatar thezoq2 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

libv4l-rs's Issues

`From<Timestamp> for time::Duration` faulty

I know this should be a pull request but in

impl From<Timestamp> for time::Duration {
    fn from(ts: Timestamp) -> Self {
        time::Duration::new(ts.sec as u64, (ts.usec / 1000) as u32)
    }
}

ts.usec should be multiplied by 1000 and not divided

Publish `Stream::handle()` on crates.io

It seems that Stream::handle() from #63 has been merged to master, but is not available on crates.io. Would it be possible to publish it? We would really appreciate it, as it is exactly what my team and I need for our project :).

Manually starting a CaptureStream results in a single queued buffer

I noticed a low FPS on my camera while using the crate, I think this may be the cause:
If .start() has not been called, calling the .next() method on an MMapStream queues all the buffers.
If .start() has been called it attempts to queue a single buffer.
Manually queuing the buffers at start can then cause an InvalidInput on the first call to .next() as it tries to re-queue the buffer.

Queues only a single buffer

let buffer_count = 4;
let v4l2_device = v4l::Device::with_path("/dev/video0").expect("failed to open video");
let mut stream = mmap::Stream::with_buffers(&v4l2_device, Type::VideoCapture, buffer_count)
    .expect("failed to create stream");
stream.start().expect("failed to start stream");

loop {
    let (_, meta) = stream.next().expect("failed to get image");
    println!("seq: {}, timestamp: {}", meta.sequence, meta.timestamp);
}

Fails with InvalidInput

let buffer_count = 4;
let v4l2_device = v4l::Device::with_path("/dev/video0").expect("failed to open video");
let mut stream = mmap::Stream::with_buffers(&v4l2_device, Type::VideoCapture, buffer_count)
    .expect("failed to create stream");

for index in 0..buffer_count as usize {
    stream.queue(index).expect("failed to queue buffer");
}
stream.start().expect("failed to start stream");

loop {
    let (_, meta) = stream.next().expect("failed to get image"); // <-- fails here
    println!("seq: {}, timestamp: {}", meta.sequence, meta.timestamp);
}

I believe creates expected behavior

let buffer_count = 4;
let v4l2_device = v4l::Device::with_path("/dev/video0").expect("failed to open video");
let mut stream = mmap::Stream::with_buffers(&v4l2_device, Type::VideoCapture, buffer_count)
    .expect("failed to create stream");

for index in 1..buffer_count as usize {
    stream.queue(index).expect("failed to queue buffer");
}
stream.start().expect("failed to start stream");

loop {
    let (_, meta) = stream.next().expect("failed to get image");
    println!("seq: {}, timestamp: {}", meta.sequence, meta.timestamp);
}

please release a new version of v4l2-sys-mit

the current version of v4l2-sys-mit on crates depends on bindgen 0.56, which in turns depends on nom 5.1.2, which triggers cargo's future incompatibility warning:

warning: the following packages contain code that will be rejected by a future version of Rust: nom v5.1.2

the version in the git repository doesn't have this problem.

Cannot set bytesused using meta struct when queueing data.

Hi,

I'm not sure if this is me misunderstanding something but when I fill the mmap output buffer with data I do not see a way to set the bytesUsed. Im streaming mjpeg and depending of the encoding the data size changes. As far as I can see now always the max buffer size is set. I tried using the meta struct to set meta.bytesused but that does not seem to be used in the library. As a workaround i did this in src/io/mmap/stream.rs:

diff --git a/src/io/mmap/stream.rs b/src/io/mmap/stream.rs
index 8a30846..13b21fc 100644
--- a/src/io/mmap/stream.rs
+++ b/src/io/mmap/stream.rs
@@ -190,9 +190,7 @@ impl<'a, 'b> OutputStream<'b> for Stream<'a> {
             v4l2_buf.type_ = self.buf_type as u32;
             v4l2_buf.memory = Memory::Mmap as u32;
             v4l2_buf.index = index as u32;
-            // output settings
-            let bytes = self.arena.get_unchecked_mut(index);
-            v4l2_buf.bytesused = bytes.len() as u32;
+            v4l2_buf.bytesused = self.buf_meta[index].bytesused;
             v4l2_buf.field = self.buf_meta[index].field;

             v4l2::ioctl(

However I do not know if this breaks other usage of the OutputStream. Am I missing something? Or am I on the right track and should my change be expanded to cover all situations.

Thanks in advance!

Panic: v4l-0.14.0/src/control.rs:172:45: called Result::unwrap() on an Err value: ()

Hi, there is a panic happening when using this lib inside an i.MX 8M Plus:

v4l-0.14.0/src/control.rs:172:45: called Result::unwrap() on an Err value: ()

Maybe we are missing part of the specification?

Below is the output of v4l2-ctl --list-ctrls-menus for both devices available:

root@ucm-imx8m-plus:~# v4l2-ctl --list-ctrls-menus --device=/dev/video0

User Controls

                         rotate 0x00980922 (int)    : min=0 max=270 step=90 default=0 value=0 flags=modify-layout
  min_number_of_capture_buffers 0x00980927 (int)    : min=1 max=16 step=1 default=1 value=1 flags=read-only, volatile
   min_number_of_output_buffers 0x00980928 (int)    : min=1 max=16 step=1 default=1 value=1 flags=read-only, volatile
      get_max_roi_region_number 0x009819b2 (int)    : min=0 max=8 step=1 default=0 value=8 flags=read-only, volatile
   vsi_priv_v4l2_roi_params_set 0x009819b3 (unknown): type=164 value=unsupported payload type flags=has-payload
     get_max_ipcm_region_number 0x009819b4 (int)    : min=0 max=2 step=1 default=0 value=2 flags=read-only, volatile
  vsi_priv_v4l2_ipcm_params_set 0x009819b5 (unknown): type=165 value=unsupported payload type flags=has-payload

Codec Controls

                 video_b_frames 0x009909ca (int)    : min=0 max=0 step=1 default=0 value=0 flags=update
                 video_gop_size 0x009909cb (int)    : min=1 max=2147483647 step=1 default=30 value=30
             video_bitrate_mode 0x009909ce (menu)   : min=0 max=1 default=0 value=0 (Variable Bitrate) flags=update
                                0: Variable Bitrate
                                1: Constant Bitrate
                  video_bitrate 0x009909cf (int)    : min=10000 max=288000000 step=1 default=2097152 value=2097152
frame_level_rate_control_enable 0x009909d7 (bool)   : default=0 value=0
           sequence_header_mode 0x009909d8 (menu)   : min=0 max=1 default=1 value=1 (Joined With 1st Frame)
                                0: Separate Buffer
                                1: Joined With 1st Frame
     h264_mb_level_rate_control 0x009909da (bool)   : default=0 value=0
       number_of_mbs_in_a_slice 0x009909dc (int)    : min=1 max=120 step=1 default=1 value=1
      slice_partitioning_method 0x009909dd (menu)   : min=0 max=1 default=0 value=0 (Single)
                                0: Single
                                1: Max Macroblocks
         repeat_sequence_header 0x009909e2 (bool)   : default=1 value=1
                force_key_frame 0x009909e5 (button) : value=0 flags=write-only, execute-on-write
          h264_i_frame_qp_value 0x00990a5e (int)    : min=-1 max=51 step=1 default=30 value=30
          h264_p_frame_qp_value 0x00990a5f (int)    : min=-1 max=51 step=1 default=30 value=30
          h264_b_frame_qp_value 0x00990a60 (int)    : min=-1 max=51 step=1 default=30 value=30
          h264_minimum_qp_value 0x00990a61 (int)    : min=0 max=51 step=1 default=0 value=0
          h264_maximum_qp_value 0x00990a62 (int)    : min=0 max=51 step=1 default=51 value=51
           h264_cpb_buffer_size 0x00990a64 (int)    : min=0 max=288000000 step=1 default=0 value=0
                     h264_level 0x00990a67 (menu)   : min=0 max=15 default=14 value=14 (5)
                                0: 1
                                1: 1b
                                2: 1.1
                                3: 1.2
                                4: 1.3
                                5: 2
                                6: 2.1
                                7: 2.2
                                8: 3
                                9: 3.1
                                10: 3.2
                                11: 4
                                12: 4.1
                                13: 4.2
                                14: 5
                                15: 5.1
                   h264_profile 0x00990a6b (menu)   : min=0 max=16 default=0 value=0 (Baseline)
                                0: Baseline
                                1: Constrained Baseline
                                2: Main
                                3: Extended
                                4: High
                                5: High 10
                                6: High 422
                                7: High 444 Predictive
                                8: High 10 Intra
                                9: High 422 Intra
                                10: High 444 Intra
                                11: CAVLC 444 Intra
                                12: Scalable Baseline
                                13: Scalable High
                                14: Scalable High Intra
                                15: Stereo High
                                16: Multiview High
    h264_chroma_qp_index_offset 0x00990a80 (int)    : min=-12 max=12 step=1 default=0 value=0
           vpx_minimum_qp_value 0x00990afb (int)    : min=0 max=127 step=1 default=0 value=0
           vpx_maximum_qp_value 0x00990afc (int)    : min=0 max=127 step=1 default=127 value=127
           vpx_i_frame_qp_value 0x00990afd (int)    : min=-1 max=127 step=1 default=30 value=30
           vpx_p_frame_qp_value 0x00990afe (int)    : min=-1 max=127 step=1 default=30 value=30
                    vp8_profile 0x00990aff (menu)   : min=0 max=3 default=0 value=0 (0)
                                0: 0
                                1: 1
                                2: 2
                                3: 3
                    vp9_profile 0x00990b00 (menu)   : min=0 max=3 default=0 value=0 (0)
                                0: 0
                                1: 1
                                2: 2
                                3: 3
          hevc_minimum_qp_value 0x00990b58 (int)    : min=0 max=51 step=1 default=0 value=0
          hevc_maximum_qp_value 0x00990b59 (int)    : min=0 max=51 step=1 default=51 value=51
          hevc_i_frame_qp_value 0x00990b5a (int)    : min=-1 max=51 step=1 default=30 value=30
          hevc_p_frame_qp_value 0x00990b5b (int)    : min=-1 max=51 step=1 default=30 value=30
                   hevc_profile 0x00990b67 (menu)   : min=0 max=2 default=0 value=0 (Main)
                                0: Main
                                1: Main Still Picture
                                2: Main 10
                     hevc_level 0x00990b68 (menu)   : min=0 max=8 default=7 value=7 (5)
                                0: 1
                                1: 2
                                2: 2.1
                                3: 3
                                4: 3.1
                                5: 4
                                6: 4.1
                                7: 5
                                8: 5.1
root@ucm-imx8m-plus:~# v4l2-ctl --list-ctrls-menus --device=/dev/video1

User Controls

  min_number_of_capture_buffers 0x00980927 (int)    : min=1 max=16 step=1 default=1 value=1 flags=read-only, volatile
   min_number_of_output_buffers 0x00980928 (int)    : min=1 max=16 step=1 default=1 value=1 flags=read-only, volatile
     frame_disable_reorder_ctrl 0x009819b1 (bool)   : default=0 value=0
             vsi_get_10bit_meta 0x009819b6 (unknown): type=166 value=unsupported payload type flags=read-only, volatile, has-payload
         en_disable_secure_mode 0x009819b7 (bool)   : default=0 value=0

Codec Controls

                   h264_profile 0x00990a6b (menu)   : min=0 max=16 default=0 value=0 (Baseline)
                                0: Baseline
                                1: Constrained Baseline
                                2: Main
                                3: Extended
                                4: High
                                5: High 10
                                6: High 422
                                7: High 444 Predictive
                                8: High 10 Intra
                                9: High 422 Intra
                                10: High 444 Intra
                                11: CAVLC 444 Intra
                                12: Scalable Baseline
                                13: Scalable High
                                14: Scalable High Intra
                                15: Stereo High
                                16: Multiview High
                    vp8_profile 0x00990aff (menu)   : min=0 max=3 default=0 value=0 (0)
                                0: 0
                                1: 1
                                2: 2
                                3: 3
                    vp9_profile 0x00990b00 (menu)   : min=0 max=3 default=0 value=0 (0)
                                0: 0
                                1: 1
                                2: 2
                                3: 3
                   hevc_profile 0x00990b67 (menu)   : min=0 max=2 default=0 value=0 (Main)
                                0: Main
                                1: Main Still Picture
                                2: Main 10

Thanks

Fails to build on Fedora "v4l2_pix_format_union_(anonymous_at_/usr/include/linux/videodev2_h_500_2)" is not a valid Ident

When I try to build v4l2-sys-mit v0.2.0 on Fedora it fails with the error below. I have tried in a clean Fedora container with the same results. Works in a Ubuntu container.

   Compiling v4l2-sys-mit v0.2.0
error: failed to run custom build command for `v4l2-sys-mit v0.2.0`

Caused by:
  process didn't exit successfully: `/webcam/target/debug/build/v4l2-sys-mit-8a538bcaf39af04d/build-script-build` (exit status: 101)
  --- stderr
  thread 'main' panicked at /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-0.56.0/src/ir/context.rs:846:9:
  "v4l2_pix_format_union_(anonymous_at_/usr/include/linux/videodev2_h_500_2)" is not a valid Ident
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

delay

The video delay is very large. Is there a way to solve it. I'm a novice.

Build failed with v4l2 feature

Hi,

I'm trying to include dependency using only v4l2-sys

v4l = { version = "0.5.0", features = [ "v4l2" ] }

but it fails:

fatal error: 'libv4l1.h' file not found

Yeah, I know, I can install it but why does it even need this header if I selected v4l2 feature.

Devices with no capture formats cause panic

  • Trying to enumerate the capture formats on devices that have none causes a panic.

Minimal reproducible example:

extern crate clap;
extern crate v4l;

use clap::{App, Arg};
use v4l::prelude::*;

fn main() {
    let matches = App::new("v4l device")
        .version("0.2")
        .author("Christopher N. Hesse <[email protected]>")
        .about("Video4Linux device example")
        .arg(
            Arg::with_name("device")
                .short("d")
                .long("device")
                .value_name("INDEX or PATH")
                .help("Device node path or index (default: 0)")
                .takes_value(true),
        )
        .get_matches();

    // Determine which device to use
    let mut path: String = matches
        .value_of("device")
        .unwrap_or("/dev/video0")
        .to_string();

    if path.parse::<u64>().is_ok() {
        path = format!("/dev/video{}", path);
    }

    println!("Using device: {}\n", path);

    let device = CaptureDevice::with_path(path).unwrap();

    println!("Formats:");
    
    for fmt in device.enum_formats().unwrap() {
        println!("\t{:#?}", fmt.description);
        println!("\t\tflags: {:#}", fmt.flags);
        println!("\t\tformat: {:#}", fmt.fourcc);
    }
}

Output:

v4l-rs-bug-repro is 📦 v0.1.0 via 🦀 v1.45.2 
❯ RUST_BACKTRACE=1 cargo run -- --device=/dev/video2
   Compiling v4l-rs-bug-repro v0.1.0 (/home/ibiyemi/projects/scratch/v4l-rs-bug-repro)
    Finished dev [unoptimized + debuginfo] target(s) in 0.56s
     Running `target/debug/v4l-rs-bug-repro --device=/dev/video2`
Using device: /dev/video2

Formats:
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Os { code: 22, kind: InvalidInput, message: "Invalid argument" }', src/main.rs:38:16
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/libunwind.rs:86
   1: backtrace::backtrace::trace_unsynchronized
             at /cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.46/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:78
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:59
   4: core::fmt::write
             at src/libcore/fmt/mod.rs:1076
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1537
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:62
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:49
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:198
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:218
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:486
  11: rust_begin_unwind
             at src/libstd/panicking.rs:388
  12: core::panicking::panic_fmt
             at src/libcore/panicking.rs:101
  13: core::option::expect_none_failed
             at src/libcore/option.rs:1272
  14: core::result::Result<T,E>::unwrap
             at /home/ibiyemi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libcore/result.rs:1005
  15: v4l_rs_bug_repro::main
             at src/main.rs:38
  16: std::rt::lang_start::{{closure}}
             at /home/ibiyemi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67
  17: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:52
  18: std::panicking::try::do_call
             at src/libstd/panicking.rs:297
  19: std::panicking::try
             at src/libstd/panicking.rs:274
  20: std::panic::catch_unwind
             at src/libstd/panic.rs:394
  21: std::rt::lang_start_internal
             at src/libstd/rt.rs:51
  22: std::rt::lang_start
             at /home/ibiyemi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src/libstd/rt.rs:67
  23: main
  24: __libc_start_main
  25: _start

Where /dev/video2 is a v4l2loopback device with no capture formats.

Build fail when features=libv4l

Cargo.toml

[package]
name = "v4l2_test"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
v4l = { version = "0.14.0", features = ["libv4l"] }
cargo build -v
       Fresh glob v0.3.1
       Fresh unicode-ident v1.0.12
       Fresh proc-macro2 v1.0.78
       Fresh quote v1.0.35
       Fresh bitflags v2.4.2
       Fresh minimal-lexical v0.2.1
       Fresh linux-raw-sys v0.4.13
       Fresh memchr v2.7.1
       Fresh regex-syntax v0.8.2
       Fresh cfg-if v1.0.0
       Fresh rustix v0.38.30
       Fresh regex-automata v0.4.4
       Fresh nom v7.1.3
       Fresh libloading v0.8.1
       Fresh syn v2.0.48
       Fresh either v1.9.0
       Fresh home v0.5.9
       Fresh clang-sys v1.7.0
       Fresh which v4.4.2
       Fresh prettyplease v0.2.16
       Fresh cexpr v0.6.0
       Fresh regex v1.10.3
       Fresh shlex v1.3.0
       Fresh log v0.4.20
       Fresh lazy_static v1.4.0
       Fresh bitflags v1.3.2
       Fresh lazycell v1.3.0
       Fresh rustc-hash v1.1.0
       Fresh peeking_take_while v0.1.2
       Fresh bindgen v0.65.1
       Fresh libc v0.2.152
       Dirty v4l2-sys-mit v0.3.0: the file `target/debug/build/v4l2-sys-mit-86f56289e69f4dfe/out/v4l2_bindings.rs` has changed (1705912026.817375900s, 817375900ns after last build at 1705912026.000000000s)
   Compiling v4l2-sys-mit v0.3.0
       Dirty v4l-sys v0.3.0: the file `target/debug/build/v4l-sys-2fff74701d7ec040/out/libv4l_bindings.rs` has changed (1705912027.600018400s, 600018400ns after last build at 1705912027.000000000s)
   Compiling v4l-sys v0.3.0
     Running `/home/deehy/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name v4l2_sys_mit --edition=2018 /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l2-sys-mit-0.3.0/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=261 --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=4ad9c7016295d975 -C extra-filename=-4ad9c7016295d975 --out-dir /mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps -L dependency=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps --cap-lints allow`
     Running `/home/deehy/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name v4l_sys --edition=2018 /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-sys-0.3.0/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=261 --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=4a232513af6dbc6e -C extra-filename=-4a232513af6dbc6e --out-dir /mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps -L dependency=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps --cap-lints allow -l v4l1 -l v4l2 -l v4lconvert`
   Compiling v4l v0.14.0
     Running `/home/deehy/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name v4l --edition=2018 /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=261 --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="libv4l"' --cfg 'feature="v4l-sys"' --cfg 'feature="v4l2"' --cfg 'feature="v4l2-sys"' -C metadata=8a2a37446c628d66 -C extra-filename=-8a2a37446c628d66 --out-dir /mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps -L dependency=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps --extern bitflags=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/libbitflags-b7cee2ca4fb438d0.rmeta --extern libc=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/liblibc-a00c9f6be6c2f4ac.rmeta --extern v4l_sys=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/libv4l_sys-4a232513af6dbc6e.rmeta --extern v4l2_sys=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/libv4l2_sys_mit-4ad9c7016295d975.rmeta --cap-lints allow`
error[E0428]: the name `detail` is defined multiple times
  --> /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/v4l2/api.rs:59:1
   |
8  | mod detail {
   | ---------- previous definition of the module `detail` here
...
59 | mod detail {
   | ^^^^^^^^^^ `detail` redefined here
   |
   = note: `detail` must be defined only once in the type namespace of this module

error[E0252]: the name `v4l_sys` is defined multiple times
  --> /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/lib.rs:74:9
   |
71 | pub use v4l_sys;
   |         ------- previous import of the module `v4l_sys` here
...
74 | pub use v4l2_sys as v4l_sys;
   |         ^^^^^^^^^^^^^^^^^^^ `v4l_sys` reimported here
   |
   = note: `v4l_sys` must be defined only once in the type namespace of this module
help: you can use `as` to change the binding name of the import
   |
74 | pub use v4l2_sys as other_v4l_sys;
   |         ~~~~~~~~~~~~~~~~~~~~~~~~~

error[E0425]: cannot find function `v4l2_open` in this scope
  --> /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/v4l2/api.rs:14:9
   |
14 |         v4l2_open(path, flags)
   |         ^^^^^^^^^ not found in this scope
   |
help: consider importing this function
   |
9  +     use v4l_sys::v4l2_open;
   |

error[E0425]: cannot find function `v4l2_close` in this scope
  --> /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/v4l2/api.rs:17:9
   |
17 |         v4l2_close(fd)
   |         ^^^^^^^^^^ not found in this scope
   |
help: consider importing this function
   |
9  +     use v4l_sys::v4l2_close;
   |

error[E0425]: cannot find function `v4l2_ioctl` in this scope
  --> /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/v4l2/api.rs:27:9
   |
27 |         v4l2_ioctl(
   |         ^^^^^^^^^^ not found in this scope
   |
help: consider importing this function
   |
9  +     use v4l_sys::v4l2_ioctl;
   |

error[E0425]: cannot find function `v4l2_mmap` in this scope
  --> /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/v4l2/api.rs:44:9
   |
44 |         v4l2_mmap(
   |         ^^^^^^^^^ not found in this scope
   |
help: consider importing this function
   |
9  +     use v4l_sys::v4l2_mmap;
   |

error[E0425]: cannot find function `v4l2_munmap` in this scope
  --> /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/v4l2/api.rs:54:9
   |
54 |         v4l2_munmap(start, length.try_into().expect("usize -> c size_t failed"))
   |         ^^^^^^^^^^^ not found in this scope
   |
help: consider importing this function
   |
9  +     use v4l_sys::v4l2_munmap;
   |

Some errors have detailed explanations: E0252, E0425, E0428.
For more information about an error, try `rustc --explain E0252`.
error: could not compile `v4l` (lib) due to 7 previous errors

Caused by:
  process didn't exit successfully: `/home/deehy/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/bin/rustc --crate-name v4l --edition=2018 /home/deehy/.cargo/registry/src/index.crates.io-6f17d22bba15001f/v4l-0.14.0/src/lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=261 --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 --cfg 'feature="default"' --cfg 'feature="libv4l"' --cfg 'feature="v4l-sys"' --cfg 'feature="v4l2"' --cfg 'feature="v4l2-sys"' -C metadata=8a2a37446c628d66 -C extra-filename=-8a2a37446c628d66 --out-dir /mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps -L dependency=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps --extern bitflags=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/libbitflags-b7cee2ca4fb438d0.rmeta --extern libc=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/liblibc-a00c9f6be6c2f4ac.rmeta --extern v4l_sys=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/libv4l_sys-4a232513af6dbc6e.rmeta --extern v4l2_sys=/mnt/c/Users/dongf/Source/Rust/v4l2_test/target/debug/deps/libv4l2_sys_mit-4ad9c7016295d975.rmeta --cap-lints allow` (exit status: 1)

Consistently getting 7.5fps using examples

Hey, sorry for the issue.

I seem to be consistently getting about 7.5FPS running any capture examples (stream_forward_mmap, stream_capture_mmap). This happens even when varying the format that I'm using for the device.

I'm wondering if there could be something I'm doing wrong? the format I'm using doesn't even seem to support 7.5 FPS for any of it's formats... which is strange.

Let me know if there's any advice you can give me.

OS Invalid input error

I am trying to execute your example but i am getting this error:

Stream couldn't started: Os { code: 22, kind: InvalidInput, message: "Invalid argument" }

I am using pop-os 22.04 and using droidcam as a camera.

`Format::new` not const fn

I would like to be able to define a nice PREFERRED_FORMAT constant for my project, but mine is ugly because I have to manually list all of the fields. Perhaps v4l::Format::new could be changed to

const fn new(width: u32, height: u32, fourcc: FourCC) -> Self {
    Format {
        width,
        height,
        fourcc,
        field_order: FieldOrder::Any,
        stride: 0,
        size: 0,
        flags: Flags::empty(), // <- used to be Flags::from(0), which isn't const fn
        colorspace: Colorspace::Default,
        quantization: Quantization::Default,
        transfer: TransferFunction::Default,
    }
}

I think this change would make this library much more ergonomic.

v4l2_buffer's bytesuesd field

Hey, I've been checking out different rust libraries for v4l, and I noticed this one doesn't use the bytesused field for v4l2_buffer. I'm trying to send webcam frames over a network, so I'm trying to get the smallest possible frame sizes.
In the standard example:

use v4l::prelude::*;

let mut dev = CaptureDevice::new(0).expect("Failed to open device");

let mut stream =
    MmapStream::with_buffers(&mut dev, 4).expect("Failed to create buffer stream");

loop {
    let frame = stream.next().unwrap();
    println!(
        "Buffer size: {}, seq: {}, timestamp: {}",
       frame.len(),
       frame.meta().seq,
       frame.meta().timestamp
   );
}

The len value is reported as 1843789 on my machine, even though I know that only about 33K of those bytes are used to describe an actual frame. Is there a way in this library to find how many bytes are framedata? I know that rscam is able to give me the real sizes through the v4l2_buffer.bytesused. It seems like that is more intuitive for the user.

Device enumeration bug

I ran into a bug with device enumeration. The following script misplaces part of the index:

fn main() {  
    let device_list = v4l::context::enum_devices();  
    for device in device_list.iter() {  
        let index = device.index();  
        let path = device.path();  
        println!("Device index: {} and path {}", index, path.display());  
    }  
}

Produces the following output:

Device index: 3 and path /dev/video3  
Device index: 2 and path /dev/video2  
Device index: 1 and path /dev/video1  
Device index: 0 and path /dev/video0  
Device index: 11 and path /dev/video11  
Device index: 1 and path /dev/video10

As you see, the last line drops a zero.

Cards 10 and 11 are v4l2-loopbacks created with the following line:
v4l2loopback devices=2 card_label="VirtualCam1,VirtualCam2" exclusive_caps=1,0 video_nr=10,11
Edit: Trying to fix missing line-breaks

Hardware Encoding/Decoding

V4L2 supports hardware encoding and decoding via it's Memory to Memory (M2M) mode. Would it be possible to add support for hardware encoding to libv4l-rs?

This tutorial ( https://lalitm.com/hw-encoding-raspi/ ) seems to lay out how to do it for people how are fluent in C (ie. not myself, not without staring at it for a long time 😅).

Would this fit within the way things are setup in this library? Would it make more sense to try to build HW encode/decode separately on top of something like nix?

Also I'm not sure but this seems related to #15.

License is MIT?

I'm not sure if I'm misunderstanding how these licenses work, but this library is licensed under the MIT license, even though libv4l is LGPL. Is that correct? Does this mean that I can use this library without having to worry about the terms of the LGPL license (such as releasing my source code)?

Missing reset_controls

Its boring to have a for loop that iterates over each control and set_control to set the default value.

Dequeue does not read buffer index in OutputStream

Hi,

I'm using your library to configure a Raspberry Pi as Output device and have run into an issue when trying to stream.
It seems that there is a line missing in src/io/mmap/stream.rs:218 that reads the returned index from the DQBUF ioctl.

In the CaptureStream you do this:

fn dequeue(&mut self) -> io::Result<usize> {
        let mut v4l2_buf: v4l2_buffer;
        unsafe {
            v4l2_buf = mem::zeroed();
            v4l2_buf.type_ = self.buf_type as u32;
            v4l2_buf.memory = Memory::Mmap as u32;
            v4l2::ioctl(
                self.handle.fd(),
                v4l2::vidioc::VIDIOC_DQBUF,
                &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void,
            )?;
        }
        self.arena_index = v4l2_buf.index as usize;

        self.buf_meta[self.arena_index] = Metadata {
            bytesused: v4l2_buf.bytesused,
            flags: v4l2_buf.flags.into(),
            field: v4l2_buf.field,
            timestamp: v4l2_buf.timestamp.into(),
            sequence: v4l2_buf.sequence,
        };

        Ok(self.arena_index)
    }

However in the OutputStream implementation the line self.arena_index = v4l2_buf.index as usize; is missing.
When I added that line all started working.

Please let me know if you need any more info or if I'm doing something wrong.

Thanks!

Build fails with error[E03008]

Hi
I'm using WSL 2 on windows 10 to cross compile eye-rs to Raspberry Pi 3B+ ( so armv7-unknown-linux-gnueabihf). However, when I build an example script it throws this:

error[E0308]: mismatched types
  --> /cargo/registry/src/github.com-1ecc6299db9ec823/v4l-0.7.2/src/v4l2/api.rs:65:52
   |
65 |         libc::mmap(start, length, prot, flags, fd, offset)
   |                                                    ^^^^^^ expected `i32`, found `i64`
   |
help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
   |
65 |         libc::mmap(start, length, prot, flags, fd, offset.try_into().unwrap())
   |                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
   --> /cargo/registry/src/github.com-1ecc6299db9ec823/v4l-0.7.2/src/buffers/userptr_manager.rs:106:38
    |
106 |                 v4l2_buf.m.userptr = buf.as_ptr() as u64;
    |                                      ^^^^^^^^^^^^^^^^^^^ expected `u32`, found `u64`
    |
help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
    |
106 |                 v4l2_buf.m.userptr = (buf.as_ptr() as u64).try_into().unwrap();
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
   --> /cargo/registry/src/github.com-1ecc6299db9ec823/v4l-0.7.2/src/buffers/userptr_manager.rs:147:34
    |
147 |             v4l2_buf.m.userptr = buf.as_ptr() as u64;
    |                                  ^^^^^^^^^^^^^^^^^^^ expected `u32`, found `u64`
    |
help: you can convert an `u64` to `u32` and panic if the converted value wouldn't fit
    |
147 |             v4l2_buf.m.userptr = (buf.as_ptr() as u64).try_into().unwrap();
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
  --> /cargo/registry/src/github.com-1ecc6299db9ec823/v4l-0.7.2/src/timestamp.rs:40:18
   |
40 |             sec: tv.tv_sec,
   |                  ^^^^^^^^^ expected `i64`, found `i32`

error[E0308]: mismatched types
  --> /cargo/registry/src/github.com-1ecc6299db9ec823/v4l-0.7.2/src/timestamp.rs:41:19
   |
41 |             usec: tv.tv_usec,
   |                   ^^^^^^^^^^ expected `i64`, found `i32`

error[E0308]: mismatched types
  --> /cargo/registry/src/github.com-1ecc6299db9ec823/v4l-0.7.2/src/timestamp.rs:53:21
   |
53 |         tv.tv_sec = self.sec;
   |                     ^^^^^^^^ expected `i32`, found `i64`
   |
help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
   |
53 |         tv.tv_sec = self.sec.try_into().unwrap();
   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0308]: mismatched types
  --> /cargo/registry/src/github.com-1ecc6299db9ec823/v4l-0.7.2/src/timestamp.rs:54:22
   |
54 |         tv.tv_usec = self.usec;
   |                      ^^^^^^^^^ expected `i32`, found `i64`
   |
help: you can convert an `i64` to `i32` and panic if the converted value wouldn't fit
   |
54 |         tv.tv_usec = self.usec.try_into().unwrap();
   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 7 previous errors

For more information about this error, try `rustc --explain E0308`.
error: could not compile `v4l`.

I get the same errors even when using 0.10.

Unable to stream to v4l2loopback device using `stream_forward_mmap.rs` example on versions after 67ace34

Using the examples/stream_forward_mmap.rs example I am unable to stream to a v4l2loopback device and then play it with ffplay.

The last working version is the one from commit 67ace34. commit 8586075 and after does not work for me.

$ cargo build --examples && ./target/debug/examples/stream_forward_mmap -d 0 -o 2 -c 100
# output appearing to work

In another terminal:

$ ffplay /dev/video2
ffplay version n4.3.1 Copyright (c) 2003-2020 the FFmpeg developers
  built with gcc 10.2.0 (GCC)
  configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librav1e --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-nvdec --enable-nvenc --enable-shared --enable-version3
  libavutil      56. 51.100 / 56. 51.100
  libavcodec     58. 91.100 / 58. 91.100
  libavformat    58. 45.100 / 58. 45.100
  libavdevice    58. 10.100 / 58. 10.100
  libavfilter     7. 85.100 /  7. 85.100
  libswscale      5.  7.100 /  5.  7.100
  libswresample   3.  7.100 /  3.  7.100
  libpostproc    55.  7.100 / 55.  7.100
    nan    :  0.000 fd=   0 aq=    0KB vq=    0KB sq=    0B f=0/0   

Using the (now deprecated) example forward_video and this patch #22 worked fine.

Unable to build for RISC-V

error: failed to run custom build command for `v4l2-sys-mit v0.2.0`

Caused by:
  process didn't exit successfully: `/home/whqee/devel/rust/hello_v4l2/target/release/build/v4l2-sys-mit-e9452ce4c76c1710/build-script-build` (exit status: 101)
  --- stderr
  error: unknown target triple 'riscv64gc-unknown-linux-gnu', please use -triple or -arch
  thread 'main' panicked at 'libclang error; possible causes include:
  - Invalid flag syntax
  - Unrecognized flags
  - Invalid flag arguments
  - File I/O errors
  - Host vs. target architecture mismatch
  If you encounter an error missing from this list, please file an issue or a PR!', /home/whqee/.cargo/registry/src/github.com-1ecc6299db9ec823/bindgen-0.56.0/src/ir/context.rs:531:15
  stack backtrace:
     0: rust_begin_unwind
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/std/src/panicking.rs:575:5
     1: core::panicking::panic_fmt
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:64:14
     2: core::panicking::panic_display
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:147:5
     3: core::panicking::panic_str
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/panicking.rs:131:5
     4: core::option::expect_failed
               at /rustc/9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0/library/core/src/option.rs:1924:5
     5: core::option::Option<T>::expect
     6: bindgen::ir::context::BindgenContext::new
     7: bindgen::Bindings::generate
     8: bindgen::Builder::generate
     9: build_script_build::main
    10: core::ops::function::FnOnce::call_once
  note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

`stream.next()` blocks when camera unplugged

When I start a stream and unplug the camera, the stream.next() call blocks forever. It would be nice if I could set a timeout. Perhaps I'm missing something, but I can't see a way to do that in this library.
It seems like there's a poll function that's made for this.
Perhaps this should be the standard behavior - I think most users would expect an error when a camera is unplugged.

Accessing to Handle for Streams

I trying to implement async versions of CaptureStream/OutputStream traits (i.e. with next function which returns Future).
I see that Stream types internally has reference to Handle but this ref hasn't accessible via public interface.
Also I see that Device type has function handle which returns reference to internal Handle.
How about adding similar functions to our stream types too?
I don't sure may we add it to Stream trait directly.
In any case I need a way to get file descriptors from streams.
Any ideas?

Strings contain trailing zeroes

Hi!

Those strings coming from unused bytes of fixed size arrays are converted to UTF-8 along with trailing zeros. I think this zeros can be trimmed safely.

let caps = device_info.query_caps()?;
println!("caps = {:#?}", caps);
caps = Capabilities {
    driver: "uvcvideo\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}",
    card: "A4 TECH USB2.0 PC Camera E: A4 \u{0}",
    bus: "usb-0000:00:14.0-3.2\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}",
    version: (
        5,
        3,
        18,
    ),
    capabilities: VIDEO_CAPTURE | EXT_PIX_FORMAT | STREAMING,
}

Getting zeroes in capture buffers

This is less of an issue but more of me seeking help. I'm trying to capture frames with Queue from next branch and getting all frame buffers set to zero. I've checked ffmpeg and it could capture frames as expected.

This is what I'm doing:

let afd = AsyncFd::with_interest(Arc::clone(&handle), Interest::READABLE)?;
        let mut queue =
            Queue::with_mmap(Arc::clone(&handle), Type::VideoCapture, Self::BUFFER_COUNT)?;

        for i in 0..queue.len() {
            let metadata = queue.query_buf(i as u32).unwrap();
            let buf = queue.index_mut(i);
            buf.fill(0);
            queue.enqueue(&metadata).unwrap();
        }

        let queue = queue.start_stream()?;

.............................

loop {
            let mut guard = self.device_poll_handler.ready(Interest::READABLE).await?;
            // remove a buffer from the drivers' outgoing queue
            let metadata @ Metadata { sequence: _, timestamp: _, flags: _, bytesused: _, .. } =
                match self.queue.dequeue() {
                    Ok(buf) => buf,
                    Err(ref err) if err.kind() == ErrorKind::WouldBlock => {
                        guard.clear_ready();
                        continue;
                    }
                    Err(err) => return Err(err),
                };

            let buffer = self.queue.index(metadata.index as _);
                info!(
                    "Frame#{}(index {}/pointer: {:?}): {:?}`",
                    metadata.sequence,
                    metadata.index,
                    buffer.as_ptr(),
                    &buffer[..40],
                );

            let result = Ok(VideoFrame {
                metadata,
                buffer: Bytes::copy_from_slice(&buffer[..metadata.bytesused as _]),
                // queue: &self.queue,
                ntp_timestamp: SystemTime::now(), // .duration_since(self.shift + Duration::from(timestamp))
                                                  // .unwrap().as_millis().into(),
            });
            self.queue.enqueue(&metadata).unwrap();
            return result;
        }

Here what I'm getting in output:

2023-11-07T16:15:17.180491Z  INFO lib::mediaengine: Opened video device 1 with format:
 width          : 1920
height         : 1080
fourcc         : H264
field          : progressive
stride         : 0
size           : 778240
colorspace     : sRGB
quantization   : default
transfer       : default transfer function

 and Parameters:
capabilities : TIME_PER_FRAME
modes        : (empty)
interval     : 30/300 [s]

2023-11-07T16:15:17.883648Z  INFO lib::mediaengine::video: Frame#10090(index 2/pointer: 0x7f8e9fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:17.983515Z  INFO lib::mediaengine::video: Frame#10091(index 3/pointer: 0x7f8d5fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.083395Z  INFO lib::mediaengine::video: Frame#10092(index 4/pointer: 0x7f8c1fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.183530Z  INFO lib::mediaengine::video: Frame#10093(index 5/pointer: 0x7f7ec00000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.283405Z  INFO lib::mediaengine::video: Frame#10094(index 6/pointer: 0x7f7d800000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.384713Z  INFO lib::mediaengine::video: Frame#10095(index 7/pointer: 0x7f7c400000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.486195Z  INFO lib::mediaengine::video: Frame#10096(index 0/pointer: 0x7f96298000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.584187Z  INFO lib::mediaengine::video: Frame#10097(index 1/pointer: 0x7f94e98000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.683948Z  INFO lib::mediaengine::video: Frame#10098(index 2/pointer: 0x7f8e9fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.783278Z  INFO lib::mediaengine::video: Frame#10099(index 3/pointer: 0x7f8d5fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.883003Z  INFO lib::mediaengine::video: Frame#10100(index 4/pointer: 0x7f8c1fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:18.983262Z  INFO lib::mediaengine::video: Frame#10101(index 5/pointer: 0x7f7ec00000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.083439Z  INFO lib::mediaengine::video: Frame#10102(index 6/pointer: 0x7f7d800000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.183494Z  INFO lib::mediaengine::video: Frame#10103(index 7/pointer: 0x7f7c400000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.287652Z  INFO lib::mediaengine::video: Frame#10104(index 0/pointer: 0x7f96298000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.384111Z  INFO lib::mediaengine::video: Frame#10105(index 1/pointer: 0x7f94e98000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.483396Z  INFO lib::mediaengine::video: Frame#10106(index 2/pointer: 0x7f8e9fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.583426Z  INFO lib::mediaengine::video: Frame#10107(index 3/pointer: 0x7f8d5fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.683899Z  INFO lib::mediaengine::video: Frame#10108(index 4/pointer: 0x7f8c1fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.783537Z  INFO lib::mediaengine::video: Frame#10109(index 5/pointer: 0x7f7ec00000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.883382Z  INFO lib::mediaengine::video: Frame#10110(index 6/pointer: 0x7f7d800000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:19.983671Z  INFO lib::mediaengine::video: Frame#10111(index 7/pointer: 0x7f7c400000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:20.083790Z  INFO lib::mediaengine::video: Frame#10112(index 0/pointer: 0x7f96298000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:20.183754Z  INFO lib::mediaengine::video: Frame#10113(index 1/pointer: 0x7f94e98000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:20.283560Z  INFO lib::mediaengine::video: Frame#10114(index 2/pointer: 0x7f8e9fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:20.383660Z  INFO lib::mediaengine::video: Frame#10115(index 3/pointer: 0x7f8d5fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`
2023-11-07T16:15:20.483666Z  INFO lib::mediaengine::video: Frame#10116(index 4/pointer: 0x7f8c1fa000): [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]`

I'm sure I'm doing something wrong but maybe someone can help me anyway?

Unhelpful error message when compiling with default features off

If v4l crate expects user to enable either libv4l or v4l2 features then there should probably be some #[cfg(...)] comile_error!() stating this if none or both of the features are enabled.

Now I get something like:

error[E0432]: unresolved import `crate::v4l_sys`
 --> /home/vi/.cargo/registry/src/-3d9d141e372ea94e/v4l-0.14.0/src/v4l2/videodev.rs:1:12
  |
1 | use crate::v4l_sys::v4l2_ext_control;
  |            ^^^^^^^ could not find `v4l_sys` in the crate root

(many similar compiler errors)

Maintenance

Hi there,

I wanted to ask if this crate is still maintained and if you do not have the time to maintain it anymore could add a contributor who can review and merge the pull requests and publish new versions on crates.io.

This crate is really useful and in my opinion the best wrapper around v4l for rust currently.

I'd be happy to help here!

Crash on mem::zeroed

I'm trying to run a stream capture example on arm64 device and getting this type of error:

The application panicked (crashed).
Message:  attempted to zero-initialize type `buffer::Metadata`, which is invalid
Location: library/core/src/panicking.rs:126

  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ BACKTRACE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
                                ⋮ 7 frames hidden ⋮
   8: core::panicking::panic_nounwind_fmt::hef625da4d1887edc
      at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/panicking.rs:96
   9: core::panicking::panic_nounwind::h39541cbd5a72f09a
      at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/panicking.rs:126
  10: core::mem::zeroed::hffae7c8a55c7cecb
      at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/mem/mod.rs:653
  11: v4l::io::mmap::stream::Stream::with_buffers::h57158218617a1fba
      at /home/noah/.cargo/git/checkouts/libv4l-rs-917e1f4ffd90b94a/9844291/src/io/mmap/stream.rs:55
  12: lib::mediaengine::MediaEngine::process_video::{{closure}}::h36fd47a510f39921

As if it is enclosed in unsafe this may be somehow expected, I guess, but how could I overcome this?
Or is this me lacking some compiler settings?

Texture data size mismatch when running `glium` example.

Hey, I'm not digging in to the example, so I'm not sure if it's something to worry about, but running the glium example I get the following error:

Using device: /dev/video0

Active format:
width          : 640
height         : 480
fourcc         : YUYV
field          : progressive
stride         : 1280
size           : 614400
colorspace     : sRGB
quantization   : default
transfer       : default transfer function

Active parameters:
capabilities : TIME_PER_FRAME
modes        : (empty)
interval     : 1/30 [s]

thread 'main' panicked at 'Texture data size mismatch', /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/glium-0.27.0/src/texture/any.rs:148:13
stack backtrace:
   0: std::panicking::begin_panic
             at /home/michael/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/panicking.rs:519:12
   1: glium::texture::any::new_texture
             at /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/glium-0.27.0/src/texture/any.rs:148:13
   2: glium::texture::texture2d::Texture2d::new_impl
             at ./target/debug/build/glium-aab36beb853d0737/out/textures.rs:2899:95
   3: glium::texture::texture2d::Texture2d::new
             at ./target/debug/build/glium-aab36beb853d0737/out/textures.rs:2862:21
   4: glium::main::{{closure}}
             at ./examples/glium.rs:168:30
   5: winit::platform_impl::platform::sticky_exit_callback
             at /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.22.2/src/platform_impl/linux/mod.rs:698:5
   6: winit::platform_impl::platform::x11::EventLoop<T>::run_return
             at /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.22.2/src/platform_impl/linux/x11/mod.rs:274:13
   7: winit::platform_impl::platform::x11::EventLoop<T>::run
             at /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.22.2/src/platform_impl/linux/x11/mod.rs:390:9
   8: winit::platform_impl::platform::EventLoop<T>::run
             at /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.22.2/src/platform_impl/linux/mod.rs:645:35
   9: winit::event_loop::EventLoop<T>::run
             at /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/winit-0.22.2/src/event_loop.rs:149:9
  10: glium::main
             at ./examples/glium.rs:161:5
  11: core::ops::function::FnOnce::call_once
             at /home/michael/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ops/function.rs:227:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

Thought I'd just let you know.

Failed to start media pipeline

First, thanks for the great work on this crate.

I'm running into a bit of a strange issue where my video stream is refusing to start. My settings for the device:

let mut fmt = dev.format()?;
fmt.fourcc = FourCC::new(b"BA81");
fmt.width = 640;
fmt.height = 480;
fmt.stride = 640;
fmt.size = 640 * 480;
fmt.field_order = FieldOrder::Progressive;
fmt.colorspace = Colorspace::RAW;
dev.set_format(&fmt)?;

// Using an mmap stream:
mmap::Stream::with_buffers(&dev, Type::VideoCapture, 8)

When I check syslog, I see a bunch of the following:

Jul 23 00:08:38 pi3 kernel: [33785.523627] unicam 3f801000.csi: Wrong width or height 640x480 (remote pad set to 3280x2464)
Jul 23 00:08:38 pi3 kernel: [33785.523643] unicam 3f801000.csi: Failed to start media pipeline: -22

Versions and such:

# v4l-utils package
1.20.0-2

# uname -a
Linux pi3 5.15.32-v8+ #1538 SMP PREEMPT Thu Mar 31 19:40:39 BST 2022 aarch64 GNU/Linux

The main question I have is: how can I configure that remote pad setting? Seems to be part of the issue here.

Problems I encountered using this crate.

Hello @raymanfx ,

first of, I want to thank you for creating this crate. Unfortunately I'm wondering about some decisions that you did in this crate.

You implemented an mmap interface where you can queue multiple buffers, but in the way you are using it
images are always only generated once you call io::mmap::stream::dequeue so you will never have images queued up ready to use.
For that to work you need to open the filedescriptor as NONBLOCK.

Also with your current iteration I'm not sure why queue and dequeue are still public as you cannot do anything with them.
You can dequeue a new image, you get a buffer_index but you cannot get the image from this index, as the arena is private
and you don't have any get and get_meta functions anymore. We are currently using it in this way: We run an analysis on an
image, get the next image and skip all images that were asynchronously taken in the meantime (see NONBLOCK above) until we reach the newest image that is available at this time, without waiting for a new one. This isn't possible with the use of the next method. As you will always wait for a new image, regardless of how long it waits. For this to work you also need a method to poll the filedescriptor to you
know if there are images waiting currently.

For the changes we made to do that, you can look at our fork here: https://github.com/HULKs/libv4l-rs/tree/hulksChanges

If you want to, we can come to an understanding on how to integrate these changes properly into your crate. It would be nicer
to have one good v4l wrapper instead of forking and maintaining a second one.

Have a nice day!

Unable to stream to v4l2 loopback device using stream_forward_mmap example

I cloned master, and ran cargo build --examples, then ran ./target/debug/examples/stream_forward_mmap -d 4 -o 0 (and yes, my loopback is /dev/video/0 and my USB webcam is /dev/video/4 - i double checked).

The result is a panic with a message about slice lengths not matching:
thread 'main' panicked at 'source slice length (460800) does not match destination slice length (1228800)', /home/filip/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/mod.rs:2775:13

Complete output in enclosed text file.

Any idea what's wrong? I'm a bit of a beginner at both Rust and V4l2

output.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.