From 8a9ad327bc040f99df5088e171dd7f7f76136477 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 21 Sep 2026 13:56:54 -0700 Subject: [PATCH 1/8] quest(main): start capture-v4l-bindings Co-Authored-By: Claude Opus 5 --- quest/main/README.md | 1 + quest/{next => main}/capture-v4l-bindings.md | 0 quest/next/README.md | 1 - quest/next/cli-packaging.md | 2 +- 4 files changed, 2 insertions(+), 2 deletions(-) rename quest/{next => main}/capture-v4l-bindings.md (100%) diff --git a/quest/main/README.md b/quest/main/README.md index 00d4d20eb3..99df975d9e 100644 --- a/quest/main/README.md +++ b/quest/main/README.md @@ -92,6 +92,7 @@ do not add another media abstraction or a renderer crate during stabilization. - [Origin failover machine](/quest/main/origin-failover-machine.md) - a front's source selection and track splicing become a pure step function with a runtime-free test per transition +- [Capture without V4L2 bindgen](/quest/main/capture-v4l-bindings.md) - moq-video `capture` and `v4l2` build on Linux without libclang or kernel headers, via an in-tree `v4l` fork with checked-in bindings ## Related diff --git a/quest/next/capture-v4l-bindings.md b/quest/main/capture-v4l-bindings.md similarity index 100% rename from quest/next/capture-v4l-bindings.md rename to quest/main/capture-v4l-bindings.md diff --git a/quest/next/README.md b/quest/next/README.md index 80826e516a..7d3c58e3f1 100644 --- a/quest/next/README.md +++ b/quest/next/README.md @@ -147,7 +147,6 @@ transport, benchmark tooling); worktrees isolate commits, not semantics. - [`moq relay`](/quest/next/moq-relay-subcommand.md) - the relay runs under a `moq` verb with its own flags and TOML, while `moq-relay` stays a minimal binary - [`moq --listen` admission](/quest/next/cli-serve.md) - a listening CLI session is authenticated, scoped, counted, and drained like a relay's instead of accepting everything - [#709](/quest/next/709-automatic-letsencrypt-support.md) - the relay provisions and renews its own ACME certificate through rustls-acme over TLS-ALPN-01, persisted on disk -- [Capture without V4L2 bindgen](/quest/next/capture-v4l-bindings.md) - moq-video capture builds on Linux without libclang or kernel headers - [Audio capture without ALSA link](/quest/next/capture-alsa-link.md) - moq-audio capture and playback build on Linux without linking libasound - [Ship capture and playback](/quest/next/cli-packaging.md) - a released moq binary can capture and play, which no distribution currently enables - [io_uring flow control](/quest/next/uring-flow-control-windows.md) - the relay's io_uring workers honor the QUIC flow-control windows instead of refusing them diff --git a/quest/next/cli-packaging.md b/quest/next/cli-packaging.md index 52972b02c2..73faeaceb9 100644 --- a/quest/next/cli-packaging.md +++ b/quest/next/cli-packaging.md @@ -31,5 +31,5 @@ then fails to open a device is the same gap one layer down. ## Required -- [Capture without V4L2 bindgen](/quest/next/capture-v4l-bindings.md) - the camera path must build without libclang before every distribution can ship it +- [Capture without V4L2 bindgen](/quest/main/capture-v4l-bindings.md) - the camera path must build without libclang before every distribution can ship it - [Audio capture without runtime system libraries](/quest/next/capture-alsa-link.md) - the microphone path must start without system audio libraries before every distribution can ship it From 814ffaaea042509c8ce1101ebbb83b21559e3d96 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 21 Sep 2026 14:31:54 -0700 Subject: [PATCH 2/8] feat(video): fork v4l in-tree with checked-in V4L2 bindings moq-video's `capture` and `v4l2` features pulled the `v4l` crate, whose sys dependency runs bindgen over the kernel's videodev2.h at build time, so every Linux build host needed libclang and the kernel headers. That was the one cost that kept `cargo install moq-cli` from ever shipping capture by default. rs/moq-v4l forks `v4l` 0.14 with the bindings generated once and checked in, the way rs/moq-nvenc forks its SDK. The output is arch-independent (no layout tests, fixed-width integers, `timeval`/`timespec` from libc) and the regeneration script sits beside it. Only the raw-ioctl backend survives; nothing links at build time, and the crate is an empty stub off Linux. The fork also completes the VIDIOC request table, so moq-video's hand-built DQEVENT/SUBSCRIBE_EVENT/G_SELECTION/DECODER_CMD codes and their test move into the crate. Co-Authored-By: Claude Opus 5 --- Cargo.lock | 86 +- Cargo.toml | 4 + doc/bin/cli.md | 4 +- doc/lib/rs/moq-video.md | 5 +- nix/overlay.nix | 8 +- quest/future/video-vaapi.md | 5 +- quest/main/README.md | 1 - quest/main/capture-v4l-bindings.md | 28 - quest/next/cli-packaging.md | 14 +- rs/moq-cli/Cargo.toml | 13 +- rs/moq-ffi/Cargo.toml | 4 +- rs/moq-transcode/Cargo.toml | 7 +- rs/moq-v4l/Cargo.toml | 17 + rs/moq-v4l/LICENSE | 9 + rs/moq-v4l/README.md | 21 + rs/moq-v4l/src/buffer.rs | 115 + rs/moq-v4l/src/capability.rs | 120 + rs/moq-v4l/src/context.rs | 97 + rs/moq-v4l/src/control.rs | 253 ++ rs/moq-v4l/src/device.rs | 397 +++ rs/moq-v4l/src/format/colorspace.rs | 77 + rs/moq-v4l/src/format/description.rs | 70 + rs/moq-v4l/src/format/field.rs | 65 + rs/moq-v4l/src/format/fourcc.rs | 67 + rs/moq-v4l/src/format/mod.rs | 157 + rs/moq-v4l/src/format/quantization.rs | 40 + rs/moq-v4l/src/format/transfer.rs | 58 + rs/moq-v4l/src/fraction.rs | 55 + rs/moq-v4l/src/frameinterval.rs | 95 + rs/moq-v4l/src/framesize.rs | 141 + rs/moq-v4l/src/io/mmap/arena.rs | 141 + rs/moq-v4l/src/io/mmap/mod.rs | 4 + rs/moq-v4l/src/io/mmap/stream.rs | 285 ++ rs/moq-v4l/src/io/mod.rs | 4 + rs/moq-v4l/src/io/traits.rs | 38 + rs/moq-v4l/src/io/userptr/arena.rs | 119 + rs/moq-v4l/src/io/userptr/mod.rs | 4 + rs/moq-v4l/src/io/userptr/stream.rs | 214 ++ rs/moq-v4l/src/lib.rs | 102 + rs/moq-v4l/src/memory.rs | 23 + rs/moq-v4l/src/parameters.rs | 28 + rs/moq-v4l/src/sys/bindgen.sh | 15 + rs/moq-v4l/src/sys/mod.rs | 10 + rs/moq-v4l/src/sys/videodev2.rs | 3556 ++++++++++++++++++++ rs/moq-v4l/src/timestamp.rs | 66 + rs/moq-v4l/src/v4l2/api.rs | 258 ++ rs/moq-v4l/src/v4l2/mod.rs | 5 + rs/moq-v4l/src/v4l2/videodev.rs | 17 + rs/moq-v4l/src/v4l2/vidioc.rs | 171 + rs/moq-v4l/src/video/capture/mod.rs | 57 + rs/moq-v4l/src/video/capture/parameters.rs | 87 + rs/moq-v4l/src/video/macros.rs | 163 + rs/moq-v4l/src/video/mod.rs | 9 + rs/moq-v4l/src/video/output/mod.rs | 57 + rs/moq-v4l/src/video/output/parameters.rs | 55 + rs/moq-v4l/src/video/traits.rs | 89 + rs/moq-video/Cargo.toml | 46 +- rs/moq-video/src/capture/v4l2.rs | 62 +- rs/moq-video/src/decode/backend/v4l2.rs | 2 +- rs/moq-video/src/encode/backend/v4l2.rs | 4 +- rs/moq-video/src/v4l2.rs | 73 +- 61 files changed, 7545 insertions(+), 252 deletions(-) delete mode 100644 quest/main/capture-v4l-bindings.md create mode 100644 rs/moq-v4l/Cargo.toml create mode 100644 rs/moq-v4l/LICENSE create mode 100644 rs/moq-v4l/README.md create mode 100644 rs/moq-v4l/src/buffer.rs create mode 100644 rs/moq-v4l/src/capability.rs create mode 100644 rs/moq-v4l/src/context.rs create mode 100644 rs/moq-v4l/src/control.rs create mode 100644 rs/moq-v4l/src/device.rs create mode 100644 rs/moq-v4l/src/format/colorspace.rs create mode 100644 rs/moq-v4l/src/format/description.rs create mode 100644 rs/moq-v4l/src/format/field.rs create mode 100644 rs/moq-v4l/src/format/fourcc.rs create mode 100644 rs/moq-v4l/src/format/mod.rs create mode 100644 rs/moq-v4l/src/format/quantization.rs create mode 100644 rs/moq-v4l/src/format/transfer.rs create mode 100644 rs/moq-v4l/src/fraction.rs create mode 100644 rs/moq-v4l/src/frameinterval.rs create mode 100644 rs/moq-v4l/src/framesize.rs create mode 100644 rs/moq-v4l/src/io/mmap/arena.rs create mode 100644 rs/moq-v4l/src/io/mmap/mod.rs create mode 100644 rs/moq-v4l/src/io/mmap/stream.rs create mode 100644 rs/moq-v4l/src/io/mod.rs create mode 100644 rs/moq-v4l/src/io/traits.rs create mode 100644 rs/moq-v4l/src/io/userptr/arena.rs create mode 100644 rs/moq-v4l/src/io/userptr/mod.rs create mode 100644 rs/moq-v4l/src/io/userptr/stream.rs create mode 100644 rs/moq-v4l/src/lib.rs create mode 100644 rs/moq-v4l/src/memory.rs create mode 100644 rs/moq-v4l/src/parameters.rs create mode 100755 rs/moq-v4l/src/sys/bindgen.sh create mode 100644 rs/moq-v4l/src/sys/mod.rs create mode 100644 rs/moq-v4l/src/sys/videodev2.rs create mode 100644 rs/moq-v4l/src/timestamp.rs create mode 100644 rs/moq-v4l/src/v4l2/api.rs create mode 100644 rs/moq-v4l/src/v4l2/mod.rs create mode 100644 rs/moq-v4l/src/v4l2/videodev.rs create mode 100644 rs/moq-v4l/src/v4l2/vidioc.rs create mode 100644 rs/moq-v4l/src/video/capture/mod.rs create mode 100644 rs/moq-v4l/src/video/capture/parameters.rs create mode 100644 rs/moq-v4l/src/video/macros.rs create mode 100644 rs/moq-v4l/src/video/mod.rs create mode 100644 rs/moq-v4l/src/video/output/mod.rs create mode 100644 rs/moq-v4l/src/video/output/parameters.rs create mode 100644 rs/moq-v4l/src/video/traits.rs diff --git a/Cargo.lock b/Cargo.lock index ea5c3a578c..c97f2983b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -677,29 +677,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.65.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "log", - "peeking_take_while", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex 1.3.0", - "syn 2.0.119", - "which", -] - [[package]] name = "bindgen" version = "0.70.1" @@ -3028,15 +3005,6 @@ dependencies = [ "digest 0.11.3", ] -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "http" version = "1.5.0" @@ -3946,12 +3914,6 @@ dependencies = [ "spin 0.9.9", ] -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.189" @@ -4962,6 +4924,14 @@ dependencies = [ "web-transport-trait", ] +[[package]] +name = "moq-v4l" +version = "0.0.1" +dependencies = [ + "bitflags 2.13.1", + "libc", +] + [[package]] name = "moq-vaapi" version = "0.0.4" @@ -4999,6 +4969,7 @@ dependencies = [ "moq-mux", "moq-net", "moq-nvenc", + "moq-v4l", "moq-vaapi", "ndk", "objc2 0.6.4", @@ -5019,7 +4990,6 @@ dependencies = [ "tokio", "tracing", "tracing-test", - "v4l", "wgpu", "windows", "x11rb 0.14.0", @@ -6397,12 +6367,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "pem" version = "3.0.6" @@ -9509,26 +9473,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "v4l" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fbfea44a46799d62c55323f3c55d06df722fbe577851d848d328a1041c3403" -dependencies = [ - "bitflags 1.3.2", - "libc", - "v4l2-sys-mit", -] - -[[package]] -name = "v4l2-sys-mit" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6779878362b9bacadc7893eac76abe69612e8837ef746573c4a5239daf11990b" -dependencies = [ - "bindgen 0.65.1", -] - [[package]] name = "valuable" version = "0.1.1" @@ -10141,18 +10085,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "wide" version = "1.6.1" diff --git a/Cargo.toml b/Cargo.toml index dd18764035..8476ae0de1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ members = [ "rs/moq-tokio", "rs/moq-transcode", "rs/moq-uring", + "rs/moq-v4l", "rs/moq-video", "rs/moq-wasm", "rs/quest", @@ -72,6 +73,7 @@ default-members = [ "rs/moq-tokio", "rs/moq-transcode", "rs/moq-uring", + "rs/moq-v4l", "rs/moq-video", # "rs/moq-wasm", # wasm32-unknown-unknown target only "rs/quest", @@ -100,6 +102,7 @@ aws-lc-rs = "1" axum = { version = "0.8", features = ["tokio"] } axum-server = { version = "0.8", features = ["tls-rustls"] } base64 = "0.23" +bitflags = "2" block2 = "0.6.2" bytes = "1" clap = { version = "4", features = ["derive"] } @@ -147,6 +150,7 @@ moq-noq-udp = "1.3" # driver at runtime. Compiles on any platform (macOS included) but only actually # used by moq-video on Linux. moq-nvenc = { version = "0.0.5", path = "rs/moq-nvenc" } +moq-v4l = { version = "0.0.1", path = "rs/moq-v4l" } moq-pattern = { version = "0.1.0", path = "rs/moq-pattern" } moq-relay = { version = "0.14.18", path = "rs/moq-relay", default-features = false } moq-rtc = { version = "0.2.11", path = "rs/moq-rtc" } diff --git a/doc/bin/cli.md b/doc/bin/cli.md index 70f1493158..e626cfb3a2 100644 --- a/doc/bin/cli.md +++ b/doc/bin/cli.md @@ -123,8 +123,8 @@ M2M) with a built-in H.264 software fallback; audio is Opus. The camera is opened only while someone is watching, and `--bitrate` is the opening ceiling. Backends with live bitrate control lower it to fit the connection's bandwidth estimate. `moq devices` prints every source -id. Requires the `capture` feature; on Linux that needs libclang, V4L2, and -ALSA headers, and `--display` also needs the `pipewire` feature (links +id. Requires the `capture` feature; on Linux that needs the ALSA headers for +the microphone, and `--display` also needs the `pipewire` feature (links libpipewire). ## Transcode diff --git a/doc/lib/rs/moq-video.md b/doc/lib/rs/moq-video.md index e396500b34..6d2d2c7fcf 100644 --- a/doc/lib/rs/moq-video.md +++ b/doc/lib/rs/moq-video.md @@ -55,9 +55,10 @@ while let Some(frame) = video.read().await? { ```bash cargo add moq-video # nvidia, mediacodec, openh264 on by default -cargo add moq-video --features capture # camera + screen capture (Linux: bindgen needs libclang + V4L2 headers) +cargo add moq-video --features capture # camera + screen capture, no system build deps cargo add moq-video --features render # wgpu rendering -cargo add moq-video --features vaapi,v4l2 # Linux VAAPI + V4L2 M2M codecs (bindgen needs libclang) +cargo add moq-video --features v4l2 # Linux V4L2 M2M codecs, no system build deps +cargo add moq-video --features vaapi # Linux VAAPI codecs (bindgen needs libclang) cargo add moq-video --features pipewire # Wayland screen capture (links libpipewire) cargo add moq-video --no-default-features --features openh264 # software H.264 only cargo add moq-video --no-default-features --features nvidia # Linux NVIDIA only, no C++ or wgpu diff --git a/nix/overlay.nix b/nix/overlay.nix index bf09d5cc59..29fd04cb62 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -145,10 +145,10 @@ let doCheck = false; nativeBuildInputs = with final; [ pkg-config - # libmoq is the only nix-built package that pulls moq-video, and on Linux - # that brings v4l -> v4l2-sys-mit, whose build.rs runs bindgen over - # . Sets LIBCLANG_PATH + BINDGEN_EXTRA_CLANG_ARGS so it - # finds libclang and the libc headers, same as the devShell in flake.nix. + # libmoq is the only nix-built package that pulls moq-video, and its `vaapi` + # feature brings moq-vaapi, whose build.rs runs bindgen over its vendored + # libva headers. Sets LIBCLANG_PATH + BINDGEN_EXTRA_CLANG_ARGS so it finds + # libclang and the libc headers, same as the devShell in flake.nix. rustPlatform.bindgenHook ]; diff --git a/quest/future/video-vaapi.md b/quest/future/video-vaapi.md index 864b4b3988..350f5c73d6 100644 --- a/quest/future/video-vaapi.md +++ b/quest/future/video-vaapi.md @@ -34,9 +34,8 @@ That is why `vaapi` is off by default while `nvidia` is on. Commit the generated bindings to the crate and drop the build script and the bindgen dependency, as `moq-nvenc` does: the output is portable (layout tests off, fixed-width types, `c_char` left symbolic), so one checked-in file serves -every Linux target. Then the feature can return to default-on here. The -`v4l2` feature has the same shape, but its bindgen lives in the third-party -`v4l` crate, so that is a separate decision. +every Linux target, as `moq-v4l` already does for `videodev2.h`. Then the +feature can return to default-on here. Note what is already fine: a host with libva present but no usable VA driver already falls back cleanly, since `Encoder::new` returns `Err` and diff --git a/quest/main/README.md b/quest/main/README.md index 99df975d9e..00d4d20eb3 100644 --- a/quest/main/README.md +++ b/quest/main/README.md @@ -92,7 +92,6 @@ do not add another media abstraction or a renderer crate during stabilization. - [Origin failover machine](/quest/main/origin-failover-machine.md) - a front's source selection and track splicing become a pure step function with a runtime-free test per transition -- [Capture without V4L2 bindgen](/quest/main/capture-v4l-bindings.md) - moq-video `capture` and `v4l2` build on Linux without libclang or kernel headers, via an in-tree `v4l` fork with checked-in bindings ## Related diff --git a/quest/main/capture-v4l-bindings.md b/quest/main/capture-v4l-bindings.md deleted file mode 100644 index e6b96476de..0000000000 --- a/quest/main/capture-v4l-bindings.md +++ /dev/null @@ -1,28 +0,0 @@ -# [S] Capture without the V4L2 bindgen build dependency - -## Goal - -moq-video `capture` builds for every builder without libclang or kernel -headers at build time, and carries no runtime system requirement. - -## Plan - -The runtime side is already clean: the camera path drives the kernel through -ioctls, so no system library ships in the binary. What remains is build time. -Nix already covers in-tree builds (bindgenHook provides libclang), so vendor -or pin the `v4l` crate with checked-in bindings and drop its bindgen build -script, the way `moq-nvenc` does and -[VAAPI](/quest/future/video-vaapi.md) plans. That covers every other builder too -(`cargo install`, Docker). Keep the `v4l` API so `capture/v4l2.rs` and the -`v4l2` codec backend need no logic changes; fixing `v4l` fixes both features -since both drive the same device node through it. - -Verify by building `just rs capture` with no libclang on PATH and by -inspecting the binary to prove no new runtime library requirement. The PR -3850 capture gate keeps the coverage. - -## Related - -- [Ship capture and playback](/quest/next/cli-packaging.md) - the shippable capture milestone this work supports -- [VAAPI encode and decode](/quest/future/video-vaapi.md) - same pre-generated bindings pattern for libva -- [Linux capture parity](/quest/future/capture-linux.md) - the Linux capture milestone this work supports diff --git a/quest/next/cli-packaging.md b/quest/next/cli-packaging.md index 73faeaceb9..ca561c110e 100644 --- a/quest/next/cli-packaging.md +++ b/quest/next/cli-packaging.md @@ -15,13 +15,14 @@ is a packaging gap, not a documentation one: `doc/bin/cli.md` already documents the `--features capture` build. Turn both on by default and keep the heavy parts individually droppable. The -sub-features already exist for this: `nvidia` is opt-out, and `vaapi`, `v4l2`, -and `pipewire` are opt-in because they need libclang or libpipewire on the -build host, so a self-compiler can shed CUDA or add the Linux extras, and +sub-features already exist for this: `nvidia` is opt-out, `vaapi` and +`pipewire` are opt-in because they need libclang or libpipewire on the build +host, and `v4l2` is opt-in only by habit now that moq-v4l checks its bindings +in, so a self-compiler can shed CUDA or add the Linux extras, and `--no-default-features` still reaches a minimal build. The cost is real and -lands on Linux source builds: the camera path pulls libclang and V4L2 headers -through bindgen, the microphone pulls ALSA through cpal, and `play` pulls -winit plus a GPU stack. macOS and Windows use OS frameworks and add nothing. +lands on Linux source builds: the microphone pulls ALSA through cpal, and +`play` pulls winit plus a GPU stack. The camera path costs nothing. macOS and +Windows use OS frameworks and add nothing. Check each distribution actually builds: the Nix overlay needs those system dependencies present, and a Docker image without them fails at build rather @@ -31,5 +32,4 @@ then fails to open a device is the same gap one layer down. ## Required -- [Capture without V4L2 bindgen](/quest/main/capture-v4l-bindings.md) - the camera path must build without libclang before every distribution can ship it - [Audio capture without runtime system libraries](/quest/next/capture-alsa-link.md) - the microphone path must start without system audio libraries before every distribution can ship it diff --git a/rs/moq-cli/Cargo.toml b/rs/moq-cli/Cargo.toml index 7b7759580f..fce0df7b2b 100644 --- a/rs/moq-cli/Cargo.toml +++ b/rs/moq-cli/Cargo.toml @@ -38,9 +38,9 @@ noq = ["moq-tokio/noq"] qlog = ["moq-tokio/qlog"] websocket = ["moq-tokio/websocket"] # Device capture (camera + microphone) + encode/publish. Off by default because -# it pulls in moq-video + moq-audio capture, which add system build deps on Linux -# (camera: `v4l`/v4l2-sys-mit needs libclang + V4L2 headers via bindgen; mic: cpal -# needs ALSA/libasound), plus binary size. macOS/Windows use OS frameworks, no +# it pulls in moq-video + moq-audio capture: on Linux the microphone needs +# ALSA/libasound at build time through cpal (the camera needs nothing, moq-v4l +# checks its bindings in), plus binary size. macOS/Windows use OS frameworks, no # extra install. H.264 is vendored static (openh264), so no system ffmpeg/libav. # Enable with `cargo build -p moq-cli --features capture`, adding `pipewire` for # display capture on Linux. @@ -70,10 +70,9 @@ nvdec = ["nvidia"] # pulls in moq-video. vaapi = ["moq-video?/vaapi", "moq-transcode?/vaapi"] # The V4L2 M2M codecs of an ARM SoC (a Raspberry Pi's VideoCore and the like), -# opt-in like the moq-video feature it turns on: the `v4l` crate's bindgen needs -# libclang and the kernel headers on the build host. `capture` already pays that -# for the camera, so a capture build adds it for free. Only bites when `capture`, -# `transcode`, or `play` pulls in moq-video. +# opt-in like the moq-video feature it turns on. Costs the build nothing: moq-v4l +# checks its bindings in. Only applies when `capture`, `transcode`, or `play` +# pulls in moq-video. v4l2 = ["moq-video?/v4l2", "moq-transcode?/v4l2"] # Screen capture for `capture --display` on Linux (xdg-desktop-portal + PipeWire), # opt-in like moq-video's own `pipewire` because it links libpipewire-0.3 at diff --git a/rs/moq-ffi/Cargo.toml b/rs/moq-ffi/Cargo.toml index e38b3f96f3..466d94f714 100644 --- a/rs/moq-ffi/Cargo.toml +++ b/rs/moq-ffi/Cargo.toml @@ -55,8 +55,8 @@ url = { workspace = true } moq-audio = { workspace = true, optional = true, features = ["aac"] } moq-tokio = { workspace = true, default-features = true } # `openh264`, `nvidia`, and `vaapi` back on, matching rs/libmoq: the workspace turns -# moq-video's defaults off for `capture` (V4L2, libclang), and the codecs are -# collateral rather than the goal. Nothing is paid for them off Linux, since +# moq-video's defaults off for `capture` (device code the bindings don't +# expose), and the codecs are collateral rather than the goal. Nothing is paid for them off Linux, since # cudarc / moq-nvenc / libloading / moq-vaapi sit behind # `cfg(target_os = "linux")` and Android is `target_os = "android"`. On Linux # both dlopen the driver, so the wrappers still link GPU-less and start diff --git a/rs/moq-transcode/Cargo.toml b/rs/moq-transcode/Cargo.toml index 7b25d4989b..a92e4d86d1 100644 --- a/rs/moq-transcode/Cargo.toml +++ b/rs/moq-transcode/Cargo.toml @@ -17,7 +17,8 @@ categories = ["multimedia", "multimedia::video", "multimedia::encoding"] # the zero-copy GPU pipeline, while OpenH264 keeps a software H.264 fallback. # NVIDIA dlopens its driver and needs nothing on the build host. OpenH264 is # vendored C++, so a hardware-only build can disable default features and select -# `nvidia`. `vaapi` and `v4l2` stay opt-in because their bindgen needs libclang. +# `nvidia`. `vaapi` stays opt-in because its bindgen needs libclang; `v4l2` +# mirrors moq-video's opt-in too, though it costs the build nothing. default = ["nvidia", "openh264"] # NVENC + NVDEC (Linux, dlopen'd at runtime; a no-op elsewhere). nvidia = ["moq-video/nvidia"] @@ -26,8 +27,8 @@ openh264 = ["moq-video/openh264"] # Intel/AMD VAAPI hardware encoder (Linux; libva dlopen'd at runtime, but # moq-vaapi's bindgen needs libclang at build time). vaapi = ["moq-video/vaapi"] -# The V4L2 M2M codecs of an ARM SoC (Linux; the `v4l` crate's bindgen needs -# libclang and the kernel headers at build time). +# The V4L2 M2M codecs of an ARM SoC (Linux; moq-v4l checks its bindings in, so +# nothing is needed on the build host). v4l2 = ["moq-video/v4l2"] [dependencies] diff --git a/rs/moq-v4l/Cargo.toml b/rs/moq-v4l/Cargo.toml new file mode 100644 index 0000000000..3ac5ae7273 --- /dev/null +++ b/rs/moq-v4l/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "moq-v4l" +version = "0.0.1" +edition = "2021" +license = "MIT" +rust-version.workspace = true + +description = "Safe Video4Linux 2 bindings, forked from raymanfx/libv4l-rs with the kernel bindings checked in (no bindgen, no libclang)" +repository = "https://github.com/moq-dev/moq" +readme = "README.md" + +keywords = ["v4l2", "video", "capture", "linux"] +categories = ["multimedia::video", "os::linux-apis"] + +[dependencies] +bitflags = { workspace = true } +libc = { workspace = true } diff --git a/rs/moq-v4l/LICENSE b/rs/moq-v4l/LICENSE new file mode 100644 index 0000000000..34379332a5 --- /dev/null +++ b/rs/moq-v4l/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2020 Christopher N. Hesse. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/rs/moq-v4l/README.md b/rs/moq-v4l/README.md new file mode 100644 index 0000000000..c68f0d5190 --- /dev/null +++ b/rs/moq-v4l/README.md @@ -0,0 +1,21 @@ +# moq-v4l + +Safe Rust bindings for the kernel's Video4Linux 2 API, vendored for the MoQ +workspace. `moq-video` uses them for camera capture and, behind its `v4l2` +feature, the memory-to-memory hardware codecs most ARM SoCs expose. + +This is a fork of [`v4l`](https://github.com/raymanfx/libv4l-rs) (MIT, +Copyright Christopher N. Hesse) with one change: the `videodev2.h` bindings +that upstream's `v4l2-sys-mit` generates in a build script are checked in +under `src/sys/`, so a build needs neither libclang nor the kernel headers. +The `libv4l` backend did not survive the fork; every call is an ioctl on the +device node and nothing links at build time. + +The bindings are arch-independent: layout tests are off, integer types are +fixed-width, and `timeval` / `timespec` come from `libc`. Regenerate them on a +Linux host with `bindgen-cli` and the kernel UAPI headers installed by running +`src/sys/bindgen.sh`. + +## License + +MIT, inherited from upstream. See `LICENSE`. diff --git a/rs/moq-v4l/src/buffer.rs b/rs/moq-v4l/src/buffer.rs new file mode 100644 index 0000000000..d08d743009 --- /dev/null +++ b/rs/moq-v4l/src/buffer.rs @@ -0,0 +1,115 @@ +use bitflags::bitflags; +use std::fmt; + +use crate::timestamp::Timestamp; + +/// Buffer type +/// +/// Specific types of devices require buffers of corresponding types. +#[allow(clippy::unreadable_literal)] +#[rustfmt::skip] +#[repr(u32)] +#[derive(Debug, Clone, Copy)] +pub enum Type { + VideoCapture = 1, + VideoOutput = 2, + VideoOverlay = 3, + VbiCaputre = 4, + VbiOutput = 5, + SlicedVbiCapture = 6, + SlicedVbiOutput = 7, + VideoOutputOverlay = 8, + VideoCaptureMplane = 9, + VideoOutputMplane = 10, + SdrCapture = 11, + SdrOutput = 12, + MetaCapture = 13, + MetaOutput = 14, + + /// Deprecated, do not use + Private = 0x80, +} + +bitflags! { + #[allow(clippy::unreadable_literal)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct Flags: u32 { + /// Buffer is mapped + const MAPPED = 0x00000001; + /// Buffer is queued for processing + const QUEUED = 0x00000002; + /// Buffer is ready + const DONE = 0x00000004; + /// Image is a keyframe (I-frame) + const KEYFRAME = 0x00000008; + /// Image is a P-frame + const PFRAME = 0x00000010; + /// Image is a B-frame + const BFRAME = 0x00000020; + /// Buffer is ready, but the data contained within is corrupted + const ERROR = 0x00000040; + /// Buffer is added to an unqueued request + const IN_REQUEST = 0x00000080; + /// Timecode field is valid + const TIMECODE = 0x00000100; + /// Don't return the capture buffer until OUTPUT timestamp changes + const M2M_HOLD_CAPTURE_BUF = 0x00000200; + /// Buffer is prepared for queuing + const PREPARED = 0x00000400; + /// Cache handling flags + const NO_CACHE_INVALIDATE = 0x00000800; + const NO_CACHE_CLEAN = 0x00001000; + /// Timestamp type + const TIMESTAMP_MASK = 0x0000e000; + const TIMESTAMP_UNKNOWN = 0x00000000; + const TIMESTAMP_MONOTONIC = 0x00002000; + const TIMESTAMP_COPY = 0x00004000; + /// Timestamp sources + const TSTAMP_SRC_MASK = 0x00070000; + const TSTAMP_SRC_EOF = 0x00000000; + const TSTAMP_SRC_SOE = 0x00010000; + /// mem2mem encoder/decoder + const LAST = 0x00100000; + /// request_fd is valid + const REQUEST_FD = 0x00800000; + } +} + +impl Default for Flags { + fn default() -> Self { + Flags::from(0) + } +} + +impl From for Flags { + fn from(flags: u32) -> Self { + Self::from_bits_truncate(flags) + } +} + +impl From for u32 { + fn from(flags: Flags) -> Self { + flags.bits() + } +} + +impl fmt::Display for Flags { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +/// Buffer metadata, mostly used not to convolute the main buffer structs +#[derive(Copy, Clone, Default)] +pub struct Metadata { + /// Number of bytes occupied by the data in the buffer + pub bytesused: u32, + /// Buffer flags + pub flags: Flags, + /// Indicates the field order of the image in the buffer. + pub field: u32, + /// Time of capture (usually set by the driver) + pub timestamp: Timestamp, + /// Sequence number, counting the frames + pub sequence: u32, +} diff --git a/rs/moq-v4l/src/capability.rs b/rs/moq-v4l/src/capability.rs new file mode 100644 index 0000000000..04b3619064 --- /dev/null +++ b/rs/moq-v4l/src/capability.rs @@ -0,0 +1,120 @@ +use bitflags::bitflags; +use std::{fmt, str}; + +use crate::sys::*; + +bitflags! { + #[allow(clippy::unreadable_literal)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct Flags: u32 { + const VIDEO_CAPTURE = 0x00000001; + const VIDEO_OUTPUT = 0x00000002; + const VIDEO_OVERLAY = 0x00000004; + const VBI_CAPTURE = 0x00000010; + const VBI_OUTPUT = 0x00000020; + const SLICED_VBI_CAPTURE = 0x00000040; + const SLICED_VBI_OUTPUT = 0x00000080; + const RDS_CAPTURE = 0x00000100; + const VIDEO_OUTPUT_OVERLAY = 0x00000200; + const HW_FREQ_SEEK = 0x00000400; + const RDS_OUTPUT = 0x00000800; + + const VIDEO_CAPTURE_MPLANE = 0x00001000; + const VIDEO_OUTPUT_MPLANE = 0x00002000; + const VIDEO_M2M_MPLANE = 0x00004000; + const VIDEO_M2M = 0x00008000; + + const TUNER = 0x00010000; + const AUDIO = 0x00020000; + const RADIO = 0x00040000; + const MODULATOR = 0x00080000; + + const SDR_CAPTURE = 0x00100000; + const EXT_PIX_FORMAT = 0x00200000; + const SDR_OUTPUT = 0x00400000; + const META_CAPTURE = 0x00800000; + + const READ_WRITE = 0x01000000; + const ASYNC_IO = 0x02000000; + const STREAMING = 0x04000000; + const META_OUTPUT = 0x08000000; + + const TOUCH = 0x10000000; + + const DEVICE_CAPS = 0x80000000; + } +} + +impl From for Flags { + fn from(flags: u32) -> Self { + Self::from_bits_truncate(flags) + } +} + +impl From for u32 { + fn from(flags: Flags) -> Self { + flags.bits() + } +} + +impl fmt::Display for Flags { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +#[derive(Debug)] +/// Device capabilities +pub struct Capabilities { + /// Driver name, e.g. uvc for usb video class devices + pub driver: String, + /// Card name + pub card: String, + /// Bus name, e.g. USB or PCI + pub bus: String, + /// Version number MAJOR.MINOR.PATCH + pub version: (u8, u8, u8), + + /// Capability flags + pub capabilities: Flags, +} + +impl From for Capabilities { + fn from(cap: v4l2_capability) -> Self { + Self { + driver: str::from_utf8(&cap.driver) + .unwrap() + .trim_matches(char::from(0)) + .to_string(), + card: str::from_utf8(&cap.card) + .unwrap() + .trim_matches(char::from(0)) + .to_string(), + bus: str::from_utf8(&cap.bus_info) + .unwrap() + .trim_matches(char::from(0)) + .to_string(), + version: ( + ((cap.version >> 16) & 0xff) as u8, + ((cap.version >> 8) & 0xff) as u8, + (cap.version & 0xff) as u8, + ), + capabilities: Flags::from(cap.device_caps), + } + } +} + +impl fmt::Display for Capabilities { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "Driver : {}", self.driver)?; + writeln!(f, "Card : {}", self.card)?; + writeln!(f, "Bus : {}", self.bus)?; + writeln!( + f, + "Version : {}.{}.{}", + self.version.0, self.version.1, self.version.2 + )?; + writeln!(f, "Capabilities : {}", self.capabilities)?; + Ok(()) + } +} diff --git a/rs/moq-v4l/src/context.rs b/rs/moq-v4l/src/context.rs new file mode 100644 index 0000000000..1d4ed7f302 --- /dev/null +++ b/rs/moq-v4l/src/context.rs @@ -0,0 +1,97 @@ +use std::fs; +use std::path::{Path, PathBuf}; + +/// Returns a list of devices currently known to the system +/// +/// # Example +/// +/// ``` +/// use moq_v4l::context; +/// for dev in context::enum_devices() { +/// print!("{}{}", dev.index(), dev.name().unwrap()); +/// } +/// ``` +pub fn enum_devices() -> Vec { + let mut devices = Vec::new(); + + let entries = fs::read_dir("/dev"); + if let Ok(entries) = entries { + for dentry in entries { + let dentry = match dentry { + Ok(dentry) => dentry, + Err(_) => continue, + }; + + let file_name = dentry.file_name(); + let file_name = file_name.to_str().unwrap(); + + if file_name.starts_with("video") { + let node = Node::new(dentry.path()); + devices.push(node); + } + } + } + + devices +} + +/// Represents a video4linux device node +pub struct Node { + /// Device node path + path: PathBuf, +} + +impl Node { + /// Returns a device node observer by path + /// + /// The device is opened in read only mode. + /// + /// # Arguments + /// + /// * `path` - Node path (usually a character device or sysfs entry) + /// + /// # Example + /// + /// ``` + /// use moq_v4l::context::Node; + /// let node = Node::new("/dev/video0"); + /// ``` + pub fn new>(path: P) -> Self { + Node { + path: PathBuf::from(path.as_ref()), + } + } + + /// Returns the absolute path of the device node + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the index of the device node + pub fn index(&self) -> usize { + let file_name = self.path.file_name().unwrap(); + + let mut index_str = String::new(); + for c in file_name.to_str().unwrap().chars() { + if !c.is_ascii_digit() { + continue; + } + + index_str.push(c); + } + + let index = index_str.parse::(); + index.unwrap() + } + + /// Returns name of the device by parsing its sysfs entry + pub fn name(&self) -> Option { + let index = self.index(); + let path = format!("{}{}{}", "/sys/class/video4linux/video", index, "/name"); + let name = fs::read_to_string(path); + match name { + Ok(name) => Some(name.trim().to_string()), + Err(_) => None, + } + } +} diff --git a/rs/moq-v4l/src/control.rs b/rs/moq-v4l/src/control.rs new file mode 100644 index 0000000000..93732a4390 --- /dev/null +++ b/rs/moq-v4l/src/control.rs @@ -0,0 +1,253 @@ +use bitflags::bitflags; +use std::convert::{TryFrom, TryInto}; +use std::{ffi, fmt, mem, str}; + +use crate::sys::*; + +/// Control data type +#[allow(clippy::unreadable_literal)] +#[rustfmt::skip] +#[repr(u32)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum Type { + Integer = 1, + Boolean = 2, + Menu = 3, + Button = 4, + Integer64 = 5, + CtrlClass = 6, + String = 7, + Bitmask = 8, + IntegerMenu = 9, + + /* Compound types are >= 0x0100 */ + U8 = 0x0100, + U16 = 0x0101, + U32 = 0x0102, + Area = 0x0106, +} + +impl TryFrom for Type { + type Error = (); + + fn try_from(repr: u32) -> Result { + match repr { + 1 => Ok(Type::Integer), + 2 => Ok(Type::Boolean), + 3 => Ok(Type::Menu), + 4 => Ok(Type::Button), + 5 => Ok(Type::Integer64), + 6 => Ok(Type::CtrlClass), + 7 => Ok(Type::String), + 8 => Ok(Type::Bitmask), + 9 => Ok(Type::IntegerMenu), + + 0x0100 => Ok(Type::U8), + 0x0101 => Ok(Type::U16), + 0x0102 => Ok(Type::U32), + 0x0106 => Ok(Type::Area), + _ => Err(()), + } + } +} + +impl From for u32 { + fn from(t: Type) -> Self { + t as Self + } +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +bitflags! { + #[allow(clippy::unreadable_literal)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct Flags: u32 { + const DISABLED = 0x0001; + const GRABBED = 0x0002; + const READ_ONLY = 0x0004; + const UPDATE = 0x0008; + const INACTIVE = 0x0010; + const SLIDER = 0x0020; + const WRITE_ONLY = 0x0040; + const VOLATILE = 0x0080; + const HAS_PAYLOAD = 0x0100; + const EXECUTE_ON_WRITE = 0x0200; + const MODIFY_LAYOUT = 0x0400; + + const NEXT_CTRL = 0x80000000; + const NEXT_COMPOUND = 0x40000000; + } +} + +impl From for Flags { + fn from(flags: u32) -> Self { + Self::from_bits_truncate(flags) + } +} + +impl From for u32 { + fn from(flags: Flags) -> Self { + flags.bits() + } +} + +impl fmt::Display for Flags { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +#[derive(Debug)] +/// Device control menu item +pub enum MenuItem { + Name(String), + Value(i64), +} + +impl fmt::Display for MenuItem { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MenuItem::Name(name) => { + write!(f, "{}", name)?; + } + MenuItem::Value(value) => { + write!(f, "{}", value)?; + } + } + Ok(()) + } +} + +impl TryFrom<(Type, v4l2_querymenu)> for MenuItem { + type Error = (); + + fn try_from(item: (Type, v4l2_querymenu)) -> Result { + unsafe { + match item.0 { + Type::Menu => Ok(MenuItem::Name( + str::from_utf8(&item.1.__bindgen_anon_1.name) + .unwrap() + .trim_matches(char::from(0)) + .to_string(), + )), + Type::IntegerMenu => Ok(MenuItem::Value(item.1.__bindgen_anon_1.value)), + _ => Err(()), + } + } + } +} + +#[derive(Debug)] +/// Device control description +pub struct Description { + /// Control identifier, set by the the application + pub id: u32, + /// Type of control + pub typ: Type, + /// Name of the control, intended for the user + pub name: String, + /// Minimum value, inclusive + pub minimum: i64, + /// Maximum value, inclusive + pub maximum: i64, + /// Step size, always positive + pub step: u64, + /// Default value + pub default: i64, + /// Control flags + pub flags: Flags, + + /// Items for menu controls (only valid if typ is a menu type) + pub items: Option>, +} + +impl From for Description { + fn from(ctrl: v4l2_query_ext_ctrl) -> Self { + Self { + id: ctrl.id, + typ: Type::try_from(ctrl.type_).unwrap(), + name: unsafe { ffi::CStr::from_ptr(ctrl.name.as_ptr()) } + .to_str() + .unwrap() + .to_string(), + minimum: ctrl.minimum, + maximum: ctrl.maximum, + step: ctrl.step, + default: ctrl.default_value, + flags: Flags::from(ctrl.flags), + items: None, + } + } +} + +impl fmt::Display for Description { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "ID : {}", self.id)?; + writeln!(f, "Type : {}", self.typ)?; + writeln!(f, "Name : {}", self.name)?; + writeln!(f, "Minimum : {}", self.minimum)?; + writeln!(f, "Maximum : {}", self.maximum)?; + writeln!(f, "Step : {}", self.step)?; + writeln!(f, "Default : {}", self.default)?; + writeln!(f, "Flags : {}", self.flags)?; + if let Some(items) = &self.items { + writeln!(f, "Menu ==>")?; + for item in items { + writeln!(f, " * {}", item.1)?; + } + } + Ok(()) + } +} + +#[derive(Debug)] +pub struct Control { + pub id: u32, + pub value: Value, +} + +#[derive(Debug, PartialEq, Eq)] +/// Device control value +pub enum Value { + /* buttons */ + None, + /* single values */ + Integer(i64), + Boolean(bool), + String(String), + /* compound (matrix) values */ + CompoundU8(Vec), + CompoundU16(Vec), + CompoundU32(Vec), + CompoundPtr(Vec), +} + +impl TryInto for Control { + type Error = (); + + fn try_into(self) -> Result { + unsafe { + let mut ctrl = v4l2_control { + id: self.id, + ..mem::zeroed() + }; + match self.value { + Value::None => Ok(ctrl), + Value::Integer(val) => { + ctrl.value = val as i32; + Ok(ctrl) + } + Value::Boolean(val) => { + ctrl.value = val as i32; + Ok(ctrl) + } + _ => Err(()), + } + } + } +} diff --git a/rs/moq-v4l/src/device.rs b/rs/moq-v4l/src/device.rs new file mode 100644 index 0000000000..e7bae14949 --- /dev/null +++ b/rs/moq-v4l/src/device.rs @@ -0,0 +1,397 @@ +use std::convert::TryFrom; +use std::path::Path; +use std::sync::Arc; +use std::{io, mem}; + +use libc; + +use crate::control; +use crate::sys::*; +use crate::v4l2; +use crate::v4l2::videodev::v4l2_ext_controls; +use crate::{capability::Capabilities, control::Control}; + +/// Linux capture device abstraction +pub struct Device { + /// Raw handle + handle: Arc, +} + +impl Device { + /// Returns a capture device by index + /// + /// Devices are usually enumerated by the system. + /// An index of zero thus represents the first device the system got to know about. + /// + /// # Arguments + /// + /// * `index` - Index (0: first, 1: second, ..) + /// + /// # Example + /// + /// ``` + /// use moq_v4l::device::Device; + /// let dev = Device::new(0); + /// ``` + pub fn new(index: usize) -> io::Result { + let path = format!("{}{}", "/dev/video", index); + let fd = v4l2::open(path, libc::O_RDWR | libc::O_NONBLOCK)?; + + if fd == -1 { + return Err(io::Error::last_os_error()); + } + + Ok(Device { + handle: Arc::new(Handle::new(fd)), + }) + } + + /// Returns a capture device by path + /// + /// Linux device nodes are usually found in /dev/videoX or /sys/class/video4linux/videoX. + /// + /// # Arguments + /// + /// * `path` - Path (e.g. "/dev/video0") + /// + /// # Example + /// + /// ``` + /// use moq_v4l::device::Device; + /// let dev = Device::with_path("/dev/video0"); + /// ``` + pub fn with_path>(path: P) -> io::Result { + let fd = v4l2::open(&path, libc::O_RDWR | libc::O_NONBLOCK)?; + + if fd == -1 { + return Err(io::Error::last_os_error()); + } + + Ok(Device { + handle: Arc::new(Handle::new(fd)), + }) + } + + /// Returns the raw device handle + pub fn handle(&self) -> Arc { + self.handle.clone() + } + + /// Returns video4linux framework defined information such as card, driver, etc. + pub fn query_caps(&self) -> io::Result { + unsafe { + let mut v4l2_caps: v4l2_capability = mem::zeroed(); + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_QUERYCAP, + &mut v4l2_caps as *mut _ as *mut std::os::raw::c_void, + )?; + + Ok(Capabilities::from(v4l2_caps)) + } + } + + /// Returns the supported controls for a device such as gain, focus, white balance, etc. + pub fn query_controls(&self) -> io::Result> { + let mut controls = Vec::new(); + unsafe { + let mut v4l2_ctrl: v4l2_query_ext_ctrl = mem::zeroed(); + + loop { + v4l2_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + v4l2_ctrl.id |= V4L2_CTRL_FLAG_NEXT_COMPOUND; + match v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_QUERY_EXT_CTRL, + &mut v4l2_ctrl as *mut _ as *mut std::os::raw::c_void, + ) { + Ok(_) => { + // get the basic control information + let mut control = control::Description::from(v4l2_ctrl); + + // if this is a menu control, enumerate its items + if control.typ == control::Type::Menu || control.typ == control::Type::IntegerMenu { + let mut items = Vec::new(); + + for i in (v4l2_ctrl.minimum..=v4l2_ctrl.maximum).step_by(v4l2_ctrl.step as usize) { + let mut v4l2_menu = v4l2_querymenu { + id: v4l2_ctrl.id, + index: i as u32, + ..mem::zeroed() + }; + let res = v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_QUERYMENU, + &mut v4l2_menu as *mut _ as *mut std::os::raw::c_void, + ); + + // BEWARE OF DRAGONS! + // The API docs [1] state VIDIOC_QUERYMENU should may return EINVAL + // for some indices between minimum and maximum when an item is not + // supported by a driver. + // + // I have no idea why it is advertised in the first place then, but + // have seen this happen with a Logitech C920 HD Pro webcam. + // In case of errors, let's just skip the offending index. + // + // [1] https://github.com/torvalds/linux/blob/master/Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst#description + if res.is_err() { + continue; + } + + let item = control::MenuItem::try_from((control.typ, v4l2_menu)).unwrap(); + items.push((v4l2_menu.index, item)); + } + + control.items = Some(items); + } + + controls.push(control); + } + Err(e) => { + if controls.is_empty() || e.kind() != io::ErrorKind::InvalidInput { + return Err(e); + } else { + break; + } + } + } + } + } + + Ok(controls) + } + + /// Returns the control value for an ID + /// + /// # Arguments + /// + /// * `id` - Control identifier + pub fn control(&self, id: u32) -> io::Result { + unsafe { + let mut queryctrl = v4l2_query_ext_ctrl { id, ..mem::zeroed() }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_QUERY_EXT_CTRL, + &mut queryctrl as *mut _ as *mut std::os::raw::c_void, + )?; + + // determine the control type + let description = control::Description::from(queryctrl); + + // query the actual control value + let mut v4l2_ctrl = v4l2_ext_control { id, ..mem::zeroed() }; + let mut v4l2_ctrls = v4l2_ext_controls { + count: 1, + controls: &mut v4l2_ctrl, + ..mem::zeroed() + }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_G_EXT_CTRLS, + &mut v4l2_ctrls as *mut _ as *mut std::os::raw::c_void, + )?; + + let value = match description.typ { + control::Type::Integer64 => control::Value::Integer(v4l2_ctrl.__bindgen_anon_1.value64), + control::Type::Integer | control::Type::Menu => { + control::Value::Integer(v4l2_ctrl.__bindgen_anon_1.value as i64) + } + control::Type::Boolean => control::Value::Boolean(v4l2_ctrl.__bindgen_anon_1.value == 1), + _ => return Err(io::Error::other("cannot handle control type")), + }; + + Ok(Control { id, value }) + } + } + + /// Modifies the control value + /// + /// # Arguments + /// + /// * `ctrl` - Control to be set + pub fn set_control(&self, ctrl: Control) -> io::Result<()> { + self.set_controls(vec![ctrl]) + } + + /// Modifies the control values atomically + /// + /// # Arguments + /// + /// * `ctrls` - Vec of the controls to be set + pub fn set_controls(&self, ctrls: Vec) -> io::Result<()> { + unsafe { + let mut control_list: Vec = vec![]; + let mut class: Option = None; + + if ctrls.is_empty() { + return Err(io::Error::new(io::ErrorKind::InvalidInput, "ctrls cannot be empty")); + } + + for ref ctrl in ctrls { + let mut control = v4l2_ext_control { + id: ctrl.id, + ..mem::zeroed() + }; + class = match class { + Some(c) => { + if c != (control.id & 0xFFFF0000) { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "All controls must be in the same class", + )); + } else { + Some(c) + } + } + None => Some(control.id & 0xFFFF0000), + }; + + match ctrl.value { + control::Value::None => {} + control::Value::Integer(val) => { + control.__bindgen_anon_1.value64 = val; + control.size = std::mem::size_of::() as u32; + } + control::Value::Boolean(val) => { + control.__bindgen_anon_1.value64 = val as i64; + control.size = std::mem::size_of::() as u32; + } + control::Value::String(ref val) => { + control.__bindgen_anon_1.string = val.as_ptr() as *mut std::os::raw::c_char; + control.size = val.len() as u32; + } + control::Value::CompoundU8(ref val) => { + control.__bindgen_anon_1.p_u8 = val.as_ptr() as *mut u8; + control.size = (val.len() * std::mem::size_of::()) as u32; + } + control::Value::CompoundU16(ref val) => { + control.__bindgen_anon_1.p_u16 = val.as_ptr() as *mut u16; + control.size = (val.len() * std::mem::size_of::()) as u32; + } + control::Value::CompoundU32(ref val) => { + control.__bindgen_anon_1.p_u32 = val.as_ptr() as *mut u32; + control.size = (val.len() * std::mem::size_of::()) as u32; + } + control::Value::CompoundPtr(ref val) => { + control.__bindgen_anon_1.ptr = val.as_ptr() as *mut std::os::raw::c_void; + control.size = (val.len() * std::mem::size_of::()) as u32; + } + }; + + control_list.push(control); + } + + let class = class + .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "failed to determine control class"))?; + + let mut controls = v4l2_ext_controls { + count: control_list.len() as u32, + controls: control_list.as_mut_ptr(), + + which: class, + ..mem::zeroed() + }; + + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_S_EXT_CTRLS, + &mut controls as *mut _ as *mut std::os::raw::c_void, + ) + } + } +} + +impl io::Read for Device { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + unsafe { + let ret = libc::read( + self.handle().fd(), + buf.as_mut_ptr() as *mut std::os::raw::c_void, + buf.len(), + ); + match ret { + -1 => Err(io::Error::last_os_error()), + ret => Ok(ret as usize), + } + } + } +} + +impl io::Write for Device { + fn write(&mut self, buf: &[u8]) -> io::Result { + unsafe { + let ret = libc::write( + self.handle().fd(), + buf.as_ptr() as *const std::os::raw::c_void, + buf.len(), + ); + + match ret { + -1 => Err(io::Error::last_os_error()), + ret => Ok(ret as usize), + } + } + } + + fn flush(&mut self) -> io::Result<()> { + // write doesn't use a buffer, so it effectively flushes with each call + // therefore, we don't have anything to flush later + Ok(()) + } +} + +/// Device handle for low-level access. +/// +/// Acquiring a handle facilitates (possibly mutating) interactions with the device. +pub struct Handle { + fd: std::os::raw::c_int, +} + +impl Handle { + fn new(fd: std::os::raw::c_int) -> Self { + Self { fd } + } + + /// Returns the raw file descriptor + pub fn fd(&self) -> std::os::raw::c_int { + self.fd + } + + /// Polls the file descriptor for I/O events + /// + /// # Arguments + /// + /// * `events` - The events you are interested in (e.g. POLLIN) + /// + /// * `timeout` - Timeout in milliseconds. A value of zero returns immediately, + /// even if the fd is not ready. A negative value means infinite timeout (blocking). + pub fn poll(&self, events: i16, timeout: i32) -> io::Result { + match unsafe { + libc::poll( + [libc::pollfd { + fd: self.fd, + events, + revents: 0, + }] + .as_mut_ptr(), + 1, + timeout, + ) + } { + -1 => Err(io::Error::last_os_error()), + ret => { + // A return value of zero means that we timed out. A positive value signifies the + // number of fds with non-zero revents fields (aka I/O activity). + assert!(ret == 0 || ret == 1); + Ok(ret) + } + } + } +} + +impl Drop for Handle { + fn drop(&mut self) { + v4l2::close(self.fd).unwrap(); + } +} diff --git a/rs/moq-v4l/src/format/colorspace.rs b/rs/moq-v4l/src/format/colorspace.rs new file mode 100644 index 0000000000..cb2fb7c684 --- /dev/null +++ b/rs/moq-v4l/src/format/colorspace.rs @@ -0,0 +1,77 @@ +use std::convert::TryFrom; +use std::fmt; + +#[derive(Debug, Copy, Clone)] +#[repr(u32)] +/// Colorspace for pixels. +/// +/// The driver decides this for capture streams and the user sets it for +/// output streams. +pub enum Colorspace { + /// driver will pick default + Default = 0, + /// SMPTE 170M + SMPTE170M = 1, + /// SMPTE 240M + SMPTE240M = 2, + /// Rec. 709, aka BT.709 + Rec709 = 3, + // BT878=4: deprecated, no driver returns this + /// NTSC + NTSC = 5, + /// EBU Tech 3213 + EBUTech3212 = 6, + /// use for JPEGs: sRGB colorspace, YCbCr encoding, and full range quantization + JPEG = 7, + /// sRGB + SRGB = 8, + /// opRGB + OPRGB = 9, + /// Rec. 2020, aka BT.2020 + Rec2020 = 10, + /// for RAW images + RAW = 11, + /// DCI-P3 + DCIP3 = 12, +} + +impl fmt::Display for Colorspace { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => write!(f, "default"), + Self::SMPTE170M => write!(f, "SMPTE 170M"), + Self::SMPTE240M => write!(f, "SMPTE 240M"), + Self::Rec709 => write!(f, "Rec. 709"), + Self::NTSC => write!(f, "NTSC"), + Self::EBUTech3212 => write!(f, "EBU Tech 3213"), + Self::JPEG => write!(f, "JPEG"), + Self::SRGB => write!(f, "sRGB"), + Self::OPRGB => write!(f, "opRGB"), + Self::Rec2020 => write!(f, "Rec. 2020"), + Self::RAW => write!(f, "RAW"), + Self::DCIP3 => write!(f, "DCI-P3"), + } + } +} + +impl TryFrom for Colorspace { + type Error = (); + + fn try_from(code: u32) -> Result { + match code { + 0 => Ok(Self::Default), + 1 => Ok(Self::SMPTE170M), + 2 => Ok(Self::SMPTE240M), + 3 => Ok(Self::Rec709), + 5 => Ok(Self::NTSC), + 6 => Ok(Self::EBUTech3212), + 7 => Ok(Self::JPEG), + 8 => Ok(Self::SRGB), + 9 => Ok(Self::OPRGB), + 10 => Ok(Self::Rec2020), + 11 => Ok(Self::RAW), + 12 => Ok(Self::DCIP3), + _ => Err(()), + } + } +} diff --git a/rs/moq-v4l/src/format/description.rs b/rs/moq-v4l/src/format/description.rs new file mode 100644 index 0000000000..84aff27e8a --- /dev/null +++ b/rs/moq-v4l/src/format/description.rs @@ -0,0 +1,70 @@ +use bitflags::bitflags; +use std::{fmt, str}; + +use crate::format::FourCC; +use crate::sys::*; + +bitflags! { + #[allow(clippy::unreadable_literal)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct Flags : u32 { + const COMPRESSED = 0x0001; + const EMULATED = 0x0002; + const CONTINUOUS_BITSTREAM = 0x0004; + const DYN_RESOLUTION = 0x0008; + } +} + +impl From for Flags { + fn from(flags: u32) -> Self { + Self::from_bits_truncate(flags) + } +} + +impl From for u32 { + fn from(flags: Flags) -> Self { + flags.bits() + } +} + +impl fmt::Display for Flags { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +#[derive(Debug)] +/// Format description as returned by [`crate::v4l2::vidioc::VIDIOC_ENUM_FMT`] +pub struct Description { + pub index: u32, + pub typ: u32, + pub flags: Flags, + pub description: String, + pub fourcc: FourCC, +} + +impl fmt::Display for Description { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "index : {}", self.index)?; + writeln!(f, "type: : {}", self.typ)?; + writeln!(f, "flags: : {}", self.flags)?; + writeln!(f, "description : {}", self.description)?; + writeln!(f, "fourcc : {}", self.fourcc)?; + Ok(()) + } +} + +impl From for Description { + fn from(desc: v4l2_fmtdesc) -> Self { + Self { + index: desc.index, + typ: desc.type_, + flags: Flags::from(desc.flags), + description: str::from_utf8(&desc.description) + .unwrap() + .trim_matches(char::from(0)) + .to_string(), + fourcc: FourCC::from(desc.pixelformat), + } + } +} diff --git a/rs/moq-v4l/src/format/field.rs b/rs/moq-v4l/src/format/field.rs new file mode 100644 index 0000000000..6efd5c3b7e --- /dev/null +++ b/rs/moq-v4l/src/format/field.rs @@ -0,0 +1,65 @@ +use std::convert::TryFrom; +use std::fmt; + +#[derive(Debug, Copy, Clone)] +#[repr(u32)] +/// Represents how fields are interlaced (if they are) +pub enum FieldOrder { + /// Progressive, Top, Bottom, or Interlaced is acceptable; driver will pick one + Any = 0, + /// progressive, not interlaced + Progressive = 1, + /// top, or odd, field + Top = 2, + /// bottom, or even, field + Bottom = 3, + /// both fields interlaced + Interlaced = 4, + /// top field stored first, then bottom field + SequentialTB = 5, + /// bottom field stored first, then top field + SequentialBT = 6, + /// one field at a time, alternates between top and bottom + Alternate = 7, + /// both fields interlaced, starts with top + InterlacedTB = 8, + /// both fields interlaced, starts with bottom + InterlacedBT = 9, +} + +impl fmt::Display for FieldOrder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Any => write!(f, "any"), + Self::Progressive => write!(f, "progressive"), + Self::Top => write!(f, "top"), + Self::Bottom => write!(f, "bottom"), + Self::Interlaced => write!(f, "interlaced"), + Self::SequentialTB => write!(f, "sequential, top then bottom"), + Self::SequentialBT => write!(f, "sequential, bottom then top"), + Self::Alternate => write!(f, "alternate between fields"), + Self::InterlacedTB => write!(f, "interlaced, starting with top"), + Self::InterlacedBT => write!(f, "interlaced, starting with bottom"), + } + } +} + +impl TryFrom for FieldOrder { + type Error = (); + + fn try_from(code: u32) -> Result { + match code { + 0 => Ok(Self::Any), + 1 => Ok(Self::Progressive), + 2 => Ok(Self::Top), + 3 => Ok(Self::Bottom), + 4 => Ok(Self::Interlaced), + 5 => Ok(Self::SequentialTB), + 6 => Ok(Self::SequentialBT), + 7 => Ok(Self::Alternate), + 8 => Ok(Self::InterlacedTB), + 9 => Ok(Self::InterlacedBT), + _ => Err(()), + } + } +} diff --git a/rs/moq-v4l/src/format/fourcc.rs b/rs/moq-v4l/src/format/fourcc.rs new file mode 100644 index 0000000000..e0e51fbea8 --- /dev/null +++ b/rs/moq-v4l/src/format/fourcc.rs @@ -0,0 +1,67 @@ +use std::{fmt, str}; + +#[derive(Debug, Default, Copy, Clone, Eq)] +/// Four character code representing a pixelformat +pub struct FourCC { + pub repr: [u8; 4], +} + +impl FourCC { + #[allow(clippy::trivially_copy_pass_by_ref)] + /// Returns a pixelformat as four character code + /// + /// # Arguments + /// + /// * `repr` - Four characters as raw bytes + /// + /// # Example + /// + /// ``` + /// use moq_v4l::format::FourCC; + /// let fourcc = FourCC::new(b"YUYV"); + /// ``` + pub fn new(repr: &[u8; 4]) -> FourCC { + FourCC { repr: *repr } + } + + /// Returns the string representation of a four character code + /// + /// # Example + /// + /// ``` + /// use moq_v4l::format::FourCC; + /// let fourcc = FourCC::new(b"YUYV"); + /// let str = fourcc.str().unwrap(); + /// ``` + pub fn str(&self) -> Result<&str, str::Utf8Error> { + str::from_utf8(&self.repr) + } +} + +impl fmt::Display for FourCC { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let string = str::from_utf8(&self.repr); + if let Ok(string) = string { + write!(f, "{}", string)?; + } + Ok(()) + } +} + +impl PartialEq for FourCC { + fn eq(&self, other: &FourCC) -> bool { + self.repr.iter().zip(other.repr.iter()).all(|(a, b)| a == b) + } +} + +impl From for FourCC { + fn from(code: u32) -> Self { + FourCC::new(&code.to_le_bytes()) + } +} + +impl From for u32 { + fn from(fourcc: FourCC) -> Self { + Self::from_le_bytes(fourcc.repr) + } +} diff --git a/rs/moq-v4l/src/format/mod.rs b/rs/moq-v4l/src/format/mod.rs new file mode 100644 index 0000000000..7b1d30a4bf --- /dev/null +++ b/rs/moq-v4l/src/format/mod.rs @@ -0,0 +1,157 @@ +use bitflags::bitflags; +use std::{convert::TryFrom, fmt, mem}; + +use crate::sys::*; + +pub mod colorspace; +pub use colorspace::Colorspace; + +pub mod description; +pub use description::Description; + +pub mod field; +pub use field::FieldOrder; + +pub mod fourcc; +pub use fourcc::FourCC; + +pub mod quantization; +pub use quantization::Quantization; + +pub mod transfer; +pub use transfer::TransferFunction; + +bitflags! { + #[allow(clippy::unreadable_literal)] + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct Flags : u32 { + const PREMUL_ALPHA = 0x00000001; + } +} + +impl From for Flags { + fn from(flags: u32) -> Self { + Self::from_bits_truncate(flags) + } +} + +impl From for u32 { + fn from(flags: Flags) -> Self { + flags.bits() + } +} + +impl fmt::Display for Flags { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +#[derive(Debug, Copy, Clone)] +/// Streaming format (single-planar) +pub struct Format { + /// width in pixels + pub width: u32, + /// height in pixels + pub height: u32, + /// pixelformat code + pub fourcc: FourCC, + /// field order for interlacing + pub field_order: FieldOrder, + + /// bytes per line + pub stride: u32, + /// maximum number of bytes required to store an image + pub size: u32, + + /// flags set by the application or driver + pub flags: Flags, + + /// supplements the pixelformat (fourcc) information + pub colorspace: Colorspace, + /// the way colors are mapped + pub quantization: Quantization, + /// the transfer function for the colorspace + pub transfer: TransferFunction, +} + +impl Format { + /// Returns a capture format + /// + /// # Arguments + /// + /// * `width` - Width in pixels + /// * `height` - Height in pixels + /// * `fourcc` - Four character code (pixelformat) + /// + /// # Example + /// + /// ``` + /// use moq_v4l::{Format, FourCC}; + /// let fmt = Format::new(640, 480, FourCC::new(b"YUYV")); + /// ``` + pub 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(), + colorspace: Colorspace::Default, + quantization: Quantization::Default, + transfer: TransferFunction::Default, + } + } +} + +impl fmt::Display for Format { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "width : {}", self.width)?; + writeln!(f, "height : {}", self.height)?; + writeln!(f, "fourcc : {}", self.fourcc)?; + writeln!(f, "field : {}", self.field_order)?; + writeln!(f, "stride : {}", self.stride)?; + writeln!(f, "size : {}", self.size)?; + writeln!(f, "colorspace : {}", self.colorspace)?; + writeln!(f, "quantization : {}", self.quantization)?; + writeln!(f, "transfer : {}", self.transfer)?; + Ok(()) + } +} + +impl From for Format { + fn from(fmt: v4l2_pix_format) -> Self { + Self { + width: fmt.width, + height: fmt.height, + fourcc: FourCC::from(fmt.pixelformat), + field_order: FieldOrder::try_from(fmt.field).expect("Invalid field order"), + stride: fmt.bytesperline, + size: fmt.sizeimage, + flags: Flags::from(fmt.flags), + colorspace: Colorspace::try_from(fmt.colorspace).expect("Invalid colorspace"), + quantization: Quantization::try_from(fmt.quantization).expect("Invalid quantization"), + transfer: TransferFunction::try_from(fmt.xfer_func).expect("Invalid transfer function"), + } + } +} + +impl From for v4l2_pix_format { + fn from(format: Format) -> Self { + Self { + width: format.width, + height: format.height, + pixelformat: format.fourcc.into(), + field: format.field_order as u32, + bytesperline: format.stride, + sizeimage: format.size, + colorspace: format.colorspace as u32, + flags: format.flags.into(), + quantization: format.quantization as u32, + xfer_func: format.transfer as u32, + ..unsafe { mem::zeroed() } + } + } +} diff --git a/rs/moq-v4l/src/format/quantization.rs b/rs/moq-v4l/src/format/quantization.rs new file mode 100644 index 0000000000..5c64df986c --- /dev/null +++ b/rs/moq-v4l/src/format/quantization.rs @@ -0,0 +1,40 @@ +use std::convert::TryFrom; +use std::fmt; + +#[derive(Debug, Copy, Clone)] +#[repr(u32)] +/// Quantization for the colorspace. +/// +/// The driver decides this for capture streams and the user sets +/// it for output streams. +pub enum Quantization { + /// default for the colorspace + Default = 0, + /// maps to the full range; 0 goes to 0 and 1 goes to 255 + FullRange = 1, + /// maps to a limited range; 0 goes to 16 and 1 goes to 235 + LimitedRange = 2, +} + +impl fmt::Display for Quantization { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => write!(f, "default"), + Self::FullRange => write!(f, "full range"), + Self::LimitedRange => write!(f, "limited range"), + } + } +} + +impl TryFrom for Quantization { + type Error = (); + + fn try_from(code: u32) -> Result { + match code { + 0 => Ok(Self::Default), + 1 => Ok(Self::FullRange), + 2 => Ok(Self::LimitedRange), + _ => Err(()), + } + } +} diff --git a/rs/moq-v4l/src/format/transfer.rs b/rs/moq-v4l/src/format/transfer.rs new file mode 100644 index 0000000000..486f8dcba1 --- /dev/null +++ b/rs/moq-v4l/src/format/transfer.rs @@ -0,0 +1,58 @@ +use std::convert::TryFrom; +use std::fmt; + +#[derive(Debug, Copy, Clone)] +#[repr(u32)] +/// Transfer function for the colorspace. The driver decides this for capture streams and the user +/// sets it for output streams. +pub enum TransferFunction { + /// default from the colorspace + Default = 0, + /// Rec. 709 transfer function + Rec709 = 1, + /// sRGB transfer function + SRGB = 2, + /// opRGB transfer function + OPRGB = 3, + /// SMPTE 230M transfer function + SMPTE240M = 4, + /// No transfer function + None = 5, + /// DCI-P3 transfer function + DCIP3 = 6, + /// SMPTE 2084 transfer function + SMPTE2084 = 7, +} + +impl fmt::Display for TransferFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Default => write!(f, "default transfer function"), + Self::Rec709 => write!(f, "Rec. 709 transfer function"), + Self::SRGB => write!(f, "sRGB transfer function"), + Self::OPRGB => write!(f, "opRGB transfer function"), + Self::SMPTE240M => write!(f, "SMPTE 240M transfer function"), + Self::None => write!(f, "No transfer function"), + Self::DCIP3 => write!(f, "DCI-P3 transfer function"), + Self::SMPTE2084 => write!(f, "SMPTE 2084 transfer function"), + } + } +} + +impl TryFrom for TransferFunction { + type Error = (); + + fn try_from(colorspace_code: u32) -> Result { + match colorspace_code { + 0 => Ok(Self::Default), + 1 => Ok(Self::Rec709), + 2 => Ok(Self::SRGB), + 3 => Ok(Self::OPRGB), + 4 => Ok(Self::SMPTE240M), + 5 => Ok(Self::None), + 6 => Ok(Self::DCIP3), + 7 => Ok(Self::SMPTE2084), + _ => Err(()), + } + } +} diff --git a/rs/moq-v4l/src/fraction.rs b/rs/moq-v4l/src/fraction.rs new file mode 100644 index 0000000000..83c778ec5a --- /dev/null +++ b/rs/moq-v4l/src/fraction.rs @@ -0,0 +1,55 @@ +use crate::sys::*; +use std::fmt; + +#[derive(Debug, Default, Clone, Copy)] +/// Fraction used for timing settings +pub struct Fraction { + pub numerator: u32, + pub denominator: u32, +} + +impl Fraction { + /// Returns a fraction representation + /// + /// # Arguments + /// + /// * `num` - Numerator + /// * `denom` - Denominator + /// + /// # Example + /// + /// ``` + /// use moq_v4l::fraction::Fraction; + /// let frac = Fraction::new(30, 1); + /// ``` + pub fn new(num: u32, denom: u32) -> Self { + Fraction { + numerator: num, + denominator: denom, + } + } +} + +impl fmt::Display for Fraction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}/{}", self.numerator, self.denominator) + } +} + +impl From for Fraction { + fn from(frac: v4l2_fract) -> Self { + Self { + numerator: frac.numerator, + denominator: frac.denominator, + } + } +} + +impl From for v4l2_fract { + fn from(fraction: Fraction) -> Self { + Self { + numerator: fraction.numerator, + denominator: fraction.denominator, + } + } +} diff --git a/rs/moq-v4l/src/frameinterval.rs b/rs/moq-v4l/src/frameinterval.rs new file mode 100644 index 0000000000..77dd54eb8f --- /dev/null +++ b/rs/moq-v4l/src/frameinterval.rs @@ -0,0 +1,95 @@ +use std::convert::TryFrom; +use std::fmt; + +use crate::sys::*; +use crate::{format::FourCC, fraction::Fraction}; + +#[derive(Debug)] +/// Format description as returned by [`crate::v4l2::vidioc::VIDIOC_ENUM_FRAMEINTERVALS`] +pub struct FrameInterval { + pub index: u32, + pub fourcc: FourCC, + pub width: u32, + pub height: u32, + pub typ: u32, + pub interval: FrameIntervalEnum, +} + +impl fmt::Display for FrameInterval { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.interval.fmt(f) + } +} + +#[derive(Debug)] +pub enum FrameIntervalEnum { + Discrete(Fraction), + Stepwise(Stepwise), +} + +impl fmt::Display for FrameIntervalEnum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + FrameIntervalEnum::Discrete(val) => write!(f, "Discrete({})", val)?, + FrameIntervalEnum::Stepwise(val) => write!(f, "Stepwise({})", val)?, + } + + Ok(()) + } +} + +impl TryFrom for FrameIntervalEnum { + type Error = String; + + fn try_from(desc: v4l2_frmivalenum) -> Result { + unsafe { + // Unsafe because of access to union __bindgen_anon_1 + #[allow(non_upper_case_globals)] + match desc.type_ { + v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_DISCRETE => Ok(FrameIntervalEnum::Discrete(Fraction::from( + desc.__bindgen_anon_1.discrete, + ))), + v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_CONTINUOUS | v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_STEPWISE => Ok({ + FrameIntervalEnum::Stepwise(Stepwise { + min: Fraction::from(desc.__bindgen_anon_1.stepwise.min), + max: Fraction::from(desc.__bindgen_anon_1.stepwise.max), + step: Fraction::from(desc.__bindgen_anon_1.stepwise.step), + }) + }), + typ => Err(format!("Unknown frame size type: {}", typ)), + } + } + } +} + +#[derive(Debug)] +pub struct Stepwise { + /// Minimum frame interval (in seconds). + pub min: Fraction, + /// Maximum frame interval (in seconds). + pub max: Fraction, + /// Frame interval step size (in seconds). + pub step: Fraction, +} + +impl fmt::Display for Stepwise { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{} - {} with step {}", self.min, self.max, self.step)?; + Ok(()) + } +} + +impl TryFrom for FrameInterval { + type Error = String; + + fn try_from(desc: v4l2_frmivalenum) -> Result { + Ok(FrameInterval { + index: desc.index, + fourcc: FourCC::from(desc.pixel_format), + width: desc.width, + height: desc.height, + typ: desc.type_, + interval: FrameIntervalEnum::try_from(desc)?, + }) + } +} diff --git a/rs/moq-v4l/src/framesize.rs b/rs/moq-v4l/src/framesize.rs new file mode 100644 index 0000000000..809ae227f3 --- /dev/null +++ b/rs/moq-v4l/src/framesize.rs @@ -0,0 +1,141 @@ +use std::convert::TryFrom; +use std::fmt; + +use crate::format::FourCC; +use crate::sys::*; + +#[derive(Debug)] +/// Format description as returned by [`crate::v4l2::vidioc::VIDIOC_ENUM_FRAMESIZES`] +pub struct FrameSize { + pub index: u32, + pub fourcc: FourCC, + pub typ: u32, + pub size: FrameSizeEnum, +} + +impl fmt::Display for FrameSize { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.size.fmt(f) + } +} + +#[derive(Debug)] +pub enum FrameSizeEnum { + Discrete(Discrete), + Stepwise(Stepwise), +} + +impl FrameSizeEnum { + pub fn to_discrete(self) -> impl IntoIterator { + match self { + Self::Discrete(discrete) => vec![discrete], + Self::Stepwise(stepwise) => { + let mut discrete = Vec::new(); + + for width in (stepwise.min_width..=stepwise.max_width).step_by(stepwise.step_width as usize) { + for height in (stepwise.min_height..=stepwise.max_height).step_by(stepwise.step_height as usize) { + discrete.push(Discrete { width, height }); + } + } + + discrete + } + } + } +} + +impl fmt::Display for FrameSizeEnum { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + FrameSizeEnum::Discrete(val) => write!(f, "Discrete({})", val)?, + FrameSizeEnum::Stepwise(val) => write!(f, "Stepwise({})", val)?, + } + + Ok(()) + } +} + +impl TryFrom for FrameSizeEnum { + type Error = String; + + fn try_from(desc: v4l2_frmsizeenum) -> Result { + unsafe { + // Unsafe because of access to union __bindgen_anon_1 + #[allow(non_upper_case_globals)] + match desc.type_ { + v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_DISCRETE => Ok({ + FrameSizeEnum::Discrete(Discrete { + width: desc.__bindgen_anon_1.discrete.width, + height: desc.__bindgen_anon_1.discrete.height, + }) + }), + v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_STEPWISE | v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_CONTINUOUS => Ok({ + FrameSizeEnum::Stepwise(Stepwise { + min_width: desc.__bindgen_anon_1.stepwise.min_width, + max_width: desc.__bindgen_anon_1.stepwise.max_width, + step_width: desc.__bindgen_anon_1.stepwise.step_width, + min_height: desc.__bindgen_anon_1.stepwise.min_height, + max_height: desc.__bindgen_anon_1.stepwise.max_height, + step_height: desc.__bindgen_anon_1.stepwise.step_height, + }) + }), + typ => Err(format!("Unknown frame size type: {}", typ)), + } + } + } +} + +#[derive(Debug)] +pub struct Discrete { + /// Width of the frame (in pixels). + pub width: u32, + /// Height of the frame (in pixels). + pub height: u32, +} + +impl fmt::Display for Discrete { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}x{}", self.width, self.height)?; + Ok(()) + } +} + +#[derive(Debug)] +pub struct Stepwise { + /// Minimum frame width (in pixels). + pub min_width: u32, + /// Maximum frame width (in pixels). + pub max_width: u32, + /// Frame width step size (in pixels). + pub step_width: u32, + /// Minimum frame height (in pixels). + pub min_height: u32, + /// Maximum frame height (in pixels). + pub max_height: u32, + /// Frame height step size (in pixels). + pub step_height: u32, +} + +impl fmt::Display for Stepwise { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}x{} - {}x{} with step {}/{}", + self.min_width, self.min_height, self.max_width, self.max_height, self.step_width, self.step_height, + )?; + Ok(()) + } +} + +impl TryFrom for FrameSize { + type Error = String; + + fn try_from(desc: v4l2_frmsizeenum) -> Result { + Ok(FrameSize { + index: desc.index, + typ: desc.type_, + fourcc: FourCC::from(desc.pixel_format), + size: FrameSizeEnum::try_from(desc)?, + }) + } +} diff --git a/rs/moq-v4l/src/io/mmap/arena.rs b/rs/moq-v4l/src/io/mmap/arena.rs new file mode 100644 index 0000000000..ebaffbca54 --- /dev/null +++ b/rs/moq-v4l/src/io/mmap/arena.rs @@ -0,0 +1,141 @@ +use std::{io, mem, ptr, slice, sync::Arc}; + +use crate::buffer; +use crate::device::Handle; +use crate::memory::Memory; +use crate::sys::*; +use crate::v4l2; + +/// Manage mapped buffers +/// +/// All buffers are unmapped in the Drop impl. +/// In case of errors during unmapping, we panic because there is memory corruption going on. +pub struct Arena<'a> { + handle: Arc, + pub bufs: Vec<&'a mut [u8]>, + pub buf_type: buffer::Type, +} + +impl<'a> Arena<'a> { + /// Returns a new buffer manager instance + /// + /// You usually do not need to use this directly. + /// A MappedBufferStream creates its own manager instance by default. + /// + /// # Arguments + /// + /// * `handle` - Device handle to get its file descriptor + /// * `buf_type` - Type of the buffers + pub fn new(handle: Arc, buf_type: buffer::Type) -> Self { + Arena { + handle, + bufs: Vec::new(), + buf_type, + } + } + + fn buffer_desc(&self) -> v4l2_buffer { + v4l2_buffer { + type_: self.buf_type as u32, + memory: Memory::Mmap as u32, + ..unsafe { mem::zeroed() } + } + } + + fn requestbuffers_desc(&self) -> v4l2_requestbuffers { + v4l2_requestbuffers { + type_: self.buf_type as u32, + memory: Memory::Mmap as u32, + ..unsafe { mem::zeroed() } + } + } + + pub fn allocate(&mut self, count: u32) -> io::Result { + let mut v4l2_reqbufs = v4l2_requestbuffers { + count, + ..self.requestbuffers_desc() + }; + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_REQBUFS, + &mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void, + )?; + } + + for index in 0..v4l2_reqbufs.count { + let mut v4l2_buf = v4l2_buffer { + index, + ..self.buffer_desc() + }; + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_QUERYBUF, + &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void, + )?; + + let ptr = v4l2::mmap( + ptr::null_mut(), + v4l2_buf.length as usize, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED, + self.handle.fd(), + v4l2_buf.m.offset as libc::off_t, + )?; + + let slice = slice::from_raw_parts_mut::(ptr as *mut u8, v4l2_buf.length as usize); + self.bufs.push(slice); + } + } + + Ok(v4l2_reqbufs.count) + } + + pub fn release(&mut self) -> io::Result<()> { + for buf in &self.bufs { + unsafe { + v4l2::munmap(buf.as_ptr() as *mut core::ffi::c_void, buf.len())?; + } + } + + // free all buffers by requesting 0 + let mut v4l2_reqbufs = v4l2_requestbuffers { + count: 0, + ..self.requestbuffers_desc() + }; + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_REQBUFS, + &mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.bufs.clear(); + Ok(()) + } +} + +impl<'a> Drop for Arena<'a> { + fn drop(&mut self) { + if self.bufs.is_empty() { + // nothing to do + return; + } + + if let Err(e) = self.release() { + if let Some(code) = e.raw_os_error() { + // ENODEV means the file descriptor wrapped in the handle became invalid, most + // likely because the device was unplugged or the connection (USB, PCI, ..) + // broke down. Handle this case gracefully by ignoring it. + if code == 19 { + /* ignore */ + return; + } + } + + panic!("{:?}", e) + } + } +} diff --git a/rs/moq-v4l/src/io/mmap/mod.rs b/rs/moq-v4l/src/io/mmap/mod.rs new file mode 100644 index 0000000000..81957832fc --- /dev/null +++ b/rs/moq-v4l/src/io/mmap/mod.rs @@ -0,0 +1,4 @@ +pub(crate) mod arena; + +pub mod stream; +pub use stream::Stream; diff --git a/rs/moq-v4l/src/io/mmap/stream.rs b/rs/moq-v4l/src/io/mmap/stream.rs new file mode 100644 index 0000000000..57bb1a2073 --- /dev/null +++ b/rs/moq-v4l/src/io/mmap/stream.rs @@ -0,0 +1,285 @@ +use std::convert::TryInto; +use std::time::Duration; +use std::{io, mem, sync::Arc}; + +use crate::buffer::{Metadata, Type}; +use crate::device::{Device, Handle}; +use crate::io::mmap::arena::Arena; +use crate::io::traits::{CaptureStream, OutputStream, Stream as StreamTrait}; +use crate::memory::Memory; +use crate::sys::*; +use crate::v4l2; + +/// Stream of mapped buffers +/// +/// An arena instance is used internally for buffer handling. +pub struct Stream<'a> { + handle: Arc, + arena: Arena<'a>, + arena_index: usize, + buf_type: Type, + buf_meta: Vec, + timeout: Option, + + active: bool, +} + +impl<'a> Stream<'a> { + /// Returns a stream for frame capturing + /// + /// # Arguments + /// + /// * `dev` - Capture device ref to get its file descriptor + /// * `buf_type` - Type of the buffers + /// + /// # Example + /// + /// ``` + /// use moq_v4l::buffer::Type; + /// use moq_v4l::device::Device; + /// use moq_v4l::io::mmap::Stream; + /// + /// let dev = Device::new(0); + /// if let Ok(dev) = dev { + /// let stream = Stream::new(&dev, Type::VideoCapture); + /// } + /// ``` + pub fn new(dev: &Device, buf_type: Type) -> io::Result { + Stream::with_buffers(dev, buf_type, 4) + } + + pub fn with_buffers(dev: &Device, buf_type: Type, buf_count: u32) -> io::Result { + let mut arena = Arena::new(dev.handle(), buf_type); + let count = arena.allocate(buf_count)?; + let mut buf_meta = Vec::new(); + buf_meta.resize(count as usize, Metadata::default()); + + Ok(Stream { + handle: dev.handle(), + arena, + arena_index: 0, + buf_type, + buf_meta, + active: false, + timeout: None, + }) + } + + /// Returns the raw device handle + pub fn handle(&self) -> Arc { + self.handle.clone() + } + + /// Sets a timeout of the v4l file handle. + pub fn set_timeout(&mut self, duration: Duration) { + self.timeout = Some(duration.as_millis().try_into().unwrap()); + } + + /// Clears the timeout of the v4l file handle. + pub fn clear_timeout(&mut self) { + self.timeout = None; + } + + fn buffer_desc(&self) -> v4l2_buffer { + v4l2_buffer { + type_: self.buf_type as u32, + memory: Memory::Mmap as u32, + ..unsafe { mem::zeroed() } + } + } +} + +impl<'a> Drop for Stream<'a> { + fn drop(&mut self) { + if let Err(e) = self.stop() { + if let Some(code) = e.raw_os_error() { + // ENODEV means the file descriptor wrapped in the handle became invalid, most + // likely because the device was unplugged or the connection (USB, PCI, ..) + // broke down. Handle this case gracefully by ignoring it. + if code == 19 { + /* ignore */ + return; + } + } + + panic!("{:?}", e) + } + } +} + +impl<'a> StreamTrait for Stream<'a> { + type Item = [u8]; + + fn start(&mut self) -> io::Result<()> { + unsafe { + let mut typ = self.buf_type as u32; + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_STREAMON, + &mut typ as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.active = true; + Ok(()) + } + + fn stop(&mut self) -> io::Result<()> { + unsafe { + let mut typ = self.buf_type as u32; + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_STREAMOFF, + &mut typ as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.active = false; + Ok(()) + } +} + +impl<'a, 'b> CaptureStream<'b> for Stream<'a> { + fn queue(&mut self, index: usize) -> io::Result<()> { + let mut v4l2_buf = v4l2_buffer { + index: index as u32, + ..self.buffer_desc() + }; + + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_QBUF, + &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void, + )?; + } + + Ok(()) + } + + fn dequeue(&mut self) -> io::Result { + let mut v4l2_buf = self.buffer_desc(); + + if self.handle.poll(libc::POLLIN, self.timeout.unwrap_or(-1))? == 0 { + // This condition can only happen if there was a timeout. + // A timeout is only possible if the `timeout` value is non-zero, meaning we should + // propagate it to the caller. + return Err(io::Error::new(io::ErrorKind::TimedOut, "VIDIOC_DQBUF")); + } + + unsafe { + 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) + } + + fn next(&'b mut self) -> io::Result<(&'b Self::Item, &'b Metadata)> { + if !self.active { + // Enqueue all buffers once on stream start + for index in 0..self.arena.bufs.len() { + CaptureStream::queue(self, index)?; + } + + self.start()?; + } else { + CaptureStream::queue(self, self.arena_index)?; + } + + self.arena_index = CaptureStream::dequeue(self)?; + + // The index used to access the buffer elements is given to us by v4l2, so we assume it + // will always be valid. + let bytes = &self.arena.bufs[self.arena_index]; + let meta = &self.buf_meta[self.arena_index]; + Ok((bytes, meta)) + } +} + +impl<'a, 'b> OutputStream<'b> for Stream<'a> { + fn queue(&mut self, index: usize) -> io::Result<()> { + let mut v4l2_buf = v4l2_buffer { + index: index as u32, + ..self.buffer_desc() + }; + unsafe { + // output settings + // + // MetaData.bytesused is initialized to 0. For an output device, when bytesused is + // set to 0 v4l2 will set it to the size of the plane: + // https://www.kernel.org/doc/html/v4.15/media/uapi/v4l/buffer.html#struct-v4l2-plane + v4l2_buf.bytesused = self.buf_meta[index].bytesused; + v4l2_buf.field = self.buf_meta[index].field; + + if self.handle.poll(libc::POLLOUT, self.timeout.unwrap_or(-1))? == 0 { + // This condition can only happen if there was a timeout. + // A timeout is only possible if the `timeout` value is non-zero, meaning we should + // propagate it to the caller. + return Err(io::Error::new(io::ErrorKind::TimedOut, "VIDIOC_QBUF")); + } + + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_QBUF, + &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void, + ) + } + } + + fn dequeue(&mut self) -> io::Result { + let mut v4l2_buf = self.buffer_desc(); + + unsafe { + 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) + } + + fn next(&'b mut self) -> io::Result<(&'b mut Self::Item, &'b mut Metadata)> { + let init = !self.active; + if !self.active { + self.start()?; + } + + // Only queue and dequeue once the buffer has been filled at the call site. The initial + // call to this function from the call site will happen just after the buffers have been + // allocated, meaning we need to return the empty buffer initially so it can be filled. + if !init { + OutputStream::queue(self, self.arena_index)?; + self.arena_index = OutputStream::dequeue(self)?; + } + + // The index used to access the buffer elements is given to us by v4l2, so we assume it + // will always be valid. + let bytes = &mut self.arena.bufs[self.arena_index]; + let meta = &mut self.buf_meta[self.arena_index]; + Ok((bytes, meta)) + } +} diff --git a/rs/moq-v4l/src/io/mod.rs b/rs/moq-v4l/src/io/mod.rs new file mode 100644 index 0000000000..983175c20b --- /dev/null +++ b/rs/moq-v4l/src/io/mod.rs @@ -0,0 +1,4 @@ +pub mod traits; + +pub mod mmap; +pub mod userptr; diff --git a/rs/moq-v4l/src/io/traits.rs b/rs/moq-v4l/src/io/traits.rs new file mode 100644 index 0000000000..6b431d4e71 --- /dev/null +++ b/rs/moq-v4l/src/io/traits.rs @@ -0,0 +1,38 @@ +use std::io; + +use crate::buffer::Metadata; + +/// Streaming I/O +pub trait Stream { + type Item: ?Sized; + + /// Start streaming, takes exclusive ownership of a device + fn start(&mut self) -> io::Result<()>; + + /// Stop streaming, frees all buffers + fn stop(&mut self) -> io::Result<()>; +} + +pub trait CaptureStream<'a>: Stream { + /// Insert a buffer into the drivers' incoming queue + fn queue(&mut self, index: usize) -> io::Result<()>; + + /// Remove a buffer from the drivers' outgoing queue + fn dequeue(&mut self) -> io::Result; + + /// Fetch a new frame by first queueing and then dequeueing. + /// First time initialization is performed if necessary. + fn next(&'a mut self) -> io::Result<(&'a Self::Item, &'a Metadata)>; +} + +pub trait OutputStream<'a>: Stream { + /// Insert a buffer into the drivers' incoming queue + fn queue(&mut self, index: usize) -> io::Result<()>; + + /// Remove a buffer from the drivers' outgoing queue + fn dequeue(&mut self) -> io::Result; + + /// Dump a new frame by first queueing and then dequeueing. + /// First time initialization is performed if necessary. + fn next(&'a mut self) -> io::Result<(&'a mut Self::Item, &'a mut Metadata)>; +} diff --git a/rs/moq-v4l/src/io/userptr/arena.rs b/rs/moq-v4l/src/io/userptr/arena.rs new file mode 100644 index 0000000000..890aa03b11 --- /dev/null +++ b/rs/moq-v4l/src/io/userptr/arena.rs @@ -0,0 +1,119 @@ +use std::{io, mem, sync::Arc}; + +use crate::buffer; +use crate::device::Handle; +use crate::memory::Memory; +use crate::sys::*; +use crate::v4l2; + +/// Manage user allocated buffers +/// +/// All buffers are released in the Drop impl. +pub struct Arena { + handle: Arc, + pub bufs: Vec>, + pub buf_type: buffer::Type, +} + +impl Arena { + /// Returns a new buffer manager instance + /// + /// You usually do not need to use this directly. + /// A UserBufferStream creates its own manager instance by default. + /// + /// # Arguments + /// + /// * `dev` - Device handle to get its file descriptor + /// * `buf_type` - Type of the buffers + pub fn new(handle: Arc, buf_type: buffer::Type) -> Self { + Arena { + handle, + bufs: Vec::new(), + buf_type, + } + } + + fn requestbuffers_desc(&self) -> v4l2_requestbuffers { + v4l2_requestbuffers { + type_: self.buf_type as u32, + memory: Memory::UserPtr as u32, + ..unsafe { mem::zeroed() } + } + } + + pub fn allocate(&mut self, count: u32) -> io::Result { + // we need to get the maximum buffer size from the format first + let mut v4l2_fmt = v4l2_format { + type_: self.buf_type as u32, + ..unsafe { mem::zeroed() } + }; + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_G_FMT, + &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, + )?; + } + + let mut v4l2_reqbufs = v4l2_requestbuffers { + count, + ..self.requestbuffers_desc() + }; + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_REQBUFS, + &mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void, + )?; + } + + // allocate the new user buffers + self.bufs.resize(v4l2_reqbufs.count as usize, Vec::new()); + for i in 0..v4l2_reqbufs.count { + let buf = &mut self.bufs[i as usize]; + unsafe { + buf.resize(v4l2_fmt.fmt.pix.sizeimage as usize, 0); + } + } + + Ok(v4l2_reqbufs.count) + } + + pub fn release(&mut self) -> io::Result<()> { + // free all buffers by requesting 0 + let mut v4l2_reqbufs = v4l2_requestbuffers { + count: 0, + ..self.requestbuffers_desc() + }; + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_REQBUFS, + &mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void, + ) + } + } +} + +impl Drop for Arena { + fn drop(&mut self) { + if self.bufs.is_empty() { + // nothing to do + return; + } + + if let Err(e) = self.release() { + if let Some(code) = e.raw_os_error() { + // ENODEV means the file descriptor wrapped in the handle became invalid, most + // likely because the device was unplugged or the connection (USB, PCI, ..) + // broke down. Handle this case gracefully by ignoring it. + if code == 19 { + /* ignore */ + return; + } + } + + panic!("{:?}", e) + } + } +} diff --git a/rs/moq-v4l/src/io/userptr/mod.rs b/rs/moq-v4l/src/io/userptr/mod.rs new file mode 100644 index 0000000000..81957832fc --- /dev/null +++ b/rs/moq-v4l/src/io/userptr/mod.rs @@ -0,0 +1,4 @@ +pub(crate) mod arena; + +pub mod stream; +pub use stream::Stream; diff --git a/rs/moq-v4l/src/io/userptr/stream.rs b/rs/moq-v4l/src/io/userptr/stream.rs new file mode 100644 index 0000000000..1f5b2b51c6 --- /dev/null +++ b/rs/moq-v4l/src/io/userptr/stream.rs @@ -0,0 +1,214 @@ +use std::convert::TryInto; +use std::time::Duration; +use std::{io, mem, sync::Arc}; + +use crate::buffer::{Metadata, Type}; +use crate::device::{Device, Handle}; +use crate::io::traits::{CaptureStream, Stream as StreamTrait}; +use crate::io::userptr::arena::Arena; +use crate::memory::Memory; +use crate::sys::*; +use crate::v4l2; + +/// Stream of user buffers +/// +/// An arena instance is used internally for buffer handling. +pub struct Stream { + handle: Arc, + arena: Arena, + arena_index: usize, + buf_type: Type, + buf_meta: Vec, + timeout: Option, + + active: bool, +} + +impl Stream { + /// Returns a stream for frame capturing + /// + /// # Arguments + /// + /// * `dev` - Device ref to get its file descriptor + /// * `buf_type` - Type of the buffers + /// + /// # Example + /// + /// ``` + /// use moq_v4l::buffer::Type; + /// use moq_v4l::device::Device; + /// use moq_v4l::io::userptr::Stream; + /// + /// let dev = Device::new(0); + /// if let Ok(dev) = dev { + /// let stream = Stream::new(&dev, Type::VideoCapture); + /// } + /// ``` + pub fn new(dev: &Device, buf_type: Type) -> io::Result { + Stream::with_buffers(dev, buf_type, 4) + } + + pub fn with_buffers(dev: &Device, buf_type: Type, buf_count: u32) -> io::Result { + let mut arena = Arena::new(dev.handle(), buf_type); + let count = arena.allocate(buf_count)?; + let mut buf_meta = Vec::new(); + buf_meta.resize(count as usize, Metadata::default()); + + Ok(Stream { + handle: dev.handle(), + arena, + arena_index: 0, + buf_type, + buf_meta, + active: false, + timeout: None, + }) + } + + /// Returns the raw device handle + pub fn handle(&self) -> Arc { + self.handle.clone() + } + + /// Sets a timeout of the v4l file handle. + pub fn set_timeout(&mut self, duration: Duration) { + self.timeout = Some(duration.as_millis().try_into().unwrap()); + } + + /// Clears the timeout of the v4l file handle. + pub fn clear_timeout(&mut self) { + self.timeout = None; + } + + fn buffer_desc(&self) -> v4l2_buffer { + v4l2_buffer { + type_: self.buf_type as u32, + memory: Memory::UserPtr as u32, + ..unsafe { mem::zeroed() } + } + } +} + +impl Drop for Stream { + fn drop(&mut self) { + if let Err(e) = self.stop() { + if let Some(code) = e.raw_os_error() { + // ENODEV means the file descriptor wrapped in the handle became invalid, most + // likely because the device was unplugged or the connection (USB, PCI, ..) + // broke down. Handle this case gracefully by ignoring it. + if code == 19 { + /* ignore */ + return; + } + } + + panic!("{:?}", e) + } + } +} + +impl StreamTrait for Stream { + type Item = [u8]; + + fn start(&mut self) -> io::Result<()> { + unsafe { + let mut typ = self.buf_type as u32; + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_STREAMON, + &mut typ as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.active = true; + Ok(()) + } + + fn stop(&mut self) -> io::Result<()> { + unsafe { + let mut typ = self.buf_type as u32; + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_STREAMOFF, + &mut typ as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.active = false; + Ok(()) + } +} + +impl<'a> CaptureStream<'a> for Stream { + fn queue(&mut self, index: usize) -> io::Result<()> { + let buf = &mut self.arena.bufs[index]; + let mut v4l2_buf = v4l2_buffer { + index: index as u32, + m: v4l2_buffer__bindgen_ty_1 { + userptr: buf.as_ptr() as std::os::raw::c_ulong, + }, + length: buf.len() as u32, + ..self.buffer_desc() + }; + unsafe { + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_QBUF, + &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void, + )?; + } + + Ok(()) + } + + fn dequeue(&mut self) -> io::Result { + let mut v4l2_buf = self.buffer_desc(); + + if self.handle.poll(libc::POLLIN, self.timeout.unwrap_or(-1))? == 0 { + // This condition can only happen if there was a timeout. + // A timeout is only possible if the `timeout` value is non-zero, meaning we should + // propagate it to the caller. + return Err(io::Error::new(io::ErrorKind::TimedOut, "VIDIOC_DQBUF")); + } + + unsafe { + 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) + } + + fn next(&'a mut self) -> io::Result<(&'a Self::Item, &'a Metadata)> { + if !self.active { + // Enqueue all buffers once on stream start + for index in 0..self.arena.bufs.len() { + self.queue(index)?; + } + + self.start()?; + } else { + self.queue(self.arena_index)?; + } + + self.arena_index = self.dequeue()?; + + // The index used to access the buffer elements is given to us by v4l2, so we assume it + // will always be valid. + let bytes = &mut self.arena.bufs[self.arena_index]; + let meta = &self.buf_meta[self.arena_index]; + Ok((bytes, meta)) + } +} diff --git a/rs/moq-v4l/src/lib.rs b/rs/moq-v4l/src/lib.rs new file mode 100644 index 0000000000..7a3acf1361 --- /dev/null +++ b/rs/moq-v4l/src/lib.rs @@ -0,0 +1,102 @@ +//! Safe bindings for the kernel's Video4Linux 2 (v4l2) API, forked from the +//! `v4l` crate with the `videodev2.h` bindings checked in, so a build needs +//! neither libclang nor the kernel headers. Only the `v4l2` backend survived +//! the fork: every call is an ioctl on the device node, nothing links libv4l. +//! +//! # Overview +//! +//! Video devices on Linux can be accessed by path or by index (which then corresponds to a path), +//! e.g. "/dev/video0" for the device which first became known to the system. +//! +//! There are three methods of dealing with (capture) device memory: +//! * `MMAP` (memory region in device memory or kernel space, mapped into userspace) +//! * `User` pointer (memory region allocated in host memory, written into by the kernel) +//! * `DMA` (direct memory access for memory transfer without involving the CPU) +//! +//! The following schematic shows the `mmap` and `userptr` mechanisms: +//! +//! **mmap** +//! +//! 1. `device --[MAP]--> kernel --[MAP]--> user` +//! 2. `device --[DMA]--> kernel --[MAP]--> user` +//! +//! **userptr** +//! +//! 3. `device --[DMA]--> user` +//! +//! +//! It is important to note that user pointer is for device-to-user memory transfer whereas +//! DMA is for device-to-device transfer, e.g. directly uploading a captured frame into GPU +//! memory. +//! +//! As you can see, user pointer and DMA are potential candidates for zero-copy applications where +//! buffers should be writable. If a read-only buffer is good enough, MMAP buffers are fine and +//! do not incur any copy overhead either. Most (if not all) devices reporting streaming I/O +//! capabilities support MMAP buffer sharing, but not all support user pointer access. +//! +//! The regular user of this crate will mainly be interested in frame capturing. +//! Here is a very brief example of streaming I/O with memory mapped buffers: +//! +//! ```no_run +//! use moq_v4l::buffer::Type; +//! use moq_v4l::io::traits::CaptureStream; +//! use moq_v4l::prelude::*; +//! +//! let mut dev = Device::new(0).expect("Failed to open device"); +//! +//! let mut stream = +//! MmapStream::with_buffers(&mut dev, Type::VideoCapture, 4).expect("Failed to create buffer stream"); +//! +//! loop { +//! let (buf, meta) = stream.next().unwrap(); +//! println!( +//! "Buffer size: {}, seq: {}, timestamp: {}", +//! buf.len(), +//! meta.sequence, +//! meta.timestamp +//! ); +//!} +//!``` +//! +//! Have a look at the examples to learn more about device and buffer management. + +// Every call is a Linux ioctl, so elsewhere the crate is an empty stub and +// moq-video only depends on it there. +#![cfg(target_os = "linux")] + +pub mod sys; + +pub mod v4l2; + +pub mod buffer; +pub mod capability; +pub mod context; +pub mod control; +pub mod device; +pub mod format; +pub mod fraction; +pub mod frameinterval; +pub mod framesize; +pub mod memory; +pub mod parameters; +pub mod timestamp; +pub mod video; + +pub mod io; + +pub use { + capability::Capabilities, + control::Control, + device::Device, + format::{Format, FourCC}, + fraction::Fraction, + frameinterval::FrameInterval, + framesize::FrameSize, + memory::Memory, + timestamp::Timestamp, +}; + +pub mod prelude { + pub use crate::device::Device; + pub use crate::io::{mmap::Stream as MmapStream, userptr::Stream as UserptrStream}; +} diff --git a/rs/moq-v4l/src/memory.rs b/rs/moq-v4l/src/memory.rs new file mode 100644 index 0000000000..375f4ac5a9 --- /dev/null +++ b/rs/moq-v4l/src/memory.rs @@ -0,0 +1,23 @@ +use std::fmt; + +/// Memory used for buffer exchange +#[allow(clippy::unreadable_literal)] +#[rustfmt::skip] +#[repr(u32)] +pub enum Memory { + Mmap = 1, + UserPtr = 2, + Overlay = 3, + DmaBuf = 4, +} + +impl fmt::Display for Memory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Memory::Mmap => write!(f, "memory-mapped"), + Memory::UserPtr => write!(f, "user pointer"), + Memory::Overlay => write!(f, "overlay"), + Memory::DmaBuf => write!(f, "DMA buffered"), + } + } +} diff --git a/rs/moq-v4l/src/parameters.rs b/rs/moq-v4l/src/parameters.rs new file mode 100644 index 0000000000..66716baea4 --- /dev/null +++ b/rs/moq-v4l/src/parameters.rs @@ -0,0 +1,28 @@ +use bitflags::bitflags; +use std::fmt; + +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct Capabilities: u32 { + #[allow(clippy::unreadable_literal)] + const TIME_PER_FRAME = 0x1000; + } +} + +impl From for Capabilities { + fn from(caps: u32) -> Self { + Self::from_bits_truncate(caps) + } +} + +impl From for u32 { + fn from(capabilities: Capabilities) -> Self { + capabilities.bits() + } +} + +impl fmt::Display for Capabilities { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} diff --git a/rs/moq-v4l/src/sys/bindgen.sh b/rs/moq-v4l/src/sys/bindgen.sh new file mode 100755 index 0000000000..d7773e3950 --- /dev/null +++ b/rs/moq-v4l/src/sys/bindgen.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# Regenerates videodev2.rs from the host's kernel headers. Run on Linux with +# bindgen-cli and the kernel UAPI headers installed (linux-libc-dev on Debian); +# the output is arch-independent, so any 64-bit host produces the same file. +set -eu +cd "$(dirname "$0")" +echo '#include ' > wrapper.h +trap 'rm -f wrapper.h' EXIT +bindgen wrapper.h \ + --no-layout-tests \ + --allowlist-type 'v4l2.*' \ + --allowlist-var 'V4L2_.*' \ + --blocklist-type '(timeval|timespec|__time_t|__suseconds_t|__syscall_slong_t)' \ + --raw-line 'pub use libc::{timespec, timeval};' \ + -o videodev2.rs diff --git a/rs/moq-v4l/src/sys/mod.rs b/rs/moq-v4l/src/sys/mod.rs new file mode 100644 index 0000000000..83dc870861 --- /dev/null +++ b/rs/moq-v4l/src/sys/mod.rs @@ -0,0 +1,10 @@ +//! Raw `videodev2.h` bindings, generated by [bindgen](https://github.com/rust-lang/rust-bindgen) +//! via `bindgen.sh` and checked in. The output is plain C-ABI struct, enum, and +//! constant definitions with no layout tests, and `timeval` / `timespec` come +//! from `libc`, so one file serves every Linux target. +#![allow(clippy::all)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +include!("videodev2.rs"); diff --git a/rs/moq-v4l/src/sys/videodev2.rs b/rs/moq-v4l/src/sys/videodev2.rs new file mode 100644 index 0000000000..10c3fcd056 --- /dev/null +++ b/rs/moq-v4l/src/sys/videodev2.rs @@ -0,0 +1,3556 @@ +/* automatically generated by rust-bindgen 0.73.2 */ + +pub use libc::{timespec, timeval}; + +pub const V4L2_SEL_TGT_CROP: u32 = 0; +pub const V4L2_SEL_TGT_CROP_DEFAULT: u32 = 1; +pub const V4L2_SEL_TGT_CROP_BOUNDS: u32 = 2; +pub const V4L2_SEL_TGT_NATIVE_SIZE: u32 = 3; +pub const V4L2_SEL_TGT_COMPOSE: u32 = 256; +pub const V4L2_SEL_TGT_COMPOSE_DEFAULT: u32 = 257; +pub const V4L2_SEL_TGT_COMPOSE_BOUNDS: u32 = 258; +pub const V4L2_SEL_TGT_COMPOSE_PADDED: u32 = 259; +pub const V4L2_SEL_FLAG_GE: u32 = 1; +pub const V4L2_SEL_FLAG_LE: u32 = 2; +pub const V4L2_SEL_FLAG_KEEP_CONFIG: u32 = 4; +pub const V4L2_SEL_TGT_CROP_ACTIVE: u32 = 0; +pub const V4L2_SEL_TGT_COMPOSE_ACTIVE: u32 = 256; +pub const V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL: u32 = 0; +pub const V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL: u32 = 256; +pub const V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS: u32 = 2; +pub const V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS: u32 = 258; +pub const V4L2_SUBDEV_SEL_FLAG_SIZE_GE: u32 = 1; +pub const V4L2_SUBDEV_SEL_FLAG_SIZE_LE: u32 = 2; +pub const V4L2_SUBDEV_SEL_FLAG_KEEP_CONFIG: u32 = 4; +pub const V4L2_CTRL_CLASS_USER: u32 = 9961472; +pub const V4L2_CTRL_CLASS_CODEC: u32 = 10027008; +pub const V4L2_CTRL_CLASS_CAMERA: u32 = 10092544; +pub const V4L2_CTRL_CLASS_FM_TX: u32 = 10158080; +pub const V4L2_CTRL_CLASS_FLASH: u32 = 10223616; +pub const V4L2_CTRL_CLASS_JPEG: u32 = 10289152; +pub const V4L2_CTRL_CLASS_IMAGE_SOURCE: u32 = 10354688; +pub const V4L2_CTRL_CLASS_IMAGE_PROC: u32 = 10420224; +pub const V4L2_CTRL_CLASS_DV: u32 = 10485760; +pub const V4L2_CTRL_CLASS_FM_RX: u32 = 10551296; +pub const V4L2_CTRL_CLASS_RF_TUNER: u32 = 10616832; +pub const V4L2_CTRL_CLASS_DETECT: u32 = 10682368; +pub const V4L2_CTRL_CLASS_CODEC_STATELESS: u32 = 10747904; +pub const V4L2_CTRL_CLASS_COLORIMETRY: u32 = 10813440; +pub const V4L2_CID_BASE: u32 = 9963776; +pub const V4L2_CID_USER_BASE: u32 = 9963776; +pub const V4L2_CID_USER_CLASS: u32 = 9961473; +pub const V4L2_CID_BRIGHTNESS: u32 = 9963776; +pub const V4L2_CID_CONTRAST: u32 = 9963777; +pub const V4L2_CID_SATURATION: u32 = 9963778; +pub const V4L2_CID_HUE: u32 = 9963779; +pub const V4L2_CID_AUDIO_VOLUME: u32 = 9963781; +pub const V4L2_CID_AUDIO_BALANCE: u32 = 9963782; +pub const V4L2_CID_AUDIO_BASS: u32 = 9963783; +pub const V4L2_CID_AUDIO_TREBLE: u32 = 9963784; +pub const V4L2_CID_AUDIO_MUTE: u32 = 9963785; +pub const V4L2_CID_AUDIO_LOUDNESS: u32 = 9963786; +pub const V4L2_CID_BLACK_LEVEL: u32 = 9963787; +pub const V4L2_CID_AUTO_WHITE_BALANCE: u32 = 9963788; +pub const V4L2_CID_DO_WHITE_BALANCE: u32 = 9963789; +pub const V4L2_CID_RED_BALANCE: u32 = 9963790; +pub const V4L2_CID_BLUE_BALANCE: u32 = 9963791; +pub const V4L2_CID_GAMMA: u32 = 9963792; +pub const V4L2_CID_WHITENESS: u32 = 9963792; +pub const V4L2_CID_EXPOSURE: u32 = 9963793; +pub const V4L2_CID_AUTOGAIN: u32 = 9963794; +pub const V4L2_CID_GAIN: u32 = 9963795; +pub const V4L2_CID_HFLIP: u32 = 9963796; +pub const V4L2_CID_VFLIP: u32 = 9963797; +pub const V4L2_CID_POWER_LINE_FREQUENCY: u32 = 9963800; +pub const V4L2_CID_HUE_AUTO: u32 = 9963801; +pub const V4L2_CID_WHITE_BALANCE_TEMPERATURE: u32 = 9963802; +pub const V4L2_CID_SHARPNESS: u32 = 9963803; +pub const V4L2_CID_BACKLIGHT_COMPENSATION: u32 = 9963804; +pub const V4L2_CID_CHROMA_AGC: u32 = 9963805; +pub const V4L2_CID_COLOR_KILLER: u32 = 9963806; +pub const V4L2_CID_COLORFX: u32 = 9963807; +pub const V4L2_CID_AUTOBRIGHTNESS: u32 = 9963808; +pub const V4L2_CID_BAND_STOP_FILTER: u32 = 9963809; +pub const V4L2_CID_ROTATE: u32 = 9963810; +pub const V4L2_CID_BG_COLOR: u32 = 9963811; +pub const V4L2_CID_CHROMA_GAIN: u32 = 9963812; +pub const V4L2_CID_ILLUMINATORS_1: u32 = 9963813; +pub const V4L2_CID_ILLUMINATORS_2: u32 = 9963814; +pub const V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: u32 = 9963815; +pub const V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: u32 = 9963816; +pub const V4L2_CID_ALPHA_COMPONENT: u32 = 9963817; +pub const V4L2_CID_COLORFX_CBCR: u32 = 9963818; +pub const V4L2_CID_COLORFX_RGB: u32 = 9963819; +pub const V4L2_CID_LASTP1: u32 = 9963820; +pub const V4L2_CID_USER_MEYE_BASE: u32 = 9967872; +pub const V4L2_CID_USER_BTTV_BASE: u32 = 9967888; +pub const V4L2_CID_USER_S2255_BASE: u32 = 9967920; +pub const V4L2_CID_USER_SI476X_BASE: u32 = 9967936; +pub const V4L2_CID_USER_TI_VPE_BASE: u32 = 9967952; +pub const V4L2_CID_USER_SAA7134_BASE: u32 = 9967968; +pub const V4L2_CID_USER_ADV7180_BASE: u32 = 9967984; +pub const V4L2_CID_USER_TC358743_BASE: u32 = 9968000; +pub const V4L2_CID_USER_MAX217X_BASE: u32 = 9968016; +pub const V4L2_CID_USER_IMX_BASE: u32 = 9968048; +pub const V4L2_CID_USER_ATMEL_ISC_BASE: u32 = 9968064; +pub const V4L2_CID_USER_CODA_BASE: u32 = 9968096; +pub const V4L2_CID_USER_CCS_BASE: u32 = 9968112; +pub const V4L2_CID_USER_ALLEGRO_BASE: u32 = 9968240; +pub const V4L2_CID_USER_ISL7998X_BASE: u32 = 9968256; +pub const V4L2_CID_USER_DW100_BASE: u32 = 9968272; +pub const V4L2_CID_USER_ASPEED_BASE: u32 = 9968288; +pub const V4L2_CID_USER_NPCM_BASE: u32 = 9968304; +pub const V4L2_CID_USER_THP7312_BASE: u32 = 9968320; +pub const V4L2_CID_CODEC_BASE: u32 = 10029312; +pub const V4L2_CID_CODEC_CLASS: u32 = 10027009; +pub const V4L2_CID_MPEG_STREAM_TYPE: u32 = 10029312; +pub const V4L2_CID_MPEG_STREAM_PID_PMT: u32 = 10029313; +pub const V4L2_CID_MPEG_STREAM_PID_AUDIO: u32 = 10029314; +pub const V4L2_CID_MPEG_STREAM_PID_VIDEO: u32 = 10029315; +pub const V4L2_CID_MPEG_STREAM_PID_PCR: u32 = 10029316; +pub const V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: u32 = 10029317; +pub const V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: u32 = 10029318; +pub const V4L2_CID_MPEG_STREAM_VBI_FMT: u32 = 10029319; +pub const V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: u32 = 10029412; +pub const V4L2_CID_MPEG_AUDIO_ENCODING: u32 = 10029413; +pub const V4L2_CID_MPEG_AUDIO_L1_BITRATE: u32 = 10029414; +pub const V4L2_CID_MPEG_AUDIO_L2_BITRATE: u32 = 10029415; +pub const V4L2_CID_MPEG_AUDIO_L3_BITRATE: u32 = 10029416; +pub const V4L2_CID_MPEG_AUDIO_MODE: u32 = 10029417; +pub const V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: u32 = 10029418; +pub const V4L2_CID_MPEG_AUDIO_EMPHASIS: u32 = 10029419; +pub const V4L2_CID_MPEG_AUDIO_CRC: u32 = 10029420; +pub const V4L2_CID_MPEG_AUDIO_MUTE: u32 = 10029421; +pub const V4L2_CID_MPEG_AUDIO_AAC_BITRATE: u32 = 10029422; +pub const V4L2_CID_MPEG_AUDIO_AC3_BITRATE: u32 = 10029423; +pub const V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK: u32 = 10029424; +pub const V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK: u32 = 10029425; +pub const V4L2_CID_MPEG_VIDEO_ENCODING: u32 = 10029512; +pub const V4L2_CID_MPEG_VIDEO_ASPECT: u32 = 10029513; +pub const V4L2_CID_MPEG_VIDEO_B_FRAMES: u32 = 10029514; +pub const V4L2_CID_MPEG_VIDEO_GOP_SIZE: u32 = 10029515; +pub const V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: u32 = 10029516; +pub const V4L2_CID_MPEG_VIDEO_PULLDOWN: u32 = 10029517; +pub const V4L2_CID_MPEG_VIDEO_BITRATE_MODE: u32 = 10029518; +pub const V4L2_CID_MPEG_VIDEO_BITRATE: u32 = 10029519; +pub const V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: u32 = 10029520; +pub const V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: u32 = 10029521; +pub const V4L2_CID_MPEG_VIDEO_MUTE: u32 = 10029522; +pub const V4L2_CID_MPEG_VIDEO_MUTE_YUV: u32 = 10029523; +pub const V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE: u32 = 10029524; +pub const V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER: u32 = 10029525; +pub const V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: u32 = 10029526; +pub const V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: u32 = 10029527; +pub const V4L2_CID_MPEG_VIDEO_HEADER_MODE: u32 = 10029528; +pub const V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: u32 = 10029529; +pub const V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: u32 = 10029530; +pub const V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: u32 = 10029531; +pub const V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: u32 = 10029532; +pub const V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: u32 = 10029533; +pub const V4L2_CID_MPEG_VIDEO_VBV_SIZE: u32 = 10029534; +pub const V4L2_CID_MPEG_VIDEO_DEC_PTS: u32 = 10029535; +pub const V4L2_CID_MPEG_VIDEO_DEC_FRAME: u32 = 10029536; +pub const V4L2_CID_MPEG_VIDEO_VBV_DELAY: u32 = 10029537; +pub const V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER: u32 = 10029538; +pub const V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE: u32 = 10029539; +pub const V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE: u32 = 10029540; +pub const V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: u32 = 10029541; +pub const V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID: u32 = 10029542; +pub const V4L2_CID_MPEG_VIDEO_AU_DELIMITER: u32 = 10029543; +pub const V4L2_CID_MPEG_VIDEO_LTR_COUNT: u32 = 10029544; +pub const V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: u32 = 10029545; +pub const V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: u32 = 10029546; +pub const V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR: u32 = 10029547; +pub const V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD: u32 = 10029548; +pub const V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE: u32 = 10029549; +pub const V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: u32 = 10029582; +pub const V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: u32 = 10029583; +pub const V4L2_CID_FWHT_I_FRAME_QP: u32 = 10029602; +pub const V4L2_CID_FWHT_P_FRAME_QP: u32 = 10029603; +pub const V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: u32 = 10029612; +pub const V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: u32 = 10029613; +pub const V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: u32 = 10029614; +pub const V4L2_CID_MPEG_VIDEO_H263_MIN_QP: u32 = 10029615; +pub const V4L2_CID_MPEG_VIDEO_H263_MAX_QP: u32 = 10029616; +pub const V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: u32 = 10029662; +pub const V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: u32 = 10029663; +pub const V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: u32 = 10029664; +pub const V4L2_CID_MPEG_VIDEO_H264_MIN_QP: u32 = 10029665; +pub const V4L2_CID_MPEG_VIDEO_H264_MAX_QP: u32 = 10029666; +pub const V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: u32 = 10029667; +pub const V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: u32 = 10029668; +pub const V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: u32 = 10029669; +pub const V4L2_CID_MPEG_VIDEO_H264_I_PERIOD: u32 = 10029670; +pub const V4L2_CID_MPEG_VIDEO_H264_LEVEL: u32 = 10029671; +pub const V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: u32 = 10029672; +pub const V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: u32 = 10029673; +pub const V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: u32 = 10029674; +pub const V4L2_CID_MPEG_VIDEO_H264_PROFILE: u32 = 10029675; +pub const V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT: u32 = 10029676; +pub const V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH: u32 = 10029677; +pub const V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: u32 = 10029678; +pub const V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: u32 = 10029679; +pub const V4L2_CID_MPEG_VIDEO_H264_SEI_FRAME_PACKING: u32 = 10029680; +pub const V4L2_CID_MPEG_VIDEO_H264_SEI_FP_CURRENT_FRAME_0: u32 = 10029681; +pub const V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: u32 = 10029682; +pub const V4L2_CID_MPEG_VIDEO_H264_FMO: u32 = 10029683; +pub const V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: u32 = 10029684; +pub const V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP: u32 = 10029685; +pub const V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_DIRECTION: u32 = 10029686; +pub const V4L2_CID_MPEG_VIDEO_H264_FMO_CHANGE_RATE: u32 = 10029687; +pub const V4L2_CID_MPEG_VIDEO_H264_FMO_RUN_LENGTH: u32 = 10029688; +pub const V4L2_CID_MPEG_VIDEO_H264_ASO: u32 = 10029689; +pub const V4L2_CID_MPEG_VIDEO_H264_ASO_SLICE_ORDER: u32 = 10029690; +pub const V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING: u32 = 10029691; +pub const V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE: u32 = 10029692; +pub const V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER: u32 = 10029693; +pub const V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP: u32 = 10029694; +pub const V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: u32 = 10029695; +pub const V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: u32 = 10029696; +pub const V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: u32 = 10029697; +pub const V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: u32 = 10029698; +pub const V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: u32 = 10029699; +pub const V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: u32 = 10029700; +pub const V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP: u32 = 10029701; +pub const V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP: u32 = 10029702; +pub const V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR: u32 = 10029703; +pub const V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR: u32 = 10029704; +pub const V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR: u32 = 10029705; +pub const V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR: u32 = 10029706; +pub const V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR: u32 = 10029707; +pub const V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR: u32 = 10029708; +pub const V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L6_BR: u32 = 10029709; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: u32 = 10029712; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: u32 = 10029713; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: u32 = 10029714; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP: u32 = 10029715; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP: u32 = 10029716; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: u32 = 10029717; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: u32 = 10029718; +pub const V4L2_CID_MPEG_VIDEO_MPEG4_QPEL: u32 = 10029719; +pub const V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: u32 = 10029812; +pub const V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4: u32 = 10029813; +pub const V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES: u32 = 10029814; +pub const V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL: u32 = 10029815; +pub const V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS: u32 = 10029816; +pub const V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD: u32 = 10029817; +pub const V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: u32 = 10029818; +pub const V4L2_CID_MPEG_VIDEO_VPX_MIN_QP: u32 = 10029819; +pub const V4L2_CID_MPEG_VIDEO_VPX_MAX_QP: u32 = 10029820; +pub const V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP: u32 = 10029821; +pub const V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: u32 = 10029822; +pub const V4L2_CID_MPEG_VIDEO_VP8_PROFILE: u32 = 10029823; +pub const V4L2_CID_MPEG_VIDEO_VPX_PROFILE: u32 = 10029823; +pub const V4L2_CID_MPEG_VIDEO_VP9_PROFILE: u32 = 10029824; +pub const V4L2_CID_MPEG_VIDEO_VP9_LEVEL: u32 = 10029825; +pub const V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP: u32 = 10029912; +pub const V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP: u32 = 10029913; +pub const V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP: u32 = 10029914; +pub const V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP: u32 = 10029915; +pub const V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP: u32 = 10029916; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP: u32 = 10029917; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE: u32 = 10029918; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER: u32 = 10029919; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP: u32 = 10029920; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP: u32 = 10029921; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP: u32 = 10029922; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP: u32 = 10029923; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP: u32 = 10029924; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP: u32 = 10029925; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP: u32 = 10029926; +pub const V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: u32 = 10029927; +pub const V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: u32 = 10029928; +pub const V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION: u32 = 10029929; +pub const V4L2_CID_MPEG_VIDEO_HEVC_TIER: u32 = 10029930; +pub const V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH: u32 = 10029931; +pub const V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: u32 = 10029932; +pub const V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2: u32 = 10029933; +pub const V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2: u32 = 10029934; +pub const V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE: u32 = 10029935; +pub const V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD: u32 = 10029936; +pub const V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU: u32 = 10029937; +pub const V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED: u32 = 10029938; +pub const V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT: u32 = 10029939; +pub const V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB: u32 = 10029940; +pub const V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID: u32 = 10029941; +pub const V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING: u32 = 10029942; +pub const V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1: u32 = 10029943; +pub const V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT: u32 = 10029944; +pub const V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION: u32 = 10029945; +pub const V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE: u32 = 10029946; +pub const V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD: u32 = 10029947; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR: u32 = 10029948; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR: u32 = 10029949; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR: u32 = 10029950; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR: u32 = 10029951; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR: u32 = 10029952; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR: u32 = 10029953; +pub const V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR: u32 = 10029954; +pub const V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES: u32 = 10029955; +pub const V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR: u32 = 10029956; +pub const V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY: u32 = 10029957; +pub const V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: u32 = 10029958; +pub const V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP: u32 = 10029959; +pub const V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP: u32 = 10029960; +pub const V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP: u32 = 10029961; +pub const V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP: u32 = 10029962; +pub const V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP: u32 = 10029963; +pub const V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP: u32 = 10029964; +pub const V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY: u32 = 10029965; +pub const V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: u32 = 10029966; +pub const V4L2_CID_MPEG_VIDEO_AV1_PROFILE: u32 = 10029967; +pub const V4L2_CID_MPEG_VIDEO_AV1_LEVEL: u32 = 10029968; +pub const V4L2_CID_MPEG_VIDEO_AVERAGE_QP: u32 = 10029969; +pub const V4L2_CID_CODEC_CX2341X_BASE: u32 = 10031104; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: u32 = 10031104; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER: u32 = 10031105; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE: u32 = 10031106; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE: u32 = 10031107; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE: u32 = 10031108; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER: u32 = 10031109; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE: u32 = 10031110; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM: u32 = 10031111; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP: u32 = 10031112; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM: u32 = 10031113; +pub const V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP: u32 = 10031114; +pub const V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS: u32 = 10031115; +pub const V4L2_CID_CODEC_MFC51_BASE: u32 = 10031360; +pub const V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY: u32 = 10031360; +pub const V4L2_CID_MPEG_MFC51_VIDEO_DECODER_H264_DISPLAY_DELAY_ENABLE: u32 = 10031361; +pub const V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE: u32 = 10031362; +pub const V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE: u32 = 10031363; +pub const V4L2_CID_MPEG_MFC51_VIDEO_PADDING: u32 = 10031364; +pub const V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV: u32 = 10031365; +pub const V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT: u32 = 10031366; +pub const V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF: u32 = 10031367; +pub const V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY: u32 = 10031410; +pub const V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK: u32 = 10031411; +pub const V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH: u32 = 10031412; +pub const V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC: u32 = 10031413; +pub const V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P: u32 = 10031414; +pub const V4L2_CID_CAMERA_CLASS_BASE: u32 = 10094848; +pub const V4L2_CID_CAMERA_CLASS: u32 = 10092545; +pub const V4L2_CID_EXPOSURE_AUTO: u32 = 10094849; +pub const V4L2_CID_EXPOSURE_ABSOLUTE: u32 = 10094850; +pub const V4L2_CID_EXPOSURE_AUTO_PRIORITY: u32 = 10094851; +pub const V4L2_CID_PAN_RELATIVE: u32 = 10094852; +pub const V4L2_CID_TILT_RELATIVE: u32 = 10094853; +pub const V4L2_CID_PAN_RESET: u32 = 10094854; +pub const V4L2_CID_TILT_RESET: u32 = 10094855; +pub const V4L2_CID_PAN_ABSOLUTE: u32 = 10094856; +pub const V4L2_CID_TILT_ABSOLUTE: u32 = 10094857; +pub const V4L2_CID_FOCUS_ABSOLUTE: u32 = 10094858; +pub const V4L2_CID_FOCUS_RELATIVE: u32 = 10094859; +pub const V4L2_CID_FOCUS_AUTO: u32 = 10094860; +pub const V4L2_CID_ZOOM_ABSOLUTE: u32 = 10094861; +pub const V4L2_CID_ZOOM_RELATIVE: u32 = 10094862; +pub const V4L2_CID_ZOOM_CONTINUOUS: u32 = 10094863; +pub const V4L2_CID_PRIVACY: u32 = 10094864; +pub const V4L2_CID_IRIS_ABSOLUTE: u32 = 10094865; +pub const V4L2_CID_IRIS_RELATIVE: u32 = 10094866; +pub const V4L2_CID_AUTO_EXPOSURE_BIAS: u32 = 10094867; +pub const V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE: u32 = 10094868; +pub const V4L2_CID_WIDE_DYNAMIC_RANGE: u32 = 10094869; +pub const V4L2_CID_IMAGE_STABILIZATION: u32 = 10094870; +pub const V4L2_CID_ISO_SENSITIVITY: u32 = 10094871; +pub const V4L2_CID_ISO_SENSITIVITY_AUTO: u32 = 10094872; +pub const V4L2_CID_EXPOSURE_METERING: u32 = 10094873; +pub const V4L2_CID_SCENE_MODE: u32 = 10094874; +pub const V4L2_CID_3A_LOCK: u32 = 10094875; +pub const V4L2_LOCK_EXPOSURE: u32 = 1; +pub const V4L2_LOCK_WHITE_BALANCE: u32 = 2; +pub const V4L2_LOCK_FOCUS: u32 = 4; +pub const V4L2_CID_AUTO_FOCUS_START: u32 = 10094876; +pub const V4L2_CID_AUTO_FOCUS_STOP: u32 = 10094877; +pub const V4L2_CID_AUTO_FOCUS_STATUS: u32 = 10094878; +pub const V4L2_AUTO_FOCUS_STATUS_IDLE: u32 = 0; +pub const V4L2_AUTO_FOCUS_STATUS_BUSY: u32 = 1; +pub const V4L2_AUTO_FOCUS_STATUS_REACHED: u32 = 2; +pub const V4L2_AUTO_FOCUS_STATUS_FAILED: u32 = 4; +pub const V4L2_CID_AUTO_FOCUS_RANGE: u32 = 10094879; +pub const V4L2_CID_PAN_SPEED: u32 = 10094880; +pub const V4L2_CID_TILT_SPEED: u32 = 10094881; +pub const V4L2_CID_CAMERA_ORIENTATION: u32 = 10094882; +pub const V4L2_CAMERA_ORIENTATION_FRONT: u32 = 0; +pub const V4L2_CAMERA_ORIENTATION_BACK: u32 = 1; +pub const V4L2_CAMERA_ORIENTATION_EXTERNAL: u32 = 2; +pub const V4L2_CID_CAMERA_SENSOR_ROTATION: u32 = 10094883; +pub const V4L2_CID_HDR_SENSOR_MODE: u32 = 10094884; +pub const V4L2_CID_FM_TX_CLASS_BASE: u32 = 10160384; +pub const V4L2_CID_FM_TX_CLASS: u32 = 10158081; +pub const V4L2_CID_RDS_TX_DEVIATION: u32 = 10160385; +pub const V4L2_CID_RDS_TX_PI: u32 = 10160386; +pub const V4L2_CID_RDS_TX_PTY: u32 = 10160387; +pub const V4L2_CID_RDS_TX_PS_NAME: u32 = 10160389; +pub const V4L2_CID_RDS_TX_RADIO_TEXT: u32 = 10160390; +pub const V4L2_CID_RDS_TX_MONO_STEREO: u32 = 10160391; +pub const V4L2_CID_RDS_TX_ARTIFICIAL_HEAD: u32 = 10160392; +pub const V4L2_CID_RDS_TX_COMPRESSED: u32 = 10160393; +pub const V4L2_CID_RDS_TX_DYNAMIC_PTY: u32 = 10160394; +pub const V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: u32 = 10160395; +pub const V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: u32 = 10160396; +pub const V4L2_CID_RDS_TX_MUSIC_SPEECH: u32 = 10160397; +pub const V4L2_CID_RDS_TX_ALT_FREQS_ENABLE: u32 = 10160398; +pub const V4L2_CID_RDS_TX_ALT_FREQS: u32 = 10160399; +pub const V4L2_CID_AUDIO_LIMITER_ENABLED: u32 = 10160448; +pub const V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: u32 = 10160449; +pub const V4L2_CID_AUDIO_LIMITER_DEVIATION: u32 = 10160450; +pub const V4L2_CID_AUDIO_COMPRESSION_ENABLED: u32 = 10160464; +pub const V4L2_CID_AUDIO_COMPRESSION_GAIN: u32 = 10160465; +pub const V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: u32 = 10160466; +pub const V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: u32 = 10160467; +pub const V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: u32 = 10160468; +pub const V4L2_CID_PILOT_TONE_ENABLED: u32 = 10160480; +pub const V4L2_CID_PILOT_TONE_DEVIATION: u32 = 10160481; +pub const V4L2_CID_PILOT_TONE_FREQUENCY: u32 = 10160482; +pub const V4L2_CID_TUNE_PREEMPHASIS: u32 = 10160496; +pub const V4L2_CID_TUNE_POWER_LEVEL: u32 = 10160497; +pub const V4L2_CID_TUNE_ANTENNA_CAPACITOR: u32 = 10160498; +pub const V4L2_CID_FLASH_CLASS_BASE: u32 = 10225920; +pub const V4L2_CID_FLASH_CLASS: u32 = 10223617; +pub const V4L2_CID_FLASH_LED_MODE: u32 = 10225921; +pub const V4L2_CID_FLASH_STROBE_SOURCE: u32 = 10225922; +pub const V4L2_CID_FLASH_STROBE: u32 = 10225923; +pub const V4L2_CID_FLASH_STROBE_STOP: u32 = 10225924; +pub const V4L2_CID_FLASH_STROBE_STATUS: u32 = 10225925; +pub const V4L2_CID_FLASH_TIMEOUT: u32 = 10225926; +pub const V4L2_CID_FLASH_INTENSITY: u32 = 10225927; +pub const V4L2_CID_FLASH_TORCH_INTENSITY: u32 = 10225928; +pub const V4L2_CID_FLASH_INDICATOR_INTENSITY: u32 = 10225929; +pub const V4L2_CID_FLASH_FAULT: u32 = 10225930; +pub const V4L2_FLASH_FAULT_OVER_VOLTAGE: u32 = 1; +pub const V4L2_FLASH_FAULT_TIMEOUT: u32 = 2; +pub const V4L2_FLASH_FAULT_OVER_TEMPERATURE: u32 = 4; +pub const V4L2_FLASH_FAULT_SHORT_CIRCUIT: u32 = 8; +pub const V4L2_FLASH_FAULT_OVER_CURRENT: u32 = 16; +pub const V4L2_FLASH_FAULT_INDICATOR: u32 = 32; +pub const V4L2_FLASH_FAULT_UNDER_VOLTAGE: u32 = 64; +pub const V4L2_FLASH_FAULT_INPUT_VOLTAGE: u32 = 128; +pub const V4L2_FLASH_FAULT_LED_OVER_TEMPERATURE: u32 = 256; +pub const V4L2_CID_FLASH_CHARGE: u32 = 10225931; +pub const V4L2_CID_FLASH_READY: u32 = 10225932; +pub const V4L2_CID_JPEG_CLASS_BASE: u32 = 10291456; +pub const V4L2_CID_JPEG_CLASS: u32 = 10289153; +pub const V4L2_CID_JPEG_CHROMA_SUBSAMPLING: u32 = 10291457; +pub const V4L2_CID_JPEG_RESTART_INTERVAL: u32 = 10291458; +pub const V4L2_CID_JPEG_COMPRESSION_QUALITY: u32 = 10291459; +pub const V4L2_CID_JPEG_ACTIVE_MARKER: u32 = 10291460; +pub const V4L2_JPEG_ACTIVE_MARKER_APP0: u32 = 1; +pub const V4L2_JPEG_ACTIVE_MARKER_APP1: u32 = 2; +pub const V4L2_JPEG_ACTIVE_MARKER_COM: u32 = 65536; +pub const V4L2_JPEG_ACTIVE_MARKER_DQT: u32 = 131072; +pub const V4L2_JPEG_ACTIVE_MARKER_DHT: u32 = 262144; +pub const V4L2_CID_IMAGE_SOURCE_CLASS_BASE: u32 = 10356992; +pub const V4L2_CID_IMAGE_SOURCE_CLASS: u32 = 10354689; +pub const V4L2_CID_VBLANK: u32 = 10356993; +pub const V4L2_CID_HBLANK: u32 = 10356994; +pub const V4L2_CID_ANALOGUE_GAIN: u32 = 10356995; +pub const V4L2_CID_TEST_PATTERN_RED: u32 = 10356996; +pub const V4L2_CID_TEST_PATTERN_GREENR: u32 = 10356997; +pub const V4L2_CID_TEST_PATTERN_BLUE: u32 = 10356998; +pub const V4L2_CID_TEST_PATTERN_GREENB: u32 = 10356999; +pub const V4L2_CID_UNIT_CELL_SIZE: u32 = 10357000; +pub const V4L2_CID_NOTIFY_GAINS: u32 = 10357001; +pub const V4L2_CID_IMAGE_PROC_CLASS_BASE: u32 = 10422528; +pub const V4L2_CID_IMAGE_PROC_CLASS: u32 = 10420225; +pub const V4L2_CID_LINK_FREQ: u32 = 10422529; +pub const V4L2_CID_PIXEL_RATE: u32 = 10422530; +pub const V4L2_CID_TEST_PATTERN: u32 = 10422531; +pub const V4L2_CID_DEINTERLACING_MODE: u32 = 10422532; +pub const V4L2_CID_DIGITAL_GAIN: u32 = 10422533; +pub const V4L2_CID_DV_CLASS_BASE: u32 = 10488064; +pub const V4L2_CID_DV_CLASS: u32 = 10485761; +pub const V4L2_CID_DV_TX_HOTPLUG: u32 = 10488065; +pub const V4L2_CID_DV_TX_RXSENSE: u32 = 10488066; +pub const V4L2_CID_DV_TX_EDID_PRESENT: u32 = 10488067; +pub const V4L2_CID_DV_TX_MODE: u32 = 10488068; +pub const V4L2_CID_DV_TX_RGB_RANGE: u32 = 10488069; +pub const V4L2_CID_DV_TX_IT_CONTENT_TYPE: u32 = 10488070; +pub const V4L2_CID_DV_RX_POWER_PRESENT: u32 = 10488164; +pub const V4L2_CID_DV_RX_RGB_RANGE: u32 = 10488165; +pub const V4L2_CID_DV_RX_IT_CONTENT_TYPE: u32 = 10488166; +pub const V4L2_CID_FM_RX_CLASS_BASE: u32 = 10553600; +pub const V4L2_CID_FM_RX_CLASS: u32 = 10551297; +pub const V4L2_CID_TUNE_DEEMPHASIS: u32 = 10553601; +pub const V4L2_CID_RDS_RECEPTION: u32 = 10553602; +pub const V4L2_CID_RDS_RX_PTY: u32 = 10553603; +pub const V4L2_CID_RDS_RX_PS_NAME: u32 = 10553604; +pub const V4L2_CID_RDS_RX_RADIO_TEXT: u32 = 10553605; +pub const V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: u32 = 10553606; +pub const V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: u32 = 10553607; +pub const V4L2_CID_RDS_RX_MUSIC_SPEECH: u32 = 10553608; +pub const V4L2_CID_RF_TUNER_CLASS_BASE: u32 = 10619136; +pub const V4L2_CID_RF_TUNER_CLASS: u32 = 10616833; +pub const V4L2_CID_RF_TUNER_BANDWIDTH_AUTO: u32 = 10619147; +pub const V4L2_CID_RF_TUNER_BANDWIDTH: u32 = 10619148; +pub const V4L2_CID_RF_TUNER_RF_GAIN: u32 = 10619168; +pub const V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: u32 = 10619177; +pub const V4L2_CID_RF_TUNER_LNA_GAIN: u32 = 10619178; +pub const V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: u32 = 10619187; +pub const V4L2_CID_RF_TUNER_MIXER_GAIN: u32 = 10619188; +pub const V4L2_CID_RF_TUNER_IF_GAIN_AUTO: u32 = 10619197; +pub const V4L2_CID_RF_TUNER_IF_GAIN: u32 = 10619198; +pub const V4L2_CID_RF_TUNER_PLL_LOCK: u32 = 10619227; +pub const V4L2_CID_DETECT_CLASS_BASE: u32 = 10684672; +pub const V4L2_CID_DETECT_CLASS: u32 = 10682369; +pub const V4L2_CID_DETECT_MD_MODE: u32 = 10684673; +pub const V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD: u32 = 10684674; +pub const V4L2_CID_DETECT_MD_THRESHOLD_GRID: u32 = 10684675; +pub const V4L2_CID_DETECT_MD_REGION_GRID: u32 = 10684676; +pub const V4L2_CID_CODEC_STATELESS_BASE: u32 = 10750208; +pub const V4L2_CID_CODEC_STATELESS_CLASS: u32 = 10747905; +pub const V4L2_CID_STATELESS_H264_DECODE_MODE: u32 = 10750208; +pub const V4L2_CID_STATELESS_H264_START_CODE: u32 = 10750209; +pub const V4L2_H264_SPS_CONSTRAINT_SET0_FLAG: u32 = 1; +pub const V4L2_H264_SPS_CONSTRAINT_SET1_FLAG: u32 = 2; +pub const V4L2_H264_SPS_CONSTRAINT_SET2_FLAG: u32 = 4; +pub const V4L2_H264_SPS_CONSTRAINT_SET3_FLAG: u32 = 8; +pub const V4L2_H264_SPS_CONSTRAINT_SET4_FLAG: u32 = 16; +pub const V4L2_H264_SPS_CONSTRAINT_SET5_FLAG: u32 = 32; +pub const V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE: u32 = 1; +pub const V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS: u32 = 2; +pub const V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO: u32 = 4; +pub const V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED: u32 = 8; +pub const V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY: u32 = 16; +pub const V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD: u32 = 32; +pub const V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE: u32 = 64; +pub const V4L2_CID_STATELESS_H264_SPS: u32 = 10750210; +pub const V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE: u32 = 1; +pub const V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT: u32 = 2; +pub const V4L2_H264_PPS_FLAG_WEIGHTED_PRED: u32 = 4; +pub const V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT: u32 = 8; +pub const V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED: u32 = 16; +pub const V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT: u32 = 32; +pub const V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE: u32 = 64; +pub const V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT: u32 = 128; +pub const V4L2_CID_STATELESS_H264_PPS: u32 = 10750211; +pub const V4L2_CID_STATELESS_H264_SCALING_MATRIX: u32 = 10750212; +pub const V4L2_CID_STATELESS_H264_PRED_WEIGHTS: u32 = 10750213; +pub const V4L2_H264_SLICE_TYPE_P: u32 = 0; +pub const V4L2_H264_SLICE_TYPE_B: u32 = 1; +pub const V4L2_H264_SLICE_TYPE_I: u32 = 2; +pub const V4L2_H264_SLICE_TYPE_SP: u32 = 3; +pub const V4L2_H264_SLICE_TYPE_SI: u32 = 4; +pub const V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED: u32 = 1; +pub const V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH: u32 = 2; +pub const V4L2_H264_TOP_FIELD_REF: u32 = 1; +pub const V4L2_H264_BOTTOM_FIELD_REF: u32 = 2; +pub const V4L2_H264_FRAME_REF: u32 = 3; +pub const V4L2_H264_NUM_DPB_ENTRIES: u32 = 16; +pub const V4L2_H264_REF_LIST_LEN: u32 = 32; +pub const V4L2_CID_STATELESS_H264_SLICE_PARAMS: u32 = 10750214; +pub const V4L2_H264_DPB_ENTRY_FLAG_VALID: u32 = 1; +pub const V4L2_H264_DPB_ENTRY_FLAG_ACTIVE: u32 = 2; +pub const V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM: u32 = 4; +pub const V4L2_H264_DPB_ENTRY_FLAG_FIELD: u32 = 8; +pub const V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC: u32 = 1; +pub const V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC: u32 = 2; +pub const V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD: u32 = 4; +pub const V4L2_H264_DECODE_PARAM_FLAG_PFRAME: u32 = 8; +pub const V4L2_H264_DECODE_PARAM_FLAG_BFRAME: u32 = 16; +pub const V4L2_CID_STATELESS_H264_DECODE_PARAMS: u32 = 10750215; +pub const V4L2_FWHT_VERSION: u32 = 3; +pub const V4L2_FWHT_FL_COMPONENTS_NUM_OFFSET: u32 = 16; +pub const V4L2_FWHT_FL_PIXENC_OFFSET: u32 = 19; +pub const V4L2_FWHT_FL_PIXENC_YUV: u32 = 524288; +pub const V4L2_FWHT_FL_PIXENC_RGB: u32 = 1048576; +pub const V4L2_FWHT_FL_PIXENC_HSV: u32 = 1572864; +pub const V4L2_CID_STATELESS_FWHT_PARAMS: u32 = 10750308; +pub const V4L2_VP8_SEGMENT_FLAG_ENABLED: u32 = 1; +pub const V4L2_VP8_SEGMENT_FLAG_UPDATE_MAP: u32 = 2; +pub const V4L2_VP8_SEGMENT_FLAG_UPDATE_FEATURE_DATA: u32 = 4; +pub const V4L2_VP8_SEGMENT_FLAG_DELTA_VALUE_MODE: u32 = 8; +pub const V4L2_VP8_LF_ADJ_ENABLE: u32 = 1; +pub const V4L2_VP8_LF_DELTA_UPDATE: u32 = 2; +pub const V4L2_VP8_LF_FILTER_TYPE_SIMPLE: u32 = 4; +pub const V4L2_VP8_COEFF_PROB_CNT: u32 = 11; +pub const V4L2_VP8_MV_PROB_CNT: u32 = 19; +pub const V4L2_VP8_FRAME_FLAG_KEY_FRAME: u32 = 1; +pub const V4L2_VP8_FRAME_FLAG_EXPERIMENTAL: u32 = 2; +pub const V4L2_VP8_FRAME_FLAG_SHOW_FRAME: u32 = 4; +pub const V4L2_VP8_FRAME_FLAG_MB_NO_SKIP_COEFF: u32 = 8; +pub const V4L2_VP8_FRAME_FLAG_SIGN_BIAS_GOLDEN: u32 = 16; +pub const V4L2_VP8_FRAME_FLAG_SIGN_BIAS_ALT: u32 = 32; +pub const V4L2_CID_STATELESS_VP8_FRAME: u32 = 10750408; +pub const V4L2_MPEG2_SEQ_FLAG_PROGRESSIVE: u32 = 1; +pub const V4L2_CID_STATELESS_MPEG2_SEQUENCE: u32 = 10750428; +pub const V4L2_MPEG2_PIC_CODING_TYPE_I: u32 = 1; +pub const V4L2_MPEG2_PIC_CODING_TYPE_P: u32 = 2; +pub const V4L2_MPEG2_PIC_CODING_TYPE_B: u32 = 3; +pub const V4L2_MPEG2_PIC_CODING_TYPE_D: u32 = 4; +pub const V4L2_MPEG2_PIC_TOP_FIELD: u32 = 1; +pub const V4L2_MPEG2_PIC_BOTTOM_FIELD: u32 = 2; +pub const V4L2_MPEG2_PIC_FRAME: u32 = 3; +pub const V4L2_MPEG2_PIC_FLAG_TOP_FIELD_FIRST: u32 = 1; +pub const V4L2_MPEG2_PIC_FLAG_FRAME_PRED_DCT: u32 = 2; +pub const V4L2_MPEG2_PIC_FLAG_CONCEALMENT_MV: u32 = 4; +pub const V4L2_MPEG2_PIC_FLAG_Q_SCALE_TYPE: u32 = 8; +pub const V4L2_MPEG2_PIC_FLAG_INTRA_VLC: u32 = 16; +pub const V4L2_MPEG2_PIC_FLAG_ALT_SCAN: u32 = 32; +pub const V4L2_MPEG2_PIC_FLAG_REPEAT_FIRST: u32 = 64; +pub const V4L2_MPEG2_PIC_FLAG_PROGRESSIVE: u32 = 128; +pub const V4L2_CID_STATELESS_MPEG2_PICTURE: u32 = 10750429; +pub const V4L2_CID_STATELESS_MPEG2_QUANTISATION: u32 = 10750430; +pub const V4L2_CID_STATELESS_HEVC_SPS: u32 = 10750608; +pub const V4L2_CID_STATELESS_HEVC_PPS: u32 = 10750609; +pub const V4L2_CID_STATELESS_HEVC_SLICE_PARAMS: u32 = 10750610; +pub const V4L2_CID_STATELESS_HEVC_SCALING_MATRIX: u32 = 10750611; +pub const V4L2_CID_STATELESS_HEVC_DECODE_PARAMS: u32 = 10750612; +pub const V4L2_CID_STATELESS_HEVC_DECODE_MODE: u32 = 10750613; +pub const V4L2_CID_STATELESS_HEVC_START_CODE: u32 = 10750614; +pub const V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS: u32 = 10750615; +pub const V4L2_HEVC_SLICE_TYPE_B: u32 = 0; +pub const V4L2_HEVC_SLICE_TYPE_P: u32 = 1; +pub const V4L2_HEVC_SLICE_TYPE_I: u32 = 2; +pub const V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE: u32 = 1; +pub const V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED: u32 = 2; +pub const V4L2_HEVC_SPS_FLAG_AMP_ENABLED: u32 = 4; +pub const V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET: u32 = 8; +pub const V4L2_HEVC_SPS_FLAG_PCM_ENABLED: u32 = 16; +pub const V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED: u32 = 32; +pub const V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT: u32 = 64; +pub const V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED: u32 = 128; +pub const V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED: u32 = 256; +pub const V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED: u32 = 1; +pub const V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT: u32 = 2; +pub const V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED: u32 = 4; +pub const V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT: u32 = 8; +pub const V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED: u32 = 16; +pub const V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED: u32 = 32; +pub const V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED: u32 = 64; +pub const V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT: u32 = 128; +pub const V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED: u32 = 256; +pub const V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED: u32 = 512; +pub const V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED: u32 = 1024; +pub const V4L2_HEVC_PPS_FLAG_TILES_ENABLED: u32 = 2048; +pub const V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED: u32 = 4096; +pub const V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED: u32 = 8192; +pub const V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED: u32 = 16384; +pub const V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED: u32 = 32768; +pub const V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER: u32 = 65536; +pub const V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT: u32 = 131072; +pub const V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT: u32 = 262144; +pub const V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT: u32 = 524288; +pub const V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING: u32 = 1048576; +pub const V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE: u32 = 1; +pub const V4L2_HEVC_SEI_PIC_STRUCT_FRAME: u32 = 0; +pub const V4L2_HEVC_SEI_PIC_STRUCT_TOP_FIELD: u32 = 1; +pub const V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_FIELD: u32 = 2; +pub const V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM: u32 = 3; +pub const V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP: u32 = 4; +pub const V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM_TOP: u32 = 5; +pub const V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM: u32 = 6; +pub const V4L2_HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING: u32 = 7; +pub const V4L2_HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING: u32 = 8; +pub const V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_PREVIOUS_BOTTOM: u32 = 9; +pub const V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_PREVIOUS_TOP: u32 = 10; +pub const V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_NEXT_BOTTOM: u32 = 11; +pub const V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_NEXT_TOP: u32 = 12; +pub const V4L2_HEVC_DPB_ENTRIES_NUM_MAX: u32 = 16; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA: u32 = 1; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA: u32 = 2; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED: u32 = 4; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO: u32 = 8; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT: u32 = 16; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0: u32 = 32; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV: u32 = 64; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED: u32 = 128; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED: u32 = 256; +pub const V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT: u32 = 512; +pub const V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC: u32 = 1; +pub const V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC: u32 = 2; +pub const V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR: u32 = 4; +pub const V4L2_CID_COLORIMETRY_CLASS_BASE: u32 = 10815744; +pub const V4L2_CID_COLORIMETRY_CLASS: u32 = 10813441; +pub const V4L2_CID_COLORIMETRY_HDR10_CLL_INFO: u32 = 10815744; +pub const V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY: u32 = 10815745; +pub const V4L2_HDR10_MASTERING_PRIMARIES_X_LOW: u32 = 5; +pub const V4L2_HDR10_MASTERING_PRIMARIES_X_HIGH: u32 = 37000; +pub const V4L2_HDR10_MASTERING_PRIMARIES_Y_LOW: u32 = 5; +pub const V4L2_HDR10_MASTERING_PRIMARIES_Y_HIGH: u32 = 42000; +pub const V4L2_HDR10_MASTERING_WHITE_POINT_X_LOW: u32 = 5; +pub const V4L2_HDR10_MASTERING_WHITE_POINT_X_HIGH: u32 = 37000; +pub const V4L2_HDR10_MASTERING_WHITE_POINT_Y_LOW: u32 = 5; +pub const V4L2_HDR10_MASTERING_WHITE_POINT_Y_HIGH: u32 = 42000; +pub const V4L2_HDR10_MASTERING_MAX_LUMA_LOW: u32 = 50000; +pub const V4L2_HDR10_MASTERING_MAX_LUMA_HIGH: u32 = 100000000; +pub const V4L2_HDR10_MASTERING_MIN_LUMA_LOW: u32 = 1; +pub const V4L2_HDR10_MASTERING_MIN_LUMA_HIGH: u32 = 50000; +pub const V4L2_VP9_LOOP_FILTER_FLAG_DELTA_ENABLED: u32 = 1; +pub const V4L2_VP9_LOOP_FILTER_FLAG_DELTA_UPDATE: u32 = 2; +pub const V4L2_VP9_SEGMENTATION_FLAG_ENABLED: u32 = 1; +pub const V4L2_VP9_SEGMENTATION_FLAG_UPDATE_MAP: u32 = 2; +pub const V4L2_VP9_SEGMENTATION_FLAG_TEMPORAL_UPDATE: u32 = 4; +pub const V4L2_VP9_SEGMENTATION_FLAG_UPDATE_DATA: u32 = 8; +pub const V4L2_VP9_SEGMENTATION_FLAG_ABS_OR_DELTA_UPDATE: u32 = 16; +pub const V4L2_VP9_SEG_LVL_ALT_Q: u32 = 0; +pub const V4L2_VP9_SEG_LVL_ALT_L: u32 = 1; +pub const V4L2_VP9_SEG_LVL_REF_FRAME: u32 = 2; +pub const V4L2_VP9_SEG_LVL_SKIP: u32 = 3; +pub const V4L2_VP9_SEG_LVL_MAX: u32 = 4; +pub const V4L2_VP9_SEGMENT_FEATURE_ENABLED_MASK: u32 = 15; +pub const V4L2_VP9_FRAME_FLAG_KEY_FRAME: u32 = 1; +pub const V4L2_VP9_FRAME_FLAG_SHOW_FRAME: u32 = 2; +pub const V4L2_VP9_FRAME_FLAG_ERROR_RESILIENT: u32 = 4; +pub const V4L2_VP9_FRAME_FLAG_INTRA_ONLY: u32 = 8; +pub const V4L2_VP9_FRAME_FLAG_ALLOW_HIGH_PREC_MV: u32 = 16; +pub const V4L2_VP9_FRAME_FLAG_REFRESH_FRAME_CTX: u32 = 32; +pub const V4L2_VP9_FRAME_FLAG_PARALLEL_DEC_MODE: u32 = 64; +pub const V4L2_VP9_FRAME_FLAG_X_SUBSAMPLING: u32 = 128; +pub const V4L2_VP9_FRAME_FLAG_Y_SUBSAMPLING: u32 = 256; +pub const V4L2_VP9_FRAME_FLAG_COLOR_RANGE_FULL_SWING: u32 = 512; +pub const V4L2_VP9_SIGN_BIAS_LAST: u32 = 1; +pub const V4L2_VP9_SIGN_BIAS_GOLDEN: u32 = 2; +pub const V4L2_VP9_SIGN_BIAS_ALT: u32 = 4; +pub const V4L2_VP9_RESET_FRAME_CTX_NONE: u32 = 0; +pub const V4L2_VP9_RESET_FRAME_CTX_SPEC: u32 = 1; +pub const V4L2_VP9_RESET_FRAME_CTX_ALL: u32 = 2; +pub const V4L2_VP9_INTERP_FILTER_EIGHTTAP: u32 = 0; +pub const V4L2_VP9_INTERP_FILTER_EIGHTTAP_SMOOTH: u32 = 1; +pub const V4L2_VP9_INTERP_FILTER_EIGHTTAP_SHARP: u32 = 2; +pub const V4L2_VP9_INTERP_FILTER_BILINEAR: u32 = 3; +pub const V4L2_VP9_INTERP_FILTER_SWITCHABLE: u32 = 4; +pub const V4L2_VP9_REFERENCE_MODE_SINGLE_REFERENCE: u32 = 0; +pub const V4L2_VP9_REFERENCE_MODE_COMPOUND_REFERENCE: u32 = 1; +pub const V4L2_VP9_REFERENCE_MODE_SELECT: u32 = 2; +pub const V4L2_VP9_PROFILE_MAX: u32 = 3; +pub const V4L2_CID_STATELESS_VP9_FRAME: u32 = 10750508; +pub const V4L2_VP9_NUM_FRAME_CTX: u32 = 4; +pub const V4L2_CID_STATELESS_VP9_COMPRESSED_HDR: u32 = 10750509; +pub const V4L2_VP9_TX_MODE_ONLY_4X4: u32 = 0; +pub const V4L2_VP9_TX_MODE_ALLOW_8X8: u32 = 1; +pub const V4L2_VP9_TX_MODE_ALLOW_16X16: u32 = 2; +pub const V4L2_VP9_TX_MODE_ALLOW_32X32: u32 = 3; +pub const V4L2_VP9_TX_MODE_SELECT: u32 = 4; +pub const V4L2_AV1_TOTAL_REFS_PER_FRAME: u32 = 8; +pub const V4L2_AV1_CDEF_MAX: u32 = 8; +pub const V4L2_AV1_NUM_PLANES_MAX: u32 = 3; +pub const V4L2_AV1_MAX_SEGMENTS: u32 = 8; +pub const V4L2_AV1_MAX_OPERATING_POINTS: u32 = 32; +pub const V4L2_AV1_REFS_PER_FRAME: u32 = 7; +pub const V4L2_AV1_MAX_NUM_Y_POINTS: u32 = 16; +pub const V4L2_AV1_MAX_NUM_CB_POINTS: u32 = 16; +pub const V4L2_AV1_MAX_NUM_CR_POINTS: u32 = 16; +pub const V4L2_AV1_AR_COEFFS_SIZE: u32 = 25; +pub const V4L2_AV1_MAX_NUM_PLANES: u32 = 3; +pub const V4L2_AV1_MAX_TILE_COLS: u32 = 64; +pub const V4L2_AV1_MAX_TILE_ROWS: u32 = 64; +pub const V4L2_AV1_MAX_TILE_COUNT: u32 = 512; +pub const V4L2_AV1_SEQUENCE_FLAG_STILL_PICTURE: u32 = 1; +pub const V4L2_AV1_SEQUENCE_FLAG_USE_128X128_SUPERBLOCK: u32 = 2; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_FILTER_INTRA: u32 = 4; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTRA_EDGE_FILTER: u32 = 8; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_INTERINTRA_COMPOUND: u32 = 16; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_MASKED_COMPOUND: u32 = 32; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_WARPED_MOTION: u32 = 64; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_DUAL_FILTER: u32 = 128; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_ORDER_HINT: u32 = 256; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_JNT_COMP: u32 = 512; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_REF_FRAME_MVS: u32 = 1024; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_SUPERRES: u32 = 2048; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_CDEF: u32 = 4096; +pub const V4L2_AV1_SEQUENCE_FLAG_ENABLE_RESTORATION: u32 = 8192; +pub const V4L2_AV1_SEQUENCE_FLAG_MONO_CHROME: u32 = 16384; +pub const V4L2_AV1_SEQUENCE_FLAG_COLOR_RANGE: u32 = 32768; +pub const V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_X: u32 = 65536; +pub const V4L2_AV1_SEQUENCE_FLAG_SUBSAMPLING_Y: u32 = 131072; +pub const V4L2_AV1_SEQUENCE_FLAG_FILM_GRAIN_PARAMS_PRESENT: u32 = 262144; +pub const V4L2_AV1_SEQUENCE_FLAG_SEPARATE_UV_DELTA_Q: u32 = 524288; +pub const V4L2_CID_STATELESS_AV1_SEQUENCE: u32 = 10750708; +pub const V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY: u32 = 10750709; +pub const V4L2_AV1_GLOBAL_MOTION_FLAG_IS_GLOBAL: u32 = 1; +pub const V4L2_AV1_GLOBAL_MOTION_FLAG_IS_ROT_ZOOM: u32 = 2; +pub const V4L2_AV1_GLOBAL_MOTION_FLAG_IS_TRANSLATION: u32 = 4; +pub const V4L2_AV1_LOOP_RESTORATION_FLAG_USES_LR: u32 = 1; +pub const V4L2_AV1_LOOP_RESTORATION_FLAG_USES_CHROMA_LR: u32 = 2; +pub const V4L2_AV1_SEGMENTATION_FLAG_ENABLED: u32 = 1; +pub const V4L2_AV1_SEGMENTATION_FLAG_UPDATE_MAP: u32 = 2; +pub const V4L2_AV1_SEGMENTATION_FLAG_TEMPORAL_UPDATE: u32 = 4; +pub const V4L2_AV1_SEGMENTATION_FLAG_UPDATE_DATA: u32 = 8; +pub const V4L2_AV1_SEGMENTATION_FLAG_SEG_ID_PRE_SKIP: u32 = 16; +pub const V4L2_AV1_LOOP_FILTER_FLAG_DELTA_ENABLED: u32 = 1; +pub const V4L2_AV1_LOOP_FILTER_FLAG_DELTA_UPDATE: u32 = 2; +pub const V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_PRESENT: u32 = 4; +pub const V4L2_AV1_LOOP_FILTER_FLAG_DELTA_LF_MULTI: u32 = 8; +pub const V4L2_AV1_QUANTIZATION_FLAG_DIFF_UV_DELTA: u32 = 1; +pub const V4L2_AV1_QUANTIZATION_FLAG_USING_QMATRIX: u32 = 2; +pub const V4L2_AV1_QUANTIZATION_FLAG_DELTA_Q_PRESENT: u32 = 4; +pub const V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING: u32 = 1; +pub const V4L2_AV1_FRAME_FLAG_SHOW_FRAME: u32 = 1; +pub const V4L2_AV1_FRAME_FLAG_SHOWABLE_FRAME: u32 = 2; +pub const V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE: u32 = 4; +pub const V4L2_AV1_FRAME_FLAG_DISABLE_CDF_UPDATE: u32 = 8; +pub const V4L2_AV1_FRAME_FLAG_ALLOW_SCREEN_CONTENT_TOOLS: u32 = 16; +pub const V4L2_AV1_FRAME_FLAG_FORCE_INTEGER_MV: u32 = 32; +pub const V4L2_AV1_FRAME_FLAG_ALLOW_INTRABC: u32 = 64; +pub const V4L2_AV1_FRAME_FLAG_USE_SUPERRES: u32 = 128; +pub const V4L2_AV1_FRAME_FLAG_ALLOW_HIGH_PRECISION_MV: u32 = 256; +pub const V4L2_AV1_FRAME_FLAG_IS_MOTION_MODE_SWITCHABLE: u32 = 512; +pub const V4L2_AV1_FRAME_FLAG_USE_REF_FRAME_MVS: u32 = 1024; +pub const V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF: u32 = 2048; +pub const V4L2_AV1_FRAME_FLAG_ALLOW_WARPED_MOTION: u32 = 4096; +pub const V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT: u32 = 8192; +pub const V4L2_AV1_FRAME_FLAG_REDUCED_TX_SET: u32 = 16384; +pub const V4L2_AV1_FRAME_FLAG_SKIP_MODE_ALLOWED: u32 = 32768; +pub const V4L2_AV1_FRAME_FLAG_SKIP_MODE_PRESENT: u32 = 65536; +pub const V4L2_AV1_FRAME_FLAG_FRAME_SIZE_OVERRIDE: u32 = 131072; +pub const V4L2_AV1_FRAME_FLAG_BUFFER_REMOVAL_TIME_PRESENT: u32 = 262144; +pub const V4L2_AV1_FRAME_FLAG_FRAME_REFS_SHORT_SIGNALING: u32 = 524288; +pub const V4L2_CID_STATELESS_AV1_FRAME: u32 = 10750710; +pub const V4L2_AV1_FILM_GRAIN_FLAG_APPLY_GRAIN: u32 = 1; +pub const V4L2_AV1_FILM_GRAIN_FLAG_UPDATE_GRAIN: u32 = 2; +pub const V4L2_AV1_FILM_GRAIN_FLAG_CHROMA_SCALING_FROM_LUMA: u32 = 4; +pub const V4L2_AV1_FILM_GRAIN_FLAG_OVERLAP: u32 = 8; +pub const V4L2_AV1_FILM_GRAIN_FLAG_CLIP_TO_RESTRICTED_RANGE: u32 = 16; +pub const V4L2_CID_STATELESS_AV1_FILM_GRAIN: u32 = 10750713; +pub const V4L2_CTRL_CLASS_MPEG: u32 = 10027008; +pub const V4L2_CID_MPEG_CLASS: u32 = 10027009; +pub const V4L2_CID_MPEG_BASE: u32 = 10029312; +pub const V4L2_CID_MPEG_CX2341X_BASE: u32 = 10031104; +pub const V4L2_CID_MPEG_MFC51_BASE: u32 = 10031360; +pub const V4L2_CAP_VIDEO_CAPTURE: u32 = 1; +pub const V4L2_CAP_VIDEO_OUTPUT: u32 = 2; +pub const V4L2_CAP_VIDEO_OVERLAY: u32 = 4; +pub const V4L2_CAP_VBI_CAPTURE: u32 = 16; +pub const V4L2_CAP_VBI_OUTPUT: u32 = 32; +pub const V4L2_CAP_SLICED_VBI_CAPTURE: u32 = 64; +pub const V4L2_CAP_SLICED_VBI_OUTPUT: u32 = 128; +pub const V4L2_CAP_RDS_CAPTURE: u32 = 256; +pub const V4L2_CAP_VIDEO_OUTPUT_OVERLAY: u32 = 512; +pub const V4L2_CAP_HW_FREQ_SEEK: u32 = 1024; +pub const V4L2_CAP_RDS_OUTPUT: u32 = 2048; +pub const V4L2_CAP_VIDEO_CAPTURE_MPLANE: u32 = 4096; +pub const V4L2_CAP_VIDEO_OUTPUT_MPLANE: u32 = 8192; +pub const V4L2_CAP_VIDEO_M2M_MPLANE: u32 = 16384; +pub const V4L2_CAP_VIDEO_M2M: u32 = 32768; +pub const V4L2_CAP_TUNER: u32 = 65536; +pub const V4L2_CAP_AUDIO: u32 = 131072; +pub const V4L2_CAP_RADIO: u32 = 262144; +pub const V4L2_CAP_MODULATOR: u32 = 524288; +pub const V4L2_CAP_SDR_CAPTURE: u32 = 1048576; +pub const V4L2_CAP_EXT_PIX_FORMAT: u32 = 2097152; +pub const V4L2_CAP_SDR_OUTPUT: u32 = 4194304; +pub const V4L2_CAP_META_CAPTURE: u32 = 8388608; +pub const V4L2_CAP_READWRITE: u32 = 16777216; +pub const V4L2_CAP_EDID: u32 = 33554432; +pub const V4L2_CAP_STREAMING: u32 = 67108864; +pub const V4L2_CAP_META_OUTPUT: u32 = 134217728; +pub const V4L2_CAP_TOUCH: u32 = 268435456; +pub const V4L2_CAP_IO_MC: u32 = 536870912; +pub const V4L2_CAP_DEVICE_CAPS: u32 = 2147483648; +pub const V4L2_PIX_FMT_PRIV_MAGIC: u32 = 4276996862; +pub const V4L2_PIX_FMT_FLAG_PREMUL_ALPHA: u32 = 1; +pub const V4L2_PIX_FMT_FLAG_SET_CSC: u32 = 2; +pub const V4L2_FMT_FLAG_COMPRESSED: u32 = 1; +pub const V4L2_FMT_FLAG_EMULATED: u32 = 2; +pub const V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM: u32 = 4; +pub const V4L2_FMT_FLAG_DYN_RESOLUTION: u32 = 8; +pub const V4L2_FMT_FLAG_ENC_CAP_FRAME_INTERVAL: u32 = 16; +pub const V4L2_FMT_FLAG_CSC_COLORSPACE: u32 = 32; +pub const V4L2_FMT_FLAG_CSC_XFER_FUNC: u32 = 64; +pub const V4L2_FMT_FLAG_CSC_YCBCR_ENC: u32 = 128; +pub const V4L2_FMT_FLAG_CSC_HSV_ENC: u32 = 128; +pub const V4L2_FMT_FLAG_CSC_QUANTIZATION: u32 = 256; +pub const V4L2_FMT_FLAG_META_LINE_BASED: u32 = 512; +pub const V4L2_TC_TYPE_24FPS: u32 = 1; +pub const V4L2_TC_TYPE_25FPS: u32 = 2; +pub const V4L2_TC_TYPE_30FPS: u32 = 3; +pub const V4L2_TC_TYPE_50FPS: u32 = 4; +pub const V4L2_TC_TYPE_60FPS: u32 = 5; +pub const V4L2_TC_FLAG_DROPFRAME: u32 = 1; +pub const V4L2_TC_FLAG_COLORFRAME: u32 = 2; +pub const V4L2_TC_USERBITS_field: u32 = 12; +pub const V4L2_TC_USERBITS_USERDEFINED: u32 = 0; +pub const V4L2_TC_USERBITS_8BITCHARS: u32 = 8; +pub const V4L2_JPEG_MARKER_DHT: u32 = 8; +pub const V4L2_JPEG_MARKER_DQT: u32 = 16; +pub const V4L2_JPEG_MARKER_DRI: u32 = 32; +pub const V4L2_JPEG_MARKER_COM: u32 = 64; +pub const V4L2_JPEG_MARKER_APP: u32 = 128; +pub const V4L2_MEMORY_FLAG_NON_COHERENT: u32 = 1; +pub const V4L2_BUF_CAP_SUPPORTS_MMAP: u32 = 1; +pub const V4L2_BUF_CAP_SUPPORTS_USERPTR: u32 = 2; +pub const V4L2_BUF_CAP_SUPPORTS_DMABUF: u32 = 4; +pub const V4L2_BUF_CAP_SUPPORTS_REQUESTS: u32 = 8; +pub const V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS: u32 = 16; +pub const V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF: u32 = 32; +pub const V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS: u32 = 64; +pub const V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS: u32 = 128; +pub const V4L2_BUF_CAP_SUPPORTS_REMOVE_BUFS: u32 = 256; +pub const V4L2_BUF_FLAG_MAPPED: u32 = 1; +pub const V4L2_BUF_FLAG_QUEUED: u32 = 2; +pub const V4L2_BUF_FLAG_DONE: u32 = 4; +pub const V4L2_BUF_FLAG_KEYFRAME: u32 = 8; +pub const V4L2_BUF_FLAG_PFRAME: u32 = 16; +pub const V4L2_BUF_FLAG_BFRAME: u32 = 32; +pub const V4L2_BUF_FLAG_ERROR: u32 = 64; +pub const V4L2_BUF_FLAG_IN_REQUEST: u32 = 128; +pub const V4L2_BUF_FLAG_TIMECODE: u32 = 256; +pub const V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF: u32 = 512; +pub const V4L2_BUF_FLAG_PREPARED: u32 = 1024; +pub const V4L2_BUF_FLAG_NO_CACHE_INVALIDATE: u32 = 2048; +pub const V4L2_BUF_FLAG_NO_CACHE_CLEAN: u32 = 4096; +pub const V4L2_BUF_FLAG_TIMESTAMP_MASK: u32 = 57344; +pub const V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN: u32 = 0; +pub const V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC: u32 = 8192; +pub const V4L2_BUF_FLAG_TIMESTAMP_COPY: u32 = 16384; +pub const V4L2_BUF_FLAG_TSTAMP_SRC_MASK: u32 = 458752; +pub const V4L2_BUF_FLAG_TSTAMP_SRC_EOF: u32 = 0; +pub const V4L2_BUF_FLAG_TSTAMP_SRC_SOE: u32 = 65536; +pub const V4L2_BUF_FLAG_LAST: u32 = 1048576; +pub const V4L2_BUF_FLAG_REQUEST_FD: u32 = 8388608; +pub const V4L2_FBUF_CAP_EXTERNOVERLAY: u32 = 1; +pub const V4L2_FBUF_CAP_CHROMAKEY: u32 = 2; +pub const V4L2_FBUF_CAP_LIST_CLIPPING: u32 = 4; +pub const V4L2_FBUF_CAP_BITMAP_CLIPPING: u32 = 8; +pub const V4L2_FBUF_CAP_LOCAL_ALPHA: u32 = 16; +pub const V4L2_FBUF_CAP_GLOBAL_ALPHA: u32 = 32; +pub const V4L2_FBUF_CAP_LOCAL_INV_ALPHA: u32 = 64; +pub const V4L2_FBUF_CAP_SRC_CHROMAKEY: u32 = 128; +pub const V4L2_FBUF_FLAG_PRIMARY: u32 = 1; +pub const V4L2_FBUF_FLAG_OVERLAY: u32 = 2; +pub const V4L2_FBUF_FLAG_CHROMAKEY: u32 = 4; +pub const V4L2_FBUF_FLAG_LOCAL_ALPHA: u32 = 8; +pub const V4L2_FBUF_FLAG_GLOBAL_ALPHA: u32 = 16; +pub const V4L2_FBUF_FLAG_LOCAL_INV_ALPHA: u32 = 32; +pub const V4L2_FBUF_FLAG_SRC_CHROMAKEY: u32 = 64; +pub const V4L2_MODE_HIGHQUALITY: u32 = 1; +pub const V4L2_CAP_TIMEPERFRAME: u32 = 4096; +pub const V4L2_STD_UNKNOWN: u32 = 0; +pub const V4L2_DV_PROGRESSIVE: u32 = 0; +pub const V4L2_DV_INTERLACED: u32 = 1; +pub const V4L2_DV_VSYNC_POS_POL: u32 = 1; +pub const V4L2_DV_HSYNC_POS_POL: u32 = 2; +pub const V4L2_DV_BT_STD_CEA861: u32 = 1; +pub const V4L2_DV_BT_STD_DMT: u32 = 2; +pub const V4L2_DV_BT_STD_CVT: u32 = 4; +pub const V4L2_DV_BT_STD_GTF: u32 = 8; +pub const V4L2_DV_BT_STD_SDI: u32 = 16; +pub const V4L2_DV_FL_REDUCED_BLANKING: u32 = 1; +pub const V4L2_DV_FL_CAN_REDUCE_FPS: u32 = 2; +pub const V4L2_DV_FL_REDUCED_FPS: u32 = 4; +pub const V4L2_DV_FL_HALF_LINE: u32 = 8; +pub const V4L2_DV_FL_IS_CE_VIDEO: u32 = 16; +pub const V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE: u32 = 32; +pub const V4L2_DV_FL_HAS_PICTURE_ASPECT: u32 = 64; +pub const V4L2_DV_FL_HAS_CEA861_VIC: u32 = 128; +pub const V4L2_DV_FL_HAS_HDMI_VIC: u32 = 256; +pub const V4L2_DV_FL_CAN_DETECT_REDUCED_FPS: u32 = 512; +pub const V4L2_DV_BT_656_1120: u32 = 0; +pub const V4L2_DV_BT_CAP_INTERLACED: u32 = 1; +pub const V4L2_DV_BT_CAP_PROGRESSIVE: u32 = 2; +pub const V4L2_DV_BT_CAP_REDUCED_BLANKING: u32 = 4; +pub const V4L2_DV_BT_CAP_CUSTOM: u32 = 8; +pub const V4L2_INPUT_TYPE_TUNER: u32 = 1; +pub const V4L2_INPUT_TYPE_CAMERA: u32 = 2; +pub const V4L2_INPUT_TYPE_TOUCH: u32 = 3; +pub const V4L2_IN_ST_NO_POWER: u32 = 1; +pub const V4L2_IN_ST_NO_SIGNAL: u32 = 2; +pub const V4L2_IN_ST_NO_COLOR: u32 = 4; +pub const V4L2_IN_ST_HFLIP: u32 = 16; +pub const V4L2_IN_ST_VFLIP: u32 = 32; +pub const V4L2_IN_ST_NO_H_LOCK: u32 = 256; +pub const V4L2_IN_ST_COLOR_KILL: u32 = 512; +pub const V4L2_IN_ST_NO_V_LOCK: u32 = 1024; +pub const V4L2_IN_ST_NO_STD_LOCK: u32 = 2048; +pub const V4L2_IN_ST_NO_SYNC: u32 = 65536; +pub const V4L2_IN_ST_NO_EQU: u32 = 131072; +pub const V4L2_IN_ST_NO_CARRIER: u32 = 262144; +pub const V4L2_IN_ST_MACROVISION: u32 = 16777216; +pub const V4L2_IN_ST_NO_ACCESS: u32 = 33554432; +pub const V4L2_IN_ST_VTR: u32 = 67108864; +pub const V4L2_IN_CAP_DV_TIMINGS: u32 = 2; +pub const V4L2_IN_CAP_CUSTOM_TIMINGS: u32 = 2; +pub const V4L2_IN_CAP_STD: u32 = 4; +pub const V4L2_IN_CAP_NATIVE_SIZE: u32 = 8; +pub const V4L2_OUTPUT_TYPE_MODULATOR: u32 = 1; +pub const V4L2_OUTPUT_TYPE_ANALOG: u32 = 2; +pub const V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY: u32 = 3; +pub const V4L2_OUT_CAP_DV_TIMINGS: u32 = 2; +pub const V4L2_OUT_CAP_CUSTOM_TIMINGS: u32 = 2; +pub const V4L2_OUT_CAP_STD: u32 = 4; +pub const V4L2_OUT_CAP_NATIVE_SIZE: u32 = 8; +pub const V4L2_CTRL_ID_MASK: u32 = 268435455; +pub const V4L2_CTRL_MAX_DIMS: u32 = 4; +pub const V4L2_CTRL_WHICH_CUR_VAL: u32 = 0; +pub const V4L2_CTRL_WHICH_DEF_VAL: u32 = 251658240; +pub const V4L2_CTRL_WHICH_REQUEST_VAL: u32 = 251723776; +pub const V4L2_CTRL_FLAG_DISABLED: u32 = 1; +pub const V4L2_CTRL_FLAG_GRABBED: u32 = 2; +pub const V4L2_CTRL_FLAG_READ_ONLY: u32 = 4; +pub const V4L2_CTRL_FLAG_UPDATE: u32 = 8; +pub const V4L2_CTRL_FLAG_INACTIVE: u32 = 16; +pub const V4L2_CTRL_FLAG_SLIDER: u32 = 32; +pub const V4L2_CTRL_FLAG_WRITE_ONLY: u32 = 64; +pub const V4L2_CTRL_FLAG_VOLATILE: u32 = 128; +pub const V4L2_CTRL_FLAG_HAS_PAYLOAD: u32 = 256; +pub const V4L2_CTRL_FLAG_EXECUTE_ON_WRITE: u32 = 512; +pub const V4L2_CTRL_FLAG_MODIFY_LAYOUT: u32 = 1024; +pub const V4L2_CTRL_FLAG_DYNAMIC_ARRAY: u32 = 2048; +pub const V4L2_CTRL_FLAG_NEXT_CTRL: u32 = 2147483648; +pub const V4L2_CTRL_FLAG_NEXT_COMPOUND: u32 = 1073741824; +pub const V4L2_CID_MAX_CTRLS: u32 = 1024; +pub const V4L2_CID_PRIVATE_BASE: u32 = 134217728; +pub const V4L2_TUNER_CAP_LOW: u32 = 1; +pub const V4L2_TUNER_CAP_NORM: u32 = 2; +pub const V4L2_TUNER_CAP_HWSEEK_BOUNDED: u32 = 4; +pub const V4L2_TUNER_CAP_HWSEEK_WRAP: u32 = 8; +pub const V4L2_TUNER_CAP_STEREO: u32 = 16; +pub const V4L2_TUNER_CAP_LANG2: u32 = 32; +pub const V4L2_TUNER_CAP_SAP: u32 = 32; +pub const V4L2_TUNER_CAP_LANG1: u32 = 64; +pub const V4L2_TUNER_CAP_RDS: u32 = 128; +pub const V4L2_TUNER_CAP_RDS_BLOCK_IO: u32 = 256; +pub const V4L2_TUNER_CAP_RDS_CONTROLS: u32 = 512; +pub const V4L2_TUNER_CAP_FREQ_BANDS: u32 = 1024; +pub const V4L2_TUNER_CAP_HWSEEK_PROG_LIM: u32 = 2048; +pub const V4L2_TUNER_CAP_1HZ: u32 = 4096; +pub const V4L2_TUNER_SUB_MONO: u32 = 1; +pub const V4L2_TUNER_SUB_STEREO: u32 = 2; +pub const V4L2_TUNER_SUB_LANG2: u32 = 4; +pub const V4L2_TUNER_SUB_SAP: u32 = 4; +pub const V4L2_TUNER_SUB_LANG1: u32 = 8; +pub const V4L2_TUNER_SUB_RDS: u32 = 16; +pub const V4L2_TUNER_MODE_MONO: u32 = 0; +pub const V4L2_TUNER_MODE_STEREO: u32 = 1; +pub const V4L2_TUNER_MODE_LANG2: u32 = 2; +pub const V4L2_TUNER_MODE_SAP: u32 = 2; +pub const V4L2_TUNER_MODE_LANG1: u32 = 3; +pub const V4L2_TUNER_MODE_LANG1_LANG2: u32 = 4; +pub const V4L2_BAND_MODULATION_VSB: u32 = 2; +pub const V4L2_BAND_MODULATION_FM: u32 = 4; +pub const V4L2_BAND_MODULATION_AM: u32 = 8; +pub const V4L2_RDS_BLOCK_MSK: u32 = 7; +pub const V4L2_RDS_BLOCK_A: u32 = 0; +pub const V4L2_RDS_BLOCK_B: u32 = 1; +pub const V4L2_RDS_BLOCK_C: u32 = 2; +pub const V4L2_RDS_BLOCK_D: u32 = 3; +pub const V4L2_RDS_BLOCK_C_ALT: u32 = 4; +pub const V4L2_RDS_BLOCK_INVALID: u32 = 7; +pub const V4L2_RDS_BLOCK_CORRECTED: u32 = 64; +pub const V4L2_RDS_BLOCK_ERROR: u32 = 128; +pub const V4L2_AUDCAP_STEREO: u32 = 1; +pub const V4L2_AUDCAP_AVL: u32 = 2; +pub const V4L2_AUDMODE_AVL: u32 = 1; +pub const V4L2_ENC_IDX_FRAME_I: u32 = 0; +pub const V4L2_ENC_IDX_FRAME_P: u32 = 1; +pub const V4L2_ENC_IDX_FRAME_B: u32 = 2; +pub const V4L2_ENC_IDX_FRAME_MASK: u32 = 15; +pub const V4L2_ENC_IDX_ENTRIES: u32 = 64; +pub const V4L2_ENC_CMD_START: u32 = 0; +pub const V4L2_ENC_CMD_STOP: u32 = 1; +pub const V4L2_ENC_CMD_PAUSE: u32 = 2; +pub const V4L2_ENC_CMD_RESUME: u32 = 3; +pub const V4L2_ENC_CMD_STOP_AT_GOP_END: u32 = 1; +pub const V4L2_DEC_CMD_START: u32 = 0; +pub const V4L2_DEC_CMD_STOP: u32 = 1; +pub const V4L2_DEC_CMD_PAUSE: u32 = 2; +pub const V4L2_DEC_CMD_RESUME: u32 = 3; +pub const V4L2_DEC_CMD_FLUSH: u32 = 4; +pub const V4L2_DEC_CMD_START_MUTE_AUDIO: u32 = 1; +pub const V4L2_DEC_CMD_PAUSE_TO_BLACK: u32 = 1; +pub const V4L2_DEC_CMD_STOP_TO_BLACK: u32 = 1; +pub const V4L2_DEC_CMD_STOP_IMMEDIATELY: u32 = 2; +pub const V4L2_DEC_START_FMT_NONE: u32 = 0; +pub const V4L2_DEC_START_FMT_GOP: u32 = 1; +pub const V4L2_VBI_UNSYNC: u32 = 1; +pub const V4L2_VBI_INTERLACED: u32 = 2; +pub const V4L2_VBI_ITU_525_F1_START: u32 = 1; +pub const V4L2_VBI_ITU_525_F2_START: u32 = 264; +pub const V4L2_VBI_ITU_625_F1_START: u32 = 1; +pub const V4L2_VBI_ITU_625_F2_START: u32 = 314; +pub const V4L2_SLICED_TELETEXT_B: u32 = 1; +pub const V4L2_SLICED_VPS: u32 = 1024; +pub const V4L2_SLICED_CAPTION_525: u32 = 4096; +pub const V4L2_SLICED_WSS_625: u32 = 16384; +pub const V4L2_SLICED_VBI_525: u32 = 4096; +pub const V4L2_SLICED_VBI_625: u32 = 17409; +pub const V4L2_MPEG_VBI_IVTV_TELETEXT_B: u32 = 1; +pub const V4L2_MPEG_VBI_IVTV_CAPTION_525: u32 = 4; +pub const V4L2_MPEG_VBI_IVTV_WSS_625: u32 = 5; +pub const V4L2_MPEG_VBI_IVTV_VPS: u32 = 7; +pub const V4L2_MPEG_VBI_IVTV_MAGIC0: &[u8; 5] = b"itv0\0"; +pub const V4L2_MPEG_VBI_IVTV_MAGIC1: &[u8; 5] = b"ITV0\0"; +pub const V4L2_EVENT_ALL: u32 = 0; +pub const V4L2_EVENT_VSYNC: u32 = 1; +pub const V4L2_EVENT_EOS: u32 = 2; +pub const V4L2_EVENT_CTRL: u32 = 3; +pub const V4L2_EVENT_FRAME_SYNC: u32 = 4; +pub const V4L2_EVENT_SOURCE_CHANGE: u32 = 5; +pub const V4L2_EVENT_MOTION_DET: u32 = 6; +pub const V4L2_EVENT_PRIVATE_START: u32 = 134217728; +pub const V4L2_EVENT_CTRL_CH_VALUE: u32 = 1; +pub const V4L2_EVENT_CTRL_CH_FLAGS: u32 = 2; +pub const V4L2_EVENT_CTRL_CH_RANGE: u32 = 4; +pub const V4L2_EVENT_CTRL_CH_DIMENSIONS: u32 = 8; +pub const V4L2_EVENT_SRC_CH_RESOLUTION: u32 = 1; +pub const V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ: u32 = 1; +pub const V4L2_EVENT_SUB_FL_SEND_INITIAL: u32 = 1; +pub const V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK: u32 = 2; +pub const V4L2_CHIP_MATCH_BRIDGE: u32 = 0; +pub const V4L2_CHIP_MATCH_SUBDEV: u32 = 4; +pub const V4L2_CHIP_MATCH_HOST: u32 = 0; +pub const V4L2_CHIP_MATCH_I2C_DRIVER: u32 = 1; +pub const V4L2_CHIP_MATCH_I2C_ADDR: u32 = 2; +pub const V4L2_CHIP_MATCH_AC97: u32 = 3; +pub const V4L2_CHIP_FL_READABLE: u32 = 1; +pub const V4L2_CHIP_FL_WRITABLE: u32 = 2; +pub const V4L2_CAP_ASYNCIO: u32 = 33554432; +pub type __s8 = ::std::os::raw::c_schar; +pub type __u8 = ::std::os::raw::c_uchar; +pub type __s16 = ::std::os::raw::c_short; +pub type __u16 = ::std::os::raw::c_ushort; +pub type __s32 = ::std::os::raw::c_int; +pub type __u32 = ::std::os::raw::c_uint; +pub type __s64 = ::std::os::raw::c_longlong; +pub type __u64 = ::std::os::raw::c_ulonglong; +pub type __le32 = __u32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_edid { + pub pad: __u32, + pub start_block: __u32, + pub blocks: __u32, + pub reserved: [__u32; 5usize], + pub edid: *mut __u8, +} +pub const v4l2_power_line_frequency_V4L2_CID_POWER_LINE_FREQUENCY_DISABLED: + v4l2_power_line_frequency = 0; +pub const v4l2_power_line_frequency_V4L2_CID_POWER_LINE_FREQUENCY_50HZ: v4l2_power_line_frequency = + 1; +pub const v4l2_power_line_frequency_V4L2_CID_POWER_LINE_FREQUENCY_60HZ: v4l2_power_line_frequency = + 2; +pub const v4l2_power_line_frequency_V4L2_CID_POWER_LINE_FREQUENCY_AUTO: v4l2_power_line_frequency = + 3; +pub type v4l2_power_line_frequency = ::std::os::raw::c_uint; +pub const v4l2_colorfx_V4L2_COLORFX_NONE: v4l2_colorfx = 0; +pub const v4l2_colorfx_V4L2_COLORFX_BW: v4l2_colorfx = 1; +pub const v4l2_colorfx_V4L2_COLORFX_SEPIA: v4l2_colorfx = 2; +pub const v4l2_colorfx_V4L2_COLORFX_NEGATIVE: v4l2_colorfx = 3; +pub const v4l2_colorfx_V4L2_COLORFX_EMBOSS: v4l2_colorfx = 4; +pub const v4l2_colorfx_V4L2_COLORFX_SKETCH: v4l2_colorfx = 5; +pub const v4l2_colorfx_V4L2_COLORFX_SKY_BLUE: v4l2_colorfx = 6; +pub const v4l2_colorfx_V4L2_COLORFX_GRASS_GREEN: v4l2_colorfx = 7; +pub const v4l2_colorfx_V4L2_COLORFX_SKIN_WHITEN: v4l2_colorfx = 8; +pub const v4l2_colorfx_V4L2_COLORFX_VIVID: v4l2_colorfx = 9; +pub const v4l2_colorfx_V4L2_COLORFX_AQUA: v4l2_colorfx = 10; +pub const v4l2_colorfx_V4L2_COLORFX_ART_FREEZE: v4l2_colorfx = 11; +pub const v4l2_colorfx_V4L2_COLORFX_SILHOUETTE: v4l2_colorfx = 12; +pub const v4l2_colorfx_V4L2_COLORFX_SOLARIZATION: v4l2_colorfx = 13; +pub const v4l2_colorfx_V4L2_COLORFX_ANTIQUE: v4l2_colorfx = 14; +pub const v4l2_colorfx_V4L2_COLORFX_SET_CBCR: v4l2_colorfx = 15; +pub const v4l2_colorfx_V4L2_COLORFX_SET_RGB: v4l2_colorfx = 16; +pub type v4l2_colorfx = ::std::os::raw::c_uint; +pub const v4l2_mpeg_stream_type_V4L2_MPEG_STREAM_TYPE_MPEG2_PS: v4l2_mpeg_stream_type = 0; +pub const v4l2_mpeg_stream_type_V4L2_MPEG_STREAM_TYPE_MPEG2_TS: v4l2_mpeg_stream_type = 1; +pub const v4l2_mpeg_stream_type_V4L2_MPEG_STREAM_TYPE_MPEG1_SS: v4l2_mpeg_stream_type = 2; +pub const v4l2_mpeg_stream_type_V4L2_MPEG_STREAM_TYPE_MPEG2_DVD: v4l2_mpeg_stream_type = 3; +pub const v4l2_mpeg_stream_type_V4L2_MPEG_STREAM_TYPE_MPEG1_VCD: v4l2_mpeg_stream_type = 4; +pub const v4l2_mpeg_stream_type_V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD: v4l2_mpeg_stream_type = 5; +pub type v4l2_mpeg_stream_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_stream_vbi_fmt_V4L2_MPEG_STREAM_VBI_FMT_NONE: v4l2_mpeg_stream_vbi_fmt = 0; +pub const v4l2_mpeg_stream_vbi_fmt_V4L2_MPEG_STREAM_VBI_FMT_IVTV: v4l2_mpeg_stream_vbi_fmt = 1; +pub type v4l2_mpeg_stream_vbi_fmt = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_sampling_freq_V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100: + v4l2_mpeg_audio_sampling_freq = 0; +pub const v4l2_mpeg_audio_sampling_freq_V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000: + v4l2_mpeg_audio_sampling_freq = 1; +pub const v4l2_mpeg_audio_sampling_freq_V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000: + v4l2_mpeg_audio_sampling_freq = 2; +pub type v4l2_mpeg_audio_sampling_freq = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_encoding_V4L2_MPEG_AUDIO_ENCODING_LAYER_1: v4l2_mpeg_audio_encoding = 0; +pub const v4l2_mpeg_audio_encoding_V4L2_MPEG_AUDIO_ENCODING_LAYER_2: v4l2_mpeg_audio_encoding = 1; +pub const v4l2_mpeg_audio_encoding_V4L2_MPEG_AUDIO_ENCODING_LAYER_3: v4l2_mpeg_audio_encoding = 2; +pub const v4l2_mpeg_audio_encoding_V4L2_MPEG_AUDIO_ENCODING_AAC: v4l2_mpeg_audio_encoding = 3; +pub const v4l2_mpeg_audio_encoding_V4L2_MPEG_AUDIO_ENCODING_AC3: v4l2_mpeg_audio_encoding = 4; +pub type v4l2_mpeg_audio_encoding = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_32K: v4l2_mpeg_audio_l1_bitrate = 0; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_64K: v4l2_mpeg_audio_l1_bitrate = 1; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_96K: v4l2_mpeg_audio_l1_bitrate = 2; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_128K: v4l2_mpeg_audio_l1_bitrate = + 3; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_160K: v4l2_mpeg_audio_l1_bitrate = + 4; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_192K: v4l2_mpeg_audio_l1_bitrate = + 5; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_224K: v4l2_mpeg_audio_l1_bitrate = + 6; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_256K: v4l2_mpeg_audio_l1_bitrate = + 7; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_288K: v4l2_mpeg_audio_l1_bitrate = + 8; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_320K: v4l2_mpeg_audio_l1_bitrate = + 9; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_352K: v4l2_mpeg_audio_l1_bitrate = + 10; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_384K: v4l2_mpeg_audio_l1_bitrate = + 11; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_416K: v4l2_mpeg_audio_l1_bitrate = + 12; +pub const v4l2_mpeg_audio_l1_bitrate_V4L2_MPEG_AUDIO_L1_BITRATE_448K: v4l2_mpeg_audio_l1_bitrate = + 13; +pub type v4l2_mpeg_audio_l1_bitrate = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_32K: v4l2_mpeg_audio_l2_bitrate = 0; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_48K: v4l2_mpeg_audio_l2_bitrate = 1; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_56K: v4l2_mpeg_audio_l2_bitrate = 2; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_64K: v4l2_mpeg_audio_l2_bitrate = 3; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_80K: v4l2_mpeg_audio_l2_bitrate = 4; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_96K: v4l2_mpeg_audio_l2_bitrate = 5; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_112K: v4l2_mpeg_audio_l2_bitrate = + 6; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_128K: v4l2_mpeg_audio_l2_bitrate = + 7; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_160K: v4l2_mpeg_audio_l2_bitrate = + 8; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_192K: v4l2_mpeg_audio_l2_bitrate = + 9; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_224K: v4l2_mpeg_audio_l2_bitrate = + 10; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_256K: v4l2_mpeg_audio_l2_bitrate = + 11; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_320K: v4l2_mpeg_audio_l2_bitrate = + 12; +pub const v4l2_mpeg_audio_l2_bitrate_V4L2_MPEG_AUDIO_L2_BITRATE_384K: v4l2_mpeg_audio_l2_bitrate = + 13; +pub type v4l2_mpeg_audio_l2_bitrate = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_32K: v4l2_mpeg_audio_l3_bitrate = 0; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_40K: v4l2_mpeg_audio_l3_bitrate = 1; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_48K: v4l2_mpeg_audio_l3_bitrate = 2; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_56K: v4l2_mpeg_audio_l3_bitrate = 3; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_64K: v4l2_mpeg_audio_l3_bitrate = 4; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_80K: v4l2_mpeg_audio_l3_bitrate = 5; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_96K: v4l2_mpeg_audio_l3_bitrate = 6; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_112K: v4l2_mpeg_audio_l3_bitrate = + 7; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_128K: v4l2_mpeg_audio_l3_bitrate = + 8; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_160K: v4l2_mpeg_audio_l3_bitrate = + 9; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_192K: v4l2_mpeg_audio_l3_bitrate = + 10; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_224K: v4l2_mpeg_audio_l3_bitrate = + 11; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_256K: v4l2_mpeg_audio_l3_bitrate = + 12; +pub const v4l2_mpeg_audio_l3_bitrate_V4L2_MPEG_AUDIO_L3_BITRATE_320K: v4l2_mpeg_audio_l3_bitrate = + 13; +pub type v4l2_mpeg_audio_l3_bitrate = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_mode_V4L2_MPEG_AUDIO_MODE_STEREO: v4l2_mpeg_audio_mode = 0; +pub const v4l2_mpeg_audio_mode_V4L2_MPEG_AUDIO_MODE_JOINT_STEREO: v4l2_mpeg_audio_mode = 1; +pub const v4l2_mpeg_audio_mode_V4L2_MPEG_AUDIO_MODE_DUAL: v4l2_mpeg_audio_mode = 2; +pub const v4l2_mpeg_audio_mode_V4L2_MPEG_AUDIO_MODE_MONO: v4l2_mpeg_audio_mode = 3; +pub type v4l2_mpeg_audio_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_mode_extension_V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4: + v4l2_mpeg_audio_mode_extension = 0; +pub const v4l2_mpeg_audio_mode_extension_V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8: + v4l2_mpeg_audio_mode_extension = 1; +pub const v4l2_mpeg_audio_mode_extension_V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12: + v4l2_mpeg_audio_mode_extension = 2; +pub const v4l2_mpeg_audio_mode_extension_V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16: + v4l2_mpeg_audio_mode_extension = 3; +pub type v4l2_mpeg_audio_mode_extension = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_emphasis_V4L2_MPEG_AUDIO_EMPHASIS_NONE: v4l2_mpeg_audio_emphasis = 0; +pub const v4l2_mpeg_audio_emphasis_V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS: v4l2_mpeg_audio_emphasis = + 1; +pub const v4l2_mpeg_audio_emphasis_V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17: v4l2_mpeg_audio_emphasis = 2; +pub type v4l2_mpeg_audio_emphasis = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_crc_V4L2_MPEG_AUDIO_CRC_NONE: v4l2_mpeg_audio_crc = 0; +pub const v4l2_mpeg_audio_crc_V4L2_MPEG_AUDIO_CRC_CRC16: v4l2_mpeg_audio_crc = 1; +pub type v4l2_mpeg_audio_crc = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_32K: v4l2_mpeg_audio_ac3_bitrate = + 0; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_40K: v4l2_mpeg_audio_ac3_bitrate = + 1; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_48K: v4l2_mpeg_audio_ac3_bitrate = + 2; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_56K: v4l2_mpeg_audio_ac3_bitrate = + 3; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_64K: v4l2_mpeg_audio_ac3_bitrate = + 4; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_80K: v4l2_mpeg_audio_ac3_bitrate = + 5; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_96K: v4l2_mpeg_audio_ac3_bitrate = + 6; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_112K: + v4l2_mpeg_audio_ac3_bitrate = 7; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_128K: + v4l2_mpeg_audio_ac3_bitrate = 8; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_160K: + v4l2_mpeg_audio_ac3_bitrate = 9; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_192K: + v4l2_mpeg_audio_ac3_bitrate = 10; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_224K: + v4l2_mpeg_audio_ac3_bitrate = 11; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_256K: + v4l2_mpeg_audio_ac3_bitrate = 12; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_320K: + v4l2_mpeg_audio_ac3_bitrate = 13; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_384K: + v4l2_mpeg_audio_ac3_bitrate = 14; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_448K: + v4l2_mpeg_audio_ac3_bitrate = 15; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_512K: + v4l2_mpeg_audio_ac3_bitrate = 16; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_576K: + v4l2_mpeg_audio_ac3_bitrate = 17; +pub const v4l2_mpeg_audio_ac3_bitrate_V4L2_MPEG_AUDIO_AC3_BITRATE_640K: + v4l2_mpeg_audio_ac3_bitrate = 18; +pub type v4l2_mpeg_audio_ac3_bitrate = ::std::os::raw::c_uint; +pub const v4l2_mpeg_audio_dec_playback_V4L2_MPEG_AUDIO_DEC_PLAYBACK_AUTO: + v4l2_mpeg_audio_dec_playback = 0; +pub const v4l2_mpeg_audio_dec_playback_V4L2_MPEG_AUDIO_DEC_PLAYBACK_STEREO: + v4l2_mpeg_audio_dec_playback = 1; +pub const v4l2_mpeg_audio_dec_playback_V4L2_MPEG_AUDIO_DEC_PLAYBACK_LEFT: + v4l2_mpeg_audio_dec_playback = 2; +pub const v4l2_mpeg_audio_dec_playback_V4L2_MPEG_AUDIO_DEC_PLAYBACK_RIGHT: + v4l2_mpeg_audio_dec_playback = 3; +pub const v4l2_mpeg_audio_dec_playback_V4L2_MPEG_AUDIO_DEC_PLAYBACK_MONO: + v4l2_mpeg_audio_dec_playback = 4; +pub const v4l2_mpeg_audio_dec_playback_V4L2_MPEG_AUDIO_DEC_PLAYBACK_SWAPPED_STEREO: + v4l2_mpeg_audio_dec_playback = 5; +pub type v4l2_mpeg_audio_dec_playback = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_encoding_V4L2_MPEG_VIDEO_ENCODING_MPEG_1: v4l2_mpeg_video_encoding = 0; +pub const v4l2_mpeg_video_encoding_V4L2_MPEG_VIDEO_ENCODING_MPEG_2: v4l2_mpeg_video_encoding = 1; +pub const v4l2_mpeg_video_encoding_V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC: v4l2_mpeg_video_encoding = + 2; +pub type v4l2_mpeg_video_encoding = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_aspect_V4L2_MPEG_VIDEO_ASPECT_1x1: v4l2_mpeg_video_aspect = 0; +pub const v4l2_mpeg_video_aspect_V4L2_MPEG_VIDEO_ASPECT_4x3: v4l2_mpeg_video_aspect = 1; +pub const v4l2_mpeg_video_aspect_V4L2_MPEG_VIDEO_ASPECT_16x9: v4l2_mpeg_video_aspect = 2; +pub const v4l2_mpeg_video_aspect_V4L2_MPEG_VIDEO_ASPECT_221x100: v4l2_mpeg_video_aspect = 3; +pub type v4l2_mpeg_video_aspect = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_bitrate_mode_V4L2_MPEG_VIDEO_BITRATE_MODE_VBR: + v4l2_mpeg_video_bitrate_mode = 0; +pub const v4l2_mpeg_video_bitrate_mode_V4L2_MPEG_VIDEO_BITRATE_MODE_CBR: + v4l2_mpeg_video_bitrate_mode = 1; +pub const v4l2_mpeg_video_bitrate_mode_V4L2_MPEG_VIDEO_BITRATE_MODE_CQ: + v4l2_mpeg_video_bitrate_mode = 2; +pub type v4l2_mpeg_video_bitrate_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_header_mode_V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE: + v4l2_mpeg_video_header_mode = 0; +pub const v4l2_mpeg_video_header_mode_V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME: + v4l2_mpeg_video_header_mode = 1; +pub type v4l2_mpeg_video_header_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_multi_slice_mode_V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + v4l2_mpeg_video_multi_slice_mode = 0; +pub const v4l2_mpeg_video_multi_slice_mode_V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: + v4l2_mpeg_video_multi_slice_mode = 1; +pub const v4l2_mpeg_video_multi_slice_mode_V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: + v4l2_mpeg_video_multi_slice_mode = 2; +pub const v4l2_mpeg_video_multi_slice_mode_V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + v4l2_mpeg_video_multi_slice_mode = 1; +pub const v4l2_mpeg_video_multi_slice_mode_V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + v4l2_mpeg_video_multi_slice_mode = 2; +pub type v4l2_mpeg_video_multi_slice_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_intra_refresh_period_type_V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM : v4l2_mpeg_video_intra_refresh_period_type = 0 ; +pub const v4l2_mpeg_video_intra_refresh_period_type_V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC : v4l2_mpeg_video_intra_refresh_period_type = 1 ; +pub type v4l2_mpeg_video_intra_refresh_period_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_mpeg2_level_V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW: v4l2_mpeg_video_mpeg2_level = + 0; +pub const v4l2_mpeg_video_mpeg2_level_V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN: + v4l2_mpeg_video_mpeg2_level = 1; +pub const v4l2_mpeg_video_mpeg2_level_V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440: + v4l2_mpeg_video_mpeg2_level = 2; +pub const v4l2_mpeg_video_mpeg2_level_V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH: + v4l2_mpeg_video_mpeg2_level = 3; +pub type v4l2_mpeg_video_mpeg2_level = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_mpeg2_profile_V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE: + v4l2_mpeg_video_mpeg2_profile = 0; +pub const v4l2_mpeg_video_mpeg2_profile_V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN: + v4l2_mpeg_video_mpeg2_profile = 1; +pub const v4l2_mpeg_video_mpeg2_profile_V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE: + v4l2_mpeg_video_mpeg2_profile = 2; +pub const v4l2_mpeg_video_mpeg2_profile_V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE: + v4l2_mpeg_video_mpeg2_profile = 3; +pub const v4l2_mpeg_video_mpeg2_profile_V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH: + v4l2_mpeg_video_mpeg2_profile = 4; +pub const v4l2_mpeg_video_mpeg2_profile_V4L2_MPEG_VIDEO_MPEG2_PROFILE_MULTIVIEW: + v4l2_mpeg_video_mpeg2_profile = 5; +pub type v4l2_mpeg_video_mpeg2_profile = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_entropy_mode_V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC: + v4l2_mpeg_video_h264_entropy_mode = 0; +pub const v4l2_mpeg_video_h264_entropy_mode_V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC: + v4l2_mpeg_video_h264_entropy_mode = 1; +pub type v4l2_mpeg_video_h264_entropy_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_1_0: v4l2_mpeg_video_h264_level = 0; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_1B: v4l2_mpeg_video_h264_level = 1; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_1_1: v4l2_mpeg_video_h264_level = 2; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_1_2: v4l2_mpeg_video_h264_level = 3; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_1_3: v4l2_mpeg_video_h264_level = 4; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_2_0: v4l2_mpeg_video_h264_level = 5; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_2_1: v4l2_mpeg_video_h264_level = 6; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_2_2: v4l2_mpeg_video_h264_level = 7; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_3_0: v4l2_mpeg_video_h264_level = 8; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_3_1: v4l2_mpeg_video_h264_level = 9; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_3_2: v4l2_mpeg_video_h264_level = + 10; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_4_0: v4l2_mpeg_video_h264_level = + 11; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_4_1: v4l2_mpeg_video_h264_level = + 12; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_4_2: v4l2_mpeg_video_h264_level = + 13; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_5_0: v4l2_mpeg_video_h264_level = + 14; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_5_1: v4l2_mpeg_video_h264_level = + 15; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_5_2: v4l2_mpeg_video_h264_level = + 16; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_6_0: v4l2_mpeg_video_h264_level = + 17; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_6_1: v4l2_mpeg_video_h264_level = + 18; +pub const v4l2_mpeg_video_h264_level_V4L2_MPEG_VIDEO_H264_LEVEL_6_2: v4l2_mpeg_video_h264_level = + 19; +pub type v4l2_mpeg_video_h264_level = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_loop_filter_mode_V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + v4l2_mpeg_video_h264_loop_filter_mode = 0; +pub const v4l2_mpeg_video_h264_loop_filter_mode_V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + v4l2_mpeg_video_h264_loop_filter_mode = 1; +pub const v4l2_mpeg_video_h264_loop_filter_mode_V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY : v4l2_mpeg_video_h264_loop_filter_mode = 2 ; +pub type v4l2_mpeg_video_h264_loop_filter_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + v4l2_mpeg_video_h264_profile = 0; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + v4l2_mpeg_video_h264_profile = 1; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + v4l2_mpeg_video_h264_profile = 2; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + v4l2_mpeg_video_h264_profile = 3; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + v4l2_mpeg_video_h264_profile = 4; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + v4l2_mpeg_video_h264_profile = 5; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + v4l2_mpeg_video_h264_profile = 6; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + v4l2_mpeg_video_h264_profile = 7; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10_INTRA: + v4l2_mpeg_video_h264_profile = 8; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422_INTRA: + v4l2_mpeg_video_h264_profile = 9; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_INTRA: + v4l2_mpeg_video_h264_profile = 10; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_CAVLC_444_INTRA: + v4l2_mpeg_video_h264_profile = 11; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_BASELINE: + v4l2_mpeg_video_h264_profile = 12; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH: + v4l2_mpeg_video_h264_profile = 13; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_SCALABLE_HIGH_INTRA: + v4l2_mpeg_video_h264_profile = 14; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH: + v4l2_mpeg_video_h264_profile = 15; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: + v4l2_mpeg_video_h264_profile = 16; +pub const v4l2_mpeg_video_h264_profile_V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + v4l2_mpeg_video_h264_profile = 17; +pub type v4l2_mpeg_video_h264_profile = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED: + v4l2_mpeg_video_h264_vui_sar_idc = 0; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1: + v4l2_mpeg_video_h264_vui_sar_idc = 1; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11: + v4l2_mpeg_video_h264_vui_sar_idc = 2; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11: + v4l2_mpeg_video_h264_vui_sar_idc = 3; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11: + v4l2_mpeg_video_h264_vui_sar_idc = 4; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33: + v4l2_mpeg_video_h264_vui_sar_idc = 5; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11: + v4l2_mpeg_video_h264_vui_sar_idc = 6; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11: + v4l2_mpeg_video_h264_vui_sar_idc = 7; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11: + v4l2_mpeg_video_h264_vui_sar_idc = 8; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33: + v4l2_mpeg_video_h264_vui_sar_idc = 9; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11: + v4l2_mpeg_video_h264_vui_sar_idc = 10; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11: + v4l2_mpeg_video_h264_vui_sar_idc = 11; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33: + v4l2_mpeg_video_h264_vui_sar_idc = 12; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99: + v4l2_mpeg_video_h264_vui_sar_idc = 13; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3: + v4l2_mpeg_video_h264_vui_sar_idc = 14; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2: + v4l2_mpeg_video_h264_vui_sar_idc = 15; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1: + v4l2_mpeg_video_h264_vui_sar_idc = 16; +pub const v4l2_mpeg_video_h264_vui_sar_idc_V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED: + v4l2_mpeg_video_h264_vui_sar_idc = 17; +pub type v4l2_mpeg_video_h264_vui_sar_idc = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_sei_fp_arrangement_type_V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_CHECKERBOARD : v4l2_mpeg_video_h264_sei_fp_arrangement_type = 0 ; +pub const v4l2_mpeg_video_h264_sei_fp_arrangement_type_V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_COLUMN : v4l2_mpeg_video_h264_sei_fp_arrangement_type = 1 ; +pub const v4l2_mpeg_video_h264_sei_fp_arrangement_type_V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_ROW : v4l2_mpeg_video_h264_sei_fp_arrangement_type = 2 ; +pub const v4l2_mpeg_video_h264_sei_fp_arrangement_type_V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_SIDE_BY_SIDE : v4l2_mpeg_video_h264_sei_fp_arrangement_type = 3 ; +pub const v4l2_mpeg_video_h264_sei_fp_arrangement_type_V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TOP_BOTTOM : v4l2_mpeg_video_h264_sei_fp_arrangement_type = 4 ; +pub const v4l2_mpeg_video_h264_sei_fp_arrangement_type_V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL : v4l2_mpeg_video_h264_sei_fp_arrangement_type = 5 ; +pub type v4l2_mpeg_video_h264_sei_fp_arrangement_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_fmo_map_type_V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_INTERLEAVED_SLICES: + v4l2_mpeg_video_h264_fmo_map_type = 0; +pub const v4l2_mpeg_video_h264_fmo_map_type_V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES: + v4l2_mpeg_video_h264_fmo_map_type = 1; +pub const v4l2_mpeg_video_h264_fmo_map_type_V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_FOREGROUND_WITH_LEFT_OVER : v4l2_mpeg_video_h264_fmo_map_type = 2 ; +pub const v4l2_mpeg_video_h264_fmo_map_type_V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_BOX_OUT: + v4l2_mpeg_video_h264_fmo_map_type = 3; +pub const v4l2_mpeg_video_h264_fmo_map_type_V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_RASTER_SCAN: + v4l2_mpeg_video_h264_fmo_map_type = 4; +pub const v4l2_mpeg_video_h264_fmo_map_type_V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_WIPE_SCAN: + v4l2_mpeg_video_h264_fmo_map_type = 5; +pub const v4l2_mpeg_video_h264_fmo_map_type_V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT: + v4l2_mpeg_video_h264_fmo_map_type = 6; +pub type v4l2_mpeg_video_h264_fmo_map_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_fmo_change_dir_V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_RIGHT: + v4l2_mpeg_video_h264_fmo_change_dir = 0; +pub const v4l2_mpeg_video_h264_fmo_change_dir_V4L2_MPEG_VIDEO_H264_FMO_CHANGE_DIR_LEFT: + v4l2_mpeg_video_h264_fmo_change_dir = 1; +pub type v4l2_mpeg_video_h264_fmo_change_dir = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_h264_hierarchical_coding_type_V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B : v4l2_mpeg_video_h264_hierarchical_coding_type = 0 ; +pub const v4l2_mpeg_video_h264_hierarchical_coding_type_V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P : v4l2_mpeg_video_h264_hierarchical_coding_type = 1 ; +pub type v4l2_mpeg_video_h264_hierarchical_coding_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_0: v4l2_mpeg_video_mpeg4_level = + 0; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B: v4l2_mpeg_video_mpeg4_level = + 1; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_1: v4l2_mpeg_video_mpeg4_level = + 2; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_2: v4l2_mpeg_video_mpeg4_level = + 3; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_3: v4l2_mpeg_video_mpeg4_level = + 4; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B: v4l2_mpeg_video_mpeg4_level = + 5; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_4: v4l2_mpeg_video_mpeg4_level = + 6; +pub const v4l2_mpeg_video_mpeg4_level_V4L2_MPEG_VIDEO_MPEG4_LEVEL_5: v4l2_mpeg_video_mpeg4_level = + 7; +pub type v4l2_mpeg_video_mpeg4_level = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_mpeg4_profile_V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: + v4l2_mpeg_video_mpeg4_profile = 0; +pub const v4l2_mpeg_video_mpeg4_profile_V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: + v4l2_mpeg_video_mpeg4_profile = 1; +pub const v4l2_mpeg_video_mpeg4_profile_V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE: + v4l2_mpeg_video_mpeg4_profile = 2; +pub const v4l2_mpeg_video_mpeg4_profile_V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE: + v4l2_mpeg_video_mpeg4_profile = 3; +pub const v4l2_mpeg_video_mpeg4_profile_V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY: + v4l2_mpeg_video_mpeg4_profile = 4; +pub type v4l2_mpeg_video_mpeg4_profile = ::std::os::raw::c_uint; +pub const v4l2_vp8_num_partitions_V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION: v4l2_vp8_num_partitions = 0; +pub const v4l2_vp8_num_partitions_V4L2_CID_MPEG_VIDEO_VPX_2_PARTITIONS: v4l2_vp8_num_partitions = 1; +pub const v4l2_vp8_num_partitions_V4L2_CID_MPEG_VIDEO_VPX_4_PARTITIONS: v4l2_vp8_num_partitions = 2; +pub const v4l2_vp8_num_partitions_V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS: v4l2_vp8_num_partitions = 3; +pub type v4l2_vp8_num_partitions = ::std::os::raw::c_uint; +pub const v4l2_vp8_num_ref_frames_V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME: v4l2_vp8_num_ref_frames = 0; +pub const v4l2_vp8_num_ref_frames_V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME: v4l2_vp8_num_ref_frames = 1; +pub const v4l2_vp8_num_ref_frames_V4L2_CID_MPEG_VIDEO_VPX_3_REF_FRAME: v4l2_vp8_num_ref_frames = 2; +pub type v4l2_vp8_num_ref_frames = ::std::os::raw::c_uint; +pub const v4l2_vp8_golden_frame_sel_V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV: + v4l2_vp8_golden_frame_sel = 0; +pub const v4l2_vp8_golden_frame_sel_V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD: + v4l2_vp8_golden_frame_sel = 1; +pub type v4l2_vp8_golden_frame_sel = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_vp8_profile_V4L2_MPEG_VIDEO_VP8_PROFILE_0: v4l2_mpeg_video_vp8_profile = + 0; +pub const v4l2_mpeg_video_vp8_profile_V4L2_MPEG_VIDEO_VP8_PROFILE_1: v4l2_mpeg_video_vp8_profile = + 1; +pub const v4l2_mpeg_video_vp8_profile_V4L2_MPEG_VIDEO_VP8_PROFILE_2: v4l2_mpeg_video_vp8_profile = + 2; +pub const v4l2_mpeg_video_vp8_profile_V4L2_MPEG_VIDEO_VP8_PROFILE_3: v4l2_mpeg_video_vp8_profile = + 3; +pub type v4l2_mpeg_video_vp8_profile = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_vp9_profile_V4L2_MPEG_VIDEO_VP9_PROFILE_0: v4l2_mpeg_video_vp9_profile = + 0; +pub const v4l2_mpeg_video_vp9_profile_V4L2_MPEG_VIDEO_VP9_PROFILE_1: v4l2_mpeg_video_vp9_profile = + 1; +pub const v4l2_mpeg_video_vp9_profile_V4L2_MPEG_VIDEO_VP9_PROFILE_2: v4l2_mpeg_video_vp9_profile = + 2; +pub const v4l2_mpeg_video_vp9_profile_V4L2_MPEG_VIDEO_VP9_PROFILE_3: v4l2_mpeg_video_vp9_profile = + 3; +pub type v4l2_mpeg_video_vp9_profile = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_1_0: v4l2_mpeg_video_vp9_level = 0; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_1_1: v4l2_mpeg_video_vp9_level = 1; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_2_0: v4l2_mpeg_video_vp9_level = 2; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_2_1: v4l2_mpeg_video_vp9_level = 3; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_3_0: v4l2_mpeg_video_vp9_level = 4; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_3_1: v4l2_mpeg_video_vp9_level = 5; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_4_0: v4l2_mpeg_video_vp9_level = 6; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_4_1: v4l2_mpeg_video_vp9_level = 7; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_5_0: v4l2_mpeg_video_vp9_level = 8; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_5_1: v4l2_mpeg_video_vp9_level = 9; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_5_2: v4l2_mpeg_video_vp9_level = 10; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_6_0: v4l2_mpeg_video_vp9_level = 11; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_6_1: v4l2_mpeg_video_vp9_level = 12; +pub const v4l2_mpeg_video_vp9_level_V4L2_MPEG_VIDEO_VP9_LEVEL_6_2: v4l2_mpeg_video_vp9_level = 13; +pub type v4l2_mpeg_video_vp9_level = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_hevc_hier_coding_type_V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B: + v4l2_mpeg_video_hevc_hier_coding_type = 0; +pub const v4l2_mpeg_video_hevc_hier_coding_type_V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P: + v4l2_mpeg_video_hevc_hier_coding_type = 1; +pub type v4l2_mpeg_video_hevc_hier_coding_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_hevc_profile_V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN: + v4l2_mpeg_video_hevc_profile = 0; +pub const v4l2_mpeg_video_hevc_profile_V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE: + v4l2_mpeg_video_hevc_profile = 1; +pub const v4l2_mpeg_video_hevc_profile_V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10: + v4l2_mpeg_video_hevc_profile = 2; +pub type v4l2_mpeg_video_hevc_profile = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_1: v4l2_mpeg_video_hevc_level = 0; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_2: v4l2_mpeg_video_hevc_level = 1; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1: v4l2_mpeg_video_hevc_level = 2; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_3: v4l2_mpeg_video_hevc_level = 3; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1: v4l2_mpeg_video_hevc_level = 4; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_4: v4l2_mpeg_video_hevc_level = 5; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1: v4l2_mpeg_video_hevc_level = 6; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_5: v4l2_mpeg_video_hevc_level = 7; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1: v4l2_mpeg_video_hevc_level = 8; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2: v4l2_mpeg_video_hevc_level = 9; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_6: v4l2_mpeg_video_hevc_level = 10; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1: v4l2_mpeg_video_hevc_level = + 11; +pub const v4l2_mpeg_video_hevc_level_V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2: v4l2_mpeg_video_hevc_level = + 12; +pub type v4l2_mpeg_video_hevc_level = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_hevc_tier_V4L2_MPEG_VIDEO_HEVC_TIER_MAIN: v4l2_mpeg_video_hevc_tier = 0; +pub const v4l2_mpeg_video_hevc_tier_V4L2_MPEG_VIDEO_HEVC_TIER_HIGH: v4l2_mpeg_video_hevc_tier = 1; +pub type v4l2_mpeg_video_hevc_tier = ::std::os::raw::c_uint; +pub const v4l2_cid_mpeg_video_hevc_loop_filter_mode_V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED : v4l2_cid_mpeg_video_hevc_loop_filter_mode = 0 ; +pub const v4l2_cid_mpeg_video_hevc_loop_filter_mode_V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED : v4l2_cid_mpeg_video_hevc_loop_filter_mode = 1 ; +pub const v4l2_cid_mpeg_video_hevc_loop_filter_mode_V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY : v4l2_cid_mpeg_video_hevc_loop_filter_mode = 2 ; +pub type v4l2_cid_mpeg_video_hevc_loop_filter_mode = ::std::os::raw::c_uint; +pub const v4l2_cid_mpeg_video_hevc_refresh_type_V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE: + v4l2_cid_mpeg_video_hevc_refresh_type = 0; +pub const v4l2_cid_mpeg_video_hevc_refresh_type_V4L2_MPEG_VIDEO_HEVC_REFRESH_CRA: + v4l2_cid_mpeg_video_hevc_refresh_type = 1; +pub const v4l2_cid_mpeg_video_hevc_refresh_type_V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR: + v4l2_cid_mpeg_video_hevc_refresh_type = 2; +pub type v4l2_cid_mpeg_video_hevc_refresh_type = ::std::os::raw::c_uint; +pub const v4l2_cid_mpeg_video_hevc_size_of_length_field_V4L2_MPEG_VIDEO_HEVC_SIZE_0: + v4l2_cid_mpeg_video_hevc_size_of_length_field = 0; +pub const v4l2_cid_mpeg_video_hevc_size_of_length_field_V4L2_MPEG_VIDEO_HEVC_SIZE_1: + v4l2_cid_mpeg_video_hevc_size_of_length_field = 1; +pub const v4l2_cid_mpeg_video_hevc_size_of_length_field_V4L2_MPEG_VIDEO_HEVC_SIZE_2: + v4l2_cid_mpeg_video_hevc_size_of_length_field = 2; +pub const v4l2_cid_mpeg_video_hevc_size_of_length_field_V4L2_MPEG_VIDEO_HEVC_SIZE_4: + v4l2_cid_mpeg_video_hevc_size_of_length_field = 3; +pub type v4l2_cid_mpeg_video_hevc_size_of_length_field = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_frame_skip_mode_V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED: + v4l2_mpeg_video_frame_skip_mode = 0; +pub const v4l2_mpeg_video_frame_skip_mode_V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT: + v4l2_mpeg_video_frame_skip_mode = 1; +pub const v4l2_mpeg_video_frame_skip_mode_V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT: + v4l2_mpeg_video_frame_skip_mode = 2; +pub type v4l2_mpeg_video_frame_skip_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_av1_profile_V4L2_MPEG_VIDEO_AV1_PROFILE_MAIN: + v4l2_mpeg_video_av1_profile = 0; +pub const v4l2_mpeg_video_av1_profile_V4L2_MPEG_VIDEO_AV1_PROFILE_HIGH: + v4l2_mpeg_video_av1_profile = 1; +pub const v4l2_mpeg_video_av1_profile_V4L2_MPEG_VIDEO_AV1_PROFILE_PROFESSIONAL: + v4l2_mpeg_video_av1_profile = 2; +pub type v4l2_mpeg_video_av1_profile = ::std::os::raw::c_uint; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_2_0: v4l2_mpeg_video_av1_level = 0; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_2_1: v4l2_mpeg_video_av1_level = 1; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_2_2: v4l2_mpeg_video_av1_level = 2; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_2_3: v4l2_mpeg_video_av1_level = 3; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_3_0: v4l2_mpeg_video_av1_level = 4; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_3_1: v4l2_mpeg_video_av1_level = 5; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_3_2: v4l2_mpeg_video_av1_level = 6; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_3_3: v4l2_mpeg_video_av1_level = 7; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_4_0: v4l2_mpeg_video_av1_level = 8; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_4_1: v4l2_mpeg_video_av1_level = 9; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_4_2: v4l2_mpeg_video_av1_level = 10; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_4_3: v4l2_mpeg_video_av1_level = 11; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_5_0: v4l2_mpeg_video_av1_level = 12; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_5_1: v4l2_mpeg_video_av1_level = 13; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_5_2: v4l2_mpeg_video_av1_level = 14; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_5_3: v4l2_mpeg_video_av1_level = 15; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_6_0: v4l2_mpeg_video_av1_level = 16; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_6_1: v4l2_mpeg_video_av1_level = 17; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_6_2: v4l2_mpeg_video_av1_level = 18; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_6_3: v4l2_mpeg_video_av1_level = 19; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_7_0: v4l2_mpeg_video_av1_level = 20; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_7_1: v4l2_mpeg_video_av1_level = 21; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_7_2: v4l2_mpeg_video_av1_level = 22; +pub const v4l2_mpeg_video_av1_level_V4L2_MPEG_VIDEO_AV1_LEVEL_7_3: v4l2_mpeg_video_av1_level = 23; +pub type v4l2_mpeg_video_av1_level = ::std::os::raw::c_uint; +pub const v4l2_mpeg_cx2341x_video_spatial_filter_mode_V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL : v4l2_mpeg_cx2341x_video_spatial_filter_mode = 0 ; +pub const v4l2_mpeg_cx2341x_video_spatial_filter_mode_V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO : v4l2_mpeg_cx2341x_video_spatial_filter_mode = 1 ; +pub type v4l2_mpeg_cx2341x_video_spatial_filter_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_cx2341x_video_luma_spatial_filter_type_V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF : v4l2_mpeg_cx2341x_video_luma_spatial_filter_type = 0 ; +pub const v4l2_mpeg_cx2341x_video_luma_spatial_filter_type_V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR : v4l2_mpeg_cx2341x_video_luma_spatial_filter_type = 1 ; +pub const v4l2_mpeg_cx2341x_video_luma_spatial_filter_type_V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT : v4l2_mpeg_cx2341x_video_luma_spatial_filter_type = 2 ; +pub const v4l2_mpeg_cx2341x_video_luma_spatial_filter_type_V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE : v4l2_mpeg_cx2341x_video_luma_spatial_filter_type = 3 ; +pub const v4l2_mpeg_cx2341x_video_luma_spatial_filter_type_V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE : v4l2_mpeg_cx2341x_video_luma_spatial_filter_type = 4 ; +pub type v4l2_mpeg_cx2341x_video_luma_spatial_filter_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type_V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF : v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type = 0 ; +pub const v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type_V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR : v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type = 1 ; +pub type v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_cx2341x_video_temporal_filter_mode_V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL : v4l2_mpeg_cx2341x_video_temporal_filter_mode = 0 ; +pub const v4l2_mpeg_cx2341x_video_temporal_filter_mode_V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO : v4l2_mpeg_cx2341x_video_temporal_filter_mode = 1 ; +pub type v4l2_mpeg_cx2341x_video_temporal_filter_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_cx2341x_video_median_filter_type_V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF : v4l2_mpeg_cx2341x_video_median_filter_type = 0 ; +pub const v4l2_mpeg_cx2341x_video_median_filter_type_V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR : v4l2_mpeg_cx2341x_video_median_filter_type = 1 ; +pub const v4l2_mpeg_cx2341x_video_median_filter_type_V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT : v4l2_mpeg_cx2341x_video_median_filter_type = 2 ; +pub const v4l2_mpeg_cx2341x_video_median_filter_type_V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT : v4l2_mpeg_cx2341x_video_median_filter_type = 3 ; +pub const v4l2_mpeg_cx2341x_video_median_filter_type_V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG : v4l2_mpeg_cx2341x_video_median_filter_type = 4 ; +pub type v4l2_mpeg_cx2341x_video_median_filter_type = ::std::os::raw::c_uint; +pub const v4l2_mpeg_mfc51_video_frame_skip_mode_V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED: + v4l2_mpeg_mfc51_video_frame_skip_mode = 0; +pub const v4l2_mpeg_mfc51_video_frame_skip_mode_V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT : v4l2_mpeg_mfc51_video_frame_skip_mode = 1 ; +pub const v4l2_mpeg_mfc51_video_frame_skip_mode_V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT: + v4l2_mpeg_mfc51_video_frame_skip_mode = 2; +pub type v4l2_mpeg_mfc51_video_frame_skip_mode = ::std::os::raw::c_uint; +pub const v4l2_mpeg_mfc51_video_force_frame_type_V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED: + v4l2_mpeg_mfc51_video_force_frame_type = 0; +pub const v4l2_mpeg_mfc51_video_force_frame_type_V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME: + v4l2_mpeg_mfc51_video_force_frame_type = 1; +pub const v4l2_mpeg_mfc51_video_force_frame_type_V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED : v4l2_mpeg_mfc51_video_force_frame_type = 2 ; +pub type v4l2_mpeg_mfc51_video_force_frame_type = ::std::os::raw::c_uint; +pub const v4l2_exposure_auto_type_V4L2_EXPOSURE_AUTO: v4l2_exposure_auto_type = 0; +pub const v4l2_exposure_auto_type_V4L2_EXPOSURE_MANUAL: v4l2_exposure_auto_type = 1; +pub const v4l2_exposure_auto_type_V4L2_EXPOSURE_SHUTTER_PRIORITY: v4l2_exposure_auto_type = 2; +pub const v4l2_exposure_auto_type_V4L2_EXPOSURE_APERTURE_PRIORITY: v4l2_exposure_auto_type = 3; +pub type v4l2_exposure_auto_type = ::std::os::raw::c_uint; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_MANUAL: + v4l2_auto_n_preset_white_balance = 0; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_AUTO: + v4l2_auto_n_preset_white_balance = 1; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_INCANDESCENT: + v4l2_auto_n_preset_white_balance = 2; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_FLUORESCENT: + v4l2_auto_n_preset_white_balance = 3; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_FLUORESCENT_H: + v4l2_auto_n_preset_white_balance = 4; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_HORIZON: + v4l2_auto_n_preset_white_balance = 5; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_DAYLIGHT: + v4l2_auto_n_preset_white_balance = 6; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_FLASH: + v4l2_auto_n_preset_white_balance = 7; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_CLOUDY: + v4l2_auto_n_preset_white_balance = 8; +pub const v4l2_auto_n_preset_white_balance_V4L2_WHITE_BALANCE_SHADE: + v4l2_auto_n_preset_white_balance = 9; +pub type v4l2_auto_n_preset_white_balance = ::std::os::raw::c_uint; +pub const v4l2_iso_sensitivity_auto_type_V4L2_ISO_SENSITIVITY_MANUAL: + v4l2_iso_sensitivity_auto_type = 0; +pub const v4l2_iso_sensitivity_auto_type_V4L2_ISO_SENSITIVITY_AUTO: v4l2_iso_sensitivity_auto_type = + 1; +pub type v4l2_iso_sensitivity_auto_type = ::std::os::raw::c_uint; +pub const v4l2_exposure_metering_V4L2_EXPOSURE_METERING_AVERAGE: v4l2_exposure_metering = 0; +pub const v4l2_exposure_metering_V4L2_EXPOSURE_METERING_CENTER_WEIGHTED: v4l2_exposure_metering = 1; +pub const v4l2_exposure_metering_V4L2_EXPOSURE_METERING_SPOT: v4l2_exposure_metering = 2; +pub const v4l2_exposure_metering_V4L2_EXPOSURE_METERING_MATRIX: v4l2_exposure_metering = 3; +pub type v4l2_exposure_metering = ::std::os::raw::c_uint; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_NONE: v4l2_scene_mode = 0; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_BACKLIGHT: v4l2_scene_mode = 1; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_BEACH_SNOW: v4l2_scene_mode = 2; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_CANDLE_LIGHT: v4l2_scene_mode = 3; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_DAWN_DUSK: v4l2_scene_mode = 4; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_FALL_COLORS: v4l2_scene_mode = 5; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_FIREWORKS: v4l2_scene_mode = 6; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_LANDSCAPE: v4l2_scene_mode = 7; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_NIGHT: v4l2_scene_mode = 8; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_PARTY_INDOOR: v4l2_scene_mode = 9; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_PORTRAIT: v4l2_scene_mode = 10; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_SPORTS: v4l2_scene_mode = 11; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_SUNSET: v4l2_scene_mode = 12; +pub const v4l2_scene_mode_V4L2_SCENE_MODE_TEXT: v4l2_scene_mode = 13; +pub type v4l2_scene_mode = ::std::os::raw::c_uint; +pub const v4l2_auto_focus_range_V4L2_AUTO_FOCUS_RANGE_AUTO: v4l2_auto_focus_range = 0; +pub const v4l2_auto_focus_range_V4L2_AUTO_FOCUS_RANGE_NORMAL: v4l2_auto_focus_range = 1; +pub const v4l2_auto_focus_range_V4L2_AUTO_FOCUS_RANGE_MACRO: v4l2_auto_focus_range = 2; +pub const v4l2_auto_focus_range_V4L2_AUTO_FOCUS_RANGE_INFINITY: v4l2_auto_focus_range = 3; +pub type v4l2_auto_focus_range = ::std::os::raw::c_uint; +pub const v4l2_preemphasis_V4L2_PREEMPHASIS_DISABLED: v4l2_preemphasis = 0; +pub const v4l2_preemphasis_V4L2_PREEMPHASIS_50_uS: v4l2_preemphasis = 1; +pub const v4l2_preemphasis_V4L2_PREEMPHASIS_75_uS: v4l2_preemphasis = 2; +pub type v4l2_preemphasis = ::std::os::raw::c_uint; +pub const v4l2_flash_led_mode_V4L2_FLASH_LED_MODE_NONE: v4l2_flash_led_mode = 0; +pub const v4l2_flash_led_mode_V4L2_FLASH_LED_MODE_FLASH: v4l2_flash_led_mode = 1; +pub const v4l2_flash_led_mode_V4L2_FLASH_LED_MODE_TORCH: v4l2_flash_led_mode = 2; +pub type v4l2_flash_led_mode = ::std::os::raw::c_uint; +pub const v4l2_flash_strobe_source_V4L2_FLASH_STROBE_SOURCE_SOFTWARE: v4l2_flash_strobe_source = 0; +pub const v4l2_flash_strobe_source_V4L2_FLASH_STROBE_SOURCE_EXTERNAL: v4l2_flash_strobe_source = 1; +pub type v4l2_flash_strobe_source = ::std::os::raw::c_uint; +pub const v4l2_jpeg_chroma_subsampling_V4L2_JPEG_CHROMA_SUBSAMPLING_444: + v4l2_jpeg_chroma_subsampling = 0; +pub const v4l2_jpeg_chroma_subsampling_V4L2_JPEG_CHROMA_SUBSAMPLING_422: + v4l2_jpeg_chroma_subsampling = 1; +pub const v4l2_jpeg_chroma_subsampling_V4L2_JPEG_CHROMA_SUBSAMPLING_420: + v4l2_jpeg_chroma_subsampling = 2; +pub const v4l2_jpeg_chroma_subsampling_V4L2_JPEG_CHROMA_SUBSAMPLING_411: + v4l2_jpeg_chroma_subsampling = 3; +pub const v4l2_jpeg_chroma_subsampling_V4L2_JPEG_CHROMA_SUBSAMPLING_410: + v4l2_jpeg_chroma_subsampling = 4; +pub const v4l2_jpeg_chroma_subsampling_V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY: + v4l2_jpeg_chroma_subsampling = 5; +pub type v4l2_jpeg_chroma_subsampling = ::std::os::raw::c_uint; +pub const v4l2_dv_tx_mode_V4L2_DV_TX_MODE_DVI_D: v4l2_dv_tx_mode = 0; +pub const v4l2_dv_tx_mode_V4L2_DV_TX_MODE_HDMI: v4l2_dv_tx_mode = 1; +pub type v4l2_dv_tx_mode = ::std::os::raw::c_uint; +pub const v4l2_dv_rgb_range_V4L2_DV_RGB_RANGE_AUTO: v4l2_dv_rgb_range = 0; +pub const v4l2_dv_rgb_range_V4L2_DV_RGB_RANGE_LIMITED: v4l2_dv_rgb_range = 1; +pub const v4l2_dv_rgb_range_V4L2_DV_RGB_RANGE_FULL: v4l2_dv_rgb_range = 2; +pub type v4l2_dv_rgb_range = ::std::os::raw::c_uint; +pub const v4l2_dv_it_content_type_V4L2_DV_IT_CONTENT_TYPE_GRAPHICS: v4l2_dv_it_content_type = 0; +pub const v4l2_dv_it_content_type_V4L2_DV_IT_CONTENT_TYPE_PHOTO: v4l2_dv_it_content_type = 1; +pub const v4l2_dv_it_content_type_V4L2_DV_IT_CONTENT_TYPE_CINEMA: v4l2_dv_it_content_type = 2; +pub const v4l2_dv_it_content_type_V4L2_DV_IT_CONTENT_TYPE_GAME: v4l2_dv_it_content_type = 3; +pub const v4l2_dv_it_content_type_V4L2_DV_IT_CONTENT_TYPE_NO_ITC: v4l2_dv_it_content_type = 4; +pub type v4l2_dv_it_content_type = ::std::os::raw::c_uint; +pub const v4l2_deemphasis_V4L2_DEEMPHASIS_DISABLED: v4l2_deemphasis = 0; +pub const v4l2_deemphasis_V4L2_DEEMPHASIS_50_uS: v4l2_deemphasis = 1; +pub const v4l2_deemphasis_V4L2_DEEMPHASIS_75_uS: v4l2_deemphasis = 2; +pub type v4l2_deemphasis = ::std::os::raw::c_uint; +pub const v4l2_detect_md_mode_V4L2_DETECT_MD_MODE_DISABLED: v4l2_detect_md_mode = 0; +pub const v4l2_detect_md_mode_V4L2_DETECT_MD_MODE_GLOBAL: v4l2_detect_md_mode = 1; +pub const v4l2_detect_md_mode_V4L2_DETECT_MD_MODE_THRESHOLD_GRID: v4l2_detect_md_mode = 2; +pub const v4l2_detect_md_mode_V4L2_DETECT_MD_MODE_REGION_GRID: v4l2_detect_md_mode = 3; +pub type v4l2_detect_md_mode = ::std::os::raw::c_uint; +pub const v4l2_stateless_h264_decode_mode_V4L2_STATELESS_H264_DECODE_MODE_SLICE_BASED: + v4l2_stateless_h264_decode_mode = 0; +pub const v4l2_stateless_h264_decode_mode_V4L2_STATELESS_H264_DECODE_MODE_FRAME_BASED: + v4l2_stateless_h264_decode_mode = 1; +pub type v4l2_stateless_h264_decode_mode = ::std::os::raw::c_uint; +pub const v4l2_stateless_h264_start_code_V4L2_STATELESS_H264_START_CODE_NONE: + v4l2_stateless_h264_start_code = 0; +pub const v4l2_stateless_h264_start_code_V4L2_STATELESS_H264_START_CODE_ANNEX_B: + v4l2_stateless_h264_start_code = 1; +pub type v4l2_stateless_h264_start_code = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_h264_sps { + pub profile_idc: __u8, + pub constraint_set_flags: __u8, + pub level_idc: __u8, + pub seq_parameter_set_id: __u8, + pub chroma_format_idc: __u8, + pub bit_depth_luma_minus8: __u8, + pub bit_depth_chroma_minus8: __u8, + pub log2_max_frame_num_minus4: __u8, + pub pic_order_cnt_type: __u8, + pub log2_max_pic_order_cnt_lsb_minus4: __u8, + pub max_num_ref_frames: __u8, + pub num_ref_frames_in_pic_order_cnt_cycle: __u8, + pub offset_for_ref_frame: [__s32; 255usize], + pub offset_for_non_ref_pic: __s32, + pub offset_for_top_to_bottom_field: __s32, + pub pic_width_in_mbs_minus1: __u16, + pub pic_height_in_map_units_minus1: __u16, + pub flags: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_h264_pps { + pub pic_parameter_set_id: __u8, + pub seq_parameter_set_id: __u8, + pub num_slice_groups_minus1: __u8, + pub num_ref_idx_l0_default_active_minus1: __u8, + pub num_ref_idx_l1_default_active_minus1: __u8, + pub weighted_bipred_idc: __u8, + pub pic_init_qp_minus26: __s8, + pub pic_init_qs_minus26: __s8, + pub chroma_qp_index_offset: __s8, + pub second_chroma_qp_index_offset: __s8, + pub flags: __u16, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_h264_scaling_matrix { + pub scaling_list_4x4: [[__u8; 16usize]; 6usize], + pub scaling_list_8x8: [[__u8; 64usize]; 6usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_h264_weight_factors { + pub luma_weight: [__s16; 32usize], + pub luma_offset: [__s16; 32usize], + pub chroma_weight: [[__s16; 2usize]; 32usize], + pub chroma_offset: [[__s16; 2usize]; 32usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_h264_pred_weights { + pub luma_log2_weight_denom: __u16, + pub chroma_log2_weight_denom: __u16, + pub weight_factors: [v4l2_h264_weight_factors; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_h264_reference { + pub fields: __u8, + pub index: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_h264_slice_params { + pub header_bit_size: __u32, + pub first_mb_in_slice: __u32, + pub slice_type: __u8, + pub colour_plane_id: __u8, + pub redundant_pic_cnt: __u8, + pub cabac_init_idc: __u8, + pub slice_qp_delta: __s8, + pub slice_qs_delta: __s8, + pub disable_deblocking_filter_idc: __u8, + pub slice_alpha_c0_offset_div2: __s8, + pub slice_beta_offset_div2: __s8, + pub num_ref_idx_l0_active_minus1: __u8, + pub num_ref_idx_l1_active_minus1: __u8, + pub reserved: __u8, + pub ref_pic_list0: [v4l2_h264_reference; 32usize], + pub ref_pic_list1: [v4l2_h264_reference; 32usize], + pub flags: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_h264_dpb_entry { + pub reference_ts: __u64, + pub pic_num: __u32, + pub frame_num: __u16, + pub fields: __u8, + pub reserved: [__u8; 5usize], + pub top_field_order_cnt: __s32, + pub bottom_field_order_cnt: __s32, + pub flags: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_h264_decode_params { + pub dpb: [v4l2_h264_dpb_entry; 16usize], + pub nal_ref_idc: __u16, + pub frame_num: __u16, + pub top_field_order_cnt: __s32, + pub bottom_field_order_cnt: __s32, + pub idr_pic_id: __u16, + pub pic_order_cnt_lsb: __u16, + pub delta_pic_order_cnt_bottom: __s32, + pub delta_pic_order_cnt0: __s32, + pub delta_pic_order_cnt1: __s32, + pub dec_ref_pic_marking_bit_size: __u32, + pub pic_order_cnt_bit_size: __u32, + pub slice_group_change_cycle: __u32, + pub reserved: __u32, + pub flags: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_fwht_params { + pub backward_ref_ts: __u64, + pub version: __u32, + pub width: __u32, + pub height: __u32, + pub flags: __u32, + pub colorspace: __u32, + pub xfer_func: __u32, + pub ycbcr_enc: __u32, + pub quantization: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp8_segment { + pub quant_update: [__s8; 4usize], + pub lf_update: [__s8; 4usize], + pub segment_probs: [__u8; 3usize], + pub padding: __u8, + pub flags: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp8_loop_filter { + pub ref_frm_delta: [__s8; 4usize], + pub mb_mode_delta: [__s8; 4usize], + pub sharpness_level: __u8, + pub level: __u8, + pub padding: __u16, + pub flags: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp8_quantization { + pub y_ac_qi: __u8, + pub y_dc_delta: __s8, + pub y2_dc_delta: __s8, + pub y2_ac_delta: __s8, + pub uv_dc_delta: __s8, + pub uv_ac_delta: __s8, + pub padding: __u16, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp8_entropy { + pub coeff_probs: [[[[__u8; 11usize]; 3usize]; 8usize]; 4usize], + pub y_mode_probs: [__u8; 4usize], + pub uv_mode_probs: [__u8; 3usize], + pub mv_probs: [[__u8; 19usize]; 2usize], + pub padding: [__u8; 3usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp8_entropy_coder_state { + pub range: __u8, + pub value: __u8, + pub bit_count: __u8, + pub padding: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_vp8_frame { + pub segment: v4l2_vp8_segment, + pub lf: v4l2_vp8_loop_filter, + pub quant: v4l2_vp8_quantization, + pub entropy: v4l2_vp8_entropy, + pub coder_state: v4l2_vp8_entropy_coder_state, + pub width: __u16, + pub height: __u16, + pub horizontal_scale: __u8, + pub vertical_scale: __u8, + pub version: __u8, + pub prob_skip_false: __u8, + pub prob_intra: __u8, + pub prob_last: __u8, + pub prob_gf: __u8, + pub num_dct_parts: __u8, + pub first_part_size: __u32, + pub first_part_header_bits: __u32, + pub dct_part_sizes: [__u32; 8usize], + pub last_frame_ts: __u64, + pub golden_frame_ts: __u64, + pub alt_frame_ts: __u64, + pub flags: __u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_mpeg2_sequence { + pub horizontal_size: __u16, + pub vertical_size: __u16, + pub vbv_buffer_size: __u32, + pub profile_and_level_indication: __u16, + pub chroma_format: __u8, + pub flags: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_mpeg2_picture { + pub backward_ref_ts: __u64, + pub forward_ref_ts: __u64, + pub flags: __u32, + pub f_code: [[__u8; 2usize]; 2usize], + pub picture_coding_type: __u8, + pub picture_structure: __u8, + pub intra_dc_precision: __u8, + pub reserved: [__u8; 5usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_mpeg2_quantisation { + pub intra_quantiser_matrix: [__u8; 64usize], + pub non_intra_quantiser_matrix: [__u8; 64usize], + pub chroma_intra_quantiser_matrix: [__u8; 64usize], + pub chroma_non_intra_quantiser_matrix: [__u8; 64usize], +} +pub const v4l2_stateless_hevc_decode_mode_V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED: + v4l2_stateless_hevc_decode_mode = 0; +pub const v4l2_stateless_hevc_decode_mode_V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED: + v4l2_stateless_hevc_decode_mode = 1; +pub type v4l2_stateless_hevc_decode_mode = ::std::os::raw::c_uint; +pub const v4l2_stateless_hevc_start_code_V4L2_STATELESS_HEVC_START_CODE_NONE: + v4l2_stateless_hevc_start_code = 0; +pub const v4l2_stateless_hevc_start_code_V4L2_STATELESS_HEVC_START_CODE_ANNEX_B: + v4l2_stateless_hevc_start_code = 1; +pub type v4l2_stateless_hevc_start_code = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_hevc_sps { + pub video_parameter_set_id: __u8, + pub seq_parameter_set_id: __u8, + pub pic_width_in_luma_samples: __u16, + pub pic_height_in_luma_samples: __u16, + pub bit_depth_luma_minus8: __u8, + pub bit_depth_chroma_minus8: __u8, + pub log2_max_pic_order_cnt_lsb_minus4: __u8, + pub sps_max_dec_pic_buffering_minus1: __u8, + pub sps_max_num_reorder_pics: __u8, + pub sps_max_latency_increase_plus1: __u8, + pub log2_min_luma_coding_block_size_minus3: __u8, + pub log2_diff_max_min_luma_coding_block_size: __u8, + pub log2_min_luma_transform_block_size_minus2: __u8, + pub log2_diff_max_min_luma_transform_block_size: __u8, + pub max_transform_hierarchy_depth_inter: __u8, + pub max_transform_hierarchy_depth_intra: __u8, + pub pcm_sample_bit_depth_luma_minus1: __u8, + pub pcm_sample_bit_depth_chroma_minus1: __u8, + pub log2_min_pcm_luma_coding_block_size_minus3: __u8, + pub log2_diff_max_min_pcm_luma_coding_block_size: __u8, + pub num_short_term_ref_pic_sets: __u8, + pub num_long_term_ref_pics_sps: __u8, + pub chroma_format_idc: __u8, + pub sps_max_sub_layers_minus1: __u8, + pub reserved: [__u8; 6usize], + pub flags: __u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_hevc_pps { + pub pic_parameter_set_id: __u8, + pub num_extra_slice_header_bits: __u8, + pub num_ref_idx_l0_default_active_minus1: __u8, + pub num_ref_idx_l1_default_active_minus1: __u8, + pub init_qp_minus26: __s8, + pub diff_cu_qp_delta_depth: __u8, + pub pps_cb_qp_offset: __s8, + pub pps_cr_qp_offset: __s8, + pub num_tile_columns_minus1: __u8, + pub num_tile_rows_minus1: __u8, + pub column_width_minus1: [__u8; 20usize], + pub row_height_minus1: [__u8; 22usize], + pub pps_beta_offset_div2: __s8, + pub pps_tc_offset_div2: __s8, + pub log2_parallel_merge_level_minus2: __u8, + pub reserved: __u8, + pub flags: __u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_hevc_dpb_entry { + pub timestamp: __u64, + pub flags: __u8, + pub field_pic: __u8, + pub reserved: __u16, + pub pic_order_cnt_val: __s32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_hevc_pred_weight_table { + pub delta_luma_weight_l0: [__s8; 16usize], + pub luma_offset_l0: [__s8; 16usize], + pub delta_chroma_weight_l0: [[__s8; 2usize]; 16usize], + pub chroma_offset_l0: [[__s8; 2usize]; 16usize], + pub delta_luma_weight_l1: [__s8; 16usize], + pub luma_offset_l1: [__s8; 16usize], + pub delta_chroma_weight_l1: [[__s8; 2usize]; 16usize], + pub chroma_offset_l1: [[__s8; 2usize]; 16usize], + pub luma_log2_weight_denom: __u8, + pub delta_chroma_log2_weight_denom: __s8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_hevc_slice_params { + pub bit_size: __u32, + pub data_byte_offset: __u32, + pub num_entry_point_offsets: __u32, + pub nal_unit_type: __u8, + pub nuh_temporal_id_plus1: __u8, + pub slice_type: __u8, + pub colour_plane_id: __u8, + pub slice_pic_order_cnt: __s32, + pub num_ref_idx_l0_active_minus1: __u8, + pub num_ref_idx_l1_active_minus1: __u8, + pub collocated_ref_idx: __u8, + pub five_minus_max_num_merge_cand: __u8, + pub slice_qp_delta: __s8, + pub slice_cb_qp_offset: __s8, + pub slice_cr_qp_offset: __s8, + pub slice_act_y_qp_offset: __s8, + pub slice_act_cb_qp_offset: __s8, + pub slice_act_cr_qp_offset: __s8, + pub slice_beta_offset_div2: __s8, + pub slice_tc_offset_div2: __s8, + pub pic_struct: __u8, + pub reserved0: [__u8; 3usize], + pub slice_segment_addr: __u32, + pub ref_idx_l0: [__u8; 16usize], + pub ref_idx_l1: [__u8; 16usize], + pub short_term_ref_pic_set_size: __u16, + pub long_term_ref_pic_set_size: __u16, + pub pred_weight_table: v4l2_hevc_pred_weight_table, + pub reserved1: [__u8; 2usize], + pub flags: __u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_hevc_decode_params { + pub pic_order_cnt_val: __s32, + pub short_term_ref_pic_set_size: __u16, + pub long_term_ref_pic_set_size: __u16, + pub num_active_dpb_entries: __u8, + pub num_poc_st_curr_before: __u8, + pub num_poc_st_curr_after: __u8, + pub num_poc_lt_curr: __u8, + pub poc_st_curr_before: [__u8; 16usize], + pub poc_st_curr_after: [__u8; 16usize], + pub poc_lt_curr: [__u8; 16usize], + pub num_delta_pocs_of_ref_rps_idx: __u8, + pub reserved: [__u8; 3usize], + pub dpb: [v4l2_hevc_dpb_entry; 16usize], + pub flags: __u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_hevc_scaling_matrix { + pub scaling_list_4x4: [[__u8; 16usize]; 6usize], + pub scaling_list_8x8: [[__u8; 64usize]; 6usize], + pub scaling_list_16x16: [[__u8; 64usize]; 6usize], + pub scaling_list_32x32: [[__u8; 64usize]; 2usize], + pub scaling_list_dc_coef_16x16: [__u8; 6usize], + pub scaling_list_dc_coef_32x32: [__u8; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_hdr10_cll_info { + pub max_content_light_level: __u16, + pub max_pic_average_light_level: __u16, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_hdr10_mastering_display { + pub display_primaries_x: [__u16; 3usize], + pub display_primaries_y: [__u16; 3usize], + pub white_point_x: __u16, + pub white_point_y: __u16, + pub max_display_mastering_luminance: __u32, + pub min_display_mastering_luminance: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp9_loop_filter { + pub ref_deltas: [__s8; 4usize], + pub mode_deltas: [__s8; 2usize], + pub level: __u8, + pub sharpness: __u8, + pub flags: __u8, + pub reserved: [__u8; 7usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp9_quantization { + pub base_q_idx: __u8, + pub delta_q_y_dc: __s8, + pub delta_q_uv_dc: __s8, + pub delta_q_uv_ac: __s8, + pub reserved: [__u8; 4usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp9_segmentation { + pub feature_data: [[__s16; 4usize]; 8usize], + pub feature_enabled: [__u8; 8usize], + pub tree_probs: [__u8; 7usize], + pub pred_probs: [__u8; 3usize], + pub flags: __u8, + pub reserved: [__u8; 5usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_vp9_frame { + pub lf: v4l2_vp9_loop_filter, + pub quant: v4l2_vp9_quantization, + pub seg: v4l2_vp9_segmentation, + pub flags: __u32, + pub compressed_header_size: __u16, + pub uncompressed_header_size: __u16, + pub frame_width_minus_1: __u16, + pub frame_height_minus_1: __u16, + pub render_width_minus_1: __u16, + pub render_height_minus_1: __u16, + pub last_frame_ts: __u64, + pub golden_frame_ts: __u64, + pub alt_frame_ts: __u64, + pub ref_frame_sign_bias: __u8, + pub reset_frame_context: __u8, + pub frame_context_idx: __u8, + pub profile: __u8, + pub bit_depth: __u8, + pub interpolation_filter: __u8, + pub tile_cols_log2: __u8, + pub tile_rows_log2: __u8, + pub reference_mode: __u8, + pub reserved: [__u8; 7usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vp9_mv_probs { + pub joint: [__u8; 3usize], + pub sign: [__u8; 2usize], + pub classes: [[__u8; 10usize]; 2usize], + pub class0_bit: [__u8; 2usize], + pub bits: [[__u8; 10usize]; 2usize], + pub class0_fr: [[[__u8; 3usize]; 2usize]; 2usize], + pub fr: [[__u8; 3usize]; 2usize], + pub class0_hp: [__u8; 2usize], + pub hp: [__u8; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_vp9_compressed_hdr { + pub tx_mode: __u8, + pub tx8: [[__u8; 1usize]; 2usize], + pub tx16: [[__u8; 2usize]; 2usize], + pub tx32: [[__u8; 3usize]; 2usize], + pub coef: [[[[[[__u8; 3usize]; 6usize]; 6usize]; 2usize]; 2usize]; 4usize], + pub skip: [__u8; 3usize], + pub inter_mode: [[__u8; 3usize]; 7usize], + pub interp_filter: [[__u8; 2usize]; 4usize], + pub is_inter: [__u8; 4usize], + pub comp_mode: [__u8; 5usize], + pub single_ref: [[__u8; 2usize]; 5usize], + pub comp_ref: [__u8; 5usize], + pub y_mode: [[__u8; 9usize]; 4usize], + pub uv_mode: [[__u8; 9usize]; 10usize], + pub partition: [[__u8; 3usize]; 16usize], + pub mv: v4l2_vp9_mv_probs, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_av1_sequence { + pub flags: __u32, + pub seq_profile: __u8, + pub order_hint_bits: __u8, + pub bit_depth: __u8, + pub reserved: __u8, + pub max_frame_width_minus_1: __u16, + pub max_frame_height_minus_1: __u16, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_av1_tile_group_entry { + pub tile_offset: __u32, + pub tile_size: __u32, + pub tile_row: __u32, + pub tile_col: __u32, +} +pub const v4l2_av1_warp_model_V4L2_AV1_WARP_MODEL_IDENTITY: v4l2_av1_warp_model = 0; +pub const v4l2_av1_warp_model_V4L2_AV1_WARP_MODEL_TRANSLATION: v4l2_av1_warp_model = 1; +pub const v4l2_av1_warp_model_V4L2_AV1_WARP_MODEL_ROTZOOM: v4l2_av1_warp_model = 2; +pub const v4l2_av1_warp_model_V4L2_AV1_WARP_MODEL_AFFINE: v4l2_av1_warp_model = 3; +pub type v4l2_av1_warp_model = ::std::os::raw::c_uint; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_INTRA_FRAME: v4l2_av1_reference_frame = 0; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_LAST_FRAME: v4l2_av1_reference_frame = 1; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_LAST2_FRAME: v4l2_av1_reference_frame = 2; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_LAST3_FRAME: v4l2_av1_reference_frame = 3; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_GOLDEN_FRAME: v4l2_av1_reference_frame = 4; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_BWDREF_FRAME: v4l2_av1_reference_frame = 5; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_ALTREF2_FRAME: v4l2_av1_reference_frame = 6; +pub const v4l2_av1_reference_frame_V4L2_AV1_REF_ALTREF_FRAME: v4l2_av1_reference_frame = 7; +pub type v4l2_av1_reference_frame = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_av1_global_motion { + pub flags: [__u8; 8usize], + pub type_: [v4l2_av1_warp_model; 8usize], + pub params: [[__s32; 6usize]; 8usize], + pub invalid: __u8, + pub reserved: [__u8; 3usize], +} +pub const v4l2_av1_frame_restoration_type_V4L2_AV1_FRAME_RESTORE_NONE: + v4l2_av1_frame_restoration_type = 0; +pub const v4l2_av1_frame_restoration_type_V4L2_AV1_FRAME_RESTORE_WIENER: + v4l2_av1_frame_restoration_type = 1; +pub const v4l2_av1_frame_restoration_type_V4L2_AV1_FRAME_RESTORE_SGRPROJ: + v4l2_av1_frame_restoration_type = 2; +pub const v4l2_av1_frame_restoration_type_V4L2_AV1_FRAME_RESTORE_SWITCHABLE: + v4l2_av1_frame_restoration_type = 3; +pub type v4l2_av1_frame_restoration_type = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_av1_loop_restoration { + pub flags: __u8, + pub lr_unit_shift: __u8, + pub lr_uv_shift: __u8, + pub reserved: __u8, + pub frame_restoration_type: [v4l2_av1_frame_restoration_type; 3usize], + pub loop_restoration_size: [__u32; 3usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_av1_cdef { + pub damping_minus_3: __u8, + pub bits: __u8, + pub y_pri_strength: [__u8; 8usize], + pub y_sec_strength: [__u8; 8usize], + pub uv_pri_strength: [__u8; 8usize], + pub uv_sec_strength: [__u8; 8usize], +} +pub const v4l2_av1_segment_feature_V4L2_AV1_SEG_LVL_ALT_Q: v4l2_av1_segment_feature = 0; +pub const v4l2_av1_segment_feature_V4L2_AV1_SEG_LVL_ALT_LF_Y_V: v4l2_av1_segment_feature = 1; +pub const v4l2_av1_segment_feature_V4L2_AV1_SEG_LVL_REF_FRAME: v4l2_av1_segment_feature = 5; +pub const v4l2_av1_segment_feature_V4L2_AV1_SEG_LVL_REF_SKIP: v4l2_av1_segment_feature = 6; +pub const v4l2_av1_segment_feature_V4L2_AV1_SEG_LVL_REF_GLOBALMV: v4l2_av1_segment_feature = 7; +pub const v4l2_av1_segment_feature_V4L2_AV1_SEG_LVL_MAX: v4l2_av1_segment_feature = 8; +pub type v4l2_av1_segment_feature = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_av1_segmentation { + pub flags: __u8, + pub last_active_seg_id: __u8, + pub feature_enabled: [__u8; 8usize], + pub feature_data: [[__s16; 8usize]; 8usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_av1_loop_filter { + pub flags: __u8, + pub level: [__u8; 4usize], + pub sharpness: __u8, + pub ref_deltas: [__s8; 8usize], + pub mode_deltas: [__s8; 2usize], + pub delta_lf_res: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_av1_quantization { + pub flags: __u8, + pub base_q_idx: __u8, + pub delta_q_y_dc: __s8, + pub delta_q_u_dc: __s8, + pub delta_q_u_ac: __s8, + pub delta_q_v_dc: __s8, + pub delta_q_v_ac: __s8, + pub qm_y: __u8, + pub qm_u: __u8, + pub qm_v: __u8, + pub delta_q_res: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_av1_tile_info { + pub flags: __u8, + pub context_update_tile_id: __u8, + pub tile_cols: __u8, + pub tile_rows: __u8, + pub mi_col_starts: [__u32; 65usize], + pub mi_row_starts: [__u32; 65usize], + pub width_in_sbs_minus_1: [__u32; 64usize], + pub height_in_sbs_minus_1: [__u32; 64usize], + pub tile_size_bytes: __u8, + pub reserved: [__u8; 3usize], +} +pub const v4l2_av1_frame_type_V4L2_AV1_KEY_FRAME: v4l2_av1_frame_type = 0; +pub const v4l2_av1_frame_type_V4L2_AV1_INTER_FRAME: v4l2_av1_frame_type = 1; +pub const v4l2_av1_frame_type_V4L2_AV1_INTRA_ONLY_FRAME: v4l2_av1_frame_type = 2; +pub const v4l2_av1_frame_type_V4L2_AV1_SWITCH_FRAME: v4l2_av1_frame_type = 3; +pub type v4l2_av1_frame_type = ::std::os::raw::c_uint; +pub const v4l2_av1_interpolation_filter_V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP: + v4l2_av1_interpolation_filter = 0; +pub const v4l2_av1_interpolation_filter_V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SMOOTH: + v4l2_av1_interpolation_filter = 1; +pub const v4l2_av1_interpolation_filter_V4L2_AV1_INTERPOLATION_FILTER_EIGHTTAP_SHARP: + v4l2_av1_interpolation_filter = 2; +pub const v4l2_av1_interpolation_filter_V4L2_AV1_INTERPOLATION_FILTER_BILINEAR: + v4l2_av1_interpolation_filter = 3; +pub const v4l2_av1_interpolation_filter_V4L2_AV1_INTERPOLATION_FILTER_SWITCHABLE: + v4l2_av1_interpolation_filter = 4; +pub type v4l2_av1_interpolation_filter = ::std::os::raw::c_uint; +pub const v4l2_av1_tx_mode_V4L2_AV1_TX_MODE_ONLY_4X4: v4l2_av1_tx_mode = 0; +pub const v4l2_av1_tx_mode_V4L2_AV1_TX_MODE_LARGEST: v4l2_av1_tx_mode = 1; +pub const v4l2_av1_tx_mode_V4L2_AV1_TX_MODE_SELECT: v4l2_av1_tx_mode = 2; +pub type v4l2_av1_tx_mode = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_av1_frame { + pub tile_info: v4l2_av1_tile_info, + pub quantization: v4l2_av1_quantization, + pub superres_denom: __u8, + pub segmentation: v4l2_av1_segmentation, + pub loop_filter: v4l2_av1_loop_filter, + pub cdef: v4l2_av1_cdef, + pub skip_mode_frame: [__u8; 2usize], + pub primary_ref_frame: __u8, + pub loop_restoration: v4l2_av1_loop_restoration, + pub global_motion: v4l2_av1_global_motion, + pub flags: __u32, + pub frame_type: v4l2_av1_frame_type, + pub order_hint: __u32, + pub upscaled_width: __u32, + pub interpolation_filter: v4l2_av1_interpolation_filter, + pub tx_mode: v4l2_av1_tx_mode, + pub frame_width_minus_1: __u32, + pub frame_height_minus_1: __u32, + pub render_width_minus_1: __u16, + pub render_height_minus_1: __u16, + pub current_frame_id: __u32, + pub buffer_removal_time: [__u32; 32usize], + pub reserved: [__u8; 4usize], + pub order_hints: [__u32; 8usize], + pub reference_frame_ts: [__u64; 8usize], + pub ref_frame_idx: [__s8; 7usize], + pub refresh_frame_flags: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_ctrl_av1_film_grain { + pub flags: __u8, + pub cr_mult: __u8, + pub grain_seed: __u16, + pub film_grain_params_ref_idx: __u8, + pub num_y_points: __u8, + pub point_y_value: [__u8; 16usize], + pub point_y_scaling: [__u8; 16usize], + pub num_cb_points: __u8, + pub point_cb_value: [__u8; 16usize], + pub point_cb_scaling: [__u8; 16usize], + pub num_cr_points: __u8, + pub point_cr_value: [__u8; 16usize], + pub point_cr_scaling: [__u8; 16usize], + pub grain_scaling_minus_8: __u8, + pub ar_coeff_lag: __u8, + pub ar_coeffs_y_plus_128: [__u8; 25usize], + pub ar_coeffs_cb_plus_128: [__u8; 25usize], + pub ar_coeffs_cr_plus_128: [__u8; 25usize], + pub ar_coeff_shift_minus_6: __u8, + pub grain_scale_shift: __u8, + pub cb_mult: __u8, + pub cb_luma_mult: __u8, + pub cr_luma_mult: __u8, + pub cb_offset: __u16, + pub cr_offset: __u16, + pub reserved: [__u8; 4usize], +} +pub const v4l2_field_V4L2_FIELD_ANY: v4l2_field = 0; +pub const v4l2_field_V4L2_FIELD_NONE: v4l2_field = 1; +pub const v4l2_field_V4L2_FIELD_TOP: v4l2_field = 2; +pub const v4l2_field_V4L2_FIELD_BOTTOM: v4l2_field = 3; +pub const v4l2_field_V4L2_FIELD_INTERLACED: v4l2_field = 4; +pub const v4l2_field_V4L2_FIELD_SEQ_TB: v4l2_field = 5; +pub const v4l2_field_V4L2_FIELD_SEQ_BT: v4l2_field = 6; +pub const v4l2_field_V4L2_FIELD_ALTERNATE: v4l2_field = 7; +pub const v4l2_field_V4L2_FIELD_INTERLACED_TB: v4l2_field = 8; +pub const v4l2_field_V4L2_FIELD_INTERLACED_BT: v4l2_field = 9; +pub type v4l2_field = ::std::os::raw::c_uint; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE: v4l2_buf_type = 1; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT: v4l2_buf_type = 2; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OVERLAY: v4l2_buf_type = 3; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VBI_CAPTURE: v4l2_buf_type = 4; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VBI_OUTPUT: v4l2_buf_type = 5; +pub const v4l2_buf_type_V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: v4l2_buf_type = 6; +pub const v4l2_buf_type_V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: v4l2_buf_type = 7; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: v4l2_buf_type = 8; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: v4l2_buf_type = 9; +pub const v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: v4l2_buf_type = 10; +pub const v4l2_buf_type_V4L2_BUF_TYPE_SDR_CAPTURE: v4l2_buf_type = 11; +pub const v4l2_buf_type_V4L2_BUF_TYPE_SDR_OUTPUT: v4l2_buf_type = 12; +pub const v4l2_buf_type_V4L2_BUF_TYPE_META_CAPTURE: v4l2_buf_type = 13; +pub const v4l2_buf_type_V4L2_BUF_TYPE_META_OUTPUT: v4l2_buf_type = 14; +pub const v4l2_buf_type_V4L2_BUF_TYPE_PRIVATE: v4l2_buf_type = 128; +pub type v4l2_buf_type = ::std::os::raw::c_uint; +pub const v4l2_tuner_type_V4L2_TUNER_RADIO: v4l2_tuner_type = 1; +pub const v4l2_tuner_type_V4L2_TUNER_ANALOG_TV: v4l2_tuner_type = 2; +pub const v4l2_tuner_type_V4L2_TUNER_DIGITAL_TV: v4l2_tuner_type = 3; +pub const v4l2_tuner_type_V4L2_TUNER_SDR: v4l2_tuner_type = 4; +pub const v4l2_tuner_type_V4L2_TUNER_RF: v4l2_tuner_type = 5; +pub type v4l2_tuner_type = ::std::os::raw::c_uint; +pub const v4l2_memory_V4L2_MEMORY_MMAP: v4l2_memory = 1; +pub const v4l2_memory_V4L2_MEMORY_USERPTR: v4l2_memory = 2; +pub const v4l2_memory_V4L2_MEMORY_OVERLAY: v4l2_memory = 3; +pub const v4l2_memory_V4L2_MEMORY_DMABUF: v4l2_memory = 4; +pub type v4l2_memory = ::std::os::raw::c_uint; +pub const v4l2_colorspace_V4L2_COLORSPACE_DEFAULT: v4l2_colorspace = 0; +pub const v4l2_colorspace_V4L2_COLORSPACE_SMPTE170M: v4l2_colorspace = 1; +pub const v4l2_colorspace_V4L2_COLORSPACE_SMPTE240M: v4l2_colorspace = 2; +pub const v4l2_colorspace_V4L2_COLORSPACE_REC709: v4l2_colorspace = 3; +pub const v4l2_colorspace_V4L2_COLORSPACE_BT878: v4l2_colorspace = 4; +pub const v4l2_colorspace_V4L2_COLORSPACE_470_SYSTEM_M: v4l2_colorspace = 5; +pub const v4l2_colorspace_V4L2_COLORSPACE_470_SYSTEM_BG: v4l2_colorspace = 6; +pub const v4l2_colorspace_V4L2_COLORSPACE_JPEG: v4l2_colorspace = 7; +pub const v4l2_colorspace_V4L2_COLORSPACE_SRGB: v4l2_colorspace = 8; +pub const v4l2_colorspace_V4L2_COLORSPACE_OPRGB: v4l2_colorspace = 9; +pub const v4l2_colorspace_V4L2_COLORSPACE_BT2020: v4l2_colorspace = 10; +pub const v4l2_colorspace_V4L2_COLORSPACE_RAW: v4l2_colorspace = 11; +pub const v4l2_colorspace_V4L2_COLORSPACE_DCI_P3: v4l2_colorspace = 12; +pub type v4l2_colorspace = ::std::os::raw::c_uint; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_DEFAULT: v4l2_xfer_func = 0; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_709: v4l2_xfer_func = 1; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_SRGB: v4l2_xfer_func = 2; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_OPRGB: v4l2_xfer_func = 3; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_SMPTE240M: v4l2_xfer_func = 4; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_NONE: v4l2_xfer_func = 5; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_DCI_P3: v4l2_xfer_func = 6; +pub const v4l2_xfer_func_V4L2_XFER_FUNC_SMPTE2084: v4l2_xfer_func = 7; +pub type v4l2_xfer_func = ::std::os::raw::c_uint; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_DEFAULT: v4l2_ycbcr_encoding = 0; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_601: v4l2_ycbcr_encoding = 1; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_709: v4l2_ycbcr_encoding = 2; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_XV601: v4l2_ycbcr_encoding = 3; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_XV709: v4l2_ycbcr_encoding = 4; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_SYCC: v4l2_ycbcr_encoding = 5; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_BT2020: v4l2_ycbcr_encoding = 6; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_BT2020_CONST_LUM: v4l2_ycbcr_encoding = 7; +pub const v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_SMPTE240M: v4l2_ycbcr_encoding = 8; +pub type v4l2_ycbcr_encoding = ::std::os::raw::c_uint; +pub const v4l2_hsv_encoding_V4L2_HSV_ENC_180: v4l2_hsv_encoding = 128; +pub const v4l2_hsv_encoding_V4L2_HSV_ENC_256: v4l2_hsv_encoding = 129; +pub type v4l2_hsv_encoding = ::std::os::raw::c_uint; +pub const v4l2_quantization_V4L2_QUANTIZATION_DEFAULT: v4l2_quantization = 0; +pub const v4l2_quantization_V4L2_QUANTIZATION_FULL_RANGE: v4l2_quantization = 1; +pub const v4l2_quantization_V4L2_QUANTIZATION_LIM_RANGE: v4l2_quantization = 2; +pub type v4l2_quantization = ::std::os::raw::c_uint; +pub const v4l2_priority_V4L2_PRIORITY_UNSET: v4l2_priority = 0; +pub const v4l2_priority_V4L2_PRIORITY_BACKGROUND: v4l2_priority = 1; +pub const v4l2_priority_V4L2_PRIORITY_INTERACTIVE: v4l2_priority = 2; +pub const v4l2_priority_V4L2_PRIORITY_RECORD: v4l2_priority = 3; +pub const v4l2_priority_V4L2_PRIORITY_DEFAULT: v4l2_priority = 2; +pub type v4l2_priority = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_rect { + pub left: __s32, + pub top: __s32, + pub width: __u32, + pub height: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_fract { + pub numerator: __u32, + pub denominator: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_area { + pub width: __u32, + pub height: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_capability { + pub driver: [__u8; 16usize], + pub card: [__u8; 32usize], + pub bus_info: [__u8; 32usize], + pub version: __u32, + pub capabilities: __u32, + pub device_caps: __u32, + pub reserved: [__u32; 3usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_pix_format { + pub width: __u32, + pub height: __u32, + pub pixelformat: __u32, + pub field: __u32, + pub bytesperline: __u32, + pub sizeimage: __u32, + pub colorspace: __u32, + pub priv_: __u32, + pub flags: __u32, + pub __bindgen_anon_1: v4l2_pix_format__bindgen_ty_1, + pub quantization: __u32, + pub xfer_func: __u32, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_pix_format__bindgen_ty_1 { + pub ycbcr_enc: __u32, + pub hsv_enc: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_fmtdesc { + pub index: __u32, + pub type_: __u32, + pub flags: __u32, + pub description: [__u8; 32usize], + pub pixelformat: __u32, + pub mbus_code: __u32, + pub reserved: [__u32; 3usize], +} +pub const v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_DISCRETE: v4l2_frmsizetypes = 1; +pub const v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_CONTINUOUS: v4l2_frmsizetypes = 2; +pub const v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_STEPWISE: v4l2_frmsizetypes = 3; +pub type v4l2_frmsizetypes = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_frmsize_discrete { + pub width: __u32, + pub height: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_frmsize_stepwise { + pub min_width: __u32, + pub max_width: __u32, + pub step_width: __u32, + pub min_height: __u32, + pub max_height: __u32, + pub step_height: __u32, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_frmsizeenum { + pub index: __u32, + pub pixel_format: __u32, + pub type_: __u32, + pub __bindgen_anon_1: v4l2_frmsizeenum__bindgen_ty_1, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_frmsizeenum__bindgen_ty_1 { + pub discrete: v4l2_frmsize_discrete, + pub stepwise: v4l2_frmsize_stepwise, +} +pub const v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_DISCRETE: v4l2_frmivaltypes = 1; +pub const v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_CONTINUOUS: v4l2_frmivaltypes = 2; +pub const v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_STEPWISE: v4l2_frmivaltypes = 3; +pub type v4l2_frmivaltypes = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_frmival_stepwise { + pub min: v4l2_fract, + pub max: v4l2_fract, + pub step: v4l2_fract, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_frmivalenum { + pub index: __u32, + pub pixel_format: __u32, + pub width: __u32, + pub height: __u32, + pub type_: __u32, + pub __bindgen_anon_1: v4l2_frmivalenum__bindgen_ty_1, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_frmivalenum__bindgen_ty_1 { + pub discrete: v4l2_fract, + pub stepwise: v4l2_frmival_stepwise, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_timecode { + pub type_: __u32, + pub flags: __u32, + pub frames: __u8, + pub seconds: __u8, + pub minutes: __u8, + pub hours: __u8, + pub userbits: [__u8; 4usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_jpegcompression { + pub quality: ::std::os::raw::c_int, + pub APPn: ::std::os::raw::c_int, + pub APP_len: ::std::os::raw::c_int, + pub APP_data: [::std::os::raw::c_char; 60usize], + pub COM_len: ::std::os::raw::c_int, + pub COM_data: [::std::os::raw::c_char; 60usize], + pub jpeg_markers: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_requestbuffers { + pub count: __u32, + pub type_: __u32, + pub memory: __u32, + pub capabilities: __u32, + pub flags: __u8, + pub reserved: [__u8; 3usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_plane { + pub bytesused: __u32, + pub length: __u32, + pub m: v4l2_plane__bindgen_ty_1, + pub data_offset: __u32, + pub reserved: [__u32; 11usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_plane__bindgen_ty_1 { + pub mem_offset: __u32, + pub userptr: ::std::os::raw::c_ulong, + pub fd: __s32, +} +#[repr(C)] +pub struct v4l2_buffer { + pub index: __u32, + pub type_: __u32, + pub bytesused: __u32, + pub flags: __u32, + pub field: __u32, + pub timestamp: timeval, + pub timecode: v4l2_timecode, + pub sequence: __u32, + pub memory: __u32, + pub m: v4l2_buffer__bindgen_ty_1, + pub length: __u32, + pub reserved2: __u32, + pub __bindgen_anon_1: v4l2_buffer__bindgen_ty_2, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_buffer__bindgen_ty_1 { + pub offset: __u32, + pub userptr: ::std::os::raw::c_ulong, + pub planes: *mut v4l2_plane, + pub fd: __s32, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_buffer__bindgen_ty_2 { + pub request_fd: __s32, + pub reserved: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_exportbuffer { + pub type_: __u32, + pub index: __u32, + pub plane: __u32, + pub flags: __u32, + pub fd: __s32, + pub reserved: [__u32; 11usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_framebuffer { + pub capability: __u32, + pub flags: __u32, + pub base: *mut ::std::os::raw::c_void, + pub fmt: v4l2_framebuffer__bindgen_ty_1, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_framebuffer__bindgen_ty_1 { + pub width: __u32, + pub height: __u32, + pub pixelformat: __u32, + pub field: __u32, + pub bytesperline: __u32, + pub sizeimage: __u32, + pub colorspace: __u32, + pub priv_: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_clip { + pub c: v4l2_rect, + pub next: *mut v4l2_clip, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_window { + pub w: v4l2_rect, + pub field: __u32, + pub chromakey: __u32, + pub clips: *mut v4l2_clip, + pub clipcount: __u32, + pub bitmap: *mut ::std::os::raw::c_void, + pub global_alpha: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_captureparm { + pub capability: __u32, + pub capturemode: __u32, + pub timeperframe: v4l2_fract, + pub extendedmode: __u32, + pub readbuffers: __u32, + pub reserved: [__u32; 4usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_outputparm { + pub capability: __u32, + pub outputmode: __u32, + pub timeperframe: v4l2_fract, + pub extendedmode: __u32, + pub writebuffers: __u32, + pub reserved: [__u32; 4usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_cropcap { + pub type_: __u32, + pub bounds: v4l2_rect, + pub defrect: v4l2_rect, + pub pixelaspect: v4l2_fract, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_crop { + pub type_: __u32, + pub c: v4l2_rect, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_selection { + pub type_: __u32, + pub target: __u32, + pub flags: __u32, + pub r: v4l2_rect, + pub reserved: [__u32; 9usize], +} +pub type v4l2_std_id = __u64; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_standard { + pub index: __u32, + pub id: v4l2_std_id, + pub name: [__u8; 24usize], + pub frameperiod: v4l2_fract, + pub framelines: __u32, + pub reserved: [__u32; 4usize], +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_bt_timings { + pub width: __u32, + pub height: __u32, + pub interlaced: __u32, + pub polarities: __u32, + pub pixelclock: __u64, + pub hfrontporch: __u32, + pub hsync: __u32, + pub hbackporch: __u32, + pub vfrontporch: __u32, + pub vsync: __u32, + pub vbackporch: __u32, + pub il_vfrontporch: __u32, + pub il_vsync: __u32, + pub il_vbackporch: __u32, + pub standards: __u32, + pub flags: __u32, + pub picture_aspect: v4l2_fract, + pub cea861_vic: __u8, + pub hdmi_vic: __u8, + pub reserved: [__u8; 46usize], +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_dv_timings { + pub type_: __u32, + pub __bindgen_anon_1: v4l2_dv_timings__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_dv_timings__bindgen_ty_1 { + pub bt: v4l2_bt_timings, + pub reserved: [__u32; 32usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_enum_dv_timings { + pub index: __u32, + pub pad: __u32, + pub reserved: [__u32; 2usize], + pub timings: v4l2_dv_timings, +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_bt_timings_cap { + pub min_width: __u32, + pub max_width: __u32, + pub min_height: __u32, + pub max_height: __u32, + pub min_pixelclock: __u64, + pub max_pixelclock: __u64, + pub standards: __u32, + pub capabilities: __u32, + pub reserved: [__u32; 16usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_dv_timings_cap { + pub type_: __u32, + pub pad: __u32, + pub reserved: [__u32; 2usize], + pub __bindgen_anon_1: v4l2_dv_timings_cap__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_dv_timings_cap__bindgen_ty_1 { + pub bt: v4l2_bt_timings_cap, + pub raw_data: [__u32; 32usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_input { + pub index: __u32, + pub name: [__u8; 32usize], + pub type_: __u32, + pub audioset: __u32, + pub tuner: __u32, + pub std: v4l2_std_id, + pub status: __u32, + pub capabilities: __u32, + pub reserved: [__u32; 3usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_output { + pub index: __u32, + pub name: [__u8; 32usize], + pub type_: __u32, + pub audioset: __u32, + pub modulator: __u32, + pub std: v4l2_std_id, + pub capabilities: __u32, + pub reserved: [__u32; 3usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_control { + pub id: __u32, + pub value: __s32, +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_ext_control { + pub id: __u32, + pub size: __u32, + pub reserved2: [__u32; 1usize], + pub __bindgen_anon_1: v4l2_ext_control__bindgen_ty_1, +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub union v4l2_ext_control__bindgen_ty_1 { + pub value: __s32, + pub value64: __s64, + pub string: *mut ::std::os::raw::c_char, + pub p_u8: *mut __u8, + pub p_u16: *mut __u16, + pub p_u32: *mut __u32, + pub p_s32: *mut __s32, + pub p_s64: *mut __s64, + pub p_area: *mut v4l2_area, + pub p_h264_sps: *mut v4l2_ctrl_h264_sps, + pub p_h264_pps: *mut v4l2_ctrl_h264_pps, + pub p_h264_scaling_matrix: *mut v4l2_ctrl_h264_scaling_matrix, + pub p_h264_pred_weights: *mut v4l2_ctrl_h264_pred_weights, + pub p_h264_slice_params: *mut v4l2_ctrl_h264_slice_params, + pub p_h264_decode_params: *mut v4l2_ctrl_h264_decode_params, + pub p_fwht_params: *mut v4l2_ctrl_fwht_params, + pub p_vp8_frame: *mut v4l2_ctrl_vp8_frame, + pub p_mpeg2_sequence: *mut v4l2_ctrl_mpeg2_sequence, + pub p_mpeg2_picture: *mut v4l2_ctrl_mpeg2_picture, + pub p_mpeg2_quantisation: *mut v4l2_ctrl_mpeg2_quantisation, + pub p_vp9_compressed_hdr_probs: *mut v4l2_ctrl_vp9_compressed_hdr, + pub p_vp9_frame: *mut v4l2_ctrl_vp9_frame, + pub p_hevc_sps: *mut v4l2_ctrl_hevc_sps, + pub p_hevc_pps: *mut v4l2_ctrl_hevc_pps, + pub p_hevc_slice_params: *mut v4l2_ctrl_hevc_slice_params, + pub p_hevc_scaling_matrix: *mut v4l2_ctrl_hevc_scaling_matrix, + pub p_hevc_decode_params: *mut v4l2_ctrl_hevc_decode_params, + pub p_av1_sequence: *mut v4l2_ctrl_av1_sequence, + pub p_av1_tile_group_entry: *mut v4l2_ctrl_av1_tile_group_entry, + pub p_av1_frame: *mut v4l2_ctrl_av1_frame, + pub p_av1_film_grain: *mut v4l2_ctrl_av1_film_grain, + pub p_hdr10_cll_info: *mut v4l2_ctrl_hdr10_cll_info, + pub p_hdr10_mastering_display: *mut v4l2_ctrl_hdr10_mastering_display, + pub ptr: *mut ::std::os::raw::c_void, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_ext_controls { + pub __bindgen_anon_1: v4l2_ext_controls__bindgen_ty_1, + pub count: __u32, + pub error_idx: __u32, + pub request_fd: __s32, + pub reserved: [__u32; 1usize], + pub controls: *mut v4l2_ext_control, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_ext_controls__bindgen_ty_1 { + pub ctrl_class: __u32, + pub which: __u32, +} +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_INTEGER: v4l2_ctrl_type = 1; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_BOOLEAN: v4l2_ctrl_type = 2; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_MENU: v4l2_ctrl_type = 3; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_BUTTON: v4l2_ctrl_type = 4; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_INTEGER64: v4l2_ctrl_type = 5; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_CTRL_CLASS: v4l2_ctrl_type = 6; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_STRING: v4l2_ctrl_type = 7; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_BITMASK: v4l2_ctrl_type = 8; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_INTEGER_MENU: v4l2_ctrl_type = 9; +pub const v4l2_ctrl_type_V4L2_CTRL_COMPOUND_TYPES: v4l2_ctrl_type = 256; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_U8: v4l2_ctrl_type = 256; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_U16: v4l2_ctrl_type = 257; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_U32: v4l2_ctrl_type = 258; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_AREA: v4l2_ctrl_type = 262; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_HDR10_CLL_INFO: v4l2_ctrl_type = 272; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY: v4l2_ctrl_type = 273; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_H264_SPS: v4l2_ctrl_type = 512; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_H264_PPS: v4l2_ctrl_type = 513; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_H264_SCALING_MATRIX: v4l2_ctrl_type = 514; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_H264_SLICE_PARAMS: v4l2_ctrl_type = 515; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_H264_DECODE_PARAMS: v4l2_ctrl_type = 516; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_H264_PRED_WEIGHTS: v4l2_ctrl_type = 517; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_FWHT_PARAMS: v4l2_ctrl_type = 544; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_VP8_FRAME: v4l2_ctrl_type = 576; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_MPEG2_QUANTISATION: v4l2_ctrl_type = 592; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_MPEG2_SEQUENCE: v4l2_ctrl_type = 593; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_MPEG2_PICTURE: v4l2_ctrl_type = 594; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR: v4l2_ctrl_type = 608; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_VP9_FRAME: v4l2_ctrl_type = 609; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_HEVC_SPS: v4l2_ctrl_type = 624; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_HEVC_PPS: v4l2_ctrl_type = 625; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS: v4l2_ctrl_type = 626; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX: v4l2_ctrl_type = 627; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS: v4l2_ctrl_type = 628; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_AV1_SEQUENCE: v4l2_ctrl_type = 640; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_AV1_TILE_GROUP_ENTRY: v4l2_ctrl_type = 641; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_AV1_FRAME: v4l2_ctrl_type = 642; +pub const v4l2_ctrl_type_V4L2_CTRL_TYPE_AV1_FILM_GRAIN: v4l2_ctrl_type = 643; +pub type v4l2_ctrl_type = ::std::os::raw::c_uint; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_queryctrl { + pub id: __u32, + pub type_: __u32, + pub name: [__u8; 32usize], + pub minimum: __s32, + pub maximum: __s32, + pub step: __s32, + pub default_value: __s32, + pub flags: __u32, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_query_ext_ctrl { + pub id: __u32, + pub type_: __u32, + pub name: [::std::os::raw::c_char; 32usize], + pub minimum: __s64, + pub maximum: __s64, + pub step: __u64, + pub default_value: __s64, + pub flags: __u32, + pub elem_size: __u32, + pub elems: __u32, + pub nr_of_dims: __u32, + pub dims: [__u32; 4usize], + pub reserved: [__u32; 32usize], +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_querymenu { + pub id: __u32, + pub index: __u32, + pub __bindgen_anon_1: v4l2_querymenu__bindgen_ty_1, + pub reserved: __u32, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_querymenu__bindgen_ty_1 { + pub name: [__u8; 32usize], + pub value: __s64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_tuner { + pub index: __u32, + pub name: [__u8; 32usize], + pub type_: __u32, + pub capability: __u32, + pub rangelow: __u32, + pub rangehigh: __u32, + pub rxsubchans: __u32, + pub audmode: __u32, + pub signal: __s32, + pub afc: __s32, + pub reserved: [__u32; 4usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_modulator { + pub index: __u32, + pub name: [__u8; 32usize], + pub capability: __u32, + pub rangelow: __u32, + pub rangehigh: __u32, + pub txsubchans: __u32, + pub type_: __u32, + pub reserved: [__u32; 3usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_frequency { + pub tuner: __u32, + pub type_: __u32, + pub frequency: __u32, + pub reserved: [__u32; 8usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_frequency_band { + pub tuner: __u32, + pub type_: __u32, + pub index: __u32, + pub capability: __u32, + pub rangelow: __u32, + pub rangehigh: __u32, + pub modulation: __u32, + pub reserved: [__u32; 9usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_hw_freq_seek { + pub tuner: __u32, + pub type_: __u32, + pub seek_upward: __u32, + pub wrap_around: __u32, + pub spacing: __u32, + pub rangelow: __u32, + pub rangehigh: __u32, + pub reserved: [__u32; 5usize], +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_rds_data { + pub lsb: __u8, + pub msb: __u8, + pub block: __u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_audio { + pub index: __u32, + pub name: [__u8; 32usize], + pub capability: __u32, + pub mode: __u32, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_audioout { + pub index: __u32, + pub name: [__u8; 32usize], + pub capability: __u32, + pub mode: __u32, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_enc_idx_entry { + pub offset: __u64, + pub pts: __u64, + pub length: __u32, + pub flags: __u32, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_enc_idx { + pub entries: __u32, + pub entries_cap: __u32, + pub reserved: [__u32; 4usize], + pub entry: [v4l2_enc_idx_entry; 64usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_encoder_cmd { + pub cmd: __u32, + pub flags: __u32, + pub __bindgen_anon_1: v4l2_encoder_cmd__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_encoder_cmd__bindgen_ty_1 { + pub raw: v4l2_encoder_cmd__bindgen_ty_1__bindgen_ty_1, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_encoder_cmd__bindgen_ty_1__bindgen_ty_1 { + pub data: [__u32; 8usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_decoder_cmd { + pub cmd: __u32, + pub flags: __u32, + pub __bindgen_anon_1: v4l2_decoder_cmd__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_decoder_cmd__bindgen_ty_1 { + pub stop: v4l2_decoder_cmd__bindgen_ty_1__bindgen_ty_1, + pub start: v4l2_decoder_cmd__bindgen_ty_1__bindgen_ty_2, + pub raw: v4l2_decoder_cmd__bindgen_ty_1__bindgen_ty_3, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_decoder_cmd__bindgen_ty_1__bindgen_ty_1 { + pub pts: __u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_decoder_cmd__bindgen_ty_1__bindgen_ty_2 { + pub speed: __s32, + pub format: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_decoder_cmd__bindgen_ty_1__bindgen_ty_3 { + pub data: [__u32; 16usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_vbi_format { + pub sampling_rate: __u32, + pub offset: __u32, + pub samples_per_line: __u32, + pub sample_format: __u32, + pub start: [__s32; 2usize], + pub count: [__u32; 2usize], + pub flags: __u32, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_sliced_vbi_format { + pub service_set: __u16, + pub service_lines: [[__u16; 24usize]; 2usize], + pub io_size: __u32, + pub reserved: [__u32; 2usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_sliced_vbi_cap { + pub service_set: __u16, + pub service_lines: [[__u16; 24usize]; 2usize], + pub type_: __u32, + pub reserved: [__u32; 3usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_sliced_vbi_data { + pub id: __u32, + pub field: __u32, + pub line: __u32, + pub reserved: __u32, + pub data: [__u8; 48usize], +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_mpeg_vbi_itv0_line { + pub id: __u8, + pub data: [__u8; 42usize], +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_mpeg_vbi_itv0 { + pub linemask: [__le32; 2usize], + pub line: [v4l2_mpeg_vbi_itv0_line; 35usize], +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_mpeg_vbi_ITV0 { + pub line: [v4l2_mpeg_vbi_itv0_line; 36usize], +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_mpeg_vbi_fmt_ivtv { + pub magic: [__u8; 4usize], + pub __bindgen_anon_1: v4l2_mpeg_vbi_fmt_ivtv__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_mpeg_vbi_fmt_ivtv__bindgen_ty_1 { + pub itv0: v4l2_mpeg_vbi_itv0, + pub ITV0: v4l2_mpeg_vbi_ITV0, +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_plane_pix_format { + pub sizeimage: __u32, + pub bytesperline: __u32, + pub reserved: [__u16; 6usize], +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_pix_format_mplane { + pub width: __u32, + pub height: __u32, + pub pixelformat: __u32, + pub field: __u32, + pub colorspace: __u32, + pub plane_fmt: [v4l2_plane_pix_format; 8usize], + pub num_planes: __u8, + pub flags: __u8, + pub __bindgen_anon_1: v4l2_pix_format_mplane__bindgen_ty_1, + pub quantization: __u8, + pub xfer_func: __u8, + pub reserved: [__u8; 7usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_pix_format_mplane__bindgen_ty_1 { + pub ycbcr_enc: __u8, + pub hsv_enc: __u8, +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_sdr_format { + pub pixelformat: __u32, + pub buffersize: __u32, + pub reserved: [__u8; 24usize], +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_meta_format { + pub dataformat: __u32, + pub buffersize: __u32, + pub width: __u32, + pub height: __u32, + pub bytesperline: __u32, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_format { + pub type_: __u32, + pub fmt: v4l2_format__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_format__bindgen_ty_1 { + pub pix: v4l2_pix_format, + pub pix_mp: v4l2_pix_format_mplane, + pub win: v4l2_window, + pub vbi: v4l2_vbi_format, + pub sliced: v4l2_sliced_vbi_format, + pub sdr: v4l2_sdr_format, + pub meta: v4l2_meta_format, + pub raw_data: [__u8; 200usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_streamparm { + pub type_: __u32, + pub parm: v4l2_streamparm__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_streamparm__bindgen_ty_1 { + pub capture: v4l2_captureparm, + pub output: v4l2_outputparm, + pub raw_data: [__u8; 200usize], +} +#[repr(C, packed)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_event_vsync { + pub field: __u8, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_event_ctrl { + pub changes: __u32, + pub type_: __u32, + pub __bindgen_anon_1: v4l2_event_ctrl__bindgen_ty_1, + pub flags: __u32, + pub minimum: __s32, + pub maximum: __s32, + pub step: __s32, + pub default_value: __s32, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_event_ctrl__bindgen_ty_1 { + pub value: __s32, + pub value64: __s64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_event_frame_sync { + pub frame_sequence: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_event_src_change { + pub changes: __u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_event_motion_det { + pub flags: __u32, + pub frame_sequence: __u32, + pub region_mask: __u32, +} +#[repr(C)] +pub struct v4l2_event { + pub type_: __u32, + pub u: v4l2_event__bindgen_ty_1, + pub pending: __u32, + pub sequence: __u32, + pub timestamp: timespec, + pub id: __u32, + pub reserved: [__u32; 8usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_event__bindgen_ty_1 { + pub vsync: v4l2_event_vsync, + pub ctrl: v4l2_event_ctrl, + pub frame_sync: v4l2_event_frame_sync, + pub src_change: v4l2_event_src_change, + pub motion_det: v4l2_event_motion_det, + pub data: [__u8; 64usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_event_subscription { + pub type_: __u32, + pub id: __u32, + pub flags: __u32, + pub reserved: [__u32; 5usize], +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_dbg_match { + pub type_: __u32, + pub __bindgen_anon_1: v4l2_dbg_match__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union v4l2_dbg_match__bindgen_ty_1 { + pub addr: __u32, + pub name: [::std::os::raw::c_char; 32usize], +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_dbg_register { + pub match_: v4l2_dbg_match, + pub size: __u32, + pub reg: __u64, + pub val: __u64, +} +#[repr(C, packed)] +#[derive(Copy, Clone)] +pub struct v4l2_dbg_chip_info { + pub match_: v4l2_dbg_match, + pub name: [::std::os::raw::c_char; 32usize], + pub flags: __u32, + pub reserved: [__u32; 32usize], +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct v4l2_create_buffers { + pub index: __u32, + pub count: __u32, + pub memory: __u32, + pub format: v4l2_format, + pub capabilities: __u32, + pub flags: __u32, + pub max_num_buffers: __u32, + pub reserved: [__u32; 5usize], +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct v4l2_remove_buffers { + pub index: __u32, + pub count: __u32, + pub type_: __u32, + pub reserved: [__u32; 13usize], +} diff --git a/rs/moq-v4l/src/timestamp.rs b/rs/moq-v4l/src/timestamp.rs new file mode 100644 index 0000000000..8a40d31e5f --- /dev/null +++ b/rs/moq-v4l/src/timestamp.rs @@ -0,0 +1,66 @@ +use std::{fmt, time}; + +use libc::{time_t, timeval}; + +#[derive(Debug, Default, Clone, Copy)] +/// Timestamp consisting of a seconds and a microseconds component +pub struct Timestamp { + pub sec: time_t, + pub usec: time_t, +} + +impl Timestamp { + /// Returns a timestamp representation + /// + /// # Arguments + /// + /// * `sec` - Seconds + /// * `usec` - Microseconds + /// + /// # Example + /// + /// ``` + /// use moq_v4l::timestamp::Timestamp; + /// let ts = Timestamp::new(5, 5); + /// ``` + pub fn new(sec: time_t, usec: time_t) -> Self { + Timestamp { sec, usec } + } +} + +impl fmt::Display for Timestamp { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let floating: f64 = self.sec as f64 + self.usec as f64 / 1_000_000.0; + write!(f, "{} [s]", floating) + } +} + +impl From for Timestamp { + fn from(tv: timeval) -> Self { + Self { + sec: tv.tv_sec as time_t, + usec: tv.tv_usec as time_t, + } + } +} + +impl From for timeval { + fn from(timestamp: Timestamp) -> Self { + Self { + tv_sec: timestamp.sec as time_t, + tv_usec: timestamp.usec as time_t, + } + } +} + +impl From for Timestamp { + fn from(duration: time::Duration) -> Self { + Self::new(duration.as_secs() as time_t, duration.subsec_micros() as time_t) + } +} + +impl From for time::Duration { + fn from(ts: Timestamp) -> Self { + Self::new(ts.sec as u64, (ts.usec * 1000) as u32) + } +} diff --git a/rs/moq-v4l/src/v4l2/api.rs b/rs/moq-v4l/src/v4l2/api.rs new file mode 100644 index 0000000000..ba3abe2d52 --- /dev/null +++ b/rs/moq-v4l/src/v4l2/api.rs @@ -0,0 +1,258 @@ +use std::ffi::CString; +use std::os::unix::ffi::OsStrExt; +use std::{io, path::Path}; + +use crate::v4l2::vidioc; + +mod detail { + use crate::v4l2::vidioc; + + pub unsafe fn open(path: *const std::os::raw::c_char, flags: i32) -> std::os::raw::c_int { + libc::open(path, flags) + } + pub unsafe fn close(fd: std::os::raw::c_int) -> std::os::raw::c_int { + libc::close(fd) + } + pub unsafe fn ioctl( + fd: std::os::raw::c_int, + request: vidioc::_IOC_TYPE, + argp: *mut std::os::raw::c_void, + ) -> std::os::raw::c_int { + /* + * It turns out the libc crate (and libc itself!) defines ioctl() with + * different, incompatible argument types on different platforms. To + * hack around this without conditional compilation, use syscall() + * instead as a drop-in replacement. Details: + * https://github.com/rust-lang/libc/issues/1036 + */ + libc::syscall(libc::SYS_ioctl, fd, request, argp) as std::os::raw::c_int + } + pub unsafe fn mmap( + start: *mut std::os::raw::c_void, + length: usize, + prot: std::os::raw::c_int, + flags: std::os::raw::c_int, + fd: std::os::raw::c_int, + offset: libc::off_t, + ) -> *mut std::os::raw::c_void { + libc::mmap(start, length, prot, flags, fd, offset) + } + pub unsafe fn munmap(start: *mut std::os::raw::c_void, length: usize) -> std::os::raw::c_int { + libc::munmap(start, length) + } +} + +/// A convenience wrapper around v4l2_open. +/// +/// Returns the file descriptor on success. +/// In case of errors, the last OS error will be reported, aka errno on Linux. +/// +/// # Arguments +/// +/// * `path` - Path to the device node +/// * `flags` - Open flags +/// +/// # Example +/// +/// ``` +/// /// +/// use moq_v4l::v4l2; +/// +/// let fd = v4l2::open("/dev/video0", libc::O_RDWR); +/// ``` +pub fn open>(path: P, flags: i32) -> io::Result { + let fd: std::os::raw::c_int; + let c_path = CString::new(path.as_ref().as_os_str().as_bytes()).unwrap(); + + unsafe { + fd = detail::open(c_path.as_ptr(), flags); + } + + if fd == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(fd) + } +} + +/// A convenience wrapper around v4l2_close. +/// +/// In case of errors, the last OS error will be reported, aka errno on Linux. +/// +/// # Arguments +/// +/// * `fd` - File descriptor of a previously opened device +/// +/// # Example +/// +/// ``` +/// /// +/// use moq_v4l::v4l2; +/// +/// let fd = v4l2::open("/dev/video0", libc::O_RDWR); +/// if let Ok(fd) = fd { +/// v4l2::close(fd).unwrap(); +/// } +/// ``` +pub fn close(fd: std::os::raw::c_int) -> io::Result<()> { + let ret: std::os::raw::c_int; + unsafe { + ret = detail::close(fd); + } + + if ret == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// A convenience wrapper around v4l2_ioctl. +/// +/// In case of errors, the last OS error will be reported, aka errno on Linux. +/// +/// # Arguments +/// +/// * `fd` - File descriptor +/// * `request` - IO control code (see [`vidioc`]) +/// * `argp` - Pointer to memory region holding the argument type +/// +/// # Safety +/// +/// For maximum flexibility, argp must be a raw pointer. Thus, the entire function is unsafe. +/// +/// # Example +/// +/// ``` +/// /// +/// use std::mem; +/// +/// use moq_v4l::sys::*; +/// use moq_v4l::v4l2; +/// +/// let fd = v4l2::open("/dev/video0", libc::O_RDWR); +/// let mut v4l2_caps: v4l2_capability; +/// unsafe { +/// v4l2_caps = mem::zeroed(); +/// } +/// +/// if let Ok(fd) = fd { +/// unsafe { +/// v4l2::ioctl(fd, v4l2::vidioc::VIDIOC_QUERYCAP, +/// &mut v4l2_caps as *mut _ as *mut std::os::raw::c_void); +/// } +/// } +/// ``` +pub unsafe fn ioctl( + fd: std::os::raw::c_int, + request: vidioc::_IOC_TYPE, + argp: *mut std::os::raw::c_void, +) -> io::Result<()> { + let ret = detail::ioctl(fd, request, argp); + + if ret == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} + +/// A convenience wrapper around v4l2_mmap. +/// +/// In case of errors, the last OS error will be reported, aka errno on Linux. +/// +/// # Arguments +/// +/// * `start` - Starting address of the new mapping, usually NULL +/// * `length` - Length of the mapped region +/// * `prot` - Desired memory protection of the mapped region +/// * `flags` - Mapping flags +/// * `fd` - File descriptor representing an opened device +/// * `offset` - Offset in the source region, usually 0 +/// +/// # Safety +/// +/// Start must be a raw pointer. Thus, the entire function is unsafe. +/// +/// # Example +/// +/// ``` +/// /// +/// use std::ptr; +/// use moq_v4l::v4l2; +/// +/// let fd = v4l2::open("/dev/video0", libc::O_RDWR); +/// if let Ok(fd) = fd { +/// /* VIDIOC_REQBUFS */ +/// /* VIDIOC_QUERYBUF */ +/// let mapping_length: usize = 1000; +/// +/// unsafe { +/// let mapping = v4l2::mmap(ptr::null_mut(), mapping_length, +/// libc::PROT_READ | libc::PROT_WRITE, +/// libc::MAP_SHARED, fd, 0); +/// } +/// v4l2::close(fd).unwrap(); +/// } +/// ``` +pub unsafe fn mmap( + start: *mut std::os::raw::c_void, + length: usize, + prot: std::os::raw::c_int, + flags: std::os::raw::c_int, + fd: std::os::raw::c_int, + offset: libc::off_t, +) -> io::Result<*mut std::os::raw::c_void> { + let ret = detail::mmap(start, length, prot, flags, fd, offset); + if ret as usize == usize::MAX { + Err(io::Error::last_os_error()) + } else { + Ok(ret) + } +} + +/// A convenience wrapper around v4l2_munmap. +/// +/// In case of errors, the last OS error will be reported, aka errno on Linux. +/// +/// # Arguments +/// +/// * `start` - Starting address of the mapping +/// * `length` - Length of the mapped region +/// +/// # Safety +/// +/// Start must be a raw pointer. Thus, the entire function is unsafe. +/// +/// # Example +/// +/// ``` +/// /// +/// use std::ptr; +/// use moq_v4l::v4l2; +/// +/// let fd = v4l2::open("/dev/video0", libc::O_RDWR); +/// if let Ok(fd) = fd { +/// /* VIDIOC_REQBUFS */ +/// /* VIDIOC_QUERYBUF */ +/// let mapping_length: usize = 1000; +/// +/// unsafe { +/// let mapping = v4l2::mmap(ptr::null_mut(), mapping_length, +/// libc::PROT_READ | libc::PROT_WRITE, +/// libc::MAP_SHARED, fd, 0); +/// if let Ok(mapping) = mapping { +/// v4l2::munmap(mapping, mapping_length).unwrap(); +/// } +/// } +/// v4l2::close(fd).unwrap(); +/// } +/// ``` +pub unsafe fn munmap(start: *mut std::os::raw::c_void, length: usize) -> io::Result<()> { + let ret = detail::munmap(start, length); + if ret == -1 { + Err(io::Error::last_os_error()) + } else { + Ok(()) + } +} diff --git a/rs/moq-v4l/src/v4l2/mod.rs b/rs/moq-v4l/src/v4l2/mod.rs new file mode 100644 index 0000000000..292c2b9a88 --- /dev/null +++ b/rs/moq-v4l/src/v4l2/mod.rs @@ -0,0 +1,5 @@ +pub mod api; +pub use api::*; + +pub mod videodev; +pub mod vidioc; diff --git a/rs/moq-v4l/src/v4l2/videodev.rs b/rs/moq-v4l/src/v4l2/videodev.rs new file mode 100644 index 0000000000..1c7f8ba910 --- /dev/null +++ b/rs/moq-v4l/src/v4l2/videodev.rs @@ -0,0 +1,17 @@ +use crate::sys::v4l2_ext_control; + +// We need to carry our own copy of this struct, because the `which` field used to be called +// `ctrl_class` and Linux now has both fields in a union. While the change is transparent as far as +// C (and thus Linux) is concerned, it causes us trouble with bindgen since we cannot directly +// access union members. +// +// See https://github.com/raymanfx/libv4l-rs/pull/40#issuecomment-885169894 for additional details. +#[repr(C)] +pub(crate) struct v4l2_ext_controls { + pub which: u32, + pub count: u32, + pub error_idx: u32, + pub request_fd: i32, + pub reserved: u32, + pub controls: *mut v4l2_ext_control, +} diff --git a/rs/moq-v4l/src/v4l2/vidioc.rs b/rs/moq-v4l/src/v4l2/vidioc.rs new file mode 100644 index 0000000000..7a53abe5ef --- /dev/null +++ b/rs/moq-v4l/src/v4l2/vidioc.rs @@ -0,0 +1,171 @@ +use crate::sys::*; + +#[cfg(not(target_env = "musl"))] +#[allow(non_camel_case_types)] +pub type _IOC_TYPE = std::os::raw::c_ulong; +#[cfg(target_env = "musl")] +#[allow(non_camel_case_types)] +pub type _IOC_TYPE = std::os::raw::c_int; + +// linux ioctl.h +const _IOC_NRBITS: u8 = 8; +const _IOC_TYPEBITS: u8 = 8; + +const _IOC_SIZEBITS: u8 = 14; + +const _IOC_NRSHIFT: u8 = 0; +const _IOC_TYPESHIFT: u8 = _IOC_NRSHIFT + _IOC_NRBITS; +const _IOC_SIZESHIFT: u8 = _IOC_TYPESHIFT + _IOC_TYPEBITS; +const _IOC_DIRSHIFT: u8 = _IOC_SIZESHIFT + _IOC_SIZEBITS; + +const _IOC_NONE: u8 = 0; +const _IOC_WRITE: u8 = 1; +const _IOC_READ: u8 = 2; + +macro_rules! _IOC_TYPECHECK { + ($type:ty) => { + std::mem::size_of::<$type>() + }; +} + +macro_rules! _IOC { + ($dir:expr, $type:expr, $nr:expr, $size:expr) => { + (($dir as _IOC_TYPE) << $crate::v4l2::vidioc::_IOC_DIRSHIFT) + | (($type as _IOC_TYPE) << $crate::v4l2::vidioc::_IOC_TYPESHIFT) + | (($nr as _IOC_TYPE) << $crate::v4l2::vidioc::_IOC_NRSHIFT) + | (($size as _IOC_TYPE) << $crate::v4l2::vidioc::_IOC_SIZESHIFT) + }; +} + +macro_rules! _IO { + ($type:expr, $nr:expr) => { + _IOC!($crate::v4l2::vidioc::_IOC_NONE, $type, $nr, 0) + }; +} + +macro_rules! _IOR { + ($type:expr, $nr:expr, $size:ty) => { + _IOC!($crate::v4l2::vidioc::_IOC_READ, $type, $nr, _IOC_TYPECHECK!($size)) + }; +} + +macro_rules! _IOW { + ($type:expr, $nr:expr, $size:ty) => { + _IOC!($crate::v4l2::vidioc::_IOC_WRITE, $type, $nr, _IOC_TYPECHECK!($size)) + }; +} + +macro_rules! _IOWR { + ($type:expr, $nr:expr, $size:ty) => { + _IOC!( + $crate::v4l2::vidioc::_IOC_READ | $crate::v4l2::vidioc::_IOC_WRITE, + $type, + $nr, + _IOC_TYPECHECK!($size) + ) + }; +} + +pub const VIDIOC_QUERYCAP: _IOC_TYPE = _IOR!(b'V', 0, v4l2_capability); +pub const VIDIOC_RESERVED: _IOC_TYPE = _IO!(b'V', 1); +pub const VIDIOC_ENUM_FMT: _IOC_TYPE = _IOWR!(b'V', 2, v4l2_fmtdesc); +pub const VIDIOC_G_FMT: _IOC_TYPE = _IOWR!(b'V', 4, v4l2_format); +pub const VIDIOC_S_FMT: _IOC_TYPE = _IOWR!(b'V', 5, v4l2_format); +pub const VIDIOC_REQBUFS: _IOC_TYPE = _IOWR!(b'V', 8, v4l2_requestbuffers); +pub const VIDIOC_QUERYBUF: _IOC_TYPE = _IOWR!(b'V', 9, v4l2_buffer); +pub const VIDIOC_G_FBUF: _IOC_TYPE = _IOR!(b'V', 10, v4l2_framebuffer); +pub const VIDIOC_S_FBUF: _IOC_TYPE = _IOW!(b'V', 11, v4l2_framebuffer); +pub const VIDIOC_OVERLAY: _IOC_TYPE = _IOW!(b'V', 14, std::os::raw::c_int); +pub const VIDIOC_QBUF: _IOC_TYPE = _IOWR!(b'V', 15, v4l2_buffer); +pub const VIDIOC_EXPBUF: _IOC_TYPE = _IOWR!(b'V', 16, v4l2_exportbuffer); +pub const VIDIOC_DQBUF: _IOC_TYPE = _IOWR!(b'V', 17, v4l2_buffer); +pub const VIDIOC_STREAMON: _IOC_TYPE = _IOW!(b'V', 18, std::os::raw::c_int); +pub const VIDIOC_STREAMOFF: _IOC_TYPE = _IOW!(b'V', 19, std::os::raw::c_int); +pub const VIDIOC_G_PARM: _IOC_TYPE = _IOWR!(b'V', 21, v4l2_streamparm); +pub const VIDIOC_S_PARM: _IOC_TYPE = _IOWR!(b'V', 22, v4l2_streamparm); +pub const VIDIOC_G_STD: _IOC_TYPE = _IOR!(b'V', 23, v4l2_std_id); +pub const VIDIOC_S_STD: _IOC_TYPE = _IOW!(b'V', 24, v4l2_std_id); +pub const VIDIOC_ENUMSTD: _IOC_TYPE = _IOWR!(b'V', 25, v4l2_standard); +pub const VIDIOC_ENUMINPUT: _IOC_TYPE = _IOWR!(b'V', 26, v4l2_input); +pub const VIDIOC_G_CTRL: _IOC_TYPE = _IOWR!(b'V', 27, v4l2_control); +pub const VIDIOC_S_CTRL: _IOC_TYPE = _IOWR!(b'V', 28, v4l2_control); +pub const VIDIOC_G_TUNER: _IOC_TYPE = _IOWR!(b'V', 29, v4l2_tuner); +pub const VIDIOC_S_TUNER: _IOC_TYPE = _IOW!(b'V', 30, v4l2_tuner); +pub const VIDIOC_G_AUDIO: _IOC_TYPE = _IOR!(b'V', 33, v4l2_audio); +pub const VIDIOC_S_AUDIO: _IOC_TYPE = _IOW!(b'V', 34, v4l2_audio); +pub const VIDIOC_QUERYCTRL: _IOC_TYPE = _IOWR!(b'V', 36, v4l2_queryctrl); +pub const VIDIOC_QUERYMENU: _IOC_TYPE = _IOWR!(b'V', 37, v4l2_querymenu); +pub const VIDIOC_G_INPUT: _IOC_TYPE = _IOR!(b'V', 38, std::os::raw::c_int); +pub const VIDIOC_S_INPUT: _IOC_TYPE = _IOWR!(b'V', 39, std::os::raw::c_int); +pub const VIDIOC_G_EDID: _IOC_TYPE = _IOWR!(b'V', 40, v4l2_edid); +pub const VIDIOC_S_EDID: _IOC_TYPE = _IOWR!(b'V', 41, v4l2_edid); +pub const VIDIOC_G_OUTPUT: _IOC_TYPE = _IOR!(b'V', 46, std::os::raw::c_int); +pub const VIDIOC_S_OUTPUT: _IOC_TYPE = _IOWR!(b'V', 47, std::os::raw::c_int); +pub const VIDIOC_ENUMOUTPUT: _IOC_TYPE = _IOWR!(b'V', 48, v4l2_output); +pub const VIDIOC_G_AUDOUT: _IOC_TYPE = _IOR!(b'V', 49, v4l2_audioout); +pub const VIDIOC_S_AUDOUT: _IOC_TYPE = _IOW!(b'V', 50, v4l2_audioout); +pub const VIDIOC_G_MODULATOR: _IOC_TYPE = _IOWR!(b'V', 54, v4l2_modulator); +pub const VIDIOC_S_MODULATOR: _IOC_TYPE = _IOW!(b'V', 55, v4l2_modulator); +pub const VIDIOC_G_FREQUENCY: _IOC_TYPE = _IOWR!(b'V', 56, v4l2_frequency); +pub const VIDIOC_S_FREQUENCY: _IOC_TYPE = _IOW!(b'V', 57, v4l2_frequency); +pub const VIDIOC_CROPCAP: _IOC_TYPE = _IOWR!(b'V', 58, v4l2_cropcap); +pub const VIDIOC_G_CROP: _IOC_TYPE = _IOWR!(b'V', 59, v4l2_crop); +pub const VIDIOC_S_CROP: _IOC_TYPE = _IOW!(b'V', 60, v4l2_crop); +pub const VIDIOC_G_JPEGCOMP: _IOC_TYPE = _IOR!(b'V', 61, v4l2_jpegcompression); +pub const VIDIOC_S_JPEGCOMP: _IOC_TYPE = _IOW!(b'V', 62, v4l2_jpegcompression); +pub const VIDIOC_QUERYSTD: _IOC_TYPE = _IOR!(b'V', 63, v4l2_std_id); +pub const VIDIOC_TRY_FMT: _IOC_TYPE = _IOWR!(b'V', 64, v4l2_format); +pub const VIDIOC_ENUMAUDIO: _IOC_TYPE = _IOWR!(b'V', 65, v4l2_audio); +pub const VIDIOC_ENUMAUDOUT: _IOC_TYPE = _IOWR!(b'V', 66, v4l2_audioout); +pub const VIDIOC_G_PRIORITY: _IOC_TYPE = _IOR!(b'V', 67, std::os::raw::c_int); +pub const VIDIOC_S_PRIORITY: _IOC_TYPE = _IOW!(b'V', 68, std::os::raw::c_int); +pub const VIDIOC_G_SLICED_VBI_CAP: _IOC_TYPE = _IOWR!(b'V', 69, v4l2_sliced_vbi_cap); +pub const VIDIOC_LOG_STATUS: _IOC_TYPE = _IO!(b'V', 70); +pub const VIDIOC_G_EXT_CTRLS: _IOC_TYPE = _IOWR!(b'V', 71, v4l2_ext_controls); +pub const VIDIOC_S_EXT_CTRLS: _IOC_TYPE = _IOWR!(b'V', 72, v4l2_ext_controls); +pub const VIDIOC_TRY_EXT_CTRLS: _IOC_TYPE = _IOWR!(b'V', 73, v4l2_ext_controls); +pub const VIDIOC_ENUM_FRAMESIZES: _IOC_TYPE = _IOWR!(b'V', 74, v4l2_frmsizeenum); +pub const VIDIOC_ENUM_FRAMEINTERVALS: _IOC_TYPE = _IOWR!(b'V', 75, v4l2_frmivalenum); +pub const VIDIOC_G_ENC_INDEX: _IOC_TYPE = _IOR!(b'V', 76, v4l2_enc_idx); +pub const VIDIOC_ENCODER_CMD: _IOC_TYPE = _IOWR!(b'V', 77, v4l2_encoder_cmd); +pub const VIDIOC_TRY_ENCODER_CMD: _IOC_TYPE = _IOWR!(b'V', 78, v4l2_encoder_cmd); +pub const VIDIOC_DBG_S_REGISTER: _IOC_TYPE = _IOW!(b'V', 79, v4l2_dbg_register); +pub const VIDIOC_DBG_G_REGISTER: _IOC_TYPE = _IOWR!(b'V', 80, v4l2_dbg_register); +pub const VIDIOC_S_HW_FREQ_SEEK: _IOC_TYPE = _IOW!(b'V', 82, v4l2_hw_freq_seek); +pub const VIDIOC_S_DV_TIMINGS: _IOC_TYPE = _IOWR!(b'V', 87, v4l2_dv_timings); +pub const VIDIOC_G_DV_TIMINGS: _IOC_TYPE = _IOWR!(b'V', 88, v4l2_dv_timings); +pub const VIDIOC_DQEVENT: _IOC_TYPE = _IOR!(b'V', 89, v4l2_event); +pub const VIDIOC_SUBSCRIBE_EVENT: _IOC_TYPE = _IOW!(b'V', 90, v4l2_event_subscription); +pub const VIDIOC_UNSUBSCRIBE_EVENT: _IOC_TYPE = _IOW!(b'V', 91, v4l2_event_subscription); +pub const VIDIOC_CREATE_BUFS: _IOC_TYPE = _IOWR!(b'V', 92, v4l2_create_buffers); +pub const VIDIOC_PREPARE_BUF: _IOC_TYPE = _IOWR!(b'V', 93, v4l2_buffer); +pub const VIDIOC_G_SELECTION: _IOC_TYPE = _IOWR!(b'V', 94, v4l2_selection); +pub const VIDIOC_S_SELECTION: _IOC_TYPE = _IOWR!(b'V', 95, v4l2_selection); +pub const VIDIOC_DECODER_CMD: _IOC_TYPE = _IOWR!(b'V', 96, v4l2_decoder_cmd); +pub const VIDIOC_TRY_DECODER_CMD: _IOC_TYPE = _IOWR!(b'V', 97, v4l2_decoder_cmd); +pub const VIDIOC_ENUM_DV_TIMINGS: _IOC_TYPE = _IOWR!(b'V', 98, v4l2_enum_dv_timings); +pub const VIDIOC_QUERY_DV_TIMINGS: _IOC_TYPE = _IOR!(b'V', 99, v4l2_dv_timings); +pub const VIDIOC_DV_TIMINGS_CAP: _IOC_TYPE = _IOWR!(b'V', 100, v4l2_dv_timings_cap); +pub const VIDIOC_ENUM_FREQ_BANDS: _IOC_TYPE = _IOWR!(b'V', 101, v4l2_frequency_band); +pub const VIDIOC_DBG_G_CHIP_INFO: _IOC_TYPE = _IOWR!(b'V', 102, v4l2_dbg_chip_info); +pub const VIDIOC_QUERY_EXT_CTRL: _IOC_TYPE = _IOWR!(b'V', 103, v4l2_query_ext_ctrl); +pub const VIDIOC_REMOVE_BUFS: _IOC_TYPE = _IOWR!(b'V', 104, v4l2_remove_buffers); + +#[cfg(test)] +mod tests { + use super::*; + + /// The values `videodev2.h` expands to on a 64-bit host. A wrong code is + /// `ENOTTY` at runtime on whichever board reaches it first, so the shifts, + /// the direction bits, and the generated struct sizes are pinned here. + #[test] + fn codes_match_the_header() { + assert_eq!(VIDIOC_QUERYCAP, 0x8068_5600); + assert_eq!(VIDIOC_S_FMT, 0xc0d0_5605); + assert_eq!(VIDIOC_STREAMON, 0x4004_5612); + assert_eq!(VIDIOC_DQEVENT, 0x8088_5659); + assert_eq!(VIDIOC_SUBSCRIBE_EVENT, 0x4020_565a); + assert_eq!(VIDIOC_G_SELECTION, 0xc040_565e); + assert_eq!(VIDIOC_DECODER_CMD, 0xc048_5660); + } +} diff --git a/rs/moq-v4l/src/video/capture/mod.rs b/rs/moq-v4l/src/video/capture/mod.rs new file mode 100644 index 0000000000..235ce20c54 --- /dev/null +++ b/rs/moq-v4l/src/video/capture/mod.rs @@ -0,0 +1,57 @@ +pub mod parameters; +pub use parameters::Parameters; + +use std::convert::TryFrom; +use std::{io, mem}; + +use crate::buffer::Type; +use crate::device::Device; +use crate::format::FourCC; +use crate::format::{Description as FormatDescription, Format}; +use crate::frameinterval::FrameInterval; +use crate::framesize::FrameSize; +use crate::sys::*; +use crate::v4l2; +use crate::video::traits::Capture; + +impl Capture for Device { + impl_enum_frameintervals!(); + impl_enum_framesizes!(); + impl_enum_formats!(Type::VideoCapture); + impl_format!(Type::VideoCapture); + impl_set_format!(Type::VideoCapture); + + fn params(&self) -> io::Result { + unsafe { + let mut v4l2_params = v4l2_streamparm { + type_: Type::VideoCapture as u32, + ..mem::zeroed() + }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_G_PARM, + &mut v4l2_params as *mut _ as *mut std::os::raw::c_void, + )?; + + Ok(Parameters::from(v4l2_params.parm.capture)) + } + } + + fn set_params(&self, params: &Parameters) -> io::Result { + unsafe { + let mut v4l2_params = v4l2_streamparm { + type_: Type::VideoCapture as u32, + parm: v4l2_streamparm__bindgen_ty_1 { + capture: (*params).into(), + }, + }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_S_PARM, + &mut v4l2_params as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.params() + } +} diff --git a/rs/moq-v4l/src/video/capture/parameters.rs b/rs/moq-v4l/src/video/capture/parameters.rs new file mode 100644 index 0000000000..8b859f9810 --- /dev/null +++ b/rs/moq-v4l/src/video/capture/parameters.rs @@ -0,0 +1,87 @@ +use bitflags::bitflags; +use std::{fmt, mem}; + +use crate::fraction::Fraction; +use crate::parameters::Capabilities; +use crate::sys::*; + +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] + pub struct Modes: u32 { + const HIGH_QUALITY = 0x1000; + } +} + +impl From for Modes { + fn from(caps: u32) -> Self { + Self::from_bits_truncate(caps) + } +} + +impl From for u32 { + fn from(modes: Modes) -> Self { + modes.bits() + } +} + +impl fmt::Display for Modes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self, f) + } +} + +#[derive(Debug, Copy, Clone)] +/// Streaming parameters (single-planar) +pub struct Parameters { + pub capabilities: Capabilities, + pub modes: Modes, + pub interval: Fraction, +} + +impl Parameters { + pub fn new(frac: Fraction) -> Self { + Parameters { + capabilities: Capabilities::from(0), + modes: Modes::from(0), + interval: frac, + } + } + + pub fn with_fps(fps: u32) -> Self { + Parameters { + capabilities: Capabilities::from(0), + modes: Modes::from(0), + interval: Fraction::new(1, fps), + } + } +} + +impl fmt::Display for Parameters { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "capabilities : {}", self.capabilities)?; + writeln!(f, "modes : {}", self.modes)?; + writeln!(f, "interval : {} [s]", self.interval)?; + Ok(()) + } +} + +impl From for Parameters { + fn from(params: v4l2_captureparm) -> Self { + Self { + capabilities: Capabilities::from(params.capability), + modes: Modes::from(params.capturemode), + interval: Fraction::from(params.timeperframe), + } + } +} + +impl From for v4l2_captureparm { + fn from(parameters: Parameters) -> Self { + Self { + capability: parameters.capabilities.into(), + capturemode: parameters.modes.into(), + timeperframe: parameters.interval.into(), + ..unsafe { mem::zeroed() } + } + } +} diff --git a/rs/moq-v4l/src/video/macros.rs b/rs/moq-v4l/src/video/macros.rs new file mode 100644 index 0000000000..cfe6512dfb --- /dev/null +++ b/rs/moq-v4l/src/video/macros.rs @@ -0,0 +1,163 @@ +macro_rules! impl_enum_frameintervals { + () => { + fn enum_frameintervals(&self, fourcc: FourCC, width: u32, height: u32) -> io::Result> { + let mut frameintervals = Vec::new(); + let mut v4l2_struct = v4l2_frmivalenum { + index: 0, + pixel_format: fourcc.into(), + width, + height, + ..unsafe { mem::zeroed() } + }; + + loop { + let ret = unsafe { + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_ENUM_FRAMEINTERVALS, + &mut v4l2_struct as *mut _ as *mut std::os::raw::c_void, + ) + }; + + if ret.is_err() { + if v4l2_struct.index == 0 { + return Err(ret.err().unwrap()); + } else { + return Ok(frameintervals); + } + } + + if let Ok(frame_interval) = FrameInterval::try_from(v4l2_struct) { + frameintervals.push(frame_interval); + } + + v4l2_struct.index += 1; + } + } + }; +} + +macro_rules! impl_enum_framesizes { + () => { + fn enum_framesizes(&self, fourcc: FourCC) -> io::Result> { + let mut framesizes = Vec::new(); + let mut v4l2_struct = v4l2_frmsizeenum { + index: 0, + pixel_format: fourcc.into(), + ..unsafe { mem::zeroed() } + }; + + loop { + let ret = unsafe { + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_ENUM_FRAMESIZES, + &mut v4l2_struct as *mut _ as *mut std::os::raw::c_void, + ) + }; + + if ret.is_err() { + if v4l2_struct.index == 0 { + return Err(ret.err().unwrap()); + } else { + return Ok(framesizes); + } + } + + if let Ok(frame_size) = FrameSize::try_from(v4l2_struct) { + framesizes.push(frame_size); + } + + v4l2_struct.index += 1; + } + } + }; +} + +macro_rules! impl_enum_formats { + ($typ:expr) => { + fn enum_formats(&self) -> io::Result> { + let mut formats: Vec = Vec::new(); + let mut v4l2_fmt = v4l2_fmtdesc { + index: 0, + type_: $typ as u32, + ..unsafe { mem::zeroed() } + }; + + let mut ret: io::Result<()>; + + unsafe { + ret = v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_ENUM_FMT, + &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, + ); + } + + if ret.is_err() { + // Enumerating the first format (at index 0) failed, so there are no formats available + // for this device. Just return an empty vec in this case. + return Ok(Vec::new()); + } + + while ret.is_ok() { + formats.push(FormatDescription::from(v4l2_fmt)); + v4l2_fmt.index += 1; + + unsafe { + v4l2_fmt.description = mem::zeroed(); + } + + unsafe { + ret = v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_ENUM_FMT, + &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, + ); + } + } + + Ok(formats) + } + }; +} + +macro_rules! impl_format { + ($typ:expr) => { + fn format(&self) -> io::Result { + unsafe { + let mut v4l2_fmt = v4l2_format { + type_: $typ as u32, + ..mem::zeroed() + }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_G_FMT, + &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, + )?; + + Ok(Format::from(v4l2_fmt.fmt.pix)) + } + } + }; +} + +macro_rules! impl_set_format { + ($typ:expr) => { + fn set_format(&self, fmt: &Format) -> io::Result { + unsafe { + let mut v4l2_fmt = v4l2_format { + type_: $typ as u32, + fmt: v4l2_format__bindgen_ty_1 { pix: (*fmt).into() }, + }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_S_FMT, + &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.format() + } + }; +} diff --git a/rs/moq-v4l/src/video/mod.rs b/rs/moq-v4l/src/video/mod.rs new file mode 100644 index 0000000000..5ca8ade75d --- /dev/null +++ b/rs/moq-v4l/src/video/mod.rs @@ -0,0 +1,9 @@ +#[macro_use] +mod macros; + +pub mod traits; + +pub mod capture; +pub mod output; + +pub use traits::{Capture, Output}; diff --git a/rs/moq-v4l/src/video/output/mod.rs b/rs/moq-v4l/src/video/output/mod.rs new file mode 100644 index 0000000000..9d730b7c52 --- /dev/null +++ b/rs/moq-v4l/src/video/output/mod.rs @@ -0,0 +1,57 @@ +pub mod parameters; +pub use parameters::Parameters; + +use std::convert::TryFrom; +use std::{io, mem}; + +use crate::buffer::Type; +use crate::device::Device; +use crate::format::FourCC; +use crate::format::{Description as FormatDescription, Format}; +use crate::frameinterval::FrameInterval; +use crate::framesize::FrameSize; +use crate::sys::*; +use crate::v4l2; +use crate::video::traits::Output; + +impl Output for Device { + impl_enum_frameintervals!(); + impl_enum_framesizes!(); + impl_enum_formats!(Type::VideoOutput); + impl_format!(Type::VideoOutput); + impl_set_format!(Type::VideoOutput); + + fn params(&self) -> io::Result { + unsafe { + let mut v4l2_params = v4l2_streamparm { + type_: Type::VideoOutput as u32, + ..mem::zeroed() + }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_G_PARM, + &mut v4l2_params as *mut _ as *mut std::os::raw::c_void, + )?; + + Ok(Parameters::from(v4l2_params.parm.output)) + } + } + + fn set_params(&self, params: &Parameters) -> io::Result { + unsafe { + let mut v4l2_params = v4l2_streamparm { + type_: Type::VideoOutput as u32, + parm: v4l2_streamparm__bindgen_ty_1 { + output: (*params).into(), + }, + }; + v4l2::ioctl( + self.handle().fd(), + v4l2::vidioc::VIDIOC_S_PARM, + &mut v4l2_params as *mut _ as *mut std::os::raw::c_void, + )?; + } + + self.params() + } +} diff --git a/rs/moq-v4l/src/video/output/parameters.rs b/rs/moq-v4l/src/video/output/parameters.rs new file mode 100644 index 0000000000..cfd73fe0d0 --- /dev/null +++ b/rs/moq-v4l/src/video/output/parameters.rs @@ -0,0 +1,55 @@ +use std::{fmt, mem}; + +use crate::fraction::Fraction; +use crate::parameters::Capabilities; +use crate::sys::*; + +#[derive(Debug, Copy, Clone)] +/// Output parameters (single-planar) +pub struct Parameters { + pub capabilities: Capabilities, + pub interval: Fraction, +} + +impl Parameters { + pub fn new(frac: Fraction) -> Self { + Parameters { + capabilities: Capabilities::from(0), + interval: frac, + } + } + + pub fn with_fps(fps: u32) -> Self { + Parameters { + capabilities: Capabilities::from(0), + interval: Fraction::new(1, fps), + } + } +} + +impl fmt::Display for Parameters { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "capabilities : {}", self.capabilities)?; + writeln!(f, "interval : {} [s]", self.interval)?; + Ok(()) + } +} + +impl From for Parameters { + fn from(params: v4l2_outputparm) -> Self { + Self { + capabilities: Capabilities::from(params.capability), + interval: Fraction::from(params.timeperframe), + } + } +} + +impl From for v4l2_outputparm { + fn from(parameters: Parameters) -> Self { + Self { + capability: parameters.capabilities.into(), + timeperframe: parameters.interval.into(), + ..unsafe { mem::zeroed() } + } + } +} diff --git a/rs/moq-v4l/src/video/traits.rs b/rs/moq-v4l/src/video/traits.rs new file mode 100644 index 0000000000..6816e63b27 --- /dev/null +++ b/rs/moq-v4l/src/video/traits.rs @@ -0,0 +1,89 @@ +use std::io; + +use crate::video::capture::Parameters as CaptureParameters; +use crate::video::output::Parameters as OutputParameters; +use crate::{ + format::Description as FormatDescription, format::Format, format::FourCC, frameinterval::FrameInterval, + framesize::FrameSize, +}; + +/// Capture device protocol +pub trait Capture { + /// Returns a vector of all frame intervals that the device supports for the given pixel format + /// and frame size + fn enum_frameintervals(&self, fourcc: FourCC, width: u32, height: u32) -> io::Result>; + + /// Returns a vector of valid framesizes that the device supports for the given pixel format + fn enum_framesizes(&self, fourcc: FourCC) -> io::Result>; + + /// Returns a vector of valid formats for this device + /// + /// The "emulated" field describes formats filled in by libv4lconvert. + /// There may be a conversion related performance penalty when using them. + fn enum_formats(&self) -> io::Result>; + + /// Returns the format currently in use + fn format(&self) -> io::Result; + + /// Modifies the capture format and returns the actual format + /// + /// The driver tries to match the format parameters on a best effort basis. + /// Thus, if the combination of format properties cannot be achieved, the closest possible + /// settings are used and reported back. + /// + /// + /// # Arguments + /// + /// * `fmt` - Desired format + fn set_format(&self, fmt: &Format) -> io::Result; + + /// Returns the parameters currently in use + fn params(&self) -> io::Result; + + /// Modifies the capture parameters and returns the actual parameters + /// + /// # Arguments + /// + /// * `params` - Desired parameters + fn set_params(&self, params: &CaptureParameters) -> io::Result; +} + +/// Output device protocol +pub trait Output { + /// Returns a vector of all frame intervals that the device supports for the given pixel format + /// and frame size + fn enum_frameintervals(&self, fourcc: FourCC, width: u32, height: u32) -> io::Result>; + + /// Returns a vector of valid framesizes that the device supports for the given pixel format + fn enum_framesizes(&self, fourcc: FourCC) -> io::Result>; + + /// Returns a vector of valid formats for this device + /// + /// The "emulated" field describes formats filled in by libv4lconvert. + /// There may be a conversion related performance penalty when using them. + fn enum_formats(&self) -> io::Result>; + + /// Returns the format currently in use + fn format(&self) -> io::Result; + + /// Modifies the capture format and returns the actual format + /// + /// The driver tries to match the format parameters on a best effort basis. + /// Thus, if the combination of format properties cannot be achieved, the closest possible + /// settings are used and reported back. + /// + /// # Arguments + /// + /// * `fmt` - Desired format + fn set_format(&self, fmt: &Format) -> io::Result; + + /// Returns the parameters currently in use + fn params(&self) -> io::Result; + + /// Modifies the output parameters and returns the actual parameters + /// + /// # Arguments + /// + /// * `params` - Desired parameters + fn set_params(&self, params: &OutputParameters) -> io::Result; +} diff --git a/rs/moq-video/Cargo.toml b/rs/moq-video/Cargo.toml index f59be66af5..beaa4eb75d 100644 --- a/rs/moq-video/Cargo.toml +++ b/rs/moq-video/Cargo.toml @@ -16,10 +16,10 @@ categories = ["multimedia", "multimedia::video", "multimedia::encoding"] # On by default: everything that costs the build nothing beyond cargo. Off by # default: every feature that needs libclang or a system library on the build # host, however cheap it is on other platforms, since a default is one setting -# for every host. `capture` and `v4l2` run bindgen over the kernel's videodev2.h -# (the `v4l` crate), `vaapi` runs it over its vendored libva headers, and +# for every host. `vaapi` runs bindgen over its vendored libva headers and # `pipewire` links libpipewire; a consumer whose build host has those turns them -# on. The features exist so a consumer can pick what it wants, not to hide code +# on. `capture` and `v4l2` no longer cost anything on Linux (moq-v4l checks its +# bindings in) and stay opt-in only until every distribution ships them. The features exist so a consumer can pick what it wants, not to hide code # from the default compile (`just check` lints default features only, so the # opt-in ones are compiled by nightly's `just rs features` and `just rs macos`). # OpenH264 remains the default software fallback, but is optional so a hardware- @@ -27,11 +27,11 @@ categories = ["multimedia", "multimedia::video", "multimedia::encoding"] # at the root manifest (`default-features = false`) and pick per crate, so the # relay and the language bindings never build device or rendering stacks. default = ["mediacodec", "nvidia", "openh264"] -# Native camera and screen capture. Off by default because the Linux camera path -# (the `v4l` crate) runs bindgen over the kernel's videodev2.h, so the build host -# needs libclang and the Linux headers; macOS and Windows use OS frameworks and -# would pay nothing. moq-cli's `capture` turns it on. -capture = ["dep:libc", "dep:v4l", "dep:x11rb", "dep:zune-jpeg"] +# Native camera and screen capture. Costs the build nothing on any platform: +# Linux goes through moq-v4l (bindings checked in), macOS and Windows use OS +# frameworks. Still off by default until every distribution ships it, which is +# a packaging decision rather than a build cost. moq-cli's `capture` turns it on. +capture = ["dep:libc", "dep:moq-v4l", "dep:x11rb", "dep:zune-jpeg"] # Android MediaCodec encode/decode and its AHardwareBuffer frame surface. Kept # behind a feature because these NDK entry points require API 26, while the # language-binding artifacts still support API 24 and disable default features. @@ -62,14 +62,13 @@ vaapi = ["dmabuf", "dep:moq-vaapi"] # run on a Raspberry Pi 4 (bcm2835-codec, Raspberry Pi OS Bookworm): the encoder # on `/dev/video11` produced Constrained Baseline 640x360 that plays back # correctly, and the decoder played a 640x360 stream for a minute without a -# failure and is what automatic selection picks on that board. Off by default -# because the `v4l` crate runs bindgen over the kernel's videodev2.h, so the -# build host needs libclang and the Linux headers (the same cost `capture` pays -# for the camera on Linux, so a build with both pays it once). A host with no M2M -# codec node fails at open, so automatic backend selection falls through to the -# next encoder or decoder; `Kind::Named("openh264")` sidesteps it on a board -# whose driver misbehaves. -v4l2 = ["dep:v4l", "dep:libc"] +# failure and is what automatic selection picks on that board. Costs the build +# nothing (moq-v4l checks its bindings in) and shares that dependency with +# `capture`; still off by default alongside it. A host with no M2M codec node +# fails at open, so automatic backend selection falls through to the next +# encoder or decoder; `Kind::Named("openh264")` sidesteps it on a board whose +# driver misbehaves. +v4l2 = ["dep:moq-v4l", "dep:libc"] # Linux DMA-BUF surface vocabulary and CPU fallback support. Enabled by every # backend that can produce or consume one. It pulls no graphics API by itself. dmabuf = ["dep:libc", "dep:linux-raw-sys"] @@ -172,13 +171,14 @@ moq-vaapi = { workspace = true, optional = true } # PipeWire video stream for the portal's node, behind the `pipewire` feature. # Links libpipewire-0.3 via pkg-config at build time; bindgen needs libclang. pipewire = { version = "0.10", optional = true } -# Native V4L2 webcam capture (replaces nokhwa) and, behind the `v4l2` feature, -# the M2M hardware codecs. `v4l` streams MMAP buffers; MJPEG cameras are decoded -# with the pure-Rust `zune-jpeg` (no libjpeg/IJG). The codec backends use its raw -# layer (`v4l::v4l_sys` for the videodev2.h structs, `v4l::v4l2::vidioc` for the -# request codes) rather than a second V4L2 crate, so no ioctl struct is -# hand-rolled and the dependency is one the tree already carries. -v4l = { version = "0.14", optional = true } +# Native V4L2 webcam capture and, behind the `v4l2` feature, the M2M hardware +# codecs. An in-tree fork of `v4l` (see rs/moq-v4l) with the videodev2.h +# bindings checked in, so the build needs no libclang or kernel headers. It +# streams MMAP buffers; MJPEG cameras are decoded with the pure-Rust `zune-jpeg` +# (no libjpeg/IJG). The codec backends use its raw layer (`moq_v4l::sys` for the +# videodev2.h structs, `moq_v4l::v4l2::vidioc` for the request codes) rather +# than a second V4L2 crate, so no ioctl struct is hand-rolled. +moq-v4l = { workspace = true, optional = true } # X11 display/window enumeration and capture. Pure Rust and used when no # Wayland session is active, so Linux screen capture still works without a # portal and callers can select a stable monitor or window id. diff --git a/rs/moq-video/src/capture/v4l2.rs b/rs/moq-video/src/capture/v4l2.rs index a0113c6603..e43f348d96 100644 --- a/rs/moq-video/src/capture/v4l2.rs +++ b/rs/moq-video/src/capture/v4l2.rs @@ -1,6 +1,6 @@ //! Native V4L2 webcam capture (Linux), replacing nokhwa. //! -//! Streams MMAP buffers through the [`v4l`] crate and converts each frame to CPU +//! Streams MMAP buffers through the [`moq_v4l`] crate and converts each frame to CPU //! [`I420`] for the encoder. Two source formats cover essentially all UVC //! webcams: YUYV (raw 4:2:2, resampled directly) and MJPEG (decoded to RGB with //! the pure-Rust [`zune_jpeg`], then converted). This is the CPU path feeding @@ -8,15 +8,15 @@ use std::collections::{BTreeMap, BTreeSet}; -use v4l::buffer::Type as BufType; -use v4l::capability::Flags; -use v4l::frameinterval::FrameIntervalEnum; -use v4l::framesize::FrameSizeEnum; -use v4l::io::mmap::Stream as MmapStream; -use v4l::io::traits::CaptureStream; -use v4l::video::Capture; -use v4l::video::capture::Parameters; -use v4l::{Device, Format, FourCC}; +use moq_v4l::buffer::Type as BufType; +use moq_v4l::capability::Flags; +use moq_v4l::frameinterval::FrameIntervalEnum; +use moq_v4l::framesize::FrameSizeEnum; +use moq_v4l::io::mmap::Stream as MmapStream; +use moq_v4l::io::traits::CaptureStream; +use moq_v4l::video::Capture; +use moq_v4l::video::capture::Parameters; +use moq_v4l::{Device, Format, FourCC}; use zune_jpeg::zune_core::bytestream::ZCursor; use super::channel::FrameChannel; @@ -27,8 +27,8 @@ use crate::{Error, Size}; /// List V4L2 capture nodes using paths that [`open_device`] accepts. pub(super) fn cameras() -> Result, Error> { - let mut nodes = v4l::context::enum_devices(); - nodes.sort_by_key(v4l::context::Node::index); + let mut nodes = moq_v4l::context::enum_devices(); + nodes.sort_by_key(moq_v4l::context::Node::index); let cameras = nodes .into_iter() @@ -165,14 +165,14 @@ fn frame_sizes(device: &Device, fourcc: FourCC) -> Result, Er let mut sizes = Vec::new(); for index in 0..=u32::MAX { // All fields are integers or integer unions; reserved fields must be zero. - let mut entry: v4l::v4l_sys::v4l2_frmsizeenum = unsafe { std::mem::zeroed() }; + let mut entry: moq_v4l::sys::v4l2_frmsizeenum = unsafe { std::mem::zeroed() }; entry.index = index; entry.pixel_format = fourcc.into(); // The request matches the initialized argument's type and size. let result = unsafe { - v4l::v4l2::ioctl( + moq_v4l::v4l2::ioctl( device.handle().fd(), - v4l::v4l2::vidioc::VIDIOC_ENUM_FRAMESIZES, + moq_v4l::v4l2::vidioc::VIDIOC_ENUM_FRAMESIZES, &mut entry as *mut _ as *mut std::ffi::c_void, ) }; @@ -197,16 +197,16 @@ fn framerates(device: &Device, fourcc: FourCC, size: Size) -> Result, let mut rates = Vec::new(); for index in 0..=u32::MAX { // All fields are integers or integer unions; reserved fields must be zero. - let mut entry: v4l::v4l_sys::v4l2_frmivalenum = unsafe { std::mem::zeroed() }; + let mut entry: moq_v4l::sys::v4l2_frmivalenum = unsafe { std::mem::zeroed() }; entry.index = index; entry.pixel_format = fourcc.into(); entry.width = size.width; entry.height = size.height; // The request matches the initialized argument's type and size. let result = unsafe { - v4l::v4l2::ioctl( + moq_v4l::v4l2::ioctl( device.handle().fd(), - v4l::v4l2::vidioc::VIDIOC_ENUM_FRAMEINTERVALS, + moq_v4l::v4l2::vidioc::VIDIOC_ENUM_FRAMEINTERVALS, &mut entry as *mut _ as *mut std::ffi::c_void, ) }; @@ -221,7 +221,7 @@ fn framerates(device: &Device, fourcc: FourCC, size: Size) -> Result, Err(Error::Codec(anyhow::anyhow!("V4L2 frame interval index overflow"))) } -fn rate(interval: v4l::Fraction) -> Result { +fn rate(interval: moq_v4l::Fraction) -> Result { Rate::new(interval.denominator, interval.numerator) .map_err(|error| Error::Codec(anyhow::anyhow!("invalid V4L2 frame interval: {error}"))) } @@ -448,7 +448,7 @@ fn negotiate(device: &Device, name: &str, want: Request) -> Result<(Format, Sour negotiate_with(name, want, |format| { let format = set_format(device, format)?; if let Some(fps) = framerate { - let interval = v4l::Fraction::new(fps.denominator(), fps.numerator()); + let interval = moq_v4l::Fraction::new(fps.denominator(), fps.numerator()); match Capture::set_params(device, &Parameters::new(interval)) { Ok(_) => {} Err(error) if matches!(error.raw_os_error(), Some(libc::EINVAL | libc::ENOTTY)) => {} @@ -567,7 +567,7 @@ fn set_format(device: &Device, format: Format) -> Result { mod tests { use super::*; - use v4l::framesize::{Discrete, Stepwise}; + use moq_v4l::framesize::{Discrete, Stepwise}; fn request(width: u32, height: u32) -> Request { Request { @@ -610,28 +610,28 @@ mod tests { #[test] fn rates_preserve_fractional_and_sub_one_fps_intervals() { - let ntsc = rate(v4l::Fraction::new(1001, 30000)).unwrap(); + let ntsc = rate(moq_v4l::Fraction::new(1001, 30000)).unwrap(); assert_eq!(ntsc.numerator(), 30000); assert_eq!(ntsc.rounded(), 30); assert_eq!(ntsc.denominator(), 1001); - let slow = rate(v4l::Fraction::new(2, 1)).unwrap(); + let slow = rate(moq_v4l::Fraction::new(2, 1)).unwrap(); assert_eq!(slow.numerator(), 1); assert_eq!(slow.rounded(), 1); assert_eq!(slow.denominator(), 2); assert!(slow < ntsc); - assert!(rate(v4l::Fraction::new(0, 30)).is_err()); - assert!(rate(v4l::Fraction::new(1, 0)).is_err()); + assert!(rate(moq_v4l::Fraction::new(0, 30)).is_err()); + assert!(rate(moq_v4l::Fraction::new(1, 0)).is_err()); } #[test] fn equivalent_rates_deduplicate_and_sort_numerically() { let rates: BTreeSet<_> = [(1001, 30000), (1, 30), (2, 60), (2, 1)] .into_iter() - .map(|(n, d)| rate(v4l::Fraction::new(n, d)).unwrap()) + .map(|(n, d)| rate(moq_v4l::Fraction::new(n, d)).unwrap()) .collect(); assert_eq!(rates.len(), 3); - assert_eq!(*rates.last().unwrap(), rate(v4l::Fraction::new(1, 30)).unwrap()); - assert_eq!(*rates.first().unwrap(), rate(v4l::Fraction::new(2, 1)).unwrap()); + assert_eq!(*rates.last().unwrap(), rate(moq_v4l::Fraction::new(1, 30)).unwrap()); + assert_eq!(*rates.first().unwrap(), rate(moq_v4l::Fraction::new(2, 1)).unwrap()); } #[test] @@ -657,7 +657,7 @@ mod tests { let (_, source, accepted) = negotiate_with("camera", want, |format| { formats.push(format.fourcc); let fps = if format.fourcc == Source::Yuyv.fourcc() { 30 } else { 60 }; - Ok((format, Some(rate(v4l::Fraction::new(1, fps)).unwrap()))) + Ok((format, Some(rate(moq_v4l::Fraction::new(1, fps)).unwrap()))) }) .unwrap(); assert_eq!(source, Source::Mjpeg); @@ -670,8 +670,8 @@ mod tests { #[test] fn rate_scoring_preserves_fractional_precision_and_handles_unknown_rates() { - let ntsc = Some(rate(v4l::Fraction::new(1001, 60000)).unwrap()); - let thirty = Some(rate(v4l::Fraction::new(1, 30)).unwrap()); + let ntsc = Some(rate(moq_v4l::Fraction::new(1001, 60000)).unwrap()); + let thirty = Some(rate(moq_v4l::Fraction::new(1, 30)).unwrap()); assert!(rate_distance(ntsc, thirty, Some(Rate::new(60, 1).unwrap())).is_lt()); assert!(rate_distance(thirty, ntsc, Some(Rate::new(30, 1).unwrap())).is_lt()); assert!(rate_distance(ntsc, None, Some(Rate::new(60, 1).unwrap())).is_lt()); diff --git a/rs/moq-video/src/decode/backend/v4l2.rs b/rs/moq-video/src/decode/backend/v4l2.rs index b0d1d05699..9a76f27491 100644 --- a/rs/moq-video/src/decode/backend/v4l2.rs +++ b/rs/moq-video/src/decode/backend/v4l2.rs @@ -37,7 +37,7 @@ use std::time::{Duration, Instant}; use bytes::Bytes; use moq_net::Timestamp; -use v4l::v4l_sys::{V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, V4L2_DEC_CMD_START, V4L2_DEC_CMD_STOP}; +use moq_v4l::sys::{V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, V4L2_DEC_CMD_START, V4L2_DEC_CMD_STOP}; use super::{Backend, Codec, Config}; use crate::v4l2::{self, Dequeue, Device, Dir, Format, Planes, Queue, Rect, Request, Role}; diff --git a/rs/moq-video/src/encode/backend/v4l2.rs b/rs/moq-video/src/encode/backend/v4l2.rs index c62160ece8..d37d3b2e64 100644 --- a/rs/moq-video/src/encode/backend/v4l2.rs +++ b/rs/moq-video/src/encode/backend/v4l2.rs @@ -6,7 +6,7 @@ //! spends its CPU on openh264. //! //! Behind the opt-in `v4l2` feature. It costs no runtime dependency (the -//! interface is ioctls on a device node), only the `v4l` crate's build-time +//! interface is ioctls on a device node), only the `moq_v4l` crate's build-time //! bindgen, and a host with no M2M node fails at open so automatic selection //! falls through to the next encoder. //! @@ -39,7 +39,7 @@ use std::time::{Duration, Instant}; use bytes::{Bytes, BytesMut}; use moq_net::Timestamp; -use v4l::v4l_sys::{ +use moq_v4l::sys::{ V4L2_CID_MPEG_VIDEO_BITRATE, V4L2_CID_MPEG_VIDEO_BITRATE_MODE, V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, V4L2_CID_MPEG_VIDEO_GOP_SIZE, V4L2_CID_MPEG_VIDEO_H264_LEVEL, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_CID_MPEG_VIDEO_HEADER_MODE, V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR, V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, diff --git a/rs/moq-video/src/v4l2.rs b/rs/moq-video/src/v4l2.rs index 43db7d2f31..2fc92bbeb2 100644 --- a/rs/moq-video/src/v4l2.rs +++ b/rs/moq-video/src/v4l2.rs @@ -9,9 +9,9 @@ //! here, so the ioctl sequence, the buffer pool, and the plane arithmetic are //! written once. //! -//! Built on the raw layer of the `v4l` crate that the camera capture path -//! already uses: `v4l::v4l_sys` supplies the `videodev2.h` structs and -//! `v4l::v4l2::vidioc` the request codes, so nothing here hand-rolls a struct +//! Built on the raw layer of the `moq_v4l` crate that the camera capture path +//! already uses: `moq_v4l::sys` supplies the `videodev2.h` structs and +//! `moq_v4l::v4l2::vidioc` the request codes, so nothing here hand-rolls a struct //! offset. //! //! The driver, not the caller, decides the raw layout. `VIDIOC_S_FMT` is a @@ -28,7 +28,7 @@ use std::path::{Path, PathBuf}; use std::ptr::NonNull; use std::time::Duration; -use v4l::v4l_sys::{ +use moq_v4l::sys::{ V4L2_BUF_FLAG_ERROR, V4L2_BUF_FLAG_LAST, V4L2_CAP_DEVICE_CAPS, V4L2_CAP_STREAMING, V4L2_CAP_VIDEO_M2M, V4L2_CAP_VIDEO_M2M_MPLANE, V4L2_CTRL_FLAG_DISABLED, V4L2_EVENT_SOURCE_CHANGE, V4L2_SEL_TGT_COMPOSE, timeval, v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, v4l2_buf_type_V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, v4l2_buffer, @@ -39,7 +39,7 @@ use v4l::v4l_sys::{ v4l2_streamparm, v4l2_xfer_func_V4L2_XFER_FUNC_709, v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_601, v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_709, }; -use v4l::v4l2::vidioc; +use moq_v4l::v4l2::vidioc; use crate::frame::I420; use crate::{Color, Error, Size}; @@ -73,51 +73,6 @@ pub(crate) const RAW: &[u32] = &[NV12, NV12M, YUV420, YUV420M]; /// Planes a format may use here: Y, U, and V. const MAX_PLANES: usize = 3; -/// Requests the `v4l` crate does not export, built the way -/// `linux/ioctl.h` builds them. The shifts are `asm-generic`'s, which is what -/// `v4l`'s own table already assumes. -mod request { - use v4l::v4l_sys::{v4l2_decoder_cmd, v4l2_event, v4l2_event_subscription, v4l2_selection}; - use v4l::v4l2::vidioc::_IOC_TYPE; - - const READ: u32 = 2; - const WRITE: u32 = 1; - - const fn code(dir: u32, nr: u32, size: usize) -> _IOC_TYPE { - ((dir as _IOC_TYPE) << 30) | ((size as _IOC_TYPE) << 16) | ((b'V' as _IOC_TYPE) << 8) | nr as _IOC_TYPE - } - - pub(super) const DQEVENT: _IOC_TYPE = code(READ, 89, size_of::()); - pub(super) const SUBSCRIBE_EVENT: _IOC_TYPE = code(WRITE, 90, size_of::()); - pub(super) const G_SELECTION: _IOC_TYPE = code(READ | WRITE, 94, size_of::()); - pub(super) const DECODER_CMD: _IOC_TYPE = code(READ | WRITE, 96, size_of::()); - - #[cfg(test)] - mod tests { - use v4l::v4l_sys::{v4l2_capability, v4l2_format}; - use v4l::v4l2::vidioc; - - use super::*; - - /// The codes above have to come out the way `linux/ioctl.h` builds - /// the rest, and nothing else here would notice if they did not: a wrong - /// code is `ENOTTY` at runtime on whichever board reaches it first. - /// - /// Checked against requests the `v4l` crate does export, one per direction, - /// so the shifts, the direction bits, and the struct size all have to agree - /// on whatever target this compiles for. - #[test] - fn the_codes_are_built_the_way_the_crate_builds_its_own() { - assert_eq!(code(READ, 0, size_of::()), vidioc::VIDIOC_QUERYCAP); - assert_eq!(code(WRITE, 18, size_of::()), vidioc::VIDIOC_STREAMON); - assert_eq!(code(READ | WRITE, 5, size_of::()), vidioc::VIDIOC_S_FMT); - // `v4l` 0.14 omits this newer request. This is the value from - // `videodev2.h`, and also checks the generated command struct's ABI size. - assert_eq!(DECODER_CMD, 0xc048_5660); - } - } -} - /// A `videodev2.h` struct an ioctl reads or fills. /// /// # Safety @@ -234,8 +189,8 @@ pub(crate) fn open(role: &Role) -> Result { return Ok(device); } - let mut nodes = v4l::context::enum_devices(); - nodes.sort_by_key(v4l::context::Node::index); + let mut nodes = moq_v4l::context::enum_devices(); + nodes.sort_by_key(moq_v4l::context::Node::index); let mut refused = Vec::new(); for node in nodes { @@ -340,7 +295,7 @@ impl Device { unsafe fn ioctl(&self, request: vidioc::_IOC_TYPE, arg: &mut T) -> std::io::Result<()> { // SAFETY: the caller guarantees `arg` matches `request`, and the pointer // stays valid for the call, which is the only thing the kernel needs. - unsafe { v4l::v4l2::ioctl(self.file.as_raw_fd(), request, (arg as *mut T).cast()) } + unsafe { moq_v4l::v4l2::ioctl(self.file.as_raw_fd(), request, (arg as *mut T).cast()) } } /// Wrap an ioctl failure with the node and the operation that failed. @@ -489,7 +444,7 @@ impl Device { selection.type_ = dir.buf_type(); selection.target = V4L2_SEL_TGT_COMPOSE; // SAFETY: `VIDIOC_G_SELECTION` takes a `v4l2_selection`. - unsafe { self.ioctl(request::G_SELECTION, &mut selection) }.ok()?; + unsafe { self.ioctl(vidioc::VIDIOC_G_SELECTION, &mut selection) }.ok()?; let rect = Rect { left: selection.r.left.max(0) as u32, @@ -508,7 +463,7 @@ impl Device { let mut subscription = v4l2_event_subscription::zeroed(); subscription.type_ = V4L2_EVENT_SOURCE_CHANGE; // SAFETY: `VIDIOC_SUBSCRIBE_EVENT` takes a `v4l2_event_subscription`. - unsafe { self.ioctl(request::SUBSCRIBE_EVENT, &mut subscription) } + unsafe { self.ioctl(vidioc::VIDIOC_SUBSCRIBE_EVENT, &mut subscription) } .map_err(|err| self.err("SUBSCRIBE_EVENT", err)) } @@ -521,7 +476,7 @@ impl Device { loop { let mut event = v4l2_event::zeroed(); // SAFETY: `VIDIOC_DQEVENT` takes a `v4l2_event`. - if unsafe { self.ioctl(request::DQEVENT, &mut event) }.is_err() { + if unsafe { self.ioctl(vidioc::VIDIOC_DQEVENT, &mut event) }.is_err() { return changed; } changed |= event.type_ == V4L2_EVENT_SOURCE_CHANGE; @@ -581,7 +536,7 @@ impl Device { let mut command = v4l2_decoder_cmd::zeroed(); command.cmd = cmd; // SAFETY: `VIDIOC_DECODER_CMD` takes a `v4l2_decoder_cmd`. - unsafe { self.ioctl(request::DECODER_CMD, &mut command) } + unsafe { self.ioctl(vidioc::VIDIOC_DECODER_CMD, &mut command) } .map_err(|err| self.err(format_args!("DECODER_CMD {cmd}"), err)) } @@ -703,7 +658,7 @@ impl Drop for Mapping { fn drop(&mut self) { // SAFETY: the pointer and length are what `mmap` returned and this is the // only owner, so nothing can still be reading the region. - let _ = unsafe { v4l::v4l2::munmap(self.ptr.as_ptr().cast(), self.len) }; + let _ = unsafe { moq_v4l::v4l2::munmap(self.ptr.as_ptr().cast(), self.len) }; } } @@ -749,7 +704,7 @@ impl Queue { // this plane, on an mmap queue, so `m` holds `mem_offset`. The length // is the one it reported alongside. let ptr = unsafe { - v4l::v4l2::mmap( + moq_v4l::v4l2::mmap( std::ptr::null_mut(), len, libc::PROT_READ | libc::PROT_WRITE, From c15a8e890ff22d50cf614d7874f56490a37fd139 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 21 Sep 2026 14:57:52 -0700 Subject: [PATCH 3/8] fix(video): sort the moq-v4l dependency Co-Authored-By: Claude Opus 5 --- rs/moq-video/Cargo.toml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/rs/moq-video/Cargo.toml b/rs/moq-video/Cargo.toml index beaa4eb75d..62b77dbf6e 100644 --- a/rs/moq-video/Cargo.toml +++ b/rs/moq-video/Cargo.toml @@ -161,6 +161,14 @@ libloading = { workspace = true, optional = true } # Architecture-correct DMA_BUF_IOCTL_SYNC request values for CPU access. linux-raw-sys = { workspace = true, optional = true } moq-nvenc = { workspace = true, optional = true } +# Native V4L2 webcam capture and, behind the `v4l2` feature, the M2M hardware +# codecs. An in-tree fork of `v4l` (see rs/moq-v4l) with the videodev2.h +# bindings checked in, so the build needs no libclang or kernel headers. It +# streams MMAP buffers; MJPEG cameras are decoded with the pure-Rust `zune-jpeg` +# (no libjpeg/IJG). The codec backends use its raw layer (`moq_v4l::sys` for the +# videodev2.h structs, `moq_v4l::v4l2::vidioc` for the request codes) rather +# than a second V4L2 crate, so no ioctl struct is hand-rolled. +moq-v4l = { workspace = true, optional = true } # Intel/AMD VAAPI hardware H.264 encoder and decoder, behind the opt-in `vaapi` # feature. As of moq-vaapi 0.0.3 libva is dlopen'd at runtime, so the binary carries # no NEEDED libva: the build needs no libva-dev (its build script's bindgen still @@ -171,14 +179,6 @@ moq-vaapi = { workspace = true, optional = true } # PipeWire video stream for the portal's node, behind the `pipewire` feature. # Links libpipewire-0.3 via pkg-config at build time; bindgen needs libclang. pipewire = { version = "0.10", optional = true } -# Native V4L2 webcam capture and, behind the `v4l2` feature, the M2M hardware -# codecs. An in-tree fork of `v4l` (see rs/moq-v4l) with the videodev2.h -# bindings checked in, so the build needs no libclang or kernel headers. It -# streams MMAP buffers; MJPEG cameras are decoded with the pure-Rust `zune-jpeg` -# (no libjpeg/IJG). The codec backends use its raw layer (`moq_v4l::sys` for the -# videodev2.h structs, `moq_v4l::v4l2::vidioc` for the request codes) rather -# than a second V4L2 crate, so no ioctl struct is hand-rolled. -moq-v4l = { workspace = true, optional = true } # X11 display/window enumeration and capture. Pure Rust and used when no # Wayland session is active, so Linux screen capture still works without a # portal and callers can select a stable monitor or window id. From 2630f4acc001f3cbbfb9d5392e650d40d3fd5b92 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 21 Sep 2026 14:58:24 -0700 Subject: [PATCH 4/8] fix: sort the moq-v4l workspace dependency Co-Authored-By: Claude Opus 5 --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 8476ae0de1..eaff3f0ab6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -150,7 +150,6 @@ moq-noq-udp = "1.3" # driver at runtime. Compiles on any platform (macOS included) but only actually # used by moq-video on Linux. moq-nvenc = { version = "0.0.5", path = "rs/moq-nvenc" } -moq-v4l = { version = "0.0.1", path = "rs/moq-v4l" } moq-pattern = { version = "0.1.0", path = "rs/moq-pattern" } moq-relay = { version = "0.14.18", path = "rs/moq-relay", default-features = false } moq-rtc = { version = "0.2.11", path = "rs/moq-rtc" } @@ -169,6 +168,10 @@ moq-transcode = { version = "0.0.19", path = "rs/moq-transcode", default-feature # stack the io_uring path compiles; cargo features are additive, so a default-on # backend could not be opted out of. moq-uring = { version = "0.0.1", path = "rs/moq-uring", default-features = false } +# In-tree fork of `v4l` with the videodev2.h bindings checked in, so moq-video's +# `capture` and `v4l2` need no libclang or kernel headers. Linux only; an empty +# stub elsewhere. +moq-v4l = { version = "0.0.1", path = "rs/moq-v4l" } # Standalone crate (moq-dev/vaapi); vendored from cros-libva + cros-codecs. # dlopen's libva at runtime (no libva-dev at build, no NEEDED libva in the binary). moq-vaapi = "0.0.4" From 8a6eedd4bf7547ab2abf3d8b263ec1611c4c1616 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 21 Sep 2026 15:48:19 -0700 Subject: [PATCH 5/8] style: shfmt the bindgen script Co-Authored-By: Claude Opus 5 --- rs/moq-v4l/src/sys/bindgen.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/rs/moq-v4l/src/sys/bindgen.sh b/rs/moq-v4l/src/sys/bindgen.sh index d7773e3950..e5196d4a9c 100755 --- a/rs/moq-v4l/src/sys/bindgen.sh +++ b/rs/moq-v4l/src/sys/bindgen.sh @@ -4,12 +4,12 @@ # the output is arch-independent, so any 64-bit host produces the same file. set -eu cd "$(dirname "$0")" -echo '#include ' > wrapper.h +echo '#include ' >wrapper.h trap 'rm -f wrapper.h' EXIT bindgen wrapper.h \ - --no-layout-tests \ - --allowlist-type 'v4l2.*' \ - --allowlist-var 'V4L2_.*' \ - --blocklist-type '(timeval|timespec|__time_t|__suseconds_t|__syscall_slong_t)' \ - --raw-line 'pub use libc::{timespec, timeval};' \ - -o videodev2.rs + --no-layout-tests \ + --allowlist-type 'v4l2.*' \ + --allowlist-var 'V4L2_.*' \ + --blocklist-type '(timeval|timespec|__time_t|__suseconds_t|__syscall_slong_t)' \ + --raw-line 'pub use libc::{timespec, timeval};' \ + -o videodev2.rs From 00793ea2540173dcf60c79cd2ef5d851b4c46fa5 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 22 Sep 2026 06:41:43 -0700 Subject: [PATCH 6/8] docs(video): drop the libclang claims the fork retires moq-video's README still said `capture` pulls V4L2 and libclang build dependencies, and moq-v4l's crate docs pointed at examples the fork does not carry. Co-Authored-By: Claude Opus 5 --- rs/moq-v4l/src/lib.rs | 1 - rs/moq-video/README.md | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/rs/moq-v4l/src/lib.rs b/rs/moq-v4l/src/lib.rs index 7a3acf1361..5ee8f20d6d 100644 --- a/rs/moq-v4l/src/lib.rs +++ b/rs/moq-v4l/src/lib.rs @@ -58,7 +58,6 @@ //!} //!``` //! -//! Have a look at the examples to learn more about device and buffer management. // Every call is a Linux ioctl, so elsewhere the crate is an empty stub and // moq-video only depends on it there. diff --git a/rs/moq-video/README.md b/rs/moq-video/README.md index 690bbab2fa..cc2ae3d1d3 100644 --- a/rs/moq-video/README.md +++ b/rs/moq-video/README.md @@ -14,8 +14,8 @@ swapping or bumping a backend crate is not a breaking change. The opt-in `capture` feature exposes the device APIs and their per-platform backends. Enable it with `cargo add moq-video --features capture`; the default -codec-only build accepts frames supplied by the caller without pulling Linux -V4L2 and libclang build dependencies. +codec-only build accepts frames supplied by the caller and compiles none of the +device backends. Nothing is needed on the build host either way. Per-platform, picked at compile time: @@ -102,10 +102,10 @@ Two public entry points: The default features are `openh264`, `nvidia`, and `mediacodec`. OpenH264 keeps a working software H.264 fallback but compiles vendored C++; disable defaults and select native features to omit it. `nvidia` is Linux-only, `dlopen`s the -driver at runtime, and needs no build-time toolkit. `vaapi` and `v4l2` are -opt-in because their bindgen needs libclang on the build host (plus kernel -headers for `v4l2`). `render` is also opt-in so codec-only consumers do not -compile wgpu. +driver at runtime, and needs no build-time toolkit. `vaapi` is opt-in because +its bindgen needs libclang on the build host, while `v4l2` is opt-in only by +convention, since `moq-v4l` checks its bindings in. `render` is also opt-in so +codec-only consumers do not compile wgpu. ### Vulkan producers on NVIDIA From 8f4a0e6f3917c41b4bca07c57a51696a1f4051ce Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 22 Sep 2026 06:53:33 -0700 Subject: [PATCH 7/8] docs(video): the module docs stop charging capture for bindgen Three comments still described the build cost the fork removes, and one still named the `v4l` crate's helpers. Co-Authored-By: Claude Opus 5 --- rs/moq-video/src/capture/v4l2.rs | 2 +- rs/moq-video/src/encode/backend/v4l2.rs | 8 ++++---- rs/moq-video/src/lib.rs | 3 +-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/rs/moq-video/src/capture/v4l2.rs b/rs/moq-video/src/capture/v4l2.rs index e43f348d96..128c6016b4 100644 --- a/rs/moq-video/src/capture/v4l2.rs +++ b/rs/moq-video/src/capture/v4l2.rs @@ -159,7 +159,7 @@ fn bounds(min: u32, max: u32, step: u32) -> Option<(u32, u32)> { (first <= last).then_some((first, last)) } -// Read one entry at a time: v4l's collection helpers treat every error after +// Read one entry at a time: moq-v4l's collection helpers treat every error after // the first entry as end-of-list, hiding device failures and malformed replies. fn frame_sizes(device: &Device, fourcc: FourCC) -> Result, Error> { let mut sizes = Vec::new(); diff --git a/rs/moq-video/src/encode/backend/v4l2.rs b/rs/moq-video/src/encode/backend/v4l2.rs index d37d3b2e64..2084822760 100644 --- a/rs/moq-video/src/encode/backend/v4l2.rs +++ b/rs/moq-video/src/encode/backend/v4l2.rs @@ -5,10 +5,10 @@ //! Without it a Pi either republishes what `rpicam-vid` already encoded or //! spends its CPU on openh264. //! -//! Behind the opt-in `v4l2` feature. It costs no runtime dependency (the -//! interface is ioctls on a device node), only the `moq_v4l` crate's build-time -//! bindgen, and a host with no M2M node fails at open so automatic selection -//! falls through to the next encoder. +//! Behind the opt-in `v4l2` feature. It costs nothing at build or run time (the +//! interface is ioctls on a device node and `moq_v4l` checks its bindings in), +//! and a host with no M2M node fails at open so automatic selection falls +//! through to the next encoder. //! //! Feeds the driver 8-bit 4:2:0 and takes back Annex-B with in-band SPS/PPS //! ahead of every IDR, which is the avc3 shape the H.264 importer expects. diff --git a/rs/moq-video/src/lib.rs b/rs/moq-video/src/lib.rs index 35c1807930..dcc98e206c 100644 --- a/rs/moq-video/src/lib.rs +++ b/rs/moq-video/src/lib.rs @@ -19,8 +19,7 @@ //! Windows, plus portal/PipeWire on Wayland and X11 capture on Linux. Use //! `capture::open` for an embeddable raw-frame stream or //! `encode::publish_capture` for turnkey publication. It requires the opt-in -//! `capture` feature: on Linux the camera path's bindgen needs libclang and -//! the V4L2 headers on the build host. +//! `capture` feature, which costs the build host nothing on any platform. //! - [`encode`] encodes frames with a native backend and publishes them through //! the matching `moq_mux::codec` importer, which handles catalog registration //! and framing. The codec is chosen via [`encode::Codec`]: H.264 (openh264 / From 836e6e0c0b5391ded4a9353e41a0626d9e341517 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Tue, 22 Sep 2026 09:38:32 -0700 Subject: [PATCH 8/8] fix(video): pin the vidioc codes per pointer width Co-authored-by: MiMo-V2.6-Flash --- rs/moq-v4l/src/v4l2/vidioc.rs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/rs/moq-v4l/src/v4l2/vidioc.rs b/rs/moq-v4l/src/v4l2/vidioc.rs index 7a53abe5ef..6699afbcb3 100644 --- a/rs/moq-v4l/src/v4l2/vidioc.rs +++ b/rs/moq-v4l/src/v4l2/vidioc.rs @@ -155,17 +155,30 @@ pub const VIDIOC_REMOVE_BUFS: _IOC_TYPE = _IOWR!(b'V', 104, v4l2_remove_buffers) mod tests { use super::*; - /// The values `videodev2.h` expands to on a 64-bit host. A wrong code is - /// `ENOTTY` at runtime on whichever board reaches it first, so the shifts, - /// the direction bits, and the generated struct sizes are pinned here. + /// The values `videodev2.h` expands to. A wrong code is `ENOTTY` at + /// runtime on whichever board reaches it first, so the shifts, the + /// direction bits, and the generated struct sizes are pinned here. #[test] fn codes_match_the_header() { - assert_eq!(VIDIOC_QUERYCAP, 0x8068_5600); - assert_eq!(VIDIOC_S_FMT, 0xc0d0_5605); - assert_eq!(VIDIOC_STREAMON, 0x4004_5612); - assert_eq!(VIDIOC_DQEVENT, 0x8088_5659); - assert_eq!(VIDIOC_SUBSCRIBE_EVENT, 0x4020_565a); - assert_eq!(VIDIOC_G_SELECTION, 0xc040_565e); - assert_eq!(VIDIOC_DECODER_CMD, 0xc048_5660); + // The codes are `c_ulong` (`c_int` on musl), so compare as `u32`. + assert_eq!(VIDIOC_QUERYCAP as u32, 0x8068_5600); + // `v4l2_window` drops pointer padding: a 208-byte format shrinks to 204. + #[cfg(target_pointer_width = "64")] + assert_eq!(VIDIOC_S_FMT as u32, 0xc0d0_5605); + #[cfg(target_pointer_width = "32")] + assert_eq!(VIDIOC_S_FMT as u32, 0xc0cc_5605); + assert_eq!(VIDIOC_STREAMON as u32, 0x4004_5612); + // `timespec` shrinks 16 -> 8 on ILP32 and `value64` blocks to the ABI's + // `u64` alignment: a 136-byte event becomes 128 (align 8, e.g. arm) or + // 120 (align 4, e.g. x86). + #[cfg(target_pointer_width = "64")] + assert_eq!(VIDIOC_DQEVENT as u32, 0x8088_5659); + #[cfg(all(target_pointer_width = "32", target_arch = "x86"))] + assert_eq!(VIDIOC_DQEVENT as u32, 0x8078_5659); + #[cfg(all(target_pointer_width = "32", not(target_arch = "x86")))] + assert_eq!(VIDIOC_DQEVENT as u32, 0x8080_5659); + assert_eq!(VIDIOC_SUBSCRIBE_EVENT as u32, 0x4020_565a); + assert_eq!(VIDIOC_G_SELECTION as u32, 0xc040_565e); + assert_eq!(VIDIOC_DECODER_CMD as u32, 0xc048_5660); } }