diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 55332c4..095e0e0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,7 @@ jobs: name: Build and test strategy: matrix: - libcamera_version: ["v0.4.0", "v0.5.0", "v0.5.1"] + libcamera_version: ["v0.4.0", "v0.5.0", "v0.5.1", "v0.5.2", "v0.6.0"] runs-on: ubuntu-latest steps: - name: Checkout diff --git a/Cargo.lock b/Cargo.lock index dda03c2..d2556aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -301,7 +301,7 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libcamera" -version = "0.4.0" +version = "0.6.0" dependencies = [ "bitflags", "drm-fourcc", @@ -312,6 +312,7 @@ dependencies = [ "semver", "smallvec", "thiserror", + "tokio", ] [[package]] @@ -321,6 +322,7 @@ dependencies = [ "git2", "indoc", "prettyplease", + "regex", "semver", "syn", "yaml-rust", @@ -328,7 +330,7 @@ dependencies = [ [[package]] name = "libcamera-sys" -version = "0.5.0" +version = "0.6.0" dependencies = [ "bindgen", "cc", @@ -476,6 +478,12 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + [[package]] name = "pkg-config" version = "0.3.32" @@ -666,6 +674,27 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tokio" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +dependencies = [ + "pin-project-lite", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "toml_datetime" version = "0.6.9" diff --git a/README.md b/README.md index 247fab3..5bb7a8b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ Project structure: - [libcamera-meta](./libcamera-meta/) - Scripts for generating C and Rust code from libcamera controls, properties and formats YAMLs. Mostly used by the [regenerate.sh](./regenerate.sh) script. - [libcamera](./libcamera/) - Safe libcamera Rust interface on top of `libcamera-sys`. +Code generation uses a cached clone under `libcamera-git`; run `cargo run --bin generate_from_git` (or `./regenerate.sh`) occasionally to fetch the latest upstream tags before regenerating `versioned_files`. These bindings intentionally track libcamera’s public, application-facing API; pipeline-handler internals aren’t surfaced. + Unreleased documentation for `main`: [here](https://lit-robotics.github.io/libcamera-rs/libcamera/index.html) ## Building @@ -133,6 +135,21 @@ FrameBuffer metadata: Immutable( Written 4147789 bytes to target/image.jpg ``` +Inspect generated pixel format constants and layout info ([code](./libcamera/examples/formats_constants.rs)): +```console +$ cargo run --example formats_constants +Using constant formats::NV12 => NV12 (NV12) +bits_per_pixel=12 planes=2 pixels_per_group=2 +frame size for 640x480 (align=0): 460800 bytes +``` + +Apply a generated pixel format constant to a stream configuration ([code](./libcamera/examples/configure_formats.rs)): +```console +$ cargo run --example configure_formats +validate status: Valid +configured: StreamConfigurationRef { pixel_format: NV12, size: Size { width: 640, height: 480 }, stride: 640, frame_size: 460800, buffer_count: 4, color_space: None }, stride=640 frame_size=460800 +``` + ## Notes on safety `libcamera-rs` is intended to be a fully memory-safe wrapper, however, due to `libcamera`'s complexity and many cross-references between objects it is quite hard to ensure total safety so there is very likely to be bugs. Issues and pull requests are welcome. diff --git a/docker/ci/Dockerfile b/docker/ci/Dockerfile new file mode 100644 index 0000000..d60ea1c --- /dev/null +++ b/docker/ci/Dockerfile @@ -0,0 +1,44 @@ +# Minimal CI runner image that matches the GitHub Actions workflow. +# Build per libcamera version: +# docker build -f docker/ci/Dockerfile --build-arg LIBCAMERA_VERSION=v0.5.1 -t libcamera-ci:v0.5.1 . +# +# Then run against your workspace: +# docker run --rm -v "$PWD:/workspace" -w /workspace libcamera-ci:v0.5.1 ./docker/ci/entrypoint.sh + +ARG UBUNTU_VERSION=22.04 +FROM ubuntu:${UBUNTU_VERSION} + +ARG LIBCAMERA_VERSION=v0.6.0 +ENV DEBIAN_FRONTEND=noninteractive + +# Install build prerequisites for libcamera and Rust. +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + build-essential git ninja-build pkg-config clang \ + python3 python3-pip python3-jinja2 python3-yaml python3-ply \ + libyaml-dev libssl-dev curl ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +# Meson from apt on 22.04 is too old for older libcamera tags; upgrade via pip. +RUN pip3 install --no-cache-dir --upgrade pip meson + +# Install libcamera (matching the workflow: only vimc pipeline for speed). +RUN git clone --depth 1 --branch ${LIBCAMERA_VERSION} https://git.libcamera.org/libcamera/libcamera.git /tmp/libcamera && \ + cd /tmp/libcamera && \ + meson build -Dipas=vimc -Dpipelines=vimc && \ + ninja -C build install && \ + rm -rf /tmp/libcamera + +# Install Rust toolchain (stable) with rustfmt/clippy. +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ + | sh -s -- -y --profile minimal --component rustfmt,clippy && \ + . "$HOME/.cargo/env" && \ + rustc --version && cargo --version + +ENV PATH="/root/.cargo/bin:${PATH}" +# Ensure pkg-config can find the installed libcamera. +ENV PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:/usr/local/lib/x86_64-linux-gnu/pkgconfig:${PKG_CONFIG_PATH}" + +WORKDIR /workspace +COPY docker/ci/entrypoint.sh /usr/local/bin/entrypoint.sh +ENTRYPOINT ["/usr/local/bin/entrypoint.sh"] diff --git a/docker/ci/entrypoint.sh b/docker/ci/entrypoint.sh new file mode 100755 index 0000000..a78da3d --- /dev/null +++ b/docker/ci/entrypoint.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Allow skipping doc build for speed/debugging. +: "${RUN_DOCS:=true}" + +LIBCAMERA_VERSION=$(pkg-config --modversion libcamera || true) +echo "Using libcamera from pkg-config: ${LIBCAMERA_VERSION}" + +# Keep build artifacts separate per libcamera version to avoid cross-version cache issues. +if [ -z "${CARGO_TARGET_DIR:-}" ] && [ -n "${LIBCAMERA_VERSION}" ]; then + export CARGO_TARGET_DIR="target/${LIBCAMERA_VERSION}" +fi +echo "Using CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-target}" + +cargo build +cargo fmt --all -- --check +cargo test +cargo clippy --no-deps -- -D warnings + +if [ "$RUN_DOCS" = "true" ]; then + RUSTDOCFLAGS="-Dwarnings" cargo doc --no-deps --lib +fi diff --git a/docker/ci/run-local.sh b/docker/ci/run-local.sh new file mode 100755 index 0000000..765333b --- /dev/null +++ b/docker/ci/run-local.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run the CI steps locally for each libcamera version (same matrix as GitHub Actions). +VERSIONS=( + v0.4.0 + v0.5.0 + v0.5.1 + v0.5.2 + v0.6.0 +) + +for ver in "${VERSIONS[@]}"; do + echo "=== Building CI image for libcamera ${ver} ===" + docker build -f docker/ci/Dockerfile --build-arg LIBCAMERA_VERSION="${ver}" -t "libcamera-ci:${ver}" . + echo "=== Running CI steps for libcamera ${ver} ===" + docker run --rm -v "$PWD:/workspace" -w /workspace "libcamera-ci:${ver}" ./docker/ci/entrypoint.sh +done diff --git a/libcamera-meta/Cargo.toml b/libcamera-meta/Cargo.toml index 87bf090..3da7e1a 100644 --- a/libcamera-meta/Cargo.toml +++ b/libcamera-meta/Cargo.toml @@ -11,3 +11,4 @@ prettyplease = "0.2.17" semver = "1.0.22" syn = "2.0.58" yaml-rust = "0.4" +regex = "1" diff --git a/libcamera-meta/src/bin/generate_from_git.rs b/libcamera-meta/src/bin/generate_from_git.rs index 10ff0c4..7c38aee 100644 --- a/libcamera-meta/src/bin/generate_from_git.rs +++ b/libcamera-meta/src/bin/generate_from_git.rs @@ -1,7 +1,12 @@ -use std::{collections::BTreeMap, path::Path}; +use std::{ + collections::{BTreeMap, HashMap}, + fmt::Write, + path::Path, +}; use git2::{build::CheckoutBuilder, ObjectType, Repository}; use libcamera_meta::{ControlEnumValue, ControlSize, ControlType}; +use regex::Regex; use semver::Version; use yaml_rust::{Yaml, YamlLoader}; @@ -10,6 +15,8 @@ use crate::generate_rust::ControlsType; struct ByVersionData { pub controls: BTreeMap, pub properties: BTreeMap, + pub formats_yaml: String, + pub formats_cpp: String, } #[derive(Debug)] @@ -23,6 +30,26 @@ pub struct Control { pub enumeration: Option>, } +#[derive(Debug, Clone)] +struct FormatConst { + name: String, + fourcc: u32, + modifier: u64, +} + +#[derive(Debug, Clone)] +struct PixelFormatInfo { + name: String, + fourcc: u32, + modifier: u64, + bits_per_pixel: u32, + colour_encoding: u8, + packed: bool, + pixels_per_group: u32, + planes: Vec<(u32, u32)>, + v4l2_formats: Vec, +} + fn main() { let versioned_files = Path::new("libcamera/versioned_files"); let _ = std::fs::remove_dir_all(versioned_files); @@ -114,8 +141,19 @@ fn main() { }; let controls = extract_controls("control_ids"); let properties = extract_controls("property_ids"); - - by_version.insert(version, ByVersionData { controls, properties }); + let formats_yaml = + std::fs::read_to_string(git_dir.join("src/libcamera/formats.yaml")).expect("read formats.yaml"); + let formats_cpp = std::fs::read_to_string(git_dir.join("src/libcamera/formats.cpp")).expect("read formats.cpp"); + + by_version.insert( + version, + ByVersionData { + controls, + properties, + formats_yaml, + formats_cpp, + }, + ); true }) @@ -189,6 +227,321 @@ fn main() { controls } + fn parse_format_consts( + formats_yaml: &str, + drm_map: &HashMap, + modifier_map: &HashMap, + v4l2_map: &HashMap, + ) -> Vec { + let yaml = YamlLoader::load_from_str(formats_yaml).expect("parse formats.yaml"); + let mut out = Vec::new(); + for doc in yaml { + let Some(formats) = doc["formats"].as_vec() else { + continue; + }; + for entry in formats { + let map = entry.as_hash().unwrap(); + for (name_yaml, val) in map { + let name = name_yaml.as_str().unwrap().to_string(); + let fourcc_name = val["fourcc"].as_str().unwrap(); + let mut fourcc = drm_map + .get(fourcc_name) + .copied() + .or_else(|| { + let suffix = fourcc_name.trim_start_matches("DRM_FORMAT_"); + let v4l2_name = format!("V4L2_PIX_FMT_{suffix}"); + v4l2_map.get(&v4l2_name).copied() + }) + .unwrap_or_else(|| { + let suffix = fourcc_name.trim_start_matches("DRM_FORMAT_"); + let v4l2_name = format!("V4L2_PIX_FMT_{suffix}"); + panic!("missing DRM fourcc for {fourcc_name} (also tried {v4l2_name})") + }); + if val["big_endian"].as_bool().unwrap_or(false) { + fourcc |= 1u32 << 31; + } + let modifier = val["modifier"] + .as_str() + .and_then(|m| modifier_map.get(m).copied()) + .unwrap_or(0); + out.push(FormatConst { name, fourcc, modifier }); + } + } + } + out + } + + fn build_drm_fourcc_map() -> HashMap { + let drm_path = "/usr/include/drm/drm_fourcc.h"; + match std::fs::read_to_string(drm_path) { + Ok(header) => { + let drm_re = + Regex::new(r"#define\s+(DRM_FORMAT_[A-Za-z0-9_]+)\s+fourcc_code(_be)?\(([^)]+)\)").unwrap(); + let mut map = HashMap::new(); + for caps in drm_re.captures_iter(&header) { + let name = caps.get(1).unwrap().as_str().to_string(); + let be = caps.get(2).is_some(); + let args = caps.get(3).unwrap().as_str(); + let parts: Vec = args + .split(',') + .filter_map(|p| p.trim().trim_matches('\'').chars().next().map(|c| c as u32)) + .collect(); + if parts.len() != 4 { + continue; + } + let mut fourcc = parts[0] | (parts[1] << 8) | (parts[2] << 16) | (parts[3] << 24); + if be { + fourcc |= 1u32 << 31; + } + map.insert(name, fourcc); + } + map + } + Err(err) => { + eprintln!("Warning: failed to read {drm_path}: {err}"); + HashMap::new() + } + } + } + + fn build_drm_modifier_map() -> HashMap { + let drm_path = "/usr/include/drm/drm_fourcc.h"; + let mut map = HashMap::new(); + let Ok(header) = std::fs::read_to_string(drm_path) else { + eprintln!("Warning: failed to read {drm_path} for modifiers"); + return map; + }; + const VENDOR_RE: &str = r"#define\s+DRM_FORMAT_MOD_VENDOR_([A-Za-z0-9_]+)\s+([0-9xXa-fA-F]+)"; + const MOD_RE: &str = concat!( + r"#define\s+DRM_FORMAT_MOD_([A-Za-z0-9_]+)\s+fourcc_mod_code\(", + r"\s*([A-Za-z0-9_]+)\s*,\s*([0-9xXa-fA-F]+)\s*\)", + ); + let vendor_re = Regex::new(VENDOR_RE).unwrap(); + let mod_re = Regex::new(MOD_RE).unwrap(); + let mut vendors = HashMap::new(); + for caps in vendor_re.captures_iter(&header) { + let name = caps.get(1).unwrap().as_str().to_string(); + let val_str = caps.get(2).unwrap().as_str(); + let val = u64::from_str_radix(val_str.trim_start_matches("0x"), 16).unwrap_or(0); + vendors.insert(name, val); + } + for caps in mod_re.captures_iter(&header) { + let name = caps.get(1).unwrap().as_str().to_string(); + let vendor = caps.get(2).unwrap().as_str(); + let val_str = caps.get(3).unwrap().as_str(); + let val = u64::from_str_radix(val_str.trim_start_matches("0x"), 16).unwrap_or(0); + let vendor_val = vendors.get(vendor).copied().unwrap_or(0); + let modifier = (vendor_val << 56) | val; + map.insert(format!("DRM_FORMAT_MOD_{name}"), modifier); + } + map + } + + fn build_v4l2_fourcc_map() -> HashMap { + let videodev_path = "/usr/include/linux/videodev2.h"; + match std::fs::read_to_string(videodev_path) { + Ok(header) => { + let v4l2_re = + Regex::new(r"#define\s+(V4L2_PIX_FMT_[A-Za-z0-9_]+)\s+v4l2_fourcc(_be)?\(([^)]+)\)").unwrap(); + let mut map = HashMap::new(); + for caps in v4l2_re.captures_iter(&header) { + let name = caps.get(1).unwrap().as_str().to_string(); + let be = caps.get(2).is_some(); + let args = caps.get(3).unwrap().as_str(); + let parts: Vec = args + .split(',') + .filter_map(|p| p.trim().trim_matches('\'').chars().next().map(|c| c as u32)) + .collect(); + if parts.len() != 4 { + continue; + } + let mut fourcc = parts[0] | (parts[1] << 8) | (parts[2] << 16) | (parts[3] << 24); + if be { + fourcc |= 1u32 << 31; + } + map.insert(name, fourcc); + } + map + } + Err(err) => { + eprintln!("Warning: failed to read {videodev_path}: {err}"); + HashMap::new() + } + } + } + + fn parse_pixel_format_info( + formats_cpp: &str, + format_consts: &[FormatConst], + v4l2_map: &HashMap, + ) -> Vec { + let entry_re = + Regex::new(r"(?s)\{\s*formats::(?P\w+),\s*\{\s*(?P.*?)\}\s*\}\s*,").expect("regex compile"); + let bits_re = Regex::new(r"\.bitsPerPixel\s*=\s*([0-9]+)").unwrap(); + let colour_re = Regex::new(r"ColourEncoding([A-Za-z]+)").unwrap(); + let packed_re = Regex::new(r"\.packed\s*=\s*(true|false)").unwrap(); + let ppg_re = Regex::new(r"\.pixelsPerGroup\s*=\s*([0-9]+)").unwrap(); + const PLANES_RE: &str = concat!( + r"\.planes\s*=\s*\{\{\s*\{\s*([0-9]+)\s*,\s*([0-9]+)\s*\}\s*,", + r"\s*\{\s*([0-9]+)\s*,\s*([0-9]+)\s*\}\s*,", + r"\s*\{\s*([0-9]+)\s*,\s*([0-9]+)\s*\}\s*\}\s*\}", + ); + let planes_re = Regex::new(PLANES_RE).unwrap(); + let v4l2_list_re = Regex::new(r"\.v4l2Formats\s*=\s*\{(?P[^}]*)\}").unwrap(); + let v4l2_item_re = Regex::new(r"V4L2PixelFormat\(\s*(V4L2_PIX_FMT_[A-Za-z0-9_]+)\s*\)").unwrap(); + + let const_map: HashMap<_, _> = format_consts + .iter() + .map(|c| (c.name.clone(), (c.fourcc, c.modifier))) + .collect(); + + let mut entries = Vec::new(); + for caps in entry_re.captures_iter(formats_cpp) { + let name = caps["name"].to_string(); + let body = &caps["body"]; + let (fourcc, modifier) = match const_map.get(&name) { + Some(v) => *v, + None => continue, + }; + let bits_per_pixel = bits_re + .captures(body) + .and_then(|c| c.get(1)) + .and_then(|m| m.as_str().parse::().ok()) + .unwrap_or(0); + let colour_encoding = colour_re + .captures(body) + .and_then(|c| c.get(1)) + .map(|m| m.as_str()) + .unwrap_or("RGB"); + let colour_encoding = match colour_encoding { + "RGB" => 0u8, + "YUV" => 1u8, + "RAW" => 2u8, + _ => 0u8, + }; + let packed = packed_re + .captures(body) + .and_then(|c| c.get(1)) + .map(|m| m.as_str() == "true") + .unwrap_or(false); + let pixels_per_group = ppg_re + .captures(body) + .and_then(|c| c.get(1)) + .and_then(|m| m.as_str().parse::().ok()) + .unwrap_or(1); + let planes_caps = planes_re.captures(body); + let plane_vals: Vec<(u32, u32)> = planes_caps + .map(|p| { + (1..=6) + .filter_map(|idx| p.get(idx).and_then(|m| m.as_str().parse::().ok())) + .collect::>() + }) + .unwrap_or_else(|| vec![0; 6]) + .chunks(2) + .map(|c| (c.first().copied().unwrap_or(0), c.get(1).copied().unwrap_or(0))) + .collect(); + + let mut v4l2_formats: Vec = Vec::new(); + if let Some(list_caps) = v4l2_list_re.captures(body) { + if let Some(list) = list_caps.name("formats") { + for item in v4l2_item_re.captures_iter(list.as_str()) { + let name = item.get(1).unwrap().as_str(); + if let Some(val) = v4l2_map.get(name) { + v4l2_formats.push(*val); + } + } + } + } + + entries.push(PixelFormatInfo { + name, + fourcc, + modifier, + bits_per_pixel, + colour_encoding, + packed, + pixels_per_group, + planes: plane_vals, + v4l2_formats, + }); + } + + entries + } + + fn generate_pixel_format_info_rs(infos: &[PixelFormatInfo]) -> String { + let mut out = String::from( + r#" +// Auto-generated from libcamera/src/libcamera/formats.cpp +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatPlaneInfoData { + pub bytes_per_group: u32, + pub vertical_sub_sampling: u32, +} + +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatInfoData { + pub name: &'static str, + pub fourcc: u32, + pub modifier: u64, + pub bits_per_pixel: u32, + pub colour_encoding: u8, + pub packed: bool, + pub pixels_per_group: u32, + pub planes: &'static [PixelFormatPlaneInfoData], + pub v4l2_formats: &'static [u32], +} + +pub(crate) static PIXEL_FORMAT_INFO: &[PixelFormatInfoData] = &[ +"#, + ); + + for info in infos { + let planes: Vec<(u32, u32)> = (0..3) + .map(|idx| info.planes.get(idx).copied().unwrap_or((0, 0))) + .collect(); + let v4l2_list = info + .v4l2_formats + .iter() + .map(|v| format!("0x{v:08x}")) + .collect::>() + .join(", "); + + let _ = writeln!( + out, + " PixelFormatInfoData {{ \ + name: \"{}\", fourcc: 0x{:08x}, modifier: 0x{:016x}, bits_per_pixel: {}, \ + colour_encoding: {}, packed: {}, pixels_per_group: {}, \ + planes: &[PixelFormatPlaneInfoData {{ bytes_per_group: {}, vertical_sub_sampling: {} }}, \ + PixelFormatPlaneInfoData {{ bytes_per_group: {}, vertical_sub_sampling: {} }}, \ + PixelFormatPlaneInfoData {{ bytes_per_group: {}, vertical_sub_sampling: {} }}], \ + v4l2_formats: &[{}], \ + }},", + info.name, + info.fourcc, + info.modifier, + info.bits_per_pixel, + info.colour_encoding, + info.packed, + info.pixels_per_group, + planes[0].0, + planes[0].1, + planes[1].0, + planes[1].1, + planes[2].0, + planes[2].1, + v4l2_list, + ); + } + + out.push_str("];\n"); + out + } + + let drm_map = build_drm_fourcc_map(); + let drm_modifier_map = build_drm_modifier_map(); + let v4l2_map = build_v4l2_fourcc_map(); + for (version, data) in by_version.iter() { let output_dir = versioned_files.join(version.to_string()); std::fs::create_dir_all(output_dir.as_path()).unwrap(); @@ -212,6 +565,15 @@ fn main() { generate_rust::generate_controls_file(&properties, ControlsType::Property), ) .unwrap(); + + println!("Parsing pixel formats for version {version}"); + let format_consts = parse_format_consts(&data.formats_yaml, &drm_map, &drm_modifier_map, &v4l2_map); + let pf_info = parse_pixel_format_info(&data.formats_cpp, &format_consts, &v4l2_map); + std::fs::write( + output_dir.join("pixel_format_info.rs"), + generate_pixel_format_info_rs(&pf_info), + ) + .unwrap(); } } @@ -243,6 +605,8 @@ mod generate_rust { let inner = match t { ControlType::Bool => "bool", ControlType::Byte => "u8", + ControlType::Uint16 => "u16", + ControlType::Uint32 => "u32", ControlType::Int32 => "i32", ControlType::Int64 => "i64", ControlType::Float => "f32", @@ -314,6 +678,13 @@ mod generate_rust { u32::from(*self) } "#; + out += " pub fn description(&self) -> &'static str {\n match self {\n"; + for ctrl in controls.iter() { + let desc = ctrl.description.replace('\\', "\\\\").replace('"', "\\\""); + out += &vendor_feature_gate(ctrl); + out += &format!(" {name}::{} => \"{}\",\n", ctrl.name, desc); + } + out += " }\n }\n"; out += "}\n"; let mut dyn_variants = String::new(); diff --git a/libcamera-meta/src/lib.rs b/libcamera-meta/src/lib.rs index b364467..86d811d 100644 --- a/libcamera-meta/src/lib.rs +++ b/libcamera-meta/src/lib.rs @@ -4,6 +4,8 @@ use yaml_rust::Yaml; pub enum ControlType { Bool, Byte, + Uint16, + Uint32, Int32, Int64, Float, @@ -20,6 +22,8 @@ impl TryFrom<&str> for ControlType { match value { "bool" => Ok(ControlType::Bool), "uint8_t" => Ok(ControlType::Byte), + "uint16_t" => Ok(ControlType::Uint16), + "uint32_t" => Ok(ControlType::Uint32), "int32_t" => Ok(ControlType::Int32), "int64_t" => Ok(ControlType::Int64), "float" => Ok(ControlType::Float), diff --git a/libcamera-sys/Cargo.toml b/libcamera-sys/Cargo.toml index 1672f13..3143982 100644 --- a/libcamera-sys/Cargo.toml +++ b/libcamera-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libcamera-sys" -version = "0.5.0" +version = "0.6.0" edition = "2021" description = "Low-level unsafe bindings to libcamera" documentation = "https://docs.rs/libcamera-sys" diff --git a/libcamera-sys/build.rs b/libcamera-sys/build.rs index b0e92c3..f774636 100644 --- a/libcamera-sys/build.rs +++ b/libcamera-sys/build.rs @@ -53,6 +53,12 @@ fn main() { .flag("-std=c++17") .files(c_api_sources) .include(libcamera_include_path) + .include( + libcamera_include_path + .parent() + .map(|p| p.to_path_buf()) + .unwrap_or_else(|| libcamera_include_path.to_path_buf()), + ) .compile("camera_c_api"); // C bindings diff --git a/libcamera-sys/c_api/camera.cpp b/libcamera-sys/c_api/camera.cpp index 75ba21f..248b672 100644 --- a/libcamera-sys/c_api/camera.cpp +++ b/libcamera-sys/c_api/camera.cpp @@ -1,4 +1,11 @@ #include "camera.h" +#include +#include +#include + +struct libcamera_stream_set { + std::vector streams; +}; extern "C" { @@ -22,6 +29,51 @@ libcamera_camera_configuration_status_t libcamera_camera_configuration_validate( return config->validate(); } +libcamera_orientation_t libcamera_camera_configuration_get_orientation(const libcamera_camera_configuration_t* config) { + return config->orientation; +} + +void libcamera_camera_configuration_set_orientation(libcamera_camera_configuration_t* config, libcamera_orientation_t orientation) { + config->orientation = orientation; +} + +libcamera_sensor_configuration_t *libcamera_camera_configuration_get_sensor_configuration(const libcamera_camera_configuration_t* config) { + if (!config->sensorConfig.has_value()) { + return nullptr; + } + return new libcamera_sensor_configuration_t(config->sensorConfig.value()); +} + +libcamera_stream_configuration_t *libcamera_camera_configuration_add_configuration(libcamera_camera_configuration_t *config) { + libcamera::StreamConfiguration cfg; + config->addConfiguration(cfg); + if (config->size() == 0) + return nullptr; + return &config->at(config->size() - 1); +} + +libcamera_stream_configuration_t *libcamera_camera_configuration_add_configuration_from( + libcamera_camera_configuration_t *config, + const libcamera_stream_configuration_t *src) { + if (!src) + return nullptr; + libcamera::StreamConfiguration cfg = *src; + config->addConfiguration(cfg); + if (config->size() == 0) + return nullptr; + return &config->at(config->size() - 1); +} + +char *libcamera_camera_configuration_to_string(const libcamera_camera_configuration_t *config) { + std::string out; + for (size_t i = 0; i < config->size(); ++i) { + out += config->at(i).toString(); + if (i + 1 < config->size()) + out += " "; + } + return ::strdup(out.c_str()); +} + libcamera_camera_t* libcamera_camera_copy(libcamera_camera_t *cam) { const libcamera_camera_t& ptr = *cam; return new libcamera_camera_t(ptr); @@ -50,6 +102,36 @@ void libcamera_camera_request_completed_disconnect(libcamera_camera_t *cam, libc delete handle; } +libcamera_callback_handle_t *libcamera_camera_buffer_completed_connect(libcamera_camera_t *cam, libcamera_buffer_completed_cb_t *callback, void *data) { + libcamera_callback_handle_t *handle = new libcamera_callback_handle_t {}; + + cam->get()->bufferCompleted.connect(handle, [=](libcamera::Request *request, libcamera::FrameBuffer *buffer) { + callback(data, request, buffer); + }); + + return handle; +} + +void libcamera_camera_buffer_completed_disconnect(libcamera_camera_t *cam, libcamera_callback_handle_t *handle) { + cam->get()->bufferCompleted.disconnect(handle); + delete handle; +} + +libcamera_callback_handle_t *libcamera_camera_disconnected_connect(libcamera_camera_t *cam, libcamera_disconnected_cb_t *callback, void *data) { + libcamera_callback_handle_t *handle = new libcamera_callback_handle_t {}; + + cam->get()->disconnected.connect(handle, [=]() { + callback(data); + }); + + return handle; +} + +void libcamera_camera_disconnected_disconnect(libcamera_camera_t *cam, libcamera_callback_handle_t *handle) { + cam->get()->disconnected.disconnect(handle); + delete handle; +} + int libcamera_camera_acquire(libcamera_camera_t *cam) { return cam->get()->acquire(); } @@ -66,6 +148,13 @@ const libcamera_control_list_t *libcamera_camera_properties(const libcamera_came return &cam->get()->properties(); } +const libcamera_stream_set_t *libcamera_camera_streams(const libcamera_camera_t *cam) { + auto wrapper = new libcamera_stream_set_t(); + const auto &set = cam->get()->streams(); + wrapper->streams.insert(wrapper->streams.end(), set.begin(), set.end()); + return wrapper; +} + libcamera_camera_configuration_t *libcamera_camera_generate_configuration(libcamera_camera_t *cam, const enum libcamera_stream_role *roles, size_t role_count) { std::vector roles_vec((libcamera::StreamRole*)roles, (libcamera::StreamRole*)roles + role_count); return cam->get()->generateConfiguration(roles_vec).release(); @@ -101,11 +190,70 @@ void libcamera_sensor_configuration_set_bit_depth(libcamera_sensor_configuration config->bitDepth = bit_depth; } +bool libcamera_sensor_configuration_is_valid(const libcamera_sensor_configuration_t *config) +{ + return config->isValid(); +} + +unsigned int libcamera_sensor_configuration_get_bit_depth(const libcamera_sensor_configuration_t *config) +{ + return config->bitDepth; +} + +libcamera_size_t libcamera_sensor_configuration_get_output_size(const libcamera_sensor_configuration_t *config) +{ + return config->outputSize; +} + +libcamera_rectangle_t libcamera_sensor_configuration_get_analog_crop(const libcamera_sensor_configuration_t *config) +{ + return config->analogCrop; +} + +void libcamera_sensor_configuration_get_binning(const libcamera_sensor_configuration_t *config, unsigned int *x, unsigned int *y) +{ + if (x) + *x = config->binning.binX; + if (y) + *y = config->binning.binY; +} + +void libcamera_sensor_configuration_get_skipping(const libcamera_sensor_configuration_t *config, unsigned int *x_odd_inc, unsigned int *x_even_inc, unsigned int *y_odd_inc, unsigned int *y_even_inc) +{ + if (x_odd_inc) + *x_odd_inc = config->skipping.xOddInc; + if (x_even_inc) + *x_even_inc = config->skipping.xEvenInc; + if (y_odd_inc) + *y_odd_inc = config->skipping.yOddInc; + if (y_even_inc) + *y_even_inc = config->skipping.yEvenInc; +} + void libcamera_sensor_configuration_set_output_size(libcamera_sensor_configuration_t *config, unsigned int width, unsigned int height) { config->outputSize = libcamera::Size(width, height); } +void libcamera_sensor_configuration_set_analog_crop(libcamera_sensor_configuration_t *config, const libcamera_rectangle_t *crop) +{ + config->analogCrop = *crop; +} + +void libcamera_sensor_configuration_set_binning(libcamera_sensor_configuration_t *config, unsigned int x, unsigned int y) +{ + config->binning.binX = x; + config->binning.binY = y; +} + +void libcamera_sensor_configuration_set_skipping(libcamera_sensor_configuration_t *config, unsigned int x_odd_inc, unsigned int x_even_inc, unsigned int y_odd_inc, unsigned int y_even_inc) +{ + config->skipping.xOddInc = x_odd_inc; + config->skipping.xEvenInc = x_even_inc; + config->skipping.yOddInc = y_odd_inc; + config->skipping.yEvenInc = y_even_inc; +} + void libcamera_camera_set_sensor_configuration(libcamera_camera_configuration_t *config, const libcamera_sensor_configuration_t *sensor_config) { config->sensorConfig = *sensor_config; diff --git a/libcamera-sys/c_api/camera.h b/libcamera-sys/c_api/camera.h index a7b6710..9c93938 100644 --- a/libcamera-sys/c_api/camera.h +++ b/libcamera-sys/c_api/camera.h @@ -5,6 +5,7 @@ #include "request.h" #include "signal.h" #include "stream.h" +#include "geometry.h" #include @@ -15,14 +16,39 @@ enum libcamera_camera_configuration_status { }; typedef void libcamera_request_completed_cb_t(void*, libcamera_request_t*); +typedef void libcamera_buffer_completed_cb_t(void*, libcamera_request_t*, libcamera_framebuffer_t*); +typedef void libcamera_disconnected_cb_t(void*); + +/* Mirror libcamera::Orientation (values start at 1 to match EXIF) */ +enum libcamera_orientation { + LIBCAMERA_ORIENTATION_ROTATE_0 = 1, + LIBCAMERA_ORIENTATION_ROTATE_0_MIRROR, + LIBCAMERA_ORIENTATION_ROTATE_180, + LIBCAMERA_ORIENTATION_ROTATE_180_MIRROR, + LIBCAMERA_ORIENTATION_ROTATE_90_MIRROR, + LIBCAMERA_ORIENTATION_ROTATE_270, + LIBCAMERA_ORIENTATION_ROTATE_270_MIRROR, + LIBCAMERA_ORIENTATION_ROTATE_90, +}; #ifdef __cplusplus #include +#include typedef libcamera::SensorConfiguration libcamera_sensor_configuration_t; typedef libcamera::CameraConfiguration libcamera_camera_configuration_t; typedef libcamera::CameraConfiguration::Status libcamera_camera_configuration_status_t; typedef std::shared_ptr libcamera_camera_t; +typedef libcamera::Orientation libcamera_orientation_t; + +static_assert(static_cast(libcamera::Orientation::Rotate0) == LIBCAMERA_ORIENTATION_ROTATE_0); +static_assert(static_cast(libcamera::Orientation::Rotate0Mirror) == LIBCAMERA_ORIENTATION_ROTATE_0_MIRROR); +static_assert(static_cast(libcamera::Orientation::Rotate180) == LIBCAMERA_ORIENTATION_ROTATE_180); +static_assert(static_cast(libcamera::Orientation::Rotate180Mirror) == LIBCAMERA_ORIENTATION_ROTATE_180_MIRROR); +static_assert(static_cast(libcamera::Orientation::Rotate90Mirror) == LIBCAMERA_ORIENTATION_ROTATE_90_MIRROR); +static_assert(static_cast(libcamera::Orientation::Rotate270) == LIBCAMERA_ORIENTATION_ROTATE_270); +static_assert(static_cast(libcamera::Orientation::Rotate270Mirror) == LIBCAMERA_ORIENTATION_ROTATE_270_MIRROR); +static_assert(static_cast(libcamera::Orientation::Rotate90) == LIBCAMERA_ORIENTATION_ROTATE_90); extern "C" { #else @@ -30,22 +56,34 @@ typedef enum libcamera_camera_configuration_status libcamera_camera_configuratio typedef struct libcamera_camera_configuration_t libcamera_camera_configuration_t; typedef struct libcamera_sensor_configuration_t libcamera_sensor_configuration_t; typedef struct libcamera_camera_t libcamera_camera_t; +typedef enum libcamera_orientation libcamera_orientation_t; #endif void libcamera_camera_configuration_destroy(libcamera_camera_configuration_t* config); size_t libcamera_camera_configuration_size(const libcamera_camera_configuration_t* config); libcamera_stream_configuration_t *libcamera_camera_configuration_at(libcamera_camera_configuration_t* config, size_t index); libcamera_camera_configuration_status_t libcamera_camera_configuration_validate(libcamera_camera_configuration_t* config); +libcamera_orientation_t libcamera_camera_configuration_get_orientation(const libcamera_camera_configuration_t* config); +void libcamera_camera_configuration_set_orientation(libcamera_camera_configuration_t* config, libcamera_orientation_t orientation); +libcamera_sensor_configuration_t *libcamera_camera_configuration_get_sensor_configuration(const libcamera_camera_configuration_t* config); +libcamera_stream_configuration_t *libcamera_camera_configuration_add_configuration(libcamera_camera_configuration_t *config); +libcamera_stream_configuration_t *libcamera_camera_configuration_add_configuration_from(libcamera_camera_configuration_t *config, const libcamera_stream_configuration_t *src); +char *libcamera_camera_configuration_to_string(const libcamera_camera_configuration_t *config); libcamera_camera_t *libcamera_camera_copy(libcamera_camera_t *cam); void libcamera_camera_destroy(libcamera_camera_t *cam); const char *libcamera_camera_id(const libcamera_camera_t *cam); libcamera_callback_handle_t *libcamera_camera_request_completed_connect(libcamera_camera_t *cam, libcamera_request_completed_cb_t *callback, void *data); void libcamera_camera_request_completed_disconnect(libcamera_camera_t *cam, libcamera_callback_handle_t *handle); +libcamera_callback_handle_t *libcamera_camera_buffer_completed_connect(libcamera_camera_t *cam, libcamera_buffer_completed_cb_t *callback, void *data); +void libcamera_camera_buffer_completed_disconnect(libcamera_camera_t *cam, libcamera_callback_handle_t *handle); +libcamera_callback_handle_t *libcamera_camera_disconnected_connect(libcamera_camera_t *cam, libcamera_disconnected_cb_t *callback, void *data); +void libcamera_camera_disconnected_disconnect(libcamera_camera_t *cam, libcamera_callback_handle_t *handle); int libcamera_camera_acquire(libcamera_camera_t *cam); int libcamera_camera_release(libcamera_camera_t *cam); const libcamera_control_info_map_t *libcamera_camera_controls(const libcamera_camera_t *cam); const libcamera_control_list_t *libcamera_camera_properties(const libcamera_camera_t *cam); +const libcamera_stream_set_t *libcamera_camera_streams(const libcamera_camera_t *cam); libcamera_camera_configuration_t *libcamera_camera_generate_configuration(libcamera_camera_t *cam, const enum libcamera_stream_role *roles, size_t role_count); int libcamera_camera_configure(libcamera_camera_t *cam, libcamera_camera_configuration_t *config); libcamera_request_t *libcamera_camera_create_request(libcamera_camera_t *cam, uint64_t cookie); @@ -55,8 +93,17 @@ int libcamera_camera_stop(libcamera_camera_t *cam); libcamera_sensor_configuration_t *libcamera_sensor_configuration_create(); void libcamera_sensor_configuration_destroy(libcamera_sensor_configuration_t *config); +bool libcamera_sensor_configuration_is_valid(const libcamera_sensor_configuration_t *config); +unsigned int libcamera_sensor_configuration_get_bit_depth(const libcamera_sensor_configuration_t *config); +libcamera_size_t libcamera_sensor_configuration_get_output_size(const libcamera_sensor_configuration_t *config); +libcamera_rectangle_t libcamera_sensor_configuration_get_analog_crop(const libcamera_sensor_configuration_t *config); +void libcamera_sensor_configuration_get_binning(const libcamera_sensor_configuration_t *config, unsigned int *x, unsigned int *y); +void libcamera_sensor_configuration_get_skipping(const libcamera_sensor_configuration_t *config, unsigned int *x_odd_inc, unsigned int *x_even_inc, unsigned int *y_odd_inc, unsigned int *y_even_inc); void libcamera_sensor_configuration_set_bit_depth(libcamera_sensor_configuration_t *config, unsigned int bit_depth); void libcamera_sensor_configuration_set_output_size(libcamera_sensor_configuration_t *config, unsigned int width, unsigned int height); +void libcamera_sensor_configuration_set_analog_crop(libcamera_sensor_configuration_t *config, const libcamera_rectangle_t *crop); +void libcamera_sensor_configuration_set_binning(libcamera_sensor_configuration_t *config, unsigned int x, unsigned int y); +void libcamera_sensor_configuration_set_skipping(libcamera_sensor_configuration_t *config, unsigned int x_odd_inc, unsigned int x_even_inc, unsigned int y_odd_inc, unsigned int y_even_inc); void libcamera_camera_set_sensor_configuration(libcamera_camera_configuration_t *config, const libcamera_sensor_configuration_t *sensor_config); #ifdef __cplusplus diff --git a/libcamera-sys/c_api/camera_manager.cpp b/libcamera-sys/c_api/camera_manager.cpp index d387edb..cdc8023 100644 --- a/libcamera-sys/c_api/camera_manager.cpp +++ b/libcamera-sys/c_api/camera_manager.cpp @@ -1,6 +1,7 @@ #include "camera_manager.h" #include +#include extern "C" { @@ -37,6 +38,30 @@ const char *libcamera_camera_manager_version(libcamera_camera_manager_t *mgr) { return mgr->version().c_str(); } +libcamera_callback_handle_t *libcamera_camera_manager_camera_added_connect(libcamera_camera_manager_t *mgr, libcamera_camera_added_cb_t *callback, void *data) { + libcamera_callback_handle_t *handle = new libcamera_callback_handle_t {}; + mgr->cameraAdded.connect(handle, [=](std::shared_ptr cam) { + auto copy = new std::shared_ptr(cam); + callback(data, copy); + }); + return handle; +} + +libcamera_callback_handle_t *libcamera_camera_manager_camera_removed_connect(libcamera_camera_manager_t *mgr, libcamera_camera_removed_cb_t *callback, void *data) { + libcamera_callback_handle_t *handle = new libcamera_callback_handle_t {}; + mgr->cameraRemoved.connect(handle, [=](std::shared_ptr cam) { + auto copy = new std::shared_ptr(cam); + callback(data, copy); + }); + return handle; +} + +void libcamera_camera_manager_camera_signal_disconnect(libcamera_camera_manager_t *mgr, libcamera_callback_handle_t *handle) { + mgr->cameraAdded.disconnect(handle); + mgr->cameraRemoved.disconnect(handle); + delete handle; +} + size_t libcamera_camera_list_size(libcamera_camera_list_t *list) { return list->size(); } diff --git a/libcamera-sys/c_api/camera_manager.h b/libcamera-sys/c_api/camera_manager.h index f30bf63..2b03d33 100644 --- a/libcamera-sys/c_api/camera_manager.h +++ b/libcamera-sys/c_api/camera_manager.h @@ -25,6 +25,11 @@ void libcamera_camera_manager_stop(libcamera_camera_manager_t *mgr); libcamera_camera_list_t *libcamera_camera_manager_cameras(const libcamera_camera_manager_t *mgr); libcamera_camera_t *libcamera_camera_manager_get_id(libcamera_camera_manager_t *mgr, const char *id); const char *libcamera_camera_manager_version(libcamera_camera_manager_t *mgr); +typedef void libcamera_camera_added_cb_t(void*, libcamera_camera_t*); +typedef void libcamera_camera_removed_cb_t(void*, libcamera_camera_t*); +libcamera_callback_handle_t *libcamera_camera_manager_camera_added_connect(libcamera_camera_manager_t *mgr, libcamera_camera_added_cb_t *callback, void *data); +libcamera_callback_handle_t *libcamera_camera_manager_camera_removed_connect(libcamera_camera_manager_t *mgr, libcamera_camera_removed_cb_t *callback, void *data); +void libcamera_camera_manager_camera_signal_disconnect(libcamera_camera_manager_t *mgr, libcamera_callback_handle_t *handle); void libcamera_camera_list_destroy(libcamera_camera_list_t *list); size_t libcamera_camera_list_size(libcamera_camera_list_t *list); diff --git a/libcamera-sys/c_api/color_space.cpp b/libcamera-sys/c_api/color_space.cpp new file mode 100644 index 0000000..f36b161 --- /dev/null +++ b/libcamera-sys/c_api/color_space.cpp @@ -0,0 +1,68 @@ +#include "color_space.h" + +#include + +extern "C" { + +libcamera_color_space_t libcamera_color_space_make(enum libcamera_color_space_primaries primaries, + enum libcamera_color_space_transfer_function tf, + enum libcamera_color_space_ycbcr_encoding ycbcr, + enum libcamera_color_space_range range) { + return libcamera::ColorSpace{ + static_cast(primaries), + static_cast(tf), + static_cast(ycbcr), + static_cast(range), + }; +} + +libcamera_color_space_t libcamera_color_space_raw() { + return libcamera::ColorSpace::Raw; +} + +libcamera_color_space_t libcamera_color_space_srgb() { + return libcamera::ColorSpace::Srgb; +} + +libcamera_color_space_t libcamera_color_space_sycc() { + return libcamera::ColorSpace::Sycc; +} + +libcamera_color_space_t libcamera_color_space_smpte170m() { + return libcamera::ColorSpace::Smpte170m; +} + +libcamera_color_space_t libcamera_color_space_rec709() { + return libcamera::ColorSpace::Rec709; +} + +libcamera_color_space_t libcamera_color_space_rec2020() { + return libcamera::ColorSpace::Rec2020; +} + +char *libcamera_color_space_to_string(const libcamera_color_space_t *color_space) { + if (!color_space) { + return nullptr; + } + return strdup(color_space->toString().c_str()); +} + +bool libcamera_color_space_from_string(const char *str, libcamera_color_space_t *out) { + if (!str || !out) { + return false; + } + auto cs = libcamera::ColorSpace::fromString(std::string(str)); + if (!cs.has_value()) + return false; + *out = cs.value(); + return true; +} + +bool libcamera_color_space_adjust(libcamera_color_space_t *color_space, const libcamera_pixel_format_t *pixel_format) { + if (!color_space || !pixel_format) { + return false; + } + return color_space->adjust(*pixel_format); +} + +} diff --git a/libcamera-sys/c_api/color_space.h b/libcamera-sys/c_api/color_space.h new file mode 100644 index 0000000..1acf7f0 --- /dev/null +++ b/libcamera-sys/c_api/color_space.h @@ -0,0 +1,73 @@ +#ifndef __LIBCAMERA_C_COLOR_SPACE__ +#define __LIBCAMERA_C_COLOR_SPACE__ + +#include "pixel_format.h" + +enum libcamera_color_space_primaries { + LIBCAMERA_COLOR_SPACE_PRIMARIES_RAW, + LIBCAMERA_COLOR_SPACE_PRIMARIES_SMPTE170M, + LIBCAMERA_COLOR_SPACE_PRIMARIES_REC709, + LIBCAMERA_COLOR_SPACE_PRIMARIES_REC2020, +}; + +enum libcamera_color_space_transfer_function { + LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_LINEAR, + LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_SRGB, + LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_REC709, +}; + +enum libcamera_color_space_ycbcr_encoding { + LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_NONE, + LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC601, + LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC709, + LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC2020, +}; + +enum libcamera_color_space_range { + LIBCAMERA_COLOR_SPACE_RANGE_FULL, + LIBCAMERA_COLOR_SPACE_RANGE_LIMITED, +}; + +struct libcamera_color_space { + enum libcamera_color_space_primaries primaries; + enum libcamera_color_space_transfer_function transfer_function; + enum libcamera_color_space_ycbcr_encoding ycbcr_encoding; + enum libcamera_color_space_range range; +}; + +#ifdef __cplusplus +#include +#include + +static_assert(sizeof(struct libcamera_color_space) == sizeof(libcamera::ColorSpace)); + +typedef libcamera::ColorSpace libcamera_color_space_t; + +extern "C" { +#else +typedef struct libcamera_color_space libcamera_color_space_t; +#endif + +libcamera_color_space_t libcamera_color_space_make(enum libcamera_color_space_primaries primaries, + enum libcamera_color_space_transfer_function tf, + enum libcamera_color_space_ycbcr_encoding ycbcr, + enum libcamera_color_space_range range); + +libcamera_color_space_t libcamera_color_space_raw(); +libcamera_color_space_t libcamera_color_space_srgb(); +libcamera_color_space_t libcamera_color_space_sycc(); +libcamera_color_space_t libcamera_color_space_smpte170m(); +libcamera_color_space_t libcamera_color_space_rec709(); +libcamera_color_space_t libcamera_color_space_rec2020(); +/// Converts ColorSpace to string (std::string::c_str()) +char *libcamera_color_space_to_string(const libcamera_color_space_t *color_space); +/// Convert string to ColorSpace; returns true on success and writes result. +bool libcamera_color_space_from_string(const char *str, libcamera_color_space_t *out); +/// Adjust color space to a pixel format; returns true if adjusted/valid. +bool libcamera_color_space_adjust(libcamera_color_space_t *color_space, const libcamera_pixel_format_t *pixel_format); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libcamera-sys/c_api/controls.cpp b/libcamera-sys/c_api/controls.cpp index b1da424..2db753b 100644 --- a/libcamera-sys/c_api/controls.cpp +++ b/libcamera-sys/c_api/controls.cpp @@ -3,6 +3,12 @@ #include #include +struct libcamera_control_id_map_iter { + const libcamera::ControlIdMap *map; + libcamera::ControlIdMap::const_iterator current; + libcamera::ControlIdMap::const_iterator end; +}; + extern "C" { enum libcamera_control_id_enum libcamera_control_id(libcamera_control_id_t *control){ @@ -82,6 +88,44 @@ void libcamera_control_id_enumerators_iter_destroy(libcamera_control_id_enumerat delete iter; } +libcamera_control_id_map_iter_t *libcamera_control_id_map_iter_create(const libcamera_control_id_map_t *map) { + if (!map) + return nullptr; + auto iter = new libcamera_control_id_map_iter_t(); + iter->map = map; + iter->current = map->begin(); + iter->end = map->end(); + return iter; +} + +bool libcamera_control_id_map_iter_has_next(const libcamera_control_id_map_iter_t *iter) { + if (!iter) + return false; + return iter->current != iter->end; +} + +unsigned int libcamera_control_id_map_iter_key(const libcamera_control_id_map_iter_t *iter) { + if (!iter || iter->current == iter->end) + return 0; + return iter->current->first; +} + +const libcamera_control_id_t *libcamera_control_id_map_iter_value(const libcamera_control_id_map_iter_t *iter) { + if (!iter || iter->current == iter->end) + return nullptr; + return iter->current->second; +} + +void libcamera_control_id_map_iter_next(libcamera_control_id_map_iter_t *iter) { + if (!iter || iter->current == iter->end) + return; + ++(iter->current); +} + +void libcamera_control_id_map_iter_destroy(libcamera_control_id_map_iter_t *iter) { + delete iter; +} + const libcamera_control_id_t *libcamera_control_from_id(enum libcamera_control_id_enum id){ auto it = libcamera::controls::controls.find(id); @@ -127,6 +171,18 @@ libcamera_control_list_t *libcamera_control_list_create() { return new libcamera::ControlList(); } +libcamera_control_list_t *libcamera_control_list_create_with_idmap(const libcamera_control_id_map_t *idmap) { + if (!idmap) + return nullptr; + return new libcamera::ControlList(*idmap); +} + +libcamera_control_list_t *libcamera_control_list_create_with_info_map(const libcamera_control_info_map_t *info_map) { + if (!info_map) + return nullptr; + return new libcamera::ControlList(*info_map); +} + void libcamera_control_list_destroy(libcamera_control_list_t *list) { delete list; } @@ -145,6 +201,47 @@ void libcamera_control_list_set(libcamera_control_list_t *list, enum libcamera_p list->set(id, *val); } +bool libcamera_control_list_contains(const libcamera_control_list_t *list, unsigned int id) { + if (!list) + return false; + return list->contains(id); +} + +void libcamera_control_list_clear(libcamera_control_list_t *list) { + if (list) + list->clear(); +} + +size_t libcamera_control_list_size(const libcamera_control_list_t *list) { + if (!list) + return 0; + return list->size(); +} + +bool libcamera_control_list_is_empty(const libcamera_control_list_t *list) { + if (!list) + return true; + return list->empty(); +} + +void libcamera_control_list_merge(libcamera_control_list_t *list, const libcamera_control_list_t *other, enum libcamera_control_merge_policy policy) { + if (!list || !other) + return; + list->merge(*other, static_cast(policy)); +} + +const libcamera_control_info_map_t *libcamera_control_list_info_map(const libcamera_control_list_t *list) { + if (!list) + return nullptr; + return list->infoMap(); +} + +const libcamera_control_id_map_t *libcamera_control_list_id_map(const libcamera_control_list_t *list) { + if (!list) + return nullptr; + return list->idMap(); +} + libcamera_control_list_iter_t *libcamera_control_list_iter(libcamera_control_list_t *list) { auto it = list->begin(); return new libcamera_control_list_iter_t { list, it }; diff --git a/libcamera-sys/c_api/controls.h b/libcamera-sys/c_api/controls.h index 419382c..96f46cb 100644 --- a/libcamera-sys/c_api/controls.h +++ b/libcamera-sys/c_api/controls.h @@ -8,6 +8,8 @@ #ifdef __cplusplus #include +typedef libcamera::ControlIdMap libcamera_control_id_map_t; + struct libcamera_control_list_iter { libcamera::ControlList *list; libcamera::ControlList::iterator it; @@ -22,13 +24,15 @@ struct libcamera_control_id_enumerators_iter { std::map::const_iterator current; std::map::const_iterator end; }; +struct libcamera_control_id_map_iter; +typedef struct libcamera_control_id_enumerators_iter libcamera_control_id_enumerators_iter_t; +typedef struct libcamera_control_id_map_iter libcamera_control_id_map_iter_t; typedef libcamera::ControlValue libcamera_control_value_t; typedef libcamera::ControlList libcamera_control_list_t; typedef struct libcamera_control_list_iter libcamera_control_list_iter_t; typedef struct libcamera_control_info_map_iter libcamera_control_info_map_iter_t; typedef libcamera::ControlInfoMap libcamera_control_info_map_t; -typedef libcamera::ControlIdMap libcamera_control_id_map_t; typedef libcamera::ControlId libcamera_control_id_t; typedef libcamera::ControlInfo libcamera_control_info_t; @@ -43,11 +47,10 @@ typedef struct libcamera_control_id libcamera_control_id_t; typedef struct libcamera_control_info libcamera_control_info_t; typedef struct libcamera_control_id_map libcamera_control_id_map_t; typedef struct libcamera_control_id_enumerators_iter libcamera_control_id_enumerators_iter_t; +typedef struct libcamera_control_id_map_iter libcamera_control_id_map_iter_t; #endif -typedef struct libcamera_control_id_enumerators_iter libcamera_control_id_enumerators_iter_t; - enum libcamera_control_id_enum { libcamera_control_id_DUMMY }; enum libcamera_property_id { libcamera_property_id_DUMMY }; @@ -70,6 +73,11 @@ enum libcamera_control_direction { LIBCAMERA_CONTROL_DIRECTION_IN = (1 << 0), LIBCAMERA_CONTROL_DIRECTION_OUT = (1 << 1), }; + +enum libcamera_control_merge_policy { + LIBCAMERA_CONTROL_MERGE_KEEP_EXISTING = 0, + LIBCAMERA_CONTROL_MERGE_OVERWRITE_EXISTING = 1, +}; // --- libcamera_control_id --- const libcamera_control_id_t *libcamera_control_from_id(enum libcamera_control_id_enum id); const char *libcamera_control_name_from_id(enum libcamera_control_id_enum id); @@ -92,6 +100,13 @@ int32_t libcamera_control_id_enumerators_iter_key(const libcamera_control_id_enu const char *libcamera_control_id_enumerators_iter_value(const libcamera_control_id_enumerators_iter_t *iter); void libcamera_control_id_enumerators_iter_next(libcamera_control_id_enumerators_iter_t *iter); void libcamera_control_id_enumerators_iter_destroy(libcamera_control_id_enumerators_iter_t *iter); +// --- libcamera_control_id_map_iter_t --- +libcamera_control_id_map_iter_t *libcamera_control_id_map_iter_create(const libcamera_control_id_map_t *map); +bool libcamera_control_id_map_iter_has_next(const libcamera_control_id_map_iter_t *iter); +unsigned int libcamera_control_id_map_iter_key(const libcamera_control_id_map_iter_t *iter); +const libcamera_control_id_t *libcamera_control_id_map_iter_value(const libcamera_control_id_map_iter_t *iter); +void libcamera_control_id_map_iter_next(libcamera_control_id_map_iter_t *iter); +void libcamera_control_id_map_iter_destroy(libcamera_control_id_map_iter_t *iter); // --- libcamera_property_id --- const char *libcamera_property_name_from_id(enum libcamera_property_id id); @@ -99,9 +114,18 @@ enum libcamera_control_type libcamera_property_type_from_id(enum libcamera_prope // --- libcamera_control_list_t --- libcamera_control_list_t *libcamera_control_list_create(); +libcamera_control_list_t *libcamera_control_list_create_with_idmap(const libcamera_control_id_map_t *idmap); +libcamera_control_list_t *libcamera_control_list_create_with_info_map(const libcamera_control_info_map_t *info_map); void libcamera_control_list_destroy(libcamera_control_list_t *list); const libcamera_control_value_t *libcamera_control_list_get(libcamera_control_list_t *list, enum libcamera_property_id id); void libcamera_control_list_set(libcamera_control_list_t *list, enum libcamera_property_id id, const libcamera_control_value_t *val); +bool libcamera_control_list_contains(const libcamera_control_list_t *list, unsigned int id); +void libcamera_control_list_clear(libcamera_control_list_t *list); +size_t libcamera_control_list_size(const libcamera_control_list_t *list); +bool libcamera_control_list_is_empty(const libcamera_control_list_t *list); +void libcamera_control_list_merge(libcamera_control_list_t *list, const libcamera_control_list_t *other, enum libcamera_control_merge_policy policy); +const libcamera_control_info_map_t *libcamera_control_list_info_map(const libcamera_control_list_t *list); +const libcamera_control_id_map_t *libcamera_control_list_id_map(const libcamera_control_list_t *list); libcamera_control_list_iter_t *libcamera_control_list_iter(libcamera_control_list_t *list); // --- libcamera_control_list_iter_t --- diff --git a/libcamera-sys/c_api/fence.cpp b/libcamera-sys/c_api/fence.cpp new file mode 100644 index 0000000..8a9f988 --- /dev/null +++ b/libcamera-sys/c_api/fence.cpp @@ -0,0 +1,24 @@ +#include "fence.h" +#include +#include + +extern "C" { + +libcamera_fence_t *libcamera_fence_from_fd(int fd) { + libcamera::UniqueFD ufd(fd); + if (!ufd.isValid()) + return nullptr; + return new libcamera::Fence(std::move(ufd)); +} + +void libcamera_fence_destroy(libcamera_fence_t *fence) { + delete fence; +} + +int libcamera_fence_fd(const libcamera_fence_t *fence) { + if (!fence) + return -1; + return ::dup(fence->fd().get()); +} + +} diff --git a/libcamera-sys/c_api/fence.h b/libcamera-sys/c_api/fence.h new file mode 100644 index 0000000..a843c87 --- /dev/null +++ b/libcamera-sys/c_api/fence.h @@ -0,0 +1,22 @@ +#ifndef __LIBCAMERA_C_FENCE__ +#define __LIBCAMERA_C_FENCE__ + +#ifdef __cplusplus +#include + +typedef libcamera::Fence libcamera_fence_t; + +extern "C" { +#else +typedef struct libcamera_fence libcamera_fence_t; +#endif + +libcamera_fence_t *libcamera_fence_from_fd(int fd); +void libcamera_fence_destroy(libcamera_fence_t *fence); +int libcamera_fence_fd(const libcamera_fence_t *fence); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libcamera-sys/c_api/framebuffer.cpp b/libcamera-sys/c_api/framebuffer.cpp index 9e7ea88..33683e0 100644 --- a/libcamera-sys/c_api/framebuffer.cpp +++ b/libcamera-sys/c_api/framebuffer.cpp @@ -1,4 +1,10 @@ #include "framebuffer.h" +#include "fence.h" + +#include +#include +#include +#include extern "C" { @@ -33,8 +39,47 @@ libcamera_frame_metadata_plane_t *libcamera_frame_metadata_planes_at(libcamera_f } // --- libcamera_framebuffer_t --- -const libcamera_framebuffer_planes_t *libcamera_framebuffer_planes(const libcamera_framebuffer_t *framebuffer) { - return &framebuffer->planes(); +libcamera_framebuffer_t *libcamera_framebuffer_create(const struct libcamera_framebuffer_plane_info *planes, size_t num_planes, uint64_t cookie) { + if (!planes || num_planes == 0) + return nullptr; + + std::vector fb_planes; + fb_planes.reserve(num_planes); + + for (size_t i = 0; i < num_planes; ++i) { + const auto &p = planes[i]; + libcamera::SharedFD fd(p.fd); + if (!fd.isValid()) + return nullptr; + + libcamera::FrameBuffer::Plane plane; + plane.fd = std::move(fd); + plane.offset = p.offset; + plane.length = p.length; + fb_planes.push_back(std::move(plane)); + } + +#if LIBCAMERA_VERSION_MAJOR == 0 && LIBCAMERA_VERSION_MINOR < 6 + return new libcamera::FrameBuffer(fb_planes, cookie); +#else + auto span = libcamera::Span(fb_planes); + return new libcamera::FrameBuffer(span, cookie); +#endif +} + +void libcamera_framebuffer_destroy(libcamera_framebuffer_t *framebuffer) { + delete framebuffer; +} + +struct libcamera_framebuffer_planes { + std::vector planes; +}; + +libcamera_framebuffer_planes_t *libcamera_framebuffer_planes(const libcamera_framebuffer_t *framebuffer) { + auto wrapper = new libcamera_framebuffer_planes_t(); + const auto planes = framebuffer->planes(); + wrapper->planes.assign(planes.begin(), planes.end()); + return wrapper; } const libcamera_frame_metadata_t *libcamera_framebuffer_metadata(const libcamera_framebuffer_t *framebuffer) { @@ -45,6 +90,29 @@ uint64_t libcamera_framebuffer_cookie(const libcamera_framebuffer_t *framebuffer return framebuffer->cookie(); } +void libcamera_framebuffer_set_cookie(libcamera_framebuffer_t *framebuffer, uint64_t cookie) { + framebuffer->setCookie(cookie); +} + +libcamera_fence_t *libcamera_framebuffer_release_fence_handle(libcamera_framebuffer_t *framebuffer) { + auto fence = framebuffer->releaseFence(); + return fence.release(); +} + +int libcamera_framebuffer_release_fence(libcamera_framebuffer_t *framebuffer) { + auto fence = framebuffer->releaseFence(); + if (!fence) + return -1; + int fd = fence->fd().get(); + if (fd < 0) + return -1; + return ::dup(fd); +} + +libcamera_request_t *libcamera_framebuffer_request(const libcamera_framebuffer_t *framebuffer) { + return framebuffer->request(); +} + // --- libcamera_framebuffer_plane_t --- int libcamera_framebuffer_plane_fd(libcamera_framebuffer_plane_t *plane) { return plane->fd.get(); @@ -63,12 +131,16 @@ size_t libcamera_framebuffer_plane_length(const libcamera_framebuffer_plane_t *p } // --- libcamera_framebuffer_planes_t --- +void libcamera_framebuffer_planes_destroy(libcamera_framebuffer_planes_t *planes) { + delete planes; +} + size_t libcamera_framebuffer_planes_size(const libcamera_framebuffer_planes_t *planes) { - return planes->size(); + return planes->planes.size(); } libcamera_framebuffer_plane_t *libcamera_framebuffer_planes_at(libcamera_framebuffer_planes_t *planes, size_t index) { - return &planes->at(index); + return &planes->planes.at(index); } } diff --git a/libcamera-sys/c_api/framebuffer.h b/libcamera-sys/c_api/framebuffer.h index f061af5..f7e3076 100644 --- a/libcamera-sys/c_api/framebuffer.h +++ b/libcamera-sys/c_api/framebuffer.h @@ -1,9 +1,10 @@ #ifndef __LIBCAMERA_C_FRAMEBUFFER__ #define __LIBCAMERA_C_FRAMEBUFFER__ +#include #include #include -#include +#include "fence.h" enum libcamera_frame_metadata_status { LIBCAMERA_FRAME_METADATA_STATUS_SUCCESS, @@ -16,6 +17,12 @@ struct libcamera_frame_metadata_plane { unsigned int bytes_used; }; +struct libcamera_framebuffer_plane_info { + int fd; + unsigned int offset; + unsigned int length; +}; + #ifdef __cplusplus #include @@ -24,8 +31,9 @@ typedef libcamera::FrameMetadata::Plane libcamera_frame_metadata_plane_t; typedef libcamera::Span libcamera_frame_metadata_planes_t; typedef libcamera::FrameMetadata libcamera_frame_metadata_t; typedef libcamera::FrameBuffer::Plane libcamera_framebuffer_plane_t; -typedef std::vector libcamera_framebuffer_planes_t; +typedef struct libcamera_framebuffer_planes libcamera_framebuffer_planes_t; typedef libcamera::FrameBuffer libcamera_framebuffer_t; +typedef libcamera::Request libcamera_request_t; static_assert(sizeof(struct libcamera_frame_metadata_plane) == sizeof(libcamera_frame_metadata_plane_t)); static_assert(offsetof(struct libcamera_frame_metadata_plane, bytes_used) == offsetof(libcamera_frame_metadata_plane_t, bytesused)); @@ -39,6 +47,7 @@ typedef struct libcamera_frame_metadata libcamera_frame_metadata_t; typedef struct libcamera_framebuffer_plane libcamera_framebuffer_plane_t; typedef struct libcamera_framebuffer_planes libcamera_framebuffer_planes_t; typedef struct libcamera_framebuffer libcamera_framebuffer_t; +typedef struct libcamera_request libcamera_request_t; #endif // --- libcamera_frame_metadata_t --- @@ -53,9 +62,15 @@ size_t libcamera_frame_metadata_planes_size(const libcamera_frame_metadata_plane libcamera_frame_metadata_plane_t *libcamera_frame_metadata_planes_at(libcamera_frame_metadata_planes_t *planes, size_t index); // --- libcamera_framebuffer_t --- -const libcamera_framebuffer_planes_t *libcamera_framebuffer_planes(const libcamera_framebuffer_t *framebuffer); +libcamera_framebuffer_t *libcamera_framebuffer_create(const struct libcamera_framebuffer_plane_info *planes, size_t num_planes, uint64_t cookie); +void libcamera_framebuffer_destroy(libcamera_framebuffer_t *framebuffer); +libcamera_framebuffer_planes_t *libcamera_framebuffer_planes(const libcamera_framebuffer_t *framebuffer); const libcamera_frame_metadata_t *libcamera_framebuffer_metadata(const libcamera_framebuffer_t *framebuffer); uint64_t libcamera_framebuffer_cookie(const libcamera_framebuffer_t *framebuffer); +void libcamera_framebuffer_set_cookie(libcamera_framebuffer_t *framebuffer, uint64_t cookie); +int libcamera_framebuffer_release_fence(libcamera_framebuffer_t *framebuffer); +libcamera_fence_t *libcamera_framebuffer_release_fence_handle(libcamera_framebuffer_t *framebuffer); +libcamera_request_t *libcamera_framebuffer_request(const libcamera_framebuffer_t *framebuffer); // --- libcamera_framebuffer_plane_t --- int libcamera_framebuffer_plane_fd(libcamera_framebuffer_plane_t *plane); @@ -64,6 +79,7 @@ bool libcamera_framebuffer_plane_offset_valid(const libcamera_framebuffer_plane_ size_t libcamera_framebuffer_plane_length(const libcamera_framebuffer_plane_t *plane); // --- libcamera_framebuffer_planes_t --- +void libcamera_framebuffer_planes_destroy(libcamera_framebuffer_planes_t *planes); size_t libcamera_framebuffer_planes_size(const libcamera_framebuffer_planes_t *planes); libcamera_framebuffer_plane_t *libcamera_framebuffer_planes_at(libcamera_framebuffer_planes_t *planes, size_t index); diff --git a/libcamera-sys/c_api/framebuffer_allocator.cpp b/libcamera-sys/c_api/framebuffer_allocator.cpp index 908fb4d..576c578 100644 --- a/libcamera-sys/c_api/framebuffer_allocator.cpp +++ b/libcamera-sys/c_api/framebuffer_allocator.cpp @@ -20,6 +20,10 @@ int libcamera_framebuffer_allocator_free(libcamera_framebuffer_allocator_t *allo return alloc->free(stream); } +bool libcamera_framebuffer_allocator_allocated(const libcamera_framebuffer_allocator_t *alloc) { + return alloc->allocated(); +} + const libcamera_framebuffer_list_t *libcamera_framebuffer_allocator_buffers(libcamera_framebuffer_allocator_t *alloc, libcamera_stream_t *stream) { return &alloc->buffers(stream); } diff --git a/libcamera-sys/c_api/framebuffer_allocator.h b/libcamera-sys/c_api/framebuffer_allocator.h index 5911970..55cfba1 100644 --- a/libcamera-sys/c_api/framebuffer_allocator.h +++ b/libcamera-sys/c_api/framebuffer_allocator.h @@ -22,6 +22,7 @@ libcamera_framebuffer_allocator_t *libcamera_framebuffer_allocator_create(libcam void libcamera_framebuffer_allocator_destroy(libcamera_framebuffer_allocator_t *alloc); int libcamera_framebuffer_allocator_allocate(libcamera_framebuffer_allocator_t *alloc, libcamera_stream_t *stream); int libcamera_framebuffer_allocator_free(libcamera_framebuffer_allocator_t *alloc, libcamera_stream_t *stream); +bool libcamera_framebuffer_allocator_allocated(const libcamera_framebuffer_allocator_t *alloc); const libcamera_framebuffer_list_t *libcamera_framebuffer_allocator_buffers(libcamera_framebuffer_allocator_t *alloc, libcamera_stream_t *stream); size_t libcamera_framebuffer_list_size(const libcamera_framebuffer_list_t *list); diff --git a/libcamera-sys/c_api/logging.cpp b/libcamera-sys/c_api/logging.cpp index 3c938bf..5f80288 100644 --- a/libcamera-sys/c_api/logging.cpp +++ b/libcamera-sys/c_api/logging.cpp @@ -1,24 +1,34 @@ #include #include "logging.h" +extern "C" { + int libcamera_log_set_file(const char *path, bool color) { return libcamera::logSetFile(path, color); } int libcamera_log_set_stream(libcamera_logging_stream_t stream, bool color) { - std::ostream *ostream = NULL; + std::ostream *ostream = nullptr; switch (stream) { case LIBCAMERA_LOGGING_STREAM_STDOUT: ostream = &std::cout; - break; - + break; case LIBCAMERA_LOGGING_STREAM_STDERR: ostream = &std::cerr; - break; + break; + case LIBCAMERA_LOGGING_STREAM_CUSTOM: + return -EINVAL; } return libcamera::logSetStream(ostream, color); } +int libcamera_log_set_custom_stream(void *ostream, bool color) { + if (!ostream) + return -EINVAL; + auto *os = static_cast(ostream); + return libcamera::logSetStream(os, color); +} + int libcamera_log_set_target(libcamera_logging_target_t target) { return libcamera::logSetTarget(target); } @@ -26,3 +36,5 @@ int libcamera_log_set_target(libcamera_logging_target_t target) { void libcamera_log_set_level(const char *category, const char *level) { libcamera::logSetLevel(category, level); } + +} diff --git a/libcamera-sys/c_api/logging.h b/libcamera-sys/c_api/logging.h index e3df42e..b1d7cab 100644 --- a/libcamera-sys/c_api/logging.h +++ b/libcamera-sys/c_api/logging.h @@ -6,11 +6,14 @@ enum libcamera_logging_target { LIBCAMERA_LOGGING_TARGET_NONE, LIBCAMERA_LOGGING_TARGET_SYSLOG, + LIBCAMERA_LOGGING_TARGET_FILE, + LIBCAMERA_LOGGING_TARGET_STREAM, }; enum libcamera_logging_stream { LIBCAMERA_LOGGING_STREAM_STDOUT, LIBCAMERA_LOGGING_STREAM_STDERR, + LIBCAMERA_LOGGING_STREAM_CUSTOM, }; typedef enum libcamera_logging_stream libcamera_logging_stream_t; @@ -29,6 +32,7 @@ typedef enum libcamera_logging_target libcamera_logging_target_t; int libcamera_log_set_file(const char *path, bool color); int libcamera_log_set_stream(libcamera_logging_stream_t stream, bool color); +int libcamera_log_set_custom_stream(void *ostream, bool color); int libcamera_log_set_target(libcamera_logging_target_t target); void libcamera_log_set_level(const char *category, const char *level); diff --git a/libcamera-sys/c_api/pixel_format.cpp b/libcamera-sys/c_api/pixel_format.cpp index 65b4a81..d0456d0 100644 --- a/libcamera-sys/c_api/pixel_format.cpp +++ b/libcamera-sys/c_api/pixel_format.cpp @@ -9,6 +9,17 @@ char *libcamera_pixel_format_str(const libcamera_pixel_format_t *format) { return strdup(format->toString().c_str()); } +libcamera_pixel_format_t libcamera_pixel_format_from_str(const char *name) { + if (!name) { + return libcamera::PixelFormat(); + } + return libcamera::PixelFormat::fromString(std::string(name)); +} + +bool libcamera_pixel_format_is_valid(const libcamera_pixel_format_t *format) { + return format && format->isValid(); +} + void libcamera_pixel_formats_destroy(libcamera_pixel_formats_t *formats) { delete formats; } diff --git a/libcamera-sys/c_api/pixel_format.h b/libcamera-sys/c_api/pixel_format.h index 85a098e..a0435a6 100644 --- a/libcamera-sys/c_api/pixel_format.h +++ b/libcamera-sys/c_api/pixel_format.h @@ -31,6 +31,11 @@ typedef struct libcamera_pixel_formats libcamera_pixel_formats_t; /// @return A heap allocated null-terminated string, that has to be deallocated with free() char *libcamera_pixel_format_str(const libcamera_pixel_format_t *format); +// Parse a string into a PixelFormat. Returns a PixelFormat with fourcc=0 on failure. +libcamera_pixel_format_t libcamera_pixel_format_from_str(const char *name); +// Whether the PixelFormat is valid (fourcc != 0). +bool libcamera_pixel_format_is_valid(const libcamera_pixel_format_t *format); + void libcamera_pixel_formats_destroy(libcamera_pixel_formats_t *formats); size_t libcamera_pixel_formats_size(const libcamera_pixel_formats_t *formats); libcamera_pixel_format_t libcamera_pixel_formats_get(const libcamera_pixel_formats_t *formats, size_t index); diff --git a/libcamera-sys/c_api/request.cpp b/libcamera-sys/c_api/request.cpp index b841406..2ba238d 100644 --- a/libcamera-sys/c_api/request.cpp +++ b/libcamera-sys/c_api/request.cpp @@ -1,4 +1,7 @@ #include "request.h" +#include "fence.h" +#include +#include extern "C" { @@ -22,6 +25,14 @@ int libcamera_request_add_buffer(libcamera_request_t *request, const libcamera_s return request->addBuffer(stream, buffer); } +int libcamera_request_add_buffer_with_fence(libcamera_request_t *request, const libcamera_stream_t *stream, libcamera_framebuffer_t *buffer, libcamera_fence_t *fence) { + std::unique_ptr acquire_fence; + if (fence) { + acquire_fence.reset(fence); + } + return request->addBuffer(stream, buffer, std::move(acquire_fence)); +} + libcamera_framebuffer_t *libcamera_request_find_buffer(const libcamera_request_t *request, const libcamera_stream_t *stream) { return request->findBuffer(stream); } @@ -42,6 +53,14 @@ void libcamera_request_reuse(libcamera_request_t *request, libcamera_request_reu return request->reuse(flags); } +bool libcamera_request_has_pending_buffers(const libcamera_request_t *request) { + return request->hasPendingBuffers(); +} + +char *libcamera_request_to_string(const libcamera_request_t *request) { + return ::strdup(request->toString().c_str()); +} + libcamera_framebuffer_t *libcamera_request_buffer_map_get(libcamera_request_buffer_map_t* buffer_map, const libcamera_stream_t *stream) { const auto it = buffer_map->find(stream); if (it == buffer_map->end()) diff --git a/libcamera-sys/c_api/request.h b/libcamera-sys/c_api/request.h index 6dc8486..938db7f 100644 --- a/libcamera-sys/c_api/request.h +++ b/libcamera-sys/c_api/request.h @@ -3,6 +3,7 @@ #include "controls.h" #include "framebuffer.h" +#include "fence.h" #include "stream.h" #include @@ -48,11 +49,14 @@ libcamera_control_list_t *libcamera_request_controls(libcamera_request_t *reques libcamera_control_list_t *libcamera_request_metadata(libcamera_request_t *request); const libcamera_request_buffer_map_t *libcamera_request_buffers(const libcamera_request_t *request); int libcamera_request_add_buffer(libcamera_request_t *request, const libcamera_stream_t *stream, libcamera_framebuffer_t *buffer); +int libcamera_request_add_buffer_with_fence(libcamera_request_t *request, const libcamera_stream_t *stream, libcamera_framebuffer_t *buffer, libcamera_fence_t *fence); libcamera_framebuffer_t *libcamera_request_find_buffer(const libcamera_request_t *request, const libcamera_stream_t *stream); uint32_t libcamera_request_sequence(const libcamera_request_t *request); uint64_t libcamera_request_cookie(const libcamera_request_t *request); libcamera_request_status_t libcamera_request_status(const libcamera_request_t *request); void libcamera_request_reuse(libcamera_request_t *request, libcamera_request_reuse_flag_t flags); +bool libcamera_request_has_pending_buffers(const libcamera_request_t *request); +char *libcamera_request_to_string(const libcamera_request_t *request); // --- libcamera_request_buffer_map_t --- libcamera_framebuffer_t *libcamera_request_buffer_map_get(libcamera_request_buffer_map_t* buffer_map, const libcamera_stream_t *stream); diff --git a/libcamera-sys/c_api/stream.cpp b/libcamera-sys/c_api/stream.cpp index 3597e9e..c9b4689 100644 --- a/libcamera-sys/c_api/stream.cpp +++ b/libcamera-sys/c_api/stream.cpp @@ -1,9 +1,15 @@ #include "stream.h" #include +#include +#include extern "C" { +struct libcamera_stream_set { + std::vector streams; +}; + libcamera_pixel_formats_t *libcamera_stream_formats_pixel_formats(const libcamera_stream_formats_t* formats) { return new libcamera_pixel_formats_t(std::move(formats->pixelformats())); } @@ -24,4 +30,44 @@ libcamera_stream_t *libcamera_stream_configuration_stream(const libcamera_stream return config->stream(); } +bool libcamera_stream_configuration_has_color_space(const libcamera_stream_configuration_t *config) { + return config->colorSpace.has_value(); +} + +libcamera_color_space_t libcamera_stream_configuration_get_color_space(const libcamera_stream_configuration_t *config) { + return config->colorSpace.value_or(libcamera::ColorSpace::Raw); +} + +void libcamera_stream_configuration_set_color_space(libcamera_stream_configuration_t *config, const libcamera_color_space_t *color_space) { + if (color_space) { + config->colorSpace = *color_space; + } else { + config->colorSpace.reset(); + } +} + +char *libcamera_stream_configuration_to_string(const libcamera_stream_configuration_t *config) { + return ::strdup(config->toString().c_str()); +} + +const libcamera_stream_configuration_t *libcamera_stream_get_configuration(const libcamera_stream_t *stream) { + if (!stream) + return nullptr; + return &stream->configuration(); +} + +size_t libcamera_stream_set_size(const libcamera_stream_set_t *set) { + return set->streams.size(); +} + +libcamera_stream_t *libcamera_stream_set_get(const libcamera_stream_set_t *set, size_t index) { + if (index >= set->streams.size()) + return nullptr; + return set->streams.at(index); +} + +void libcamera_stream_set_destroy(libcamera_stream_set_t *set) { + delete set; +} + } diff --git a/libcamera-sys/c_api/stream.h b/libcamera-sys/c_api/stream.h index 4ca2a88..5049ea2 100644 --- a/libcamera-sys/c_api/stream.h +++ b/libcamera-sys/c_api/stream.h @@ -3,8 +3,10 @@ #include "geometry.h" #include "pixel_format.h" +#include "color_space.h" #include +struct libcamera_stream_set; struct libcamera_stream_configuration { libcamera_pixel_format_t pixel_format; @@ -21,6 +23,9 @@ typedef libcamera::StreamFormats libcamera_stream_formats_t; typedef libcamera::StreamConfiguration libcamera_stream_configuration_t; +struct libcamera_stream_set; +typedef struct libcamera_stream_set libcamera_stream_set_t; + // Read more about this in https://github.com/google/benchmark/issues/552 #ifdef __GNUC__ #pragma GCC diagnostic push @@ -42,6 +47,7 @@ extern "C" { typedef struct libcamera_stream_formats libcamera_stream_formats_t; typedef struct libcamera_stream_configuration libcamera_stream_configuration_t; typedef struct libcamera_stream libcamera_stream_t; +typedef struct libcamera_stream_set libcamera_stream_set_t; #endif enum libcamera_stream_role { @@ -57,6 +63,14 @@ libcamera_size_range_t libcamera_stream_formats_range(const libcamera_stream_for const libcamera_stream_formats_t *libcamera_stream_configuration_formats(const libcamera_stream_configuration_t *config); libcamera_stream_t *libcamera_stream_configuration_stream(const libcamera_stream_configuration_t *config); +bool libcamera_stream_configuration_has_color_space(const libcamera_stream_configuration_t *config); +libcamera_color_space_t libcamera_stream_configuration_get_color_space(const libcamera_stream_configuration_t *config); +void libcamera_stream_configuration_set_color_space(libcamera_stream_configuration_t *config, const libcamera_color_space_t *color_space); +char *libcamera_stream_configuration_to_string(const libcamera_stream_configuration_t *config); +const libcamera_stream_configuration_t *libcamera_stream_get_configuration(const libcamera_stream_t *stream); +size_t libcamera_stream_set_size(const libcamera_stream_set_t *set); +libcamera_stream_t *libcamera_stream_set_get(const libcamera_stream_set_t *set, size_t index); +void libcamera_stream_set_destroy(libcamera_stream_set_t *set); #ifdef __cplusplus } diff --git a/libcamera-sys/c_api/transform.cpp b/libcamera-sys/c_api/transform.cpp new file mode 100644 index 0000000..f461f2e --- /dev/null +++ b/libcamera-sys/c_api/transform.cpp @@ -0,0 +1,93 @@ +#include "transform.h" +#include + +extern "C" { + +static inline libcamera::Transform to_cpp(libcamera_transform_t t) { + libcamera::Transform result; + std::memcpy(&result, &t, sizeof(result)); + return result; +} + +static inline libcamera_transform_t from_cpp(const libcamera::Transform &t) { + libcamera_transform_t result; + std::memcpy(&result, &t, sizeof(result)); + return result; +} + +libcamera_transform_t libcamera_transform_identity() { + return from_cpp(libcamera::Transform::Identity); +} + +libcamera_transform_t libcamera_transform_from_rotation(int angle, bool hflip, bool *success) { + bool ok = false; + libcamera::Transform t = libcamera::transformFromRotation(angle, &ok); + if (!ok) { + if (success) + *success = false; + return from_cpp(libcamera::Transform::Identity); + } + if (hflip) + t = libcamera::Transform::HFlip * t; + if (success) + *success = ok; + return from_cpp(t); +} + +libcamera_transform_t libcamera_transform_inverse(libcamera_transform_t transform) { + return from_cpp(-to_cpp(transform)); +} + +libcamera_transform_t libcamera_transform_combine(libcamera_transform_t a, libcamera_transform_t b) { + return from_cpp(to_cpp(a) * to_cpp(b)); +} + +char *libcamera_transform_to_string(libcamera_transform_t transform) { + return ::strdup(libcamera::transformToString(to_cpp(transform))); +} + +libcamera_transform_t libcamera_transform_between_orientations(libcamera_orientation_t from, libcamera_orientation_t to) { + return from_cpp(from / to); +} + +libcamera_orientation_t libcamera_transform_apply_orientation(libcamera_orientation_t orientation, libcamera_transform_t transform) { + return orientation * to_cpp(transform); +} + +libcamera_orientation_t libcamera_orientation_from_rotation(int angle, bool *success) { + bool ok = false; + libcamera_orientation_t ori = libcamera::orientationFromRotation(angle, &ok); + if (success) + *success = ok; + return ori; +} + +libcamera_transform_t libcamera_transform_hflip() { + return from_cpp(libcamera::Transform::HFlip); +} + +libcamera_transform_t libcamera_transform_vflip() { + return from_cpp(libcamera::Transform::VFlip); +} + +libcamera_transform_t libcamera_transform_transpose() { + return from_cpp(libcamera::Transform::Transpose); +} + +libcamera_transform_t libcamera_transform_or(libcamera_transform_t a, libcamera_transform_t b) { + return from_cpp(to_cpp(a) | to_cpp(b)); +} + +libcamera_transform_t libcamera_transform_and(libcamera_transform_t a, libcamera_transform_t b) { + return from_cpp(to_cpp(a) & to_cpp(b)); +} + +libcamera_transform_t libcamera_transform_xor(libcamera_transform_t a, libcamera_transform_t b) { + return from_cpp(to_cpp(a) ^ to_cpp(b)); +} + +libcamera_transform_t libcamera_transform_not(libcamera_transform_t t) { + return from_cpp(~to_cpp(t)); +} + +} diff --git a/libcamera-sys/c_api/transform.h b/libcamera-sys/c_api/transform.h new file mode 100644 index 0000000..d3a3c09 --- /dev/null +++ b/libcamera-sys/c_api/transform.h @@ -0,0 +1,45 @@ +#ifndef __LIBCAMERA_C_TRANSFORM__ +#define __LIBCAMERA_C_TRANSFORM__ + +#include +#include + +#include "camera.h" + +struct libcamera_transform { + uint32_t value; +}; + +typedef struct libcamera_transform libcamera_transform_t; + +#ifdef __cplusplus +#include "camera.h" +#include + +static_assert(sizeof(libcamera_transform_t) == sizeof(libcamera::Transform)); +static_assert(alignof(libcamera_transform_t) == alignof(libcamera::Transform)); + +extern "C" { +#endif + +libcamera_transform_t libcamera_transform_identity(); +libcamera_transform_t libcamera_transform_from_rotation(int angle, bool hflip, bool *success); +libcamera_transform_t libcamera_transform_inverse(libcamera_transform_t transform); +libcamera_transform_t libcamera_transform_combine(libcamera_transform_t a, libcamera_transform_t b); +char *libcamera_transform_to_string(libcamera_transform_t transform); +libcamera_transform_t libcamera_transform_between_orientations(libcamera_orientation_t from, libcamera_orientation_t to); +libcamera_orientation_t libcamera_transform_apply_orientation(libcamera_orientation_t orientation, libcamera_transform_t transform); +libcamera_orientation_t libcamera_orientation_from_rotation(int angle, bool *success); +libcamera_transform_t libcamera_transform_hflip(); +libcamera_transform_t libcamera_transform_vflip(); +libcamera_transform_t libcamera_transform_transpose(); +libcamera_transform_t libcamera_transform_or(libcamera_transform_t a, libcamera_transform_t b); +libcamera_transform_t libcamera_transform_and(libcamera_transform_t a, libcamera_transform_t b); +libcamera_transform_t libcamera_transform_xor(libcamera_transform_t a, libcamera_transform_t b); +libcamera_transform_t libcamera_transform_not(libcamera_transform_t t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libcamera-sys/c_api/version.cpp b/libcamera-sys/c_api/version.cpp new file mode 100644 index 0000000..aa20e1e --- /dev/null +++ b/libcamera-sys/c_api/version.cpp @@ -0,0 +1,11 @@ +#include "version.h" + +#include + +extern "C" { + +const char *libcamera_version_string() { + return libcamera::CameraManager::version().c_str(); +} + +} diff --git a/libcamera-sys/c_api/version.h b/libcamera-sys/c_api/version.h index e4a43cc..6367664 100644 --- a/libcamera-sys/c_api/version.h +++ b/libcamera-sys/c_api/version.h @@ -1 +1,12 @@ #include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns the libcamera version string without requiring a CameraManager instance. */ +const char *libcamera_version_string(); + +#ifdef __cplusplus +} +#endif diff --git a/libcamera/Cargo.toml b/libcamera/Cargo.toml index 163c4e4..82e9e7d 100644 --- a/libcamera/Cargo.toml +++ b/libcamera/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libcamera" -version = "0.4.0" +version = "0.6.0" edition = "2021" description = "Safe Rust bindings for libcamera" documentation = "https://docs.rs/libcamera" @@ -11,21 +11,21 @@ categories = ["api-bindings", "computer-vision", "multimedia"] readme = "../README.md" [features] -default = ["vendor_draft", "libcamera_semver_versioning"] +default = ["libcamera_semver_versioning"] # Fallback to semver compatible libcamera control/property bindings when exact version is unavailable libcamera_semver_versioning = [] -# Enables draft vendor control/property extensions +# Enables draft vendor control/property extensions (requires headers that define LIBCAMERA_HAS_* vendor controls) vendor_draft = [] -# Enables Raspbbery Pi control/property extensions +# Enables Raspbbery Pi control/property extensions (requires headers that define LIBCAMERA_HAS_* vendor controls) vendor_rpi = [] [dependencies] bitflags = "2.0.0-rc.2" drm-fourcc = "2.2" libc = "0.2" -libcamera-sys = { path = "../libcamera-sys", version = "0.5.0", default-features = false } +libcamera-sys = { path = "../libcamera-sys", version = "0.6.0", default-features = false } num_enum = "0.6.1" smallvec = "1.10" thiserror = "1.0" @@ -33,3 +33,11 @@ thiserror = "1.0" [build-dependencies] semver = "1.0.22" pkg-config = "0.3" + +[dev-dependencies] +tokio = { version = "1", features = ["rt-multi-thread", "macros", "time", "sync"] } + +[[example]] +name = "vendor_features" +path = "examples/vendor_features.rs" +required-features = ["vendor_draft"] diff --git a/libcamera/build.rs b/libcamera/build.rs index 99abc03..45d832f 100644 --- a/libcamera/build.rs +++ b/libcamera/build.rs @@ -1,12 +1,13 @@ use core::panic; use std::{ - env, + env, fs, path::{Path, PathBuf}, }; use semver::{Comparator, Op, Version}; fn main() { + println!("cargo:rustc-check-cfg=cfg(libcamera_has_vendor_controls)"); let libcamera = match pkg_config::probe_library("libcamera") { Ok(lib) => Ok(lib), Err(e) => { @@ -55,7 +56,7 @@ fn main() { pre: Default::default(), }; - comparator.matches(&libcamera_version) + comparator.matches(&libcamera_version) && candidate <= &libcamera_version }); // And take the most recent compatible version @@ -73,11 +74,102 @@ fn main() { let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - for file in ["controls.rs", "properties.rs"] { + for file in ["controls.rs", "properties.rs", "pixel_format_info.rs"] { std::fs::copy(selected_version.join(file), out_path.join(file)).unwrap(); print!( "cargo:rerun-if-changed={}", selected_version.join(file).to_string_lossy() ); } + + // Generate vendor feature flags from libcamera's generated control_ids.h + let control_ids_header = libcamera + .include_paths + .first() + .map(|p| p.join("libcamera/control_ids.h")) + .expect("Unable to get libcamera include path"); + let header_contents = fs::read_to_string(&control_ids_header).expect("Failed to read libcamera/control_ids.h"); + let mut vendor_controls_present = false; + let mut feature_consts = String::new(); + for line in header_contents.lines() { + if let Some(rest) = line.trim().strip_prefix("#define LIBCAMERA_HAS_") { + let name = rest.split_whitespace().next().unwrap_or("").trim(); + if name.is_empty() { + continue; + } + feature_consts.push_str(&format!("pub const LIBCAMERA_HAS_{}: bool = true;\n", name)); + if name.contains("LIBCAMERA_VENDOR_CONTROLS") { + vendor_controls_present = true; + } + } + } + let features_rs = out_path.join("vendor_features.rs"); + fs::write(&features_rs, feature_consts).expect("Failed to write vendor_features.rs"); + println!("cargo:rerun-if-changed={}", control_ids_header.to_string_lossy()); + if vendor_controls_present { + println!("cargo:rustc-cfg=libcamera_has_vendor_controls"); + } + + // Generate pixel format constants from libcamera/formats.h + let formats_header = libcamera + .include_paths + .first() + .map(|p| p.join("libcamera/formats.h")) + .expect("Unable to get libcamera include path"); + let formats_contents = fs::read_to_string(&formats_header).expect("Failed to read libcamera/formats.h"); + let mut generated = String::from( + "// Auto-generated from libcamera/formats.h\n\ +#[allow(unused_imports)]\n\ +use crate::pixel_format::PixelFormat;\n\n", + ); + for line in formats_contents.lines() { + let line = line.trim(); + if !line.starts_with("constexpr PixelFormat") { + continue; + } + let name_start = "constexpr PixelFormat ".len(); + let name_end = match line[name_start..].find('(') { + Some(idx) => name_start + idx, + None => continue, + }; + let name = &line[name_start..name_end]; + let rest = &line[name_end + 1..]; + let parts: Vec<&str> = rest.split("__mod(").collect(); + if parts.len() < 2 { + continue; + } + let fourcc_part = parts[0].trim_end_matches(", "); + let mod_part = parts[1]; + + let big_endian = fourcc_part.contains("kDrmFormatBigEndian"); + let fourcc_inner_start = "__fourcc(".len(); + let fourcc_inner = &fourcc_part[fourcc_inner_start..] + .trim_start_matches("__fourcc(") + .trim_end_matches(')') + .trim(); + let chars: Vec = fourcc_inner + .split(',') + .filter_map(|c| c.trim().trim_matches('\'').chars().next().map(|ch| ch as u32)) + .collect(); + if chars.len() != 4 { + continue; + } + let mut fourcc: u32 = chars[0] | (chars[1] << 8) | (chars[2] << 16) | (chars[3] << 24); + if big_endian { + fourcc |= 1u32 << 31; + } + + let mod_inner = mod_part.split(')').next().unwrap_or("").trim().trim_start_matches('('); + let mut mod_nums = mod_inner.split(',').map(|s| s.trim().parse::().unwrap_or(0)); + let vendor = mod_nums.next().unwrap_or(0); + let modifier = mod_nums.next().unwrap_or(0); + let modifier = (vendor << 56) | modifier; + + generated.push_str(&format!( + "pub const {name}: PixelFormat = PixelFormat::new(0x{fourcc:08x}, 0x{modifier:016x});\n", + )); + } + let formats_rs = out_path.join("formats.rs"); + fs::write(&formats_rs, generated).expect("Failed to write formats.rs"); + println!("cargo:rerun-if-changed={}", formats_header.to_string_lossy()); } diff --git a/libcamera/examples/buffer_completed.rs b/libcamera/examples/buffer_completed.rs new file mode 100644 index 0000000..188daa5 --- /dev/null +++ b/libcamera/examples/buffer_completed.rs @@ -0,0 +1,75 @@ +//! Demonstrates listening for per-buffer completion and disconnected callbacks. +use std::{sync::mpsc, time::Duration}; + +use libcamera::{ + camera_manager::CameraManager, framebuffer_allocator::FrameBufferAllocator, request::ReuseFlag, stream::StreamRole, +}; + +fn main() { + let mgr = CameraManager::new().expect("camera manager"); + let cameras = mgr.cameras(); + let mut cam = cameras.iter().next().expect("no cameras").acquire().unwrap(); + + let (tx_req, rx_req) = mpsc::channel(); + let (tx_buf, rx_buf) = mpsc::channel(); + let (tx_disc, rx_disc) = mpsc::channel(); + + cam.on_request_completed(move |req| { + tx_req.send(req).unwrap(); + }); + + cam.on_buffer_completed(move |req, stream| { + // Buffer cookies/metadata can be inspected here; print sequence for demo. + tx_buf.send((req.sequence(), stream)).unwrap(); + // For reuse, do nothing; the request will complete later. + }); + + cam.on_disconnected(move || { + let _ = tx_disc.send(()); + }); + + // Configure a simple viewfinder stream. + let roles = [StreamRole::ViewFinder]; + let mut cfg = cam.generate_configuration(&roles).expect("config"); + cfg.validate(); + cam.configure(&mut cfg).expect("configure"); + + let stream = cfg.get(0).and_then(|c| c.stream()).expect("stream"); + let mut alloc = FrameBufferAllocator::new(&cam); + let buffers = alloc.alloc(&stream).expect("alloc"); + + let mut reqs = buffers + .into_iter() + .enumerate() + .map(|(i, buf)| { + let mut req = cam.create_request(Some(i as u64)).unwrap(); + req.add_buffer(&stream, buf).unwrap(); + req + }) + .collect::>(); + + cam.start(None).expect("start"); + for req in reqs.drain(..) { + cam.queue_request(req).map_err(|(_, e)| e).unwrap(); + } + + let mut completed = 0; + while completed < 5 { + if let Ok((seq, _stream)) = rx_buf.recv_timeout(Duration::from_secs(2)) { + println!("bufferCompleted for request seq {}", seq); + } + if let Ok(mut req) = rx_req.recv_timeout(Duration::from_millis(500)) { + println!("requestCompleted seq {}", req.sequence()); + req.reuse(ReuseFlag::REUSE_BUFFERS); + cam.queue_request(req).map_err(|(_, e)| e).unwrap(); + completed += 1; + } + if rx_disc.try_recv().is_ok() { + println!("Camera disconnected"); + break; + } + } + + cam.stop().ok(); + println!("Done."); +} diff --git a/libcamera/examples/camera_control_id_info.rs b/libcamera/examples/camera_control_id_info.rs index 709b969..b12abd3 100644 --- a/libcamera/examples/camera_control_id_info.rs +++ b/libcamera/examples/camera_control_id_info.rs @@ -21,6 +21,7 @@ fn main() { println!(" Is Input: {:#?}", id.is_input()); println!(" Is Output: {:#?}", id.is_output()); println!(" Enumarators: {:?}", id.enumerators_map()); + println!(" Description: {}", id.description()); } } } diff --git a/libcamera/examples/color_space.rs b/libcamera/examples/color_space.rs new file mode 100644 index 0000000..df6d692 --- /dev/null +++ b/libcamera/examples/color_space.rs @@ -0,0 +1,41 @@ +use libcamera::{ + camera_manager::CameraManager, + color_space::{ColorSpace, Primaries, Range, TransferFunction, YcbcrEncoding}, + logging::LoggingLevel, + stream::StreamRole, +}; + +fn main() { + let mgr = CameraManager::new().expect("camera manager"); + mgr.log_set_level("Camera", LoggingLevel::Error); + let cameras = mgr.cameras(); + let cam = cameras.iter().next().expect("no cameras found"); + + let mut cfgs = cam + .generate_configuration(&[StreamRole::ViewFinder]) + .expect("generate configuration"); + { + let mut cfg = cfgs.get_mut(0).expect("cfg"); + + // Inspect existing color space if present + println!("Original color space: {:?}", cfg.get_color_space()); + + // Set Rec709 with limited range as an example + let cs = ColorSpace::new( + Primaries::Rec709, + TransferFunction::Rec709, + YcbcrEncoding::Rec709, + Range::Limited, + ); + cfg.set_color_space(Some(cs)); + println!("Requested color space: {:?}", cfg.get_color_space()); + } + + // Apply configuration to have libcamera validate it + let status = cfgs.validate(); + println!("Validation status: {:?}", status); + println!( + "Validated color space: {:?}", + cfgs.get(0).expect("cfg").get_color_space() + ); +} diff --git a/libcamera/examples/color_space_adjust.rs b/libcamera/examples/color_space_adjust.rs new file mode 100644 index 0000000..5d84875 --- /dev/null +++ b/libcamera/examples/color_space_adjust.rs @@ -0,0 +1,18 @@ +//! Show cloning and adjusting color spaces without mutating the original. +use libcamera::{color_space::ColorSpace, pixel_format::PixelFormat}; + +fn main() { + let src = ColorSpace::rec709(); + let pf = PixelFormat::parse("YUYV").expect("parse"); + println!("source color space: {}", src); + let (adjusted, changed) = { + let mut clone = src; + let changed = clone.adjust_for_format(pf); + (clone, changed) + }; + println!( + "{} for {pf:?}: {}", + if changed { "adjusted" } else { "already compatible" }, + adjusted + ); +} diff --git a/libcamera/examples/color_space_parse.rs b/libcamera/examples/color_space_parse.rs new file mode 100644 index 0000000..03b536e --- /dev/null +++ b/libcamera/examples/color_space_parse.rs @@ -0,0 +1,24 @@ +//! Parse and adjust color spaces and pixel formats from strings. +use std::str::FromStr; + +use libcamera::{color_space::ColorSpace, pixel_format::PixelFormat}; + +fn main() { + let cs = ColorSpace::rec709(); + let cs_str = cs.to_repr(); + let pf_str = "YUYV"; + + let mut cs = ColorSpace::from_string(&cs_str).expect("parse color space"); + let pf = PixelFormat::from_str(pf_str).expect("parse pixel format"); + + println!("Parsed color space: {}", cs); + println!("Parsed pixel format: {:?}", pf); + + let adjusted = cs.adjust_for_format(pf); + println!( + "{} color space for {}: {}", + if adjusted { "Adjusted" } else { "Already compatible" }, + pf_str, + cs + ); +} diff --git a/libcamera/examples/configure_formats.rs b/libcamera/examples/configure_formats.rs new file mode 100644 index 0000000..f730c7e --- /dev/null +++ b/libcamera/examples/configure_formats.rs @@ -0,0 +1,37 @@ +//! Configure a stream using a common pixel format (NV12 if available) and inspect the result. +use libcamera::{camera_manager::CameraManager, geometry::Size, pixel_format::PixelFormat, stream::StreamRole}; + +fn main() { + let mgr = CameraManager::new().expect("camera manager"); + let cameras = mgr.cameras(); + let Some(cam) = cameras.get(0) else { + eprintln!("No cameras available"); + return; + }; + let mut cam = cam.acquire().expect("acquire"); + + let mut config = cam + .generate_configuration(&[StreamRole::ViewFinder]) + .expect("generate config"); + + if let Some(mut cfg) = config.get_mut(0) { + let nv12 = PixelFormat::parse("NV12").unwrap_or_else(|| { + eprintln!("NV12 not available; leaving pixel format unchanged"); + cfg.get_pixel_format() + }); + cfg.set_pixel_format(nv12); + cfg.set_size(Size::new(640, 480)); + } + + let status = config.validate(); + println!("validate status: {status:?}"); + cam.configure(&mut config).expect("configure"); + if let Some(cfg) = config.get(0) { + println!( + "configured: {:?}, stride={} frame_size={}", + cfg, + cfg.get_stride(), + cfg.get_frame_size() + ); + } +} diff --git a/libcamera/examples/control_list_ops.rs b/libcamera/examples/control_list_ops.rs new file mode 100644 index 0000000..87491d1 --- /dev/null +++ b/libcamera/examples/control_list_ops.rs @@ -0,0 +1,35 @@ +//! Demonstrates ControlList helpers: contains/len/merge and string array ControlValue support. +use libcamera::{ + control::{ControlList, MergePolicy}, + control_value::ControlValue, + properties::PropertyId, +}; + +fn main() { + // Build a control list with a string array value to exercise ControlValue string handling. + let mut base = ControlList::new(); + let tags = vec!["alpha".to_string(), "beta".to_string()]; + base.set_raw(PropertyId::Model as u32, ControlValue::from(tags)) + .unwrap(); + + println!( + "Base list len={} contains Model? {}", + base.len(), + base.contains(PropertyId::Model as u32) + ); + + // Merge another list with a different value for the same id. + let mut override_list = ControlList::new(); + override_list + .set_raw(PropertyId::Model as u32, ControlValue::from("override".to_string())) + .unwrap(); + + base.merge(&override_list, MergePolicy::OverwriteExisting); + if let Ok(ControlValue::String(v)) = base.get_raw(PropertyId::Model as u32) { + println!("After merge (overwrite), model entries: {:?}", v.into_vec()); + } + + // Clear/reset. + base.clear(); + println!("After clear, is_empty? {}", base.is_empty()); +} diff --git a/libcamera/examples/fence_capture.rs b/libcamera/examples/fence_capture.rs new file mode 100644 index 0000000..504c0dd --- /dev/null +++ b/libcamera/examples/fence_capture.rs @@ -0,0 +1,108 @@ +//! Demonstrates using acquire fences when queuing requests and releasing fences from framebuffers. +use std::{os::fd::AsRawFd, time::Duration}; + +use libc::{poll, pollfd, POLLIN}; +use libcamera::{ + camera_manager::CameraManager, + fence::Fence, + framebuffer::AsFrameBuffer, + framebuffer_allocator::{FrameBuffer, FrameBufferAllocator}, + framebuffer_map::MemoryMappedFrameBuffer, + logging::LoggingLevel, + request::ReuseFlag, + stream::StreamRole, +}; + +fn main() { + let mgr = CameraManager::new().expect("manager"); + let cameras = mgr.cameras(); + let mut cam = cameras.iter().next().expect("no cameras").acquire().unwrap(); + // Set global logging to reduce noise. + // Note: log_set_level is on CameraManager. + mgr.log_set_level("Camera", LoggingLevel::Error); + + // Try roles in order until we get a usable stream. + let roles_to_try = [ + StreamRole::VideoRecording, + StreamRole::ViewFinder, + StreamRole::StillCapture, + ]; + let (mut cfgs, _role) = cam + .generate_first_supported_configuration(&roles_to_try) + .unwrap_or_else(|| { + eprintln!("No usable stream found for any role; exiting."); + std::process::exit(1); + }); + cfgs.validate(); + + cam.configure(&mut cfgs).expect("configure"); + + let mut alloc = FrameBufferAllocator::new(&cam); + let stream = cfgs.get(0).and_then(|cfg| cfg.stream()).expect("stream"); + let buffers = alloc.alloc(&stream).expect("alloc buffers"); + println!("Allocated {} buffers", buffers.len()); + + // Wrap buffers to get mmap access + let buffers = buffers + .into_iter() + .map(|buf| MemoryMappedFrameBuffer::new(buf).unwrap()) + .collect::>(); + + // Create requests with fence-capable path (no acquire fences in this example). + let mut reqs = buffers + .into_iter() + .enumerate() + .map(|(i, buf)| { + let mut req = cam.create_request(Some(i as u64)).unwrap(); + req.add_buffer_with_fence(&stream, buf, None::).unwrap(); + req + }) + .collect::>(); + + // Subscribe to completion + let (tx, rx) = std::sync::mpsc::channel(); + cam.on_request_completed(move |req| { + tx.send(req).unwrap(); + }); + + cam.start(None).unwrap(); + + for req in reqs.drain(..) { + cam.queue_request(req).map_err(|(_, e)| e).unwrap(); + } + + // Recycle buffers a few times to show waiting on release fences before reuse. + for _ in 0..5 { + println!("Waiting for camera request execution"); + let mut req = match rx.recv_timeout(Duration::from_secs(5)) { + Ok(r) => r, + Err(_) => { + eprintln!("Timed out waiting for a request; camera may not be delivering frames."); + break; + } + }; + println!("Request {} completed", req.sequence()); + let fb: &MemoryMappedFrameBuffer = req.buffer(&stream).unwrap(); + println!("Metadata: {:#?}", fb.metadata()); + + if let Some(fence) = fb.release_fence() { + let fence_fd = fence.into_owned_fd().expect("dup release fence"); + let fd = fence_fd.as_raw_fd(); + let mut pfd = [pollfd { + fd, + events: POLLIN, + revents: 0, + }]; + println!("Waiting on release fence fd {}", fd); + unsafe { + let _ = poll(pfd.as_mut_ptr(), 1, 2000); + } + } else { + println!("No release fence for this buffer"); + } + + // Reuse the same request to demonstrate fence-aware recycling. + req.reuse(ReuseFlag::REUSE_BUFFERS); + cam.queue_request(req).map_err(|(_, e)| e).unwrap(); + } +} diff --git a/libcamera/examples/formats_constants.rs b/libcamera/examples/formats_constants.rs new file mode 100644 index 0000000..036f42d --- /dev/null +++ b/libcamera/examples/formats_constants.rs @@ -0,0 +1,32 @@ +//! Show generated libcamera pixel-format layout info for NV12 (if available). +use libcamera::{geometry::Size, pixel_format::PixelFormat}; + +fn main() { + let fmt = PixelFormat::parse("NV12").unwrap_or_else(|| { + eprintln!("NV12 not available in this libcamera build; pick another format"); + std::process::exit(0); + }); + println!("Using NV12 => {fmt:?}"); + + let size = Size { + width: 640, + height: 480, + }; + if let Some(info) = fmt.info() { + println!( + "name={} bits_per_pixel={} planes={} pixels_per_group={}", + info.name, + info.bits_per_pixel, + info.planes.len(), + info.pixels_per_group + ); + println!( + "frame size for {}x{} (align=0): {} bytes", + size.width, + size.height, + fmt.frame_size(size, 0) + ); + } else { + eprintln!("PixelFormatInfo unavailable; ensure libcamera headers are discoverable."); + } +} diff --git a/libcamera/examples/get_camera.rs b/libcamera/examples/get_camera.rs new file mode 100644 index 0000000..8695010 --- /dev/null +++ b/libcamera/examples/get_camera.rs @@ -0,0 +1,31 @@ +//! Fetch a camera by ID using CameraManager::get and print its model property. +use libcamera::{camera_manager::CameraManager, properties::Model}; + +fn main() { + let mgr = CameraManager::new().expect("camera manager"); + let cameras = mgr.cameras(); + + let first = match cameras.iter().next() { + Some(cam) => cam, + None => { + eprintln!("No cameras found"); + return; + } + }; + + let id = first.id().to_string(); + println!("First camera id: {}", id); + + let cam = match mgr.get(&id) { + Some(cam) => cam, + None => { + eprintln!("Camera with id {} not found via get()", id); + return; + } + }; + + match cam.properties().get::() { + Ok(model) => println!("Model: {}", model.0), + Err(e) => println!("Model property not available: {e}"), + } +} diff --git a/libcamera/examples/hotplug.rs b/libcamera/examples/hotplug.rs new file mode 100644 index 0000000..9886be4 --- /dev/null +++ b/libcamera/examples/hotplug.rs @@ -0,0 +1,16 @@ +use std::time::Duration; + +use libcamera::camera_manager::CameraManager; + +fn main() { + let mut mgr = CameraManager::new().expect("camera manager"); + let rx = mgr.subscribe_hotplug_events(); + + println!("Waiting for hotplug events. Press Ctrl+C to exit."); + loop { + if let Ok(evt) = rx.recv_timeout(Duration::from_secs(1)) { + println!("Event: {:?}", evt); + } + std::thread::sleep(Duration::from_secs(1)); + } +} diff --git a/libcamera/examples/import_dmabuf_capture.rs b/libcamera/examples/import_dmabuf_capture.rs new file mode 100644 index 0000000..c58cd1f --- /dev/null +++ b/libcamera/examples/import_dmabuf_capture.rs @@ -0,0 +1,81 @@ +//! Import a DMABUF framebuffer (memfd) and capture a single frame. +use std::{ + convert::TryInto, + io, + os::fd::{FromRawFd, OwnedFd}, + time::Duration, +}; + +use libcamera::{ + camera_manager::CameraManager, + framebuffer::{AsFrameBuffer, FrameBufferPlane, OwnedFrameBuffer}, + framebuffer_allocator::FrameBufferAllocator, + request::ReuseFlag, + stream::StreamRole, +}; + +fn main() -> io::Result<()> { + let mgr = CameraManager::new().expect("manager"); + let cameras = mgr.cameras(); + let mut cam = cameras.iter().next().expect("no cameras").acquire().unwrap(); + + // Configure viewfinder stream for simplicity. + let mut cfg = cam.generate_configuration(&[StreamRole::ViewFinder]).expect("config"); + cfg.validate(); + + cam.configure(&mut cfg).expect("configure"); + let stream = cfg.get(0).and_then(|c| c.stream()).expect("stream"); + + // Allocate a native buffer, then duplicate its DMABUF fds to create an imported framebuffer. + let mut alloc = FrameBufferAllocator::new(&cam); + let mut bufs = alloc.alloc(&stream).expect("alloc buffer"); + let src = bufs.pop().expect("at least one buffer"); + let planes = src.planes(); + + let mut plane_desc = Vec::new(); + for p in planes.into_iter() { + let fd = unsafe { libc::dup(p.fd()) }; + if fd < 0 { + return Err(io::Error::last_os_error()); + } + let len: u32 = p + .len() + .try_into() + .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "plane length overflow"))?; + plane_desc.push(FrameBufferPlane { + fd: unsafe { OwnedFd::from_raw_fd(fd) }, + offset: p.offset().unwrap_or(0) as u32, + length: len, + }); + } + + let fb = OwnedFrameBuffer::new(plane_desc, Some(123))?; + + let mut req = cam.create_request(Some(1)).expect("request"); + req.add_buffer(&stream, fb).expect("attach buffer"); + + let (tx, rx) = std::sync::mpsc::channel(); + cam.on_request_completed(move |r| { + let _ = tx.send(r); + }); + + cam.start(None)?; + cam.queue_request(req).map_err(|(_, e)| e)?; + + if let Ok(mut r) = rx.recv_timeout(Duration::from_secs(3)) { + println!("Captured request seq {}", r.sequence()); + if let Some(buf) = r.buffer_mut::(&stream) { + println!("Cookie: {}", buf.cookie()); + if let Some(meta) = buf.metadata() { + println!("Metadata: {:?}", meta); + } + } + // Ensure fences cleaned up before dropping + r.reuse(ReuseFlag::REUSE_BUFFERS); + } else { + eprintln!("Timed out waiting for capture"); + } + + cam.stop().ok(); + Ok(()) +} diff --git a/libcamera/examples/jpeg_capture.rs b/libcamera/examples/jpeg_capture.rs index 5f2aa87..8a8846a 100644 --- a/libcamera/examples/jpeg_capture.rs +++ b/libcamera/examples/jpeg_capture.rs @@ -86,10 +86,11 @@ fn main() { cam.start(None).unwrap(); // Multiple requests can be queued at a time, but for this example we just want a single frame. - cam.queue_request(reqs.pop().unwrap()).unwrap(); + cam.queue_request(reqs.pop().unwrap()).map_err(|(_, e)| e).unwrap(); println!("Waiting for camera request execution"); - let req = rx.recv_timeout(Duration::from_secs(2)).expect("Camera request failed"); + // Allow a bit more time for first exposure/conversion to complete on slower cameras. + let req = rx.recv_timeout(Duration::from_secs(5)).expect("Camera request failed"); println!("Camera request {req:?} completed!"); println!("Metadata: {:#?}", req.metadata()); diff --git a/libcamera/examples/list_cameras.rs b/libcamera/examples/list_cameras.rs index 4dbf5a4..f25e203 100644 --- a/libcamera/examples/list_cameras.rs +++ b/libcamera/examples/list_cameras.rs @@ -8,7 +8,7 @@ fn main() { let cameras = mgr.cameras(); for cam in cameras.iter() { - println!(""); + println!(); println!("ID: {}", cam.id()); println!("Properties: {:#?}", cam.properties()); diff --git a/libcamera/examples/logging.rs b/libcamera/examples/logging.rs index 2b54431..bfa4bb4 100644 --- a/libcamera/examples/logging.rs +++ b/libcamera/examples/logging.rs @@ -1,4 +1,6 @@ -use libcamera::logging::{log_set_file, log_set_stream, log_set_target, LoggingStream, LoggingTarget}; +use libcamera::logging::{ + configure_stderr, log_set_file, log_set_stream, log_set_target, LoggingLevel, LoggingStream, LoggingTarget, +}; fn main() { // Disable all logging output @@ -12,4 +14,7 @@ fn main() { // Log to stdout instead of the default stderr log_set_stream(LoggingStream::StdOut, true).expect("Can't set logging to stdout"); + + // Convenience: log Camera category to stderr with INFO level + configure_stderr("Camera", LoggingLevel::Info, true).expect("failed to configure stderr logging"); } diff --git a/libcamera/examples/logging_stdout.rs b/libcamera/examples/logging_stdout.rs new file mode 100644 index 0000000..3d4b826 --- /dev/null +++ b/libcamera/examples/logging_stdout.rs @@ -0,0 +1,8 @@ +//! Configure logging to stdout without creating a CameraManager. +use libcamera::logging::{configure_stdout, LoggingLevel}; + +fn main() { + // Direct libcamera logs to stdout and set the Camera category to INFO. + configure_stdout("Camera", LoggingLevel::Info, false).expect("configure stdout logging"); + println!("Logging configured for category \"Camera\" to stdout at INFO level."); +} diff --git a/libcamera/examples/manager_lifecycle.rs b/libcamera/examples/manager_lifecycle.rs new file mode 100644 index 0000000..7377a57 --- /dev/null +++ b/libcamera/examples/manager_lifecycle.rs @@ -0,0 +1,44 @@ +use libcamera::camera_manager::CameraManager; + +fn main() -> Result<(), Box> { + // Build a manager without auto-starting, then start it. + let mut mgr = CameraManager::new_unstarted()?; + println!("started? {}", mgr.is_started()); + mgr.start()?; + println!("started after start()? {}", mgr.is_started()); + + // Hold on to a camera to show try_stop() refusing to stop while handles exist. + let first_camera_id = { + let cameras = mgr.cameras(); + println!("found {} cameras", cameras.len()); + if let Some(cam) = cameras.get(0) { + println!("first camera id: {}", cam.id()); + match mgr.try_stop() { + Ok(()) => println!("unexpectedly stopped with live camera"), + Err(e) => println!("try_stop() while camera alive -> {}", e), + } + Some(cam.id().to_string()) + } else { + None + } + // cameras drops here; any tracked handles go away too. + }; + + // Now it is safe to stop. + mgr.try_stop()?; + println!("stopped cleanly, started? {}", mgr.is_started()); + + // Demonstrate restart: stop (succeeds because no cameras alive) then start again. + mgr.restart()?; + println!("restarted, started? {}", mgr.is_started()); + + if let Some(id) = first_camera_id { + if let Some(cam) = mgr.get(&id) { + println!("camera {} still present after restart", cam.id()); + } else { + println!("camera {} not found after restart", id); + } + } + + Ok(()) +} diff --git a/libcamera/examples/mmap_info.rs b/libcamera/examples/mmap_info.rs new file mode 100644 index 0000000..27e68d1 --- /dev/null +++ b/libcamera/examples/mmap_info.rs @@ -0,0 +1,42 @@ +//! Demonstrates writable mappings and mapped length reporting for OwnedFrameBuffer. +use std::{ + io::Write, + os::fd::{FromRawFd, OwnedFd}, +}; + +use libcamera::{ + framebuffer::{AsFrameBuffer, FrameBufferPlane, OwnedFrameBuffer}, + framebuffer_map::MemoryMappedFrameBuffer, +}; + +fn main() { + // Create a simple memfd-backed plane + let fd: OwnedFd = unsafe { + let name = std::ffi::CString::new("libcamera-mmap-info").unwrap(); + let fd = libc::memfd_create(name.as_ptr(), 0); + if fd < 0 { + panic!("memfd_create failed: {}", std::io::Error::last_os_error()); + } + let mut f = std::fs::File::from_raw_fd(fd); + f.write_all(&vec![0u8; 4096]).expect("write memfd"); + f.into() + }; + + let plane = FrameBufferPlane { + fd, + offset: 0, + length: 4096, + }; + + let fb = OwnedFrameBuffer::new(vec![plane], None).expect("owned framebuffer"); + let mut mapped = MemoryMappedFrameBuffer::new_writable(fb).expect("map"); + println!("is_writable: {}", mapped.is_writable()); + let fd = mapped.planes().into_iter().next().unwrap().fd(); + println!("mapped_len for fd {}: {:?}", fd, mapped.mapped_len(fd)); + + // Mutate the buffer through the mapping + if let Ok(mut planes) = mapped.data_mut() { + planes[0][0] = 0xAB; + println!("first byte after write: {:#04x}", planes[0][0]); + } +} diff --git a/libcamera/examples/multi_stream_clone.rs b/libcamera/examples/multi_stream_clone.rs new file mode 100644 index 0000000..2480b1d --- /dev/null +++ b/libcamera/examples/multi_stream_clone.rs @@ -0,0 +1,27 @@ +//! Demonstrates building a multi-stream configuration by cloning a validated stream config. +use libcamera::{camera_manager::CameraManager, stream::StreamRole}; + +fn main() { + let cm = CameraManager::new().expect("camera manager"); + let cams = cm.cameras(); + let Some(cam) = cams.get(0) else { + eprintln!("No cameras available."); + return; + }; + + let mut config = cam + .generate_configuration(&[StreamRole::ViewFinder]) + .expect("generate base config"); + let template_cfg = cam + .generate_configuration(&[StreamRole::ViewFinder]) + .expect("generate template config"); + + // Clone the first stream config to append another stream (for example, a second viewfinder). + let base = template_cfg.get(0).expect("base stream"); + let added = config.add_configurations_like(&[base.value()]); + println!("Appended {} cloned stream(s).", added.len()); + + let status = config.validate(); + println!("validate() => {status:?}"); + println!("Final configuration: {}", config.to_string_repr()); +} diff --git a/libcamera/examples/orientation_helpers.rs b/libcamera/examples/orientation_helpers.rs new file mode 100644 index 0000000..ecb2f5c --- /dev/null +++ b/libcamera/examples/orientation_helpers.rs @@ -0,0 +1,23 @@ +//! Demonstrates orientation helpers wrapping libcamera::orientationFromRotation and transform composition. +use libcamera::{ + camera::Orientation, + transform::{apply_transform_to_orientation, orientation_from_rotation, Transform}, +}; + +fn main() { + // Map a rotation to an EXIF orientation. + for angle in [0, 90, 180, 270] { + let ori = orientation_from_rotation(angle).expect("angle should be valid"); + println!("rotation {} => orientation {:?}", angle, ori); + } + + // Combine orientations via transforms. + let from = Orientation::Rotate0; + let to = Orientation::Rotate90; + let t = Transform::between_orientations(from, to); + println!("Transform from {:?} to {:?}: {}", from, to, t); + + // Apply an arbitrary transform to an orientation. + let rotated = apply_transform_to_orientation(Orientation::Rotate90, Transform::from_rotation(180, false).unwrap()); + println!("Rotate90 with extra 180deg => {:?}", rotated); +} diff --git a/libcamera/examples/owned_framebuffer.rs b/libcamera/examples/owned_framebuffer.rs new file mode 100644 index 0000000..0f95e54 --- /dev/null +++ b/libcamera/examples/owned_framebuffer.rs @@ -0,0 +1,47 @@ +//! Demonstrates constructing an OwnedFrameBuffer from user-provided DMABUFs and using cookies. +use std::{ + ffi::CString, + io, + os::fd::{FromRawFd, OwnedFd}, +}; + +use libc::{c_char, ftruncate}; +use libcamera::framebuffer::{AsFrameBuffer, FrameBufferPlane, OwnedFrameBuffer}; + +fn create_memfd(name: &str, size: usize) -> io::Result { + // Safe: passing null-terminated name and flags, checked for errors. + let fd = unsafe { libc::memfd_create(CString::new(name).unwrap().as_ptr() as *const c_char, libc::MFD_CLOEXEC) }; + if fd < 0 { + return Err(io::Error::last_os_error()); + } + + let ret = unsafe { ftruncate(fd, size as i64) }; + if ret < 0 { + unsafe { libc::close(fd) }; + return Err(io::Error::last_os_error()); + } + + // Safety: fd is valid and now owned by OwnedFd. + Ok(unsafe { OwnedFd::from_raw_fd(fd) }) +} + +fn main() -> io::Result<()> { + const SIZE: usize = 1024 * 1024; + let plane_fd = create_memfd("libcamera_owned_fb", SIZE)?; + + let fb = OwnedFrameBuffer::new( + vec![FrameBufferPlane { + fd: plane_fd, + offset: 0, + length: SIZE as u32, + }], + Some(42), + )?; + + println!("Initial cookie: {}", fb.cookie()); + fb.set_cookie(1337); + println!("Updated cookie: {}", fb.cookie()); + println!("Plane descriptors: {:?}", fb.planes()); + + Ok(()) +} diff --git a/libcamera/examples/pixel_format_roundtrip.rs b/libcamera/examples/pixel_format_roundtrip.rs new file mode 100644 index 0000000..934ef3c --- /dev/null +++ b/libcamera/examples/pixel_format_roundtrip.rs @@ -0,0 +1,10 @@ +//! Demonstrates round-tripping PixelFormat fourcc/modifier pairs. +use libcamera::pixel_format::PixelFormat; + +fn main() { + let fmt = PixelFormat::parse("XRGB8888").expect("parse"); + let (fourcc, modifier) = fmt.to_raw(); + let rebuilt = PixelFormat::from_raw_parts(fourcc, modifier); + println!("original={fmt:?} fourcc=0x{fourcc:08x} modifier=0x{modifier:016x}"); + println!("rebuilt equals original? {}", rebuilt == fmt); +} diff --git a/libcamera/examples/request_introspect.rs b/libcamera/examples/request_introspect.rs new file mode 100644 index 0000000..11bf828 --- /dev/null +++ b/libcamera/examples/request_introspect.rs @@ -0,0 +1,41 @@ +//! Introspect request buffer map and to_string(). +use std::io; + +use libcamera::{ + camera_manager::CameraManager, framebuffer_allocator::FrameBufferAllocator, request::ReuseFlag, stream::StreamRole, +}; + +fn main() -> io::Result<()> { + let mgr = CameraManager::new().expect("camera manager"); + let cameras = mgr.cameras(); + let mut cam = cameras.iter().next().expect("no cameras").acquire().unwrap(); + + let mut cfg = cam.generate_configuration(&[StreamRole::ViewFinder]).expect("config"); + cfg.validate(); + cam.configure(&mut cfg).expect("configure"); + let stream = cfg.get(0).and_then(|c| c.stream()).expect("stream"); + + let mut alloc = FrameBufferAllocator::new(&cam); + let mut bufs = alloc.alloc(&stream).expect("alloc buffers"); + let buf = bufs.pop().expect("at least one buffer"); + + let mut req = cam.create_request(Some(99)).expect("request"); + req.add_buffer(&stream, buf).expect("attach buffer"); + + println!("Request before queue:"); + println!("has_pending_buffers = {}", req.has_pending_buffers()); + println!("find_buffer is Some: {}", req.find_buffer(&stream).is_some()); + println!("to_string: {}", req.to_string_repr()); + + println!("Buffer map entries:"); + for (_s, fb_ptr) in req.buffers_iter() { + println!(" buffer ptr {:?}", fb_ptr); + } + + // Demonstrate reuse without queueing. + req.reuse(ReuseFlag::REUSE_BUFFERS); + println!("After reuse, has_pending_buffers = {}", req.has_pending_buffers()); + + // Drop request/buffer without queueing to keep example simple. + Ok(()) +} diff --git a/libcamera/examples/request_introspect_capture.rs b/libcamera/examples/request_introspect_capture.rs new file mode 100644 index 0000000..b910354 --- /dev/null +++ b/libcamera/examples/request_introspect_capture.rs @@ -0,0 +1,47 @@ +//! Introspect a request and run a single capture to observe live status. +use std::time::Duration; + +use libcamera::{ + camera_manager::CameraManager, framebuffer_allocator::FrameBufferAllocator, request::ReuseFlag, stream::StreamRole, +}; + +fn main() { + let mgr = CameraManager::new().expect("camera manager"); + let cameras = mgr.cameras(); + let mut cam = cameras.iter().next().expect("no cameras").acquire().unwrap(); + + let mut cfg = cam.generate_configuration(&[StreamRole::ViewFinder]).expect("config"); + cfg.validate(); + cam.configure(&mut cfg).expect("configure"); + let stream = cfg.get(0).and_then(|c| c.stream()).expect("stream"); + + let mut alloc = FrameBufferAllocator::new(&cam); + let buf = alloc.alloc(&stream).expect("alloc").pop().expect("buffer"); + + let mut req = cam.create_request(Some(99)).expect("request"); + req.add_buffer(&stream, buf).expect("attach buffer"); + + println!("Before queue: {}", req.to_string_repr()); + for (_s, fb_ptr) in req.buffers_iter() { + println!(" buf_ptr {:?}", fb_ptr); + } + + let (tx, rx) = std::sync::mpsc::channel(); + cam.on_request_completed(move |r| { + let _ = tx.send(r); + }); + + cam.start(None).expect("start"); + cam.queue_request(req).map_err(|(_, e)| e).expect("queue"); + + match rx.recv_timeout(Duration::from_secs(3)) { + Ok(mut r) => { + println!("Completed: {}", r.to_string_repr()); + println!("has_pending_buffers = {}", r.has_pending_buffers()); + r.reuse(ReuseFlag::REUSE_BUFFERS); + } + Err(_) => eprintln!("Timed out waiting for request completion"), + } + + cam.stop().ok(); +} diff --git a/libcamera/examples/sensor_config_readback.rs b/libcamera/examples/sensor_config_readback.rs new file mode 100644 index 0000000..4ea37b4 --- /dev/null +++ b/libcamera/examples/sensor_config_readback.rs @@ -0,0 +1,46 @@ +//! Demonstrates reading back sensor configuration after validation. +use libcamera::{camera_manager::CameraManager, geometry::Rectangle, stream::StreamRole}; + +fn main() { + let mgr = CameraManager::new().expect("camera manager"); + let cameras = mgr.cameras(); + let cam = match cameras.iter().next() { + Some(c) => c, + None => { + eprintln!("No cameras found"); + return; + } + }; + + let mut cfg = cam.generate_configuration(&[StreamRole::ViewFinder]).expect("config"); + cfg.validate(); + if let Some(stream_cfg) = cfg.get(0) { + println!("Stream cfg: {}", stream_cfg.to_string_repr()); + } + println!("Camera cfg: {}", cfg.to_string_repr()); + + if let Some(sensor_cfg) = cfg.sensor_configuration() { + println!("Sensor config valid: {}", sensor_cfg.is_valid()); + println!("Bit depth: {}", sensor_cfg.bit_depth()); + println!("Output size: {:?}", sensor_cfg.output_size()); + println!("Analog crop: {:?}", sensor_cfg.analog_crop()); + println!("Binning: {:?}", sensor_cfg.binning()); + println!("Skipping: {:?}", sensor_cfg.skipping()); + } else { + println!("No sensor configuration available"); + } + + // Example of setting analog crop then reading it back. + let mut sensor = cam + .generate_configuration(&[StreamRole::StillCapture]) + .unwrap() + .sensor_configuration() + .unwrap_or_default(); + sensor.set_analog_crop(Rectangle { + x: 0, + y: 0, + width: 640, + height: 480, + }); + println!("Set analog crop to {:?}", sensor.analog_crop()); +} diff --git a/libcamera/examples/vendor_features.rs b/libcamera/examples/vendor_features.rs new file mode 100644 index 0000000..ca5c816 --- /dev/null +++ b/libcamera/examples/vendor_features.rs @@ -0,0 +1,33 @@ +#![cfg(feature = "vendor_draft")] + +use libcamera::vendor_features::flat; + +fn main() { + println!("Vendor feature flags available:"); + + println!( + " {:<60} {}", + "LIBCAMERA_HAS_LIBCAMERA_VENDOR_CONTROLS_WDR_MODE", + flat::LIBCAMERA_HAS_LIBCAMERA_VENDOR_CONTROLS_WDR_MODE + ); + println!( + " {:<60} {}", + "LIBCAMERA_HAS_LIBCAMERA_VENDOR_CONTROLS_LENS_DEWARP_ENABLE", + flat::LIBCAMERA_HAS_LIBCAMERA_VENDOR_CONTROLS_LENS_DEWARP_ENABLE + ); + println!( + " {:<60} {}", + "LIBCAMERA_HAS_DRAFT_VENDOR_CONTROLS", + flat::LIBCAMERA_HAS_DRAFT_VENDOR_CONTROLS + ); + println!( + " {:<60} {}", + "LIBCAMERA_HAS_DEBUG_VENDOR_CONTROLS", + flat::LIBCAMERA_HAS_DEBUG_VENDOR_CONTROLS + ); +} + +#[cfg(not(feature = "vendor_draft"))] +fn main() { + eprintln!("Enable the `vendor_draft` feature to build this example."); +} diff --git a/libcamera/examples/video_capture.rs b/libcamera/examples/video_capture.rs index 881ec94..63caef0 100644 --- a/libcamera/examples/video_capture.rs +++ b/libcamera/examples/video_capture.rs @@ -97,7 +97,7 @@ fn main() { // Enqueue all requests to the camera for req in reqs { println!("Request queued for execution: {req:#?}"); - cam.queue_request(req).unwrap(); + cam.queue_request(req).map_err(|(_, e)| e).unwrap(); } let mut file = OpenOptions::new() @@ -108,7 +108,8 @@ fn main() { let mut count = 0; while count < 60 { println!("Waiting for camera request execution"); - let mut req = rx.recv_timeout(Duration::from_secs(2)).expect("Camera request failed"); + // Allow extra time for slower pipelines/first frame startup. + let mut req = rx.recv_timeout(Duration::from_secs(5)).expect("Camera request failed"); println!("Camera request {req:?} completed!"); println!("Metadata: {:#?}", req.metadata()); @@ -128,7 +129,7 @@ fn main() { // Recycle the request back to the camera for execution req.reuse(ReuseFlag::REUSE_BUFFERS); - cam.queue_request(req).unwrap(); + cam.queue_request(req).map_err(|(_, e)| e).unwrap(); count += 1; } diff --git a/libcamera/src/camera.rs b/libcamera/src/camera.rs index 95b369d..eb3e6b2 100644 --- a/libcamera/src/camera.rs +++ b/libcamera/src/camera.rs @@ -11,9 +11,11 @@ use std::{ use libcamera_sys::*; use crate::{ + camera_manager::CameraTracker, control::{ControlInfoMap, ControlList, PropertyList}, + geometry::{Rectangle, Size}, request::Request, - stream::{StreamConfigurationRef, StreamRole}, + stream::{Stream, StreamConfigurationRef, StreamRole}, utils::Immutable, }; @@ -55,6 +57,52 @@ impl TryFrom for CameraConfigurationSta } } +/// Desired orientation of the captured image. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Orientation { + Rotate0, + Rotate0Mirror, + Rotate180, + Rotate180Mirror, + Rotate90Mirror, + Rotate270, + Rotate270Mirror, + Rotate90, +} + +impl TryFrom for Orientation { + type Error = (); + + fn try_from(value: libcamera_orientation_t) -> Result { + match value { + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_0 => Ok(Self::Rotate0), + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_0_MIRROR => Ok(Self::Rotate0Mirror), + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_180 => Ok(Self::Rotate180), + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_180_MIRROR => Ok(Self::Rotate180Mirror), + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_90_MIRROR => Ok(Self::Rotate90Mirror), + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_270 => Ok(Self::Rotate270), + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_270_MIRROR => Ok(Self::Rotate270Mirror), + libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_90 => Ok(Self::Rotate90), + _ => Err(()), + } + } +} + +impl From for libcamera_orientation_t { + fn from(value: Orientation) -> Self { + match value { + Orientation::Rotate0 => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_0, + Orientation::Rotate0Mirror => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_0_MIRROR, + Orientation::Rotate180 => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_180, + Orientation::Rotate180Mirror => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_180_MIRROR, + Orientation::Rotate90Mirror => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_90_MIRROR, + Orientation::Rotate270 => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_270, + Orientation::Rotate270Mirror => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_270_MIRROR, + Orientation::Rotate90 => libcamera_orientation::LIBCAMERA_ORIENTATION_ROTATE_90, + } + } +} + pub struct SensorConfiguration { item: NonNull, } @@ -76,6 +124,57 @@ impl SensorConfiguration { pub fn set_output_size(&mut self, width: u32, height: u32) { unsafe { libcamera_sensor_configuration_set_output_size(self.item.as_ptr(), width, height) } } + + pub fn set_analog_crop(&mut self, crop: Rectangle) { + let rect: libcamera_rectangle_t = crop.into(); + unsafe { libcamera_sensor_configuration_set_analog_crop(self.item.as_ptr(), &rect) } + } + + pub fn set_binning(&mut self, x: u32, y: u32) { + unsafe { libcamera_sensor_configuration_set_binning(self.item.as_ptr(), x, y) } + } + + pub fn set_skipping(&mut self, x_odd: u32, x_even: u32, y_odd: u32, y_even: u32) { + unsafe { libcamera_sensor_configuration_set_skipping(self.item.as_ptr(), x_odd, x_even, y_odd, y_even) } + } + + pub fn is_valid(&self) -> bool { + unsafe { libcamera_sensor_configuration_is_valid(self.item.as_ptr()) } + } + + pub fn bit_depth(&self) -> u32 { + unsafe { libcamera_sensor_configuration_get_bit_depth(self.item.as_ptr()) } + } + + pub fn output_size(&self) -> Size { + let size = unsafe { libcamera_sensor_configuration_get_output_size(self.item.as_ptr()) }; + size.into() + } + + pub fn analog_crop(&self) -> Rectangle { + unsafe { libcamera_sensor_configuration_get_analog_crop(self.item.as_ptr()).into() } + } + + pub fn binning(&self) -> (u32, u32) { + let mut x = 0; + let mut y = 0; + unsafe { libcamera_sensor_configuration_get_binning(self.item.as_ptr(), &mut x, &mut y) }; + (x, y) + } + + pub fn skipping(&self) -> (u32, u32, u32, u32) { + let (mut x_odd, mut x_even, mut y_odd, mut y_even) = (0, 0, 0, 0); + unsafe { + libcamera_sensor_configuration_get_skipping( + self.item.as_ptr(), + &mut x_odd, + &mut x_even, + &mut y_odd, + &mut y_even, + ) + }; + (x_odd, x_even, y_odd, y_even) + } } impl Default for SensorConfiguration { @@ -122,6 +221,44 @@ impl CameraConfiguration { NonNull::new(ptr).map(|p| unsafe { StreamConfigurationRef::from_ptr(p) }) } + /// Append a new stream configuration for a given role. + pub fn add_configuration(&mut self) -> Option> { + let ptr = unsafe { libcamera_camera_configuration_add_configuration(self.ptr.as_ptr()) }; + NonNull::new(ptr).map(|p| unsafe { StreamConfigurationRef::from_ptr(p) }) + } + + /// Append a new stream configuration by cloning an existing configuration. + /// + /// This mirrors libcamera's `addConfiguration(const StreamConfiguration&)` and produces + /// a valid entry instead of an empty placeholder, allowing multi-stream configurations + /// to validate successfully. + pub fn add_configuration_like( + &mut self, + template: &StreamConfigurationRef<'_>, + ) -> Option> { + let ptr = + unsafe { libcamera_camera_configuration_add_configuration_from(self.ptr.as_ptr(), template.as_ptr()) }; + NonNull::new(ptr).map(|p| unsafe { StreamConfigurationRef::from_ptr(p) }) + } + + /// Append multiple stream configurations by cloning existing templates. + /// + /// Returns the newly appended configurations (in order) for further adjustment. + pub fn add_configurations_like<'a>( + &mut self, + templates: &[&StreamConfigurationRef<'a>], + ) -> Vec> { + let mut appended = Vec::with_capacity(templates.len()); + for tmpl in templates { + let ptr = + unsafe { libcamera_camera_configuration_add_configuration_from(self.ptr.as_ptr(), tmpl.as_ptr()) }; + if let Some(cfg) = NonNull::new(ptr).map(|p| unsafe { StreamConfigurationRef::from_ptr(p) }) { + appended.push(cfg); + } + } + appended + } + pub fn set_sensor_configuration(&mut self, mode: SensorConfiguration) { unsafe { libcamera_camera_set_sensor_configuration(self.ptr.as_ptr(), mode.item.as_ptr()) } } @@ -142,6 +279,53 @@ impl CameraConfiguration { .try_into() .unwrap() } + + /// Returns the desired orientation of the captured image. + pub fn orientation(&self) -> Orientation { + unsafe { libcamera_camera_configuration_get_orientation(self.ptr.as_ptr()) } + .try_into() + .unwrap() + } + + /// Sets the desired orientation of the captured image. + pub fn set_orientation(&mut self, orientation: Orientation) { + unsafe { libcamera_camera_configuration_set_orientation(self.ptr.as_ptr(), orientation.into()) } + } + + /// Returns the sensor configuration if one is set by the application or pipeline. + pub fn sensor_configuration(&self) -> Option { + let ptr = unsafe { libcamera_camera_configuration_get_sensor_configuration(self.ptr.as_ptr()) }; + NonNull::new(ptr).map(SensorConfiguration::from_ptr) + } + + /// Re-validate and print stride/frame_size adjustments for each stream (helper for debugging). + pub fn validate_and_log(&mut self) -> CameraConfigurationStatus { + let status = self.validate(); + for i in 0..self.len() { + if let Some(cfg) = self.get(i) { + eprintln!( + "Stream {} after validate(): stride={}, frame_size={}", + i, + cfg.get_stride(), + cfg.get_frame_size() + ); + } + } + status + } + + /// Return the libcamera textual representation of this configuration. + pub fn to_string_repr(&self) -> String { + unsafe { + let ptr = libcamera_camera_configuration_to_string(self.ptr.as_ptr()); + if ptr.is_null() { + return String::new(); + } + let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned(); + libc::free(ptr.cast()); + s + } + } } impl core::fmt::Debug for CameraConfiguration { @@ -167,6 +351,7 @@ impl Drop for CameraConfiguration { pub struct Camera<'d> { pub(crate) ptr: NonNull, _phantom: PhantomData<&'d ()>, + pub(crate) _token: Option>, } impl<'d> Camera<'d> { @@ -174,6 +359,19 @@ impl<'d> Camera<'d> { Self { ptr, _phantom: Default::default(), + _token: None, + } + } + + pub(crate) unsafe fn from_ptr_tracked( + ptr: NonNull, + tracker: Option>, + ) -> Self { + let token = tracker.map(|t| t.track()); + Self { + ptr, + _phantom: Default::default(), + _token: token, } } @@ -204,6 +402,20 @@ impl<'d> Camera<'d> { } } + /// Returns the set of active streams for this camera. + pub fn streams(&self) -> Vec { + let set = unsafe { libcamera_camera_streams(self.ptr.as_ptr()) }; + if set.is_null() { + return Vec::new(); + } + let count = unsafe { libcamera_stream_set_size(set) }; + let streams = (0..count) + .filter_map(|i| unsafe { NonNull::new(libcamera_stream_set_get(set, i)).map(|p| Stream::from_ptr(p)) }) + .collect(); + unsafe { libcamera_stream_set_destroy(set as *mut _) }; + streams + } + /// Generates default camera configuration for the given [StreamRole]s. /// /// The resulting [CameraConfiguration] contains stream configurations for each of the requested roles. @@ -216,13 +428,28 @@ impl<'d> Camera<'d> { NonNull::new(cfg).map(|p| unsafe { CameraConfiguration::from_ptr(p) }) } + /// Try roles in order and return the first generated configuration that succeeds. + pub fn generate_first_supported_configuration( + &self, + roles: &[StreamRole], + ) -> Option<(CameraConfiguration, StreamRole)> { + roles + .iter() + .find_map(|role| self.generate_configuration(&[*role]).map(|cfg| (cfg, *role))) + } + /// Acquires exclusive rights to the camera, which allows changing configuration and capturing. pub fn acquire(&self) -> io::Result> { let ret = unsafe { libcamera_camera_acquire(self.ptr.as_ptr()) }; if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err(io::Error::from_raw_os_error(-ret)) } else { - Ok(unsafe { ActiveCamera::from_ptr(NonNull::new(libcamera_camera_copy(self.ptr.as_ptr())).unwrap()) }) + Ok(unsafe { + ActiveCamera::from_ptr_with_token( + NonNull::new(libcamera_camera_copy(self.ptr.as_ptr())).unwrap(), + self._token.clone(), + ) + }) } } } @@ -244,6 +471,41 @@ extern "C" fn camera_request_completed_cb(ptr: *mut core::ffi::c_void, req: *mut } } +extern "C" fn camera_buffer_completed_cb( + ptr: *mut core::ffi::c_void, + req: *mut libcamera_request_t, + fb: *mut libcamera_framebuffer_t, +) { + let mut state = unsafe { &*(ptr as *const Mutex>) } + .lock() + .unwrap(); + + let (req_ptr, stream) = match state + .requests + .get_mut(&req) + .and_then(|r| r.stream_for_buffer_ptr(fb).map(|s| (r as *mut Request, s))) + { + Some(v) => v, + None => return, + }; + + if let Some(cb) = state.buffer_completed_cb.as_mut() { + // Safety: req_ptr is valid while held in the map; we only borrow it temporarily. + unsafe { + cb(&mut *req_ptr, stream); + } + } +} + +extern "C" fn camera_disconnected_cb(ptr: *mut core::ffi::c_void) { + let mut state = unsafe { &*(ptr as *const Mutex>) } + .lock() + .unwrap(); + if let Some(cb) = state.disconnected_cb.as_mut() { + cb(); + } +} + #[derive(Default)] struct ActiveCameraState<'d> { /// List of queued requests that are yet to be executed. @@ -251,8 +513,14 @@ struct ActiveCameraState<'d> { requests: HashMap<*mut libcamera_request_t, Request>, /// Callback for libcamera `requestCompleted` signal. request_completed_cb: Option>, + /// Callback for libcamera `bufferCompleted` signal. + buffer_completed_cb: Option>, + /// Callback for libcamera `disconnected` signal. + disconnected_cb: Option>, } +type BufferCompletedCb<'d> = Box; + /// An active instance of a camera. /// /// This gives exclusive access to the camera and allows capturing and modifying configuration. @@ -262,12 +530,29 @@ pub struct ActiveCamera<'d> { cam: Camera<'d>, /// Handle to disconnect `requestCompleted` signal. request_completed_handle: *mut libcamera_callback_handle_t, + /// Handle to disconnect `bufferCompleted` signal. + buffer_completed_handle: *mut libcamera_callback_handle_t, + /// Handle to disconnect `disconnected` signal. + disconnected_handle: *mut libcamera_callback_handle_t, /// Internal state that is shared with callback handlers. state: Box>>, + _token: Option>, +} + +/// Lightweight buffer completion event for channel delivery. +#[derive(Debug, Clone, Copy)] +pub struct BufferCompletedEvent { + pub stream: Stream, + pub request_cookie: u64, + pub request_sequence: u32, + pub buffer_ptr: usize, } impl<'d> ActiveCamera<'d> { - pub(crate) unsafe fn from_ptr(ptr: NonNull) -> Self { + pub(crate) unsafe fn from_ptr_with_token( + ptr: NonNull, + token: Option>, + ) -> Self { let mut state = Box::new(Mutex::new(ActiveCameraState::default())); let request_completed_handle = unsafe { @@ -282,7 +567,10 @@ impl<'d> ActiveCamera<'d> { Self { cam: Camera::from_ptr(ptr), request_completed_handle, + buffer_completed_handle: core::ptr::null_mut(), + disconnected_handle: core::ptr::null_mut(), state, + _token: token, } } @@ -298,13 +586,72 @@ impl<'d> ActiveCamera<'d> { state.request_completed_cb = Some(Box::new(cb)); } + /// Sets a callback for per-buffer completion events. + /// + /// This fires for every buffer as libcamera emits `bufferCompleted`; the corresponding `Request` remains queued + /// until the `requestCompleted` signal fires. + pub fn on_buffer_completed(&mut self, cb: impl FnMut(&mut Request, Stream) + Send + 'd) { + { + let mut state = self.state.lock().unwrap(); + state.buffer_completed_cb = Some(Box::new(cb)); + } + if self.buffer_completed_handle.is_null() { + let data = self.state.as_mut() as *mut Mutex> as *mut _; + self.buffer_completed_handle = unsafe { + libcamera_camera_buffer_completed_connect(self.ptr.as_ptr(), Some(camera_buffer_completed_cb), data) + }; + } + } + + /// Subscribe to request completed events via a channel (async-friendly). + /// + /// The returned receiver yields owned `Request`s as libcamera completes them. + pub fn subscribe_request_completed(&mut self) -> std::sync::mpsc::Receiver { + let (tx, rx) = std::sync::mpsc::channel(); + self.on_request_completed(move |req| { + let _ = tx.send(req); + }); + rx + } + + /// Subscribe to per-buffer completion events via a channel (async-friendly). + /// + /// The receiver yields lightweight `BufferCompletedEvent` snapshots; the underlying Request + /// remains owned by libcamera until requestCompleted fires. + pub fn subscribe_buffer_completed(&mut self) -> std::sync::mpsc::Receiver { + let (tx, rx) = std::sync::mpsc::channel(); + self.on_buffer_completed(move |req, stream| { + let event = BufferCompletedEvent { + stream, + request_cookie: req.cookie(), + request_sequence: req.sequence(), + buffer_ptr: req.find_buffer(&stream).map_or(0, |p| p as usize), + }; + let _ = tx.send(event); + }); + rx + } + + /// Sets a callback for camera disconnected events. + pub fn on_disconnected(&mut self, cb: impl FnMut() + Send + 'd) { + { + let mut state = self.state.lock().unwrap(); + state.disconnected_cb = Some(Box::new(cb)); + } + if self.disconnected_handle.is_null() { + let data = self.state.as_mut() as *mut Mutex> as *mut _; + self.disconnected_handle = + unsafe { libcamera_camera_disconnected_connect(self.ptr.as_ptr(), Some(camera_disconnected_cb), data) }; + } + } + /// Applies camera configuration. /// /// Default configuration can be obtained from [Camera::generate_configuration()] and then adjusted as needed. pub fn configure(&mut self, config: &mut CameraConfiguration) -> io::Result<()> { let ret = unsafe { libcamera_camera_configure(self.ptr.as_ptr(), config.ptr.as_ptr()) }; if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err(io::Error::from_raw_os_error(-ret)) } else { Ok(()) } @@ -328,15 +675,16 @@ impl<'d> ActiveCamera<'d> { /// `ActiveCamera::on_request_completed()`. /// /// Requests that do not have attached framebuffers are invalid and are rejected without being queued. - pub fn queue_request(&self, req: Request) -> io::Result<()> { + pub fn queue_request(&self, req: Request) -> Result<(), (Request, io::Error)> { let ptr = req.ptr.as_ptr(); - self.state.lock().unwrap().requests.insert(ptr, req); - + // Keep the request alive locally until we know queuing succeeded. + let mut pending = Some(req); let ret = unsafe { libcamera_camera_queue_request(self.ptr.as_ptr(), ptr) }; if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err((pending.take().unwrap(), io::Error::from_raw_os_error(-ret))) } else { + self.state.lock().unwrap().requests.insert(ptr, pending.take().unwrap()); Ok(()) } } @@ -348,7 +696,7 @@ impl<'d> ActiveCamera<'d> { let ctrl_ptr = controls.map(|c| c.ptr()).unwrap_or(core::ptr::null_mut()); let ret = unsafe { libcamera_camera_start(self.ptr.as_ptr(), ctrl_ptr) }; if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err(io::Error::from_raw_os_error(-ret)) } else { Ok(()) } @@ -360,7 +708,7 @@ impl<'d> ActiveCamera<'d> { pub fn stop(&mut self) -> io::Result<()> { let ret = unsafe { libcamera_camera_stop(self.ptr.as_ptr()) }; if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err(io::Error::from_raw_os_error(-ret)) } else { Ok(()) } @@ -385,6 +733,12 @@ impl Drop for ActiveCamera<'_> { fn drop(&mut self) { unsafe { libcamera_camera_request_completed_disconnect(self.ptr.as_ptr(), self.request_completed_handle); + if !self.buffer_completed_handle.is_null() { + libcamera_camera_buffer_completed_disconnect(self.ptr.as_ptr(), self.buffer_completed_handle); + } + if !self.disconnected_handle.is_null() { + libcamera_camera_disconnected_disconnect(self.ptr.as_ptr(), self.disconnected_handle); + } libcamera_camera_stop(self.ptr.as_ptr()); libcamera_camera_release(self.ptr.as_ptr()); } diff --git a/libcamera/src/camera_manager.rs b/libcamera/src/camera_manager.rs index 718e7f1..6723969 100644 --- a/libcamera/src/camera_manager.rs +++ b/libcamera/src/camera_manager.rs @@ -3,36 +3,125 @@ use std::{ io, marker::PhantomData, ptr::NonNull, + sync::{mpsc, Arc, Mutex}, }; use libcamera_sys::*; use crate::{camera::Camera, logging::LoggingLevel, utils::handle_result}; +struct ManagerCallbacks { + added: Option) + Send>>, + removed: Option) + Send>>, + hotplug_tx: Option>, +} + +/// Hotplug event propagated via channel helper. +#[derive(Debug, Clone)] +pub enum HotplugEvent { + Added(String), + Removed(String), +} + /// Camera manager used to enumerate available cameras in the system. pub struct CameraManager { ptr: NonNull, + callbacks: Box, + added_handle: *mut libcamera_callback_handle_t, + removed_handle: *mut libcamera_callback_handle_t, + started: bool, + tracker: Arc, } impl CameraManager { - /// Initializes `libcamera` and creates [Self]. + /// Initializes `libcamera`, starts the manager and creates [Self]. pub fn new() -> io::Result { + let mut mgr = Self::new_unstarted()?; + mgr.start()?; + Ok(mgr) + } + + /// Create a `CameraManager` without starting it. + /// + /// Call [Self::start] before using it to enumerate cameras. + pub fn new_unstarted() -> io::Result { let ptr = NonNull::new(unsafe { libcamera_camera_manager_create() }).unwrap(); - let ret = unsafe { libcamera_camera_manager_start(ptr.as_ptr()) }; + Ok(CameraManager { + ptr, + callbacks: Box::new(ManagerCallbacks { + added: None, + removed: None, + hotplug_tx: None, + }), + added_handle: core::ptr::null_mut(), + removed_handle: core::ptr::null_mut(), + started: false, + tracker: Arc::new(CameraTracker::default()), + }) + } + + /// Start the camera manager if it is not already running. + pub fn start(&mut self) -> io::Result<()> { + if self.started { + return Ok(()); + } + let ret = unsafe { libcamera_camera_manager_start(self.ptr.as_ptr()) }; handle_result(ret)?; - Ok(CameraManager { ptr }) + self.started = true; + Ok(()) + } + + /// Stop the camera manager. Safe to call multiple times. + pub fn stop(&mut self) -> io::Result<()> { + if !self.started { + return Ok(()); + } + unsafe { libcamera_camera_manager_stop(self.ptr.as_ptr()) }; + self.started = false; + Ok(()) + } + + /// Attempt to stop only if no tracked cameras are still alive. + pub fn try_stop(&mut self) -> io::Result<()> { + if self.tracker.has_live_handles() { + return Err(io::Error::other( + "cannot stop CameraManager while cameras are still alive", + )); + } + self.stop() + } + + /// Restart the manager by stopping (if safe) and starting again. + pub fn restart(&mut self) -> io::Result<()> { + self.try_stop()?; + self.start() + } + + /// Returns true if the manager has been started. + pub fn is_started(&self) -> bool { + self.started } /// Returns version string of the linked libcamera. pub fn version(&self) -> &str { - unsafe { CStr::from_ptr(libcamera_camera_manager_version(self.ptr.as_ptr())) } - .to_str() - .unwrap() + unsafe { CStr::from_ptr(libcamera_version_string()) }.to_str().unwrap() } /// Enumerates cameras within the system. pub fn cameras<'a>(&self) -> CameraList<'a> { - unsafe { CameraList::from_ptr(NonNull::new(libcamera_camera_manager_cameras(self.ptr.as_ptr())).unwrap()) } + unsafe { + CameraList::from_ptr( + NonNull::new(libcamera_camera_manager_cameras(self.ptr.as_ptr())).unwrap(), + Some(self.tracker.clone()), + ) + } + } + + /// Returns a camera by id if present. + pub fn get<'a>(&self, id: &str) -> Option> { + let id_cstr = CString::new(id).ok()?; + let cam_ptr = unsafe { libcamera_camera_manager_get_id(self.ptr.as_ptr(), id_cstr.as_ptr()) }; + NonNull::new(cam_ptr).map(|p| unsafe { Camera::from_ptr_tracked(p, Some(self.tracker.clone())) }) } /// Set the log level. @@ -49,27 +138,109 @@ impl CameraManager { libcamera_log_set_level(category.as_ptr(), level.as_ptr()); } } + + /// Register a callback for camera-added events. + /// + /// # Warning + /// The callback is invoked on libcamera's internal thread. Do not block in the callback; send work to another + /// thread/channel if needed. + pub fn on_camera_added(&mut self, cb: impl FnMut(Camera<'static>) + Send + 'static) { + self.callbacks.added = Some(Box::new(cb)); + if self.added_handle.is_null() { + let data = self.callbacks.as_mut() as *mut _ as *mut _; + self.added_handle = unsafe { + libcamera_camera_manager_camera_added_connect(self.ptr.as_ptr(), Some(camera_added_cb), data) + }; + } + } + + /// Register a callback for camera-removed events. + /// + /// # Warning + /// The callback is invoked on libcamera's internal thread. Do not block in the callback; send work to another + /// thread/channel if needed. + pub fn on_camera_removed(&mut self, cb: impl FnMut(Camera<'static>) + Send + 'static) { + self.callbacks.removed = Some(Box::new(cb)); + if self.removed_handle.is_null() { + let data = self.callbacks.as_mut() as *mut _ as *mut _; + self.removed_handle = unsafe { + libcamera_camera_manager_camera_removed_connect(self.ptr.as_ptr(), Some(camera_removed_cb), data) + }; + } + } + + /// Subscribe to hotplug events via a channel. + /// + /// The returned `Receiver` yields `HotplugEvent` values. Internally this hooks into the libcamera hotplug signals + /// and forwards them; it uses the same callbacks as `on_camera_added/removed`, so do not mix different senders + /// without care. + pub fn subscribe_hotplug_events(&mut self) -> mpsc::Receiver { + let (tx, rx) = mpsc::channel(); + self.callbacks.hotplug_tx = Some(tx); + // Ensure signals are connected + if self.added_handle.is_null() { + let data = self.callbacks.as_mut() as *mut _ as *mut _; + self.added_handle = unsafe { + libcamera_camera_manager_camera_added_connect(self.ptr.as_ptr(), Some(camera_added_cb), data) + }; + } + if self.removed_handle.is_null() { + let data = self.callbacks.as_mut() as *mut _ as *mut _; + self.removed_handle = unsafe { + libcamera_camera_manager_camera_removed_connect(self.ptr.as_ptr(), Some(camera_removed_cb), data) + }; + } + rx + } } impl Drop for CameraManager { fn drop(&mut self) { + if self.started { + unsafe { libcamera_camera_manager_stop(self.ptr.as_ptr()) }; + self.started = false; + } unsafe { - libcamera_camera_manager_stop(self.ptr.as_ptr()); + if !self.added_handle.is_null() { + libcamera_camera_manager_camera_signal_disconnect(self.ptr.as_ptr(), self.added_handle); + } + if !self.removed_handle.is_null() { + libcamera_camera_manager_camera_signal_disconnect(self.ptr.as_ptr(), self.removed_handle); + } libcamera_camera_manager_destroy(self.ptr.as_ptr()); } } } +#[derive(Default)] +pub(crate) struct CameraTracker { + handles: Mutex>>, +} + +impl CameraTracker { + pub(crate) fn track(&self) -> std::sync::Arc<()> { + let token = std::sync::Arc::new(()); + self.handles.lock().unwrap().push(std::sync::Arc::downgrade(&token)); + token + } + + fn has_live_handles(&self) -> bool { + self.handles.lock().unwrap().iter().any(|w| w.upgrade().is_some()) + } +} + pub struct CameraList<'d> { ptr: NonNull, _phantom: PhantomData<&'d ()>, + tracker: Option>, } impl<'d> CameraList<'d> { - pub(crate) unsafe fn from_ptr(ptr: NonNull) -> Self { + pub(crate) unsafe fn from_ptr(ptr: NonNull, tracker: Option>) -> Self { Self { ptr, _phantom: Default::default(), + tracker, } } @@ -88,7 +259,8 @@ impl<'d> CameraList<'d> { /// Returns [None] if index is out of range of available cameras. pub fn get(&self, index: usize) -> Option> { let cam_ptr = unsafe { libcamera_camera_list_get(self.ptr.as_ptr(), index as _) }; - NonNull::new(cam_ptr).map(|p| unsafe { Camera::from_ptr(p) }) + let tracker = self.tracker.clone(); + NonNull::new(cam_ptr).map(|p| unsafe { Camera::from_ptr_tracked(p, tracker) }) } /// Returns an iterator over the cameras in the list. @@ -130,3 +302,49 @@ impl<'d> Iterator for CameraListIter<'d> { } impl<'d> ExactSizeIterator for CameraListIter<'d> {} + +unsafe extern "C" fn camera_added_cb(data: *mut core::ffi::c_void, cam: *mut libcamera_camera_t) { + if data.is_null() || cam.is_null() { + return; + } + // Safety: called from libcamera thread, user must ensure callbacks are Send-safe. + let state = &mut *(data as *mut ManagerCallbacks); + if let Some(ptr) = NonNull::new(cam) { + // Clone shared_ptr once to avoid double-drop when used by multiple consumers. + let cam_copy = unsafe { libcamera_camera_copy(ptr.as_ptr()) }; + if let Some(copy_ptr) = NonNull::new(cam_copy) { + let cam = unsafe { Camera::from_ptr(copy_ptr) }; + let cam_id = cam.id().to_string(); + if let Some(cb) = state.added.as_mut() { + cb(cam); + } else { + drop(cam); + } + if let Some(tx) = state.hotplug_tx.as_ref() { + let _ = tx.send(HotplugEvent::Added(cam_id)); + } + } + } +} + +unsafe extern "C" fn camera_removed_cb(data: *mut core::ffi::c_void, cam: *mut libcamera_camera_t) { + if data.is_null() || cam.is_null() { + return; + } + let state = &mut *(data as *mut ManagerCallbacks); + if let Some(ptr) = NonNull::new(cam) { + let cam_copy = unsafe { libcamera_camera_copy(ptr.as_ptr()) }; + if let Some(copy_ptr) = NonNull::new(cam_copy) { + let cam = unsafe { Camera::from_ptr(copy_ptr) }; + let cam_id = cam.id().to_string(); + if let Some(cb) = state.removed.as_mut() { + cb(cam); + } else { + drop(cam); + } + if let Some(tx) = state.hotplug_tx.as_ref() { + let _ = tx.send(HotplugEvent::Removed(cam_id)); + } + } + } +} diff --git a/libcamera/src/color_space.rs b/libcamera/src/color_space.rs new file mode 100644 index 0000000..1ddee57 --- /dev/null +++ b/libcamera/src/color_space.rs @@ -0,0 +1,227 @@ +use std::ffi::CString; + +use libcamera_sys::*; + +/// Color primaries +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Primaries { + Raw, + Smpte170m, + Rec709, + Rec2020, +} + +/// Transfer function +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum TransferFunction { + Linear, + Srgb, + Rec709, +} + +/// YCbCr encoding +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum YcbcrEncoding { + None, + Rec601, + Rec709, + Rec2020, +} + +/// Color range +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Range { + Full, + Limited, +} + +/// Represents `libcamera::ColorSpace`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ColorSpace { + pub primaries: Primaries, + pub transfer_function: TransferFunction, + pub ycbcr_encoding: YcbcrEncoding, + pub range: Range, +} + +impl ColorSpace { + pub const fn new( + primaries: Primaries, + transfer_function: TransferFunction, + ycbcr_encoding: YcbcrEncoding, + range: Range, + ) -> Self { + Self { + primaries, + transfer_function, + ycbcr_encoding, + range, + } + } + + // Predefined color spaces from libcamera + pub fn raw() -> Self { + unsafe { libcamera_color_space_raw() }.into() + } + pub fn srgb() -> Self { + unsafe { libcamera_color_space_srgb() }.into() + } + pub fn sycc() -> Self { + unsafe { libcamera_color_space_sycc() }.into() + } + pub fn smpte170m() -> Self { + unsafe { libcamera_color_space_smpte170m() }.into() + } + pub fn rec709() -> Self { + unsafe { libcamera_color_space_rec709() }.into() + } + pub fn rec2020() -> Self { + unsafe { libcamera_color_space_rec2020() }.into() + } + + /// Returns libcamera string representation (e.g. "Smpte170m/Rec709/Full"). + pub fn to_repr(&self) -> String { + unsafe { + let ptr = libcamera_color_space_to_string(&(*self).into()); + if ptr.is_null() { + return String::new(); + } + let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned(); + libc::free(ptr.cast()); + s + } + } + + /// Parse color space from libcamera string representation. Returns None on failure. + pub fn from_string(s: &str) -> Option { + let cstr = CString::new(s).ok()?; + let mut cs = libcamera_color_space_t { + primaries: libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_RAW, + transfer_function: libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_LINEAR, + ycbcr_encoding: libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_NONE, + range: libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_FULL, + }; + let ok = unsafe { libcamera_color_space_from_string(cstr.as_ptr(), &mut cs) }; + if ok { + Some(ColorSpace::from(cs)) + } else { + None + } + } + + /// Adjust this color space for a given pixel format. + /// + /// Returns `true` if the color space was modified to make it compatible with the pixel format, + /// or `false` if it was already compatible. + pub fn adjust_for_format(&mut self, pixel_format: crate::pixel_format::PixelFormat) -> bool { + let mut cs = (*self).into(); + let adjusted = unsafe { libcamera_color_space_adjust(&mut cs, &pixel_format.0) }; + *self = cs.into(); + adjusted + } + + /// Returns a clone of this color space adjusted for the given pixel format. + /// + /// libcamera always treats the color space as compatible (possibly changing it), so this + /// will always return `Some`. + pub fn with_adjusted_for_format(&self, pixel_format: crate::pixel_format::PixelFormat) -> Option { + let mut clone = *self; + let _ = clone.adjust_for_format(pixel_format); + Some(clone) + } +} + +impl core::fmt::Display for ColorSpace { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(&self.to_repr()) + } +} + +impl From for libcamera_color_space_t { + fn from(cs: ColorSpace) -> Self { + unsafe { + libcamera_color_space_make( + match cs.primaries { + Primaries::Raw => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_RAW, + Primaries::Smpte170m => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_SMPTE170M, + Primaries::Rec709 => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC709, + Primaries::Rec2020 => libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC2020, + }, + match cs.transfer_function { + TransferFunction::Linear => { + libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_LINEAR + } + TransferFunction::Srgb => { + libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_SRGB + } + TransferFunction::Rec709 => { + libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_REC709 + } + }, + match cs.ycbcr_encoding { + YcbcrEncoding::None => { + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_NONE + } + YcbcrEncoding::Rec601 => { + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC601 + } + YcbcrEncoding::Rec709 => { + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC709 + } + YcbcrEncoding::Rec2020 => { + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC2020 + } + }, + match cs.range { + Range::Full => libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_FULL, + Range::Limited => libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_LIMITED, + }, + ) + } + } +} + +impl From for ColorSpace { + fn from(cs: libcamera_color_space_t) -> Self { + let primaries = match cs.primaries { + libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_RAW => Primaries::Raw, + libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_SMPTE170M => Primaries::Smpte170m, + libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC709 => Primaries::Rec709, + libcamera_color_space_primaries::LIBCAMERA_COLOR_SPACE_PRIMARIES_REC2020 => Primaries::Rec2020, + _ => Primaries::Raw, + }; + let transfer_function = match cs.transfer_function { + libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_LINEAR => { + TransferFunction::Linear + } + libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_SRGB => { + TransferFunction::Srgb + } + libcamera_color_space_transfer_function::LIBCAMERA_COLOR_SPACE_TRANSFER_FUNCTION_REC709 => { + TransferFunction::Rec709 + } + _ => TransferFunction::Linear, + }; + let ycbcr_encoding = match cs.ycbcr_encoding { + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_NONE => YcbcrEncoding::None, + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC601 => YcbcrEncoding::Rec601, + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC709 => YcbcrEncoding::Rec709, + libcamera_color_space_ycbcr_encoding::LIBCAMERA_COLOR_SPACE_YCBCR_ENCODING_REC2020 => { + YcbcrEncoding::Rec2020 + } + _ => YcbcrEncoding::None, + }; + let range = match cs.range { + libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_FULL => Range::Full, + libcamera_color_space_range::LIBCAMERA_COLOR_SPACE_RANGE_LIMITED => Range::Limited, + _ => Range::Full, + }; + + ColorSpace { + primaries, + transfer_function, + ycbcr_encoding, + range, + } + } +} diff --git a/libcamera/src/control.rs b/libcamera/src/control.rs index bdcb9b8..a9736c5 100644 --- a/libcamera/src/control.rs +++ b/libcamera/src/control.rs @@ -48,6 +48,68 @@ impl DynControlEntry for T { #[repr(transparent)] pub struct ControlInfo(libcamera_control_info_t); +#[repr(transparent)] +pub struct ControlIdMap(libcamera_control_id_map_t); + +impl ControlIdMap { + pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull) -> &'a mut Self { + &mut *(ptr.as_ptr() as *mut Self) + } + + pub fn iter(&self) -> Option> { + ControlIdMapIter::new(self) + } + + pub(crate) fn ptr(&self) -> *const libcamera_control_id_map_t { + &self.0 as *const libcamera_control_id_map_t + } +} + +#[derive(Clone, Copy)] +pub struct ControlIdRef { + ptr: NonNull, +} + +impl ControlIdRef { + pub(crate) unsafe fn from_ptr(ptr: NonNull) -> Self { + Self { ptr } + } + + pub fn id(&self) -> u32 { + unsafe { libcamera_control_id(self.ptr.as_ptr()) as u32 } + } + + pub fn name(&self) -> &str { + unsafe { + CStr::from_ptr(libcamera_control_name(self.ptr.as_ptr())) + .to_str() + .unwrap() + } + } + + pub fn vendor(&self) -> &str { + unsafe { + CStr::from_ptr(libcamera_control_id_vendor(self.ptr.as_ptr())) + .to_str() + .unwrap() + } + } + + pub fn ty(&self) -> ControlType { + unsafe { libcamera_control_id_type(self.ptr.as_ptr()) } + .try_into() + .unwrap_or(ControlType::None) + } + + pub fn is_array(&self) -> bool { + unsafe { libcamera_control_id_is_array(self.ptr.as_ptr()) } + } + + pub fn size(&self) -> usize { + unsafe { libcamera_control_id_size(self.ptr.as_ptr()) } + } +} + impl ControlInfo { pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull) -> &'a mut Self { // Safety: we can cast it because of `#[repr(transparent)]` @@ -200,6 +262,14 @@ impl core::fmt::Debug for ControlInfoMap { #[repr(transparent)] pub struct ControlList(libcamera_control_list_t); +/// How to merge control lists. +#[derive(Debug, Clone, Copy)] +#[repr(u32)] +pub enum MergePolicy { + KeepExisting = libcamera_control_merge_policy::LIBCAMERA_CONTROL_MERGE_KEEP_EXISTING, + OverwriteExisting = libcamera_control_merge_policy::LIBCAMERA_CONTROL_MERGE_OVERWRITE_EXISTING, +} + impl UniquePtrTarget for ControlList { unsafe fn ptr_new() -> *mut Self { libcamera_control_list_create() as *mut Self @@ -215,6 +285,20 @@ impl ControlList { UniquePtr::new() } + pub fn from_id_map(map: &ControlIdMap) -> Option> { + unsafe { + let ptr = libcamera_control_list_create_with_idmap(map.ptr()); + UniquePtr::from_raw(ptr as *mut Self) + } + } + + pub fn from_info_map(info_map: &ControlInfoMap) -> Option> { + unsafe { + let ptr = libcamera_control_list_create_with_info_map(info_map.ptr()); + UniquePtr::from_raw(ptr as *mut Self) + } + } + pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull) -> &'a mut Self { // Safety: we can cast it because of `#[repr(transparent)]` &mut *(ptr.as_ptr() as *mut Self) @@ -225,6 +309,46 @@ impl ControlList { &self.0 as *const libcamera_control_list_t } + pub fn len(&self) -> usize { + unsafe { libcamera_control_list_size(self.ptr().cast_mut()) } + } + + pub fn is_empty(&self) -> bool { + unsafe { libcamera_control_list_is_empty(self.ptr().cast_mut()) } + } + + pub fn clear(&mut self) { + unsafe { libcamera_control_list_clear(self.ptr().cast_mut()) } + } + + pub fn contains(&self, id: u32) -> bool { + unsafe { libcamera_control_list_contains(self.ptr(), id) } + } + + pub fn merge(&mut self, other: &ControlList, policy: MergePolicy) { + unsafe { libcamera_control_list_merge(self.ptr().cast_mut(), other.ptr(), policy as u32) } + } + + pub fn info_map(&self) -> Option<&ControlInfoMap> { + unsafe { + let ptr = libcamera_control_list_info_map(self.ptr()); + NonNull::new(ptr.cast_mut()).map(|p| { + let m: &mut ControlInfoMap = ControlInfoMap::from_ptr(p); + &*m + }) + } + } + + pub fn id_map(&self) -> Option<&ControlIdMap> { + unsafe { + let ptr = libcamera_control_list_id_map(self.ptr()); + NonNull::new(ptr.cast_mut()).map(|p| { + let m: &mut ControlIdMap = ControlIdMap::from_ptr(p); + &*m + }) + } + } + pub fn get(&self) -> Result { let val_ptr = NonNull::new(unsafe { libcamera_control_list_get(self.ptr().cast_mut(), C::ID as _).cast_mut() }) .ok_or(ControlError::NotFound(C::ID))?; @@ -327,23 +451,6 @@ impl PropertyList { Ok(C::try_from(val)?) } - - /// Sets property value. - /// - /// This can fail if property is not supported by the camera, but due to libcamera API limitations an error will not - /// be returned. Use [PropertyList::get] if you need to ensure that value was set. - pub fn set(&mut self, val: C) -> Result<(), ControlError> { - let ctrl_val: ControlValue = val.into(); - - unsafe { - let val_ptr = NonNull::new(libcamera_control_value_create()).unwrap(); - ctrl_val.write(val_ptr); - libcamera_control_list_set(self.ptr().cast_mut(), C::ID as _, val_ptr.as_ptr()); - libcamera_control_value_destroy(val_ptr.as_ptr()); - } - - Ok(()) - } } impl<'d> IntoIterator for &'d PropertyList { @@ -509,6 +616,52 @@ impl Drop for ControlIdEnumeratorsIter<'_> { } } +pub struct ControlIdMapIter<'a> { + iter: *mut libcamera_control_id_map_iter_t, + marker: PhantomData<&'a ControlIdMap>, +} + +impl<'a> ControlIdMapIter<'a> { + fn new(map: &'a ControlIdMap) -> Option { + unsafe { + let iter = libcamera_control_id_map_iter_create(map.ptr()); + if iter.is_null() { + None + } else { + Some(Self { + iter, + marker: PhantomData, + }) + } + } + } +} + +impl<'a> Iterator for ControlIdMapIter<'a> { + type Item = (u32, ControlIdRef); + + fn next(&mut self) -> Option { + unsafe { + if libcamera_control_id_map_iter_has_next(self.iter) { + let key = libcamera_control_id_map_iter_key(self.iter); + let id_ptr = libcamera_control_id_map_iter_value(self.iter); + libcamera_control_id_map_iter_next(self.iter); + NonNull::new(id_ptr.cast_mut()).map(|p| (key, ControlIdRef::from_ptr(p))) + } else { + None + } + } + } +} + +impl Drop for ControlIdMapIter<'_> { + fn drop(&mut self) { + unsafe { + libcamera_control_id_map_iter_destroy(self.iter); + } + } +} + #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] #[repr(u32)] pub enum ControlDirection { diff --git a/libcamera/src/control_value.rs b/libcamera/src/control_value.rs index fcbf8a5..b7fb23e 100644 --- a/libcamera/src/control_value.rs +++ b/libcamera/src/control_value.rs @@ -33,7 +33,7 @@ pub enum ControlValue { Int32(SmallVec<[i32; 1]>), Int64(SmallVec<[i64; 1]>), Float(SmallVec<[f32; 1]>), - String(String), + String(SmallVec<[String; 1]>), Rectangle(SmallVec<[Rectangle; 1]>), Size(SmallVec<[Size; 1]>), // bad gues @@ -200,7 +200,7 @@ impl_control_value_array!(ControlValue::Point, Point); impl From for ControlValue { fn from(val: String) -> Self { - Self::String(val) + Self::String(smallvec![val]) } } @@ -209,7 +209,36 @@ impl TryFrom for String { fn try_from(value: ControlValue) -> Result { match value { - ControlValue::String(v) => Ok(v), + ControlValue::String(mut v) => { + if v.len() == 1 { + Ok(v.pop().unwrap()) + } else { + Err(ControlValueError::InvalidLength { + expected: 1, + found: v.len(), + }) + } + } + _ => Err(ControlValueError::InvalidType { + expected: libcamera_control_type::LIBCAMERA_CONTROL_TYPE_STRING, + found: value.ty(), + }), + } + } +} + +impl From> for ControlValue { + fn from(val: Vec) -> Self { + ControlValue::String(SmallVec::from_vec(val)) + } +} + +impl TryFrom for Vec { + type Error = ControlValueError; + + fn try_from(value: ControlValue) -> Result { + match value { + ControlValue::String(v) => Ok(v.into_vec()), _ => Err(ControlValueError::InvalidType { expected: libcamera_control_type::LIBCAMERA_CONTROL_TYPE_STRING, found: value.ty(), @@ -256,7 +285,27 @@ impl ControlValue { } LIBCAMERA_CONTROL_TYPE_STRING => { let slice = core::slice::from_raw_parts(data as *const u8, num_elements); - Ok(Self::String(core::str::from_utf8(slice).unwrap().to_string())) + // Split on interior NULs to support string arrays; fallback to single string if no delimiters. + let mut parts = Vec::new(); + let mut start = 0usize; + for (idx, b) in slice.iter().enumerate() { + if *b == 0 { + parts.push(&slice[start..idx]); + start = idx + 1; + } + } + if start < slice.len() { + parts.push(&slice[start..]); + } + if parts.is_empty() { + parts.push(&[]); + } + let strings = parts + .into_iter() + .filter_map(|p| core::str::from_utf8(p).ok()) + .map(|s| s.to_string()) + .collect(); + Ok(Self::String(strings)) } LIBCAMERA_CONTROL_TYPE_RECTANGLE => { let slice = core::slice::from_raw_parts(data as *const libcamera_rectangle_t, num_elements); @@ -277,6 +326,7 @@ impl ControlValue { } pub(crate) unsafe fn write(&self, val: NonNull) { + let mut tmp_string_buf: Vec = Vec::new(); let (data, len) = match self { ControlValue::None => (core::ptr::null(), 0), ControlValue::Bool(v) => (v.as_ptr().cast(), v.len()), @@ -286,20 +336,25 @@ impl ControlValue { ControlValue::Int32(v) => (v.as_ptr().cast(), v.len()), ControlValue::Int64(v) => (v.as_ptr().cast(), v.len()), ControlValue::Float(v) => (v.as_ptr().cast(), v.len()), - ControlValue::String(v) => (v.as_ptr().cast(), v.len()), + ControlValue::String(v) => { + if v.len() <= 1 { + let s = v.first().map(|s| s.as_bytes()).unwrap_or(&[]); + tmp_string_buf.extend_from_slice(s); + } else { + tmp_string_buf.extend_from_slice(v.join("\0").as_bytes()); + } + (tmp_string_buf.as_ptr(), tmp_string_buf.len()) + } ControlValue::Rectangle(v) => (v.as_ptr().cast(), v.len()), ControlValue::Size(v) => (v.as_ptr().cast(), v.len()), ControlValue::Point(v) => (v.as_ptr().cast(), v.len()), }; - let ty = self.ty(); - let is_array = if ty == libcamera_control_type::LIBCAMERA_CONTROL_TYPE_STRING { - true - } else { - len != 1 - }; + // Strings must always be treated as arrays of bytes; passing a scalar causes libcamera to + // allocate only one byte. For all other types, keep the previous "len != 1" rule. + let is_array = matches!(self, ControlValue::String(_)) || len != 1; - libcamera_control_value_set(val.as_ptr(), self.ty(), data, is_array, len as _); + libcamera_control_value_set(val.as_ptr(), self.ty(), data.cast(), is_array, len as _); } pub fn ty(&self) -> u32 { diff --git a/libcamera/src/fence.rs b/libcamera/src/fence.rs new file mode 100644 index 0000000..5d35f6b --- /dev/null +++ b/libcamera/src/fence.rs @@ -0,0 +1,70 @@ +use std::{ + io, + mem::ManuallyDrop, + os::fd::{FromRawFd, IntoRawFd, OwnedFd}, + ptr::NonNull, +}; + +use libcamera_sys::*; + +/// A wrapper around libcamera::Fence for synchronizing buffer access. +pub struct Fence { + ptr: NonNull, +} + +impl Fence { + /// Create a Fence from an owned file descriptor. + /// + /// The fd is consumed; on failure it is closed. + pub fn from_fd(fd: OwnedFd) -> io::Result { + let raw = fd.into_raw_fd(); + let ptr = unsafe { libcamera_fence_from_fd(raw) }; + match NonNull::new(ptr) { + Some(ptr) => Ok(Self { ptr }), + None => { + unsafe { libc::close(raw) }; + Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid fence fd")) + } + } + } + + /// Duplicate the fence fd. + pub fn to_owned_fd(&self) -> io::Result { + let fd = unsafe { libcamera_fence_fd(self.ptr.as_ptr()) }; + if fd < 0 { + Err(io::Error::last_os_error()) + } else { + Ok(unsafe { OwnedFd::from_raw_fd(fd) }) + } + } + + /// Consume the fence and return a duplicated fd. + pub fn into_owned_fd(self) -> io::Result { + let fd = self.to_owned_fd(); + // Manually drop to avoid double-destroy after forgetting self. + let ptr = self.ptr; + let _ = ManuallyDrop::new(self); + unsafe { + libcamera_fence_destroy(ptr.as_ptr()); + } + fd + } + + pub(crate) fn into_raw(self) -> *mut libcamera_fence_t { + let ptr = self.ptr.as_ptr(); + std::mem::forget(self); + ptr + } + + pub(crate) unsafe fn from_ptr(ptr: *mut libcamera_fence_t) -> Option { + NonNull::new(ptr).map(|ptr| Self { ptr }) + } +} + +impl Drop for Fence { + fn drop(&mut self) { + unsafe { libcamera_fence_destroy(self.ptr.as_ptr()) } + } +} + +unsafe impl Send for Fence {} diff --git a/libcamera/src/formats.rs b/libcamera/src/formats.rs new file mode 100644 index 0000000..d73897f --- /dev/null +++ b/libcamera/src/formats.rs @@ -0,0 +1,13 @@ +//! Pixel format constants generated from the installed `libcamera/formats.h`. +//! +//! The names and values in this module mirror `libcamera::formats` for the +//! libcamera version detected at build time. Use these to avoid hand-rolling +//! fourcc/modifier pairs: +//! +//! ```text +//! // Example: +//! // let fmt = PixelFormat::parse("NV12").unwrap(); +//! // let info = fmt.info().unwrap(); +//! // assert_eq!(fmt.to_string(), info.name); +//! ``` +include!(concat!(env!("OUT_DIR"), "/formats.rs")); diff --git a/libcamera/src/framebuffer.rs b/libcamera/src/framebuffer.rs index aa79a32..aee796b 100644 --- a/libcamera/src/framebuffer.rs +++ b/libcamera/src/framebuffer.rs @@ -1,9 +1,14 @@ -use std::{marker::PhantomData, ptr::NonNull}; +use std::{ + io, + marker::PhantomData, + os::fd::{IntoRawFd, OwnedFd}, + ptr::NonNull, +}; use libcamera_sys::*; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use crate::utils::Immutable; +use crate::{fence::Fence, utils::Immutable}; #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] #[repr(u32)] @@ -233,6 +238,12 @@ impl core::fmt::Debug for FrameBufferPlanesRef<'_> { } } +impl Drop for FrameBufferPlanesRef<'_> { + fn drop(&mut self) { + unsafe { libcamera_framebuffer_planes_destroy(self.ptr.as_ptr()) } + } +} + impl<'d> IntoIterator for &'d FrameBufferPlanesRef<'d> { type Item = Immutable>; @@ -288,8 +299,147 @@ pub trait AsFrameBuffer: Send { fn planes(&self) -> Immutable> { unsafe { Immutable(FrameBufferPlanesRef::from_ptr( - NonNull::new(libcamera_framebuffer_planes(self.ptr().as_ptr()).cast_mut()).unwrap(), + NonNull::new(libcamera_framebuffer_planes(self.ptr().as_ptr())).unwrap(), )) } } + + /// User cookie associated with the buffer. + fn cookie(&self) -> u64 { + unsafe { libcamera_framebuffer_cookie(self.ptr().as_ptr()) } + } + + /// Set user cookie associated with the buffer. + fn set_cookie(&self, cookie: u64) { + unsafe { libcamera_framebuffer_set_cookie(self.ptr().as_ptr(), cookie) } + } + + /// Releases the acquire fence associated with this framebuffer, if any. + /// + /// Ownership of the fence is transferred to the caller. + fn release_fence(&self) -> Option { + unsafe { Fence::from_ptr(libcamera_framebuffer_release_fence_handle(self.ptr().as_ptr())) } + } + + /// Returns a non-owning view of the Request owning this framebuffer, if any. + fn request(&self) -> Option> { + let ptr = unsafe { libcamera_framebuffer_request(self.ptr().as_ptr()) }; + NonNull::new(ptr).map(|p| unsafe { crate::request::RequestRef::from_ptr(p) }) + } +} + +/// Description of a framebuffer plane for importing buffers. +pub struct FrameBufferPlane { + pub fd: OwnedFd, + pub offset: u32, + pub length: u32, +} + +/// FrameBuffer created from user-provided DMABUFs. +pub struct OwnedFrameBuffer { + ptr: NonNull, +} + +unsafe impl Send for OwnedFrameBuffer {} + +impl OwnedFrameBuffer { + /// Create a framebuffer from a set of planes. Ownership of the fds is transferred. + pub fn new(planes: Vec, cookie: Option) -> io::Result { + if planes.is_empty() { + return Err(io::Error::new(io::ErrorKind::InvalidInput, "no planes provided")); + } + + let mut infos: Vec = Vec::with_capacity(planes.len()); + let mut raw_fds = Vec::with_capacity(planes.len()); + + for plane in planes { + if plane.offset == u32::MAX || plane.length == 0 { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + "plane offset/length must be valid and non-zero", + )); + } + let fd = plane.fd.into_raw_fd(); + raw_fds.push(fd); + infos.push(libcamera_framebuffer_plane_info { + fd, + offset: plane.offset, + length: plane.length, + }); + } + + let ptr = unsafe { libcamera_framebuffer_create(infos.as_ptr(), infos.len(), cookie.unwrap_or(0)) }; + + if let Some(ptr) = NonNull::new(ptr) { + // Initialize metadata status sentinel to avoid uninitialized reads. + unsafe { + libcamera_framebuffer_metadata(ptr.as_ptr()) + .cast_mut() + .cast::() + .write(u32::MAX) + }; + Ok(Self { ptr }) + } else { + for fd in raw_fds { + unsafe { libc::close(fd) }; + } + Err(io::Error::last_os_error()) + } + } +} + +impl AsFrameBuffer for OwnedFrameBuffer { + unsafe fn ptr(&self) -> NonNull { + self.ptr + } +} + +impl OwnedFrameBuffer { + /// Returns true if planes are contiguous within a single FD and ordered without gaps. + pub fn is_contiguous(&self) -> bool { + let planes = self.planes(); + if planes.is_empty() { + return false; + } + // Gather (fd, offset, length) + let mut entries: Vec<(i32, usize, usize)> = planes + .into_iter() + .filter_map(|p| p.offset().map(|off| (p.fd(), off, p.len()))) + .collect(); + // Must all share the same fd + if entries + .iter() + .map(|e| e.0) + .collect::>() + .len() + != 1 + { + return false; + } + entries.sort_by_key(|e| e.1); + // Check contiguous offsets + let mut expected = entries[0].1; + for (_, off, len) in entries { + if off != expected { + return false; + } + expected = off + len; + } + true + } +} + +impl core::fmt::Debug for OwnedFrameBuffer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("OwnedFrameBuffer") + .field("cookie", &self.cookie()) + .field("planes", &self.planes()) + .finish() + } +} + +impl Drop for OwnedFrameBuffer { + fn drop(&mut self) { + unsafe { libcamera_framebuffer_destroy(self.ptr.as_ptr()) } + } } diff --git a/libcamera/src/framebuffer_allocator.rs b/libcamera/src/framebuffer_allocator.rs index 446f1d8..bdc9b22 100644 --- a/libcamera/src/framebuffer_allocator.rs +++ b/libcamera/src/framebuffer_allocator.rs @@ -1,4 +1,5 @@ use std::{ + collections::HashMap, io, ptr::NonNull, sync::{Arc, Mutex}, @@ -12,20 +13,23 @@ use crate::{camera::Camera, framebuffer::AsFrameBuffer, stream::Stream}; /// to keep the allocator alive as long as there are active buffers. struct FrameBufferAllocatorInstance { ptr: NonNull, - /// List of streams for which buffers were allocated. - /// We use this list to free buffers on drop. - allocated_streams: Vec>, + /// Active allocations per stream pointer. + streams: HashMap, +} + +#[derive(Debug)] +struct StreamAllocState { + count: usize, + free_requested: bool, } unsafe impl Send for FrameBufferAllocatorInstance {} impl Drop for FrameBufferAllocatorInstance { fn drop(&mut self) { - // Free allocated streams - for stream in self.allocated_streams.drain(..) { - unsafe { - libcamera_framebuffer_allocator_free(self.ptr.as_ptr(), stream.as_ptr()); - } + // Free any remaining streams. + for (stream_ptr, _) in self.streams.drain() { + unsafe { libcamera_framebuffer_allocator_free(self.ptr.as_ptr(), stream_ptr as *mut _) }; } unsafe { libcamera_framebuffer_allocator_destroy(self.ptr.as_ptr()) } @@ -41,7 +45,7 @@ impl FrameBufferAllocator { Self { inner: Arc::new(Mutex::new(FrameBufferAllocatorInstance { ptr: NonNull::new(unsafe { libcamera_framebuffer_allocator_create(cam.ptr.as_ptr()) }).unwrap(), - allocated_streams: Vec::new(), + streams: HashMap::new(), })), } } @@ -50,17 +54,30 @@ impl FrameBufferAllocator { /// [StreamConfigurationRef::get_buffer_count()](crate::stream::StreamConfigurationRef::get_buffer_count). pub fn alloc(&mut self, stream: &Stream) -> io::Result> { let mut inner = self.inner.lock().unwrap(); + let key = stream.ptr.as_ptr() as usize; + if inner.streams.contains_key(&key) { + return Err(io::Error::new( + io::ErrorKind::AlreadyExists, + "buffers already allocated for this stream", + )); + } let ret = unsafe { libcamera_framebuffer_allocator_allocate(inner.ptr.as_ptr(), stream.ptr.as_ptr()) }; if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err(io::Error::from_raw_os_error(-ret)) } else { - inner.allocated_streams.push(stream.ptr); - let buffers = unsafe { libcamera_framebuffer_allocator_buffers(inner.ptr.as_ptr(), stream.ptr.as_ptr()) }; let len = unsafe { libcamera_framebuffer_list_size(buffers) }; + inner.streams.insert( + key, + StreamAllocState { + count: len, + free_requested: false, + }, + ); + Ok((0..len) .map(|i| unsafe { libcamera_framebuffer_list_get(buffers, i) }) .map(|ptr| NonNull::new(ptr.cast_mut()).unwrap()) @@ -78,16 +95,44 @@ impl FrameBufferAllocator { FrameBuffer { ptr, + stream_key: key, _alloc: self.inner.clone(), } }) .collect()) } } + + /// Free buffers for a stream. + pub fn free(&mut self, stream: &Stream) -> io::Result<()> { + let mut inner = self.inner.lock().unwrap(); + let key = stream.ptr.as_ptr() as usize; + let state = inner + .streams + .get_mut(&key) + .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "no buffers allocated for stream"))?; + + state.free_requested = true; + if state.count == 0 { + let ret = unsafe { libcamera_framebuffer_allocator_free(inner.ptr.as_ptr(), stream.ptr.as_ptr()) }; + if ret < 0 { + return Err(io::Error::from_raw_os_error(-ret)); + } + inner.streams.remove(&key); + } + Ok(()) + } + + /// Returns true if any buffers are allocated. + pub fn allocated(&self) -> bool { + let inner = self.inner.lock().unwrap(); + unsafe { libcamera_framebuffer_allocator_allocated(inner.ptr.as_ptr()) } + } } pub struct FrameBuffer { ptr: NonNull, + stream_key: usize, _alloc: Arc>, } @@ -107,3 +152,32 @@ impl AsFrameBuffer for FrameBuffer { self.ptr } } + +impl FrameBuffer { + /// Retrieve the user cookie associated with this buffer. + pub fn cookie(&self) -> u64 { + unsafe { libcamera_framebuffer_cookie(self.ptr.as_ptr()) } + } + + /// Set a user cookie for this buffer. + pub fn set_cookie(&self, cookie: u64) { + unsafe { libcamera_framebuffer_set_cookie(self.ptr.as_ptr(), cookie) } + } +} + +impl Drop for FrameBuffer { + fn drop(&mut self) { + let mut inner = self._alloc.lock().unwrap(); + if let Some(state) = inner.streams.get_mut(&self.stream_key) { + if state.count > 0 { + state.count -= 1; + } + if state.count == 0 && state.free_requested { + unsafe { + let _ = libcamera_framebuffer_allocator_free(inner.ptr.as_ptr(), self.stream_key as *mut _); + } + inner.streams.remove(&self.stream_key); + } + } + } +} diff --git a/libcamera/src/framebuffer_map.rs b/libcamera/src/framebuffer_map.rs index cd46eaf..f9c7be4 100644 --- a/libcamera/src/framebuffer_map.rs +++ b/libcamera/src/framebuffer_map.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::{collections::HashMap, mem::MaybeUninit}; use thiserror::Error; @@ -13,8 +13,12 @@ pub enum MemoryMappedFrameBufferError { len: usize, fd_len: usize, }, + #[error("Plane {index} has an invalid offset")] + InvalidOffset { index: usize }, #[error("mmap failed with {0:?}")] MemoryMapError(std::io::Error), + #[error("mapping was created read-only; write access requested")] + NotWritable, } struct MappedPlane { @@ -26,7 +30,9 @@ struct MappedPlane { /// FrameBuffer wrapper, which exposes internal file descriptors as memory mapped [&[u8]] plane slices. pub struct MemoryMappedFrameBuffer { fb: T, - mmaps: HashMap, + writable: bool, + /// fd -> (mapped_ptr, mapped_len, map_offset) + mmaps: HashMap, planes: Vec, } @@ -35,35 +41,65 @@ impl MemoryMappedFrameBuffer { /// /// This might fail if framebuffer has invalid plane sizes/offsets or if [libc::mmap] fails itself. pub fn new(fb: T) -> Result { + Self::with_access(fb, false) + } + + /// Memory map framebuffer for read/write access. Mapping will be `PROT_READ | PROT_WRITE`. + pub fn new_writable(fb: T) -> Result { + Self::with_access(fb, true) + } + + fn with_access(fb: T, writable: bool) -> Result { struct MapInfo { + /// Page-aligned start offset for mapping + start: usize, /// Maximum offset used by data planes - mapped_len: usize, + end: usize, /// Total file descriptor size total_len: usize, } let mut planes = Vec::new(); let mut map_info: HashMap = HashMap::new(); + let page_size = { + let ps = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }; + if ps > 0 { + ps as usize + } else { + 4096 + } + }; for (index, plane) in fb.planes().into_iter().enumerate() { let fd = plane.fd(); - let offset = plane.offset().unwrap(); + let offset = plane + .offset() + .ok_or(MemoryMappedFrameBufferError::InvalidOffset { index })?; let len = plane.len(); planes.push(MappedPlane { fd, offset, len }); // Find total FD length if not known yet map_info.entry(fd).or_insert_with(|| { - let total_len = unsafe { libc::lseek64(fd, 0, libc::SEEK_END) } as usize; + let mut st = MaybeUninit::::uninit(); + let ret = unsafe { libc::fstat(fd, st.as_mut_ptr()) }; + let total_len = if ret != 0 { + 0 + } else { + let st = unsafe { st.assume_init() }; + st.st_size as usize + }; MapInfo { - mapped_len: 0, + start: offset, + end: offset, total_len, } }); let info = map_info.get_mut(&fd).unwrap(); - if offset + len > info.total_len { + // If total_len is 0 (unknown for many DMA-BUFs), skip the bound check and let mmap fail if invalid. + if info.total_len > 0 && offset + len > info.total_len { return Err(MemoryMappedFrameBufferError::PlaneOutOfBounds { index, offset, @@ -72,20 +108,23 @@ impl MemoryMappedFrameBuffer { }); } - info.mapped_len = info.mapped_len.max(offset + len); + let aligned_start = offset - (offset % page_size); + info.start = info.start.min(aligned_start); + info.end = info.end.max(offset + len); } let mmaps = map_info .iter() .map(|(fd, info)| { + let map_len = info.end.saturating_sub(info.start); let addr = unsafe { libc::mmap64( core::ptr::null_mut(), - info.mapped_len, - libc::PROT_READ, + map_len, + libc::PROT_READ | if writable { libc::PROT_WRITE } else { 0 }, libc::MAP_SHARED, *fd, - 0, + info.start as _, ) }; @@ -94,13 +133,18 @@ impl MemoryMappedFrameBuffer { std::io::Error::last_os_error(), )) } else { - Ok((*fd, (addr.cast_const(), info.mapped_len))) + Ok((*fd, (addr, map_len, info.start))) } }) - .collect::, MemoryMappedFrameBufferError>>() + .collect::, MemoryMappedFrameBufferError>>() .unwrap(); - Ok(Self { fb, mmaps, planes }) + Ok(Self { + fb, + writable, + mmaps, + planes, + }) } /// Returns data slice for each plane within the framebuffer. @@ -108,11 +152,41 @@ impl MemoryMappedFrameBuffer { self.planes .iter() .map(|plane| { - let mmap_ptr: *const u8 = self.mmaps[&plane.fd].0.cast(); - unsafe { core::slice::from_raw_parts(mmap_ptr.add(plane.offset), plane.len) } + let (mmap_ptr, _, map_offset) = self.mmaps[&plane.fd]; + let mmap_ptr: *const u8 = mmap_ptr.cast(); + let offset = plane.offset - map_offset; + unsafe { core::slice::from_raw_parts(mmap_ptr.add(offset), plane.len) } }) .collect() } + + /// Returns mutable data slices for each plane within the framebuffer. Mapping must be writable. + pub fn data_mut(&mut self) -> Result, MemoryMappedFrameBufferError> { + if !self.writable { + return Err(MemoryMappedFrameBufferError::NotWritable); + } + + Ok(self + .planes + .iter() + .map(|plane| { + let (mmap_ptr, _, map_offset) = self.mmaps[&plane.fd]; + let mmap_ptr: *mut u8 = mmap_ptr.cast(); + let offset = plane.offset - map_offset; + unsafe { core::slice::from_raw_parts_mut(mmap_ptr.add(offset), plane.len) } + }) + .collect()) + } + + /// Returns true if this mapping was created with write access. + pub fn is_writable(&self) -> bool { + self.writable + } + + /// Returns the mapped length for a given file descriptor, if present. + pub fn mapped_len(&self, fd: i32) -> Option { + self.mmaps.get(&fd).map(|(_, len, _)| *len) + } } impl AsFrameBuffer for MemoryMappedFrameBuffer { @@ -126,9 +200,9 @@ unsafe impl Send for MemoryMappedFrameBuffer {} impl Drop for MemoryMappedFrameBuffer { fn drop(&mut self) { // Unmap - for (_fd, (ptr, size)) in self.mmaps.drain() { + for (_fd, (ptr, size, _map_offset)) in self.mmaps.drain() { unsafe { - libc::munmap(ptr.cast_mut(), size); + libc::munmap(ptr, size); } } } diff --git a/libcamera/src/geometry.rs b/libcamera/src/geometry.rs index 46fd6aa..43b3c27 100644 --- a/libcamera/src/geometry.rs +++ b/libcamera/src/geometry.rs @@ -20,6 +20,116 @@ pub struct Size { pub height: u32, } +impl Size { + pub const fn new(width: u32, height: u32) -> Self { + Self { width, height } + } + + pub fn align_down_to(self, h_alignment: u32, v_alignment: u32) -> Self { + if h_alignment == 0 || v_alignment == 0 { + return self; + } + Self { + width: self.width / h_alignment * h_alignment, + height: self.height / v_alignment * v_alignment, + } + } + + pub fn align_up_to(self, h_alignment: u32, v_alignment: u32) -> Self { + if h_alignment == 0 || v_alignment == 0 { + return self; + } + Self { + width: self.width.div_ceil(h_alignment) * h_alignment, + height: self.height.div_ceil(v_alignment) * v_alignment, + } + } + + pub fn bound_to(self, bound: Size) -> Self { + Self { + width: self.width.min(bound.width), + height: self.height.min(bound.height), + } + } + + pub fn expand_to(self, expand: Size) -> Self { + Self { + width: self.width.max(expand.width), + height: self.height.max(expand.height), + } + } + + pub fn grow_by(self, margins: Size) -> Self { + Self { + width: self.width.saturating_add(margins.width), + height: self.height.saturating_add(margins.height), + } + } + + pub fn shrink_by(self, margins: Size) -> Self { + Self { + width: self.width.saturating_sub(margins.width), + height: self.height.saturating_sub(margins.height), + } + } + + /// Bound this size down to match the aspect ratio of `ratio`. + pub fn bounded_to_aspect_ratio(self, ratio: Size) -> Self { + if ratio.width == 0 || ratio.height == 0 { + return self; + } + + let ratio1 = self.width as u64 * ratio.height as u64; + let ratio2 = ratio.width as u64 * self.height as u64; + + if ratio1 > ratio2 { + Self { + width: (ratio2 / ratio.height as u64) as u32, + height: self.height, + } + } else { + Self { + width: self.width, + height: (ratio1 / ratio.width as u64) as u32, + } + } + } + + /// Expand this size up to match the aspect ratio of `ratio`. + pub fn expanded_to_aspect_ratio(self, ratio: Size) -> Self { + if ratio.width == 0 || ratio.height == 0 { + return self; + } + + let ratio1 = self.width as u64 * ratio.height as u64; + let ratio2 = ratio.width as u64 * self.height as u64; + + if ratio1 < ratio2 { + Self { + width: (ratio2 / ratio.height as u64) as u32, + height: self.height, + } + } else { + Self { + width: self.width, + height: (ratio1 / ratio.width as u64) as u32, + } + } + } + + /// Center a rectangle of this size at the given point. + pub fn centered_to(self, center: Point) -> Rectangle { + let x = center.x - (self.width as i32 / 2); + let y = center.y - (self.height as i32 / 2); + Rectangle { + x, + y, + width: self.width, + height: self.height, + } + } +} + impl From for Size { fn from(s: libcamera_size_t) -> Self { Self { @@ -47,6 +157,33 @@ pub struct SizeRange { pub v_step: u32, } +impl SizeRange { + pub fn contains(&self, size: Size) -> bool { + if size.width < self.min.width + || size.width > self.max.width + || size.height < self.min.height + || size.height > self.max.height + { + return false; + } + + if self.h_step != 0 { + let delta_w = size.width - self.min.width; + if !delta_w.is_multiple_of(self.h_step) { + return false; + } + } + if self.v_step != 0 { + let delta_h = size.height - self.min.height; + if !delta_h.is_multiple_of(self.v_step) { + return false; + } + } + + true + } +} + impl From for SizeRange { fn from(r: libcamera_size_range_t) -> Self { Self { @@ -78,6 +215,140 @@ pub struct Rectangle { pub height: u32, } +impl Rectangle { + pub fn size(&self) -> Size { + Size { + width: self.width, + height: self.height, + } + } + + /// Center point of the rectangle. + pub fn center(&self) -> Point { + Point { + x: self.x.saturating_add((self.width / 2) as i32), + y: self.y.saturating_add((self.height / 2) as i32), + } + } + + /// Top-left corner of the rectangle. + pub fn top_left(&self) -> Point { + Point { x: self.x, y: self.y } + } + + /// Intersection of this rectangle with another. + pub fn bounded_to(self, bound: Rectangle) -> Rectangle { + let top_left_x = i64::from(self.x).max(i64::from(bound.x)); + let top_left_y = i64::from(self.y).max(i64::from(bound.y)); + let bottom_right_x = + (i64::from(self.x) + i64::from(self.width)).min(i64::from(bound.x) + i64::from(bound.width)); + let bottom_right_y = + (i64::from(self.y) + i64::from(self.height)).min(i64::from(bound.y) + i64::from(bound.height)); + + let new_width = if bottom_right_x > top_left_x { + (bottom_right_x - top_left_x) as u32 + } else { + 0 + }; + let new_height = if bottom_right_y > top_left_y { + (bottom_right_y - top_left_y) as u32 + } else { + 0 + }; + + Rectangle { + x: top_left_x as i32, + y: top_left_y as i32, + width: new_width, + height: new_height, + } + } + + /// Translate the rectangle so it remains enclosed within the given boundary. + pub fn enclosed_in(self, boundary: Rectangle) -> Rectangle { + let mut result = self.bounded_to(Rectangle { + x: self.x, + y: self.y, + width: boundary.width, + height: boundary.height, + }); + + let clamp = |val: i64, min: i64, max: i64| -> i64 { + if val < min { + min + } else if val > max { + max + } else { + val + } + }; + + let max_x = i64::from(boundary.x) + i64::from(boundary.width) - i64::from(result.width); + let max_y = i64::from(boundary.y) + i64::from(boundary.height) - i64::from(result.height); + + result.x = clamp(i64::from(result.x), i64::from(boundary.x), max_x) as i32; + result.y = clamp(i64::from(result.y), i64::from(boundary.y), max_y) as i32; + result + } + + /// Return a translated rectangle. + pub fn translated_by(self, delta: Point) -> Rectangle { + Rectangle { + x: self.x.saturating_add(delta.x), + y: self.y.saturating_add(delta.y), + width: self.width, + height: self.height, + } + } + + /// Return a rectangle scaled by rational factors. + pub fn scaled_by(self, numerator: Size, denominator: Size) -> Rectangle { + if denominator.width == 0 || denominator.height == 0 { + return self; + } + Rectangle { + x: (i64::from(self.x) * i64::from(numerator.width) / i64::from(denominator.width)) as i32, + y: (i64::from(self.y) * i64::from(numerator.height) / i64::from(denominator.height)) as i32, + width: (u64::from(self.width) * u64::from(numerator.width) / u64::from(denominator.width)) as u32, + height: (u64::from(self.height) * u64::from(numerator.height) / u64::from(denominator.height)) as u32, + } + } +} + +impl core::ops::Mul for Size { + type Output = Size; + + fn mul(self, rhs: f32) -> Self::Output { + Size { + width: (self.width as f32 * rhs) as u32, + height: (self.height as f32 * rhs) as u32, + } + } +} + +impl core::ops::Div for Size { + type Output = Size; + + fn div(self, rhs: f32) -> Self::Output { + Size { + width: (self.width as f32 / rhs) as u32, + height: (self.height as f32 / rhs) as u32, + } + } +} + +impl core::ops::MulAssign for Size { + fn mul_assign(&mut self, rhs: f32) { + *self = *self * rhs; + } +} + +impl core::ops::DivAssign for Size { + fn div_assign(&mut self, rhs: f32) { + *self = *self / rhs; + } +} + impl From for Rectangle { fn from(r: libcamera_rectangle_t) -> Self { Self { @@ -99,3 +370,13 @@ impl From for libcamera_rectangle_t { } } } + +impl Size { + /// Return a size with width and height swapped. + pub fn transposed(self) -> Self { + Size { + width: self.height, + height: self.width, + } + } +} diff --git a/libcamera/src/lib.rs b/libcamera/src/lib.rs index 7759bc8..491d836 100644 --- a/libcamera/src/lib.rs +++ b/libcamera/src/lib.rs @@ -1,9 +1,17 @@ +//! Safe Rust bindings for libcamera. +//! +//! Notable helper modules: +//! - [`formats`]: generated pixel format constants matching `libcamera::formats`. +//! - [`controls`] and [`properties`]: generated identifiers for the installed libcamera version. #![warn(rust_2018_idioms)] pub mod camera; pub mod camera_manager; +pub mod color_space; pub mod control; pub mod control_value; +pub mod fence; +pub mod formats; pub mod framebuffer; pub mod framebuffer_allocator; pub mod framebuffer_map; @@ -12,7 +20,10 @@ pub mod logging; pub mod pixel_format; pub mod request; pub mod stream; +pub mod transform; pub mod utils; +pub mod vendor_features; +pub mod version; mod generated; pub use generated::*; diff --git a/libcamera/src/logging.rs b/libcamera/src/logging.rs index 9aaa997..a38dded 100644 --- a/libcamera/src/logging.rs +++ b/libcamera/src/logging.rs @@ -12,6 +12,8 @@ use crate::utils::handle_result; pub enum LoggingTarget { None, Syslog, + File, + Stream, } impl From for libcamera_logging_target_t { @@ -19,6 +21,8 @@ impl From for libcamera_logging_target_t { match value { LoggingTarget::None => libcamera_logging_target::LIBCAMERA_LOGGING_TARGET_NONE, LoggingTarget::Syslog => libcamera_logging_target::LIBCAMERA_LOGGING_TARGET_SYSLOG, + LoggingTarget::File => libcamera_logging_target::LIBCAMERA_LOGGING_TARGET_FILE, + LoggingTarget::Stream => libcamera_logging_target::LIBCAMERA_LOGGING_TARGET_STREAM, } } } @@ -48,6 +52,7 @@ impl From for &'static CStr { pub enum LoggingStream { StdOut, StdErr, + Custom(*mut core::ffi::c_void), } impl From for libcamera_logging_stream_t { @@ -55,6 +60,7 @@ impl From for libcamera_logging_stream_t { match value { LoggingStream::StdOut => libcamera_logging_stream::LIBCAMERA_LOGGING_STREAM_STDOUT, LoggingStream::StdErr => libcamera_logging_stream::LIBCAMERA_LOGGING_STREAM_STDERR, + LoggingStream::Custom(_) => libcamera_logging_stream::LIBCAMERA_LOGGING_STREAM_CUSTOM, } } } @@ -68,7 +74,12 @@ pub fn log_set_file(file: &str, color: bool) -> io::Result<()> { /// Direct logging to a stream. pub fn log_set_stream(stream: LoggingStream, color: bool) -> io::Result<()> { - let ret = unsafe { libcamera_log_set_stream(stream.into(), color) }; + let ret = unsafe { + match stream { + LoggingStream::Custom(ptr) => libcamera_log_set_custom_stream(ptr, color), + _ => libcamera_log_set_stream(stream.into(), color), + } + }; handle_result(ret) } @@ -77,3 +88,36 @@ pub fn log_set_target(target: LoggingTarget) -> io::Result<()> { let ret = unsafe { libcamera_log_set_target(target.into()) }; handle_result(ret) } + +/// Convenience: direct logging to stderr and set a default level for the "Camera" category. +pub fn configure_stderr(category: &str, level: LoggingLevel, color: bool) -> io::Result<()> { + log_set_stream(LoggingStream::StdErr, color)?; + let cm = crate::camera_manager::CameraManager::new()?; + cm.log_set_level(category, level); + Ok(()) +} + +/// Convenience: configure logging target and stream without creating a CameraManager. +pub fn configure_logging(target: LoggingTarget, stream: Option, color: bool) -> io::Result<()> { + if let Some(s) = stream { + log_set_stream(s, color)?; + log_set_target(LoggingTarget::Stream)?; + } else { + log_set_target(target)?; + } + Ok(()) +} + +/// Convenience: direct logging to stdout and set a default level for the given category. +pub fn configure_stdout(category: &str, level: LoggingLevel, color: bool) -> io::Result<()> { + log_set_stream(LoggingStream::StdOut, color)?; + set_category_level(category, level); + Ok(()) +} + +/// Set the log level for a category without constructing a CameraManager. +pub fn set_category_level(category: &str, level: LoggingLevel) { + let category = CString::new(category).expect("category contains null byte"); + let level: &CStr = level.into(); + unsafe { libcamera_log_set_level(category.as_ptr(), level.as_ptr()) }; +} diff --git a/libcamera/src/pixel_format.rs b/libcamera/src/pixel_format.rs index 07a3d6c..66cfe3f 100644 --- a/libcamera/src/pixel_format.rs +++ b/libcamera/src/pixel_format.rs @@ -1,13 +1,88 @@ -use std::{ffi::CStr, ptr::NonNull}; +use std::{ffi::CStr, fmt, ptr::NonNull, str::FromStr}; use drm_fourcc::{DrmFormat, DrmFourcc, DrmModifier}; use libcamera_sys::*; +use crate::geometry::Size; + +mod pixel_format_info_generated { + include!(concat!(env!("OUT_DIR"), "/pixel_format_info.rs")); +} +use pixel_format_info_generated::{PixelFormatInfoData, PIXEL_FORMAT_INFO}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ColourEncoding { + Rgb, + Yuv, + Raw, + Unknown(u32), +} + +impl From for ColourEncoding { + fn from(v: u32) -> Self { + match v { + 0 => ColourEncoding::Rgb, + 1 => ColourEncoding::Yuv, + 2 => ColourEncoding::Raw, + other => ColourEncoding::Unknown(other), + } + } +} + +#[derive(Debug, Clone)] +pub struct PixelFormatPlaneInfo { + pub bytes_per_group: u32, + pub vertical_sub_sampling: u32, +} + +#[derive(Debug, Clone)] +pub struct PixelFormatInfo { + pub name: String, + pub format: PixelFormat, + pub bits_per_pixel: u32, + pub colour_encoding: ColourEncoding, + pub packed: bool, + pub pixels_per_group: u32, + pub planes: Vec, + pub v4l2_formats: Vec, +} + +impl PixelFormatInfo { + fn from_data(fmt: PixelFormat, data: &PixelFormatInfoData) -> Self { + let planes = data + .planes + .iter() + .filter(|p| p.bytes_per_group > 0 && p.vertical_sub_sampling > 0) + .map(|p| PixelFormatPlaneInfo { + bytes_per_group: p.bytes_per_group, + vertical_sub_sampling: p.vertical_sub_sampling, + }) + .collect(); + Self { + name: data.name.to_string(), + format: fmt, + bits_per_pixel: data.bits_per_pixel, + colour_encoding: data.colour_encoding.into(), + packed: data.packed, + pixels_per_group: data.pixels_per_group, + planes, + v4l2_formats: data.v4l2_formats.to_vec(), + } + } +} + /// Represents `libcamera::PixelFormat`, which itself is a pair of fourcc code and u64 modifier as defined in `libdrm`. #[derive(Clone, Copy)] pub struct PixelFormat(pub(crate) libcamera_pixel_format_t); impl PixelFormat { + fn info_entry(&self) -> Option<&'static PixelFormatInfoData> { + let (fourcc, modifier) = self.to_raw(); + PIXEL_FORMAT_INFO + .iter() + .find(|info| info.fourcc == fourcc && info.modifier == modifier) + } + /// Constructs new [PixelFormat] from given fourcc code and modifier. /// /// # Examples @@ -37,6 +112,76 @@ impl PixelFormat { pub fn set_modifier(&mut self, modifier: u64) { self.0.modifier = modifier; } + + /// Returns true if this format has a non-zero modifier set. + pub fn has_modifier(&self) -> bool { + self.modifier() != 0 + } + + /// Compute the stride for a plane given width and optional alignment. + pub fn stride(&self, width: u32, plane: u32, align: u32) -> u32 { + self.info_entry() + .map(|info| compute_stride(info, width, plane, align)) + .unwrap_or(0) + } + + /// Compute plane size for the given frame size and plane index. + pub fn plane_size(&self, size: Size, plane: u32, align: u32) -> u32 { + self.info_entry() + .map(|info| compute_plane_size(info, size, plane, align)) + .unwrap_or(0) + } + + /// Compute total frame size for the given dimensions. + pub fn frame_size(&self, size: Size, align: u32) -> u32 { + self.info_entry() + .map(|info| compute_frame_size(info, size, align)) + .unwrap_or(0) + } + + /// Clears the modifier to zero. + pub fn clear_modifier(&mut self) { + self.0.modifier = 0; + } + + /// Returns the raw `(fourcc, modifier)` tuple. + pub const fn to_raw(self) -> (u32, u64) { + (self.0.fourcc, self.0.modifier) + } + + /// Constructs a PixelFormat from raw `(fourcc, modifier)` parts. + pub const fn from_raw_parts(fourcc: u32, modifier: u64) -> Self { + PixelFormat::new(fourcc, modifier) + } + + /// Parse a PixelFormat from its string representation (e.g. "YUYV"). + pub fn parse(name: &str) -> Option { + let cstr = std::ffi::CString::new(name).ok()?; + let fmt = unsafe { libcamera_pixel_format_from_str(cstr.as_ptr()) }; + let pf = PixelFormat(fmt); + if pf.is_valid() { + Some(pf) + } else { + None + } + } + + /// Returns true if the PixelFormat represents a valid libcamera format. + pub fn is_valid(&self) -> bool { + unsafe { libcamera_pixel_format_is_valid(&self.0) } + } + + pub fn info(&self) -> Option { + self.info_entry().map(|data| PixelFormatInfo::from_data(*self, data)) + } +} + +impl FromStr for PixelFormat { + type Err = String; + + fn from_str(s: &str) -> Result { + PixelFormat::parse(s).ok_or_else(|| format!("unrecognized pixel format: {s}")) + } } impl PartialEq for PixelFormat { @@ -57,6 +202,65 @@ impl core::fmt::Debug for PixelFormat { } } +impl fmt::Display for PixelFormat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +fn compute_stride(info: &PixelFormatInfoData, width: u32, plane: u32, align: u32) -> u32 { + if plane as usize >= info.planes.len() { + return 0; + } + let plane_info = &info.planes[plane as usize]; + if plane_info.bytes_per_group == 0 || plane_info.vertical_sub_sampling == 0 { + return 0; + } + let groups = (width as u64).div_ceil(info.pixels_per_group as u64); + let mut stride = groups * plane_info.bytes_per_group as u64; + if align > 0 { + stride = stride.div_ceil(align as u64) * align as u64; + } + stride as u32 +} + +fn compute_plane_size(info: &PixelFormatInfoData, size: Size, plane: u32, align: u32) -> u32 { + if plane as usize >= info.planes.len() { + return 0; + } + let plane_info = &info.planes[plane as usize]; + if plane_info.vertical_sub_sampling == 0 { + return 0; + } + let stride = compute_stride(info, size.width, plane, align) as u64; + // ceil(height / vertical_sub_sampling) + let height = (size.height as u64).div_ceil(plane_info.vertical_sub_sampling as u64); + (stride * height) as u32 +} + +fn compute_frame_size(info: &PixelFormatInfoData, size: Size, align: u32) -> u32 { + let mut total: u64 = 0; + for p in 0..info.planes.len() { + let plane = &info.planes[p]; + if plane.bytes_per_group == 0 || plane.vertical_sub_sampling == 0 { + continue; + } + total += compute_plane_size(info, size, p as u32, align) as u64; + } + total as u32 +} + +impl From for ColourEncoding { + fn from(v: u8) -> Self { + match v { + 0 => ColourEncoding::Rgb, + 1 => ColourEncoding::Yuv, + 2 => ColourEncoding::Raw, + other => ColourEncoding::Unknown(other as u32), + } + } +} + impl TryFrom for DrmFormat { type Error = drm_fourcc::UnrecognizedFourcc; diff --git a/libcamera/src/request.rs b/libcamera/src/request.rs index b5d2686..b6e2b70 100644 --- a/libcamera/src/request.rs +++ b/libcamera/src/request.rs @@ -1,11 +1,80 @@ #![allow(clippy::manual_strip)] -use std::{any::Any, collections::HashMap, io, ptr::NonNull}; +use std::{any::Any, collections::HashMap, io, marker::PhantomData, ptr::NonNull}; use bitflags::bitflags; use libcamera_sys::*; -use crate::{control::ControlList, framebuffer::AsFrameBuffer, stream::Stream}; +use crate::{control::ControlList, fence::Fence, framebuffer::AsFrameBuffer, stream::Stream}; + +/// Non-owning view of a libcamera request. +pub struct RequestRef<'d> { + pub(crate) ptr: NonNull, + _phantom: PhantomData<&'d ()>, +} + +impl<'d> RequestRef<'d> { + pub(crate) unsafe fn from_ptr(ptr: NonNull) -> Self { + Self { + ptr, + _phantom: Default::default(), + } + } + + pub fn controls(&self) -> &ControlList { + unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) } + } + + pub fn metadata(&self) -> &ControlList { + unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_metadata(self.ptr.as_ptr())).unwrap()) } + } + + pub fn find_buffer(&self, stream: &Stream) -> Option<*mut libcamera_framebuffer_t> { + let ptr = unsafe { libcamera_request_find_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr()) }; + NonNull::new(ptr).map(|p| p.as_ptr()) + } + + pub fn has_pending_buffers(&self) -> bool { + unsafe { libcamera_request_has_pending_buffers(self.ptr.as_ptr()) } + } + + pub fn to_string_repr(&self) -> String { + unsafe { + let ptr = libcamera_request_to_string(self.ptr.as_ptr()); + if ptr.is_null() { + return String::new(); + } + let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned(); + libc::free(ptr.cast()); + s + } + } + + /// Iterate over buffers attached to this request as (Stream, framebuffer pointer). + pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> { + RequestBufferMapIter::new(self.ptr) + } + + /// Returns auto-incrementing sequence number of the capture + pub fn sequence(&self) -> u32 { + unsafe { libcamera_request_sequence(self.ptr.as_ptr()) } + } + + /// Returns request identifier that was provided in + /// [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request). + /// + /// Returns zero if cookie was not provided. + pub fn cookie(&self) -> u64 { + unsafe { libcamera_request_cookie(self.ptr.as_ptr()) } + } + + /// Capture request status + pub fn status(&self) -> RequestStatus { + RequestStatus::try_from(unsafe { libcamera_request_status(self.ptr.as_ptr()) }).unwrap() + } +} + +unsafe impl Send for RequestRef<'_> {} /// Status of [Request] #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -88,7 +157,32 @@ impl Request { let ret = unsafe { libcamera_request_add_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr(), buffer.ptr().as_ptr()) }; if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err(io::Error::from_raw_os_error(-ret)) + } else { + self.buffers.insert(*stream, Box::new(buffer)); + Ok(()) + } + } + + /// Attaches framebuffer to the request with an optional acquire fence (fd is consumed). + pub fn add_buffer_with_fence( + &mut self, + stream: &Stream, + buffer: T, + fence: Option, + ) -> io::Result<()> { + let fence_ptr = fence.map(Fence::into_raw).unwrap_or(std::ptr::null_mut()); + + let ret = unsafe { + libcamera_request_add_buffer_with_fence( + self.ptr.as_ptr(), + stream.ptr.as_ptr(), + buffer.ptr().as_ptr(), + fence_ptr, + ) + }; + if ret < 0 { + Err(io::Error::from_raw_os_error(-ret)) } else { self.buffers.insert(*stream, Box::new(buffer)); Ok(()) @@ -109,6 +203,38 @@ impl Request { self.buffers.get_mut(stream).and_then(|b| b.downcast_mut()) } + pub(crate) fn stream_for_buffer_ptr(&self, fb_ptr: *mut libcamera_framebuffer_t) -> Option { + self.buffers_iter() + .find_map(|(s, ptr)| if ptr == fb_ptr { Some(s) } else { None }) + } + + /// Returns the buffer attached to a stream (raw pointer). + pub fn find_buffer(&self, stream: &Stream) -> Option<*mut libcamera_framebuffer_t> { + let ptr = unsafe { libcamera_request_find_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr()) }; + NonNull::new(ptr).map(|p| p.as_ptr()) + } + + pub fn has_pending_buffers(&self) -> bool { + unsafe { libcamera_request_has_pending_buffers(self.ptr.as_ptr()) } + } + + pub fn to_string_repr(&self) -> String { + unsafe { + let ptr = libcamera_request_to_string(self.ptr.as_ptr()); + if ptr.is_null() { + return String::new(); + } + let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned(); + libc::free(ptr.cast()); + s + } + } + + /// Iterate over buffers attached to this request as (Stream, framebuffer pointer). + pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> { + RequestBufferMapIter::new(self.ptr) + } + /// Returns auto-incrementing sequence number of the capture pub fn sequence(&self) -> u32 { unsafe { libcamera_request_sequence(self.ptr.as_ptr()) } @@ -135,16 +261,17 @@ impl Request { /// via [Self::add_buffer()] by setting flags to [ReuseFlag::REUSE_BUFFERS]. pub fn reuse(&mut self, flags: ReuseFlag) { unsafe { libcamera_request_reuse(self.ptr.as_ptr(), flags.bits()) } + // Mirror libcamera behaviour: unless REUSE_BUFFERS is set, drop our buffer map so callbacks + // and buffer() lookups can't return stale handles. + if !flags.contains(ReuseFlag::REUSE_BUFFERS) { + self.buffers.clear(); + } } } impl core::fmt::Debug for Request { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Request") - .field("seq", &self.sequence()) - .field("status", &self.status()) - .field("cookie", &self.cookie()) - .finish() + f.write_str(&self.to_string_repr()) } } @@ -155,3 +282,43 @@ impl Drop for Request { } unsafe impl Send for Request {} + +pub struct RequestBufferMapIter<'d> { + iter: NonNull, + _phantom: core::marker::PhantomData<&'d libcamera_request_buffer_map_t>, +} + +impl<'d> RequestBufferMapIter<'d> { + pub fn new(req_ptr: NonNull) -> Self { + let map = unsafe { libcamera_request_buffers(req_ptr.as_ptr()) }; + let iter = NonNull::new(unsafe { libcamera_request_buffer_map_iter(map.cast_mut()) }).unwrap(); + Self { + iter, + _phantom: Default::default(), + } + } +} + +impl<'d> Iterator for RequestBufferMapIter<'d> { + type Item = (Stream, *mut libcamera_framebuffer_t); + + fn next(&mut self) -> Option { + if unsafe { libcamera_request_buffer_map_iter_end(self.iter.as_ptr()) } { + return None; + } + let stream = unsafe { + Stream::from_ptr( + NonNull::new(libcamera_request_buffer_map_iter_stream(self.iter.as_ptr()) as *mut _).unwrap(), + ) + }; + let buffer = unsafe { libcamera_request_buffer_map_iter_buffer(self.iter.as_ptr()) }; + unsafe { libcamera_request_buffer_map_iter_next(self.iter.as_ptr()) }; + Some((stream, buffer)) + } +} + +impl Drop for RequestBufferMapIter<'_> { + fn drop(&mut self) { + unsafe { libcamera_request_buffer_map_iter_destroy(self.iter.as_ptr()) } + } +} diff --git a/libcamera/src/stream.rs b/libcamera/src/stream.rs index c5713ed..da5867c 100644 --- a/libcamera/src/stream.rs +++ b/libcamera/src/stream.rs @@ -3,6 +3,7 @@ use std::{marker::PhantomData, ptr::NonNull}; use libcamera_sys::*; use crate::{ + color_space::ColorSpace, geometry::{Size, SizeRange}, pixel_format::{PixelFormat, PixelFormats}, utils::Immutable, @@ -104,6 +105,10 @@ impl StreamConfigurationRef<'_> { } } + pub(crate) fn as_ptr(&self) -> *const libcamera_stream_configuration_t { + self.ptr.as_ptr() + } + pub fn get_pixel_format(&self) -> PixelFormat { PixelFormat(unsafe { self.ptr.as_ref() }.pixel_format) } @@ -124,6 +129,7 @@ impl StreamConfigurationRef<'_> { unsafe { self.ptr.as_ref() }.stride } + /// Stride is typically populated by libcamera after validate(); overriding manually is advanced use. pub fn set_stride(&mut self, stride: u32) { unsafe { self.ptr.as_mut() }.stride = stride } @@ -132,6 +138,7 @@ impl StreamConfigurationRef<'_> { unsafe { self.ptr.as_ref() }.frame_size } + /// Frame size is typically populated by libcamera after validate(); overriding manually is advanced use. pub fn set_frame_size(&mut self, frame_size: u32) { unsafe { self.ptr.as_mut() }.frame_size = frame_size } @@ -144,6 +151,27 @@ impl StreamConfigurationRef<'_> { unsafe { self.ptr.as_mut() }.buffer_count = buffer_count; } + /// Returns the configured color space, if any. + pub fn get_color_space(&self) -> Option { + if unsafe { libcamera_stream_configuration_has_color_space(self.ptr.as_ptr()) } { + Some(ColorSpace::from(unsafe { + libcamera_stream_configuration_get_color_space(self.ptr.as_ptr()) + })) + } else { + None + } + } + + /// Sets the color space for this stream configuration. Pass `None` to clear it. + pub fn set_color_space(&mut self, color_space: Option) { + unsafe { + match color_space { + Some(cs) => libcamera_stream_configuration_set_color_space(self.ptr.as_ptr(), &cs.into()), + None => libcamera_stream_configuration_set_color_space(self.ptr.as_ptr(), core::ptr::null()), + } + } + } + /// Returns initialized [Stream] for this configuration. /// /// Stream is only available once this configuration is applied with @@ -164,6 +192,19 @@ impl StreamConfigurationRef<'_> { ) } } + + /// Return the libcamera textual representation of this configuration. + pub fn to_string_repr(&self) -> String { + unsafe { + let ptr = libcamera_stream_configuration_to_string(self.ptr.as_ptr()); + if ptr.is_null() { + return String::new(); + } + let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned(); + libc::free(ptr.cast()); + s + } + } } impl core::fmt::Debug for StreamConfigurationRef<'_> { @@ -174,6 +215,7 @@ impl core::fmt::Debug for StreamConfigurationRef<'_> { .field("stride", &self.get_stride()) .field("frame_size", &self.get_frame_size()) .field("buffer_count", &self.get_buffer_count()) + .field("color_space", &self.get_color_space()) .finish() } } @@ -181,7 +223,7 @@ impl core::fmt::Debug for StreamConfigurationRef<'_> { /// Handle to a camera stream. /// /// Obtained from [StreamConfigurationRef::stream()] and is valid as long as camera configuration is unchanged. -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] pub struct Stream { /// libcamera_stream_t is used as unique key across various libcamera structures /// and adding a lifetime would be really inconvenient. Dangling pointer should not @@ -194,6 +236,13 @@ impl Stream { pub(crate) unsafe fn from_ptr(ptr: NonNull) -> Self { Self { ptr } } + + /// Returns the active [StreamConfigurationRef] for this stream, if available. + pub fn configuration(&self) -> Option>> { + let cfg = unsafe { libcamera_stream_get_configuration(self.ptr.as_ptr()) }; + NonNull::new(cfg as *mut libcamera_stream_configuration_t) + .map(|p| Immutable(unsafe { StreamConfigurationRef::from_ptr(p) })) + } } unsafe impl Send for Stream {} diff --git a/libcamera/src/transform.rs b/libcamera/src/transform.rs new file mode 100644 index 0000000..2e08e7f --- /dev/null +++ b/libcamera/src/transform.rs @@ -0,0 +1,116 @@ +use libcamera_sys::*; + +use crate::camera::Orientation; + +/// 2D plane transform matching libcamera::Transform. +#[derive(Clone, Copy, Debug)] +pub struct Transform(pub libcamera_transform_t); + +impl Transform { + pub fn hflip() -> Self { + Transform(unsafe { libcamera_transform_hflip() }) + } + pub fn vflip() -> Self { + Transform(unsafe { libcamera_transform_vflip() }) + } + pub fn transpose() -> Self { + Transform(unsafe { libcamera_transform_transpose() }) + } +} + +impl Transform { + pub fn identity() -> Self { + Transform(unsafe { libcamera_transform_identity() }) + } + + /// Construct from rotation degrees, optionally applying hflip. + pub fn from_rotation(angle: i32, hflip: bool) -> Option { + let mut success = false; + let t = unsafe { libcamera_transform_from_rotation(angle, hflip, &mut success) }; + if success { + Some(Transform(t)) + } else { + None + } + } + + pub fn inverse(self) -> Self { + Transform(unsafe { libcamera_transform_inverse(self.0) }) + } + + pub fn combine(self, other: Transform) -> Self { + Transform(unsafe { libcamera_transform_combine(self.0, other.0) }) + } + + pub fn to_string_repr(self) -> String { + unsafe { + let ptr = libcamera_transform_to_string(self.0); + if ptr.is_null() { + return String::new(); + } + let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned(); + libc::free(ptr.cast()); + s + } + } +} + +impl std::fmt::Display for Transform { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.to_string_repr()) + } +} + +impl Transform { + /// Compute the transform between two orientations (equivalent to libcamera Orientation division). + pub fn between_orientations(from: Orientation, to: Orientation) -> Self { + Transform(unsafe { libcamera_transform_between_orientations(from.into(), to.into()) }) + } +} + +pub fn apply_transform_to_orientation(orientation: Orientation, transform: Transform) -> Orientation { + unsafe { + libcamera_transform_apply_orientation(orientation.into(), transform.0) + .try_into() + .unwrap() + } +} + +/// Convert a rotation angle to an EXIF orientation using libcamera's helper. +pub fn orientation_from_rotation(angle: i32) -> Option { + let mut success = false; + let ori = unsafe { libcamera_orientation_from_rotation(angle, &mut success) }; + if success { + ori.try_into().ok() + } else { + None + } +} + +impl core::ops::BitOr for Transform { + type Output = Transform; + fn bitor(self, rhs: Self) -> Self::Output { + Transform(unsafe { libcamera_transform_or(self.0, rhs.0) }) + } +} + +impl core::ops::BitAnd for Transform { + type Output = Transform; + fn bitand(self, rhs: Self) -> Self::Output { + Transform(unsafe { libcamera_transform_and(self.0, rhs.0) }) + } +} + +impl core::ops::BitXor for Transform { + type Output = Transform; + fn bitxor(self, rhs: Self) -> Self::Output { + Transform(unsafe { libcamera_transform_xor(self.0, rhs.0) }) + } +} + +impl core::ops::Not for Transform { + type Output = Transform; + fn not(self) -> Self::Output { + Transform(unsafe { libcamera_transform_not(self.0) }) + } +} diff --git a/libcamera/src/utils.rs b/libcamera/src/utils.rs index a06ed84..a3f0ce4 100644 --- a/libcamera/src/utils.rs +++ b/libcamera/src/utils.rs @@ -57,6 +57,12 @@ impl UniquePtr { ptr: NonNull::new(unsafe { T::ptr_new() }).unwrap(), } } + + /// # Safety + /// Caller must ensure `ptr` was allocated by `T::ptr_new` and owns it. + pub unsafe fn from_raw(ptr: *mut T) -> Option { + NonNull::new(ptr).map(|p| Self { ptr: p }) + } } impl Default for UniquePtr { @@ -94,7 +100,7 @@ impl core::fmt::Debug for UniquePtr { #[inline] pub fn handle_result(ret: c_int) -> io::Result<()> { if ret < 0 { - Err(io::Error::from_raw_os_error(ret)) + Err(io::Error::from_raw_os_error(-ret)) } else { Ok(()) } diff --git a/libcamera/src/vendor_features/mod.rs b/libcamera/src/vendor_features/mod.rs new file mode 100644 index 0000000..df09289 --- /dev/null +++ b/libcamera/src/vendor_features/mod.rs @@ -0,0 +1,5 @@ +//! Generated vendor feature flags. +//! The flat module exposes `LIBCAMERA_HAS_*` const bools as produced by libcamera control headers. +pub mod flat { + include!(concat!(env!("OUT_DIR"), "/vendor_features.rs")); +} diff --git a/libcamera/src/version.rs b/libcamera/src/version.rs new file mode 100644 index 0000000..c4022e9 --- /dev/null +++ b/libcamera/src/version.rs @@ -0,0 +1,41 @@ +//! Compile-time libcamera version information (from libcamera/version.h) and runtime version string. +use std::ffi::CStr; + +use libcamera_sys::{ + libcamera_version_string, LIBCAMERA_VERSION_MAJOR, LIBCAMERA_VERSION_MINOR, LIBCAMERA_VERSION_PATCH, +}; + +/// Compile-time libcamera version. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Version { + pub major: u32, + pub minor: u32, + pub patch: u32, +} + +impl core::fmt::Display for Version { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}.{}.{}", self.major, self.minor, self.patch) + } +} + +/// Version of libcamera headers linked at build time. +pub const VERSION: Version = Version { + major: LIBCAMERA_VERSION_MAJOR, + minor: LIBCAMERA_VERSION_MINOR, + patch: LIBCAMERA_VERSION_PATCH, +}; + +impl Version { + /// Returns the compile-time version as a struct. + pub const fn current() -> Version { + VERSION + } +} + +/// Runtime libcamera version string reported by `CameraManager::version()`. +/// +/// This does not require creating or starting a `CameraManager`. +pub fn runtime_version() -> &'static str { + unsafe { CStr::from_ptr(libcamera_version_string()) }.to_str().unwrap() +} diff --git a/libcamera/versioned_files/0.4.0/controls.rs b/libcamera/versioned_files/0.4.0/controls.rs index b59aa9e..9bdaf84 100644 --- a/libcamera/versioned_files/0.4.0/controls.rs +++ b/libcamera/versioned_files/0.4.0/controls.rs @@ -637,6 +637,754 @@ impl ControlId { pub fn id(&self) -> u32 { u32::from(*self) } + pub fn description(&self) -> &'static str { + match self { + ControlId::AeEnable => { + "Enable or disable the AE. + +\\sa ExposureTime AnalogueGain +" + } + ControlId::AeLocked => { + "Report the lock status of a running AE algorithm. + +If the AE algorithm is locked the value shall be set to true, if it's +converging it shall be set to false. If the AE algorithm is not +running the control shall not be present in the metadata control list. + +\\sa AeEnable +" + } + ControlId::AeMeteringMode => { + "Specify a metering mode for the AE algorithm to use. + +The metering modes determine which parts of the image are used to +determine the scene brightness. Metering modes may be platform specific +and not all metering modes may be supported. +" + } + ControlId::AeConstraintMode => { + "Specify a constraint mode for the AE algorithm to use. + +The constraint modes determine how the measured scene brightness is +adjusted to reach the desired target exposure. Constraint modes may be +platform specific, and not all constraint modes may be supported. +" + } + ControlId::AeExposureMode => { + "Specify an exposure mode for the AE algorithm to use. + +The exposure modes specify how the desired total exposure is divided +between the exposure time and the sensor's analogue gain. They are +platform specific, and not all exposure modes may be supported. +" + } + ControlId::ExposureValue => { + "Specify an Exposure Value (EV) parameter. + +The EV parameter will only be applied if the AE algorithm is currently +enabled. + +By convention EV adjusts the exposure as log2. For example +EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment +of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + +\\sa AeEnable +" + } + ControlId::ExposureTime => { + "Exposure time for the frame applied in the sensor device. + +This value is specified in micro-seconds. + +Setting this value means that it is now fixed and the AE algorithm may +not change it. Setting it back to zero returns it to the control of the +AE algorithm. + +\\sa AnalogueGain AeEnable + +\\todo Document the interactions between AeEnable and setting a fixed +value for this control. Consider interactions with other AE features, +such as aperture and aperture/shutter priority mode, and decide if +control of which features should be automatically adjusted shouldn't +better be handled through a separate AE mode control. +" + } + ControlId::AnalogueGain => { + "Analogue gain value applied in the sensor device. + +The value of the control specifies the gain multiplier applied to all +colour channels. This value cannot be lower than 1.0. + +Setting this value means that it is now fixed and the AE algorithm may +not change it. Setting it back to zero returns it to the control of the +AE algorithm. + +\\sa ExposureTime AeEnable + +\\todo Document the interactions between AeEnable and setting a fixed +value for this control. Consider interactions with other AE features, +such as aperture and aperture/shutter priority mode, and decide if +control of which features should be automatically adjusted shouldn't +better be handled through a separate AE mode control. +" + } + ControlId::AeFlickerMode => { + "Set the flicker avoidance mode for AGC/AEC. + +The flicker mode determines whether, and how, the AGC/AEC algorithm +attempts to hide flicker effects caused by the duty cycle of artificial +lighting. + +Although implementation dependent, many algorithms for \"flicker +avoidance\" work by restricting this exposure time to integer multiples +of the cycle period, wherever possible. + +Implementations may not support all of the flicker modes listed below. + +By default the system will start in FlickerAuto mode if this is +supported, otherwise the flicker mode will be set to FlickerOff. +" + } + ControlId::AeFlickerPeriod => { + "Manual flicker period in microseconds. + +This value sets the current flicker period to avoid. It is used when +AeFlickerMode is set to FlickerManual. + +To cancel 50Hz mains flicker, this should be set to 10000 (corresponding +to 100Hz), or 8333 (120Hz) for 60Hz mains. + +Setting the mode to FlickerManual when no AeFlickerPeriod has ever been +set means that no flicker cancellation occurs (until the value of this +control is updated). + +Switching to modes other than FlickerManual has no effect on the +value of the AeFlickerPeriod control. + +\\sa AeFlickerMode +" + } + ControlId::AeFlickerDetected => { + "Flicker period detected in microseconds. + +The value reported here indicates the currently detected flicker +period, or zero if no flicker at all is detected. + +When AeFlickerMode is set to FlickerAuto, there may be a period during +which the value reported here remains zero. Once a non-zero value is +reported, then this is the flicker period that has been detected and is +now being cancelled. + +In the case of 50Hz mains flicker, the value would be 10000 +(corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + +It is implementation dependent whether the system can continue to detect +flicker of different periods when another frequency is already being +cancelled. + +\\sa AeFlickerMode +" + } + ControlId::Brightness => { + "Specify a fixed brightness parameter. + +Positive values (up to 1.0) produce brighter images; negative values +(up to -1.0) produce darker images and 0.0 leaves pixels unchanged. +" + } + ControlId::Contrast => { + "Specify a fixed contrast parameter. + +Normal contrast is given by the value 1.0; larger values produce images +with more contrast. +" + } + ControlId::Lux => { + "Report an estimate of the current illuminance level in lux. + +The Lux control can only be returned in metadata. +" + } + ControlId::AwbEnable => { + "Enable or disable the AWB. + +When AWB is enabled, the algorithm estimates the colour temperature of +the scene and computes colour gains and the colour correction matrix +automatically. The computed colour temperature, gains and correction +matrix are reported in metadata. The corresponding controls are ignored +if set in a request. + +When AWB is disabled, the colour temperature, gains and correction +matrix are not updated automatically and can be set manually in +requests. + +\\sa ColourCorrectionMatrix +\\sa ColourGains +\\sa ColourTemperature +" + } + ControlId::AwbMode => { + "Specify the range of illuminants to use for the AWB algorithm. + +The modes supported are platform specific, and not all modes may be +supported. +" + } + ControlId::AwbLocked => { + "Report the lock status of a running AWB algorithm. + +If the AWB algorithm is locked the value shall be set to true, if it's +converging it shall be set to false. If the AWB algorithm is not +running the control shall not be present in the metadata control list. + +\\sa AwbEnable +" + } + ControlId::ColourGains => { + "Pair of gain values for the Red and Blue colour channels, in that +order. + +ColourGains can only be applied in a Request when the AWB is disabled. +If ColourGains is set in a request but ColourTemperature is not, the +implementation shall calculate and set the ColourTemperature based on +the ColourGains. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ColourTemperature => { + "ColourTemperature of the frame, in kelvin. + +ColourTemperature can only be applied in a Request when the AWB is +disabled. + +If ColourTemperature is set in a request but ColourGains is not, the +implementation shall calculate and set the ColourGains based on the +given ColourTemperature. If ColourTemperature is set (either directly, +or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, +the ColourCorrectionMatrix is updated based on the ColourTemperature. + +The ColourTemperature used to process the frame is reported in metadata. + +\\sa AwbEnable +\\sa ColourCorrectionMatrix +\\sa ColourGains +" + } + ControlId::Saturation => { + "Specify a fixed saturation parameter. + +Normal saturation is given by the value 1.0; larger values produce more +saturated colours; 0.0 produces a greyscale image. +" + } + ControlId::SensorBlackLevels => { + "Reports the sensor black levels used for processing a frame. + +The values are in the order R, Gr, Gb, B. They are returned as numbers +out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The +SensorBlackLevels control can only be returned in metadata. +" + } + ControlId::Sharpness => { + "Intensity of the sharpening applied to the image. + +A value of 0.0 means no sharpening. The minimum value means +minimal sharpening, and shall be 0.0 unless the camera can't +disable sharpening completely. The default value shall give a +\"reasonable\" level of sharpening, suitable for most use cases. +The maximum value may apply extremely high levels of sharpening, +higher than anyone could reasonably want. Negative values are +not allowed. Note also that sharpening is not applied to raw +streams. +" + } + ControlId::FocusFoM => { + "Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + +A larger FocusFoM value indicates a more in-focus frame. This singular +value may be based on a combination of statistics gathered from +multiple focus regions within an image. The number of focus regions and +method of combination is platform dependent. In this respect, it is not +necessarily aimed at providing a way to implement a focus algorithm by +the application, rather an indication of how in-focus a frame is. +" + } + ControlId::ColourCorrectionMatrix => { + "The 3x3 matrix that converts camera RGB to sRGB within the imaging +pipeline. + +This should describe the matrix that is used after pixels have been +white-balanced, but before any gamma transformation. The 3x3 matrix is +stored in conventional reading order in an array of 9 floating point +values. + +ColourCorrectionMatrix can only be applied in a Request when the AWB is +disabled. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ScalerCrop => { + "Sets the image portion that will be scaled to form the whole of +the final output image. + +The (x,y) location of this rectangle is relative to the +PixelArrayActiveAreas that is being used. The units remain native +sensor pixels, even if the sensor is being used in a binning or +skipping mode. + +This control is only present when the pipeline supports scaling. Its +maximum valid value is given by the properties::ScalerCropMaximum +property, and the two can be used to implement digital zoom. +" + } + ControlId::DigitalGain => { + "Digital gain value applied during the processing steps applied +to the image as captured from the sensor. + +The global digital gain factor is applied to all the colour channels +of the RAW image. Different pipeline models are free to +specify how the global gain factor applies to each separate +channel. + +If an imaging pipeline applies digital gain in distinct +processing steps, this value indicates their total sum. +Pipelines are free to decide how to adjust each processing +step to respect the received gain factor and shall report +their total value in the request metadata. +" + } + ControlId::FrameDuration => { + "The instantaneous frame duration from start of frame exposure to start +of next exposure, expressed in microseconds. + +This control is meant to be returned in metadata. +" + } + ControlId::FrameDurationLimits => { + "The minimum and maximum (in that order) frame duration, expressed in +microseconds. + +When provided by applications, the control specifies the sensor frame +duration interval the pipeline has to use. This limits the largest +exposure time the sensor can use. For example, if a maximum frame +duration of 33ms is requested (corresponding to 30 frames per second), +the sensor will not be able to raise the exposure time above 33ms. +A fixed frame duration is achieved by setting the minimum and maximum +values to be the same. Setting both values to 0 reverts to using the +camera defaults. + +The maximum frame duration provides the absolute limit to the exposure +time computed by the AE algorithm and it overrides any exposure mode +setting specified with controls::AeExposureMode. Similarly, when a +manual exposure time is set through controls::ExposureTime, it also +gets clipped to the limits set by this control. When reported in +metadata, the control expresses the minimum and maximum frame durations +used after being clipped to the sensor provided frame duration limits. + +\\sa AeExposureMode +\\sa ExposureTime + +\\todo Define how to calculate the capture frame rate by +defining controls to report additional delays introduced by +the capture pipeline or post-processing stages (ie JPEG +conversion, frame scaling). + +\\todo Provide an explicit definition of default control values, for +this and all other controls. +" + } + ControlId::SensorTemperature => { + "Temperature measure from the camera sensor in Celsius. + +This value is typically obtained by a thermal sensor present on-die or +in the camera module. The range of reported temperatures is device +dependent. + +The SensorTemperature control will only be returned in metadata if a +thermal sensor is present. +" + } + ControlId::SensorTimestamp => { + "The time when the first row of the image sensor active array is exposed. + +The timestamp, expressed in nanoseconds, represents a monotonically +increasing counter since the system boot time, as defined by the +Linux-specific CLOCK_BOOTTIME clock id. + +The SensorTimestamp control can only be returned in metadata. + +\\todo Define how the sensor timestamp has to be used in the reprocessing +use case. +" + } + ControlId::AfMode => { + "The mode of the AF (autofocus) algorithm. + +An implementation may choose not to implement all the modes. +" + } + ControlId::AfRange => { + "The range of focus distances that is scanned. + +An implementation may choose not to implement all the options here. +" + } + ControlId::AfSpeed => { + "Determine whether the AF is to move the lens as quickly as possible or +more steadily. + +For example, during video recording it may be desirable not to move the +lens too abruptly, but when in a preview mode (waiting for a still +capture) it may be helpful to move the lens as quickly as is reasonably +possible. +" + } + ControlId::AfMetering => { + "The parts of the image used by the AF algorithm to measure focus. +" + } + ControlId::AfWindows => { + "The focus windows used by the AF algorithm when AfMetering is set to +AfMeteringWindows. + +The units used are pixels within the rectangle returned by the +ScalerCropMaximum property. + +In order to be activated, a rectangle must be programmed with non-zero +width and height. Internally, these rectangles are intersected with the +ScalerCropMaximum rectangle. If the window becomes empty after this +operation, then the window is ignored. If all the windows end up being +ignored, then the behaviour is platform dependent. + +On platforms that support the ScalerCrop control (for implementing +digital zoom, for example), no automatic recalculation or adjustment of +AF windows is performed internally if the ScalerCrop is changed. If any +window lies outside the output image after the scaler crop has been +applied, it is up to the application to recalculate them. + +The details of how the windows are used are platform dependent. We note +that when there is more than one AF window, a typical implementation +might find the optimal focus position for each one and finally select +the window where the focal distance for the objects shown in that part +of the image are closest to the camera. +" + } + ControlId::AfTrigger => { + "Start an autofocus scan. + +This control starts an autofocus scan when AfMode is set to AfModeAuto, +and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It +can also be used to terminate a scan early. +" + } + ControlId::AfPause => { + "Pause lens movements when in continuous autofocus mode. + +This control has no effect except when in continuous autofocus mode +(AfModeContinuous). It can be used to pause any lens movements while +(for example) images are captured. The algorithm remains inactive +until it is instructed to resume. +" + } + ControlId::LensPosition => { + "Set and report the focus lens position. + +This control instructs the lens to move to a particular position and +also reports back the position of the lens for each frame. + +The LensPosition control is ignored unless the AfMode is set to +AfModeManual, though the value is reported back unconditionally in all +modes. + +This value, which is generally a non-integer, is the reciprocal of the +focal distance in metres, also known as dioptres. That is, to set a +focal distance D, the lens position LP is given by + +\\f$LP = \\frac{1\\mathrm{m}}{D}\\f$ + +For example: + +- 0 moves the lens to infinity. +- 0.5 moves the lens to focus on objects 2m away. +- 2 moves the lens to focus on objects 50cm away. +- And larger values will focus the lens closer. + +The default value of the control should indicate a good general +position for the lens, often corresponding to the hyperfocal distance +(the closest position for which objects at infinity are still +acceptably sharp). The minimum will often be zero (meaning infinity), +and the maximum value defines the closest focus position. + +\\todo Define a property to report the Hyperfocal distance of calibrated +lenses. +" + } + ControlId::AfState => { + "The current state of the AF algorithm. + +This control reports the current state of the AF algorithm in +conjunction with the reported AfMode value and (in continuous AF mode) +the AfPauseState value. The possible state changes are described below, +though we note the following state transitions that occur when the +AfMode is changed. + +If the AfMode is set to AfModeManual, then the AfState will always +report AfStateIdle (even if the lens is subsequently moved). Changing +to the AfModeManual state does not initiate any lens movement. + +If the AfMode is set to AfModeAuto then the AfState will report +AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent +together then AfState will omit AfStateIdle and move straight to +AfStateScanning (and start a scan). + +If the AfMode is set to AfModeContinuous then the AfState will +initially report AfStateScanning. +" + } + ControlId::AfPauseState => { + "Report whether the autofocus is currently running, paused or pausing. + +This control is only applicable in continuous (AfModeContinuous) mode, +and reports whether the algorithm is currently running, paused or +pausing (that is, will pause as soon as any in-progress scan +completes). + +Any change to AfMode will cause AfPauseStateRunning to be reported. +" + } + ControlId::HdrMode => { + "Set the mode to be used for High Dynamic Range (HDR) imaging. + +HDR techniques typically include multiple exposure, image fusion and +tone mapping techniques to improve the dynamic range of the resulting +images. + +When using an HDR mode, images are captured with different sets of AGC +settings called HDR channels. Channels indicate in particular the type +of exposure (short, medium or long) used to capture the raw image, +before fusion. Each HDR image is tagged with the corresponding channel +using the HdrChannel control. + +\\sa HdrChannel +" + } + ControlId::HdrChannel => { + "The HDR channel used to capture the frame. + +This value is reported back to the application so that it can discover +whether this capture corresponds to the short or long exposure image +(or any other image used by the HDR procedure). An application can +monitor the HDR channel to discover when the differently exposed images +have arrived. + +This metadata is only available when an HDR mode has been enabled. + +\\sa HdrMode +" + } + ControlId::Gamma => { + "Specify a fixed gamma value. + +The default gamma value must be 2.2 which closely mimics sRGB gamma. +Note that this is camera gamma, so it is applied as 1.0/gamma. +" + } + ControlId::DebugMetadataEnable => "Enable or disable the debug metadata. +", + #[cfg(feature = "vendor_draft")] + ControlId::AePrecaptureTrigger => { + "Control for AE metering trigger. Currently identical to +ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + +Whether the camera device will trigger a precapture metering sequence +when it processes this request. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::NoiseReductionMode => { + "Control to select the noise reduction algorithm mode. Currently +identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::ColorCorrectionAberrationMode => { + "Control to select the color correction aberration mode. Currently +identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AeState => { + "Control to report the current AE algorithm state. Currently identical to +ANDROID_CONTROL_AE_STATE. + + Current state of the AE algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AwbState => { + "Control to report the current AWB algorithm state. Currently identical +to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::SensorRollingShutterSkew => { + "Control to report the time between the start of exposure of the first +row and the start of exposure of the last row. Currently identical to +ANDROID_SENSOR_ROLLING_SHUTTER_SKEW +" + } + #[cfg(feature = "vendor_draft")] + ControlId::LensShadingMapMode => { + "Control to report if the lens shading map is available. Currently +identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::PipelineDepth => { + "Specifies the number of pipeline stages the frame went through from when +it was exposed to when the final completed result was available to the +framework. Always less than or equal to PipelineMaxDepth. Currently +identical to ANDROID_REQUEST_PIPELINE_DEPTH. + +The typical value for this control is 3 as a frame is first exposed, +captured and then processed in a single pass through the ISP. Any +additional processing step performed after the ISP pass (in example face +detection, additional format conversions etc) count as an additional +pipeline stage. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::MaxLatency => { + "The maximum number of frames that can occur after a request (different +than the previous) has been submitted, and before the result's state +becomes synchronized. A value of -1 indicates unknown latency, and 0 +indicates per-frame control. Currently identical to +ANDROID_SYNC_MAX_LATENCY. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::TestPatternMode => { + "Control to select the test pattern mode. Currently identical to +ANDROID_SENSOR_TEST_PATTERN_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectMode => { + "Control to select the face detection mode used by the pipeline. + +Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + +\\sa FaceDetectFaceRectangles +\\sa FaceDetectFaceScores +\\sa FaceDetectFaceLandmarks +\\sa FaceDetectFaceIds +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceRectangles => { + "Boundary rectangles of the detected faces. The number of values is +the number of detected faces. + +The FaceDetectFaceRectangles control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceScores => { + "Confidence score of each of the detected faces. The range of score is +[0, 100]. The number of values should be the number of faces reported +in FaceDetectFaceRectangles. + +The FaceDetectFaceScores control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_SCORES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceLandmarks => { + "Array of human face landmark coordinates in format [..., left_eye_i, +right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The +number of values should be 3 * the number of faces reported in +FaceDetectFaceRectangles. + +The FaceDetectFaceLandmarks control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceIds => { + "Each detected face is given a unique ID that is valid for as long as the +face is visible to the camera device. A face that leaves the field of +view and later returns may be assigned a new ID. The number of values +should be the number of faces reported in FaceDetectFaceRectangles. + +The FaceDetectFaceIds control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_IDS. +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::StatsOutputEnable => { + "Toggles the Raspberry Pi IPA to output the hardware generated statistics. + +When this control is set to true, the IPA outputs a binary dump of the +hardware generated statistics through the Request metadata in the +Bcm2835StatsOutput control. + +\\sa Bcm2835StatsOutput +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::Bcm2835StatsOutput => { + "Span of the BCM2835 ISP generated statistics for the current frame. + +This is sent in the Request metadata if the StatsOutputEnable is set to +true. The statistics struct definition can be found in +include/linux/bcm2835-isp.h. + +\\sa StatsOutputEnable +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::ScalerCrops => { + "An array of rectangles, where each singular value has identical +functionality to the ScalerCrop control. This control allows the +Raspberry Pi pipeline handler to control individual scaler crops per +output stream. + +The order of rectangles passed into the control must match the order of +streams configured by the application. The pipeline handler will only +configure crop retangles up-to the number of output streams configured. +All subsequent rectangles passed into this control are ignored by the +pipeline handler. + +If both rpi::ScalerCrops and ScalerCrop controls are present in a +ControlList, the latter is discarded, and crops are obtained from this +control. + +Note that using different crop rectangles for each output stream with +this control is only applicable on the Pi5/PiSP platform. This control +should also be considered temporary/draft and will be replaced with +official libcamera API support for per-stream controls in the future. + +\\sa ScalerCrop +" + } + } + } } /// Enable or disable the AE. /// diff --git a/libcamera/versioned_files/0.4.0/pixel_format_info.rs b/libcamera/versioned_files/0.4.0/pixel_format_info.rs new file mode 100644 index 0000000..16d3ddb --- /dev/null +++ b/libcamera/versioned_files/0.4.0/pixel_format_info.rs @@ -0,0 +1,103 @@ + +// Auto-generated from libcamera/src/libcamera/formats.cpp +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatPlaneInfoData { + pub bytes_per_group: u32, + pub vertical_sub_sampling: u32, +} + +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatInfoData { + pub name: &'static str, + pub fourcc: u32, + pub modifier: u64, + pub bits_per_pixel: u32, + pub colour_encoding: u8, + pub packed: bool, + pub pixels_per_group: u32, + pub planes: &'static [PixelFormatPlaneInfoData], + pub v4l2_formats: &'static [u32], +} + +pub(crate) static PIXEL_FORMAT_INFO: &[PixelFormatInfoData] = &[ + PixelFormatInfoData { name: "RGB565", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50424752], }, + PixelFormatInfoData { name: "RGB565_BE", fourcc: 0xb6314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52424752], }, + PixelFormatInfoData { name: "BGR888", fourcc: 0x34324742, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33424752], }, + PixelFormatInfoData { name: "RGB888", fourcc: 0x34324752, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33524742], }, + PixelFormatInfoData { name: "XRGB8888", fourcc: 0x34325258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325258], }, + PixelFormatInfoData { name: "XBGR8888", fourcc: 0x34324258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324258], }, + PixelFormatInfoData { name: "RGBX8888", fourcc: 0x34325852, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325852], }, + PixelFormatInfoData { name: "BGRX8888", fourcc: 0x34325842, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325842], }, + PixelFormatInfoData { name: "ABGR8888", fourcc: 0x34324241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324241], }, + PixelFormatInfoData { name: "ARGB8888", fourcc: 0x34325241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325241], }, + PixelFormatInfoData { name: "BGRA8888", fourcc: 0x34324142, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324142], }, + PixelFormatInfoData { name: "RGBA8888", fourcc: 0x34324152, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324152], }, + PixelFormatInfoData { name: "BGR161616", fourcc: 0x38344742, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36424752], }, + PixelFormatInfoData { name: "RGB161616", fourcc: 0x38344752, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36524742], }, + PixelFormatInfoData { name: "YUYV", fourcc: 0x56595559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x56595559], }, + PixelFormatInfoData { name: "YVYU", fourcc: 0x55595659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x55595659], }, + PixelFormatInfoData { name: "UYVY", fourcc: 0x59565955, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59565955], }, + PixelFormatInfoData { name: "VYUY", fourcc: 0x59555956, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59555956], }, + PixelFormatInfoData { name: "AVUY8888", fourcc: 0x59555641, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41565559], }, + PixelFormatInfoData { name: "XVUY8888", fourcc: 0x59555658, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x58565559], }, + PixelFormatInfoData { name: "NV12", fourcc: 0x3231564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3231564e, 0x32314d4e], }, + PixelFormatInfoData { name: "NV21", fourcc: 0x3132564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3132564e, 0x31324d4e], }, + PixelFormatInfoData { name: "NV16", fourcc: 0x3631564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3631564e, 0x36314d4e], }, + PixelFormatInfoData { name: "NV61", fourcc: 0x3136564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3136564e, 0x31364d4e], }, + PixelFormatInfoData { name: "NV24", fourcc: 0x3432564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3432564e], }, + PixelFormatInfoData { name: "NV42", fourcc: 0x3234564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3234564e], }, + PixelFormatInfoData { name: "YUV420", fourcc: 0x32315559, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315559, 0x32314d59], }, + PixelFormatInfoData { name: "YVU420", fourcc: 0x32315659, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315659, 0x31324d59], }, + PixelFormatInfoData { name: "YUV422", fourcc: 0x36315559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323234, 0x36314d59], }, + PixelFormatInfoData { name: "YVU422", fourcc: 0x36315659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31364d59], }, + PixelFormatInfoData { name: "YUV444", fourcc: 0x34325559, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324d59], }, + PixelFormatInfoData { name: "YVU444", fourcc: 0x34325659, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32344d59], }, + PixelFormatInfoData { name: "R8", fourcc: 0x20203852, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59455247], }, + PixelFormatInfoData { name: "R10", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20303159], }, + PixelFormatInfoData { name: "R10_CSI2P", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50303159], }, + PixelFormatInfoData { name: "R12_CSI2P", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323159], }, + PixelFormatInfoData { name: "R12", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20323159], }, + PixelFormatInfoData { name: "R16", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20363159], }, + PixelFormatInfoData { name: "MONO_PISP_COMP1", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: true, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x4d314350], }, + PixelFormatInfoData { name: "SBGGR8", fourcc: 0x31384142, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31384142], }, + PixelFormatInfoData { name: "SGBRG8", fourcc: 0x47524247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47524247], }, + PixelFormatInfoData { name: "SGRBG8", fourcc: 0x47425247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47425247], }, + PixelFormatInfoData { name: "SRGGB8", fourcc: 0x42474752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42474752], }, + PixelFormatInfoData { name: "SBGGR10", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314742], }, + PixelFormatInfoData { name: "SGBRG10", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314247], }, + PixelFormatInfoData { name: "SGRBG10", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314142], }, + PixelFormatInfoData { name: "SRGGB10", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314752], }, + PixelFormatInfoData { name: "SBGGR10_CSI2P", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414270], }, + PixelFormatInfoData { name: "SGBRG10_CSI2P", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414770], }, + PixelFormatInfoData { name: "SGRBG10_CSI2P", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41416770], }, + PixelFormatInfoData { name: "SRGGB10_CSI2P", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41415270], }, + PixelFormatInfoData { name: "SBGGR12", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314742], }, + PixelFormatInfoData { name: "SGBRG12", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314247], }, + PixelFormatInfoData { name: "SGRBG12", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314142], }, + PixelFormatInfoData { name: "SRGGB12", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314752], }, + PixelFormatInfoData { name: "SBGGR12_CSI2P", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434270], }, + PixelFormatInfoData { name: "SGBRG12_CSI2P", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434770], }, + PixelFormatInfoData { name: "SGRBG12_CSI2P", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43436770], }, + PixelFormatInfoData { name: "SRGGB12_CSI2P", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43435270], }, + PixelFormatInfoData { name: "SBGGR14", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314742], }, + PixelFormatInfoData { name: "SGBRG14", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314247], }, + PixelFormatInfoData { name: "SGRBG14", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34315247], }, + PixelFormatInfoData { name: "SRGGB14", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314752], }, + PixelFormatInfoData { name: "SBGGR14_CSI2P", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454270], }, + PixelFormatInfoData { name: "SGBRG14_CSI2P", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454770], }, + PixelFormatInfoData { name: "SGRBG14_CSI2P", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45456770], }, + PixelFormatInfoData { name: "SRGGB14_CSI2P", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45455270], }, + PixelFormatInfoData { name: "SBGGR16", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32525942], }, + PixelFormatInfoData { name: "SGBRG16", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314247], }, + PixelFormatInfoData { name: "SGRBG16", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36315247], }, + PixelFormatInfoData { name: "SRGGB16", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314752], }, + PixelFormatInfoData { name: "SBGGR10_IPU3", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x62337069], }, + PixelFormatInfoData { name: "SGBRG10_IPU3", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67337069], }, + PixelFormatInfoData { name: "SGRBG10_IPU3", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47337069], }, + PixelFormatInfoData { name: "SRGGB10_IPU3", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x72337069], }, + PixelFormatInfoData { name: "BGGR_PISP_COMP1", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42314350], }, + PixelFormatInfoData { name: "GBRG_PISP_COMP1", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67314350], }, + PixelFormatInfoData { name: "GRBG_PISP_COMP1", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47314350], }, + PixelFormatInfoData { name: "RGGB_PISP_COMP1", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52314350], }, + PixelFormatInfoData { name: "MJPEG", fourcc: 0x47504a4d, modifier: 0x0000000000000000, bits_per_pixel: 0, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47504a4d, 0x4745504a], }, +]; diff --git a/libcamera/versioned_files/0.4.0/properties.rs b/libcamera/versioned_files/0.4.0/properties.rs index 20fdcd8..e373566 100644 --- a/libcamera/versioned_files/0.4.0/properties.rs +++ b/libcamera/versioned_files/0.4.0/properties.rs @@ -724,6 +724,681 @@ impl PropertyId { pub fn id(&self) -> u32 { u32::from(*self) } + pub fn description(&self) -> &'static str { + match self { + PropertyId::Location => "Camera mounting location +", + PropertyId::Rotation => { + "The camera physical mounting rotation. It is expressed as the angular +difference in degrees between two reference systems, one relative to the +camera module, and one defined on the external world scene to be +captured when projected on the image sensor pixel array. + +A camera sensor has a 2-dimensional reference system 'Rc' defined by +its pixel array read-out order. The origin is set to the first pixel +being read out, the X-axis points along the column read-out direction +towards the last columns, and the Y-axis along the row read-out +direction towards the last row. + +A typical example for a sensor with a 2592x1944 pixel array matrix +observed from the front is + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + +The external world scene reference system 'Rs' is a 2-dimensional +reference system on the focal plane of the camera module. The origin is +placed on the top-left corner of the visible scene, the X-axis points +towards the right, and the Y-axis points towards the bottom of the +scene. The top, bottom, left and right directions are intentionally not +defined and depend on the environment in which the camera is used. + +A typical example of a (very common) picture of a shark swimming from +left to right, as seen from the camera, is + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\\____)\\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + +With the reference system 'Rs' placed on the camera focal plane. + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \\-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + +When projected on the sensor's pixel array, the image and the associated +reference system 'Rs' are typically (but not always) inverted, due to +the camera module's lens optical inversion effect. + +Assuming the above represented scene of the swimming shark, the lens +inversion projects the scene and its reference system onto the sensor +pixel array, seen from the front of the camera sensor, as follow + + Y-axis + ^ + ! + ! + ! + ! |\\_____)\\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + +Note the shark being upside-down. + +The resulting projected reference system is named 'Rp'. + +The camera rotation property is then defined as the angular difference +in the counter-clockwise direction between the camera reference system +'Rc' and the projected scene reference system 'Rp'. It is expressed in +degrees as a number in the range [0, 360[. + +Examples + +0 degrees camera rotation + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + +90 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +180 degrees camera rotation + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +270 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + +Example one - Webcam + +A camera module installed on the user facing part of a laptop screen +casing used for video calls. The captured images are meant to be +displayed in landscape mode (width > height) on the laptop screen. + +The camera is typically mounted upside-down to compensate the lens +optical inversion effect. + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + +The two reference systems are aligned, the resulting camera rotation is +0 degrees, no rotation correction needs to be applied to the resulting +image once captured to memory buffers to correctly display it to users. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +If the camera sensor is not mounted upside-down to compensate for the +lens optical inversion, the two reference systems will not be aligned, +with 'Rp' being rotated 180 degrees relatively to 'Rc'. + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\\_____)\\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +The image once captured to memory will then be rotated by 180 degrees + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \\( \\| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +A software rotation correction of 180 degrees should be applied to +correctly display the image. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +Example two - Phone camera + +A camera installed on the back side of a mobile device facing away from +the user. The captured images are meant to be displayed in portrait mode +(height > width) to match the device screen orientation and the device +usage orientation used when taking the picture. + +The camera sensor is typically mounted with its pixel array longer side +aligned to the device longer side, upside-down mounted to compensate for +the lens optical inversion effect. + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +The two reference systems are not aligned and the 'Rp' reference +system is rotated by 90 degrees in the counter-clockwise direction +relatively to the 'Rc' reference system. + +The image once captured to memory will be rotated. + + +-------------------------------------+ + | _ _ | + | \\ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + +A correction of 90 degrees in counter-clockwise direction has to be +applied to correctly display the image in portrait mode on the device +screen. + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\\____)\\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ +" + } + PropertyId::Model => { + "The model name shall to the extent possible describe the sensor. For +most devices this is the model name of the sensor. While for some +devices the sensor model is unavailable as the sensor or the entire +camera is part of a larger unit and exposed as a black-box to the +system. In such cases the model name of the smallest device that +contains the camera sensor shall be used. + +The model name is not meant to be a camera name displayed to the +end-user, but may be combined with other camera information to create a +camera name. + +The model name is not guaranteed to be unique in the system nor is +it guaranteed to be stable or have any other properties required to make +it a good candidate to be used as a permanent identifier of a camera. + +The model name shall describe the camera in a human readable format and +shall be encoded in ASCII. + +Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. +" + } + PropertyId::UnitCellSize => { + "The pixel unit cell physical size, in nanometers. + +The UnitCellSize properties defines the horizontal and vertical sizes of +a single pixel unit, including its active and non-active parts. In +other words, it expresses the horizontal and vertical distance between +the top-left corners of adjacent pixels. + +The property can be used to calculate the physical size of the sensor's +pixel array area and for calibration purposes. +" + } + PropertyId::PixelArraySize => { + "The camera sensor pixel array readable area vertical and horizontal +sizes, in pixels. + +The PixelArraySize property defines the size in pixel units of the +readable part of full pixel array matrix, including optical black +pixels used for calibration, pixels which are not considered valid for +capture and active pixels containing valid image data. + +The property describes the maximum size of the raw data captured by the +camera, which might not correspond to the physical size of the sensor +pixel array matrix, as some portions of the physical pixel array matrix +are not accessible and cannot be transmitted out. + +For example, let's consider a pixel array matrix assembled as follows + + +--------------------------------------------------+ + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + ... ... ... ... ... + + ... ... ... ... ... + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + +--------------------------------------------------+ + +starting with two lines of non-readable pixels (x), followed by N lines +of readable data (D) surrounded by two columns of non-readable pixels on +each side, and ending with two more lines of non-readable pixels. Only +the readable portion is transmitted to the receiving side, defining the +sizes of the largest possible buffer of raw data that can be presented +to applications. + + PixelArraySize.width + /----------------------------------------------/ + +----------------------------------------------+ / + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + ... ... ... ... ... + ... ... ... ... ... + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + +----------------------------------------------+ / + +This defines a rectangle whose top-left corner is placed in position (0, +0) and whose vertical and horizontal sizes are defined by this property. +All other rectangles that describe portions of the pixel array, such as +the optical black pixels rectangles and active pixel areas, are defined +relatively to this rectangle. + +All the coordinates are expressed relative to the default sensor readout +direction, without any transformation (such as horizontal and vertical +flipping) applied. When mapping them to the raw pixel buffer, +applications shall take any configured transformation into account. + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::Size) +" + } + PropertyId::PixelArrayOpticalBlackRectangles => { + "The pixel array region(s) which contain optical black pixels +considered valid for calibration purposes. + +This property describes the position and size of optical black pixel +regions in the raw data buffer as stored in memory, which might differ +from their actual physical location in the pixel array matrix. + +It is important to note, in fact, that camera sensors might +automatically reorder or skip portions of their pixels array matrix when +transmitting data to the receiver. For instance, a sensor may merge the +top and bottom optical black rectangles into a single rectangle, +transmitted at the beginning of the frame. + +The pixel array contains several areas with different purposes, +interleaved by lines and columns which are said not to be valid for +capturing purposes. Invalid lines and columns are defined as invalid as +they could be positioned too close to the chip margins or to the optical +black shielding placed on top of optical black pixels. + + PixelArraySize.width + /----------------------------------------------/ + x1 x2 + +--o---------------------------------------o---+ / + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + ... ... ... ... ... + ... ... ... ... ... + y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + +----------------------------------------------+ / + +The readable pixel array matrix is composed by +2 invalid lines (I) +4 lines of valid optical black pixels (O) +2 invalid lines (I) +n lines of valid pixel data (P) +2 invalid lines (I) + +And the position of the optical black pixel rectangles is defined by + + PixelArrayOpticalBlackRectangles = { + { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + { x1, y3, 2, y4 - y3 + 1 }, + { x2, y3, 2, y4 - y3 + 1 }, + }; + +If the camera, when capturing the full pixel array matrix, automatically +skips the invalid lines and columns, producing the following data +buffer, when captured to memory + + PixelArraySize.width + /----------------------------------------------/ + x1 + +--------------------------------------------o-+ / + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + ... ... ... ... ... | + ... ... ... ... ... | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + +----------------------------------------------+ / + +then the invalid lines and columns should not be reported as part of the +PixelArraySize property in first place. + +In this case, the position of the black pixel rectangles will be + + PixelArrayOpticalBlackRectangles = { + { 0, 0, y1 + 1, PixelArraySize[0] }, + { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + }; + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::OpticalBlackRectangles) +" + } + PropertyId::PixelArrayActiveAreas => { + "The PixelArrayActiveAreas property defines the (possibly multiple and +overlapping) portions of the camera sensor readable pixel matrix +which are considered valid for image acquisition purposes. + +This property describes an arbitrary number of overlapping rectangles, +with each rectangle representing the maximum image size that the camera +sensor can produce for a particular aspect ratio. They are defined +relatively to the PixelArraySize rectangle. + +When multiple rectangles are reported, they shall be ordered from the +tallest to the shortest. + +Example 1 +A camera sensor which only produces images in the 4:3 image resolution +will report a single PixelArrayActiveAreas rectangle, from which all +other image formats are obtained by either cropping the field-of-view +and/or applying pixel sub-sampling techniques such as pixel skipping or +binning. + + PixelArraySize.width + /----------------/ + x1 x2 + (0,0)-> +-o------------o-+ / + y1 o +------------+ | | + | |////////////| | | + | |////////////| | | PixelArraySize.height + | |////////////| | | + y2 o +------------+ | | + +----------------+ / + +The property reports a single rectangle + + PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + +Example 2 +A camera sensor which can produce images in different native +resolutions will report several overlapping rectangles, one for each +natively supported resolution. + + PixelArraySize.width + /------------------/ + x1 x2 x3 x4 + (0,0)-> +o---o------o---o+ / + y1 o +------+ | | + | |//////| | | + y2 o+---+------+---+| | + ||///|//////|///|| | PixelArraySize.height + y3 o+---+------+---+| | + | |//////| | | + y4 o +------+ | | + +----+------+----+ / + +The property reports two rectangles + + PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + +The first rectangle describes the maximum field-of-view of all image +formats in the 4:3 resolutions, while the second one describes the +maximum field of view for all image formats in the 16:9 resolutions. + +Multiple rectangles shall only be reported when the sensor can't capture +the pixels in the corner regions. If all the pixels in the (x1,y1) - +(x4,y4) area can be captured, the PixelArrayActiveAreas property shall +contains the single rectangle (x1,y1) - (x4,y4). + +\\todo Rename this property to ActiveAreas once we will have property + categories (i.e. Properties::PixelArray::ActiveAreas) +" + } + PropertyId::ScalerCropMaximum => { + "The maximum valid rectangle for the controls::ScalerCrop control. This +reflects the minimum mandatory cropping applied in the camera sensor and +the rest of the pipeline. Just as the ScalerCrop control, it defines a +rectangle taken from the sensor's active pixel array. + +This property is valid only after the camera has been successfully +configured and its value may change whenever a new configuration is +applied. + +\\todo Turn this property into a \"maximum control value\" for the +ScalerCrop control once \"dynamic\" controls have been implemented. +" + } + PropertyId::SensorSensitivity => { + "The relative sensitivity of the chosen sensor mode. + +Some sensors have readout modes with different sensitivities. For example, +a binned camera mode might, with the same exposure and gains, produce +twice the signal level of the full resolution readout. This would be +signalled by the binned mode, when it is chosen, indicating a value here +that is twice that of the full resolution mode. This value will be valid +after the configure method has returned successfully. +" + } + PropertyId::SystemDevices => { + "A list of integer values of type dev_t denoting the major and minor +device numbers of the underlying devices used in the operation of this +camera. + +Different cameras may report identical devices. +" + } + #[cfg(feature = "vendor_draft")] + PropertyId::ColorFilterArrangement => { + "The arrangement of color filters on sensor; represents the colors in the +top-left 2x2 section of the sensor, in reading order. Currently +identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. +" + } + } + } } /// Camera mounting location #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] diff --git a/libcamera/versioned_files/0.5.0/controls.rs b/libcamera/versioned_files/0.5.0/controls.rs index 2a61193..e42ce55 100644 --- a/libcamera/versioned_files/0.5.0/controls.rs +++ b/libcamera/versioned_files/0.5.0/controls.rs @@ -770,6 +770,891 @@ impl ControlId { pub fn id(&self) -> u32 { u32::from(*self) } + pub fn description(&self) -> &'static str { + match self { + ControlId::AeEnable => { + "Enable or disable the AEGC algorithm. When this control is set to true, +both ExposureTimeMode and AnalogueGainMode are set to auto, and if this +control is set to false then both are set to manual. + +If ExposureTimeMode or AnalogueGainMode are also set in the same +request as AeEnable, then the modes supplied by ExposureTimeMode or +AnalogueGainMode will take precedence. + +\\sa ExposureTimeMode AnalogueGainMode +" + } + ControlId::AeState => { + "Report the AEGC algorithm state. + +The AEGC algorithm computes the exposure time and the analogue gain +to be applied to the image sensor. + +The AEGC algorithm behaviour is controlled by the ExposureTimeMode and +AnalogueGainMode controls, which allow applications to decide how +the exposure time and gain are computed, in Auto or Manual mode, +independently from one another. + +The AeState control reports the AEGC algorithm state through a single +value and describes it as a single computation block which computes +both the exposure time and the analogue gain values. + +When both the exposure time and analogue gain values are configured to +be in Manual mode, the AEGC algorithm is quiescent and does not actively +compute any value and the AeState control will report AeStateIdle. + +When at least the exposure time or analogue gain are configured to be +computed by the AEGC algorithm, the AeState control will report if the +algorithm has converged to stable values for all of the controls set +to be computed in Auto mode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::AeMeteringMode => { + "Specify a metering mode for the AE algorithm to use. + +The metering modes determine which parts of the image are used to +determine the scene brightness. Metering modes may be platform specific +and not all metering modes may be supported. +" + } + ControlId::AeConstraintMode => { + "Specify a constraint mode for the AE algorithm to use. + +The constraint modes determine how the measured scene brightness is +adjusted to reach the desired target exposure. Constraint modes may be +platform specific, and not all constraint modes may be supported. +" + } + ControlId::AeExposureMode => { + "Specify an exposure mode for the AE algorithm to use. + +The exposure modes specify how the desired total exposure is divided +between the exposure time and the sensor's analogue gain. They are +platform specific, and not all exposure modes may be supported. + +When one of AnalogueGainMode or ExposureTimeMode is set to Manual, +the fixed values will override any choices made by AeExposureMode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureValue => { + "Specify an Exposure Value (EV) parameter. + +The EV parameter will only be applied if the AE algorithm is currently +enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode +are in Auto mode. + +By convention EV adjusts the exposure as log2. For example +EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment +of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureTime => { + "Exposure time for the frame applied in the sensor device. + +This value is specified in micro-seconds. + +This control will only take effect if ExposureTimeMode is Manual. If +this control is set when ExposureTimeMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what exposure time +was used for the current frame, regardless of ExposureTimeMode. +ExposureTimeMode will indicate the source of the exposure time value, +whether it came from the AE algorithm or not. + +\\sa AnalogueGain +\\sa ExposureTimeMode +" + } + ControlId::ExposureTimeMode => { + "Controls the source of the exposure time that is applied to the image +sensor. + +When set to Auto, the AE algorithm computes the exposure time and +configures the image sensor accordingly. When set to Manual, the value +of the ExposureTime control is used. + +When transitioning from Auto to Manual mode and no ExposureTime control +is provided by the application, the last value computed by the AE +algorithm when the mode was Auto will be used. If the ExposureTimeMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If ExposureTimeModeManual is supported, the ExposureTime control must +also be supported. + +Cameras that support manual control of the sensor shall support manual +mode for both ExposureTimeMode and AnalogueGainMode, and shall expose +the ExposureTime and AnalogueGain controls. If the camera also has an +AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall +support both manual and auto mode. If auto mode is available, it shall +be the default mode. These rules do not apply to black box cameras +such as UVC cameras, where the available gain and exposure modes are +completely dependent on what the device exposes. + +\\par Flickerless exposure mode transitions + +Applications that wish to transition from ExposureTimeModeAuto to direct +control of the exposure time without causing extra flicker can do so by +selecting an ExposureTime value as close as possible to the last value +computed by the auto exposure algorithm in order to avoid any visible +flickering. + +To select the correct value to use as ExposureTime value, applications +should accommodate the natural delay in applying controls caused by the +capture pipeline frame depth. + +When switching to manual exposure mode, applications should not +immediately specify an ExposureTime value in the same request where +ExposureTimeMode is set to Manual. They should instead wait for the +first Request where ExposureTimeMode is reported as +ExposureTimeModeManual in the Request metadata, and use the reported +ExposureTime to populate the control value in the next Request to be +queued to the Camera. + +The implementation of the auto-exposure algorithm should equally try to +minimize flickering and when transitioning from manual exposure mode to +auto exposure use the last value provided by the application as starting +point. + +1. Start with ExposureTimeMode set to Auto + +2. Set ExposureTimeMode to Manual + +3. Wait for the first completed request that has ExposureTimeMode +set to Manual + +4. Copy the value reported in ExposureTime into a new request, and +submit it + +5. Proceed to run manual exposure time as desired + +\\sa ExposureTime +" + } + ControlId::AnalogueGain => { + "Analogue gain value applied in the sensor device. + +The value of the control specifies the gain multiplier applied to all +colour channels. This value cannot be lower than 1.0. + +This control will only take effect if AnalogueGainMode is Manual. If +this control is set when AnalogueGainMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what analogue gain +was used for the current request, regardless of AnalogueGainMode. +AnalogueGainMode will indicate the source of the analogue gain value, +whether it came from the AEGC algorithm or not. + +\\sa ExposureTime +\\sa AnalogueGainMode +" + } + ControlId::AnalogueGainMode => { + "Controls the source of the analogue gain that is applied to the image +sensor. + +When set to Auto, the AEGC algorithm computes the analogue gain and +configures the image sensor accordingly. When set to Manual, the value +of the AnalogueGain control is used. + +When transitioning from Auto to Manual mode and no AnalogueGain control +is provided by the application, the last value computed by the AEGC +algorithm when the mode was Auto will be used. If the AnalogueGainMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If AnalogueGainModeManual is supported, the AnalogueGain control must +also be supported. + +For cameras where we have control over the ISP, both ExposureTimeMode +and AnalogueGainMode are expected to support manual mode, and both +controls (as well as ExposureTimeMode and AnalogueGain) are expected to +be present. If the camera also has an AEGC implementation, both +ExposureTimeMode and AnalogueGainMode shall support both manual and +auto mode. If auto mode is available, it shall be the default mode. +These rules do not apply to black box cameras such as UVC cameras, +where the available gain and exposure modes are completely dependent on +what the hardware exposes. + +The same procedure described for performing flickerless transitions in +the ExposureTimeMode control documentation can be applied to analogue +gain. + +\\sa ExposureTimeMode +\\sa AnalogueGain +" + } + ControlId::AeFlickerMode => { + "Set the flicker avoidance mode for AGC/AEC. + +The flicker mode determines whether, and how, the AGC/AEC algorithm +attempts to hide flicker effects caused by the duty cycle of artificial +lighting. + +Although implementation dependent, many algorithms for \"flicker +avoidance\" work by restricting this exposure time to integer multiples +of the cycle period, wherever possible. + +Implementations may not support all of the flicker modes listed below. + +By default the system will start in FlickerAuto mode if this is +supported, otherwise the flicker mode will be set to FlickerOff. +" + } + ControlId::AeFlickerPeriod => { + "Manual flicker period in microseconds. + +This value sets the current flicker period to avoid. It is used when +AeFlickerMode is set to FlickerManual. + +To cancel 50Hz mains flicker, this should be set to 10000 (corresponding +to 100Hz), or 8333 (120Hz) for 60Hz mains. + +Setting the mode to FlickerManual when no AeFlickerPeriod has ever been +set means that no flicker cancellation occurs (until the value of this +control is updated). + +Switching to modes other than FlickerManual has no effect on the +value of the AeFlickerPeriod control. + +\\sa AeFlickerMode +" + } + ControlId::AeFlickerDetected => { + "Flicker period detected in microseconds. + +The value reported here indicates the currently detected flicker +period, or zero if no flicker at all is detected. + +When AeFlickerMode is set to FlickerAuto, there may be a period during +which the value reported here remains zero. Once a non-zero value is +reported, then this is the flicker period that has been detected and is +now being cancelled. + +In the case of 50Hz mains flicker, the value would be 10000 +(corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + +It is implementation dependent whether the system can continue to detect +flicker of different periods when another frequency is already being +cancelled. + +\\sa AeFlickerMode +" + } + ControlId::Brightness => { + "Specify a fixed brightness parameter. + +Positive values (up to 1.0) produce brighter images; negative values +(up to -1.0) produce darker images and 0.0 leaves pixels unchanged. +" + } + ControlId::Contrast => { + "Specify a fixed contrast parameter. + +Normal contrast is given by the value 1.0; larger values produce images +with more contrast. +" + } + ControlId::Lux => { + "Report an estimate of the current illuminance level in lux. + +The Lux control can only be returned in metadata. +" + } + ControlId::AwbEnable => { + "Enable or disable the AWB. + +When AWB is enabled, the algorithm estimates the colour temperature of +the scene and computes colour gains and the colour correction matrix +automatically. The computed colour temperature, gains and correction +matrix are reported in metadata. The corresponding controls are ignored +if set in a request. + +When AWB is disabled, the colour temperature, gains and correction +matrix are not updated automatically and can be set manually in +requests. + +\\sa ColourCorrectionMatrix +\\sa ColourGains +\\sa ColourTemperature +" + } + ControlId::AwbMode => { + "Specify the range of illuminants to use for the AWB algorithm. + +The modes supported are platform specific, and not all modes may be +supported. +" + } + ControlId::AwbLocked => { + "Report the lock status of a running AWB algorithm. + +If the AWB algorithm is locked the value shall be set to true, if it's +converging it shall be set to false. If the AWB algorithm is not +running the control shall not be present in the metadata control list. + +\\sa AwbEnable +" + } + ControlId::ColourGains => { + "Pair of gain values for the Red and Blue colour channels, in that +order. + +ColourGains can only be applied in a Request when the AWB is disabled. +If ColourGains is set in a request but ColourTemperature is not, the +implementation shall calculate and set the ColourTemperature based on +the ColourGains. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ColourTemperature => { + "ColourTemperature of the frame, in kelvin. + +ColourTemperature can only be applied in a Request when the AWB is +disabled. + +If ColourTemperature is set in a request but ColourGains is not, the +implementation shall calculate and set the ColourGains based on the +given ColourTemperature. If ColourTemperature is set (either directly, +or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, +the ColourCorrectionMatrix is updated based on the ColourTemperature. + +The ColourTemperature used to process the frame is reported in metadata. + +\\sa AwbEnable +\\sa ColourCorrectionMatrix +\\sa ColourGains +" + } + ControlId::Saturation => { + "Specify a fixed saturation parameter. + +Normal saturation is given by the value 1.0; larger values produce more +saturated colours; 0.0 produces a greyscale image. +" + } + ControlId::SensorBlackLevels => { + "Reports the sensor black levels used for processing a frame. + +The values are in the order R, Gr, Gb, B. They are returned as numbers +out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The +SensorBlackLevels control can only be returned in metadata. +" + } + ControlId::Sharpness => { + "Intensity of the sharpening applied to the image. + +A value of 0.0 means no sharpening. The minimum value means +minimal sharpening, and shall be 0.0 unless the camera can't +disable sharpening completely. The default value shall give a +\"reasonable\" level of sharpening, suitable for most use cases. +The maximum value may apply extremely high levels of sharpening, +higher than anyone could reasonably want. Negative values are +not allowed. Note also that sharpening is not applied to raw +streams. +" + } + ControlId::FocusFoM => { + "Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + +A larger FocusFoM value indicates a more in-focus frame. This singular +value may be based on a combination of statistics gathered from +multiple focus regions within an image. The number of focus regions and +method of combination is platform dependent. In this respect, it is not +necessarily aimed at providing a way to implement a focus algorithm by +the application, rather an indication of how in-focus a frame is. +" + } + ControlId::ColourCorrectionMatrix => { + "The 3x3 matrix that converts camera RGB to sRGB within the imaging +pipeline. + +This should describe the matrix that is used after pixels have been +white-balanced, but before any gamma transformation. The 3x3 matrix is +stored in conventional reading order in an array of 9 floating point +values. + +ColourCorrectionMatrix can only be applied in a Request when the AWB is +disabled. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ScalerCrop => { + "Sets the image portion that will be scaled to form the whole of +the final output image. + +The (x,y) location of this rectangle is relative to the +PixelArrayActiveAreas that is being used. The units remain native +sensor pixels, even if the sensor is being used in a binning or +skipping mode. + +This control is only present when the pipeline supports scaling. Its +maximum valid value is given by the properties::ScalerCropMaximum +property, and the two can be used to implement digital zoom. +" + } + ControlId::DigitalGain => { + "Digital gain value applied during the processing steps applied +to the image as captured from the sensor. + +The global digital gain factor is applied to all the colour channels +of the RAW image. Different pipeline models are free to +specify how the global gain factor applies to each separate +channel. + +If an imaging pipeline applies digital gain in distinct +processing steps, this value indicates their total sum. +Pipelines are free to decide how to adjust each processing +step to respect the received gain factor and shall report +their total value in the request metadata. +" + } + ControlId::FrameDuration => { + "The instantaneous frame duration from start of frame exposure to start +of next exposure, expressed in microseconds. + +This control is meant to be returned in metadata. +" + } + ControlId::FrameDurationLimits => { + "The minimum and maximum (in that order) frame duration, expressed in +microseconds. + +When provided by applications, the control specifies the sensor frame +duration interval the pipeline has to use. This limits the largest +exposure time the sensor can use. For example, if a maximum frame +duration of 33ms is requested (corresponding to 30 frames per second), +the sensor will not be able to raise the exposure time above 33ms. +A fixed frame duration is achieved by setting the minimum and maximum +values to be the same. Setting both values to 0 reverts to using the +camera defaults. + +The maximum frame duration provides the absolute limit to the exposure +time computed by the AE algorithm and it overrides any exposure mode +setting specified with controls::AeExposureMode. Similarly, when a +manual exposure time is set through controls::ExposureTime, it also +gets clipped to the limits set by this control. When reported in +metadata, the control expresses the minimum and maximum frame durations +used after being clipped to the sensor provided frame duration limits. + +\\sa AeExposureMode +\\sa ExposureTime + +\\todo Define how to calculate the capture frame rate by +defining controls to report additional delays introduced by +the capture pipeline or post-processing stages (ie JPEG +conversion, frame scaling). + +\\todo Provide an explicit definition of default control values, for +this and all other controls. +" + } + ControlId::SensorTemperature => { + "Temperature measure from the camera sensor in Celsius. + +This value is typically obtained by a thermal sensor present on-die or +in the camera module. The range of reported temperatures is device +dependent. + +The SensorTemperature control will only be returned in metadata if a +thermal sensor is present. +" + } + ControlId::SensorTimestamp => { + "The time when the first row of the image sensor active array is exposed. + +The timestamp, expressed in nanoseconds, represents a monotonically +increasing counter since the system boot time, as defined by the +Linux-specific CLOCK_BOOTTIME clock id. + +The SensorTimestamp control can only be returned in metadata. + +\\todo Define how the sensor timestamp has to be used in the reprocessing +use case. +" + } + ControlId::AfMode => { + "The mode of the AF (autofocus) algorithm. + +An implementation may choose not to implement all the modes. +" + } + ControlId::AfRange => { + "The range of focus distances that is scanned. + +An implementation may choose not to implement all the options here. +" + } + ControlId::AfSpeed => { + "Determine whether the AF is to move the lens as quickly as possible or +more steadily. + +For example, during video recording it may be desirable not to move the +lens too abruptly, but when in a preview mode (waiting for a still +capture) it may be helpful to move the lens as quickly as is reasonably +possible. +" + } + ControlId::AfMetering => { + "The parts of the image used by the AF algorithm to measure focus. +" + } + ControlId::AfWindows => { + "The focus windows used by the AF algorithm when AfMetering is set to +AfMeteringWindows. + +The units used are pixels within the rectangle returned by the +ScalerCropMaximum property. + +In order to be activated, a rectangle must be programmed with non-zero +width and height. Internally, these rectangles are intersected with the +ScalerCropMaximum rectangle. If the window becomes empty after this +operation, then the window is ignored. If all the windows end up being +ignored, then the behaviour is platform dependent. + +On platforms that support the ScalerCrop control (for implementing +digital zoom, for example), no automatic recalculation or adjustment of +AF windows is performed internally if the ScalerCrop is changed. If any +window lies outside the output image after the scaler crop has been +applied, it is up to the application to recalculate them. + +The details of how the windows are used are platform dependent. We note +that when there is more than one AF window, a typical implementation +might find the optimal focus position for each one and finally select +the window where the focal distance for the objects shown in that part +of the image are closest to the camera. +" + } + ControlId::AfTrigger => { + "Start an autofocus scan. + +This control starts an autofocus scan when AfMode is set to AfModeAuto, +and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It +can also be used to terminate a scan early. +" + } + ControlId::AfPause => { + "Pause lens movements when in continuous autofocus mode. + +This control has no effect except when in continuous autofocus mode +(AfModeContinuous). It can be used to pause any lens movements while +(for example) images are captured. The algorithm remains inactive +until it is instructed to resume. +" + } + ControlId::LensPosition => { + "Set and report the focus lens position. + +This control instructs the lens to move to a particular position and +also reports back the position of the lens for each frame. + +The LensPosition control is ignored unless the AfMode is set to +AfModeManual, though the value is reported back unconditionally in all +modes. + +This value, which is generally a non-integer, is the reciprocal of the +focal distance in metres, also known as dioptres. That is, to set a +focal distance D, the lens position LP is given by + +\\f$LP = \\frac{1\\mathrm{m}}{D}\\f$ + +For example: + +- 0 moves the lens to infinity. +- 0.5 moves the lens to focus on objects 2m away. +- 2 moves the lens to focus on objects 50cm away. +- And larger values will focus the lens closer. + +The default value of the control should indicate a good general +position for the lens, often corresponding to the hyperfocal distance +(the closest position for which objects at infinity are still +acceptably sharp). The minimum will often be zero (meaning infinity), +and the maximum value defines the closest focus position. + +\\todo Define a property to report the Hyperfocal distance of calibrated +lenses. +" + } + ControlId::AfState => { + "The current state of the AF algorithm. + +This control reports the current state of the AF algorithm in +conjunction with the reported AfMode value and (in continuous AF mode) +the AfPauseState value. The possible state changes are described below, +though we note the following state transitions that occur when the +AfMode is changed. + +If the AfMode is set to AfModeManual, then the AfState will always +report AfStateIdle (even if the lens is subsequently moved). Changing +to the AfModeManual state does not initiate any lens movement. + +If the AfMode is set to AfModeAuto then the AfState will report +AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent +together then AfState will omit AfStateIdle and move straight to +AfStateScanning (and start a scan). + +If the AfMode is set to AfModeContinuous then the AfState will +initially report AfStateScanning. +" + } + ControlId::AfPauseState => { + "Report whether the autofocus is currently running, paused or pausing. + +This control is only applicable in continuous (AfModeContinuous) mode, +and reports whether the algorithm is currently running, paused or +pausing (that is, will pause as soon as any in-progress scan +completes). + +Any change to AfMode will cause AfPauseStateRunning to be reported. +" + } + ControlId::HdrMode => { + "Set the mode to be used for High Dynamic Range (HDR) imaging. + +HDR techniques typically include multiple exposure, image fusion and +tone mapping techniques to improve the dynamic range of the resulting +images. + +When using an HDR mode, images are captured with different sets of AGC +settings called HDR channels. Channels indicate in particular the type +of exposure (short, medium or long) used to capture the raw image, +before fusion. Each HDR image is tagged with the corresponding channel +using the HdrChannel control. + +\\sa HdrChannel +" + } + ControlId::HdrChannel => { + "The HDR channel used to capture the frame. + +This value is reported back to the application so that it can discover +whether this capture corresponds to the short or long exposure image +(or any other image used by the HDR procedure). An application can +monitor the HDR channel to discover when the differently exposed images +have arrived. + +This metadata is only available when an HDR mode has been enabled. + +\\sa HdrMode +" + } + ControlId::Gamma => { + "Specify a fixed gamma value. + +The default gamma value must be 2.2 which closely mimics sRGB gamma. +Note that this is camera gamma, so it is applied as 1.0/gamma. +" + } + ControlId::DebugMetadataEnable => "Enable or disable the debug metadata. +", + #[cfg(feature = "vendor_draft")] + ControlId::AePrecaptureTrigger => { + "Control for AE metering trigger. Currently identical to +ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + +Whether the camera device will trigger a precapture metering sequence +when it processes this request. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::NoiseReductionMode => { + "Control to select the noise reduction algorithm mode. Currently +identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::ColorCorrectionAberrationMode => { + "Control to select the color correction aberration mode. Currently +identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AwbState => { + "Control to report the current AWB algorithm state. Currently identical +to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::SensorRollingShutterSkew => { + "Control to report the time between the start of exposure of the first +row and the start of exposure of the last row. Currently identical to +ANDROID_SENSOR_ROLLING_SHUTTER_SKEW +" + } + #[cfg(feature = "vendor_draft")] + ControlId::LensShadingMapMode => { + "Control to report if the lens shading map is available. Currently +identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::PipelineDepth => { + "Specifies the number of pipeline stages the frame went through from when +it was exposed to when the final completed result was available to the +framework. Always less than or equal to PipelineMaxDepth. Currently +identical to ANDROID_REQUEST_PIPELINE_DEPTH. + +The typical value for this control is 3 as a frame is first exposed, +captured and then processed in a single pass through the ISP. Any +additional processing step performed after the ISP pass (in example face +detection, additional format conversions etc) count as an additional +pipeline stage. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::MaxLatency => { + "The maximum number of frames that can occur after a request (different +than the previous) has been submitted, and before the result's state +becomes synchronized. A value of -1 indicates unknown latency, and 0 +indicates per-frame control. Currently identical to +ANDROID_SYNC_MAX_LATENCY. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::TestPatternMode => { + "Control to select the test pattern mode. Currently identical to +ANDROID_SENSOR_TEST_PATTERN_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectMode => { + "Control to select the face detection mode used by the pipeline. + +Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + +\\sa FaceDetectFaceRectangles +\\sa FaceDetectFaceScores +\\sa FaceDetectFaceLandmarks +\\sa FaceDetectFaceIds +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceRectangles => { + "Boundary rectangles of the detected faces. The number of values is +the number of detected faces. + +The FaceDetectFaceRectangles control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceScores => { + "Confidence score of each of the detected faces. The range of score is +[0, 100]. The number of values should be the number of faces reported +in FaceDetectFaceRectangles. + +The FaceDetectFaceScores control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_SCORES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceLandmarks => { + "Array of human face landmark coordinates in format [..., left_eye_i, +right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The +number of values should be 3 * the number of faces reported in +FaceDetectFaceRectangles. + +The FaceDetectFaceLandmarks control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceIds => { + "Each detected face is given a unique ID that is valid for as long as the +face is visible to the camera device. A face that leaves the field of +view and later returns may be assigned a new ID. The number of values +should be the number of faces reported in FaceDetectFaceRectangles. + +The FaceDetectFaceIds control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_IDS. +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::StatsOutputEnable => { + "Toggles the Raspberry Pi IPA to output the hardware generated statistics. + +When this control is set to true, the IPA outputs a binary dump of the +hardware generated statistics through the Request metadata in the +Bcm2835StatsOutput control. + +\\sa Bcm2835StatsOutput +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::Bcm2835StatsOutput => { + "Span of the BCM2835 ISP generated statistics for the current frame. + +This is sent in the Request metadata if the StatsOutputEnable is set to +true. The statistics struct definition can be found in +include/linux/bcm2835-isp.h. + +\\sa StatsOutputEnable +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::ScalerCrops => { + "An array of rectangles, where each singular value has identical +functionality to the ScalerCrop control. This control allows the +Raspberry Pi pipeline handler to control individual scaler crops per +output stream. + +The order of rectangles passed into the control must match the order of +streams configured by the application. The pipeline handler will only +configure crop retangles up-to the number of output streams configured. +All subsequent rectangles passed into this control are ignored by the +pipeline handler. + +If both rpi::ScalerCrops and ScalerCrop controls are present in a +ControlList, the latter is discarded, and crops are obtained from this +control. + +Note that using different crop rectangles for each output stream with +this control is only applicable on the Pi5/PiSP platform. This control +should also be considered temporary/draft and will be replaced with +official libcamera API support for per-stream controls in the future. + +\\sa ScalerCrop +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::PispStatsOutput => { + "Span of the PiSP Frontend ISP generated statistics for the current +frame. This is sent in the Request metadata if the StatsOutputEnable is +set to true. The statistics struct definition can be found in +https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + +\\sa StatsOutputEnable +" + } + } + } } /// Enable or disable the AEGC algorithm. When this control is set to true, /// both ExposureTimeMode and AnalogueGainMode are set to auto, and if this diff --git a/libcamera/versioned_files/0.5.0/pixel_format_info.rs b/libcamera/versioned_files/0.5.0/pixel_format_info.rs new file mode 100644 index 0000000..16d3ddb --- /dev/null +++ b/libcamera/versioned_files/0.5.0/pixel_format_info.rs @@ -0,0 +1,103 @@ + +// Auto-generated from libcamera/src/libcamera/formats.cpp +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatPlaneInfoData { + pub bytes_per_group: u32, + pub vertical_sub_sampling: u32, +} + +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatInfoData { + pub name: &'static str, + pub fourcc: u32, + pub modifier: u64, + pub bits_per_pixel: u32, + pub colour_encoding: u8, + pub packed: bool, + pub pixels_per_group: u32, + pub planes: &'static [PixelFormatPlaneInfoData], + pub v4l2_formats: &'static [u32], +} + +pub(crate) static PIXEL_FORMAT_INFO: &[PixelFormatInfoData] = &[ + PixelFormatInfoData { name: "RGB565", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50424752], }, + PixelFormatInfoData { name: "RGB565_BE", fourcc: 0xb6314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52424752], }, + PixelFormatInfoData { name: "BGR888", fourcc: 0x34324742, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33424752], }, + PixelFormatInfoData { name: "RGB888", fourcc: 0x34324752, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33524742], }, + PixelFormatInfoData { name: "XRGB8888", fourcc: 0x34325258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325258], }, + PixelFormatInfoData { name: "XBGR8888", fourcc: 0x34324258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324258], }, + PixelFormatInfoData { name: "RGBX8888", fourcc: 0x34325852, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325852], }, + PixelFormatInfoData { name: "BGRX8888", fourcc: 0x34325842, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325842], }, + PixelFormatInfoData { name: "ABGR8888", fourcc: 0x34324241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324241], }, + PixelFormatInfoData { name: "ARGB8888", fourcc: 0x34325241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325241], }, + PixelFormatInfoData { name: "BGRA8888", fourcc: 0x34324142, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324142], }, + PixelFormatInfoData { name: "RGBA8888", fourcc: 0x34324152, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324152], }, + PixelFormatInfoData { name: "BGR161616", fourcc: 0x38344742, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36424752], }, + PixelFormatInfoData { name: "RGB161616", fourcc: 0x38344752, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36524742], }, + PixelFormatInfoData { name: "YUYV", fourcc: 0x56595559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x56595559], }, + PixelFormatInfoData { name: "YVYU", fourcc: 0x55595659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x55595659], }, + PixelFormatInfoData { name: "UYVY", fourcc: 0x59565955, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59565955], }, + PixelFormatInfoData { name: "VYUY", fourcc: 0x59555956, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59555956], }, + PixelFormatInfoData { name: "AVUY8888", fourcc: 0x59555641, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41565559], }, + PixelFormatInfoData { name: "XVUY8888", fourcc: 0x59555658, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x58565559], }, + PixelFormatInfoData { name: "NV12", fourcc: 0x3231564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3231564e, 0x32314d4e], }, + PixelFormatInfoData { name: "NV21", fourcc: 0x3132564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3132564e, 0x31324d4e], }, + PixelFormatInfoData { name: "NV16", fourcc: 0x3631564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3631564e, 0x36314d4e], }, + PixelFormatInfoData { name: "NV61", fourcc: 0x3136564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3136564e, 0x31364d4e], }, + PixelFormatInfoData { name: "NV24", fourcc: 0x3432564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3432564e], }, + PixelFormatInfoData { name: "NV42", fourcc: 0x3234564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3234564e], }, + PixelFormatInfoData { name: "YUV420", fourcc: 0x32315559, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315559, 0x32314d59], }, + PixelFormatInfoData { name: "YVU420", fourcc: 0x32315659, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315659, 0x31324d59], }, + PixelFormatInfoData { name: "YUV422", fourcc: 0x36315559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323234, 0x36314d59], }, + PixelFormatInfoData { name: "YVU422", fourcc: 0x36315659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31364d59], }, + PixelFormatInfoData { name: "YUV444", fourcc: 0x34325559, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324d59], }, + PixelFormatInfoData { name: "YVU444", fourcc: 0x34325659, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32344d59], }, + PixelFormatInfoData { name: "R8", fourcc: 0x20203852, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59455247], }, + PixelFormatInfoData { name: "R10", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20303159], }, + PixelFormatInfoData { name: "R10_CSI2P", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50303159], }, + PixelFormatInfoData { name: "R12_CSI2P", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323159], }, + PixelFormatInfoData { name: "R12", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20323159], }, + PixelFormatInfoData { name: "R16", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20363159], }, + PixelFormatInfoData { name: "MONO_PISP_COMP1", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: true, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x4d314350], }, + PixelFormatInfoData { name: "SBGGR8", fourcc: 0x31384142, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31384142], }, + PixelFormatInfoData { name: "SGBRG8", fourcc: 0x47524247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47524247], }, + PixelFormatInfoData { name: "SGRBG8", fourcc: 0x47425247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47425247], }, + PixelFormatInfoData { name: "SRGGB8", fourcc: 0x42474752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42474752], }, + PixelFormatInfoData { name: "SBGGR10", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314742], }, + PixelFormatInfoData { name: "SGBRG10", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314247], }, + PixelFormatInfoData { name: "SGRBG10", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314142], }, + PixelFormatInfoData { name: "SRGGB10", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314752], }, + PixelFormatInfoData { name: "SBGGR10_CSI2P", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414270], }, + PixelFormatInfoData { name: "SGBRG10_CSI2P", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414770], }, + PixelFormatInfoData { name: "SGRBG10_CSI2P", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41416770], }, + PixelFormatInfoData { name: "SRGGB10_CSI2P", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41415270], }, + PixelFormatInfoData { name: "SBGGR12", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314742], }, + PixelFormatInfoData { name: "SGBRG12", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314247], }, + PixelFormatInfoData { name: "SGRBG12", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314142], }, + PixelFormatInfoData { name: "SRGGB12", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314752], }, + PixelFormatInfoData { name: "SBGGR12_CSI2P", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434270], }, + PixelFormatInfoData { name: "SGBRG12_CSI2P", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434770], }, + PixelFormatInfoData { name: "SGRBG12_CSI2P", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43436770], }, + PixelFormatInfoData { name: "SRGGB12_CSI2P", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43435270], }, + PixelFormatInfoData { name: "SBGGR14", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314742], }, + PixelFormatInfoData { name: "SGBRG14", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314247], }, + PixelFormatInfoData { name: "SGRBG14", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34315247], }, + PixelFormatInfoData { name: "SRGGB14", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314752], }, + PixelFormatInfoData { name: "SBGGR14_CSI2P", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454270], }, + PixelFormatInfoData { name: "SGBRG14_CSI2P", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454770], }, + PixelFormatInfoData { name: "SGRBG14_CSI2P", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45456770], }, + PixelFormatInfoData { name: "SRGGB14_CSI2P", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45455270], }, + PixelFormatInfoData { name: "SBGGR16", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32525942], }, + PixelFormatInfoData { name: "SGBRG16", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314247], }, + PixelFormatInfoData { name: "SGRBG16", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36315247], }, + PixelFormatInfoData { name: "SRGGB16", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314752], }, + PixelFormatInfoData { name: "SBGGR10_IPU3", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x62337069], }, + PixelFormatInfoData { name: "SGBRG10_IPU3", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67337069], }, + PixelFormatInfoData { name: "SGRBG10_IPU3", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47337069], }, + PixelFormatInfoData { name: "SRGGB10_IPU3", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x72337069], }, + PixelFormatInfoData { name: "BGGR_PISP_COMP1", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42314350], }, + PixelFormatInfoData { name: "GBRG_PISP_COMP1", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67314350], }, + PixelFormatInfoData { name: "GRBG_PISP_COMP1", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47314350], }, + PixelFormatInfoData { name: "RGGB_PISP_COMP1", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52314350], }, + PixelFormatInfoData { name: "MJPEG", fourcc: 0x47504a4d, modifier: 0x0000000000000000, bits_per_pixel: 0, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47504a4d, 0x4745504a], }, +]; diff --git a/libcamera/versioned_files/0.5.0/properties.rs b/libcamera/versioned_files/0.5.0/properties.rs index 20fdcd8..e373566 100644 --- a/libcamera/versioned_files/0.5.0/properties.rs +++ b/libcamera/versioned_files/0.5.0/properties.rs @@ -724,6 +724,681 @@ impl PropertyId { pub fn id(&self) -> u32 { u32::from(*self) } + pub fn description(&self) -> &'static str { + match self { + PropertyId::Location => "Camera mounting location +", + PropertyId::Rotation => { + "The camera physical mounting rotation. It is expressed as the angular +difference in degrees between two reference systems, one relative to the +camera module, and one defined on the external world scene to be +captured when projected on the image sensor pixel array. + +A camera sensor has a 2-dimensional reference system 'Rc' defined by +its pixel array read-out order. The origin is set to the first pixel +being read out, the X-axis points along the column read-out direction +towards the last columns, and the Y-axis along the row read-out +direction towards the last row. + +A typical example for a sensor with a 2592x1944 pixel array matrix +observed from the front is + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + +The external world scene reference system 'Rs' is a 2-dimensional +reference system on the focal plane of the camera module. The origin is +placed on the top-left corner of the visible scene, the X-axis points +towards the right, and the Y-axis points towards the bottom of the +scene. The top, bottom, left and right directions are intentionally not +defined and depend on the environment in which the camera is used. + +A typical example of a (very common) picture of a shark swimming from +left to right, as seen from the camera, is + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\\____)\\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + +With the reference system 'Rs' placed on the camera focal plane. + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \\-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + +When projected on the sensor's pixel array, the image and the associated +reference system 'Rs' are typically (but not always) inverted, due to +the camera module's lens optical inversion effect. + +Assuming the above represented scene of the swimming shark, the lens +inversion projects the scene and its reference system onto the sensor +pixel array, seen from the front of the camera sensor, as follow + + Y-axis + ^ + ! + ! + ! + ! |\\_____)\\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + +Note the shark being upside-down. + +The resulting projected reference system is named 'Rp'. + +The camera rotation property is then defined as the angular difference +in the counter-clockwise direction between the camera reference system +'Rc' and the projected scene reference system 'Rp'. It is expressed in +degrees as a number in the range [0, 360[. + +Examples + +0 degrees camera rotation + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + +90 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +180 degrees camera rotation + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +270 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + +Example one - Webcam + +A camera module installed on the user facing part of a laptop screen +casing used for video calls. The captured images are meant to be +displayed in landscape mode (width > height) on the laptop screen. + +The camera is typically mounted upside-down to compensate the lens +optical inversion effect. + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + +The two reference systems are aligned, the resulting camera rotation is +0 degrees, no rotation correction needs to be applied to the resulting +image once captured to memory buffers to correctly display it to users. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +If the camera sensor is not mounted upside-down to compensate for the +lens optical inversion, the two reference systems will not be aligned, +with 'Rp' being rotated 180 degrees relatively to 'Rc'. + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\\_____)\\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +The image once captured to memory will then be rotated by 180 degrees + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \\( \\| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +A software rotation correction of 180 degrees should be applied to +correctly display the image. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +Example two - Phone camera + +A camera installed on the back side of a mobile device facing away from +the user. The captured images are meant to be displayed in portrait mode +(height > width) to match the device screen orientation and the device +usage orientation used when taking the picture. + +The camera sensor is typically mounted with its pixel array longer side +aligned to the device longer side, upside-down mounted to compensate for +the lens optical inversion effect. + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +The two reference systems are not aligned and the 'Rp' reference +system is rotated by 90 degrees in the counter-clockwise direction +relatively to the 'Rc' reference system. + +The image once captured to memory will be rotated. + + +-------------------------------------+ + | _ _ | + | \\ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + +A correction of 90 degrees in counter-clockwise direction has to be +applied to correctly display the image in portrait mode on the device +screen. + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\\____)\\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ +" + } + PropertyId::Model => { + "The model name shall to the extent possible describe the sensor. For +most devices this is the model name of the sensor. While for some +devices the sensor model is unavailable as the sensor or the entire +camera is part of a larger unit and exposed as a black-box to the +system. In such cases the model name of the smallest device that +contains the camera sensor shall be used. + +The model name is not meant to be a camera name displayed to the +end-user, but may be combined with other camera information to create a +camera name. + +The model name is not guaranteed to be unique in the system nor is +it guaranteed to be stable or have any other properties required to make +it a good candidate to be used as a permanent identifier of a camera. + +The model name shall describe the camera in a human readable format and +shall be encoded in ASCII. + +Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. +" + } + PropertyId::UnitCellSize => { + "The pixel unit cell physical size, in nanometers. + +The UnitCellSize properties defines the horizontal and vertical sizes of +a single pixel unit, including its active and non-active parts. In +other words, it expresses the horizontal and vertical distance between +the top-left corners of adjacent pixels. + +The property can be used to calculate the physical size of the sensor's +pixel array area and for calibration purposes. +" + } + PropertyId::PixelArraySize => { + "The camera sensor pixel array readable area vertical and horizontal +sizes, in pixels. + +The PixelArraySize property defines the size in pixel units of the +readable part of full pixel array matrix, including optical black +pixels used for calibration, pixels which are not considered valid for +capture and active pixels containing valid image data. + +The property describes the maximum size of the raw data captured by the +camera, which might not correspond to the physical size of the sensor +pixel array matrix, as some portions of the physical pixel array matrix +are not accessible and cannot be transmitted out. + +For example, let's consider a pixel array matrix assembled as follows + + +--------------------------------------------------+ + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + ... ... ... ... ... + + ... ... ... ... ... + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + +--------------------------------------------------+ + +starting with two lines of non-readable pixels (x), followed by N lines +of readable data (D) surrounded by two columns of non-readable pixels on +each side, and ending with two more lines of non-readable pixels. Only +the readable portion is transmitted to the receiving side, defining the +sizes of the largest possible buffer of raw data that can be presented +to applications. + + PixelArraySize.width + /----------------------------------------------/ + +----------------------------------------------+ / + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + ... ... ... ... ... + ... ... ... ... ... + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + +----------------------------------------------+ / + +This defines a rectangle whose top-left corner is placed in position (0, +0) and whose vertical and horizontal sizes are defined by this property. +All other rectangles that describe portions of the pixel array, such as +the optical black pixels rectangles and active pixel areas, are defined +relatively to this rectangle. + +All the coordinates are expressed relative to the default sensor readout +direction, without any transformation (such as horizontal and vertical +flipping) applied. When mapping them to the raw pixel buffer, +applications shall take any configured transformation into account. + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::Size) +" + } + PropertyId::PixelArrayOpticalBlackRectangles => { + "The pixel array region(s) which contain optical black pixels +considered valid for calibration purposes. + +This property describes the position and size of optical black pixel +regions in the raw data buffer as stored in memory, which might differ +from their actual physical location in the pixel array matrix. + +It is important to note, in fact, that camera sensors might +automatically reorder or skip portions of their pixels array matrix when +transmitting data to the receiver. For instance, a sensor may merge the +top and bottom optical black rectangles into a single rectangle, +transmitted at the beginning of the frame. + +The pixel array contains several areas with different purposes, +interleaved by lines and columns which are said not to be valid for +capturing purposes. Invalid lines and columns are defined as invalid as +they could be positioned too close to the chip margins or to the optical +black shielding placed on top of optical black pixels. + + PixelArraySize.width + /----------------------------------------------/ + x1 x2 + +--o---------------------------------------o---+ / + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + ... ... ... ... ... + ... ... ... ... ... + y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + +----------------------------------------------+ / + +The readable pixel array matrix is composed by +2 invalid lines (I) +4 lines of valid optical black pixels (O) +2 invalid lines (I) +n lines of valid pixel data (P) +2 invalid lines (I) + +And the position of the optical black pixel rectangles is defined by + + PixelArrayOpticalBlackRectangles = { + { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + { x1, y3, 2, y4 - y3 + 1 }, + { x2, y3, 2, y4 - y3 + 1 }, + }; + +If the camera, when capturing the full pixel array matrix, automatically +skips the invalid lines and columns, producing the following data +buffer, when captured to memory + + PixelArraySize.width + /----------------------------------------------/ + x1 + +--------------------------------------------o-+ / + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + ... ... ... ... ... | + ... ... ... ... ... | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + +----------------------------------------------+ / + +then the invalid lines and columns should not be reported as part of the +PixelArraySize property in first place. + +In this case, the position of the black pixel rectangles will be + + PixelArrayOpticalBlackRectangles = { + { 0, 0, y1 + 1, PixelArraySize[0] }, + { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + }; + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::OpticalBlackRectangles) +" + } + PropertyId::PixelArrayActiveAreas => { + "The PixelArrayActiveAreas property defines the (possibly multiple and +overlapping) portions of the camera sensor readable pixel matrix +which are considered valid for image acquisition purposes. + +This property describes an arbitrary number of overlapping rectangles, +with each rectangle representing the maximum image size that the camera +sensor can produce for a particular aspect ratio. They are defined +relatively to the PixelArraySize rectangle. + +When multiple rectangles are reported, they shall be ordered from the +tallest to the shortest. + +Example 1 +A camera sensor which only produces images in the 4:3 image resolution +will report a single PixelArrayActiveAreas rectangle, from which all +other image formats are obtained by either cropping the field-of-view +and/or applying pixel sub-sampling techniques such as pixel skipping or +binning. + + PixelArraySize.width + /----------------/ + x1 x2 + (0,0)-> +-o------------o-+ / + y1 o +------------+ | | + | |////////////| | | + | |////////////| | | PixelArraySize.height + | |////////////| | | + y2 o +------------+ | | + +----------------+ / + +The property reports a single rectangle + + PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + +Example 2 +A camera sensor which can produce images in different native +resolutions will report several overlapping rectangles, one for each +natively supported resolution. + + PixelArraySize.width + /------------------/ + x1 x2 x3 x4 + (0,0)-> +o---o------o---o+ / + y1 o +------+ | | + | |//////| | | + y2 o+---+------+---+| | + ||///|//////|///|| | PixelArraySize.height + y3 o+---+------+---+| | + | |//////| | | + y4 o +------+ | | + +----+------+----+ / + +The property reports two rectangles + + PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + +The first rectangle describes the maximum field-of-view of all image +formats in the 4:3 resolutions, while the second one describes the +maximum field of view for all image formats in the 16:9 resolutions. + +Multiple rectangles shall only be reported when the sensor can't capture +the pixels in the corner regions. If all the pixels in the (x1,y1) - +(x4,y4) area can be captured, the PixelArrayActiveAreas property shall +contains the single rectangle (x1,y1) - (x4,y4). + +\\todo Rename this property to ActiveAreas once we will have property + categories (i.e. Properties::PixelArray::ActiveAreas) +" + } + PropertyId::ScalerCropMaximum => { + "The maximum valid rectangle for the controls::ScalerCrop control. This +reflects the minimum mandatory cropping applied in the camera sensor and +the rest of the pipeline. Just as the ScalerCrop control, it defines a +rectangle taken from the sensor's active pixel array. + +This property is valid only after the camera has been successfully +configured and its value may change whenever a new configuration is +applied. + +\\todo Turn this property into a \"maximum control value\" for the +ScalerCrop control once \"dynamic\" controls have been implemented. +" + } + PropertyId::SensorSensitivity => { + "The relative sensitivity of the chosen sensor mode. + +Some sensors have readout modes with different sensitivities. For example, +a binned camera mode might, with the same exposure and gains, produce +twice the signal level of the full resolution readout. This would be +signalled by the binned mode, when it is chosen, indicating a value here +that is twice that of the full resolution mode. This value will be valid +after the configure method has returned successfully. +" + } + PropertyId::SystemDevices => { + "A list of integer values of type dev_t denoting the major and minor +device numbers of the underlying devices used in the operation of this +camera. + +Different cameras may report identical devices. +" + } + #[cfg(feature = "vendor_draft")] + PropertyId::ColorFilterArrangement => { + "The arrangement of color filters on sensor; represents the colors in the +top-left 2x2 section of the sensor, in reading order. Currently +identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. +" + } + } + } } /// Camera mounting location #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] diff --git a/libcamera/versioned_files/0.5.1/controls.rs b/libcamera/versioned_files/0.5.1/controls.rs index 2a61193..e42ce55 100644 --- a/libcamera/versioned_files/0.5.1/controls.rs +++ b/libcamera/versioned_files/0.5.1/controls.rs @@ -770,6 +770,891 @@ impl ControlId { pub fn id(&self) -> u32 { u32::from(*self) } + pub fn description(&self) -> &'static str { + match self { + ControlId::AeEnable => { + "Enable or disable the AEGC algorithm. When this control is set to true, +both ExposureTimeMode and AnalogueGainMode are set to auto, and if this +control is set to false then both are set to manual. + +If ExposureTimeMode or AnalogueGainMode are also set in the same +request as AeEnable, then the modes supplied by ExposureTimeMode or +AnalogueGainMode will take precedence. + +\\sa ExposureTimeMode AnalogueGainMode +" + } + ControlId::AeState => { + "Report the AEGC algorithm state. + +The AEGC algorithm computes the exposure time and the analogue gain +to be applied to the image sensor. + +The AEGC algorithm behaviour is controlled by the ExposureTimeMode and +AnalogueGainMode controls, which allow applications to decide how +the exposure time and gain are computed, in Auto or Manual mode, +independently from one another. + +The AeState control reports the AEGC algorithm state through a single +value and describes it as a single computation block which computes +both the exposure time and the analogue gain values. + +When both the exposure time and analogue gain values are configured to +be in Manual mode, the AEGC algorithm is quiescent and does not actively +compute any value and the AeState control will report AeStateIdle. + +When at least the exposure time or analogue gain are configured to be +computed by the AEGC algorithm, the AeState control will report if the +algorithm has converged to stable values for all of the controls set +to be computed in Auto mode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::AeMeteringMode => { + "Specify a metering mode for the AE algorithm to use. + +The metering modes determine which parts of the image are used to +determine the scene brightness. Metering modes may be platform specific +and not all metering modes may be supported. +" + } + ControlId::AeConstraintMode => { + "Specify a constraint mode for the AE algorithm to use. + +The constraint modes determine how the measured scene brightness is +adjusted to reach the desired target exposure. Constraint modes may be +platform specific, and not all constraint modes may be supported. +" + } + ControlId::AeExposureMode => { + "Specify an exposure mode for the AE algorithm to use. + +The exposure modes specify how the desired total exposure is divided +between the exposure time and the sensor's analogue gain. They are +platform specific, and not all exposure modes may be supported. + +When one of AnalogueGainMode or ExposureTimeMode is set to Manual, +the fixed values will override any choices made by AeExposureMode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureValue => { + "Specify an Exposure Value (EV) parameter. + +The EV parameter will only be applied if the AE algorithm is currently +enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode +are in Auto mode. + +By convention EV adjusts the exposure as log2. For example +EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment +of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureTime => { + "Exposure time for the frame applied in the sensor device. + +This value is specified in micro-seconds. + +This control will only take effect if ExposureTimeMode is Manual. If +this control is set when ExposureTimeMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what exposure time +was used for the current frame, regardless of ExposureTimeMode. +ExposureTimeMode will indicate the source of the exposure time value, +whether it came from the AE algorithm or not. + +\\sa AnalogueGain +\\sa ExposureTimeMode +" + } + ControlId::ExposureTimeMode => { + "Controls the source of the exposure time that is applied to the image +sensor. + +When set to Auto, the AE algorithm computes the exposure time and +configures the image sensor accordingly. When set to Manual, the value +of the ExposureTime control is used. + +When transitioning from Auto to Manual mode and no ExposureTime control +is provided by the application, the last value computed by the AE +algorithm when the mode was Auto will be used. If the ExposureTimeMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If ExposureTimeModeManual is supported, the ExposureTime control must +also be supported. + +Cameras that support manual control of the sensor shall support manual +mode for both ExposureTimeMode and AnalogueGainMode, and shall expose +the ExposureTime and AnalogueGain controls. If the camera also has an +AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall +support both manual and auto mode. If auto mode is available, it shall +be the default mode. These rules do not apply to black box cameras +such as UVC cameras, where the available gain and exposure modes are +completely dependent on what the device exposes. + +\\par Flickerless exposure mode transitions + +Applications that wish to transition from ExposureTimeModeAuto to direct +control of the exposure time without causing extra flicker can do so by +selecting an ExposureTime value as close as possible to the last value +computed by the auto exposure algorithm in order to avoid any visible +flickering. + +To select the correct value to use as ExposureTime value, applications +should accommodate the natural delay in applying controls caused by the +capture pipeline frame depth. + +When switching to manual exposure mode, applications should not +immediately specify an ExposureTime value in the same request where +ExposureTimeMode is set to Manual. They should instead wait for the +first Request where ExposureTimeMode is reported as +ExposureTimeModeManual in the Request metadata, and use the reported +ExposureTime to populate the control value in the next Request to be +queued to the Camera. + +The implementation of the auto-exposure algorithm should equally try to +minimize flickering and when transitioning from manual exposure mode to +auto exposure use the last value provided by the application as starting +point. + +1. Start with ExposureTimeMode set to Auto + +2. Set ExposureTimeMode to Manual + +3. Wait for the first completed request that has ExposureTimeMode +set to Manual + +4. Copy the value reported in ExposureTime into a new request, and +submit it + +5. Proceed to run manual exposure time as desired + +\\sa ExposureTime +" + } + ControlId::AnalogueGain => { + "Analogue gain value applied in the sensor device. + +The value of the control specifies the gain multiplier applied to all +colour channels. This value cannot be lower than 1.0. + +This control will only take effect if AnalogueGainMode is Manual. If +this control is set when AnalogueGainMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what analogue gain +was used for the current request, regardless of AnalogueGainMode. +AnalogueGainMode will indicate the source of the analogue gain value, +whether it came from the AEGC algorithm or not. + +\\sa ExposureTime +\\sa AnalogueGainMode +" + } + ControlId::AnalogueGainMode => { + "Controls the source of the analogue gain that is applied to the image +sensor. + +When set to Auto, the AEGC algorithm computes the analogue gain and +configures the image sensor accordingly. When set to Manual, the value +of the AnalogueGain control is used. + +When transitioning from Auto to Manual mode and no AnalogueGain control +is provided by the application, the last value computed by the AEGC +algorithm when the mode was Auto will be used. If the AnalogueGainMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If AnalogueGainModeManual is supported, the AnalogueGain control must +also be supported. + +For cameras where we have control over the ISP, both ExposureTimeMode +and AnalogueGainMode are expected to support manual mode, and both +controls (as well as ExposureTimeMode and AnalogueGain) are expected to +be present. If the camera also has an AEGC implementation, both +ExposureTimeMode and AnalogueGainMode shall support both manual and +auto mode. If auto mode is available, it shall be the default mode. +These rules do not apply to black box cameras such as UVC cameras, +where the available gain and exposure modes are completely dependent on +what the hardware exposes. + +The same procedure described for performing flickerless transitions in +the ExposureTimeMode control documentation can be applied to analogue +gain. + +\\sa ExposureTimeMode +\\sa AnalogueGain +" + } + ControlId::AeFlickerMode => { + "Set the flicker avoidance mode for AGC/AEC. + +The flicker mode determines whether, and how, the AGC/AEC algorithm +attempts to hide flicker effects caused by the duty cycle of artificial +lighting. + +Although implementation dependent, many algorithms for \"flicker +avoidance\" work by restricting this exposure time to integer multiples +of the cycle period, wherever possible. + +Implementations may not support all of the flicker modes listed below. + +By default the system will start in FlickerAuto mode if this is +supported, otherwise the flicker mode will be set to FlickerOff. +" + } + ControlId::AeFlickerPeriod => { + "Manual flicker period in microseconds. + +This value sets the current flicker period to avoid. It is used when +AeFlickerMode is set to FlickerManual. + +To cancel 50Hz mains flicker, this should be set to 10000 (corresponding +to 100Hz), or 8333 (120Hz) for 60Hz mains. + +Setting the mode to FlickerManual when no AeFlickerPeriod has ever been +set means that no flicker cancellation occurs (until the value of this +control is updated). + +Switching to modes other than FlickerManual has no effect on the +value of the AeFlickerPeriod control. + +\\sa AeFlickerMode +" + } + ControlId::AeFlickerDetected => { + "Flicker period detected in microseconds. + +The value reported here indicates the currently detected flicker +period, or zero if no flicker at all is detected. + +When AeFlickerMode is set to FlickerAuto, there may be a period during +which the value reported here remains zero. Once a non-zero value is +reported, then this is the flicker period that has been detected and is +now being cancelled. + +In the case of 50Hz mains flicker, the value would be 10000 +(corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + +It is implementation dependent whether the system can continue to detect +flicker of different periods when another frequency is already being +cancelled. + +\\sa AeFlickerMode +" + } + ControlId::Brightness => { + "Specify a fixed brightness parameter. + +Positive values (up to 1.0) produce brighter images; negative values +(up to -1.0) produce darker images and 0.0 leaves pixels unchanged. +" + } + ControlId::Contrast => { + "Specify a fixed contrast parameter. + +Normal contrast is given by the value 1.0; larger values produce images +with more contrast. +" + } + ControlId::Lux => { + "Report an estimate of the current illuminance level in lux. + +The Lux control can only be returned in metadata. +" + } + ControlId::AwbEnable => { + "Enable or disable the AWB. + +When AWB is enabled, the algorithm estimates the colour temperature of +the scene and computes colour gains and the colour correction matrix +automatically. The computed colour temperature, gains and correction +matrix are reported in metadata. The corresponding controls are ignored +if set in a request. + +When AWB is disabled, the colour temperature, gains and correction +matrix are not updated automatically and can be set manually in +requests. + +\\sa ColourCorrectionMatrix +\\sa ColourGains +\\sa ColourTemperature +" + } + ControlId::AwbMode => { + "Specify the range of illuminants to use for the AWB algorithm. + +The modes supported are platform specific, and not all modes may be +supported. +" + } + ControlId::AwbLocked => { + "Report the lock status of a running AWB algorithm. + +If the AWB algorithm is locked the value shall be set to true, if it's +converging it shall be set to false. If the AWB algorithm is not +running the control shall not be present in the metadata control list. + +\\sa AwbEnable +" + } + ControlId::ColourGains => { + "Pair of gain values for the Red and Blue colour channels, in that +order. + +ColourGains can only be applied in a Request when the AWB is disabled. +If ColourGains is set in a request but ColourTemperature is not, the +implementation shall calculate and set the ColourTemperature based on +the ColourGains. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ColourTemperature => { + "ColourTemperature of the frame, in kelvin. + +ColourTemperature can only be applied in a Request when the AWB is +disabled. + +If ColourTemperature is set in a request but ColourGains is not, the +implementation shall calculate and set the ColourGains based on the +given ColourTemperature. If ColourTemperature is set (either directly, +or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, +the ColourCorrectionMatrix is updated based on the ColourTemperature. + +The ColourTemperature used to process the frame is reported in metadata. + +\\sa AwbEnable +\\sa ColourCorrectionMatrix +\\sa ColourGains +" + } + ControlId::Saturation => { + "Specify a fixed saturation parameter. + +Normal saturation is given by the value 1.0; larger values produce more +saturated colours; 0.0 produces a greyscale image. +" + } + ControlId::SensorBlackLevels => { + "Reports the sensor black levels used for processing a frame. + +The values are in the order R, Gr, Gb, B. They are returned as numbers +out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The +SensorBlackLevels control can only be returned in metadata. +" + } + ControlId::Sharpness => { + "Intensity of the sharpening applied to the image. + +A value of 0.0 means no sharpening. The minimum value means +minimal sharpening, and shall be 0.0 unless the camera can't +disable sharpening completely. The default value shall give a +\"reasonable\" level of sharpening, suitable for most use cases. +The maximum value may apply extremely high levels of sharpening, +higher than anyone could reasonably want. Negative values are +not allowed. Note also that sharpening is not applied to raw +streams. +" + } + ControlId::FocusFoM => { + "Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + +A larger FocusFoM value indicates a more in-focus frame. This singular +value may be based on a combination of statistics gathered from +multiple focus regions within an image. The number of focus regions and +method of combination is platform dependent. In this respect, it is not +necessarily aimed at providing a way to implement a focus algorithm by +the application, rather an indication of how in-focus a frame is. +" + } + ControlId::ColourCorrectionMatrix => { + "The 3x3 matrix that converts camera RGB to sRGB within the imaging +pipeline. + +This should describe the matrix that is used after pixels have been +white-balanced, but before any gamma transformation. The 3x3 matrix is +stored in conventional reading order in an array of 9 floating point +values. + +ColourCorrectionMatrix can only be applied in a Request when the AWB is +disabled. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ScalerCrop => { + "Sets the image portion that will be scaled to form the whole of +the final output image. + +The (x,y) location of this rectangle is relative to the +PixelArrayActiveAreas that is being used. The units remain native +sensor pixels, even if the sensor is being used in a binning or +skipping mode. + +This control is only present when the pipeline supports scaling. Its +maximum valid value is given by the properties::ScalerCropMaximum +property, and the two can be used to implement digital zoom. +" + } + ControlId::DigitalGain => { + "Digital gain value applied during the processing steps applied +to the image as captured from the sensor. + +The global digital gain factor is applied to all the colour channels +of the RAW image. Different pipeline models are free to +specify how the global gain factor applies to each separate +channel. + +If an imaging pipeline applies digital gain in distinct +processing steps, this value indicates their total sum. +Pipelines are free to decide how to adjust each processing +step to respect the received gain factor and shall report +their total value in the request metadata. +" + } + ControlId::FrameDuration => { + "The instantaneous frame duration from start of frame exposure to start +of next exposure, expressed in microseconds. + +This control is meant to be returned in metadata. +" + } + ControlId::FrameDurationLimits => { + "The minimum and maximum (in that order) frame duration, expressed in +microseconds. + +When provided by applications, the control specifies the sensor frame +duration interval the pipeline has to use. This limits the largest +exposure time the sensor can use. For example, if a maximum frame +duration of 33ms is requested (corresponding to 30 frames per second), +the sensor will not be able to raise the exposure time above 33ms. +A fixed frame duration is achieved by setting the minimum and maximum +values to be the same. Setting both values to 0 reverts to using the +camera defaults. + +The maximum frame duration provides the absolute limit to the exposure +time computed by the AE algorithm and it overrides any exposure mode +setting specified with controls::AeExposureMode. Similarly, when a +manual exposure time is set through controls::ExposureTime, it also +gets clipped to the limits set by this control. When reported in +metadata, the control expresses the minimum and maximum frame durations +used after being clipped to the sensor provided frame duration limits. + +\\sa AeExposureMode +\\sa ExposureTime + +\\todo Define how to calculate the capture frame rate by +defining controls to report additional delays introduced by +the capture pipeline or post-processing stages (ie JPEG +conversion, frame scaling). + +\\todo Provide an explicit definition of default control values, for +this and all other controls. +" + } + ControlId::SensorTemperature => { + "Temperature measure from the camera sensor in Celsius. + +This value is typically obtained by a thermal sensor present on-die or +in the camera module. The range of reported temperatures is device +dependent. + +The SensorTemperature control will only be returned in metadata if a +thermal sensor is present. +" + } + ControlId::SensorTimestamp => { + "The time when the first row of the image sensor active array is exposed. + +The timestamp, expressed in nanoseconds, represents a monotonically +increasing counter since the system boot time, as defined by the +Linux-specific CLOCK_BOOTTIME clock id. + +The SensorTimestamp control can only be returned in metadata. + +\\todo Define how the sensor timestamp has to be used in the reprocessing +use case. +" + } + ControlId::AfMode => { + "The mode of the AF (autofocus) algorithm. + +An implementation may choose not to implement all the modes. +" + } + ControlId::AfRange => { + "The range of focus distances that is scanned. + +An implementation may choose not to implement all the options here. +" + } + ControlId::AfSpeed => { + "Determine whether the AF is to move the lens as quickly as possible or +more steadily. + +For example, during video recording it may be desirable not to move the +lens too abruptly, but when in a preview mode (waiting for a still +capture) it may be helpful to move the lens as quickly as is reasonably +possible. +" + } + ControlId::AfMetering => { + "The parts of the image used by the AF algorithm to measure focus. +" + } + ControlId::AfWindows => { + "The focus windows used by the AF algorithm when AfMetering is set to +AfMeteringWindows. + +The units used are pixels within the rectangle returned by the +ScalerCropMaximum property. + +In order to be activated, a rectangle must be programmed with non-zero +width and height. Internally, these rectangles are intersected with the +ScalerCropMaximum rectangle. If the window becomes empty after this +operation, then the window is ignored. If all the windows end up being +ignored, then the behaviour is platform dependent. + +On platforms that support the ScalerCrop control (for implementing +digital zoom, for example), no automatic recalculation or adjustment of +AF windows is performed internally if the ScalerCrop is changed. If any +window lies outside the output image after the scaler crop has been +applied, it is up to the application to recalculate them. + +The details of how the windows are used are platform dependent. We note +that when there is more than one AF window, a typical implementation +might find the optimal focus position for each one and finally select +the window where the focal distance for the objects shown in that part +of the image are closest to the camera. +" + } + ControlId::AfTrigger => { + "Start an autofocus scan. + +This control starts an autofocus scan when AfMode is set to AfModeAuto, +and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It +can also be used to terminate a scan early. +" + } + ControlId::AfPause => { + "Pause lens movements when in continuous autofocus mode. + +This control has no effect except when in continuous autofocus mode +(AfModeContinuous). It can be used to pause any lens movements while +(for example) images are captured. The algorithm remains inactive +until it is instructed to resume. +" + } + ControlId::LensPosition => { + "Set and report the focus lens position. + +This control instructs the lens to move to a particular position and +also reports back the position of the lens for each frame. + +The LensPosition control is ignored unless the AfMode is set to +AfModeManual, though the value is reported back unconditionally in all +modes. + +This value, which is generally a non-integer, is the reciprocal of the +focal distance in metres, also known as dioptres. That is, to set a +focal distance D, the lens position LP is given by + +\\f$LP = \\frac{1\\mathrm{m}}{D}\\f$ + +For example: + +- 0 moves the lens to infinity. +- 0.5 moves the lens to focus on objects 2m away. +- 2 moves the lens to focus on objects 50cm away. +- And larger values will focus the lens closer. + +The default value of the control should indicate a good general +position for the lens, often corresponding to the hyperfocal distance +(the closest position for which objects at infinity are still +acceptably sharp). The minimum will often be zero (meaning infinity), +and the maximum value defines the closest focus position. + +\\todo Define a property to report the Hyperfocal distance of calibrated +lenses. +" + } + ControlId::AfState => { + "The current state of the AF algorithm. + +This control reports the current state of the AF algorithm in +conjunction with the reported AfMode value and (in continuous AF mode) +the AfPauseState value. The possible state changes are described below, +though we note the following state transitions that occur when the +AfMode is changed. + +If the AfMode is set to AfModeManual, then the AfState will always +report AfStateIdle (even if the lens is subsequently moved). Changing +to the AfModeManual state does not initiate any lens movement. + +If the AfMode is set to AfModeAuto then the AfState will report +AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent +together then AfState will omit AfStateIdle and move straight to +AfStateScanning (and start a scan). + +If the AfMode is set to AfModeContinuous then the AfState will +initially report AfStateScanning. +" + } + ControlId::AfPauseState => { + "Report whether the autofocus is currently running, paused or pausing. + +This control is only applicable in continuous (AfModeContinuous) mode, +and reports whether the algorithm is currently running, paused or +pausing (that is, will pause as soon as any in-progress scan +completes). + +Any change to AfMode will cause AfPauseStateRunning to be reported. +" + } + ControlId::HdrMode => { + "Set the mode to be used for High Dynamic Range (HDR) imaging. + +HDR techniques typically include multiple exposure, image fusion and +tone mapping techniques to improve the dynamic range of the resulting +images. + +When using an HDR mode, images are captured with different sets of AGC +settings called HDR channels. Channels indicate in particular the type +of exposure (short, medium or long) used to capture the raw image, +before fusion. Each HDR image is tagged with the corresponding channel +using the HdrChannel control. + +\\sa HdrChannel +" + } + ControlId::HdrChannel => { + "The HDR channel used to capture the frame. + +This value is reported back to the application so that it can discover +whether this capture corresponds to the short or long exposure image +(or any other image used by the HDR procedure). An application can +monitor the HDR channel to discover when the differently exposed images +have arrived. + +This metadata is only available when an HDR mode has been enabled. + +\\sa HdrMode +" + } + ControlId::Gamma => { + "Specify a fixed gamma value. + +The default gamma value must be 2.2 which closely mimics sRGB gamma. +Note that this is camera gamma, so it is applied as 1.0/gamma. +" + } + ControlId::DebugMetadataEnable => "Enable or disable the debug metadata. +", + #[cfg(feature = "vendor_draft")] + ControlId::AePrecaptureTrigger => { + "Control for AE metering trigger. Currently identical to +ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + +Whether the camera device will trigger a precapture metering sequence +when it processes this request. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::NoiseReductionMode => { + "Control to select the noise reduction algorithm mode. Currently +identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::ColorCorrectionAberrationMode => { + "Control to select the color correction aberration mode. Currently +identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AwbState => { + "Control to report the current AWB algorithm state. Currently identical +to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::SensorRollingShutterSkew => { + "Control to report the time between the start of exposure of the first +row and the start of exposure of the last row. Currently identical to +ANDROID_SENSOR_ROLLING_SHUTTER_SKEW +" + } + #[cfg(feature = "vendor_draft")] + ControlId::LensShadingMapMode => { + "Control to report if the lens shading map is available. Currently +identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::PipelineDepth => { + "Specifies the number of pipeline stages the frame went through from when +it was exposed to when the final completed result was available to the +framework. Always less than or equal to PipelineMaxDepth. Currently +identical to ANDROID_REQUEST_PIPELINE_DEPTH. + +The typical value for this control is 3 as a frame is first exposed, +captured and then processed in a single pass through the ISP. Any +additional processing step performed after the ISP pass (in example face +detection, additional format conversions etc) count as an additional +pipeline stage. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::MaxLatency => { + "The maximum number of frames that can occur after a request (different +than the previous) has been submitted, and before the result's state +becomes synchronized. A value of -1 indicates unknown latency, and 0 +indicates per-frame control. Currently identical to +ANDROID_SYNC_MAX_LATENCY. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::TestPatternMode => { + "Control to select the test pattern mode. Currently identical to +ANDROID_SENSOR_TEST_PATTERN_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectMode => { + "Control to select the face detection mode used by the pipeline. + +Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + +\\sa FaceDetectFaceRectangles +\\sa FaceDetectFaceScores +\\sa FaceDetectFaceLandmarks +\\sa FaceDetectFaceIds +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceRectangles => { + "Boundary rectangles of the detected faces. The number of values is +the number of detected faces. + +The FaceDetectFaceRectangles control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceScores => { + "Confidence score of each of the detected faces. The range of score is +[0, 100]. The number of values should be the number of faces reported +in FaceDetectFaceRectangles. + +The FaceDetectFaceScores control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_SCORES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceLandmarks => { + "Array of human face landmark coordinates in format [..., left_eye_i, +right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The +number of values should be 3 * the number of faces reported in +FaceDetectFaceRectangles. + +The FaceDetectFaceLandmarks control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceIds => { + "Each detected face is given a unique ID that is valid for as long as the +face is visible to the camera device. A face that leaves the field of +view and later returns may be assigned a new ID. The number of values +should be the number of faces reported in FaceDetectFaceRectangles. + +The FaceDetectFaceIds control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_IDS. +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::StatsOutputEnable => { + "Toggles the Raspberry Pi IPA to output the hardware generated statistics. + +When this control is set to true, the IPA outputs a binary dump of the +hardware generated statistics through the Request metadata in the +Bcm2835StatsOutput control. + +\\sa Bcm2835StatsOutput +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::Bcm2835StatsOutput => { + "Span of the BCM2835 ISP generated statistics for the current frame. + +This is sent in the Request metadata if the StatsOutputEnable is set to +true. The statistics struct definition can be found in +include/linux/bcm2835-isp.h. + +\\sa StatsOutputEnable +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::ScalerCrops => { + "An array of rectangles, where each singular value has identical +functionality to the ScalerCrop control. This control allows the +Raspberry Pi pipeline handler to control individual scaler crops per +output stream. + +The order of rectangles passed into the control must match the order of +streams configured by the application. The pipeline handler will only +configure crop retangles up-to the number of output streams configured. +All subsequent rectangles passed into this control are ignored by the +pipeline handler. + +If both rpi::ScalerCrops and ScalerCrop controls are present in a +ControlList, the latter is discarded, and crops are obtained from this +control. + +Note that using different crop rectangles for each output stream with +this control is only applicable on the Pi5/PiSP platform. This control +should also be considered temporary/draft and will be replaced with +official libcamera API support for per-stream controls in the future. + +\\sa ScalerCrop +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::PispStatsOutput => { + "Span of the PiSP Frontend ISP generated statistics for the current +frame. This is sent in the Request metadata if the StatsOutputEnable is +set to true. The statistics struct definition can be found in +https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + +\\sa StatsOutputEnable +" + } + } + } } /// Enable or disable the AEGC algorithm. When this control is set to true, /// both ExposureTimeMode and AnalogueGainMode are set to auto, and if this diff --git a/libcamera/versioned_files/0.5.1/pixel_format_info.rs b/libcamera/versioned_files/0.5.1/pixel_format_info.rs new file mode 100644 index 0000000..16d3ddb --- /dev/null +++ b/libcamera/versioned_files/0.5.1/pixel_format_info.rs @@ -0,0 +1,103 @@ + +// Auto-generated from libcamera/src/libcamera/formats.cpp +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatPlaneInfoData { + pub bytes_per_group: u32, + pub vertical_sub_sampling: u32, +} + +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatInfoData { + pub name: &'static str, + pub fourcc: u32, + pub modifier: u64, + pub bits_per_pixel: u32, + pub colour_encoding: u8, + pub packed: bool, + pub pixels_per_group: u32, + pub planes: &'static [PixelFormatPlaneInfoData], + pub v4l2_formats: &'static [u32], +} + +pub(crate) static PIXEL_FORMAT_INFO: &[PixelFormatInfoData] = &[ + PixelFormatInfoData { name: "RGB565", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50424752], }, + PixelFormatInfoData { name: "RGB565_BE", fourcc: 0xb6314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52424752], }, + PixelFormatInfoData { name: "BGR888", fourcc: 0x34324742, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33424752], }, + PixelFormatInfoData { name: "RGB888", fourcc: 0x34324752, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33524742], }, + PixelFormatInfoData { name: "XRGB8888", fourcc: 0x34325258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325258], }, + PixelFormatInfoData { name: "XBGR8888", fourcc: 0x34324258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324258], }, + PixelFormatInfoData { name: "RGBX8888", fourcc: 0x34325852, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325852], }, + PixelFormatInfoData { name: "BGRX8888", fourcc: 0x34325842, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325842], }, + PixelFormatInfoData { name: "ABGR8888", fourcc: 0x34324241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324241], }, + PixelFormatInfoData { name: "ARGB8888", fourcc: 0x34325241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325241], }, + PixelFormatInfoData { name: "BGRA8888", fourcc: 0x34324142, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324142], }, + PixelFormatInfoData { name: "RGBA8888", fourcc: 0x34324152, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324152], }, + PixelFormatInfoData { name: "BGR161616", fourcc: 0x38344742, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36424752], }, + PixelFormatInfoData { name: "RGB161616", fourcc: 0x38344752, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36524742], }, + PixelFormatInfoData { name: "YUYV", fourcc: 0x56595559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x56595559], }, + PixelFormatInfoData { name: "YVYU", fourcc: 0x55595659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x55595659], }, + PixelFormatInfoData { name: "UYVY", fourcc: 0x59565955, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59565955], }, + PixelFormatInfoData { name: "VYUY", fourcc: 0x59555956, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59555956], }, + PixelFormatInfoData { name: "AVUY8888", fourcc: 0x59555641, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41565559], }, + PixelFormatInfoData { name: "XVUY8888", fourcc: 0x59555658, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x58565559], }, + PixelFormatInfoData { name: "NV12", fourcc: 0x3231564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3231564e, 0x32314d4e], }, + PixelFormatInfoData { name: "NV21", fourcc: 0x3132564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3132564e, 0x31324d4e], }, + PixelFormatInfoData { name: "NV16", fourcc: 0x3631564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3631564e, 0x36314d4e], }, + PixelFormatInfoData { name: "NV61", fourcc: 0x3136564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3136564e, 0x31364d4e], }, + PixelFormatInfoData { name: "NV24", fourcc: 0x3432564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3432564e], }, + PixelFormatInfoData { name: "NV42", fourcc: 0x3234564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3234564e], }, + PixelFormatInfoData { name: "YUV420", fourcc: 0x32315559, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315559, 0x32314d59], }, + PixelFormatInfoData { name: "YVU420", fourcc: 0x32315659, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315659, 0x31324d59], }, + PixelFormatInfoData { name: "YUV422", fourcc: 0x36315559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323234, 0x36314d59], }, + PixelFormatInfoData { name: "YVU422", fourcc: 0x36315659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31364d59], }, + PixelFormatInfoData { name: "YUV444", fourcc: 0x34325559, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324d59], }, + PixelFormatInfoData { name: "YVU444", fourcc: 0x34325659, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32344d59], }, + PixelFormatInfoData { name: "R8", fourcc: 0x20203852, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59455247], }, + PixelFormatInfoData { name: "R10", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20303159], }, + PixelFormatInfoData { name: "R10_CSI2P", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50303159], }, + PixelFormatInfoData { name: "R12_CSI2P", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323159], }, + PixelFormatInfoData { name: "R12", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20323159], }, + PixelFormatInfoData { name: "R16", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20363159], }, + PixelFormatInfoData { name: "MONO_PISP_COMP1", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: true, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x4d314350], }, + PixelFormatInfoData { name: "SBGGR8", fourcc: 0x31384142, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31384142], }, + PixelFormatInfoData { name: "SGBRG8", fourcc: 0x47524247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47524247], }, + PixelFormatInfoData { name: "SGRBG8", fourcc: 0x47425247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47425247], }, + PixelFormatInfoData { name: "SRGGB8", fourcc: 0x42474752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42474752], }, + PixelFormatInfoData { name: "SBGGR10", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314742], }, + PixelFormatInfoData { name: "SGBRG10", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314247], }, + PixelFormatInfoData { name: "SGRBG10", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314142], }, + PixelFormatInfoData { name: "SRGGB10", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314752], }, + PixelFormatInfoData { name: "SBGGR10_CSI2P", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414270], }, + PixelFormatInfoData { name: "SGBRG10_CSI2P", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414770], }, + PixelFormatInfoData { name: "SGRBG10_CSI2P", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41416770], }, + PixelFormatInfoData { name: "SRGGB10_CSI2P", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41415270], }, + PixelFormatInfoData { name: "SBGGR12", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314742], }, + PixelFormatInfoData { name: "SGBRG12", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314247], }, + PixelFormatInfoData { name: "SGRBG12", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314142], }, + PixelFormatInfoData { name: "SRGGB12", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314752], }, + PixelFormatInfoData { name: "SBGGR12_CSI2P", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434270], }, + PixelFormatInfoData { name: "SGBRG12_CSI2P", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434770], }, + PixelFormatInfoData { name: "SGRBG12_CSI2P", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43436770], }, + PixelFormatInfoData { name: "SRGGB12_CSI2P", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43435270], }, + PixelFormatInfoData { name: "SBGGR14", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314742], }, + PixelFormatInfoData { name: "SGBRG14", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314247], }, + PixelFormatInfoData { name: "SGRBG14", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34315247], }, + PixelFormatInfoData { name: "SRGGB14", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314752], }, + PixelFormatInfoData { name: "SBGGR14_CSI2P", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454270], }, + PixelFormatInfoData { name: "SGBRG14_CSI2P", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454770], }, + PixelFormatInfoData { name: "SGRBG14_CSI2P", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45456770], }, + PixelFormatInfoData { name: "SRGGB14_CSI2P", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45455270], }, + PixelFormatInfoData { name: "SBGGR16", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32525942], }, + PixelFormatInfoData { name: "SGBRG16", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314247], }, + PixelFormatInfoData { name: "SGRBG16", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36315247], }, + PixelFormatInfoData { name: "SRGGB16", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314752], }, + PixelFormatInfoData { name: "SBGGR10_IPU3", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x62337069], }, + PixelFormatInfoData { name: "SGBRG10_IPU3", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67337069], }, + PixelFormatInfoData { name: "SGRBG10_IPU3", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47337069], }, + PixelFormatInfoData { name: "SRGGB10_IPU3", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x72337069], }, + PixelFormatInfoData { name: "BGGR_PISP_COMP1", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42314350], }, + PixelFormatInfoData { name: "GBRG_PISP_COMP1", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67314350], }, + PixelFormatInfoData { name: "GRBG_PISP_COMP1", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47314350], }, + PixelFormatInfoData { name: "RGGB_PISP_COMP1", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52314350], }, + PixelFormatInfoData { name: "MJPEG", fourcc: 0x47504a4d, modifier: 0x0000000000000000, bits_per_pixel: 0, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47504a4d, 0x4745504a], }, +]; diff --git a/libcamera/versioned_files/0.5.1/properties.rs b/libcamera/versioned_files/0.5.1/properties.rs index 20fdcd8..e373566 100644 --- a/libcamera/versioned_files/0.5.1/properties.rs +++ b/libcamera/versioned_files/0.5.1/properties.rs @@ -724,6 +724,681 @@ impl PropertyId { pub fn id(&self) -> u32 { u32::from(*self) } + pub fn description(&self) -> &'static str { + match self { + PropertyId::Location => "Camera mounting location +", + PropertyId::Rotation => { + "The camera physical mounting rotation. It is expressed as the angular +difference in degrees between two reference systems, one relative to the +camera module, and one defined on the external world scene to be +captured when projected on the image sensor pixel array. + +A camera sensor has a 2-dimensional reference system 'Rc' defined by +its pixel array read-out order. The origin is set to the first pixel +being read out, the X-axis points along the column read-out direction +towards the last columns, and the Y-axis along the row read-out +direction towards the last row. + +A typical example for a sensor with a 2592x1944 pixel array matrix +observed from the front is + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + +The external world scene reference system 'Rs' is a 2-dimensional +reference system on the focal plane of the camera module. The origin is +placed on the top-left corner of the visible scene, the X-axis points +towards the right, and the Y-axis points towards the bottom of the +scene. The top, bottom, left and right directions are intentionally not +defined and depend on the environment in which the camera is used. + +A typical example of a (very common) picture of a shark swimming from +left to right, as seen from the camera, is + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\\____)\\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + +With the reference system 'Rs' placed on the camera focal plane. + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \\-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + +When projected on the sensor's pixel array, the image and the associated +reference system 'Rs' are typically (but not always) inverted, due to +the camera module's lens optical inversion effect. + +Assuming the above represented scene of the swimming shark, the lens +inversion projects the scene and its reference system onto the sensor +pixel array, seen from the front of the camera sensor, as follow + + Y-axis + ^ + ! + ! + ! + ! |\\_____)\\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + +Note the shark being upside-down. + +The resulting projected reference system is named 'Rp'. + +The camera rotation property is then defined as the angular difference +in the counter-clockwise direction between the camera reference system +'Rc' and the projected scene reference system 'Rp'. It is expressed in +degrees as a number in the range [0, 360[. + +Examples + +0 degrees camera rotation + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + +90 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +180 degrees camera rotation + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +270 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + +Example one - Webcam + +A camera module installed on the user facing part of a laptop screen +casing used for video calls. The captured images are meant to be +displayed in landscape mode (width > height) on the laptop screen. + +The camera is typically mounted upside-down to compensate the lens +optical inversion effect. + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + +The two reference systems are aligned, the resulting camera rotation is +0 degrees, no rotation correction needs to be applied to the resulting +image once captured to memory buffers to correctly display it to users. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +If the camera sensor is not mounted upside-down to compensate for the +lens optical inversion, the two reference systems will not be aligned, +with 'Rp' being rotated 180 degrees relatively to 'Rc'. + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\\_____)\\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +The image once captured to memory will then be rotated by 180 degrees + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \\( \\| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +A software rotation correction of 180 degrees should be applied to +correctly display the image. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +Example two - Phone camera + +A camera installed on the back side of a mobile device facing away from +the user. The captured images are meant to be displayed in portrait mode +(height > width) to match the device screen orientation and the device +usage orientation used when taking the picture. + +The camera sensor is typically mounted with its pixel array longer side +aligned to the device longer side, upside-down mounted to compensate for +the lens optical inversion effect. + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +The two reference systems are not aligned and the 'Rp' reference +system is rotated by 90 degrees in the counter-clockwise direction +relatively to the 'Rc' reference system. + +The image once captured to memory will be rotated. + + +-------------------------------------+ + | _ _ | + | \\ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + +A correction of 90 degrees in counter-clockwise direction has to be +applied to correctly display the image in portrait mode on the device +screen. + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\\____)\\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ +" + } + PropertyId::Model => { + "The model name shall to the extent possible describe the sensor. For +most devices this is the model name of the sensor. While for some +devices the sensor model is unavailable as the sensor or the entire +camera is part of a larger unit and exposed as a black-box to the +system. In such cases the model name of the smallest device that +contains the camera sensor shall be used. + +The model name is not meant to be a camera name displayed to the +end-user, but may be combined with other camera information to create a +camera name. + +The model name is not guaranteed to be unique in the system nor is +it guaranteed to be stable or have any other properties required to make +it a good candidate to be used as a permanent identifier of a camera. + +The model name shall describe the camera in a human readable format and +shall be encoded in ASCII. + +Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. +" + } + PropertyId::UnitCellSize => { + "The pixel unit cell physical size, in nanometers. + +The UnitCellSize properties defines the horizontal and vertical sizes of +a single pixel unit, including its active and non-active parts. In +other words, it expresses the horizontal and vertical distance between +the top-left corners of adjacent pixels. + +The property can be used to calculate the physical size of the sensor's +pixel array area and for calibration purposes. +" + } + PropertyId::PixelArraySize => { + "The camera sensor pixel array readable area vertical and horizontal +sizes, in pixels. + +The PixelArraySize property defines the size in pixel units of the +readable part of full pixel array matrix, including optical black +pixels used for calibration, pixels which are not considered valid for +capture and active pixels containing valid image data. + +The property describes the maximum size of the raw data captured by the +camera, which might not correspond to the physical size of the sensor +pixel array matrix, as some portions of the physical pixel array matrix +are not accessible and cannot be transmitted out. + +For example, let's consider a pixel array matrix assembled as follows + + +--------------------------------------------------+ + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + ... ... ... ... ... + + ... ... ... ... ... + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + +--------------------------------------------------+ + +starting with two lines of non-readable pixels (x), followed by N lines +of readable data (D) surrounded by two columns of non-readable pixels on +each side, and ending with two more lines of non-readable pixels. Only +the readable portion is transmitted to the receiving side, defining the +sizes of the largest possible buffer of raw data that can be presented +to applications. + + PixelArraySize.width + /----------------------------------------------/ + +----------------------------------------------+ / + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + ... ... ... ... ... + ... ... ... ... ... + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + +----------------------------------------------+ / + +This defines a rectangle whose top-left corner is placed in position (0, +0) and whose vertical and horizontal sizes are defined by this property. +All other rectangles that describe portions of the pixel array, such as +the optical black pixels rectangles and active pixel areas, are defined +relatively to this rectangle. + +All the coordinates are expressed relative to the default sensor readout +direction, without any transformation (such as horizontal and vertical +flipping) applied. When mapping them to the raw pixel buffer, +applications shall take any configured transformation into account. + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::Size) +" + } + PropertyId::PixelArrayOpticalBlackRectangles => { + "The pixel array region(s) which contain optical black pixels +considered valid for calibration purposes. + +This property describes the position and size of optical black pixel +regions in the raw data buffer as stored in memory, which might differ +from their actual physical location in the pixel array matrix. + +It is important to note, in fact, that camera sensors might +automatically reorder or skip portions of their pixels array matrix when +transmitting data to the receiver. For instance, a sensor may merge the +top and bottom optical black rectangles into a single rectangle, +transmitted at the beginning of the frame. + +The pixel array contains several areas with different purposes, +interleaved by lines and columns which are said not to be valid for +capturing purposes. Invalid lines and columns are defined as invalid as +they could be positioned too close to the chip margins or to the optical +black shielding placed on top of optical black pixels. + + PixelArraySize.width + /----------------------------------------------/ + x1 x2 + +--o---------------------------------------o---+ / + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + ... ... ... ... ... + ... ... ... ... ... + y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + +----------------------------------------------+ / + +The readable pixel array matrix is composed by +2 invalid lines (I) +4 lines of valid optical black pixels (O) +2 invalid lines (I) +n lines of valid pixel data (P) +2 invalid lines (I) + +And the position of the optical black pixel rectangles is defined by + + PixelArrayOpticalBlackRectangles = { + { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + { x1, y3, 2, y4 - y3 + 1 }, + { x2, y3, 2, y4 - y3 + 1 }, + }; + +If the camera, when capturing the full pixel array matrix, automatically +skips the invalid lines and columns, producing the following data +buffer, when captured to memory + + PixelArraySize.width + /----------------------------------------------/ + x1 + +--------------------------------------------o-+ / + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + ... ... ... ... ... | + ... ... ... ... ... | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + +----------------------------------------------+ / + +then the invalid lines and columns should not be reported as part of the +PixelArraySize property in first place. + +In this case, the position of the black pixel rectangles will be + + PixelArrayOpticalBlackRectangles = { + { 0, 0, y1 + 1, PixelArraySize[0] }, + { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + }; + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::OpticalBlackRectangles) +" + } + PropertyId::PixelArrayActiveAreas => { + "The PixelArrayActiveAreas property defines the (possibly multiple and +overlapping) portions of the camera sensor readable pixel matrix +which are considered valid for image acquisition purposes. + +This property describes an arbitrary number of overlapping rectangles, +with each rectangle representing the maximum image size that the camera +sensor can produce for a particular aspect ratio. They are defined +relatively to the PixelArraySize rectangle. + +When multiple rectangles are reported, they shall be ordered from the +tallest to the shortest. + +Example 1 +A camera sensor which only produces images in the 4:3 image resolution +will report a single PixelArrayActiveAreas rectangle, from which all +other image formats are obtained by either cropping the field-of-view +and/or applying pixel sub-sampling techniques such as pixel skipping or +binning. + + PixelArraySize.width + /----------------/ + x1 x2 + (0,0)-> +-o------------o-+ / + y1 o +------------+ | | + | |////////////| | | + | |////////////| | | PixelArraySize.height + | |////////////| | | + y2 o +------------+ | | + +----------------+ / + +The property reports a single rectangle + + PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + +Example 2 +A camera sensor which can produce images in different native +resolutions will report several overlapping rectangles, one for each +natively supported resolution. + + PixelArraySize.width + /------------------/ + x1 x2 x3 x4 + (0,0)-> +o---o------o---o+ / + y1 o +------+ | | + | |//////| | | + y2 o+---+------+---+| | + ||///|//////|///|| | PixelArraySize.height + y3 o+---+------+---+| | + | |//////| | | + y4 o +------+ | | + +----+------+----+ / + +The property reports two rectangles + + PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + +The first rectangle describes the maximum field-of-view of all image +formats in the 4:3 resolutions, while the second one describes the +maximum field of view for all image formats in the 16:9 resolutions. + +Multiple rectangles shall only be reported when the sensor can't capture +the pixels in the corner regions. If all the pixels in the (x1,y1) - +(x4,y4) area can be captured, the PixelArrayActiveAreas property shall +contains the single rectangle (x1,y1) - (x4,y4). + +\\todo Rename this property to ActiveAreas once we will have property + categories (i.e. Properties::PixelArray::ActiveAreas) +" + } + PropertyId::ScalerCropMaximum => { + "The maximum valid rectangle for the controls::ScalerCrop control. This +reflects the minimum mandatory cropping applied in the camera sensor and +the rest of the pipeline. Just as the ScalerCrop control, it defines a +rectangle taken from the sensor's active pixel array. + +This property is valid only after the camera has been successfully +configured and its value may change whenever a new configuration is +applied. + +\\todo Turn this property into a \"maximum control value\" for the +ScalerCrop control once \"dynamic\" controls have been implemented. +" + } + PropertyId::SensorSensitivity => { + "The relative sensitivity of the chosen sensor mode. + +Some sensors have readout modes with different sensitivities. For example, +a binned camera mode might, with the same exposure and gains, produce +twice the signal level of the full resolution readout. This would be +signalled by the binned mode, when it is chosen, indicating a value here +that is twice that of the full resolution mode. This value will be valid +after the configure method has returned successfully. +" + } + PropertyId::SystemDevices => { + "A list of integer values of type dev_t denoting the major and minor +device numbers of the underlying devices used in the operation of this +camera. + +Different cameras may report identical devices. +" + } + #[cfg(feature = "vendor_draft")] + PropertyId::ColorFilterArrangement => { + "The arrangement of color filters on sensor; represents the colors in the +top-left 2x2 section of the sensor, in reading order. Currently +identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. +" + } + } + } } /// Camera mounting location #[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] diff --git a/libcamera/versioned_files/0.5.2/control_ids_core.yaml b/libcamera/versioned_files/0.5.2/control_ids_core.yaml new file mode 100644 index 0000000..eec4b4f --- /dev/null +++ b/libcamera/versioned_files/0.5.2/control_ids_core.yaml @@ -0,0 +1,1287 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +# Unless otherwise stated, all controls are bi-directional, i.e. they can be +# set through Request::controls() and returned out through Request::metadata(). +vendor: libcamera +controls: + - AeEnable: + type: bool + direction: in + description: | + Enable or disable the AEGC algorithm. When this control is set to true, + both ExposureTimeMode and AnalogueGainMode are set to auto, and if this + control is set to false then both are set to manual. + + If ExposureTimeMode or AnalogueGainMode are also set in the same + request as AeEnable, then the modes supplied by ExposureTimeMode or + AnalogueGainMode will take precedence. + + \sa ExposureTimeMode AnalogueGainMode + + - AeState: + type: int32_t + direction: out + description: | + Report the AEGC algorithm state. + + The AEGC algorithm computes the exposure time and the analogue gain + to be applied to the image sensor. + + The AEGC algorithm behaviour is controlled by the ExposureTimeMode and + AnalogueGainMode controls, which allow applications to decide how + the exposure time and gain are computed, in Auto or Manual mode, + independently from one another. + + The AeState control reports the AEGC algorithm state through a single + value and describes it as a single computation block which computes + both the exposure time and the analogue gain values. + + When both the exposure time and analogue gain values are configured to + be in Manual mode, the AEGC algorithm is quiescent and does not actively + compute any value and the AeState control will report AeStateIdle. + + When at least the exposure time or analogue gain are configured to be + computed by the AEGC algorithm, the AeState control will report if the + algorithm has converged to stable values for all of the controls set + to be computed in Auto mode. + + \sa AnalogueGainMode + \sa ExposureTimeMode + + enum: + - name: AeStateIdle + value: 0 + description: | + The AEGC algorithm is inactive. + + This state is returned when both AnalogueGainMode and + ExposureTimeMode are set to Manual and the algorithm is not + actively computing any value. + - name: AeStateSearching + value: 1 + description: | + The AEGC algorithm is actively computing new values, for either the + exposure time or the analogue gain, but has not converged to a + stable result yet. + + This state is returned if at least one of AnalogueGainMode or + ExposureTimeMode is auto and the algorithm hasn't converged yet. + + The AEGC algorithm converges once stable values are computed for + all of the controls set to be computed in Auto mode. Once the + algorithm converges the state is moved to AeStateConverged. + - name: AeStateConverged + value: 2 + description: | + The AEGC algorithm has converged. + + This state is returned if at least one of AnalogueGainMode or + ExposureTimeMode is Auto, and the AEGC algorithm has converged to a + stable value. + + If the measurements move too far away from the convergence point + then the AEGC algorithm might start adjusting again, in which case + the state is moved to AeStateSearching. + + # AeMeteringMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeMeteringMode: + type: int32_t + direction: inout + description: | + Specify a metering mode for the AE algorithm to use. + + The metering modes determine which parts of the image are used to + determine the scene brightness. Metering modes may be platform specific + and not all metering modes may be supported. + enum: + - name: MeteringCentreWeighted + value: 0 + description: Centre-weighted metering mode. + - name: MeteringSpot + value: 1 + description: Spot metering mode. + - name: MeteringMatrix + value: 2 + description: Matrix metering mode. + - name: MeteringCustom + value: 3 + description: Custom metering mode. + + # AeConstraintMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeConstraintMode: + type: int32_t + direction: inout + description: | + Specify a constraint mode for the AE algorithm to use. + + The constraint modes determine how the measured scene brightness is + adjusted to reach the desired target exposure. Constraint modes may be + platform specific, and not all constraint modes may be supported. + enum: + - name: ConstraintNormal + value: 0 + description: | + Default constraint mode. + + This mode aims to balance the exposure of different parts of the + image so as to reach a reasonable average level. However, highlights + in the image may appear over-exposed and lowlights may appear + under-exposed. + - name: ConstraintHighlight + value: 1 + description: | + Highlight constraint mode. + + This mode adjusts the exposure levels in order to try and avoid + over-exposing the brightest parts (highlights) of an image. + Other non-highlight parts of the image may appear under-exposed. + - name: ConstraintShadows + value: 2 + description: | + Shadows constraint mode. + + This mode adjusts the exposure levels in order to try and avoid + under-exposing the dark parts (shadows) of an image. Other normally + exposed parts of the image may appear over-exposed. + - name: ConstraintCustom + value: 3 + description: | + Custom constraint mode. + + # AeExposureMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeExposureMode: + type: int32_t + direction: inout + description: | + Specify an exposure mode for the AE algorithm to use. + + The exposure modes specify how the desired total exposure is divided + between the exposure time and the sensor's analogue gain. They are + platform specific, and not all exposure modes may be supported. + + When one of AnalogueGainMode or ExposureTimeMode is set to Manual, + the fixed values will override any choices made by AeExposureMode. + + \sa AnalogueGainMode + \sa ExposureTimeMode + + enum: + - name: ExposureNormal + value: 0 + description: Default exposure mode. + - name: ExposureShort + value: 1 + description: Exposure mode allowing only short exposure times. + - name: ExposureLong + value: 2 + description: Exposure mode allowing long exposure times. + - name: ExposureCustom + value: 3 + description: Custom exposure mode. + + - ExposureValue: + type: float + direction: inout + description: | + Specify an Exposure Value (EV) parameter. + + The EV parameter will only be applied if the AE algorithm is currently + enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode + are in Auto mode. + + By convention EV adjusts the exposure as log2. For example + EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment + of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + + \sa AnalogueGainMode + \sa ExposureTimeMode + + - ExposureTime: + type: int32_t + direction: inout + description: | + Exposure time for the frame applied in the sensor device. + + This value is specified in microseconds. + + This control will only take effect if ExposureTimeMode is Manual. If + this control is set when ExposureTimeMode is Auto, the value will be + ignored and will not be retained. + + When reported in metadata, this control indicates what exposure time + was used for the current frame, regardless of ExposureTimeMode. + ExposureTimeMode will indicate the source of the exposure time value, + whether it came from the AE algorithm or not. + + \sa AnalogueGain + \sa ExposureTimeMode + + - ExposureTimeMode: + type: int32_t + direction: inout + description: | + Controls the source of the exposure time that is applied to the image + sensor. + + When set to Auto, the AE algorithm computes the exposure time and + configures the image sensor accordingly. When set to Manual, the value + of the ExposureTime control is used. + + When transitioning from Auto to Manual mode and no ExposureTime control + is provided by the application, the last value computed by the AE + algorithm when the mode was Auto will be used. If the ExposureTimeMode + was never set to Auto (either because the camera started in Manual mode, + or Auto is not supported by the camera), the camera should use a + best-effort default value. + + If ExposureTimeModeManual is supported, the ExposureTime control must + also be supported. + + Cameras that support manual control of the sensor shall support manual + mode for both ExposureTimeMode and AnalogueGainMode, and shall expose + the ExposureTime and AnalogueGain controls. If the camera also has an + AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall + support both manual and auto mode. If auto mode is available, it shall + be the default mode. These rules do not apply to black box cameras + such as UVC cameras, where the available gain and exposure modes are + completely dependent on what the device exposes. + + \par Flickerless exposure mode transitions + + Applications that wish to transition from ExposureTimeModeAuto to direct + control of the exposure time without causing extra flicker can do so by + selecting an ExposureTime value as close as possible to the last value + computed by the auto exposure algorithm in order to avoid any visible + flickering. + + To select the correct value to use as ExposureTime value, applications + should accommodate the natural delay in applying controls caused by the + capture pipeline frame depth. + + When switching to manual exposure mode, applications should not + immediately specify an ExposureTime value in the same request where + ExposureTimeMode is set to Manual. They should instead wait for the + first Request where ExposureTimeMode is reported as + ExposureTimeModeManual in the Request metadata, and use the reported + ExposureTime to populate the control value in the next Request to be + queued to the Camera. + + The implementation of the auto-exposure algorithm should equally try to + minimize flickering and when transitioning from manual exposure mode to + auto exposure use the last value provided by the application as starting + point. + + 1. Start with ExposureTimeMode set to Auto + + 2. Set ExposureTimeMode to Manual + + 3. Wait for the first completed request that has ExposureTimeMode + set to Manual + + 4. Copy the value reported in ExposureTime into a new request, and + submit it + + 5. Proceed to run manual exposure time as desired + + \sa ExposureTime + enum: + - name: ExposureTimeModeAuto + value: 0 + description: | + The exposure time will be calculated automatically and set by the + AE algorithm. + + If ExposureTime is set while this mode is active, it will be + ignored, and its value will not be retained. + + When transitioning from Manual to Auto mode, the AEGC should start + its adjustments based on the last set manual ExposureTime value. + - name: ExposureTimeModeManual + value: 1 + description: | + The exposure time will not be updated by the AE algorithm. + + When transitioning from Auto to Manual mode, the last computed + exposure value is used until a new value is specified through the + ExposureTime control. If an ExposureTime value is specified in the + same request where the ExposureTimeMode is changed from Auto to + Manual, the provided ExposureTime is applied immediately. + + - AnalogueGain: + type: float + direction: inout + description: | + Analogue gain value applied in the sensor device. + + The value of the control specifies the gain multiplier applied to all + colour channels. This value cannot be lower than 1.0. + + This control will only take effect if AnalogueGainMode is Manual. If + this control is set when AnalogueGainMode is Auto, the value will be + ignored and will not be retained. + + When reported in metadata, this control indicates what analogue gain + was used for the current request, regardless of AnalogueGainMode. + AnalogueGainMode will indicate the source of the analogue gain value, + whether it came from the AEGC algorithm or not. + + \sa ExposureTime + \sa AnalogueGainMode + + - AnalogueGainMode: + type: int32_t + direction: inout + description: | + Controls the source of the analogue gain that is applied to the image + sensor. + + When set to Auto, the AEGC algorithm computes the analogue gain and + configures the image sensor accordingly. When set to Manual, the value + of the AnalogueGain control is used. + + When transitioning from Auto to Manual mode and no AnalogueGain control + is provided by the application, the last value computed by the AEGC + algorithm when the mode was Auto will be used. If the AnalogueGainMode + was never set to Auto (either because the camera started in Manual mode, + or Auto is not supported by the camera), the camera should use a + best-effort default value. + + If AnalogueGainModeManual is supported, the AnalogueGain control must + also be supported. + + For cameras where we have control over the ISP, both ExposureTimeMode + and AnalogueGainMode are expected to support manual mode, and both + controls (as well as ExposureTimeMode and AnalogueGain) are expected to + be present. If the camera also has an AEGC implementation, both + ExposureTimeMode and AnalogueGainMode shall support both manual and + auto mode. If auto mode is available, it shall be the default mode. + These rules do not apply to black box cameras such as UVC cameras, + where the available gain and exposure modes are completely dependent on + what the hardware exposes. + + The same procedure described for performing flickerless transitions in + the ExposureTimeMode control documentation can be applied to analogue + gain. + + \sa ExposureTimeMode + \sa AnalogueGain + enum: + - name: AnalogueGainModeAuto + value: 0 + description: | + The analogue gain will be calculated automatically and set by the + AEGC algorithm. + + If AnalogueGain is set while this mode is active, it will be + ignored, and it will also not be retained. + + When transitioning from Manual to Auto mode, the AEGC should start + its adjustments based on the last set manual AnalogueGain value. + - name: AnalogueGainModeManual + value: 1 + description: | + The analogue gain will not be updated by the AEGC algorithm. + + When transitioning from Auto to Manual mode, the last computed + gain value is used until a new value is specified through the + AnalogueGain control. If an AnalogueGain value is specified in the + same request where the AnalogueGainMode is changed from Auto to + Manual, the provided AnalogueGain is applied immediately. + + - AeFlickerMode: + type: int32_t + direction: inout + description: | + Set the flicker avoidance mode for AGC/AEC. + + The flicker mode determines whether, and how, the AGC/AEC algorithm + attempts to hide flicker effects caused by the duty cycle of artificial + lighting. + + Although implementation dependent, many algorithms for "flicker + avoidance" work by restricting this exposure time to integer multiples + of the cycle period, wherever possible. + + Implementations may not support all of the flicker modes listed below. + + By default the system will start in FlickerAuto mode if this is + supported, otherwise the flicker mode will be set to FlickerOff. + + enum: + - name: FlickerOff + value: 0 + description: | + No flicker avoidance is performed. + - name: FlickerManual + value: 1 + description: | + Manual flicker avoidance. + + Suppress flicker effects caused by lighting running with a period + specified by the AeFlickerPeriod control. + \sa AeFlickerPeriod + - name: FlickerAuto + value: 2 + description: | + Automatic flicker period detection and avoidance. + + The system will automatically determine the most likely value of + flicker period, and avoid flicker of this frequency. Once flicker + is being corrected, it is implementation dependent whether the + system is still able to detect a change in the flicker period. + \sa AeFlickerDetected + + - AeFlickerPeriod: + type: int32_t + direction: inout + description: | + Manual flicker period in microseconds. + + This value sets the current flicker period to avoid. It is used when + AeFlickerMode is set to FlickerManual. + + To cancel 50Hz mains flicker, this should be set to 10000 (corresponding + to 100Hz), or 8333 (120Hz) for 60Hz mains. + + Setting the mode to FlickerManual when no AeFlickerPeriod has ever been + set means that no flicker cancellation occurs (until the value of this + control is updated). + + Switching to modes other than FlickerManual has no effect on the + value of the AeFlickerPeriod control. + + \sa AeFlickerMode + + - AeFlickerDetected: + type: int32_t + direction: out + description: | + Flicker period detected in microseconds. + + The value reported here indicates the currently detected flicker + period, or zero if no flicker at all is detected. + + When AeFlickerMode is set to FlickerAuto, there may be a period during + which the value reported here remains zero. Once a non-zero value is + reported, then this is the flicker period that has been detected and is + now being cancelled. + + In the case of 50Hz mains flicker, the value would be 10000 + (corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + + It is implementation dependent whether the system can continue to detect + flicker of different periods when another frequency is already being + cancelled. + + \sa AeFlickerMode + + - Brightness: + type: float + direction: inout + description: | + Specify a fixed brightness parameter. + + Positive values (up to 1.0) produce brighter images; negative values + (up to -1.0) produce darker images and 0.0 leaves pixels unchanged. + + - Contrast: + type: float + direction: inout + description: | + Specify a fixed contrast parameter. + + Normal contrast is given by the value 1.0; larger values produce images + with more contrast. + + - Lux: + type: float + direction: out + description: | + Report an estimate of the current illuminance level in lux. + + The Lux control can only be returned in metadata. + + - AwbEnable: + type: bool + direction: inout + description: | + Enable or disable the AWB. + + When AWB is enabled, the algorithm estimates the colour temperature of + the scene and computes colour gains and the colour correction matrix + automatically. The computed colour temperature, gains and correction + matrix are reported in metadata. The corresponding controls are ignored + if set in a request. + + When AWB is disabled, the colour temperature, gains and correction + matrix are not updated automatically and can be set manually in + requests. + + \sa ColourCorrectionMatrix + \sa ColourGains + \sa ColourTemperature + + # AwbMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AwbMode: + type: int32_t + direction: inout + description: | + Specify the range of illuminants to use for the AWB algorithm. + + The modes supported are platform specific, and not all modes may be + supported. + enum: + - name: AwbAuto + value: 0 + description: Search over the whole colour temperature range. + - name: AwbIncandescent + value: 1 + description: Incandescent AWB lamp mode. + - name: AwbTungsten + value: 2 + description: Tungsten AWB lamp mode. + - name: AwbFluorescent + value: 3 + description: Fluorescent AWB lamp mode. + - name: AwbIndoor + value: 4 + description: Indoor AWB lighting mode. + - name: AwbDaylight + value: 5 + description: Daylight AWB lighting mode. + - name: AwbCloudy + value: 6 + description: Cloudy AWB lighting mode. + - name: AwbCustom + value: 7 + description: Custom AWB mode. + + - AwbLocked: + type: bool + direction: out + description: | + Report the lock status of a running AWB algorithm. + + If the AWB algorithm is locked the value shall be set to true, if it's + converging it shall be set to false. If the AWB algorithm is not + running the control shall not be present in the metadata control list. + + \sa AwbEnable + + - ColourGains: + type: float + direction: inout + description: | + Pair of gain values for the Red and Blue colour channels, in that + order. + + ColourGains can only be applied in a Request when the AWB is disabled. + If ColourGains is set in a request but ColourTemperature is not, the + implementation shall calculate and set the ColourTemperature based on + the ColourGains. + + \sa AwbEnable + \sa ColourTemperature + size: [2] + + - ColourTemperature: + type: int32_t + direction: out + description: | + ColourTemperature of the frame, in kelvin. + + ColourTemperature can only be applied in a Request when the AWB is + disabled. + + If ColourTemperature is set in a request but ColourGains is not, the + implementation shall calculate and set the ColourGains based on the + given ColourTemperature. If ColourTemperature is set (either directly, + or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, + the ColourCorrectionMatrix is updated based on the ColourTemperature. + + The ColourTemperature used to process the frame is reported in metadata. + + \sa AwbEnable + \sa ColourCorrectionMatrix + \sa ColourGains + + - Saturation: + type: float + direction: inout + description: | + Specify a fixed saturation parameter. + + Normal saturation is given by the value 1.0; larger values produce more + saturated colours; 0.0 produces a greyscale image. + + - SensorBlackLevels: + type: int32_t + direction: out + description: | + Reports the sensor black levels used for processing a frame. + + The values are in the order R, Gr, Gb, B. They are returned as numbers + out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The + SensorBlackLevels control can only be returned in metadata. + size: [4] + + - Sharpness: + type: float + direction: inout + description: | + Intensity of the sharpening applied to the image. + + A value of 0.0 means no sharpening. The minimum value means + minimal sharpening, and shall be 0.0 unless the camera can't + disable sharpening completely. The default value shall give a + "reasonable" level of sharpening, suitable for most use cases. + The maximum value may apply extremely high levels of sharpening, + higher than anyone could reasonably want. Negative values are + not allowed. Note also that sharpening is not applied to raw + streams. + + - FocusFoM: + type: int32_t + direction: out + description: | + Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + + A larger FocusFoM value indicates a more in-focus frame. This singular + value may be based on a combination of statistics gathered from + multiple focus regions within an image. The number of focus regions and + method of combination is platform dependent. In this respect, it is not + necessarily aimed at providing a way to implement a focus algorithm by + the application, rather an indication of how in-focus a frame is. + + - ColourCorrectionMatrix: + type: float + direction: inout + description: | + The 3x3 matrix that converts camera RGB to sRGB within the imaging + pipeline. + + This should describe the matrix that is used after pixels have been + white-balanced, but before any gamma transformation. The 3x3 matrix is + stored in conventional reading order in an array of 9 floating point + values. + + ColourCorrectionMatrix can only be applied in a Request when the AWB is + disabled. + + \sa AwbEnable + \sa ColourTemperature + size: [3,3] + + - ScalerCrop: + type: Rectangle + direction: inout + description: | + Sets the image portion that will be scaled to form the whole of + the final output image. + + The (x,y) location of this rectangle is relative to the + PixelArrayActiveAreas that is being used. The units remain native + sensor pixels, even if the sensor is being used in a binning or + skipping mode. + + This control is only present when the pipeline supports scaling. Its + maximum valid value is given by the properties::ScalerCropMaximum + property, and the two can be used to implement digital zoom. + + - DigitalGain: + type: float + direction: inout + description: | + Digital gain value applied during the processing steps applied + to the image as captured from the sensor. + + The global digital gain factor is applied to all the colour channels + of the RAW image. Different pipeline models are free to + specify how the global gain factor applies to each separate + channel. + + If an imaging pipeline applies digital gain in distinct + processing steps, this value indicates their total sum. + Pipelines are free to decide how to adjust each processing + step to respect the received gain factor and shall report + their total value in the request metadata. + + - FrameDuration: + type: int64_t + direction: out + description: | + The instantaneous frame duration from start of frame exposure to start + of next exposure, expressed in microseconds. + + This control is meant to be returned in metadata. + + - FrameDurationLimits: + type: int64_t + direction: inout + description: | + The minimum and maximum (in that order) frame duration, expressed in + microseconds. + + When provided by applications, the control specifies the sensor frame + duration interval the pipeline has to use. This limits the largest + exposure time the sensor can use. For example, if a maximum frame + duration of 33ms is requested (corresponding to 30 frames per second), + the sensor will not be able to raise the exposure time above 33ms. + A fixed frame duration is achieved by setting the minimum and maximum + values to be the same. Setting both values to 0 reverts to using the + camera defaults. + + The maximum frame duration provides the absolute limit to the exposure + time computed by the AE algorithm and it overrides any exposure mode + setting specified with controls::AeExposureMode. Similarly, when a + manual exposure time is set through controls::ExposureTime, it also + gets clipped to the limits set by this control. When reported in + metadata, the control expresses the minimum and maximum frame durations + used after being clipped to the sensor provided frame duration limits. + + \sa AeExposureMode + \sa ExposureTime + + \todo Define how to calculate the capture frame rate by + defining controls to report additional delays introduced by + the capture pipeline or post-processing stages (ie JPEG + conversion, frame scaling). + + \todo Provide an explicit definition of default control values, for + this and all other controls. + + size: [2] + + - SensorTemperature: + type: float + direction: out + description: | + Temperature measure from the camera sensor in Celsius. + + This value is typically obtained by a thermal sensor present on-die or + in the camera module. The range of reported temperatures is device + dependent. + + The SensorTemperature control will only be returned in metadata if a + thermal sensor is present. + + - SensorTimestamp: + type: int64_t + direction: out + description: | + The time when the first row of the image sensor active array is exposed. + + The timestamp, expressed in nanoseconds, represents a monotonically + increasing counter since the system boot time, as defined by the + Linux-specific CLOCK_BOOTTIME clock id. + + The SensorTimestamp control can only be returned in metadata. + + \todo Define how the sensor timestamp has to be used in the reprocessing + use case. + + - AfMode: + type: int32_t + direction: inout + description: | + The mode of the AF (autofocus) algorithm. + + An implementation may choose not to implement all the modes. + + enum: + - name: AfModeManual + value: 0 + description: | + The AF algorithm is in manual mode. + + In this mode it will never perform any action nor move the lens of + its own accord, but an application can specify the desired lens + position using the LensPosition control. The AfState will always + report AfStateIdle. + + If the camera is started in AfModeManual, it will move the focus + lens to the position specified by the LensPosition control. + + This mode is the recommended default value for the AfMode control. + External cameras (as reported by the Location property set to + CameraLocationExternal) may use a different default value. + - name: AfModeAuto + value: 1 + description: | + The AF algorithm is in auto mode. + + In this mode the algorithm will never move the lens or change state + unless the AfTrigger control is used. The AfTrigger control can be + used to initiate a focus scan, the results of which will be + reported by AfState. + + If the autofocus algorithm is moved from AfModeAuto to another mode + while a scan is in progress, the scan is cancelled immediately, + without waiting for the scan to finish. + + When first entering this mode the AfState will report AfStateIdle. + When a trigger control is sent, AfState will report AfStateScanning + for a period before spontaneously changing to AfStateFocused or + AfStateFailed, depending on the outcome of the scan. It will remain + in this state until another scan is initiated by the AfTrigger + control. If a scan is cancelled (without changing to another mode), + AfState will return to AfStateIdle. + - name: AfModeContinuous + value: 2 + description: | + The AF algorithm is in continuous mode. + + In this mode the lens can re-start a scan spontaneously at any + moment, without any user intervention. The AfState still reports + whether the algorithm is currently scanning or not, though the + application has no ability to initiate or cancel scans, nor to move + the lens for itself. + + However, applications can pause the AF algorithm from continuously + scanning by using the AfPause control. This allows video or still + images to be captured whilst guaranteeing that the focus is fixed. + + When set to AfModeContinuous, the system will immediately initiate a + scan so AfState will report AfStateScanning, and will settle on one + of AfStateFocused or AfStateFailed, depending on the scan result. + + - AfRange: + type: int32_t + direction: inout + description: | + The range of focus distances that is scanned. + + An implementation may choose not to implement all the options here. + enum: + - name: AfRangeNormal + value: 0 + description: | + A wide range of focus distances is scanned. + + Scanned distances cover all the way from infinity down to close + distances, though depending on the implementation, possibly not + including the very closest macro positions. + - name: AfRangeMacro + value: 1 + description: | + Only close distances are scanned. + - name: AfRangeFull + value: 2 + description: | + The full range of focus distances is scanned. + + This range is similar to AfRangeNormal but includes the very + closest macro positions. + + - AfSpeed: + type: int32_t + direction: inout + description: | + Determine whether the AF is to move the lens as quickly as possible or + more steadily. + + For example, during video recording it may be desirable not to move the + lens too abruptly, but when in a preview mode (waiting for a still + capture) it may be helpful to move the lens as quickly as is reasonably + possible. + enum: + - name: AfSpeedNormal + value: 0 + description: Move the lens at its usual speed. + - name: AfSpeedFast + value: 1 + description: Move the lens more quickly. + + - AfMetering: + type: int32_t + direction: inout + description: | + The parts of the image used by the AF algorithm to measure focus. + enum: + - name: AfMeteringAuto + value: 0 + description: | + Let the AF algorithm decide for itself where it will measure focus. + - name: AfMeteringWindows + value: 1 + description: | + Use the rectangles defined by the AfWindows control to measure focus. + + If no windows are specified the behaviour is platform dependent. + + - AfWindows: + type: Rectangle + direction: inout + description: | + The focus windows used by the AF algorithm when AfMetering is set to + AfMeteringWindows. + + The units used are pixels within the rectangle returned by the + ScalerCropMaximum property. + + In order to be activated, a rectangle must be programmed with non-zero + width and height. Internally, these rectangles are intersected with the + ScalerCropMaximum rectangle. If the window becomes empty after this + operation, then the window is ignored. If all the windows end up being + ignored, then the behaviour is platform dependent. + + On platforms that support the ScalerCrop control (for implementing + digital zoom, for example), no automatic recalculation or adjustment of + AF windows is performed internally if the ScalerCrop is changed. If any + window lies outside the output image after the scaler crop has been + applied, it is up to the application to recalculate them. + + The details of how the windows are used are platform dependent. We note + that when there is more than one AF window, a typical implementation + might find the optimal focus position for each one and finally select + the window where the focal distance for the objects shown in that part + of the image are closest to the camera. + + size: [n] + + - AfTrigger: + type: int32_t + direction: in + description: | + Start an autofocus scan. + + This control starts an autofocus scan when AfMode is set to AfModeAuto, + and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It + can also be used to terminate a scan early. + + enum: + - name: AfTriggerStart + value: 0 + description: | + Start an AF scan. + + Setting the control to AfTriggerStart is ignored if a scan is in + progress. + - name: AfTriggerCancel + value: 1 + description: | + Cancel an AF scan. + + This does not cause the lens to move anywhere else. Ignored if no + scan is in progress. + + - AfPause: + type: int32_t + direction: in + description: | + Pause lens movements when in continuous autofocus mode. + + This control has no effect except when in continuous autofocus mode + (AfModeContinuous). It can be used to pause any lens movements while + (for example) images are captured. The algorithm remains inactive + until it is instructed to resume. + + enum: + - name: AfPauseImmediate + value: 0 + description: | + Pause the continuous autofocus algorithm immediately. + + The autofocus algorithm is paused whether or not any kind of scan + is underway. AfPauseState will subsequently report + AfPauseStatePaused. AfState may report any of AfStateScanning, + AfStateFocused or AfStateFailed, depending on the algorithm's state + when it received this control. + - name: AfPauseDeferred + value: 1 + description: | + Pause the continuous autofocus algorithm at the end of the scan. + + This is similar to AfPauseImmediate, and if the AfState is + currently reporting AfStateFocused or AfStateFailed it will remain + in that state and AfPauseState will report AfPauseStatePaused. + + However, if the algorithm is scanning (AfStateScanning), + AfPauseState will report AfPauseStatePausing until the scan is + finished, at which point AfState will report one of AfStateFocused + or AfStateFailed, and AfPauseState will change to + AfPauseStatePaused. + + - name: AfPauseResume + value: 2 + description: | + Resume continuous autofocus operation. + + The algorithm starts again from exactly where it left off, and + AfPauseState will report AfPauseStateRunning. + + - LensPosition: + type: float + direction: inout + description: | + Set and report the focus lens position. + + This control instructs the lens to move to a particular position and + also reports back the position of the lens for each frame. + + The LensPosition control is ignored unless the AfMode is set to + AfModeManual, though the value is reported back unconditionally in all + modes. + + This value, which is generally a non-integer, is the reciprocal of the + focal distance in metres, also known as dioptres. That is, to set a + focal distance D, the lens position LP is given by + + \f$LP = \frac{1\mathrm{m}}{D}\f$ + + For example: + + - 0 moves the lens to infinity. + - 0.5 moves the lens to focus on objects 2m away. + - 2 moves the lens to focus on objects 50cm away. + - And larger values will focus the lens closer. + + The default value of the control should indicate a good general + position for the lens, often corresponding to the hyperfocal distance + (the closest position for which objects at infinity are still + acceptably sharp). The minimum will often be zero (meaning infinity), + and the maximum value defines the closest focus position. + + \todo Define a property to report the Hyperfocal distance of calibrated + lenses. + + - AfState: + type: int32_t + direction: out + description: | + The current state of the AF algorithm. + + This control reports the current state of the AF algorithm in + conjunction with the reported AfMode value and (in continuous AF mode) + the AfPauseState value. The possible state changes are described below, + though we note the following state transitions that occur when the + AfMode is changed. + + If the AfMode is set to AfModeManual, then the AfState will always + report AfStateIdle (even if the lens is subsequently moved). Changing + to the AfModeManual state does not initiate any lens movement. + + If the AfMode is set to AfModeAuto then the AfState will report + AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent + together then AfState will omit AfStateIdle and move straight to + AfStateScanning (and start a scan). + + If the AfMode is set to AfModeContinuous then the AfState will + initially report AfStateScanning. + + enum: + - name: AfStateIdle + value: 0 + description: | + The AF algorithm is in manual mode (AfModeManual) or in auto mode + (AfModeAuto) and a scan has not yet been triggered, or an + in-progress scan was cancelled. + - name: AfStateScanning + value: 1 + description: | + The AF algorithm is in auto mode (AfModeAuto), and a scan has been + started using the AfTrigger control. + + The scan can be cancelled by sending AfTriggerCancel at which point + the algorithm will either move back to AfStateIdle or, if the scan + actually completes before the cancel request is processed, to one + of AfStateFocused or AfStateFailed. + + Alternatively the AF algorithm could be in continuous mode + (AfModeContinuous) at which point it may enter this state + spontaneously whenever it determines that a rescan is needed. + - name: AfStateFocused + value: 2 + description: | + The AF algorithm is in auto (AfModeAuto) or continuous + (AfModeContinuous) mode and a scan has completed with the result + that the algorithm believes the image is now in focus. + - name: AfStateFailed + value: 3 + description: | + The AF algorithm is in auto (AfModeAuto) or continuous + (AfModeContinuous) mode and a scan has completed with the result + that the algorithm did not find a good focus position. + + - AfPauseState: + type: int32_t + direction: out + description: | + Report whether the autofocus is currently running, paused or pausing. + + This control is only applicable in continuous (AfModeContinuous) mode, + and reports whether the algorithm is currently running, paused or + pausing (that is, will pause as soon as any in-progress scan + completes). + + Any change to AfMode will cause AfPauseStateRunning to be reported. + + enum: + - name: AfPauseStateRunning + value: 0 + description: | + Continuous AF is running and the algorithm may restart a scan + spontaneously. + - name: AfPauseStatePausing + value: 1 + description: | + Continuous AF has been sent an AfPauseDeferred control, and will + pause as soon as any in-progress scan completes. + + When the scan completes, the AfPauseState control will report + AfPauseStatePaused. No new scans will be start spontaneously until + the AfPauseResume control is sent. + - name: AfPauseStatePaused + value: 2 + description: | + Continuous AF is paused. + + No further state changes or lens movements will occur until the + AfPauseResume control is sent. + + - HdrMode: + type: int32_t + direction: inout + description: | + Set the mode to be used for High Dynamic Range (HDR) imaging. + + HDR techniques typically include multiple exposure, image fusion and + tone mapping techniques to improve the dynamic range of the resulting + images. + + When using an HDR mode, images are captured with different sets of AGC + settings called HDR channels. Channels indicate in particular the type + of exposure (short, medium or long) used to capture the raw image, + before fusion. Each HDR image is tagged with the corresponding channel + using the HdrChannel control. + + \sa HdrChannel + + enum: + - name: HdrModeOff + value: 0 + description: | + HDR is disabled. + + Metadata for this frame will not include the HdrChannel control. + - name: HdrModeMultiExposureUnmerged + value: 1 + description: | + Multiple exposures will be generated in an alternating fashion. + + The multiple exposures will not be merged together and will be + returned to the application as they are. Each image will be tagged + with the correct HDR channel, indicating what kind of exposure it + is. The tag should be the same as in the HdrModeMultiExposure case. + + The expectation is that an application using this mode would merge + the frames to create HDR images for itself if it requires them. + - name: HdrModeMultiExposure + value: 2 + description: | + Multiple exposures will be generated and merged to create HDR + images. + + Each image will be tagged with the HDR channel (long, medium or + short) that arrived and which caused this image to be output. + + Systems that use two channels for HDR will return images tagged + alternately as the short and long channel. Systems that use three + channels for HDR will cycle through the short, medium and long + channel before repeating. + - name: HdrModeSingleExposure + value: 3 + description: | + Multiple frames all at a single exposure will be used to create HDR + images. + + These images should be reported as all corresponding to the HDR + short channel. + - name: HdrModeNight + value: 4 + description: | + Multiple frames will be combined to produce "night mode" images. + + It is up to the implementation exactly which HDR channels it uses, + and the images will all be tagged accordingly with the correct HDR + channel information. + + - HdrChannel: + type: int32_t + direction: out + description: | + The HDR channel used to capture the frame. + + This value is reported back to the application so that it can discover + whether this capture corresponds to the short or long exposure image + (or any other image used by the HDR procedure). An application can + monitor the HDR channel to discover when the differently exposed images + have arrived. + + This metadata is only available when an HDR mode has been enabled. + + \sa HdrMode + + enum: + - name: HdrChannelNone + value: 0 + description: | + This image does not correspond to any of the captures used to create + an HDR image. + - name: HdrChannelShort + value: 1 + description: | + This is a short exposure image. + - name: HdrChannelMedium + value: 2 + description: | + This is a medium exposure image. + - name: HdrChannelLong + value: 3 + description: | + This is a long exposure image. + + - Gamma: + type: float + direction: inout + description: | + Specify a fixed gamma value. + + The default gamma value must be 2.2 which closely mimics sRGB gamma. + Note that this is camera gamma, so it is applied as 1.0/gamma. + + - DebugMetadataEnable: + type: bool + direction: inout + description: | + Enable or disable the debug metadata. + + - FrameWallClock: + type: int64_t + direction: out + description: | + This timestamp corresponds to the same moment in time as the + SensorTimestamp, but is represented as a wall clock time as measured by + the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is + expressed in nanoseconds. + + Being a wall clock measurement, it can be used to synchronise timing + across different devices. + + \sa SensorTimestamp + + The FrameWallClock control can only be returned in metadata. + +... diff --git a/libcamera/versioned_files/0.5.2/control_ids_debug.yaml b/libcamera/versioned_files/0.5.2/control_ids_debug.yaml new file mode 100644 index 0000000..7975327 --- /dev/null +++ b/libcamera/versioned_files/0.5.2/control_ids_debug.yaml @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +%YAML 1.1 +--- +vendor: debug +controls: [] diff --git a/libcamera/versioned_files/0.5.2/control_ids_draft.yaml b/libcamera/versioned_files/0.5.2/control_ids_draft.yaml new file mode 100644 index 0000000..03309ee --- /dev/null +++ b/libcamera/versioned_files/0.5.2/control_ids_draft.yaml @@ -0,0 +1,297 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +# Unless otherwise stated, all controls are bi-directional, i.e. they can be +# set through Request::controls() and returned out through Request::metadata(). +vendor: draft +controls: + - AePrecaptureTrigger: + type: int32_t + direction: inout + description: | + Control for AE metering trigger. Currently identical to + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + + Whether the camera device will trigger a precapture metering sequence + when it processes this request. + enum: + - name: AePrecaptureTriggerIdle + value: 0 + description: The trigger is idle. + - name: AePrecaptureTriggerStart + value: 1 + description: The pre-capture AE metering is started by the camera. + - name: AePrecaptureTriggerCancel + value: 2 + description: | + The camera will cancel any active or completed metering sequence. + The AE algorithm is reset to its initial state. + + - NoiseReductionMode: + type: int32_t + direction: inout + description: | + Control to select the noise reduction algorithm mode. Currently + identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. + enum: + - name: NoiseReductionModeOff + value: 0 + description: No noise reduction is applied + - name: NoiseReductionModeFast + value: 1 + description: | + Noise reduction is applied without reducing the frame rate. + - name: NoiseReductionModeHighQuality + value: 2 + description: | + High quality noise reduction at the expense of frame rate. + - name: NoiseReductionModeMinimal + value: 3 + description: | + Minimal noise reduction is applied without reducing the frame rate. + - name: NoiseReductionModeZSL + value: 4 + description: | + Noise reduction is applied at different levels to different streams. + + - ColorCorrectionAberrationMode: + type: int32_t + direction: inout + description: | + Control to select the color correction aberration mode. Currently + identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. + enum: + - name: ColorCorrectionAberrationOff + value: 0 + description: No aberration correction is applied. + - name: ColorCorrectionAberrationFast + value: 1 + description: Aberration correction will not slow down the frame rate. + - name: ColorCorrectionAberrationHighQuality + value: 2 + description: | + High quality aberration correction which might reduce the frame + rate. + + - AwbState: + type: int32_t + direction: out + description: | + Control to report the current AWB algorithm state. Currently identical + to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. + enum: + - name: AwbStateInactive + value: 0 + description: The AWB algorithm is inactive. + - name: AwbStateSearching + value: 1 + description: The AWB algorithm has not converged yet. + - name: AwbConverged + value: 2 + description: The AWB algorithm has converged. + - name: AwbLocked + value: 3 + description: The AWB algorithm is locked. + + - SensorRollingShutterSkew: + type: int64_t + direction: out + description: | + Control to report the time between the start of exposure of the first + row and the start of exposure of the last row. Currently identical to + ANDROID_SENSOR_ROLLING_SHUTTER_SKEW + + - LensShadingMapMode: + type: int32_t + direction: inout + description: | + Control to report if the lens shading map is available. Currently + identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. + enum: + - name: LensShadingMapModeOff + value: 0 + description: No lens shading map mode is available. + - name: LensShadingMapModeOn + value: 1 + description: The lens shading map mode is available. + + - PipelineDepth: + type: int32_t + direction: out + description: | + Specifies the number of pipeline stages the frame went through from when + it was exposed to when the final completed result was available to the + framework. Always less than or equal to PipelineMaxDepth. Currently + identical to ANDROID_REQUEST_PIPELINE_DEPTH. + + The typical value for this control is 3 as a frame is first exposed, + captured and then processed in a single pass through the ISP. Any + additional processing step performed after the ISP pass (in example face + detection, additional format conversions etc) count as an additional + pipeline stage. + + - MaxLatency: + type: int32_t + direction: out + description: | + The maximum number of frames that can occur after a request (different + than the previous) has been submitted, and before the result's state + becomes synchronized. A value of -1 indicates unknown latency, and 0 + indicates per-frame control. Currently identical to + ANDROID_SYNC_MAX_LATENCY. + + - TestPatternMode: + type: int32_t + direction: inout + description: | + Control to select the test pattern mode. Currently identical to + ANDROID_SENSOR_TEST_PATTERN_MODE. + enum: + - name: TestPatternModeOff + value: 0 + description: | + No test pattern mode is used. The camera device returns frames from + the image sensor. + - name: TestPatternModeSolidColor + value: 1 + description: | + Each pixel in [R, G_even, G_odd, B] is replaced by its respective + color channel provided in test pattern data. + \todo Add control for test pattern data. + - name: TestPatternModeColorBars + value: 2 + description: | + All pixel data is replaced with an 8-bar color pattern. The vertical + bars (left-to-right) are as follows; white, yellow, cyan, green, + magenta, red, blue and black. Each bar should take up 1/8 of the + sensor pixel array width. When this is not possible, the bar size + should be rounded down to the nearest integer and the pattern can + repeat on the right side. Each bar's height must always take up the + full sensor pixel array height. + - name: TestPatternModeColorBarsFadeToGray + value: 3 + description: | + The test pattern is similar to TestPatternModeColorBars, + except that each bar should start at its specified color at the top + and fade to gray at the bottom. Furthermore each bar is further + subdevided into a left and right half. The left half should have a + smooth gradient, and the right half should have a quantized + gradient. In particular, the right half's should consist of blocks + of the same color for 1/16th active sensor pixel array width. The + least significant bits in the quantized gradient should be copied + from the most significant bits of the smooth gradient. The height of + each bar should always be a multiple of 128. When this is not the + case, the pattern should repeat at the bottom of the image. + - name: TestPatternModePn9 + value: 4 + description: | + All pixel data is replaced by a pseudo-random sequence generated + from a PN9 512-bit sequence (typically implemented in hardware with + a linear feedback shift register). The generator should be reset at + the beginning of each frame, and thus each subsequent raw frame with + this test pattern should be exactly the same as the last. + - name: TestPatternModeCustom1 + value: 256 + description: | + The first custom test pattern. All custom patterns that are + available only on this camera device are at least this numeric + value. All of the custom test patterns will be static (that is the + raw image must not vary from frame to frame). + + - FaceDetectMode: + type: int32_t + direction: inout + description: | + Control to select the face detection mode used by the pipeline. + + Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + + \sa FaceDetectFaceRectangles + \sa FaceDetectFaceScores + \sa FaceDetectFaceLandmarks + \sa FaceDetectFaceIds + + enum: + - name: FaceDetectModeOff + value: 0 + description: | + Pipeline doesn't perform face detection and doesn't report any + control related to face detection. + - name: FaceDetectModeSimple + value: 1 + description: | + Pipeline performs face detection and reports the + FaceDetectFaceRectangles and FaceDetectFaceScores controls for each + detected face. FaceDetectFaceLandmarks and FaceDetectFaceIds are + optional. + - name: FaceDetectModeFull + value: 2 + description: | + Pipeline performs face detection and reports all the controls + related to face detection including FaceDetectFaceRectangles, + FaceDetectFaceScores, FaceDetectFaceLandmarks, and + FaceDeteceFaceIds for each detected face. + + - FaceDetectFaceRectangles: + type: Rectangle + direction: out + description: | + Boundary rectangles of the detected faces. The number of values is + the number of detected faces. + + The FaceDetectFaceRectangles control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. + size: [n] + + - FaceDetectFaceScores: + type: uint8_t + direction: out + description: | + Confidence score of each of the detected faces. The range of score is + [0, 100]. The number of values should be the number of faces reported + in FaceDetectFaceRectangles. + + The FaceDetectFaceScores control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_SCORES. + size: [n] + + - FaceDetectFaceLandmarks: + type: Point + direction: out + description: | + Array of human face landmark coordinates in format [..., left_eye_i, + right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The + number of values should be 3 * the number of faces reported in + FaceDetectFaceRectangles. + + The FaceDetectFaceLandmarks control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. + size: [n] + + - FaceDetectFaceIds: + type: int32_t + direction: out + description: | + Each detected face is given a unique ID that is valid for as long as the + face is visible to the camera device. A face that leaves the field of + view and later returns may be assigned a new ID. The number of values + should be the number of faces reported in FaceDetectFaceRectangles. + + The FaceDetectFaceIds control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_IDS. + size: [n] + +... diff --git a/libcamera/versioned_files/0.5.2/control_ids_rpi.yaml b/libcamera/versioned_files/0.5.2/control_ids_rpi.yaml new file mode 100644 index 0000000..a861511 --- /dev/null +++ b/libcamera/versioned_files/0.5.2/control_ids_rpi.yaml @@ -0,0 +1,186 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2023, Raspberry Pi Ltd +# +%YAML 1.1 +--- +# Raspberry Pi (VC4 and PiSP) specific vendor controls +vendor: rpi +controls: + - StatsOutputEnable: + type: bool + direction: inout + description: | + Toggles the Raspberry Pi IPA to output the hardware generated statistics. + + When this control is set to true, the IPA outputs a binary dump of the + hardware generated statistics through the Request metadata in the + Bcm2835StatsOutput control. + + \sa Bcm2835StatsOutput + + - Bcm2835StatsOutput: + type: uint8_t + size: [n] + direction: out + description: | + Span of the BCM2835 ISP generated statistics for the current frame. + + This is sent in the Request metadata if the StatsOutputEnable is set to + true. The statistics struct definition can be found in + include/linux/bcm2835-isp.h. + + \sa StatsOutputEnable + + - ScalerCrops: + type: Rectangle + size: [n] + direction: out + description: | + An array of rectangles, where each singular value has identical + functionality to the ScalerCrop control. This control allows the + Raspberry Pi pipeline handler to control individual scaler crops per + output stream. + + The order of rectangles passed into the control must match the order of + streams configured by the application. The pipeline handler will only + configure crop retangles up-to the number of output streams configured. + All subsequent rectangles passed into this control are ignored by the + pipeline handler. + + If both rpi::ScalerCrops and ScalerCrop controls are present in a + ControlList, the latter is discarded, and crops are obtained from this + control. + + Note that using different crop rectangles for each output stream with + this control is only applicable on the Pi5/PiSP platform. This control + should also be considered temporary/draft and will be replaced with + official libcamera API support for per-stream controls in the future. + + \sa ScalerCrop + + - PispStatsOutput: + type: uint8_t + direction: out + size: [n] + description: | + Span of the PiSP Frontend ISP generated statistics for the current + frame. This is sent in the Request metadata if the StatsOutputEnable is + set to true. The statistics struct definition can be found in + https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + + \sa StatsOutputEnable + + - SyncMode: + type: int32_t + direction: in + description: | + Enable or disable camera synchronisation ("sync") mode. + + When sync mode is enabled, a camera will synchronise frames temporally + with other cameras, either attached to the same device or a different + one. There should be one "server" device, which broadcasts timing + information to one or more "clients". Communication is one-way, from + server to clients only, and it is only clients that adjust their frame + timings to match the server. + + Sync mode requires all cameras to be running at (as far as possible) the + same fixed framerate. Clients may continue to make adjustments to keep + their cameras synchronised with the server for the duration of the + session, though any updates after the initial ones should remain small. + + \sa SyncReady + \sa SyncTimer + \sa SyncFrames + + enum: + - name: SyncModeOff + value: 0 + description: Disable sync mode. + - name: SyncModeServer + value: 1 + description: | + Enable sync mode, act as server. The server broadcasts timing + messages to any clients that are listening, so that the clients can + synchronise their camera frames with the server's. + - name: SyncModeClient + value: 2 + description: | + Enable sync mode, act as client. A client listens for any server + messages, and arranges for its camera frames to synchronise as + closely as possible with the server's. Many clients can listen out + for the same server. Clients can also be started ahead of any + servers, causing them merely to wait for the server to start. + + - SyncReady: + type: bool + direction: out + description: | + When using the camera synchronisation algorithm, the server broadcasts + timing information to the clients. This also includes the time (some + number of frames in the future, called the "ready time") at which the + server will signal its controlling application, using this control, to + start using the image frames. + + The client receives the "ready time" from the server, and will signal + its application to start using the frames at this same moment. + + While this control value is false, applications (on both client and + server) should continue to wait, and not use the frames. + + Once this value becomes true, it means that this is the first frame + where the server and its clients have agreed that they will both be + synchronised and that applications should begin consuming frames. + Thereafter, this control will continue to signal the value true for + the rest of the session. + + \sa SyncMode + \sa SyncTimer + \sa SyncFrames + + - SyncTimer: + type: int64_t + direction: out + description: | + This reports the amount of time, in microseconds, until the "ready + time", at which the server and client will signal their controlling + applications that the frames are now synchronised and should be + used. The value may be refined slightly over time, becoming more precise + as the "ready time" approaches. + + Servers always report this value, whereas clients will omit this control + until they have received a message from the server that enables them to + calculate it. + + Normally the value will start positive (the "ready time" is in the + future), and decrease towards zero, before becoming negative (the "ready + time" has elapsed). So there should be just one frame where the timer + value is, or is very close to, zero - the one for which the SyncReady + control becomes true. At this moment, the value indicates how closely + synchronised the client believes it is with the server. + + But note that if frames are being dropped, then the "near zero" valued + frame, or indeed any other, could be skipped. In these cases the timer + value allows an application to deduce that this has happened. + + \sa SyncMode + \sa SyncReady + \sa SyncFrames + + - SyncFrames: + type: int32_t + direction: in + description: | + The number of frames the server should wait, after enabling + SyncModeServer, before signalling (via the SyncReady control) that + frames should be used. This therefore determines the "ready time" for + all synchronised cameras. + + This control value should be set only for the device that is to act as + the server, before or at the same moment at which SyncModeServer is + enabled. + + \sa SyncMode + \sa SyncReady + \sa SyncTimer +... diff --git a/libcamera/versioned_files/0.5.2/controls.rs b/libcamera/versioned_files/0.5.2/controls.rs new file mode 100644 index 0000000..11cd268 --- /dev/null +++ b/libcamera/versioned_files/0.5.2/controls.rs @@ -0,0 +1,5013 @@ +use std::ops::{Deref, DerefMut}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +#[allow(unused_imports)] +use crate::control::{Control, Property, ControlEntry, DynControlEntry}; +use crate::control_value::{ControlValue, ControlValueError}; +#[allow(unused_imports)] +use crate::geometry::{Rectangle, Point, Size}; +#[allow(unused_imports)] +use libcamera_sys::*; +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(u32)] +pub enum ControlId { + /// Enable or disable the AEGC algorithm. When this control is set to true, + /// both ExposureTimeMode and AnalogueGainMode are set to auto, and if this + /// control is set to false then both are set to manual. + /// + /// If ExposureTimeMode or AnalogueGainMode are also set in the same + /// request as AeEnable, then the modes supplied by ExposureTimeMode or + /// AnalogueGainMode will take precedence. + /// + /// \sa ExposureTimeMode AnalogueGainMode + AeEnable = AE_ENABLE, + /// Report the AEGC algorithm state. + /// + /// The AEGC algorithm computes the exposure time and the analogue gain + /// to be applied to the image sensor. + /// + /// The AEGC algorithm behaviour is controlled by the ExposureTimeMode and + /// AnalogueGainMode controls, which allow applications to decide how + /// the exposure time and gain are computed, in Auto or Manual mode, + /// independently from one another. + /// + /// The AeState control reports the AEGC algorithm state through a single + /// value and describes it as a single computation block which computes + /// both the exposure time and the analogue gain values. + /// + /// When both the exposure time and analogue gain values are configured to + /// be in Manual mode, the AEGC algorithm is quiescent and does not actively + /// compute any value and the AeState control will report AeStateIdle. + /// + /// When at least the exposure time or analogue gain are configured to be + /// computed by the AEGC algorithm, the AeState control will report if the + /// algorithm has converged to stable values for all of the controls set + /// to be computed in Auto mode. + /// + /// \sa AnalogueGainMode + /// \sa ExposureTimeMode + AeState = AE_STATE, + /// Specify a metering mode for the AE algorithm to use. + /// + /// The metering modes determine which parts of the image are used to + /// determine the scene brightness. Metering modes may be platform specific + /// and not all metering modes may be supported. + AeMeteringMode = AE_METERING_MODE, + /// Specify a constraint mode for the AE algorithm to use. + /// + /// The constraint modes determine how the measured scene brightness is + /// adjusted to reach the desired target exposure. Constraint modes may be + /// platform specific, and not all constraint modes may be supported. + AeConstraintMode = AE_CONSTRAINT_MODE, + /// Specify an exposure mode for the AE algorithm to use. + /// + /// The exposure modes specify how the desired total exposure is divided + /// between the exposure time and the sensor's analogue gain. They are + /// platform specific, and not all exposure modes may be supported. + /// + /// When one of AnalogueGainMode or ExposureTimeMode is set to Manual, + /// the fixed values will override any choices made by AeExposureMode. + /// + /// \sa AnalogueGainMode + /// \sa ExposureTimeMode + AeExposureMode = AE_EXPOSURE_MODE, + /// Specify an Exposure Value (EV) parameter. + /// + /// The EV parameter will only be applied if the AE algorithm is currently + /// enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode + /// are in Auto mode. + /// + /// By convention EV adjusts the exposure as log2. For example + /// EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment + /// of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + /// + /// \sa AnalogueGainMode + /// \sa ExposureTimeMode + ExposureValue = EXPOSURE_VALUE, + /// Exposure time for the frame applied in the sensor device. + /// + /// This value is specified in microseconds. + /// + /// This control will only take effect if ExposureTimeMode is Manual. If + /// this control is set when ExposureTimeMode is Auto, the value will be + /// ignored and will not be retained. + /// + /// When reported in metadata, this control indicates what exposure time + /// was used for the current frame, regardless of ExposureTimeMode. + /// ExposureTimeMode will indicate the source of the exposure time value, + /// whether it came from the AE algorithm or not. + /// + /// \sa AnalogueGain + /// \sa ExposureTimeMode + ExposureTime = EXPOSURE_TIME, + /// Controls the source of the exposure time that is applied to the image + /// sensor. + /// + /// When set to Auto, the AE algorithm computes the exposure time and + /// configures the image sensor accordingly. When set to Manual, the value + /// of the ExposureTime control is used. + /// + /// When transitioning from Auto to Manual mode and no ExposureTime control + /// is provided by the application, the last value computed by the AE + /// algorithm when the mode was Auto will be used. If the ExposureTimeMode + /// was never set to Auto (either because the camera started in Manual mode, + /// or Auto is not supported by the camera), the camera should use a + /// best-effort default value. + /// + /// If ExposureTimeModeManual is supported, the ExposureTime control must + /// also be supported. + /// + /// Cameras that support manual control of the sensor shall support manual + /// mode for both ExposureTimeMode and AnalogueGainMode, and shall expose + /// the ExposureTime and AnalogueGain controls. If the camera also has an + /// AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall + /// support both manual and auto mode. If auto mode is available, it shall + /// be the default mode. These rules do not apply to black box cameras + /// such as UVC cameras, where the available gain and exposure modes are + /// completely dependent on what the device exposes. + /// + /// \par Flickerless exposure mode transitions + /// + /// Applications that wish to transition from ExposureTimeModeAuto to direct + /// control of the exposure time without causing extra flicker can do so by + /// selecting an ExposureTime value as close as possible to the last value + /// computed by the auto exposure algorithm in order to avoid any visible + /// flickering. + /// + /// To select the correct value to use as ExposureTime value, applications + /// should accommodate the natural delay in applying controls caused by the + /// capture pipeline frame depth. + /// + /// When switching to manual exposure mode, applications should not + /// immediately specify an ExposureTime value in the same request where + /// ExposureTimeMode is set to Manual. They should instead wait for the + /// first Request where ExposureTimeMode is reported as + /// ExposureTimeModeManual in the Request metadata, and use the reported + /// ExposureTime to populate the control value in the next Request to be + /// queued to the Camera. + /// + /// The implementation of the auto-exposure algorithm should equally try to + /// minimize flickering and when transitioning from manual exposure mode to + /// auto exposure use the last value provided by the application as starting + /// point. + /// + /// 1. Start with ExposureTimeMode set to Auto + /// + /// 2. Set ExposureTimeMode to Manual + /// + /// 3. Wait for the first completed request that has ExposureTimeMode + /// set to Manual + /// + /// 4. Copy the value reported in ExposureTime into a new request, and + /// submit it + /// + /// 5. Proceed to run manual exposure time as desired + /// + /// \sa ExposureTime + ExposureTimeMode = EXPOSURE_TIME_MODE, + /// Analogue gain value applied in the sensor device. + /// + /// The value of the control specifies the gain multiplier applied to all + /// colour channels. This value cannot be lower than 1.0. + /// + /// This control will only take effect if AnalogueGainMode is Manual. If + /// this control is set when AnalogueGainMode is Auto, the value will be + /// ignored and will not be retained. + /// + /// When reported in metadata, this control indicates what analogue gain + /// was used for the current request, regardless of AnalogueGainMode. + /// AnalogueGainMode will indicate the source of the analogue gain value, + /// whether it came from the AEGC algorithm or not. + /// + /// \sa ExposureTime + /// \sa AnalogueGainMode + AnalogueGain = ANALOGUE_GAIN, + /// Controls the source of the analogue gain that is applied to the image + /// sensor. + /// + /// When set to Auto, the AEGC algorithm computes the analogue gain and + /// configures the image sensor accordingly. When set to Manual, the value + /// of the AnalogueGain control is used. + /// + /// When transitioning from Auto to Manual mode and no AnalogueGain control + /// is provided by the application, the last value computed by the AEGC + /// algorithm when the mode was Auto will be used. If the AnalogueGainMode + /// was never set to Auto (either because the camera started in Manual mode, + /// or Auto is not supported by the camera), the camera should use a + /// best-effort default value. + /// + /// If AnalogueGainModeManual is supported, the AnalogueGain control must + /// also be supported. + /// + /// For cameras where we have control over the ISP, both ExposureTimeMode + /// and AnalogueGainMode are expected to support manual mode, and both + /// controls (as well as ExposureTimeMode and AnalogueGain) are expected to + /// be present. If the camera also has an AEGC implementation, both + /// ExposureTimeMode and AnalogueGainMode shall support both manual and + /// auto mode. If auto mode is available, it shall be the default mode. + /// These rules do not apply to black box cameras such as UVC cameras, + /// where the available gain and exposure modes are completely dependent on + /// what the hardware exposes. + /// + /// The same procedure described for performing flickerless transitions in + /// the ExposureTimeMode control documentation can be applied to analogue + /// gain. + /// + /// \sa ExposureTimeMode + /// \sa AnalogueGain + AnalogueGainMode = ANALOGUE_GAIN_MODE, + /// Set the flicker avoidance mode for AGC/AEC. + /// + /// The flicker mode determines whether, and how, the AGC/AEC algorithm + /// attempts to hide flicker effects caused by the duty cycle of artificial + /// lighting. + /// + /// Although implementation dependent, many algorithms for "flicker + /// avoidance" work by restricting this exposure time to integer multiples + /// of the cycle period, wherever possible. + /// + /// Implementations may not support all of the flicker modes listed below. + /// + /// By default the system will start in FlickerAuto mode if this is + /// supported, otherwise the flicker mode will be set to FlickerOff. + AeFlickerMode = AE_FLICKER_MODE, + /// Manual flicker period in microseconds. + /// + /// This value sets the current flicker period to avoid. It is used when + /// AeFlickerMode is set to FlickerManual. + /// + /// To cancel 50Hz mains flicker, this should be set to 10000 (corresponding + /// to 100Hz), or 8333 (120Hz) for 60Hz mains. + /// + /// Setting the mode to FlickerManual when no AeFlickerPeriod has ever been + /// set means that no flicker cancellation occurs (until the value of this + /// control is updated). + /// + /// Switching to modes other than FlickerManual has no effect on the + /// value of the AeFlickerPeriod control. + /// + /// \sa AeFlickerMode + AeFlickerPeriod = AE_FLICKER_PERIOD, + /// Flicker period detected in microseconds. + /// + /// The value reported here indicates the currently detected flicker + /// period, or zero if no flicker at all is detected. + /// + /// When AeFlickerMode is set to FlickerAuto, there may be a period during + /// which the value reported here remains zero. Once a non-zero value is + /// reported, then this is the flicker period that has been detected and is + /// now being cancelled. + /// + /// In the case of 50Hz mains flicker, the value would be 10000 + /// (corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + /// + /// It is implementation dependent whether the system can continue to detect + /// flicker of different periods when another frequency is already being + /// cancelled. + /// + /// \sa AeFlickerMode + AeFlickerDetected = AE_FLICKER_DETECTED, + /// Specify a fixed brightness parameter. + /// + /// Positive values (up to 1.0) produce brighter images; negative values + /// (up to -1.0) produce darker images and 0.0 leaves pixels unchanged. + Brightness = BRIGHTNESS, + /// Specify a fixed contrast parameter. + /// + /// Normal contrast is given by the value 1.0; larger values produce images + /// with more contrast. + Contrast = CONTRAST, + /// Report an estimate of the current illuminance level in lux. + /// + /// The Lux control can only be returned in metadata. + Lux = LUX, + /// Enable or disable the AWB. + /// + /// When AWB is enabled, the algorithm estimates the colour temperature of + /// the scene and computes colour gains and the colour correction matrix + /// automatically. The computed colour temperature, gains and correction + /// matrix are reported in metadata. The corresponding controls are ignored + /// if set in a request. + /// + /// When AWB is disabled, the colour temperature, gains and correction + /// matrix are not updated automatically and can be set manually in + /// requests. + /// + /// \sa ColourCorrectionMatrix + /// \sa ColourGains + /// \sa ColourTemperature + AwbEnable = AWB_ENABLE, + /// Specify the range of illuminants to use for the AWB algorithm. + /// + /// The modes supported are platform specific, and not all modes may be + /// supported. + AwbMode = AWB_MODE, + /// Report the lock status of a running AWB algorithm. + /// + /// If the AWB algorithm is locked the value shall be set to true, if it's + /// converging it shall be set to false. If the AWB algorithm is not + /// running the control shall not be present in the metadata control list. + /// + /// \sa AwbEnable + AwbLocked = AWB_LOCKED, + /// Pair of gain values for the Red and Blue colour channels, in that + /// order. + /// + /// ColourGains can only be applied in a Request when the AWB is disabled. + /// If ColourGains is set in a request but ColourTemperature is not, the + /// implementation shall calculate and set the ColourTemperature based on + /// the ColourGains. + /// + /// \sa AwbEnable + /// \sa ColourTemperature + ColourGains = COLOUR_GAINS, + /// ColourTemperature of the frame, in kelvin. + /// + /// ColourTemperature can only be applied in a Request when the AWB is + /// disabled. + /// + /// If ColourTemperature is set in a request but ColourGains is not, the + /// implementation shall calculate and set the ColourGains based on the + /// given ColourTemperature. If ColourTemperature is set (either directly, + /// or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, + /// the ColourCorrectionMatrix is updated based on the ColourTemperature. + /// + /// The ColourTemperature used to process the frame is reported in metadata. + /// + /// \sa AwbEnable + /// \sa ColourCorrectionMatrix + /// \sa ColourGains + ColourTemperature = COLOUR_TEMPERATURE, + /// Specify a fixed saturation parameter. + /// + /// Normal saturation is given by the value 1.0; larger values produce more + /// saturated colours; 0.0 produces a greyscale image. + Saturation = SATURATION, + /// Reports the sensor black levels used for processing a frame. + /// + /// The values are in the order R, Gr, Gb, B. They are returned as numbers + /// out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The + /// SensorBlackLevels control can only be returned in metadata. + SensorBlackLevels = SENSOR_BLACK_LEVELS, + /// Intensity of the sharpening applied to the image. + /// + /// A value of 0.0 means no sharpening. The minimum value means + /// minimal sharpening, and shall be 0.0 unless the camera can't + /// disable sharpening completely. The default value shall give a + /// "reasonable" level of sharpening, suitable for most use cases. + /// The maximum value may apply extremely high levels of sharpening, + /// higher than anyone could reasonably want. Negative values are + /// not allowed. Note also that sharpening is not applied to raw + /// streams. + Sharpness = SHARPNESS, + /// Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + /// + /// A larger FocusFoM value indicates a more in-focus frame. This singular + /// value may be based on a combination of statistics gathered from + /// multiple focus regions within an image. The number of focus regions and + /// method of combination is platform dependent. In this respect, it is not + /// necessarily aimed at providing a way to implement a focus algorithm by + /// the application, rather an indication of how in-focus a frame is. + FocusFoM = FOCUS_FO_M, + /// The 3x3 matrix that converts camera RGB to sRGB within the imaging + /// pipeline. + /// + /// This should describe the matrix that is used after pixels have been + /// white-balanced, but before any gamma transformation. The 3x3 matrix is + /// stored in conventional reading order in an array of 9 floating point + /// values. + /// + /// ColourCorrectionMatrix can only be applied in a Request when the AWB is + /// disabled. + /// + /// \sa AwbEnable + /// \sa ColourTemperature + ColourCorrectionMatrix = COLOUR_CORRECTION_MATRIX, + /// Sets the image portion that will be scaled to form the whole of + /// the final output image. + /// + /// The (x,y) location of this rectangle is relative to the + /// PixelArrayActiveAreas that is being used. The units remain native + /// sensor pixels, even if the sensor is being used in a binning or + /// skipping mode. + /// + /// This control is only present when the pipeline supports scaling. Its + /// maximum valid value is given by the properties::ScalerCropMaximum + /// property, and the two can be used to implement digital zoom. + ScalerCrop = SCALER_CROP, + /// Digital gain value applied during the processing steps applied + /// to the image as captured from the sensor. + /// + /// The global digital gain factor is applied to all the colour channels + /// of the RAW image. Different pipeline models are free to + /// specify how the global gain factor applies to each separate + /// channel. + /// + /// If an imaging pipeline applies digital gain in distinct + /// processing steps, this value indicates their total sum. + /// Pipelines are free to decide how to adjust each processing + /// step to respect the received gain factor and shall report + /// their total value in the request metadata. + DigitalGain = DIGITAL_GAIN, + /// The instantaneous frame duration from start of frame exposure to start + /// of next exposure, expressed in microseconds. + /// + /// This control is meant to be returned in metadata. + FrameDuration = FRAME_DURATION, + /// The minimum and maximum (in that order) frame duration, expressed in + /// microseconds. + /// + /// When provided by applications, the control specifies the sensor frame + /// duration interval the pipeline has to use. This limits the largest + /// exposure time the sensor can use. For example, if a maximum frame + /// duration of 33ms is requested (corresponding to 30 frames per second), + /// the sensor will not be able to raise the exposure time above 33ms. + /// A fixed frame duration is achieved by setting the minimum and maximum + /// values to be the same. Setting both values to 0 reverts to using the + /// camera defaults. + /// + /// The maximum frame duration provides the absolute limit to the exposure + /// time computed by the AE algorithm and it overrides any exposure mode + /// setting specified with controls::AeExposureMode. Similarly, when a + /// manual exposure time is set through controls::ExposureTime, it also + /// gets clipped to the limits set by this control. When reported in + /// metadata, the control expresses the minimum and maximum frame durations + /// used after being clipped to the sensor provided frame duration limits. + /// + /// \sa AeExposureMode + /// \sa ExposureTime + /// + /// \todo Define how to calculate the capture frame rate by + /// defining controls to report additional delays introduced by + /// the capture pipeline or post-processing stages (ie JPEG + /// conversion, frame scaling). + /// + /// \todo Provide an explicit definition of default control values, for + /// this and all other controls. + FrameDurationLimits = FRAME_DURATION_LIMITS, + /// Temperature measure from the camera sensor in Celsius. + /// + /// This value is typically obtained by a thermal sensor present on-die or + /// in the camera module. The range of reported temperatures is device + /// dependent. + /// + /// The SensorTemperature control will only be returned in metadata if a + /// thermal sensor is present. + SensorTemperature = SENSOR_TEMPERATURE, + /// The time when the first row of the image sensor active array is exposed. + /// + /// The timestamp, expressed in nanoseconds, represents a monotonically + /// increasing counter since the system boot time, as defined by the + /// Linux-specific CLOCK_BOOTTIME clock id. + /// + /// The SensorTimestamp control can only be returned in metadata. + /// + /// \todo Define how the sensor timestamp has to be used in the reprocessing + /// use case. + SensorTimestamp = SENSOR_TIMESTAMP, + /// The mode of the AF (autofocus) algorithm. + /// + /// An implementation may choose not to implement all the modes. + AfMode = AF_MODE, + /// The range of focus distances that is scanned. + /// + /// An implementation may choose not to implement all the options here. + AfRange = AF_RANGE, + /// Determine whether the AF is to move the lens as quickly as possible or + /// more steadily. + /// + /// For example, during video recording it may be desirable not to move the + /// lens too abruptly, but when in a preview mode (waiting for a still + /// capture) it may be helpful to move the lens as quickly as is reasonably + /// possible. + AfSpeed = AF_SPEED, + /// The parts of the image used by the AF algorithm to measure focus. + AfMetering = AF_METERING, + /// The focus windows used by the AF algorithm when AfMetering is set to + /// AfMeteringWindows. + /// + /// The units used are pixels within the rectangle returned by the + /// ScalerCropMaximum property. + /// + /// In order to be activated, a rectangle must be programmed with non-zero + /// width and height. Internally, these rectangles are intersected with the + /// ScalerCropMaximum rectangle. If the window becomes empty after this + /// operation, then the window is ignored. If all the windows end up being + /// ignored, then the behaviour is platform dependent. + /// + /// On platforms that support the ScalerCrop control (for implementing + /// digital zoom, for example), no automatic recalculation or adjustment of + /// AF windows is performed internally if the ScalerCrop is changed. If any + /// window lies outside the output image after the scaler crop has been + /// applied, it is up to the application to recalculate them. + /// + /// The details of how the windows are used are platform dependent. We note + /// that when there is more than one AF window, a typical implementation + /// might find the optimal focus position for each one and finally select + /// the window where the focal distance for the objects shown in that part + /// of the image are closest to the camera. + AfWindows = AF_WINDOWS, + /// Start an autofocus scan. + /// + /// This control starts an autofocus scan when AfMode is set to AfModeAuto, + /// and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It + /// can also be used to terminate a scan early. + AfTrigger = AF_TRIGGER, + /// Pause lens movements when in continuous autofocus mode. + /// + /// This control has no effect except when in continuous autofocus mode + /// (AfModeContinuous). It can be used to pause any lens movements while + /// (for example) images are captured. The algorithm remains inactive + /// until it is instructed to resume. + AfPause = AF_PAUSE, + /// Set and report the focus lens position. + /// + /// This control instructs the lens to move to a particular position and + /// also reports back the position of the lens for each frame. + /// + /// The LensPosition control is ignored unless the AfMode is set to + /// AfModeManual, though the value is reported back unconditionally in all + /// modes. + /// + /// This value, which is generally a non-integer, is the reciprocal of the + /// focal distance in metres, also known as dioptres. That is, to set a + /// focal distance D, the lens position LP is given by + /// + /// \f$LP = \frac{1\mathrm{m}}{D}\f$ + /// + /// For example: + /// + /// - 0 moves the lens to infinity. + /// - 0.5 moves the lens to focus on objects 2m away. + /// - 2 moves the lens to focus on objects 50cm away. + /// - And larger values will focus the lens closer. + /// + /// The default value of the control should indicate a good general + /// position for the lens, often corresponding to the hyperfocal distance + /// (the closest position for which objects at infinity are still + /// acceptably sharp). The minimum will often be zero (meaning infinity), + /// and the maximum value defines the closest focus position. + /// + /// \todo Define a property to report the Hyperfocal distance of calibrated + /// lenses. + LensPosition = LENS_POSITION, + /// The current state of the AF algorithm. + /// + /// This control reports the current state of the AF algorithm in + /// conjunction with the reported AfMode value and (in continuous AF mode) + /// the AfPauseState value. The possible state changes are described below, + /// though we note the following state transitions that occur when the + /// AfMode is changed. + /// + /// If the AfMode is set to AfModeManual, then the AfState will always + /// report AfStateIdle (even if the lens is subsequently moved). Changing + /// to the AfModeManual state does not initiate any lens movement. + /// + /// If the AfMode is set to AfModeAuto then the AfState will report + /// AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent + /// together then AfState will omit AfStateIdle and move straight to + /// AfStateScanning (and start a scan). + /// + /// If the AfMode is set to AfModeContinuous then the AfState will + /// initially report AfStateScanning. + AfState = AF_STATE, + /// Report whether the autofocus is currently running, paused or pausing. + /// + /// This control is only applicable in continuous (AfModeContinuous) mode, + /// and reports whether the algorithm is currently running, paused or + /// pausing (that is, will pause as soon as any in-progress scan + /// completes). + /// + /// Any change to AfMode will cause AfPauseStateRunning to be reported. + AfPauseState = AF_PAUSE_STATE, + /// Set the mode to be used for High Dynamic Range (HDR) imaging. + /// + /// HDR techniques typically include multiple exposure, image fusion and + /// tone mapping techniques to improve the dynamic range of the resulting + /// images. + /// + /// When using an HDR mode, images are captured with different sets of AGC + /// settings called HDR channels. Channels indicate in particular the type + /// of exposure (short, medium or long) used to capture the raw image, + /// before fusion. Each HDR image is tagged with the corresponding channel + /// using the HdrChannel control. + /// + /// \sa HdrChannel + HdrMode = HDR_MODE, + /// The HDR channel used to capture the frame. + /// + /// This value is reported back to the application so that it can discover + /// whether this capture corresponds to the short or long exposure image + /// (or any other image used by the HDR procedure). An application can + /// monitor the HDR channel to discover when the differently exposed images + /// have arrived. + /// + /// This metadata is only available when an HDR mode has been enabled. + /// + /// \sa HdrMode + HdrChannel = HDR_CHANNEL, + /// Specify a fixed gamma value. + /// + /// The default gamma value must be 2.2 which closely mimics sRGB gamma. + /// Note that this is camera gamma, so it is applied as 1.0/gamma. + Gamma = GAMMA, + /// Enable or disable the debug metadata. + DebugMetadataEnable = DEBUG_METADATA_ENABLE, + /// This timestamp corresponds to the same moment in time as the + /// SensorTimestamp, but is represented as a wall clock time as measured by + /// the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is + /// expressed in nanoseconds. + /// + /// Being a wall clock measurement, it can be used to synchronise timing + /// across different devices. + /// + /// \sa SensorTimestamp + /// + /// The FrameWallClock control can only be returned in metadata. + FrameWallClock = FRAME_WALL_CLOCK, + /// Control for AE metering trigger. Currently identical to + /// ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + /// + /// Whether the camera device will trigger a precapture metering sequence + /// when it processes this request. + #[cfg(feature = "vendor_draft")] + AePrecaptureTrigger = AE_PRECAPTURE_TRIGGER, + /// Control to select the noise reduction algorithm mode. Currently + /// identical to ANDROID_NOISE_REDUCTION_MODE. + /// + /// Mode of operation for the noise reduction algorithm. + #[cfg(feature = "vendor_draft")] + NoiseReductionMode = NOISE_REDUCTION_MODE, + /// Control to select the color correction aberration mode. Currently + /// identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + /// + /// Mode of operation for the chromatic aberration correction algorithm. + #[cfg(feature = "vendor_draft")] + ColorCorrectionAberrationMode = COLOR_CORRECTION_ABERRATION_MODE, + /// Control to report the current AWB algorithm state. Currently identical + /// to ANDROID_CONTROL_AWB_STATE. + /// + /// Current state of the AWB algorithm. + #[cfg(feature = "vendor_draft")] + AwbState = AWB_STATE, + /// Control to report the time between the start of exposure of the first + /// row and the start of exposure of the last row. Currently identical to + /// ANDROID_SENSOR_ROLLING_SHUTTER_SKEW + #[cfg(feature = "vendor_draft")] + SensorRollingShutterSkew = SENSOR_ROLLING_SHUTTER_SKEW, + /// Control to report if the lens shading map is available. Currently + /// identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. + #[cfg(feature = "vendor_draft")] + LensShadingMapMode = LENS_SHADING_MAP_MODE, + /// Specifies the number of pipeline stages the frame went through from when + /// it was exposed to when the final completed result was available to the + /// framework. Always less than or equal to PipelineMaxDepth. Currently + /// identical to ANDROID_REQUEST_PIPELINE_DEPTH. + /// + /// The typical value for this control is 3 as a frame is first exposed, + /// captured and then processed in a single pass through the ISP. Any + /// additional processing step performed after the ISP pass (in example face + /// detection, additional format conversions etc) count as an additional + /// pipeline stage. + #[cfg(feature = "vendor_draft")] + PipelineDepth = PIPELINE_DEPTH, + /// The maximum number of frames that can occur after a request (different + /// than the previous) has been submitted, and before the result's state + /// becomes synchronized. A value of -1 indicates unknown latency, and 0 + /// indicates per-frame control. Currently identical to + /// ANDROID_SYNC_MAX_LATENCY. + #[cfg(feature = "vendor_draft")] + MaxLatency = MAX_LATENCY, + /// Control to select the test pattern mode. Currently identical to + /// ANDROID_SENSOR_TEST_PATTERN_MODE. + #[cfg(feature = "vendor_draft")] + TestPatternMode = TEST_PATTERN_MODE, + /// Control to select the face detection mode used by the pipeline. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + /// + /// \sa FaceDetectFaceRectangles + /// \sa FaceDetectFaceScores + /// \sa FaceDetectFaceLandmarks + /// \sa FaceDetectFaceIds + #[cfg(feature = "vendor_draft")] + FaceDetectMode = FACE_DETECT_MODE, + /// Boundary rectangles of the detected faces. The number of values is + /// the number of detected faces. + /// + /// The FaceDetectFaceRectangles control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceRectangles = FACE_DETECT_FACE_RECTANGLES, + /// Confidence score of each of the detected faces. The range of score is + /// [0, 100]. The number of values should be the number of faces reported + /// in FaceDetectFaceRectangles. + /// + /// The FaceDetectFaceScores control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_SCORES. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceScores = FACE_DETECT_FACE_SCORES, + /// Array of human face landmark coordinates in format [..., left_eye_i, + /// right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The + /// number of values should be 3 * the number of faces reported in + /// FaceDetectFaceRectangles. + /// + /// The FaceDetectFaceLandmarks control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceLandmarks = FACE_DETECT_FACE_LANDMARKS, + /// Each detected face is given a unique ID that is valid for as long as the + /// face is visible to the camera device. A face that leaves the field of + /// view and later returns may be assigned a new ID. The number of values + /// should be the number of faces reported in FaceDetectFaceRectangles. + /// + /// The FaceDetectFaceIds control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_IDS. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceIds = FACE_DETECT_FACE_IDS, + /// Toggles the Raspberry Pi IPA to output the hardware generated statistics. + /// + /// When this control is set to true, the IPA outputs a binary dump of the + /// hardware generated statistics through the Request metadata in the + /// Bcm2835StatsOutput control. + /// + /// \sa Bcm2835StatsOutput + #[cfg(feature = "vendor_rpi")] + StatsOutputEnable = STATS_OUTPUT_ENABLE, + /// Span of the BCM2835 ISP generated statistics for the current frame. + /// + /// This is sent in the Request metadata if the StatsOutputEnable is set to + /// true. The statistics struct definition can be found in + /// include/linux/bcm2835-isp.h. + /// + /// \sa StatsOutputEnable + #[cfg(feature = "vendor_rpi")] + Bcm2835StatsOutput = BCM2835_STATS_OUTPUT, + /// An array of rectangles, where each singular value has identical + /// functionality to the ScalerCrop control. This control allows the + /// Raspberry Pi pipeline handler to control individual scaler crops per + /// output stream. + /// + /// The order of rectangles passed into the control must match the order of + /// streams configured by the application. The pipeline handler will only + /// configure crop retangles up-to the number of output streams configured. + /// All subsequent rectangles passed into this control are ignored by the + /// pipeline handler. + /// + /// If both rpi::ScalerCrops and ScalerCrop controls are present in a + /// ControlList, the latter is discarded, and crops are obtained from this + /// control. + /// + /// Note that using different crop rectangles for each output stream with + /// this control is only applicable on the Pi5/PiSP platform. This control + /// should also be considered temporary/draft and will be replaced with + /// official libcamera API support for per-stream controls in the future. + /// + /// \sa ScalerCrop + #[cfg(feature = "vendor_rpi")] + ScalerCrops = SCALER_CROPS, + /// Span of the PiSP Frontend ISP generated statistics for the current + /// frame. This is sent in the Request metadata if the StatsOutputEnable is + /// set to true. The statistics struct definition can be found in + /// https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + /// + /// \sa StatsOutputEnable + #[cfg(feature = "vendor_rpi")] + PispStatsOutput = PISP_STATS_OUTPUT, + /// Enable or disable camera synchronisation ("sync") mode. + /// + /// When sync mode is enabled, a camera will synchronise frames temporally + /// with other cameras, either attached to the same device or a different + /// one. There should be one "server" device, which broadcasts timing + /// information to one or more "clients". Communication is one-way, from + /// server to clients only, and it is only clients that adjust their frame + /// timings to match the server. + /// + /// Sync mode requires all cameras to be running at (as far as possible) the + /// same fixed framerate. Clients may continue to make adjustments to keep + /// their cameras synchronised with the server for the duration of the + /// session, though any updates after the initial ones should remain small. + /// + /// \sa SyncReady + /// \sa SyncTimer + /// \sa SyncFrames + #[cfg(feature = "vendor_rpi")] + SyncMode = SYNC_MODE, + /// When using the camera synchronisation algorithm, the server broadcasts + /// timing information to the clients. This also includes the time (some + /// number of frames in the future, called the "ready time") at which the + /// server will signal its controlling application, using this control, to + /// start using the image frames. + /// + /// The client receives the "ready time" from the server, and will signal + /// its application to start using the frames at this same moment. + /// + /// While this control value is false, applications (on both client and + /// server) should continue to wait, and not use the frames. + /// + /// Once this value becomes true, it means that this is the first frame + /// where the server and its clients have agreed that they will both be + /// synchronised and that applications should begin consuming frames. + /// Thereafter, this control will continue to signal the value true for + /// the rest of the session. + /// + /// \sa SyncMode + /// \sa SyncTimer + /// \sa SyncFrames + #[cfg(feature = "vendor_rpi")] + SyncReady = SYNC_READY, + /// This reports the amount of time, in microseconds, until the "ready + /// time", at which the server and client will signal their controlling + /// applications that the frames are now synchronised and should be + /// used. The value may be refined slightly over time, becoming more precise + /// as the "ready time" approaches. + /// + /// Servers always report this value, whereas clients will omit this control + /// until they have received a message from the server that enables them to + /// calculate it. + /// + /// Normally the value will start positive (the "ready time" is in the + /// future), and decrease towards zero, before becoming negative (the "ready + /// time" has elapsed). So there should be just one frame where the timer + /// value is, or is very close to, zero - the one for which the SyncReady + /// control becomes true. At this moment, the value indicates how closely + /// synchronised the client believes it is with the server. + /// + /// But note that if frames are being dropped, then the "near zero" valued + /// frame, or indeed any other, could be skipped. In these cases the timer + /// value allows an application to deduce that this has happened. + /// + /// \sa SyncMode + /// \sa SyncReady + /// \sa SyncFrames + #[cfg(feature = "vendor_rpi")] + SyncTimer = SYNC_TIMER, + /// The number of frames the server should wait, after enabling + /// SyncModeServer, before signalling (via the SyncReady control) that + /// frames should be used. This therefore determines the "ready time" for + /// all synchronised cameras. + /// + /// This control value should be set only for the device that is to act as + /// the server, before or at the same moment at which SyncModeServer is + /// enabled. + /// + /// \sa SyncMode + /// \sa SyncReady + /// \sa SyncTimer + #[cfg(feature = "vendor_rpi")] + SyncFrames = SYNC_FRAMES, +} +impl ControlId { + pub fn id(&self) -> u32 { + u32::from(*self) + } + pub fn description(&self) -> &'static str { + match self { + ControlId::AeEnable => { + "Enable or disable the AEGC algorithm. When this control is set to true, +both ExposureTimeMode and AnalogueGainMode are set to auto, and if this +control is set to false then both are set to manual. + +If ExposureTimeMode or AnalogueGainMode are also set in the same +request as AeEnable, then the modes supplied by ExposureTimeMode or +AnalogueGainMode will take precedence. + +\\sa ExposureTimeMode AnalogueGainMode +" + } + ControlId::AeState => { + "Report the AEGC algorithm state. + +The AEGC algorithm computes the exposure time and the analogue gain +to be applied to the image sensor. + +The AEGC algorithm behaviour is controlled by the ExposureTimeMode and +AnalogueGainMode controls, which allow applications to decide how +the exposure time and gain are computed, in Auto or Manual mode, +independently from one another. + +The AeState control reports the AEGC algorithm state through a single +value and describes it as a single computation block which computes +both the exposure time and the analogue gain values. + +When both the exposure time and analogue gain values are configured to +be in Manual mode, the AEGC algorithm is quiescent and does not actively +compute any value and the AeState control will report AeStateIdle. + +When at least the exposure time or analogue gain are configured to be +computed by the AEGC algorithm, the AeState control will report if the +algorithm has converged to stable values for all of the controls set +to be computed in Auto mode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::AeMeteringMode => { + "Specify a metering mode for the AE algorithm to use. + +The metering modes determine which parts of the image are used to +determine the scene brightness. Metering modes may be platform specific +and not all metering modes may be supported. +" + } + ControlId::AeConstraintMode => { + "Specify a constraint mode for the AE algorithm to use. + +The constraint modes determine how the measured scene brightness is +adjusted to reach the desired target exposure. Constraint modes may be +platform specific, and not all constraint modes may be supported. +" + } + ControlId::AeExposureMode => { + "Specify an exposure mode for the AE algorithm to use. + +The exposure modes specify how the desired total exposure is divided +between the exposure time and the sensor's analogue gain. They are +platform specific, and not all exposure modes may be supported. + +When one of AnalogueGainMode or ExposureTimeMode is set to Manual, +the fixed values will override any choices made by AeExposureMode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureValue => { + "Specify an Exposure Value (EV) parameter. + +The EV parameter will only be applied if the AE algorithm is currently +enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode +are in Auto mode. + +By convention EV adjusts the exposure as log2. For example +EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment +of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureTime => { + "Exposure time for the frame applied in the sensor device. + +This value is specified in microseconds. + +This control will only take effect if ExposureTimeMode is Manual. If +this control is set when ExposureTimeMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what exposure time +was used for the current frame, regardless of ExposureTimeMode. +ExposureTimeMode will indicate the source of the exposure time value, +whether it came from the AE algorithm or not. + +\\sa AnalogueGain +\\sa ExposureTimeMode +" + } + ControlId::ExposureTimeMode => { + "Controls the source of the exposure time that is applied to the image +sensor. + +When set to Auto, the AE algorithm computes the exposure time and +configures the image sensor accordingly. When set to Manual, the value +of the ExposureTime control is used. + +When transitioning from Auto to Manual mode and no ExposureTime control +is provided by the application, the last value computed by the AE +algorithm when the mode was Auto will be used. If the ExposureTimeMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If ExposureTimeModeManual is supported, the ExposureTime control must +also be supported. + +Cameras that support manual control of the sensor shall support manual +mode for both ExposureTimeMode and AnalogueGainMode, and shall expose +the ExposureTime and AnalogueGain controls. If the camera also has an +AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall +support both manual and auto mode. If auto mode is available, it shall +be the default mode. These rules do not apply to black box cameras +such as UVC cameras, where the available gain and exposure modes are +completely dependent on what the device exposes. + +\\par Flickerless exposure mode transitions + +Applications that wish to transition from ExposureTimeModeAuto to direct +control of the exposure time without causing extra flicker can do so by +selecting an ExposureTime value as close as possible to the last value +computed by the auto exposure algorithm in order to avoid any visible +flickering. + +To select the correct value to use as ExposureTime value, applications +should accommodate the natural delay in applying controls caused by the +capture pipeline frame depth. + +When switching to manual exposure mode, applications should not +immediately specify an ExposureTime value in the same request where +ExposureTimeMode is set to Manual. They should instead wait for the +first Request where ExposureTimeMode is reported as +ExposureTimeModeManual in the Request metadata, and use the reported +ExposureTime to populate the control value in the next Request to be +queued to the Camera. + +The implementation of the auto-exposure algorithm should equally try to +minimize flickering and when transitioning from manual exposure mode to +auto exposure use the last value provided by the application as starting +point. + +1. Start with ExposureTimeMode set to Auto + +2. Set ExposureTimeMode to Manual + +3. Wait for the first completed request that has ExposureTimeMode +set to Manual + +4. Copy the value reported in ExposureTime into a new request, and +submit it + +5. Proceed to run manual exposure time as desired + +\\sa ExposureTime +" + } + ControlId::AnalogueGain => { + "Analogue gain value applied in the sensor device. + +The value of the control specifies the gain multiplier applied to all +colour channels. This value cannot be lower than 1.0. + +This control will only take effect if AnalogueGainMode is Manual. If +this control is set when AnalogueGainMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what analogue gain +was used for the current request, regardless of AnalogueGainMode. +AnalogueGainMode will indicate the source of the analogue gain value, +whether it came from the AEGC algorithm or not. + +\\sa ExposureTime +\\sa AnalogueGainMode +" + } + ControlId::AnalogueGainMode => { + "Controls the source of the analogue gain that is applied to the image +sensor. + +When set to Auto, the AEGC algorithm computes the analogue gain and +configures the image sensor accordingly. When set to Manual, the value +of the AnalogueGain control is used. + +When transitioning from Auto to Manual mode and no AnalogueGain control +is provided by the application, the last value computed by the AEGC +algorithm when the mode was Auto will be used. If the AnalogueGainMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If AnalogueGainModeManual is supported, the AnalogueGain control must +also be supported. + +For cameras where we have control over the ISP, both ExposureTimeMode +and AnalogueGainMode are expected to support manual mode, and both +controls (as well as ExposureTimeMode and AnalogueGain) are expected to +be present. If the camera also has an AEGC implementation, both +ExposureTimeMode and AnalogueGainMode shall support both manual and +auto mode. If auto mode is available, it shall be the default mode. +These rules do not apply to black box cameras such as UVC cameras, +where the available gain and exposure modes are completely dependent on +what the hardware exposes. + +The same procedure described for performing flickerless transitions in +the ExposureTimeMode control documentation can be applied to analogue +gain. + +\\sa ExposureTimeMode +\\sa AnalogueGain +" + } + ControlId::AeFlickerMode => { + "Set the flicker avoidance mode for AGC/AEC. + +The flicker mode determines whether, and how, the AGC/AEC algorithm +attempts to hide flicker effects caused by the duty cycle of artificial +lighting. + +Although implementation dependent, many algorithms for \"flicker +avoidance\" work by restricting this exposure time to integer multiples +of the cycle period, wherever possible. + +Implementations may not support all of the flicker modes listed below. + +By default the system will start in FlickerAuto mode if this is +supported, otherwise the flicker mode will be set to FlickerOff. +" + } + ControlId::AeFlickerPeriod => { + "Manual flicker period in microseconds. + +This value sets the current flicker period to avoid. It is used when +AeFlickerMode is set to FlickerManual. + +To cancel 50Hz mains flicker, this should be set to 10000 (corresponding +to 100Hz), or 8333 (120Hz) for 60Hz mains. + +Setting the mode to FlickerManual when no AeFlickerPeriod has ever been +set means that no flicker cancellation occurs (until the value of this +control is updated). + +Switching to modes other than FlickerManual has no effect on the +value of the AeFlickerPeriod control. + +\\sa AeFlickerMode +" + } + ControlId::AeFlickerDetected => { + "Flicker period detected in microseconds. + +The value reported here indicates the currently detected flicker +period, or zero if no flicker at all is detected. + +When AeFlickerMode is set to FlickerAuto, there may be a period during +which the value reported here remains zero. Once a non-zero value is +reported, then this is the flicker period that has been detected and is +now being cancelled. + +In the case of 50Hz mains flicker, the value would be 10000 +(corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + +It is implementation dependent whether the system can continue to detect +flicker of different periods when another frequency is already being +cancelled. + +\\sa AeFlickerMode +" + } + ControlId::Brightness => { + "Specify a fixed brightness parameter. + +Positive values (up to 1.0) produce brighter images; negative values +(up to -1.0) produce darker images and 0.0 leaves pixels unchanged. +" + } + ControlId::Contrast => { + "Specify a fixed contrast parameter. + +Normal contrast is given by the value 1.0; larger values produce images +with more contrast. +" + } + ControlId::Lux => { + "Report an estimate of the current illuminance level in lux. + +The Lux control can only be returned in metadata. +" + } + ControlId::AwbEnable => { + "Enable or disable the AWB. + +When AWB is enabled, the algorithm estimates the colour temperature of +the scene and computes colour gains and the colour correction matrix +automatically. The computed colour temperature, gains and correction +matrix are reported in metadata. The corresponding controls are ignored +if set in a request. + +When AWB is disabled, the colour temperature, gains and correction +matrix are not updated automatically and can be set manually in +requests. + +\\sa ColourCorrectionMatrix +\\sa ColourGains +\\sa ColourTemperature +" + } + ControlId::AwbMode => { + "Specify the range of illuminants to use for the AWB algorithm. + +The modes supported are platform specific, and not all modes may be +supported. +" + } + ControlId::AwbLocked => { + "Report the lock status of a running AWB algorithm. + +If the AWB algorithm is locked the value shall be set to true, if it's +converging it shall be set to false. If the AWB algorithm is not +running the control shall not be present in the metadata control list. + +\\sa AwbEnable +" + } + ControlId::ColourGains => { + "Pair of gain values for the Red and Blue colour channels, in that +order. + +ColourGains can only be applied in a Request when the AWB is disabled. +If ColourGains is set in a request but ColourTemperature is not, the +implementation shall calculate and set the ColourTemperature based on +the ColourGains. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ColourTemperature => { + "ColourTemperature of the frame, in kelvin. + +ColourTemperature can only be applied in a Request when the AWB is +disabled. + +If ColourTemperature is set in a request but ColourGains is not, the +implementation shall calculate and set the ColourGains based on the +given ColourTemperature. If ColourTemperature is set (either directly, +or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, +the ColourCorrectionMatrix is updated based on the ColourTemperature. + +The ColourTemperature used to process the frame is reported in metadata. + +\\sa AwbEnable +\\sa ColourCorrectionMatrix +\\sa ColourGains +" + } + ControlId::Saturation => { + "Specify a fixed saturation parameter. + +Normal saturation is given by the value 1.0; larger values produce more +saturated colours; 0.0 produces a greyscale image. +" + } + ControlId::SensorBlackLevels => { + "Reports the sensor black levels used for processing a frame. + +The values are in the order R, Gr, Gb, B. They are returned as numbers +out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The +SensorBlackLevels control can only be returned in metadata. +" + } + ControlId::Sharpness => { + "Intensity of the sharpening applied to the image. + +A value of 0.0 means no sharpening. The minimum value means +minimal sharpening, and shall be 0.0 unless the camera can't +disable sharpening completely. The default value shall give a +\"reasonable\" level of sharpening, suitable for most use cases. +The maximum value may apply extremely high levels of sharpening, +higher than anyone could reasonably want. Negative values are +not allowed. Note also that sharpening is not applied to raw +streams. +" + } + ControlId::FocusFoM => { + "Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + +A larger FocusFoM value indicates a more in-focus frame. This singular +value may be based on a combination of statistics gathered from +multiple focus regions within an image. The number of focus regions and +method of combination is platform dependent. In this respect, it is not +necessarily aimed at providing a way to implement a focus algorithm by +the application, rather an indication of how in-focus a frame is. +" + } + ControlId::ColourCorrectionMatrix => { + "The 3x3 matrix that converts camera RGB to sRGB within the imaging +pipeline. + +This should describe the matrix that is used after pixels have been +white-balanced, but before any gamma transformation. The 3x3 matrix is +stored in conventional reading order in an array of 9 floating point +values. + +ColourCorrectionMatrix can only be applied in a Request when the AWB is +disabled. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ScalerCrop => { + "Sets the image portion that will be scaled to form the whole of +the final output image. + +The (x,y) location of this rectangle is relative to the +PixelArrayActiveAreas that is being used. The units remain native +sensor pixels, even if the sensor is being used in a binning or +skipping mode. + +This control is only present when the pipeline supports scaling. Its +maximum valid value is given by the properties::ScalerCropMaximum +property, and the two can be used to implement digital zoom. +" + } + ControlId::DigitalGain => { + "Digital gain value applied during the processing steps applied +to the image as captured from the sensor. + +The global digital gain factor is applied to all the colour channels +of the RAW image. Different pipeline models are free to +specify how the global gain factor applies to each separate +channel. + +If an imaging pipeline applies digital gain in distinct +processing steps, this value indicates their total sum. +Pipelines are free to decide how to adjust each processing +step to respect the received gain factor and shall report +their total value in the request metadata. +" + } + ControlId::FrameDuration => { + "The instantaneous frame duration from start of frame exposure to start +of next exposure, expressed in microseconds. + +This control is meant to be returned in metadata. +" + } + ControlId::FrameDurationLimits => { + "The minimum and maximum (in that order) frame duration, expressed in +microseconds. + +When provided by applications, the control specifies the sensor frame +duration interval the pipeline has to use. This limits the largest +exposure time the sensor can use. For example, if a maximum frame +duration of 33ms is requested (corresponding to 30 frames per second), +the sensor will not be able to raise the exposure time above 33ms. +A fixed frame duration is achieved by setting the minimum and maximum +values to be the same. Setting both values to 0 reverts to using the +camera defaults. + +The maximum frame duration provides the absolute limit to the exposure +time computed by the AE algorithm and it overrides any exposure mode +setting specified with controls::AeExposureMode. Similarly, when a +manual exposure time is set through controls::ExposureTime, it also +gets clipped to the limits set by this control. When reported in +metadata, the control expresses the minimum and maximum frame durations +used after being clipped to the sensor provided frame duration limits. + +\\sa AeExposureMode +\\sa ExposureTime + +\\todo Define how to calculate the capture frame rate by +defining controls to report additional delays introduced by +the capture pipeline or post-processing stages (ie JPEG +conversion, frame scaling). + +\\todo Provide an explicit definition of default control values, for +this and all other controls. +" + } + ControlId::SensorTemperature => { + "Temperature measure from the camera sensor in Celsius. + +This value is typically obtained by a thermal sensor present on-die or +in the camera module. The range of reported temperatures is device +dependent. + +The SensorTemperature control will only be returned in metadata if a +thermal sensor is present. +" + } + ControlId::SensorTimestamp => { + "The time when the first row of the image sensor active array is exposed. + +The timestamp, expressed in nanoseconds, represents a monotonically +increasing counter since the system boot time, as defined by the +Linux-specific CLOCK_BOOTTIME clock id. + +The SensorTimestamp control can only be returned in metadata. + +\\todo Define how the sensor timestamp has to be used in the reprocessing +use case. +" + } + ControlId::AfMode => { + "The mode of the AF (autofocus) algorithm. + +An implementation may choose not to implement all the modes. +" + } + ControlId::AfRange => { + "The range of focus distances that is scanned. + +An implementation may choose not to implement all the options here. +" + } + ControlId::AfSpeed => { + "Determine whether the AF is to move the lens as quickly as possible or +more steadily. + +For example, during video recording it may be desirable not to move the +lens too abruptly, but when in a preview mode (waiting for a still +capture) it may be helpful to move the lens as quickly as is reasonably +possible. +" + } + ControlId::AfMetering => { + "The parts of the image used by the AF algorithm to measure focus. +" + } + ControlId::AfWindows => { + "The focus windows used by the AF algorithm when AfMetering is set to +AfMeteringWindows. + +The units used are pixels within the rectangle returned by the +ScalerCropMaximum property. + +In order to be activated, a rectangle must be programmed with non-zero +width and height. Internally, these rectangles are intersected with the +ScalerCropMaximum rectangle. If the window becomes empty after this +operation, then the window is ignored. If all the windows end up being +ignored, then the behaviour is platform dependent. + +On platforms that support the ScalerCrop control (for implementing +digital zoom, for example), no automatic recalculation or adjustment of +AF windows is performed internally if the ScalerCrop is changed. If any +window lies outside the output image after the scaler crop has been +applied, it is up to the application to recalculate them. + +The details of how the windows are used are platform dependent. We note +that when there is more than one AF window, a typical implementation +might find the optimal focus position for each one and finally select +the window where the focal distance for the objects shown in that part +of the image are closest to the camera. +" + } + ControlId::AfTrigger => { + "Start an autofocus scan. + +This control starts an autofocus scan when AfMode is set to AfModeAuto, +and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It +can also be used to terminate a scan early. +" + } + ControlId::AfPause => { + "Pause lens movements when in continuous autofocus mode. + +This control has no effect except when in continuous autofocus mode +(AfModeContinuous). It can be used to pause any lens movements while +(for example) images are captured. The algorithm remains inactive +until it is instructed to resume. +" + } + ControlId::LensPosition => { + "Set and report the focus lens position. + +This control instructs the lens to move to a particular position and +also reports back the position of the lens for each frame. + +The LensPosition control is ignored unless the AfMode is set to +AfModeManual, though the value is reported back unconditionally in all +modes. + +This value, which is generally a non-integer, is the reciprocal of the +focal distance in metres, also known as dioptres. That is, to set a +focal distance D, the lens position LP is given by + +\\f$LP = \\frac{1\\mathrm{m}}{D}\\f$ + +For example: + +- 0 moves the lens to infinity. +- 0.5 moves the lens to focus on objects 2m away. +- 2 moves the lens to focus on objects 50cm away. +- And larger values will focus the lens closer. + +The default value of the control should indicate a good general +position for the lens, often corresponding to the hyperfocal distance +(the closest position for which objects at infinity are still +acceptably sharp). The minimum will often be zero (meaning infinity), +and the maximum value defines the closest focus position. + +\\todo Define a property to report the Hyperfocal distance of calibrated +lenses. +" + } + ControlId::AfState => { + "The current state of the AF algorithm. + +This control reports the current state of the AF algorithm in +conjunction with the reported AfMode value and (in continuous AF mode) +the AfPauseState value. The possible state changes are described below, +though we note the following state transitions that occur when the +AfMode is changed. + +If the AfMode is set to AfModeManual, then the AfState will always +report AfStateIdle (even if the lens is subsequently moved). Changing +to the AfModeManual state does not initiate any lens movement. + +If the AfMode is set to AfModeAuto then the AfState will report +AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent +together then AfState will omit AfStateIdle and move straight to +AfStateScanning (and start a scan). + +If the AfMode is set to AfModeContinuous then the AfState will +initially report AfStateScanning. +" + } + ControlId::AfPauseState => { + "Report whether the autofocus is currently running, paused or pausing. + +This control is only applicable in continuous (AfModeContinuous) mode, +and reports whether the algorithm is currently running, paused or +pausing (that is, will pause as soon as any in-progress scan +completes). + +Any change to AfMode will cause AfPauseStateRunning to be reported. +" + } + ControlId::HdrMode => { + "Set the mode to be used for High Dynamic Range (HDR) imaging. + +HDR techniques typically include multiple exposure, image fusion and +tone mapping techniques to improve the dynamic range of the resulting +images. + +When using an HDR mode, images are captured with different sets of AGC +settings called HDR channels. Channels indicate in particular the type +of exposure (short, medium or long) used to capture the raw image, +before fusion. Each HDR image is tagged with the corresponding channel +using the HdrChannel control. + +\\sa HdrChannel +" + } + ControlId::HdrChannel => { + "The HDR channel used to capture the frame. + +This value is reported back to the application so that it can discover +whether this capture corresponds to the short or long exposure image +(or any other image used by the HDR procedure). An application can +monitor the HDR channel to discover when the differently exposed images +have arrived. + +This metadata is only available when an HDR mode has been enabled. + +\\sa HdrMode +" + } + ControlId::Gamma => { + "Specify a fixed gamma value. + +The default gamma value must be 2.2 which closely mimics sRGB gamma. +Note that this is camera gamma, so it is applied as 1.0/gamma. +" + } + ControlId::DebugMetadataEnable => "Enable or disable the debug metadata. +", + ControlId::FrameWallClock => { + "This timestamp corresponds to the same moment in time as the +SensorTimestamp, but is represented as a wall clock time as measured by +the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is +expressed in nanoseconds. + +Being a wall clock measurement, it can be used to synchronise timing +across different devices. + +\\sa SensorTimestamp + +The FrameWallClock control can only be returned in metadata. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AePrecaptureTrigger => { + "Control for AE metering trigger. Currently identical to +ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + +Whether the camera device will trigger a precapture metering sequence +when it processes this request. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::NoiseReductionMode => { + "Control to select the noise reduction algorithm mode. Currently +identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::ColorCorrectionAberrationMode => { + "Control to select the color correction aberration mode. Currently +identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AwbState => { + "Control to report the current AWB algorithm state. Currently identical +to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::SensorRollingShutterSkew => { + "Control to report the time between the start of exposure of the first +row and the start of exposure of the last row. Currently identical to +ANDROID_SENSOR_ROLLING_SHUTTER_SKEW +" + } + #[cfg(feature = "vendor_draft")] + ControlId::LensShadingMapMode => { + "Control to report if the lens shading map is available. Currently +identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::PipelineDepth => { + "Specifies the number of pipeline stages the frame went through from when +it was exposed to when the final completed result was available to the +framework. Always less than or equal to PipelineMaxDepth. Currently +identical to ANDROID_REQUEST_PIPELINE_DEPTH. + +The typical value for this control is 3 as a frame is first exposed, +captured and then processed in a single pass through the ISP. Any +additional processing step performed after the ISP pass (in example face +detection, additional format conversions etc) count as an additional +pipeline stage. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::MaxLatency => { + "The maximum number of frames that can occur after a request (different +than the previous) has been submitted, and before the result's state +becomes synchronized. A value of -1 indicates unknown latency, and 0 +indicates per-frame control. Currently identical to +ANDROID_SYNC_MAX_LATENCY. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::TestPatternMode => { + "Control to select the test pattern mode. Currently identical to +ANDROID_SENSOR_TEST_PATTERN_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectMode => { + "Control to select the face detection mode used by the pipeline. + +Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + +\\sa FaceDetectFaceRectangles +\\sa FaceDetectFaceScores +\\sa FaceDetectFaceLandmarks +\\sa FaceDetectFaceIds +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceRectangles => { + "Boundary rectangles of the detected faces. The number of values is +the number of detected faces. + +The FaceDetectFaceRectangles control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceScores => { + "Confidence score of each of the detected faces. The range of score is +[0, 100]. The number of values should be the number of faces reported +in FaceDetectFaceRectangles. + +The FaceDetectFaceScores control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_SCORES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceLandmarks => { + "Array of human face landmark coordinates in format [..., left_eye_i, +right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The +number of values should be 3 * the number of faces reported in +FaceDetectFaceRectangles. + +The FaceDetectFaceLandmarks control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceIds => { + "Each detected face is given a unique ID that is valid for as long as the +face is visible to the camera device. A face that leaves the field of +view and later returns may be assigned a new ID. The number of values +should be the number of faces reported in FaceDetectFaceRectangles. + +The FaceDetectFaceIds control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_IDS. +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::StatsOutputEnable => { + "Toggles the Raspberry Pi IPA to output the hardware generated statistics. + +When this control is set to true, the IPA outputs a binary dump of the +hardware generated statistics through the Request metadata in the +Bcm2835StatsOutput control. + +\\sa Bcm2835StatsOutput +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::Bcm2835StatsOutput => { + "Span of the BCM2835 ISP generated statistics for the current frame. + +This is sent in the Request metadata if the StatsOutputEnable is set to +true. The statistics struct definition can be found in +include/linux/bcm2835-isp.h. + +\\sa StatsOutputEnable +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::ScalerCrops => { + "An array of rectangles, where each singular value has identical +functionality to the ScalerCrop control. This control allows the +Raspberry Pi pipeline handler to control individual scaler crops per +output stream. + +The order of rectangles passed into the control must match the order of +streams configured by the application. The pipeline handler will only +configure crop retangles up-to the number of output streams configured. +All subsequent rectangles passed into this control are ignored by the +pipeline handler. + +If both rpi::ScalerCrops and ScalerCrop controls are present in a +ControlList, the latter is discarded, and crops are obtained from this +control. + +Note that using different crop rectangles for each output stream with +this control is only applicable on the Pi5/PiSP platform. This control +should also be considered temporary/draft and will be replaced with +official libcamera API support for per-stream controls in the future. + +\\sa ScalerCrop +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::PispStatsOutput => { + "Span of the PiSP Frontend ISP generated statistics for the current +frame. This is sent in the Request metadata if the StatsOutputEnable is +set to true. The statistics struct definition can be found in +https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + +\\sa StatsOutputEnable +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncMode => { + "Enable or disable camera synchronisation (\"sync\") mode. + +When sync mode is enabled, a camera will synchronise frames temporally +with other cameras, either attached to the same device or a different +one. There should be one \"server\" device, which broadcasts timing +information to one or more \"clients\". Communication is one-way, from +server to clients only, and it is only clients that adjust their frame +timings to match the server. + +Sync mode requires all cameras to be running at (as far as possible) the +same fixed framerate. Clients may continue to make adjustments to keep +their cameras synchronised with the server for the duration of the +session, though any updates after the initial ones should remain small. + +\\sa SyncReady +\\sa SyncTimer +\\sa SyncFrames +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncReady => { + "When using the camera synchronisation algorithm, the server broadcasts +timing information to the clients. This also includes the time (some +number of frames in the future, called the \"ready time\") at which the +server will signal its controlling application, using this control, to +start using the image frames. + +The client receives the \"ready time\" from the server, and will signal +its application to start using the frames at this same moment. + +While this control value is false, applications (on both client and +server) should continue to wait, and not use the frames. + +Once this value becomes true, it means that this is the first frame +where the server and its clients have agreed that they will both be +synchronised and that applications should begin consuming frames. +Thereafter, this control will continue to signal the value true for +the rest of the session. + +\\sa SyncMode +\\sa SyncTimer +\\sa SyncFrames +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncTimer => { + "This reports the amount of time, in microseconds, until the \"ready +time\", at which the server and client will signal their controlling +applications that the frames are now synchronised and should be +used. The value may be refined slightly over time, becoming more precise +as the \"ready time\" approaches. + +Servers always report this value, whereas clients will omit this control +until they have received a message from the server that enables them to +calculate it. + +Normally the value will start positive (the \"ready time\" is in the +future), and decrease towards zero, before becoming negative (the \"ready +time\" has elapsed). So there should be just one frame where the timer +value is, or is very close to, zero - the one for which the SyncReady +control becomes true. At this moment, the value indicates how closely +synchronised the client believes it is with the server. + +But note that if frames are being dropped, then the \"near zero\" valued +frame, or indeed any other, could be skipped. In these cases the timer +value allows an application to deduce that this has happened. + +\\sa SyncMode +\\sa SyncReady +\\sa SyncFrames +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncFrames => { + "The number of frames the server should wait, after enabling +SyncModeServer, before signalling (via the SyncReady control) that +frames should be used. This therefore determines the \"ready time\" for +all synchronised cameras. + +This control value should be set only for the device that is to act as +the server, before or at the same moment at which SyncModeServer is +enabled. + +\\sa SyncMode +\\sa SyncReady +\\sa SyncTimer +" + } + } + } +} +/// Enable or disable the AEGC algorithm. When this control is set to true, +/// both ExposureTimeMode and AnalogueGainMode are set to auto, and if this +/// control is set to false then both are set to manual. +/// +/// If ExposureTimeMode or AnalogueGainMode are also set in the same +/// request as AeEnable, then the modes supplied by ExposureTimeMode or +/// AnalogueGainMode will take precedence. +/// +/// \sa ExposureTimeMode AnalogueGainMode +#[derive(Debug, Clone)] +pub struct AeEnable(pub bool); +impl Deref for AeEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AeEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AeEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AeEnable) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AeEnable { + const ID: u32 = ControlId::AeEnable as _; +} +impl Control for AeEnable {} +/// Report the AEGC algorithm state. +/// +/// The AEGC algorithm computes the exposure time and the analogue gain +/// to be applied to the image sensor. +/// +/// The AEGC algorithm behaviour is controlled by the ExposureTimeMode and +/// AnalogueGainMode controls, which allow applications to decide how +/// the exposure time and gain are computed, in Auto or Manual mode, +/// independently from one another. +/// +/// The AeState control reports the AEGC algorithm state through a single +/// value and describes it as a single computation block which computes +/// both the exposure time and the analogue gain values. +/// +/// When both the exposure time and analogue gain values are configured to +/// be in Manual mode, the AEGC algorithm is quiescent and does not actively +/// compute any value and the AeState control will report AeStateIdle. +/// +/// When at least the exposure time or analogue gain are configured to be +/// computed by the AEGC algorithm, the AeState control will report if the +/// algorithm has converged to stable values for all of the controls set +/// to be computed in Auto mode. +/// +/// \sa AnalogueGainMode +/// \sa ExposureTimeMode +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeState { + /// The AEGC algorithm is inactive. + /// + /// This state is returned when both AnalogueGainMode and + /// ExposureTimeMode are set to Manual and the algorithm is not + /// actively computing any value. + Idle = 0, + /// The AEGC algorithm is actively computing new values, for either the + /// exposure time or the analogue gain, but has not converged to a + /// stable result yet. + /// + /// This state is returned if at least one of AnalogueGainMode or + /// ExposureTimeMode is auto and the algorithm hasn't converged yet. + /// + /// The AEGC algorithm converges once stable values are computed for + /// all of the controls set to be computed in Auto mode. Once the + /// algorithm converges the state is moved to AeStateConverged. + Searching = 1, + /// The AEGC algorithm has converged. + /// + /// This state is returned if at least one of AnalogueGainMode or + /// ExposureTimeMode is Auto, and the AEGC algorithm has converged to a + /// stable value. + /// + /// If the measurements move too far away from the convergence point + /// then the AEGC algorithm might start adjusting again, in which case + /// the state is moved to AeStateSearching. + Converged = 2, +} +impl TryFrom for AeState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeState) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeState { + const ID: u32 = ControlId::AeState as _; +} +impl Control for AeState {} +/// Specify a metering mode for the AE algorithm to use. +/// +/// The metering modes determine which parts of the image are used to +/// determine the scene brightness. Metering modes may be platform specific +/// and not all metering modes may be supported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeMeteringMode { + /// Centre-weighted metering mode. + MeteringCentreWeighted = 0, + /// Spot metering mode. + MeteringSpot = 1, + /// Matrix metering mode. + MeteringMatrix = 2, + /// Custom metering mode. + MeteringCustom = 3, +} +impl TryFrom for AeMeteringMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeMeteringMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeMeteringMode { + const ID: u32 = ControlId::AeMeteringMode as _; +} +impl Control for AeMeteringMode {} +/// Specify a constraint mode for the AE algorithm to use. +/// +/// The constraint modes determine how the measured scene brightness is +/// adjusted to reach the desired target exposure. Constraint modes may be +/// platform specific, and not all constraint modes may be supported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeConstraintMode { + /// Default constraint mode. + /// + /// This mode aims to balance the exposure of different parts of the + /// image so as to reach a reasonable average level. However, highlights + /// in the image may appear over-exposed and lowlights may appear + /// under-exposed. + ConstraintNormal = 0, + /// Highlight constraint mode. + /// + /// This mode adjusts the exposure levels in order to try and avoid + /// over-exposing the brightest parts (highlights) of an image. + /// Other non-highlight parts of the image may appear under-exposed. + ConstraintHighlight = 1, + /// Shadows constraint mode. + /// + /// This mode adjusts the exposure levels in order to try and avoid + /// under-exposing the dark parts (shadows) of an image. Other normally + /// exposed parts of the image may appear over-exposed. + ConstraintShadows = 2, + /// Custom constraint mode. + ConstraintCustom = 3, +} +impl TryFrom for AeConstraintMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeConstraintMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeConstraintMode { + const ID: u32 = ControlId::AeConstraintMode as _; +} +impl Control for AeConstraintMode {} +/// Specify an exposure mode for the AE algorithm to use. +/// +/// The exposure modes specify how the desired total exposure is divided +/// between the exposure time and the sensor's analogue gain. They are +/// platform specific, and not all exposure modes may be supported. +/// +/// When one of AnalogueGainMode or ExposureTimeMode is set to Manual, +/// the fixed values will override any choices made by AeExposureMode. +/// +/// \sa AnalogueGainMode +/// \sa ExposureTimeMode +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeExposureMode { + /// Default exposure mode. + ExposureNormal = 0, + /// Exposure mode allowing only short exposure times. + ExposureShort = 1, + /// Exposure mode allowing long exposure times. + ExposureLong = 2, + /// Custom exposure mode. + ExposureCustom = 3, +} +impl TryFrom for AeExposureMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeExposureMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeExposureMode { + const ID: u32 = ControlId::AeExposureMode as _; +} +impl Control for AeExposureMode {} +/// Specify an Exposure Value (EV) parameter. +/// +/// The EV parameter will only be applied if the AE algorithm is currently +/// enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode +/// are in Auto mode. +/// +/// By convention EV adjusts the exposure as log2. For example +/// EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment +/// of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. +/// +/// \sa AnalogueGainMode +/// \sa ExposureTimeMode +#[derive(Debug, Clone)] +pub struct ExposureValue(pub f32); +impl Deref for ExposureValue { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ExposureValue { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ExposureValue { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ExposureValue) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ExposureValue { + const ID: u32 = ControlId::ExposureValue as _; +} +impl Control for ExposureValue {} +/// Exposure time for the frame applied in the sensor device. +/// +/// This value is specified in microseconds. +/// +/// This control will only take effect if ExposureTimeMode is Manual. If +/// this control is set when ExposureTimeMode is Auto, the value will be +/// ignored and will not be retained. +/// +/// When reported in metadata, this control indicates what exposure time +/// was used for the current frame, regardless of ExposureTimeMode. +/// ExposureTimeMode will indicate the source of the exposure time value, +/// whether it came from the AE algorithm or not. +/// +/// \sa AnalogueGain +/// \sa ExposureTimeMode +#[derive(Debug, Clone)] +pub struct ExposureTime(pub i32); +impl Deref for ExposureTime { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ExposureTime { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ExposureTime { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ExposureTime) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ExposureTime { + const ID: u32 = ControlId::ExposureTime as _; +} +impl Control for ExposureTime {} +/// Controls the source of the exposure time that is applied to the image +/// sensor. +/// +/// When set to Auto, the AE algorithm computes the exposure time and +/// configures the image sensor accordingly. When set to Manual, the value +/// of the ExposureTime control is used. +/// +/// When transitioning from Auto to Manual mode and no ExposureTime control +/// is provided by the application, the last value computed by the AE +/// algorithm when the mode was Auto will be used. If the ExposureTimeMode +/// was never set to Auto (either because the camera started in Manual mode, +/// or Auto is not supported by the camera), the camera should use a +/// best-effort default value. +/// +/// If ExposureTimeModeManual is supported, the ExposureTime control must +/// also be supported. +/// +/// Cameras that support manual control of the sensor shall support manual +/// mode for both ExposureTimeMode and AnalogueGainMode, and shall expose +/// the ExposureTime and AnalogueGain controls. If the camera also has an +/// AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall +/// support both manual and auto mode. If auto mode is available, it shall +/// be the default mode. These rules do not apply to black box cameras +/// such as UVC cameras, where the available gain and exposure modes are +/// completely dependent on what the device exposes. +/// +/// \par Flickerless exposure mode transitions +/// +/// Applications that wish to transition from ExposureTimeModeAuto to direct +/// control of the exposure time without causing extra flicker can do so by +/// selecting an ExposureTime value as close as possible to the last value +/// computed by the auto exposure algorithm in order to avoid any visible +/// flickering. +/// +/// To select the correct value to use as ExposureTime value, applications +/// should accommodate the natural delay in applying controls caused by the +/// capture pipeline frame depth. +/// +/// When switching to manual exposure mode, applications should not +/// immediately specify an ExposureTime value in the same request where +/// ExposureTimeMode is set to Manual. They should instead wait for the +/// first Request where ExposureTimeMode is reported as +/// ExposureTimeModeManual in the Request metadata, and use the reported +/// ExposureTime to populate the control value in the next Request to be +/// queued to the Camera. +/// +/// The implementation of the auto-exposure algorithm should equally try to +/// minimize flickering and when transitioning from manual exposure mode to +/// auto exposure use the last value provided by the application as starting +/// point. +/// +/// 1. Start with ExposureTimeMode set to Auto +/// +/// 2. Set ExposureTimeMode to Manual +/// +/// 3. Wait for the first completed request that has ExposureTimeMode +/// set to Manual +/// +/// 4. Copy the value reported in ExposureTime into a new request, and +/// submit it +/// +/// 5. Proceed to run manual exposure time as desired +/// +/// \sa ExposureTime +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum ExposureTimeMode { + /// The exposure time will be calculated automatically and set by the + /// AE algorithm. + /// + /// If ExposureTime is set while this mode is active, it will be + /// ignored, and its value will not be retained. + /// + /// When transitioning from Manual to Auto mode, the AEGC should start + /// its adjustments based on the last set manual ExposureTime value. + Auto = 0, + /// The exposure time will not be updated by the AE algorithm. + /// + /// When transitioning from Auto to Manual mode, the last computed + /// exposure value is used until a new value is specified through the + /// ExposureTime control. If an ExposureTime value is specified in the + /// same request where the ExposureTimeMode is changed from Auto to + /// Manual, the provided ExposureTime is applied immediately. + Manual = 1, +} +impl TryFrom for ExposureTimeMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: ExposureTimeMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for ExposureTimeMode { + const ID: u32 = ControlId::ExposureTimeMode as _; +} +impl Control for ExposureTimeMode {} +/// Analogue gain value applied in the sensor device. +/// +/// The value of the control specifies the gain multiplier applied to all +/// colour channels. This value cannot be lower than 1.0. +/// +/// This control will only take effect if AnalogueGainMode is Manual. If +/// this control is set when AnalogueGainMode is Auto, the value will be +/// ignored and will not be retained. +/// +/// When reported in metadata, this control indicates what analogue gain +/// was used for the current request, regardless of AnalogueGainMode. +/// AnalogueGainMode will indicate the source of the analogue gain value, +/// whether it came from the AEGC algorithm or not. +/// +/// \sa ExposureTime +/// \sa AnalogueGainMode +#[derive(Debug, Clone)] +pub struct AnalogueGain(pub f32); +impl Deref for AnalogueGain { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AnalogueGain { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AnalogueGain { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AnalogueGain) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AnalogueGain { + const ID: u32 = ControlId::AnalogueGain as _; +} +impl Control for AnalogueGain {} +/// Controls the source of the analogue gain that is applied to the image +/// sensor. +/// +/// When set to Auto, the AEGC algorithm computes the analogue gain and +/// configures the image sensor accordingly. When set to Manual, the value +/// of the AnalogueGain control is used. +/// +/// When transitioning from Auto to Manual mode and no AnalogueGain control +/// is provided by the application, the last value computed by the AEGC +/// algorithm when the mode was Auto will be used. If the AnalogueGainMode +/// was never set to Auto (either because the camera started in Manual mode, +/// or Auto is not supported by the camera), the camera should use a +/// best-effort default value. +/// +/// If AnalogueGainModeManual is supported, the AnalogueGain control must +/// also be supported. +/// +/// For cameras where we have control over the ISP, both ExposureTimeMode +/// and AnalogueGainMode are expected to support manual mode, and both +/// controls (as well as ExposureTimeMode and AnalogueGain) are expected to +/// be present. If the camera also has an AEGC implementation, both +/// ExposureTimeMode and AnalogueGainMode shall support both manual and +/// auto mode. If auto mode is available, it shall be the default mode. +/// These rules do not apply to black box cameras such as UVC cameras, +/// where the available gain and exposure modes are completely dependent on +/// what the hardware exposes. +/// +/// The same procedure described for performing flickerless transitions in +/// the ExposureTimeMode control documentation can be applied to analogue +/// gain. +/// +/// \sa ExposureTimeMode +/// \sa AnalogueGain +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AnalogueGainMode { + /// The analogue gain will be calculated automatically and set by the + /// AEGC algorithm. + /// + /// If AnalogueGain is set while this mode is active, it will be + /// ignored, and it will also not be retained. + /// + /// When transitioning from Manual to Auto mode, the AEGC should start + /// its adjustments based on the last set manual AnalogueGain value. + Auto = 0, + /// The analogue gain will not be updated by the AEGC algorithm. + /// + /// When transitioning from Auto to Manual mode, the last computed + /// gain value is used until a new value is specified through the + /// AnalogueGain control. If an AnalogueGain value is specified in the + /// same request where the AnalogueGainMode is changed from Auto to + /// Manual, the provided AnalogueGain is applied immediately. + Manual = 1, +} +impl TryFrom for AnalogueGainMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AnalogueGainMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AnalogueGainMode { + const ID: u32 = ControlId::AnalogueGainMode as _; +} +impl Control for AnalogueGainMode {} +/// Set the flicker avoidance mode for AGC/AEC. +/// +/// The flicker mode determines whether, and how, the AGC/AEC algorithm +/// attempts to hide flicker effects caused by the duty cycle of artificial +/// lighting. +/// +/// Although implementation dependent, many algorithms for "flicker +/// avoidance" work by restricting this exposure time to integer multiples +/// of the cycle period, wherever possible. +/// +/// Implementations may not support all of the flicker modes listed below. +/// +/// By default the system will start in FlickerAuto mode if this is +/// supported, otherwise the flicker mode will be set to FlickerOff. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeFlickerMode { + /// No flicker avoidance is performed. + FlickerOff = 0, + /// Manual flicker avoidance. + /// + /// Suppress flicker effects caused by lighting running with a period + /// specified by the AeFlickerPeriod control. + /// \sa AeFlickerPeriod + FlickerManual = 1, + /// Automatic flicker period detection and avoidance. + /// + /// The system will automatically determine the most likely value of + /// flicker period, and avoid flicker of this frequency. Once flicker + /// is being corrected, it is implementation dependent whether the + /// system is still able to detect a change in the flicker period. + /// \sa AeFlickerDetected + FlickerAuto = 2, +} +impl TryFrom for AeFlickerMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeFlickerMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeFlickerMode { + const ID: u32 = ControlId::AeFlickerMode as _; +} +impl Control for AeFlickerMode {} +/// Manual flicker period in microseconds. +/// +/// This value sets the current flicker period to avoid. It is used when +/// AeFlickerMode is set to FlickerManual. +/// +/// To cancel 50Hz mains flicker, this should be set to 10000 (corresponding +/// to 100Hz), or 8333 (120Hz) for 60Hz mains. +/// +/// Setting the mode to FlickerManual when no AeFlickerPeriod has ever been +/// set means that no flicker cancellation occurs (until the value of this +/// control is updated). +/// +/// Switching to modes other than FlickerManual has no effect on the +/// value of the AeFlickerPeriod control. +/// +/// \sa AeFlickerMode +#[derive(Debug, Clone)] +pub struct AeFlickerPeriod(pub i32); +impl Deref for AeFlickerPeriod { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AeFlickerPeriod { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AeFlickerPeriod { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AeFlickerPeriod) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AeFlickerPeriod { + const ID: u32 = ControlId::AeFlickerPeriod as _; +} +impl Control for AeFlickerPeriod {} +/// Flicker period detected in microseconds. +/// +/// The value reported here indicates the currently detected flicker +/// period, or zero if no flicker at all is detected. +/// +/// When AeFlickerMode is set to FlickerAuto, there may be a period during +/// which the value reported here remains zero. Once a non-zero value is +/// reported, then this is the flicker period that has been detected and is +/// now being cancelled. +/// +/// In the case of 50Hz mains flicker, the value would be 10000 +/// (corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. +/// +/// It is implementation dependent whether the system can continue to detect +/// flicker of different periods when another frequency is already being +/// cancelled. +/// +/// \sa AeFlickerMode +#[derive(Debug, Clone)] +pub struct AeFlickerDetected(pub i32); +impl Deref for AeFlickerDetected { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AeFlickerDetected { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AeFlickerDetected { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AeFlickerDetected) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AeFlickerDetected { + const ID: u32 = ControlId::AeFlickerDetected as _; +} +impl Control for AeFlickerDetected {} +/// Specify a fixed brightness parameter. +/// +/// Positive values (up to 1.0) produce brighter images; negative values +/// (up to -1.0) produce darker images and 0.0 leaves pixels unchanged. +#[derive(Debug, Clone)] +pub struct Brightness(pub f32); +impl Deref for Brightness { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Brightness { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Brightness { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Brightness) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Brightness { + const ID: u32 = ControlId::Brightness as _; +} +impl Control for Brightness {} +/// Specify a fixed contrast parameter. +/// +/// Normal contrast is given by the value 1.0; larger values produce images +/// with more contrast. +#[derive(Debug, Clone)] +pub struct Contrast(pub f32); +impl Deref for Contrast { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Contrast { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Contrast { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Contrast) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Contrast { + const ID: u32 = ControlId::Contrast as _; +} +impl Control for Contrast {} +/// Report an estimate of the current illuminance level in lux. +/// +/// The Lux control can only be returned in metadata. +#[derive(Debug, Clone)] +pub struct Lux(pub f32); +impl Deref for Lux { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Lux { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Lux { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Lux) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Lux { + const ID: u32 = ControlId::Lux as _; +} +impl Control for Lux {} +/// Enable or disable the AWB. +/// +/// When AWB is enabled, the algorithm estimates the colour temperature of +/// the scene and computes colour gains and the colour correction matrix +/// automatically. The computed colour temperature, gains and correction +/// matrix are reported in metadata. The corresponding controls are ignored +/// if set in a request. +/// +/// When AWB is disabled, the colour temperature, gains and correction +/// matrix are not updated automatically and can be set manually in +/// requests. +/// +/// \sa ColourCorrectionMatrix +/// \sa ColourGains +/// \sa ColourTemperature +#[derive(Debug, Clone)] +pub struct AwbEnable(pub bool); +impl Deref for AwbEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AwbEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AwbEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AwbEnable) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AwbEnable { + const ID: u32 = ControlId::AwbEnable as _; +} +impl Control for AwbEnable {} +/// Specify the range of illuminants to use for the AWB algorithm. +/// +/// The modes supported are platform specific, and not all modes may be +/// supported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AwbMode { + /// Search over the whole colour temperature range. + AwbAuto = 0, + /// Incandescent AWB lamp mode. + AwbIncandescent = 1, + /// Tungsten AWB lamp mode. + AwbTungsten = 2, + /// Fluorescent AWB lamp mode. + AwbFluorescent = 3, + /// Indoor AWB lighting mode. + AwbIndoor = 4, + /// Daylight AWB lighting mode. + AwbDaylight = 5, + /// Cloudy AWB lighting mode. + AwbCloudy = 6, + /// Custom AWB mode. + AwbCustom = 7, +} +impl TryFrom for AwbMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AwbMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AwbMode { + const ID: u32 = ControlId::AwbMode as _; +} +impl Control for AwbMode {} +/// Report the lock status of a running AWB algorithm. +/// +/// If the AWB algorithm is locked the value shall be set to true, if it's +/// converging it shall be set to false. If the AWB algorithm is not +/// running the control shall not be present in the metadata control list. +/// +/// \sa AwbEnable +#[derive(Debug, Clone)] +pub struct AwbLocked(pub bool); +impl Deref for AwbLocked { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AwbLocked { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AwbLocked { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AwbLocked) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AwbLocked { + const ID: u32 = ControlId::AwbLocked as _; +} +impl Control for AwbLocked {} +/// Pair of gain values for the Red and Blue colour channels, in that +/// order. +/// +/// ColourGains can only be applied in a Request when the AWB is disabled. +/// If ColourGains is set in a request but ColourTemperature is not, the +/// implementation shall calculate and set the ColourTemperature based on +/// the ColourGains. +/// +/// \sa AwbEnable +/// \sa ColourTemperature +#[derive(Debug, Clone)] +pub struct ColourGains(pub [f32; 2]); +impl Deref for ColourGains { + type Target = [f32; 2]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ColourGains { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ColourGains { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[f32; 2]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ColourGains) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ColourGains { + const ID: u32 = ControlId::ColourGains as _; +} +impl Control for ColourGains {} +/// ColourTemperature of the frame, in kelvin. +/// +/// ColourTemperature can only be applied in a Request when the AWB is +/// disabled. +/// +/// If ColourTemperature is set in a request but ColourGains is not, the +/// implementation shall calculate and set the ColourGains based on the +/// given ColourTemperature. If ColourTemperature is set (either directly, +/// or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, +/// the ColourCorrectionMatrix is updated based on the ColourTemperature. +/// +/// The ColourTemperature used to process the frame is reported in metadata. +/// +/// \sa AwbEnable +/// \sa ColourCorrectionMatrix +/// \sa ColourGains +#[derive(Debug, Clone)] +pub struct ColourTemperature(pub i32); +impl Deref for ColourTemperature { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ColourTemperature { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ColourTemperature { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ColourTemperature) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ColourTemperature { + const ID: u32 = ControlId::ColourTemperature as _; +} +impl Control for ColourTemperature {} +/// Specify a fixed saturation parameter. +/// +/// Normal saturation is given by the value 1.0; larger values produce more +/// saturated colours; 0.0 produces a greyscale image. +#[derive(Debug, Clone)] +pub struct Saturation(pub f32); +impl Deref for Saturation { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Saturation { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Saturation { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Saturation) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Saturation { + const ID: u32 = ControlId::Saturation as _; +} +impl Control for Saturation {} +/// Reports the sensor black levels used for processing a frame. +/// +/// The values are in the order R, Gr, Gb, B. They are returned as numbers +/// out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The +/// SensorBlackLevels control can only be returned in metadata. +#[derive(Debug, Clone)] +pub struct SensorBlackLevels(pub [i32; 4]); +impl Deref for SensorBlackLevels { + type Target = [i32; 4]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorBlackLevels { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorBlackLevels { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[i32; 4]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorBlackLevels) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorBlackLevels { + const ID: u32 = ControlId::SensorBlackLevels as _; +} +impl Control for SensorBlackLevels {} +/// Intensity of the sharpening applied to the image. +/// +/// A value of 0.0 means no sharpening. The minimum value means +/// minimal sharpening, and shall be 0.0 unless the camera can't +/// disable sharpening completely. The default value shall give a +/// "reasonable" level of sharpening, suitable for most use cases. +/// The maximum value may apply extremely high levels of sharpening, +/// higher than anyone could reasonably want. Negative values are +/// not allowed. Note also that sharpening is not applied to raw +/// streams. +#[derive(Debug, Clone)] +pub struct Sharpness(pub f32); +impl Deref for Sharpness { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Sharpness { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Sharpness { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Sharpness) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Sharpness { + const ID: u32 = ControlId::Sharpness as _; +} +impl Control for Sharpness {} +/// Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. +/// +/// A larger FocusFoM value indicates a more in-focus frame. This singular +/// value may be based on a combination of statistics gathered from +/// multiple focus regions within an image. The number of focus regions and +/// method of combination is platform dependent. In this respect, it is not +/// necessarily aimed at providing a way to implement a focus algorithm by +/// the application, rather an indication of how in-focus a frame is. +#[derive(Debug, Clone)] +pub struct FocusFoM(pub i32); +impl Deref for FocusFoM { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FocusFoM { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FocusFoM { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FocusFoM) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FocusFoM { + const ID: u32 = ControlId::FocusFoM as _; +} +impl Control for FocusFoM {} +/// The 3x3 matrix that converts camera RGB to sRGB within the imaging +/// pipeline. +/// +/// This should describe the matrix that is used after pixels have been +/// white-balanced, but before any gamma transformation. The 3x3 matrix is +/// stored in conventional reading order in an array of 9 floating point +/// values. +/// +/// ColourCorrectionMatrix can only be applied in a Request when the AWB is +/// disabled. +/// +/// \sa AwbEnable +/// \sa ColourTemperature +#[derive(Debug, Clone)] +pub struct ColourCorrectionMatrix(pub [[f32; 3]; 3]); +impl Deref for ColourCorrectionMatrix { + type Target = [[f32; 3]; 3]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ColourCorrectionMatrix { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ColourCorrectionMatrix { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[[f32; 3]; 3]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ColourCorrectionMatrix) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ColourCorrectionMatrix { + const ID: u32 = ControlId::ColourCorrectionMatrix as _; +} +impl Control for ColourCorrectionMatrix {} +/// Sets the image portion that will be scaled to form the whole of +/// the final output image. +/// +/// The (x,y) location of this rectangle is relative to the +/// PixelArrayActiveAreas that is being used. The units remain native +/// sensor pixels, even if the sensor is being used in a binning or +/// skipping mode. +/// +/// This control is only present when the pipeline supports scaling. Its +/// maximum valid value is given by the properties::ScalerCropMaximum +/// property, and the two can be used to implement digital zoom. +#[derive(Debug, Clone)] +pub struct ScalerCrop(pub Rectangle); +impl Deref for ScalerCrop { + type Target = Rectangle; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ScalerCrop { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ScalerCrop { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ScalerCrop) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ScalerCrop { + const ID: u32 = ControlId::ScalerCrop as _; +} +impl Control for ScalerCrop {} +/// Digital gain value applied during the processing steps applied +/// to the image as captured from the sensor. +/// +/// The global digital gain factor is applied to all the colour channels +/// of the RAW image. Different pipeline models are free to +/// specify how the global gain factor applies to each separate +/// channel. +/// +/// If an imaging pipeline applies digital gain in distinct +/// processing steps, this value indicates their total sum. +/// Pipelines are free to decide how to adjust each processing +/// step to respect the received gain factor and shall report +/// their total value in the request metadata. +#[derive(Debug, Clone)] +pub struct DigitalGain(pub f32); +impl Deref for DigitalGain { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for DigitalGain { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for DigitalGain { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: DigitalGain) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for DigitalGain { + const ID: u32 = ControlId::DigitalGain as _; +} +impl Control for DigitalGain {} +/// The instantaneous frame duration from start of frame exposure to start +/// of next exposure, expressed in microseconds. +/// +/// This control is meant to be returned in metadata. +#[derive(Debug, Clone)] +pub struct FrameDuration(pub i64); +impl Deref for FrameDuration { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FrameDuration { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FrameDuration { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FrameDuration) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FrameDuration { + const ID: u32 = ControlId::FrameDuration as _; +} +impl Control for FrameDuration {} +/// The minimum and maximum (in that order) frame duration, expressed in +/// microseconds. +/// +/// When provided by applications, the control specifies the sensor frame +/// duration interval the pipeline has to use. This limits the largest +/// exposure time the sensor can use. For example, if a maximum frame +/// duration of 33ms is requested (corresponding to 30 frames per second), +/// the sensor will not be able to raise the exposure time above 33ms. +/// A fixed frame duration is achieved by setting the minimum and maximum +/// values to be the same. Setting both values to 0 reverts to using the +/// camera defaults. +/// +/// The maximum frame duration provides the absolute limit to the exposure +/// time computed by the AE algorithm and it overrides any exposure mode +/// setting specified with controls::AeExposureMode. Similarly, when a +/// manual exposure time is set through controls::ExposureTime, it also +/// gets clipped to the limits set by this control. When reported in +/// metadata, the control expresses the minimum and maximum frame durations +/// used after being clipped to the sensor provided frame duration limits. +/// +/// \sa AeExposureMode +/// \sa ExposureTime +/// +/// \todo Define how to calculate the capture frame rate by +/// defining controls to report additional delays introduced by +/// the capture pipeline or post-processing stages (ie JPEG +/// conversion, frame scaling). +/// +/// \todo Provide an explicit definition of default control values, for +/// this and all other controls. +#[derive(Debug, Clone)] +pub struct FrameDurationLimits(pub [i64; 2]); +impl Deref for FrameDurationLimits { + type Target = [i64; 2]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FrameDurationLimits { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FrameDurationLimits { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[i64; 2]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FrameDurationLimits) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FrameDurationLimits { + const ID: u32 = ControlId::FrameDurationLimits as _; +} +impl Control for FrameDurationLimits {} +/// Temperature measure from the camera sensor in Celsius. +/// +/// This value is typically obtained by a thermal sensor present on-die or +/// in the camera module. The range of reported temperatures is device +/// dependent. +/// +/// The SensorTemperature control will only be returned in metadata if a +/// thermal sensor is present. +#[derive(Debug, Clone)] +pub struct SensorTemperature(pub f32); +impl Deref for SensorTemperature { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorTemperature { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorTemperature { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorTemperature) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorTemperature { + const ID: u32 = ControlId::SensorTemperature as _; +} +impl Control for SensorTemperature {} +/// The time when the first row of the image sensor active array is exposed. +/// +/// The timestamp, expressed in nanoseconds, represents a monotonically +/// increasing counter since the system boot time, as defined by the +/// Linux-specific CLOCK_BOOTTIME clock id. +/// +/// The SensorTimestamp control can only be returned in metadata. +/// +/// \todo Define how the sensor timestamp has to be used in the reprocessing +/// use case. +#[derive(Debug, Clone)] +pub struct SensorTimestamp(pub i64); +impl Deref for SensorTimestamp { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorTimestamp { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorTimestamp { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorTimestamp) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorTimestamp { + const ID: u32 = ControlId::SensorTimestamp as _; +} +impl Control for SensorTimestamp {} +/// The mode of the AF (autofocus) algorithm. +/// +/// An implementation may choose not to implement all the modes. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfMode { + /// The AF algorithm is in manual mode. + /// + /// In this mode it will never perform any action nor move the lens of + /// its own accord, but an application can specify the desired lens + /// position using the LensPosition control. The AfState will always + /// report AfStateIdle. + /// + /// If the camera is started in AfModeManual, it will move the focus + /// lens to the position specified by the LensPosition control. + /// + /// This mode is the recommended default value for the AfMode control. + /// External cameras (as reported by the Location property set to + /// CameraLocationExternal) may use a different default value. + Manual = 0, + /// The AF algorithm is in auto mode. + /// + /// In this mode the algorithm will never move the lens or change state + /// unless the AfTrigger control is used. The AfTrigger control can be + /// used to initiate a focus scan, the results of which will be + /// reported by AfState. + /// + /// If the autofocus algorithm is moved from AfModeAuto to another mode + /// while a scan is in progress, the scan is cancelled immediately, + /// without waiting for the scan to finish. + /// + /// When first entering this mode the AfState will report AfStateIdle. + /// When a trigger control is sent, AfState will report AfStateScanning + /// for a period before spontaneously changing to AfStateFocused or + /// AfStateFailed, depending on the outcome of the scan. It will remain + /// in this state until another scan is initiated by the AfTrigger + /// control. If a scan is cancelled (without changing to another mode), + /// AfState will return to AfStateIdle. + Auto = 1, + /// The AF algorithm is in continuous mode. + /// + /// In this mode the lens can re-start a scan spontaneously at any + /// moment, without any user intervention. The AfState still reports + /// whether the algorithm is currently scanning or not, though the + /// application has no ability to initiate or cancel scans, nor to move + /// the lens for itself. + /// + /// However, applications can pause the AF algorithm from continuously + /// scanning by using the AfPause control. This allows video or still + /// images to be captured whilst guaranteeing that the focus is fixed. + /// + /// When set to AfModeContinuous, the system will immediately initiate a + /// scan so AfState will report AfStateScanning, and will settle on one + /// of AfStateFocused or AfStateFailed, depending on the scan result. + Continuous = 2, +} +impl TryFrom for AfMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfMode { + const ID: u32 = ControlId::AfMode as _; +} +impl Control for AfMode {} +/// The range of focus distances that is scanned. +/// +/// An implementation may choose not to implement all the options here. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfRange { + /// A wide range of focus distances is scanned. + /// + /// Scanned distances cover all the way from infinity down to close + /// distances, though depending on the implementation, possibly not + /// including the very closest macro positions. + Normal = 0, + /// Only close distances are scanned. + Macro = 1, + /// The full range of focus distances is scanned. + /// + /// This range is similar to AfRangeNormal but includes the very + /// closest macro positions. + Full = 2, +} +impl TryFrom for AfRange { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfRange) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfRange { + const ID: u32 = ControlId::AfRange as _; +} +impl Control for AfRange {} +/// Determine whether the AF is to move the lens as quickly as possible or +/// more steadily. +/// +/// For example, during video recording it may be desirable not to move the +/// lens too abruptly, but when in a preview mode (waiting for a still +/// capture) it may be helpful to move the lens as quickly as is reasonably +/// possible. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfSpeed { + /// Move the lens at its usual speed. + Normal = 0, + /// Move the lens more quickly. + Fast = 1, +} +impl TryFrom for AfSpeed { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfSpeed) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfSpeed { + const ID: u32 = ControlId::AfSpeed as _; +} +impl Control for AfSpeed {} +/// The parts of the image used by the AF algorithm to measure focus. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfMetering { + /// Let the AF algorithm decide for itself where it will measure focus. + Auto = 0, + /// Use the rectangles defined by the AfWindows control to measure focus. + /// + /// If no windows are specified the behaviour is platform dependent. + Windows = 1, +} +impl TryFrom for AfMetering { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfMetering) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfMetering { + const ID: u32 = ControlId::AfMetering as _; +} +impl Control for AfMetering {} +/// The focus windows used by the AF algorithm when AfMetering is set to +/// AfMeteringWindows. +/// +/// The units used are pixels within the rectangle returned by the +/// ScalerCropMaximum property. +/// +/// In order to be activated, a rectangle must be programmed with non-zero +/// width and height. Internally, these rectangles are intersected with the +/// ScalerCropMaximum rectangle. If the window becomes empty after this +/// operation, then the window is ignored. If all the windows end up being +/// ignored, then the behaviour is platform dependent. +/// +/// On platforms that support the ScalerCrop control (for implementing +/// digital zoom, for example), no automatic recalculation or adjustment of +/// AF windows is performed internally if the ScalerCrop is changed. If any +/// window lies outside the output image after the scaler crop has been +/// applied, it is up to the application to recalculate them. +/// +/// The details of how the windows are used are platform dependent. We note +/// that when there is more than one AF window, a typical implementation +/// might find the optimal focus position for each one and finally select +/// the window where the focal distance for the objects shown in that part +/// of the image are closest to the camera. +#[derive(Debug, Clone)] +pub struct AfWindows(pub Vec); +impl Deref for AfWindows { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AfWindows { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AfWindows { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AfWindows) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AfWindows { + const ID: u32 = ControlId::AfWindows as _; +} +impl Control for AfWindows {} +/// Start an autofocus scan. +/// +/// This control starts an autofocus scan when AfMode is set to AfModeAuto, +/// and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It +/// can also be used to terminate a scan early. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfTrigger { + /// Start an AF scan. + /// + /// Setting the control to AfTriggerStart is ignored if a scan is in + /// progress. + Start = 0, + /// Cancel an AF scan. + /// + /// This does not cause the lens to move anywhere else. Ignored if no + /// scan is in progress. + Cancel = 1, +} +impl TryFrom for AfTrigger { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfTrigger) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfTrigger { + const ID: u32 = ControlId::AfTrigger as _; +} +impl Control for AfTrigger {} +/// Pause lens movements when in continuous autofocus mode. +/// +/// This control has no effect except when in continuous autofocus mode +/// (AfModeContinuous). It can be used to pause any lens movements while +/// (for example) images are captured. The algorithm remains inactive +/// until it is instructed to resume. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfPause { + /// Pause the continuous autofocus algorithm immediately. + /// + /// The autofocus algorithm is paused whether or not any kind of scan + /// is underway. AfPauseState will subsequently report + /// AfPauseStatePaused. AfState may report any of AfStateScanning, + /// AfStateFocused or AfStateFailed, depending on the algorithm's state + /// when it received this control. + Immediate = 0, + /// Pause the continuous autofocus algorithm at the end of the scan. + /// + /// This is similar to AfPauseImmediate, and if the AfState is + /// currently reporting AfStateFocused or AfStateFailed it will remain + /// in that state and AfPauseState will report AfPauseStatePaused. + /// + /// However, if the algorithm is scanning (AfStateScanning), + /// AfPauseState will report AfPauseStatePausing until the scan is + /// finished, at which point AfState will report one of AfStateFocused + /// or AfStateFailed, and AfPauseState will change to + /// AfPauseStatePaused. + Deferred = 1, + /// Resume continuous autofocus operation. + /// + /// The algorithm starts again from exactly where it left off, and + /// AfPauseState will report AfPauseStateRunning. + Resume = 2, +} +impl TryFrom for AfPause { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfPause) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfPause { + const ID: u32 = ControlId::AfPause as _; +} +impl Control for AfPause {} +/// Set and report the focus lens position. +/// +/// This control instructs the lens to move to a particular position and +/// also reports back the position of the lens for each frame. +/// +/// The LensPosition control is ignored unless the AfMode is set to +/// AfModeManual, though the value is reported back unconditionally in all +/// modes. +/// +/// This value, which is generally a non-integer, is the reciprocal of the +/// focal distance in metres, also known as dioptres. That is, to set a +/// focal distance D, the lens position LP is given by +/// +/// \f$LP = \frac{1\mathrm{m}}{D}\f$ +/// +/// For example: +/// +/// - 0 moves the lens to infinity. +/// - 0.5 moves the lens to focus on objects 2m away. +/// - 2 moves the lens to focus on objects 50cm away. +/// - And larger values will focus the lens closer. +/// +/// The default value of the control should indicate a good general +/// position for the lens, often corresponding to the hyperfocal distance +/// (the closest position for which objects at infinity are still +/// acceptably sharp). The minimum will often be zero (meaning infinity), +/// and the maximum value defines the closest focus position. +/// +/// \todo Define a property to report the Hyperfocal distance of calibrated +/// lenses. +#[derive(Debug, Clone)] +pub struct LensPosition(pub f32); +impl Deref for LensPosition { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for LensPosition { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for LensPosition { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: LensPosition) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for LensPosition { + const ID: u32 = ControlId::LensPosition as _; +} +impl Control for LensPosition {} +/// The current state of the AF algorithm. +/// +/// This control reports the current state of the AF algorithm in +/// conjunction with the reported AfMode value and (in continuous AF mode) +/// the AfPauseState value. The possible state changes are described below, +/// though we note the following state transitions that occur when the +/// AfMode is changed. +/// +/// If the AfMode is set to AfModeManual, then the AfState will always +/// report AfStateIdle (even if the lens is subsequently moved). Changing +/// to the AfModeManual state does not initiate any lens movement. +/// +/// If the AfMode is set to AfModeAuto then the AfState will report +/// AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent +/// together then AfState will omit AfStateIdle and move straight to +/// AfStateScanning (and start a scan). +/// +/// If the AfMode is set to AfModeContinuous then the AfState will +/// initially report AfStateScanning. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfState { + /// The AF algorithm is in manual mode (AfModeManual) or in auto mode + /// (AfModeAuto) and a scan has not yet been triggered, or an + /// in-progress scan was cancelled. + Idle = 0, + /// The AF algorithm is in auto mode (AfModeAuto), and a scan has been + /// started using the AfTrigger control. + /// + /// The scan can be cancelled by sending AfTriggerCancel at which point + /// the algorithm will either move back to AfStateIdle or, if the scan + /// actually completes before the cancel request is processed, to one + /// of AfStateFocused or AfStateFailed. + /// + /// Alternatively the AF algorithm could be in continuous mode + /// (AfModeContinuous) at which point it may enter this state + /// spontaneously whenever it determines that a rescan is needed. + Scanning = 1, + /// The AF algorithm is in auto (AfModeAuto) or continuous + /// (AfModeContinuous) mode and a scan has completed with the result + /// that the algorithm believes the image is now in focus. + Focused = 2, + /// The AF algorithm is in auto (AfModeAuto) or continuous + /// (AfModeContinuous) mode and a scan has completed with the result + /// that the algorithm did not find a good focus position. + Failed = 3, +} +impl TryFrom for AfState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfState) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfState { + const ID: u32 = ControlId::AfState as _; +} +impl Control for AfState {} +/// Report whether the autofocus is currently running, paused or pausing. +/// +/// This control is only applicable in continuous (AfModeContinuous) mode, +/// and reports whether the algorithm is currently running, paused or +/// pausing (that is, will pause as soon as any in-progress scan +/// completes). +/// +/// Any change to AfMode will cause AfPauseStateRunning to be reported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfPauseState { + /// Continuous AF is running and the algorithm may restart a scan + /// spontaneously. + Running = 0, + /// Continuous AF has been sent an AfPauseDeferred control, and will + /// pause as soon as any in-progress scan completes. + /// + /// When the scan completes, the AfPauseState control will report + /// AfPauseStatePaused. No new scans will be start spontaneously until + /// the AfPauseResume control is sent. + Pausing = 1, + /// Continuous AF is paused. + /// + /// No further state changes or lens movements will occur until the + /// AfPauseResume control is sent. + Paused = 2, +} +impl TryFrom for AfPauseState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfPauseState) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfPauseState { + const ID: u32 = ControlId::AfPauseState as _; +} +impl Control for AfPauseState {} +/// Set the mode to be used for High Dynamic Range (HDR) imaging. +/// +/// HDR techniques typically include multiple exposure, image fusion and +/// tone mapping techniques to improve the dynamic range of the resulting +/// images. +/// +/// When using an HDR mode, images are captured with different sets of AGC +/// settings called HDR channels. Channels indicate in particular the type +/// of exposure (short, medium or long) used to capture the raw image, +/// before fusion. Each HDR image is tagged with the corresponding channel +/// using the HdrChannel control. +/// +/// \sa HdrChannel +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum HdrMode { + /// HDR is disabled. + /// + /// Metadata for this frame will not include the HdrChannel control. + Off = 0, + /// Multiple exposures will be generated in an alternating fashion. + /// + /// The multiple exposures will not be merged together and will be + /// returned to the application as they are. Each image will be tagged + /// with the correct HDR channel, indicating what kind of exposure it + /// is. The tag should be the same as in the HdrModeMultiExposure case. + /// + /// The expectation is that an application using this mode would merge + /// the frames to create HDR images for itself if it requires them. + MultiExposureUnmerged = 1, + /// Multiple exposures will be generated and merged to create HDR + /// images. + /// + /// Each image will be tagged with the HDR channel (long, medium or + /// short) that arrived and which caused this image to be output. + /// + /// Systems that use two channels for HDR will return images tagged + /// alternately as the short and long channel. Systems that use three + /// channels for HDR will cycle through the short, medium and long + /// channel before repeating. + MultiExposure = 2, + /// Multiple frames all at a single exposure will be used to create HDR + /// images. + /// + /// These images should be reported as all corresponding to the HDR + /// short channel. + SingleExposure = 3, + /// Multiple frames will be combined to produce "night mode" images. + /// + /// It is up to the implementation exactly which HDR channels it uses, + /// and the images will all be tagged accordingly with the correct HDR + /// channel information. + Night = 4, +} +impl TryFrom for HdrMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: HdrMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for HdrMode { + const ID: u32 = ControlId::HdrMode as _; +} +impl Control for HdrMode {} +/// The HDR channel used to capture the frame. +/// +/// This value is reported back to the application so that it can discover +/// whether this capture corresponds to the short or long exposure image +/// (or any other image used by the HDR procedure). An application can +/// monitor the HDR channel to discover when the differently exposed images +/// have arrived. +/// +/// This metadata is only available when an HDR mode has been enabled. +/// +/// \sa HdrMode +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum HdrChannel { + /// This image does not correspond to any of the captures used to create + /// an HDR image. + None = 0, + /// This is a short exposure image. + Short = 1, + /// This is a medium exposure image. + Medium = 2, + /// This is a long exposure image. + Long = 3, +} +impl TryFrom for HdrChannel { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: HdrChannel) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for HdrChannel { + const ID: u32 = ControlId::HdrChannel as _; +} +impl Control for HdrChannel {} +/// Specify a fixed gamma value. +/// +/// The default gamma value must be 2.2 which closely mimics sRGB gamma. +/// Note that this is camera gamma, so it is applied as 1.0/gamma. +#[derive(Debug, Clone)] +pub struct Gamma(pub f32); +impl Deref for Gamma { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Gamma { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Gamma { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Gamma) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Gamma { + const ID: u32 = ControlId::Gamma as _; +} +impl Control for Gamma {} +/// Enable or disable the debug metadata. +#[derive(Debug, Clone)] +pub struct DebugMetadataEnable(pub bool); +impl Deref for DebugMetadataEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for DebugMetadataEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for DebugMetadataEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: DebugMetadataEnable) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for DebugMetadataEnable { + const ID: u32 = ControlId::DebugMetadataEnable as _; +} +impl Control for DebugMetadataEnable {} +/// This timestamp corresponds to the same moment in time as the +/// SensorTimestamp, but is represented as a wall clock time as measured by +/// the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is +/// expressed in nanoseconds. +/// +/// Being a wall clock measurement, it can be used to synchronise timing +/// across different devices. +/// +/// \sa SensorTimestamp +/// +/// The FrameWallClock control can only be returned in metadata. +#[derive(Debug, Clone)] +pub struct FrameWallClock(pub i64); +impl Deref for FrameWallClock { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FrameWallClock { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FrameWallClock { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FrameWallClock) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FrameWallClock { + const ID: u32 = ControlId::FrameWallClock as _; +} +impl Control for FrameWallClock {} +/// Control for AE metering trigger. Currently identical to +/// ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. +/// +/// Whether the camera device will trigger a precapture metering sequence +/// when it processes this request. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AePrecaptureTrigger { + /// The trigger is idle. + Idle = 0, + /// The pre-capture AE metering is started by the camera. + Start = 1, + /// The camera will cancel any active or completed metering sequence. + /// The AE algorithm is reset to its initial state. + Cancel = 2, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for AePrecaptureTrigger { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: AePrecaptureTrigger) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for AePrecaptureTrigger { + const ID: u32 = ControlId::AePrecaptureTrigger as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for AePrecaptureTrigger {} +/// Control to select the noise reduction algorithm mode. Currently +/// identical to ANDROID_NOISE_REDUCTION_MODE. +/// +/// Mode of operation for the noise reduction algorithm. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum NoiseReductionMode { + /// No noise reduction is applied + Off = 0, + /// Noise reduction is applied without reducing the frame rate. + Fast = 1, + /// High quality noise reduction at the expense of frame rate. + HighQuality = 2, + /// Minimal noise reduction is applied without reducing the frame rate. + Minimal = 3, + /// Noise reduction is applied at different levels to different streams. + ZSL = 4, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for NoiseReductionMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: NoiseReductionMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for NoiseReductionMode { + const ID: u32 = ControlId::NoiseReductionMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for NoiseReductionMode {} +/// Control to select the color correction aberration mode. Currently +/// identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. +/// +/// Mode of operation for the chromatic aberration correction algorithm. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum ColorCorrectionAberrationMode { + /// No aberration correction is applied. + ColorCorrectionAberrationOff = 0, + /// Aberration correction will not slow down the frame rate. + ColorCorrectionAberrationFast = 1, + /// High quality aberration correction which might reduce the frame + /// rate. + ColorCorrectionAberrationHighQuality = 2, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for ColorCorrectionAberrationMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: ColorCorrectionAberrationMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for ColorCorrectionAberrationMode { + const ID: u32 = ControlId::ColorCorrectionAberrationMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for ColorCorrectionAberrationMode {} +/// Control to report the current AWB algorithm state. Currently identical +/// to ANDROID_CONTROL_AWB_STATE. +/// +/// Current state of the AWB algorithm. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AwbState { + /// The AWB algorithm is inactive. + Inactive = 0, + /// The AWB algorithm has not converged yet. + Searching = 1, + /// The AWB algorithm has converged. + AwbConverged = 2, + /// The AWB algorithm is locked. + AwbLocked = 3, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for AwbState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: AwbState) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for AwbState { + const ID: u32 = ControlId::AwbState as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for AwbState {} +/// Control to report the time between the start of exposure of the first +/// row and the start of exposure of the last row. Currently identical to +/// ANDROID_SENSOR_ROLLING_SHUTTER_SKEW +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct SensorRollingShutterSkew(pub i64); +#[cfg(feature = "vendor_draft")] +impl Deref for SensorRollingShutterSkew { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for SensorRollingShutterSkew { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for SensorRollingShutterSkew { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: SensorRollingShutterSkew) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for SensorRollingShutterSkew { + const ID: u32 = ControlId::SensorRollingShutterSkew as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for SensorRollingShutterSkew {} +/// Control to report if the lens shading map is available. Currently +/// identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum LensShadingMapMode { + /// No lens shading map mode is available. + Off = 0, + /// The lens shading map mode is available. + On = 1, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for LensShadingMapMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: LensShadingMapMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for LensShadingMapMode { + const ID: u32 = ControlId::LensShadingMapMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for LensShadingMapMode {} +/// Specifies the number of pipeline stages the frame went through from when +/// it was exposed to when the final completed result was available to the +/// framework. Always less than or equal to PipelineMaxDepth. Currently +/// identical to ANDROID_REQUEST_PIPELINE_DEPTH. +/// +/// The typical value for this control is 3 as a frame is first exposed, +/// captured and then processed in a single pass through the ISP. Any +/// additional processing step performed after the ISP pass (in example face +/// detection, additional format conversions etc) count as an additional +/// pipeline stage. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct PipelineDepth(pub i32); +#[cfg(feature = "vendor_draft")] +impl Deref for PipelineDepth { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for PipelineDepth { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for PipelineDepth { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: PipelineDepth) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for PipelineDepth { + const ID: u32 = ControlId::PipelineDepth as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for PipelineDepth {} +/// The maximum number of frames that can occur after a request (different +/// than the previous) has been submitted, and before the result's state +/// becomes synchronized. A value of -1 indicates unknown latency, and 0 +/// indicates per-frame control. Currently identical to +/// ANDROID_SYNC_MAX_LATENCY. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct MaxLatency(pub i32); +#[cfg(feature = "vendor_draft")] +impl Deref for MaxLatency { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for MaxLatency { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for MaxLatency { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: MaxLatency) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for MaxLatency { + const ID: u32 = ControlId::MaxLatency as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for MaxLatency {} +/// Control to select the test pattern mode. Currently identical to +/// ANDROID_SENSOR_TEST_PATTERN_MODE. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum TestPatternMode { + /// No test pattern mode is used. The camera device returns frames from + /// the image sensor. + Off = 0, + /// Each pixel in [R, G_even, G_odd, B] is replaced by its respective + /// color channel provided in test pattern data. + /// \todo Add control for test pattern data. + SolidColor = 1, + /// All pixel data is replaced with an 8-bar color pattern. The vertical + /// bars (left-to-right) are as follows; white, yellow, cyan, green, + /// magenta, red, blue and black. Each bar should take up 1/8 of the + /// sensor pixel array width. When this is not possible, the bar size + /// should be rounded down to the nearest integer and the pattern can + /// repeat on the right side. Each bar's height must always take up the + /// full sensor pixel array height. + ColorBars = 2, + /// The test pattern is similar to TestPatternModeColorBars, + /// except that each bar should start at its specified color at the top + /// and fade to gray at the bottom. Furthermore each bar is further + /// subdevided into a left and right half. The left half should have a + /// smooth gradient, and the right half should have a quantized + /// gradient. In particular, the right half's should consist of blocks + /// of the same color for 1/16th active sensor pixel array width. The + /// least significant bits in the quantized gradient should be copied + /// from the most significant bits of the smooth gradient. The height of + /// each bar should always be a multiple of 128. When this is not the + /// case, the pattern should repeat at the bottom of the image. + ColorBarsFadeToGray = 3, + /// All pixel data is replaced by a pseudo-random sequence generated + /// from a PN9 512-bit sequence (typically implemented in hardware with + /// a linear feedback shift register). The generator should be reset at + /// the beginning of each frame, and thus each subsequent raw frame with + /// this test pattern should be exactly the same as the last. + Pn9 = 4, + /// The first custom test pattern. All custom patterns that are + /// available only on this camera device are at least this numeric + /// value. All of the custom test patterns will be static (that is the + /// raw image must not vary from frame to frame). + Custom1 = 256, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for TestPatternMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: TestPatternMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for TestPatternMode { + const ID: u32 = ControlId::TestPatternMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for TestPatternMode {} +/// Control to select the face detection mode used by the pipeline. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. +/// +/// \sa FaceDetectFaceRectangles +/// \sa FaceDetectFaceScores +/// \sa FaceDetectFaceLandmarks +/// \sa FaceDetectFaceIds +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum FaceDetectMode { + /// Pipeline doesn't perform face detection and doesn't report any + /// control related to face detection. + Off = 0, + /// Pipeline performs face detection and reports the + /// FaceDetectFaceRectangles and FaceDetectFaceScores controls for each + /// detected face. FaceDetectFaceLandmarks and FaceDetectFaceIds are + /// optional. + Simple = 1, + /// Pipeline performs face detection and reports all the controls + /// related to face detection including FaceDetectFaceRectangles, + /// FaceDetectFaceScores, FaceDetectFaceLandmarks, and + /// FaceDeteceFaceIds for each detected face. + Full = 2, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectMode { + const ID: u32 = ControlId::FaceDetectMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectMode {} +/// Boundary rectangles of the detected faces. The number of values is +/// the number of detected faces. +/// +/// The FaceDetectFaceRectangles control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceRectangles(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceRectangles { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceRectangles { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceRectangles { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceRectangles) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceRectangles { + const ID: u32 = ControlId::FaceDetectFaceRectangles as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceRectangles {} +/// Confidence score of each of the detected faces. The range of score is +/// [0, 100]. The number of values should be the number of faces reported +/// in FaceDetectFaceRectangles. +/// +/// The FaceDetectFaceScores control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_SCORES. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceScores(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceScores { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceScores { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceScores { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceScores) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceScores { + const ID: u32 = ControlId::FaceDetectFaceScores as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceScores {} +/// Array of human face landmark coordinates in format [..., left_eye_i, +/// right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The +/// number of values should be 3 * the number of faces reported in +/// FaceDetectFaceRectangles. +/// +/// The FaceDetectFaceLandmarks control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceLandmarks(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceLandmarks { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceLandmarks { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceLandmarks { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceLandmarks) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceLandmarks { + const ID: u32 = ControlId::FaceDetectFaceLandmarks as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceLandmarks {} +/// Each detected face is given a unique ID that is valid for as long as the +/// face is visible to the camera device. A face that leaves the field of +/// view and later returns may be assigned a new ID. The number of values +/// should be the number of faces reported in FaceDetectFaceRectangles. +/// +/// The FaceDetectFaceIds control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_IDS. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceIds(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceIds { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceIds { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceIds { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceIds) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceIds { + const ID: u32 = ControlId::FaceDetectFaceIds as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceIds {} +/// Toggles the Raspberry Pi IPA to output the hardware generated statistics. +/// +/// When this control is set to true, the IPA outputs a binary dump of the +/// hardware generated statistics through the Request metadata in the +/// Bcm2835StatsOutput control. +/// +/// \sa Bcm2835StatsOutput +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct StatsOutputEnable(pub bool); +#[cfg(feature = "vendor_rpi")] +impl Deref for StatsOutputEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for StatsOutputEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for StatsOutputEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: StatsOutputEnable) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for StatsOutputEnable { + const ID: u32 = ControlId::StatsOutputEnable as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for StatsOutputEnable {} +/// Span of the BCM2835 ISP generated statistics for the current frame. +/// +/// This is sent in the Request metadata if the StatsOutputEnable is set to +/// true. The statistics struct definition can be found in +/// include/linux/bcm2835-isp.h. +/// +/// \sa StatsOutputEnable +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct Bcm2835StatsOutput(pub Vec); +#[cfg(feature = "vendor_rpi")] +impl Deref for Bcm2835StatsOutput { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for Bcm2835StatsOutput { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for Bcm2835StatsOutput { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: Bcm2835StatsOutput) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for Bcm2835StatsOutput { + const ID: u32 = ControlId::Bcm2835StatsOutput as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for Bcm2835StatsOutput {} +/// An array of rectangles, where each singular value has identical +/// functionality to the ScalerCrop control. This control allows the +/// Raspberry Pi pipeline handler to control individual scaler crops per +/// output stream. +/// +/// The order of rectangles passed into the control must match the order of +/// streams configured by the application. The pipeline handler will only +/// configure crop retangles up-to the number of output streams configured. +/// All subsequent rectangles passed into this control are ignored by the +/// pipeline handler. +/// +/// If both rpi::ScalerCrops and ScalerCrop controls are present in a +/// ControlList, the latter is discarded, and crops are obtained from this +/// control. +/// +/// Note that using different crop rectangles for each output stream with +/// this control is only applicable on the Pi5/PiSP platform. This control +/// should also be considered temporary/draft and will be replaced with +/// official libcamera API support for per-stream controls in the future. +/// +/// \sa ScalerCrop +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct ScalerCrops(pub Vec); +#[cfg(feature = "vendor_rpi")] +impl Deref for ScalerCrops { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for ScalerCrops { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for ScalerCrops { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: ScalerCrops) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for ScalerCrops { + const ID: u32 = ControlId::ScalerCrops as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for ScalerCrops {} +/// Span of the PiSP Frontend ISP generated statistics for the current +/// frame. This is sent in the Request metadata if the StatsOutputEnable is +/// set to true. The statistics struct definition can be found in +/// https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h +/// +/// \sa StatsOutputEnable +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct PispStatsOutput(pub Vec); +#[cfg(feature = "vendor_rpi")] +impl Deref for PispStatsOutput { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for PispStatsOutput { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for PispStatsOutput { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: PispStatsOutput) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for PispStatsOutput { + const ID: u32 = ControlId::PispStatsOutput as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for PispStatsOutput {} +/// Enable or disable camera synchronisation ("sync") mode. +/// +/// When sync mode is enabled, a camera will synchronise frames temporally +/// with other cameras, either attached to the same device or a different +/// one. There should be one "server" device, which broadcasts timing +/// information to one or more "clients". Communication is one-way, from +/// server to clients only, and it is only clients that adjust their frame +/// timings to match the server. +/// +/// Sync mode requires all cameras to be running at (as far as possible) the +/// same fixed framerate. Clients may continue to make adjustments to keep +/// their cameras synchronised with the server for the duration of the +/// session, though any updates after the initial ones should remain small. +/// +/// \sa SyncReady +/// \sa SyncTimer +/// \sa SyncFrames +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum SyncMode { + /// Disable sync mode. + Off = 0, + /// Enable sync mode, act as server. The server broadcasts timing + /// messages to any clients that are listening, so that the clients can + /// synchronise their camera frames with the server's. + Server = 1, + /// Enable sync mode, act as client. A client listens for any server + /// messages, and arranges for its camera frames to synchronise as + /// closely as possible with the server's. Many clients can listen out + /// for the same server. Clients can also be started ahead of any + /// servers, causing them merely to wait for the server to start. + Client = 2, +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncMode { + const ID: u32 = ControlId::SyncMode as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncMode {} +/// When using the camera synchronisation algorithm, the server broadcasts +/// timing information to the clients. This also includes the time (some +/// number of frames in the future, called the "ready time") at which the +/// server will signal its controlling application, using this control, to +/// start using the image frames. +/// +/// The client receives the "ready time" from the server, and will signal +/// its application to start using the frames at this same moment. +/// +/// While this control value is false, applications (on both client and +/// server) should continue to wait, and not use the frames. +/// +/// Once this value becomes true, it means that this is the first frame +/// where the server and its clients have agreed that they will both be +/// synchronised and that applications should begin consuming frames. +/// Thereafter, this control will continue to signal the value true for +/// the rest of the session. +/// +/// \sa SyncMode +/// \sa SyncTimer +/// \sa SyncFrames +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct SyncReady(pub bool); +#[cfg(feature = "vendor_rpi")] +impl Deref for SyncReady { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for SyncReady { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncReady { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncReady) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncReady { + const ID: u32 = ControlId::SyncReady as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncReady {} +/// This reports the amount of time, in microseconds, until the "ready +/// time", at which the server and client will signal their controlling +/// applications that the frames are now synchronised and should be +/// used. The value may be refined slightly over time, becoming more precise +/// as the "ready time" approaches. +/// +/// Servers always report this value, whereas clients will omit this control +/// until they have received a message from the server that enables them to +/// calculate it. +/// +/// Normally the value will start positive (the "ready time" is in the +/// future), and decrease towards zero, before becoming negative (the "ready +/// time" has elapsed). So there should be just one frame where the timer +/// value is, or is very close to, zero - the one for which the SyncReady +/// control becomes true. At this moment, the value indicates how closely +/// synchronised the client believes it is with the server. +/// +/// But note that if frames are being dropped, then the "near zero" valued +/// frame, or indeed any other, could be skipped. In these cases the timer +/// value allows an application to deduce that this has happened. +/// +/// \sa SyncMode +/// \sa SyncReady +/// \sa SyncFrames +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct SyncTimer(pub i64); +#[cfg(feature = "vendor_rpi")] +impl Deref for SyncTimer { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for SyncTimer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncTimer { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncTimer) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncTimer { + const ID: u32 = ControlId::SyncTimer as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncTimer {} +/// The number of frames the server should wait, after enabling +/// SyncModeServer, before signalling (via the SyncReady control) that +/// frames should be used. This therefore determines the "ready time" for +/// all synchronised cameras. +/// +/// This control value should be set only for the device that is to act as +/// the server, before or at the same moment at which SyncModeServer is +/// enabled. +/// +/// \sa SyncMode +/// \sa SyncReady +/// \sa SyncTimer +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct SyncFrames(pub i32); +#[cfg(feature = "vendor_rpi")] +impl Deref for SyncFrames { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for SyncFrames { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncFrames { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncFrames) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncFrames { + const ID: u32 = ControlId::SyncFrames as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncFrames {} +pub fn make_dyn( + id: ControlId, + val: ControlValue, +) -> Result, ControlValueError> { + match id { + ControlId::AeEnable => Ok(Box::new(AeEnable::try_from(val)?)), + ControlId::AeState => Ok(Box::new(AeState::try_from(val)?)), + ControlId::AeMeteringMode => Ok(Box::new(AeMeteringMode::try_from(val)?)), + ControlId::AeConstraintMode => Ok(Box::new(AeConstraintMode::try_from(val)?)), + ControlId::AeExposureMode => Ok(Box::new(AeExposureMode::try_from(val)?)), + ControlId::ExposureValue => Ok(Box::new(ExposureValue::try_from(val)?)), + ControlId::ExposureTime => Ok(Box::new(ExposureTime::try_from(val)?)), + ControlId::ExposureTimeMode => Ok(Box::new(ExposureTimeMode::try_from(val)?)), + ControlId::AnalogueGain => Ok(Box::new(AnalogueGain::try_from(val)?)), + ControlId::AnalogueGainMode => Ok(Box::new(AnalogueGainMode::try_from(val)?)), + ControlId::AeFlickerMode => Ok(Box::new(AeFlickerMode::try_from(val)?)), + ControlId::AeFlickerPeriod => Ok(Box::new(AeFlickerPeriod::try_from(val)?)), + ControlId::AeFlickerDetected => Ok(Box::new(AeFlickerDetected::try_from(val)?)), + ControlId::Brightness => Ok(Box::new(Brightness::try_from(val)?)), + ControlId::Contrast => Ok(Box::new(Contrast::try_from(val)?)), + ControlId::Lux => Ok(Box::new(Lux::try_from(val)?)), + ControlId::AwbEnable => Ok(Box::new(AwbEnable::try_from(val)?)), + ControlId::AwbMode => Ok(Box::new(AwbMode::try_from(val)?)), + ControlId::AwbLocked => Ok(Box::new(AwbLocked::try_from(val)?)), + ControlId::ColourGains => Ok(Box::new(ColourGains::try_from(val)?)), + ControlId::ColourTemperature => Ok(Box::new(ColourTemperature::try_from(val)?)), + ControlId::Saturation => Ok(Box::new(Saturation::try_from(val)?)), + ControlId::SensorBlackLevels => Ok(Box::new(SensorBlackLevels::try_from(val)?)), + ControlId::Sharpness => Ok(Box::new(Sharpness::try_from(val)?)), + ControlId::FocusFoM => Ok(Box::new(FocusFoM::try_from(val)?)), + ControlId::ColourCorrectionMatrix => { + Ok(Box::new(ColourCorrectionMatrix::try_from(val)?)) + } + ControlId::ScalerCrop => Ok(Box::new(ScalerCrop::try_from(val)?)), + ControlId::DigitalGain => Ok(Box::new(DigitalGain::try_from(val)?)), + ControlId::FrameDuration => Ok(Box::new(FrameDuration::try_from(val)?)), + ControlId::FrameDurationLimits => { + Ok(Box::new(FrameDurationLimits::try_from(val)?)) + } + ControlId::SensorTemperature => Ok(Box::new(SensorTemperature::try_from(val)?)), + ControlId::SensorTimestamp => Ok(Box::new(SensorTimestamp::try_from(val)?)), + ControlId::AfMode => Ok(Box::new(AfMode::try_from(val)?)), + ControlId::AfRange => Ok(Box::new(AfRange::try_from(val)?)), + ControlId::AfSpeed => Ok(Box::new(AfSpeed::try_from(val)?)), + ControlId::AfMetering => Ok(Box::new(AfMetering::try_from(val)?)), + ControlId::AfWindows => Ok(Box::new(AfWindows::try_from(val)?)), + ControlId::AfTrigger => Ok(Box::new(AfTrigger::try_from(val)?)), + ControlId::AfPause => Ok(Box::new(AfPause::try_from(val)?)), + ControlId::LensPosition => Ok(Box::new(LensPosition::try_from(val)?)), + ControlId::AfState => Ok(Box::new(AfState::try_from(val)?)), + ControlId::AfPauseState => Ok(Box::new(AfPauseState::try_from(val)?)), + ControlId::HdrMode => Ok(Box::new(HdrMode::try_from(val)?)), + ControlId::HdrChannel => Ok(Box::new(HdrChannel::try_from(val)?)), + ControlId::Gamma => Ok(Box::new(Gamma::try_from(val)?)), + ControlId::DebugMetadataEnable => { + Ok(Box::new(DebugMetadataEnable::try_from(val)?)) + } + ControlId::FrameWallClock => Ok(Box::new(FrameWallClock::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::AePrecaptureTrigger => { + Ok(Box::new(AePrecaptureTrigger::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::NoiseReductionMode => Ok(Box::new(NoiseReductionMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::ColorCorrectionAberrationMode => { + Ok(Box::new(ColorCorrectionAberrationMode::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::AwbState => Ok(Box::new(AwbState::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::SensorRollingShutterSkew => { + Ok(Box::new(SensorRollingShutterSkew::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::LensShadingMapMode => Ok(Box::new(LensShadingMapMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::PipelineDepth => Ok(Box::new(PipelineDepth::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::MaxLatency => Ok(Box::new(MaxLatency::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::TestPatternMode => Ok(Box::new(TestPatternMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectMode => Ok(Box::new(FaceDetectMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceRectangles => { + Ok(Box::new(FaceDetectFaceRectangles::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceScores => { + Ok(Box::new(FaceDetectFaceScores::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceLandmarks => { + Ok(Box::new(FaceDetectFaceLandmarks::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceIds => Ok(Box::new(FaceDetectFaceIds::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::StatsOutputEnable => Ok(Box::new(StatsOutputEnable::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::Bcm2835StatsOutput => Ok(Box::new(Bcm2835StatsOutput::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::ScalerCrops => Ok(Box::new(ScalerCrops::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::PispStatsOutput => Ok(Box::new(PispStatsOutput::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncMode => Ok(Box::new(SyncMode::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncReady => Ok(Box::new(SyncReady::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncTimer => Ok(Box::new(SyncTimer::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncFrames => Ok(Box::new(SyncFrames::try_from(val)?)), + } +} diff --git a/libcamera/versioned_files/0.5.2/pixel_format_info.rs b/libcamera/versioned_files/0.5.2/pixel_format_info.rs new file mode 100644 index 0000000..16d3ddb --- /dev/null +++ b/libcamera/versioned_files/0.5.2/pixel_format_info.rs @@ -0,0 +1,103 @@ + +// Auto-generated from libcamera/src/libcamera/formats.cpp +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatPlaneInfoData { + pub bytes_per_group: u32, + pub vertical_sub_sampling: u32, +} + +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatInfoData { + pub name: &'static str, + pub fourcc: u32, + pub modifier: u64, + pub bits_per_pixel: u32, + pub colour_encoding: u8, + pub packed: bool, + pub pixels_per_group: u32, + pub planes: &'static [PixelFormatPlaneInfoData], + pub v4l2_formats: &'static [u32], +} + +pub(crate) static PIXEL_FORMAT_INFO: &[PixelFormatInfoData] = &[ + PixelFormatInfoData { name: "RGB565", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50424752], }, + PixelFormatInfoData { name: "RGB565_BE", fourcc: 0xb6314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52424752], }, + PixelFormatInfoData { name: "BGR888", fourcc: 0x34324742, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33424752], }, + PixelFormatInfoData { name: "RGB888", fourcc: 0x34324752, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33524742], }, + PixelFormatInfoData { name: "XRGB8888", fourcc: 0x34325258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325258], }, + PixelFormatInfoData { name: "XBGR8888", fourcc: 0x34324258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324258], }, + PixelFormatInfoData { name: "RGBX8888", fourcc: 0x34325852, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325852], }, + PixelFormatInfoData { name: "BGRX8888", fourcc: 0x34325842, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325842], }, + PixelFormatInfoData { name: "ABGR8888", fourcc: 0x34324241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324241], }, + PixelFormatInfoData { name: "ARGB8888", fourcc: 0x34325241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325241], }, + PixelFormatInfoData { name: "BGRA8888", fourcc: 0x34324142, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324142], }, + PixelFormatInfoData { name: "RGBA8888", fourcc: 0x34324152, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324152], }, + PixelFormatInfoData { name: "BGR161616", fourcc: 0x38344742, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36424752], }, + PixelFormatInfoData { name: "RGB161616", fourcc: 0x38344752, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36524742], }, + PixelFormatInfoData { name: "YUYV", fourcc: 0x56595559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x56595559], }, + PixelFormatInfoData { name: "YVYU", fourcc: 0x55595659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x55595659], }, + PixelFormatInfoData { name: "UYVY", fourcc: 0x59565955, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59565955], }, + PixelFormatInfoData { name: "VYUY", fourcc: 0x59555956, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59555956], }, + PixelFormatInfoData { name: "AVUY8888", fourcc: 0x59555641, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41565559], }, + PixelFormatInfoData { name: "XVUY8888", fourcc: 0x59555658, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x58565559], }, + PixelFormatInfoData { name: "NV12", fourcc: 0x3231564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3231564e, 0x32314d4e], }, + PixelFormatInfoData { name: "NV21", fourcc: 0x3132564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3132564e, 0x31324d4e], }, + PixelFormatInfoData { name: "NV16", fourcc: 0x3631564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3631564e, 0x36314d4e], }, + PixelFormatInfoData { name: "NV61", fourcc: 0x3136564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3136564e, 0x31364d4e], }, + PixelFormatInfoData { name: "NV24", fourcc: 0x3432564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3432564e], }, + PixelFormatInfoData { name: "NV42", fourcc: 0x3234564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3234564e], }, + PixelFormatInfoData { name: "YUV420", fourcc: 0x32315559, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315559, 0x32314d59], }, + PixelFormatInfoData { name: "YVU420", fourcc: 0x32315659, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315659, 0x31324d59], }, + PixelFormatInfoData { name: "YUV422", fourcc: 0x36315559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323234, 0x36314d59], }, + PixelFormatInfoData { name: "YVU422", fourcc: 0x36315659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31364d59], }, + PixelFormatInfoData { name: "YUV444", fourcc: 0x34325559, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324d59], }, + PixelFormatInfoData { name: "YVU444", fourcc: 0x34325659, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32344d59], }, + PixelFormatInfoData { name: "R8", fourcc: 0x20203852, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59455247], }, + PixelFormatInfoData { name: "R10", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20303159], }, + PixelFormatInfoData { name: "R10_CSI2P", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50303159], }, + PixelFormatInfoData { name: "R12_CSI2P", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323159], }, + PixelFormatInfoData { name: "R12", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20323159], }, + PixelFormatInfoData { name: "R16", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20363159], }, + PixelFormatInfoData { name: "MONO_PISP_COMP1", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: true, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x4d314350], }, + PixelFormatInfoData { name: "SBGGR8", fourcc: 0x31384142, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31384142], }, + PixelFormatInfoData { name: "SGBRG8", fourcc: 0x47524247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47524247], }, + PixelFormatInfoData { name: "SGRBG8", fourcc: 0x47425247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47425247], }, + PixelFormatInfoData { name: "SRGGB8", fourcc: 0x42474752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42474752], }, + PixelFormatInfoData { name: "SBGGR10", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314742], }, + PixelFormatInfoData { name: "SGBRG10", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314247], }, + PixelFormatInfoData { name: "SGRBG10", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314142], }, + PixelFormatInfoData { name: "SRGGB10", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314752], }, + PixelFormatInfoData { name: "SBGGR10_CSI2P", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414270], }, + PixelFormatInfoData { name: "SGBRG10_CSI2P", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414770], }, + PixelFormatInfoData { name: "SGRBG10_CSI2P", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41416770], }, + PixelFormatInfoData { name: "SRGGB10_CSI2P", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41415270], }, + PixelFormatInfoData { name: "SBGGR12", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314742], }, + PixelFormatInfoData { name: "SGBRG12", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314247], }, + PixelFormatInfoData { name: "SGRBG12", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314142], }, + PixelFormatInfoData { name: "SRGGB12", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314752], }, + PixelFormatInfoData { name: "SBGGR12_CSI2P", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434270], }, + PixelFormatInfoData { name: "SGBRG12_CSI2P", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434770], }, + PixelFormatInfoData { name: "SGRBG12_CSI2P", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43436770], }, + PixelFormatInfoData { name: "SRGGB12_CSI2P", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43435270], }, + PixelFormatInfoData { name: "SBGGR14", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314742], }, + PixelFormatInfoData { name: "SGBRG14", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314247], }, + PixelFormatInfoData { name: "SGRBG14", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34315247], }, + PixelFormatInfoData { name: "SRGGB14", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314752], }, + PixelFormatInfoData { name: "SBGGR14_CSI2P", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454270], }, + PixelFormatInfoData { name: "SGBRG14_CSI2P", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454770], }, + PixelFormatInfoData { name: "SGRBG14_CSI2P", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45456770], }, + PixelFormatInfoData { name: "SRGGB14_CSI2P", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45455270], }, + PixelFormatInfoData { name: "SBGGR16", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32525942], }, + PixelFormatInfoData { name: "SGBRG16", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314247], }, + PixelFormatInfoData { name: "SGRBG16", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36315247], }, + PixelFormatInfoData { name: "SRGGB16", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314752], }, + PixelFormatInfoData { name: "SBGGR10_IPU3", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x62337069], }, + PixelFormatInfoData { name: "SGBRG10_IPU3", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67337069], }, + PixelFormatInfoData { name: "SGRBG10_IPU3", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47337069], }, + PixelFormatInfoData { name: "SRGGB10_IPU3", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x72337069], }, + PixelFormatInfoData { name: "BGGR_PISP_COMP1", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42314350], }, + PixelFormatInfoData { name: "GBRG_PISP_COMP1", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67314350], }, + PixelFormatInfoData { name: "GRBG_PISP_COMP1", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47314350], }, + PixelFormatInfoData { name: "RGGB_PISP_COMP1", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52314350], }, + PixelFormatInfoData { name: "MJPEG", fourcc: 0x47504a4d, modifier: 0x0000000000000000, bits_per_pixel: 0, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47504a4d, 0x4745504a], }, +]; diff --git a/libcamera/versioned_files/0.5.2/properties.rs b/libcamera/versioned_files/0.5.2/properties.rs new file mode 100644 index 0000000..e373566 --- /dev/null +++ b/libcamera/versioned_files/0.5.2/properties.rs @@ -0,0 +1,2443 @@ +use std::ops::{Deref, DerefMut}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +#[allow(unused_imports)] +use crate::control::{Control, Property, ControlEntry, DynControlEntry}; +use crate::control_value::{ControlValue, ControlValueError}; +#[allow(unused_imports)] +use crate::geometry::{Rectangle, Point, Size}; +#[allow(unused_imports)] +use libcamera_sys::*; +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(u32)] +pub enum PropertyId { + /// Camera mounting location + Location = LOCATION, + /// The camera physical mounting rotation. It is expressed as the angular + /// difference in degrees between two reference systems, one relative to the + /// camera module, and one defined on the external world scene to be + /// captured when projected on the image sensor pixel array. + /// + /// A camera sensor has a 2-dimensional reference system 'Rc' defined by + /// its pixel array read-out order. The origin is set to the first pixel + /// being read out, the X-axis points along the column read-out direction + /// towards the last columns, and the Y-axis along the row read-out + /// direction towards the last row. + /// + /// A typical example for a sensor with a 2592x1944 pixel array matrix + /// observed from the front is + /// + /// ```text + /// 2591 X-axis 0 + /// <------------------------+ 0 + /// .......... ... ..........! + /// .......... ... ..........! Y-axis + /// ... ! + /// .......... ... ..........! + /// .......... ... ..........! 1943 + /// V + /// ``` + /// + /// + /// The external world scene reference system 'Rs' is a 2-dimensional + /// reference system on the focal plane of the camera module. The origin is + /// placed on the top-left corner of the visible scene, the X-axis points + /// towards the right, and the Y-axis points towards the bottom of the + /// scene. The top, bottom, left and right directions are intentionally not + /// defined and depend on the environment in which the camera is used. + /// + /// A typical example of a (very common) picture of a shark swimming from + /// left to right, as seen from the camera, is + /// + /// ```text + /// 0 X-axis + /// 0 +-------------------------------------> + /// ! + /// ! + /// ! + /// ! |\____)\___ + /// ! ) _____ __`< + /// ! |/ )/ + /// ! + /// ! + /// ! + /// V + /// Y-axis + /// ``` + /// + /// With the reference system 'Rs' placed on the camera focal plane. + /// + /// ```text + /// ¸.·˙! + /// ¸.·˙ ! + /// _ ¸.·˙ ! + /// +-/ \-+¸.·˙ ! + /// | (o) | ! Camera focal plane + /// +-----+˙·.¸ ! + /// ˙·.¸ ! + /// ˙·.¸ ! + /// ˙·.¸! + /// ``` + /// + /// When projected on the sensor's pixel array, the image and the associated + /// reference system 'Rs' are typically (but not always) inverted, due to + /// the camera module's lens optical inversion effect. + /// + /// Assuming the above represented scene of the swimming shark, the lens + /// inversion projects the scene and its reference system onto the sensor + /// pixel array, seen from the front of the camera sensor, as follow + /// + /// ```text + /// Y-axis + /// ^ + /// ! + /// ! + /// ! + /// ! |\_____)\__ + /// ! ) ____ ___.< + /// ! |/ )/ + /// ! + /// ! + /// ! + /// 0 +-------------------------------------> + /// 0 X-axis + /// ``` + /// + /// Note the shark being upside-down. + /// + /// The resulting projected reference system is named 'Rp'. + /// + /// The camera rotation property is then defined as the angular difference + /// in the counter-clockwise direction between the camera reference system + /// 'Rc' and the projected scene reference system 'Rp'. It is expressed in + /// degrees as a number in the range [0, 360[. + /// + /// Examples + /// + /// 0 degrees camera rotation + /// + /// + /// ```text + /// Y-Rp + /// ^ + /// Y-Rc ! + /// ^ ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// 0 +-------------------------------------> + /// 0 X-Rc + /// ``` + /// + /// + /// ```text + /// X-Rc 0 + /// <------------------------------------+ 0 + /// X-Rp 0 ! + /// <------------------------------------+ 0 ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rc + /// V + /// Y-Rp + /// ``` + /// + /// 90 degrees camera rotation + /// + /// ```text + /// 0 Y-Rc + /// 0 +--------------------> + /// ! Y-Rp + /// ! ^ + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// ! + /// ! + /// ! + /// ! + /// V + /// X-Rc + /// ``` + /// + /// 180 degrees camera rotation + /// + /// ```text + /// 0 + /// <------------------------------------+ 0 + /// X-Rc ! + /// Y-Rp ! + /// ^ ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rc + /// 0 +-------------------------------------> + /// 0 X-Rp + /// ``` + /// + /// 270 degrees camera rotation + /// + /// ```text + /// 0 Y-Rc + /// 0 +--------------------> + /// ! 0 + /// ! <-----------------------------------+ 0 + /// ! X-Rp ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rp + /// ! + /// ! + /// ! + /// ! + /// V + /// X-Rc + /// ``` + /// + /// + /// Example one - Webcam + /// + /// A camera module installed on the user facing part of a laptop screen + /// casing used for video calls. The captured images are meant to be + /// displayed in landscape mode (width > height) on the laptop screen. + /// + /// The camera is typically mounted upside-down to compensate the lens + /// optical inversion effect. + /// + /// ```text + /// Y-Rp + /// Y-Rc ^ + /// ^ ! + /// ! ! + /// ! ! |\_____)\__ + /// ! ! ) ____ ___.< + /// ! ! |/ )/ + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// 0 +-------------------------------------> + /// 0 X-Rc + /// ``` + /// + /// The two reference systems are aligned, the resulting camera rotation is + /// 0 degrees, no rotation correction needs to be applied to the resulting + /// image once captured to memory buffers to correctly display it to users. + /// + /// ```text + /// +--------------------------------------+ + /// ! ! + /// ! ! + /// ! ! + /// ! |\____)\___ ! + /// ! ) _____ __`< ! + /// ! |/ )/ ! + /// ! ! + /// ! ! + /// ! ! + /// +--------------------------------------+ + /// ``` + /// + /// If the camera sensor is not mounted upside-down to compensate for the + /// lens optical inversion, the two reference systems will not be aligned, + /// with 'Rp' being rotated 180 degrees relatively to 'Rc'. + /// + /// + /// ```text + /// X-Rc 0 + /// <------------------------------------+ 0 + /// ! + /// Y-Rp ! + /// ^ ! + /// ! ! + /// ! |\_____)\__ ! + /// ! ) ____ ___.< ! + /// ! |/ )/ ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rc + /// 0 +-------------------------------------> + /// 0 X-Rp + /// ``` + /// + /// The image once captured to memory will then be rotated by 180 degrees + /// + /// ```text + /// +--------------------------------------+ + /// ! ! + /// ! ! + /// ! ! + /// ! __/(_____/| ! + /// ! >.___ ____ ( ! + /// ! \( \| ! + /// ! ! + /// ! ! + /// ! ! + /// +--------------------------------------+ + /// ``` + /// + /// A software rotation correction of 180 degrees should be applied to + /// correctly display the image. + /// + /// ```text + /// +--------------------------------------+ + /// ! ! + /// ! ! + /// ! ! + /// ! |\____)\___ ! + /// ! ) _____ __`< ! + /// ! |/ )/ ! + /// ! ! + /// ! ! + /// ! ! + /// +--------------------------------------+ + /// ``` + /// + /// Example two - Phone camera + /// + /// A camera installed on the back side of a mobile device facing away from + /// the user. The captured images are meant to be displayed in portrait mode + /// (height > width) to match the device screen orientation and the device + /// usage orientation used when taking the picture. + /// + /// The camera sensor is typically mounted with its pixel array longer side + /// aligned to the device longer side, upside-down mounted to compensate for + /// the lens optical inversion effect. + /// + /// ```text + /// 0 Y-Rc + /// 0 +--------------------> + /// ! Y-Rp + /// ! ^ + /// ! ! + /// ! ! + /// ! ! + /// ! ! |\_____)\__ + /// ! ! ) ____ ___.< + /// ! ! |/ )/ + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// ! + /// ! + /// ! + /// ! + /// V + /// X-Rc + /// ``` + /// + /// The two reference systems are not aligned and the 'Rp' reference + /// system is rotated by 90 degrees in the counter-clockwise direction + /// relatively to the 'Rc' reference system. + /// + /// The image once captured to memory will be rotated. + /// + /// ```text + /// +-------------------------------------+ + /// | _ _ | + /// | \ / | + /// | | | | + /// | | | | + /// | | > | + /// | < | | + /// | | | | + /// | . | + /// | V | + /// +-------------------------------------+ + /// ``` + /// + /// A correction of 90 degrees in counter-clockwise direction has to be + /// applied to correctly display the image in portrait mode on the device + /// screen. + /// + /// ```text + /// +--------------------+ + /// | | + /// | | + /// | | + /// | | + /// | | + /// | | + /// | |\____)\___ | + /// | ) _____ __`< | + /// | |/ )/ | + /// | | + /// | | + /// | | + /// | | + /// | | + /// +--------------------+ + Rotation = ROTATION, + /// The model name shall to the extent possible describe the sensor. For + /// most devices this is the model name of the sensor. While for some + /// devices the sensor model is unavailable as the sensor or the entire + /// camera is part of a larger unit and exposed as a black-box to the + /// system. In such cases the model name of the smallest device that + /// contains the camera sensor shall be used. + /// + /// The model name is not meant to be a camera name displayed to the + /// end-user, but may be combined with other camera information to create a + /// camera name. + /// + /// The model name is not guaranteed to be unique in the system nor is + /// it guaranteed to be stable or have any other properties required to make + /// it a good candidate to be used as a permanent identifier of a camera. + /// + /// The model name shall describe the camera in a human readable format and + /// shall be encoded in ASCII. + /// + /// Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. + Model = MODEL, + /// The pixel unit cell physical size, in nanometers. + /// + /// The UnitCellSize properties defines the horizontal and vertical sizes of + /// a single pixel unit, including its active and non-active parts. In + /// other words, it expresses the horizontal and vertical distance between + /// the top-left corners of adjacent pixels. + /// + /// The property can be used to calculate the physical size of the sensor's + /// pixel array area and for calibration purposes. + UnitCellSize = UNIT_CELL_SIZE, + /// The camera sensor pixel array readable area vertical and horizontal + /// sizes, in pixels. + /// + /// The PixelArraySize property defines the size in pixel units of the + /// readable part of full pixel array matrix, including optical black + /// pixels used for calibration, pixels which are not considered valid for + /// capture and active pixels containing valid image data. + /// + /// The property describes the maximum size of the raw data captured by the + /// camera, which might not correspond to the physical size of the sensor + /// pixel array matrix, as some portions of the physical pixel array matrix + /// are not accessible and cannot be transmitted out. + /// + /// For example, let's consider a pixel array matrix assembled as follows + /// + /// ```text + /// +--------------------------------------------------+ + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// ... ... ... ... ... + /// ``` + /// + /// ```text + /// ... ... ... ... ... + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// +--------------------------------------------------+ + /// ``` + /// + /// starting with two lines of non-readable pixels (x), followed by N lines + /// of readable data (D) surrounded by two columns of non-readable pixels on + /// each side, and ending with two more lines of non-readable pixels. Only + /// the readable portion is transmitted to the receiving side, defining the + /// sizes of the largest possible buffer of raw data that can be presented + /// to applications. + /// + /// ```text + /// PixelArraySize.width + /// /----------------------------------------------/ + /// +----------------------------------------------+ / + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + /// ... ... ... ... ... + /// ... ... ... ... ... + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// +----------------------------------------------+ / + /// ``` + /// + /// This defines a rectangle whose top-left corner is placed in position (0, + /// 0) and whose vertical and horizontal sizes are defined by this property. + /// All other rectangles that describe portions of the pixel array, such as + /// the optical black pixels rectangles and active pixel areas, are defined + /// relatively to this rectangle. + /// + /// All the coordinates are expressed relative to the default sensor readout + /// direction, without any transformation (such as horizontal and vertical + /// flipping) applied. When mapping them to the raw pixel buffer, + /// applications shall take any configured transformation into account. + /// + /// \todo Rename this property to Size once we will have property + /// ```text + /// categories (i.e. Properties::PixelArray::Size) + PixelArraySize = PIXEL_ARRAY_SIZE, + /// The pixel array region(s) which contain optical black pixels + /// considered valid for calibration purposes. + /// + /// This property describes the position and size of optical black pixel + /// regions in the raw data buffer as stored in memory, which might differ + /// from their actual physical location in the pixel array matrix. + /// + /// It is important to note, in fact, that camera sensors might + /// automatically reorder or skip portions of their pixels array matrix when + /// transmitting data to the receiver. For instance, a sensor may merge the + /// top and bottom optical black rectangles into a single rectangle, + /// transmitted at the beginning of the frame. + /// + /// The pixel array contains several areas with different purposes, + /// interleaved by lines and columns which are said not to be valid for + /// capturing purposes. Invalid lines and columns are defined as invalid as + /// they could be positioned too close to the chip margins or to the optical + /// black shielding placed on top of optical black pixels. + /// + /// ```text + /// PixelArraySize.width + /// /----------------------------------------------/ + /// x1 x2 + /// +--o---------------------------------------o---+ / + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + /// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + /// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + /// ... ... ... ... ... + /// ... ... ... ... ... + /// y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// +----------------------------------------------+ / + /// ``` + /// + /// The readable pixel array matrix is composed by + /// 2 invalid lines (I) + /// 4 lines of valid optical black pixels (O) + /// 2 invalid lines (I) + /// n lines of valid pixel data (P) + /// 2 invalid lines (I) + /// + /// And the position of the optical black pixel rectangles is defined by + /// + /// ```text + /// PixelArrayOpticalBlackRectangles = { + /// { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + /// { x1, y3, 2, y4 - y3 + 1 }, + /// { x2, y3, 2, y4 - y3 + 1 }, + /// }; + /// ``` + /// + /// If the camera, when capturing the full pixel array matrix, automatically + /// skips the invalid lines and columns, producing the following data + /// buffer, when captured to memory + /// + /// ```text + /// PixelArraySize.width + /// /----------------------------------------------/ + /// x1 + /// +--------------------------------------------o-+ / + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + /// ... ... ... ... ... | + /// ... ... ... ... ... | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// +----------------------------------------------+ / + /// ``` + /// + /// then the invalid lines and columns should not be reported as part of the + /// PixelArraySize property in first place. + /// + /// In this case, the position of the black pixel rectangles will be + /// + /// ```text + /// PixelArrayOpticalBlackRectangles = { + /// { 0, 0, y1 + 1, PixelArraySize[0] }, + /// { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + /// { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + /// }; + /// ``` + /// + /// \todo Rename this property to Size once we will have property + /// ```text + /// categories (i.e. Properties::PixelArray::OpticalBlackRectangles) + PixelArrayOpticalBlackRectangles = PIXEL_ARRAY_OPTICAL_BLACK_RECTANGLES, + /// The PixelArrayActiveAreas property defines the (possibly multiple and + /// overlapping) portions of the camera sensor readable pixel matrix + /// which are considered valid for image acquisition purposes. + /// + /// This property describes an arbitrary number of overlapping rectangles, + /// with each rectangle representing the maximum image size that the camera + /// sensor can produce for a particular aspect ratio. They are defined + /// relatively to the PixelArraySize rectangle. + /// + /// When multiple rectangles are reported, they shall be ordered from the + /// tallest to the shortest. + /// + /// Example 1 + /// A camera sensor which only produces images in the 4:3 image resolution + /// will report a single PixelArrayActiveAreas rectangle, from which all + /// other image formats are obtained by either cropping the field-of-view + /// and/or applying pixel sub-sampling techniques such as pixel skipping or + /// binning. + /// + /// ```text + /// PixelArraySize.width + /// /----------------/ + /// x1 x2 + /// (0,0)-> +-o------------o-+ / + /// y1 o +------------+ | | + /// | |////////////| | | + /// | |////////////| | | PixelArraySize.height + /// | |////////////| | | + /// y2 o +------------+ | | + /// +----------------+ / + /// ``` + /// + /// The property reports a single rectangle + /// + /// ```text + /// PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + /// ``` + /// + /// Example 2 + /// A camera sensor which can produce images in different native + /// resolutions will report several overlapping rectangles, one for each + /// natively supported resolution. + /// + /// ```text + /// PixelArraySize.width + /// /------------------/ + /// x1 x2 x3 x4 + /// (0,0)-> +o---o------o---o+ / + /// y1 o +------+ | | + /// | |//////| | | + /// y2 o+---+------+---+| | + /// ||///|//////|///|| | PixelArraySize.height + /// y3 o+---+------+---+| | + /// | |//////| | | + /// y4 o +------+ | | + /// +----+------+----+ / + /// ``` + /// + /// The property reports two rectangles + /// + /// ```text + /// PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + /// (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + /// ``` + /// + /// The first rectangle describes the maximum field-of-view of all image + /// formats in the 4:3 resolutions, while the second one describes the + /// maximum field of view for all image formats in the 16:9 resolutions. + /// + /// Multiple rectangles shall only be reported when the sensor can't capture + /// the pixels in the corner regions. If all the pixels in the (x1,y1) - + /// (x4,y4) area can be captured, the PixelArrayActiveAreas property shall + /// contains the single rectangle (x1,y1) - (x4,y4). + /// + /// \todo Rename this property to ActiveAreas once we will have property + /// ```text + /// categories (i.e. Properties::PixelArray::ActiveAreas) + PixelArrayActiveAreas = PIXEL_ARRAY_ACTIVE_AREAS, + /// The maximum valid rectangle for the controls::ScalerCrop control. This + /// reflects the minimum mandatory cropping applied in the camera sensor and + /// the rest of the pipeline. Just as the ScalerCrop control, it defines a + /// rectangle taken from the sensor's active pixel array. + /// + /// This property is valid only after the camera has been successfully + /// configured and its value may change whenever a new configuration is + /// applied. + /// + /// \todo Turn this property into a "maximum control value" for the + /// ScalerCrop control once "dynamic" controls have been implemented. + ScalerCropMaximum = SCALER_CROP_MAXIMUM, + /// The relative sensitivity of the chosen sensor mode. + /// + /// Some sensors have readout modes with different sensitivities. For example, + /// a binned camera mode might, with the same exposure and gains, produce + /// twice the signal level of the full resolution readout. This would be + /// signalled by the binned mode, when it is chosen, indicating a value here + /// that is twice that of the full resolution mode. This value will be valid + /// after the configure method has returned successfully. + SensorSensitivity = SENSOR_SENSITIVITY, + /// A list of integer values of type dev_t denoting the major and minor + /// device numbers of the underlying devices used in the operation of this + /// camera. + /// + /// Different cameras may report identical devices. + SystemDevices = SYSTEM_DEVICES, + /// The arrangement of color filters on sensor; represents the colors in the + /// top-left 2x2 section of the sensor, in reading order. Currently + /// identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. + #[cfg(feature = "vendor_draft")] + ColorFilterArrangement = COLOR_FILTER_ARRANGEMENT, +} +impl PropertyId { + pub fn id(&self) -> u32 { + u32::from(*self) + } + pub fn description(&self) -> &'static str { + match self { + PropertyId::Location => "Camera mounting location +", + PropertyId::Rotation => { + "The camera physical mounting rotation. It is expressed as the angular +difference in degrees between two reference systems, one relative to the +camera module, and one defined on the external world scene to be +captured when projected on the image sensor pixel array. + +A camera sensor has a 2-dimensional reference system 'Rc' defined by +its pixel array read-out order. The origin is set to the first pixel +being read out, the X-axis points along the column read-out direction +towards the last columns, and the Y-axis along the row read-out +direction towards the last row. + +A typical example for a sensor with a 2592x1944 pixel array matrix +observed from the front is + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + +The external world scene reference system 'Rs' is a 2-dimensional +reference system on the focal plane of the camera module. The origin is +placed on the top-left corner of the visible scene, the X-axis points +towards the right, and the Y-axis points towards the bottom of the +scene. The top, bottom, left and right directions are intentionally not +defined and depend on the environment in which the camera is used. + +A typical example of a (very common) picture of a shark swimming from +left to right, as seen from the camera, is + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\\____)\\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + +With the reference system 'Rs' placed on the camera focal plane. + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \\-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + +When projected on the sensor's pixel array, the image and the associated +reference system 'Rs' are typically (but not always) inverted, due to +the camera module's lens optical inversion effect. + +Assuming the above represented scene of the swimming shark, the lens +inversion projects the scene and its reference system onto the sensor +pixel array, seen from the front of the camera sensor, as follow + + Y-axis + ^ + ! + ! + ! + ! |\\_____)\\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + +Note the shark being upside-down. + +The resulting projected reference system is named 'Rp'. + +The camera rotation property is then defined as the angular difference +in the counter-clockwise direction between the camera reference system +'Rc' and the projected scene reference system 'Rp'. It is expressed in +degrees as a number in the range [0, 360[. + +Examples + +0 degrees camera rotation + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + +90 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +180 degrees camera rotation + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +270 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + +Example one - Webcam + +A camera module installed on the user facing part of a laptop screen +casing used for video calls. The captured images are meant to be +displayed in landscape mode (width > height) on the laptop screen. + +The camera is typically mounted upside-down to compensate the lens +optical inversion effect. + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + +The two reference systems are aligned, the resulting camera rotation is +0 degrees, no rotation correction needs to be applied to the resulting +image once captured to memory buffers to correctly display it to users. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +If the camera sensor is not mounted upside-down to compensate for the +lens optical inversion, the two reference systems will not be aligned, +with 'Rp' being rotated 180 degrees relatively to 'Rc'. + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\\_____)\\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +The image once captured to memory will then be rotated by 180 degrees + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \\( \\| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +A software rotation correction of 180 degrees should be applied to +correctly display the image. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +Example two - Phone camera + +A camera installed on the back side of a mobile device facing away from +the user. The captured images are meant to be displayed in portrait mode +(height > width) to match the device screen orientation and the device +usage orientation used when taking the picture. + +The camera sensor is typically mounted with its pixel array longer side +aligned to the device longer side, upside-down mounted to compensate for +the lens optical inversion effect. + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +The two reference systems are not aligned and the 'Rp' reference +system is rotated by 90 degrees in the counter-clockwise direction +relatively to the 'Rc' reference system. + +The image once captured to memory will be rotated. + + +-------------------------------------+ + | _ _ | + | \\ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + +A correction of 90 degrees in counter-clockwise direction has to be +applied to correctly display the image in portrait mode on the device +screen. + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\\____)\\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ +" + } + PropertyId::Model => { + "The model name shall to the extent possible describe the sensor. For +most devices this is the model name of the sensor. While for some +devices the sensor model is unavailable as the sensor or the entire +camera is part of a larger unit and exposed as a black-box to the +system. In such cases the model name of the smallest device that +contains the camera sensor shall be used. + +The model name is not meant to be a camera name displayed to the +end-user, but may be combined with other camera information to create a +camera name. + +The model name is not guaranteed to be unique in the system nor is +it guaranteed to be stable or have any other properties required to make +it a good candidate to be used as a permanent identifier of a camera. + +The model name shall describe the camera in a human readable format and +shall be encoded in ASCII. + +Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. +" + } + PropertyId::UnitCellSize => { + "The pixel unit cell physical size, in nanometers. + +The UnitCellSize properties defines the horizontal and vertical sizes of +a single pixel unit, including its active and non-active parts. In +other words, it expresses the horizontal and vertical distance between +the top-left corners of adjacent pixels. + +The property can be used to calculate the physical size of the sensor's +pixel array area and for calibration purposes. +" + } + PropertyId::PixelArraySize => { + "The camera sensor pixel array readable area vertical and horizontal +sizes, in pixels. + +The PixelArraySize property defines the size in pixel units of the +readable part of full pixel array matrix, including optical black +pixels used for calibration, pixels which are not considered valid for +capture and active pixels containing valid image data. + +The property describes the maximum size of the raw data captured by the +camera, which might not correspond to the physical size of the sensor +pixel array matrix, as some portions of the physical pixel array matrix +are not accessible and cannot be transmitted out. + +For example, let's consider a pixel array matrix assembled as follows + + +--------------------------------------------------+ + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + ... ... ... ... ... + + ... ... ... ... ... + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + +--------------------------------------------------+ + +starting with two lines of non-readable pixels (x), followed by N lines +of readable data (D) surrounded by two columns of non-readable pixels on +each side, and ending with two more lines of non-readable pixels. Only +the readable portion is transmitted to the receiving side, defining the +sizes of the largest possible buffer of raw data that can be presented +to applications. + + PixelArraySize.width + /----------------------------------------------/ + +----------------------------------------------+ / + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + ... ... ... ... ... + ... ... ... ... ... + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + +----------------------------------------------+ / + +This defines a rectangle whose top-left corner is placed in position (0, +0) and whose vertical and horizontal sizes are defined by this property. +All other rectangles that describe portions of the pixel array, such as +the optical black pixels rectangles and active pixel areas, are defined +relatively to this rectangle. + +All the coordinates are expressed relative to the default sensor readout +direction, without any transformation (such as horizontal and vertical +flipping) applied. When mapping them to the raw pixel buffer, +applications shall take any configured transformation into account. + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::Size) +" + } + PropertyId::PixelArrayOpticalBlackRectangles => { + "The pixel array region(s) which contain optical black pixels +considered valid for calibration purposes. + +This property describes the position and size of optical black pixel +regions in the raw data buffer as stored in memory, which might differ +from their actual physical location in the pixel array matrix. + +It is important to note, in fact, that camera sensors might +automatically reorder or skip portions of their pixels array matrix when +transmitting data to the receiver. For instance, a sensor may merge the +top and bottom optical black rectangles into a single rectangle, +transmitted at the beginning of the frame. + +The pixel array contains several areas with different purposes, +interleaved by lines and columns which are said not to be valid for +capturing purposes. Invalid lines and columns are defined as invalid as +they could be positioned too close to the chip margins or to the optical +black shielding placed on top of optical black pixels. + + PixelArraySize.width + /----------------------------------------------/ + x1 x2 + +--o---------------------------------------o---+ / + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + ... ... ... ... ... + ... ... ... ... ... + y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + +----------------------------------------------+ / + +The readable pixel array matrix is composed by +2 invalid lines (I) +4 lines of valid optical black pixels (O) +2 invalid lines (I) +n lines of valid pixel data (P) +2 invalid lines (I) + +And the position of the optical black pixel rectangles is defined by + + PixelArrayOpticalBlackRectangles = { + { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + { x1, y3, 2, y4 - y3 + 1 }, + { x2, y3, 2, y4 - y3 + 1 }, + }; + +If the camera, when capturing the full pixel array matrix, automatically +skips the invalid lines and columns, producing the following data +buffer, when captured to memory + + PixelArraySize.width + /----------------------------------------------/ + x1 + +--------------------------------------------o-+ / + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + ... ... ... ... ... | + ... ... ... ... ... | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + +----------------------------------------------+ / + +then the invalid lines and columns should not be reported as part of the +PixelArraySize property in first place. + +In this case, the position of the black pixel rectangles will be + + PixelArrayOpticalBlackRectangles = { + { 0, 0, y1 + 1, PixelArraySize[0] }, + { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + }; + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::OpticalBlackRectangles) +" + } + PropertyId::PixelArrayActiveAreas => { + "The PixelArrayActiveAreas property defines the (possibly multiple and +overlapping) portions of the camera sensor readable pixel matrix +which are considered valid for image acquisition purposes. + +This property describes an arbitrary number of overlapping rectangles, +with each rectangle representing the maximum image size that the camera +sensor can produce for a particular aspect ratio. They are defined +relatively to the PixelArraySize rectangle. + +When multiple rectangles are reported, they shall be ordered from the +tallest to the shortest. + +Example 1 +A camera sensor which only produces images in the 4:3 image resolution +will report a single PixelArrayActiveAreas rectangle, from which all +other image formats are obtained by either cropping the field-of-view +and/or applying pixel sub-sampling techniques such as pixel skipping or +binning. + + PixelArraySize.width + /----------------/ + x1 x2 + (0,0)-> +-o------------o-+ / + y1 o +------------+ | | + | |////////////| | | + | |////////////| | | PixelArraySize.height + | |////////////| | | + y2 o +------------+ | | + +----------------+ / + +The property reports a single rectangle + + PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + +Example 2 +A camera sensor which can produce images in different native +resolutions will report several overlapping rectangles, one for each +natively supported resolution. + + PixelArraySize.width + /------------------/ + x1 x2 x3 x4 + (0,0)-> +o---o------o---o+ / + y1 o +------+ | | + | |//////| | | + y2 o+---+------+---+| | + ||///|//////|///|| | PixelArraySize.height + y3 o+---+------+---+| | + | |//////| | | + y4 o +------+ | | + +----+------+----+ / + +The property reports two rectangles + + PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + +The first rectangle describes the maximum field-of-view of all image +formats in the 4:3 resolutions, while the second one describes the +maximum field of view for all image formats in the 16:9 resolutions. + +Multiple rectangles shall only be reported when the sensor can't capture +the pixels in the corner regions. If all the pixels in the (x1,y1) - +(x4,y4) area can be captured, the PixelArrayActiveAreas property shall +contains the single rectangle (x1,y1) - (x4,y4). + +\\todo Rename this property to ActiveAreas once we will have property + categories (i.e. Properties::PixelArray::ActiveAreas) +" + } + PropertyId::ScalerCropMaximum => { + "The maximum valid rectangle for the controls::ScalerCrop control. This +reflects the minimum mandatory cropping applied in the camera sensor and +the rest of the pipeline. Just as the ScalerCrop control, it defines a +rectangle taken from the sensor's active pixel array. + +This property is valid only after the camera has been successfully +configured and its value may change whenever a new configuration is +applied. + +\\todo Turn this property into a \"maximum control value\" for the +ScalerCrop control once \"dynamic\" controls have been implemented. +" + } + PropertyId::SensorSensitivity => { + "The relative sensitivity of the chosen sensor mode. + +Some sensors have readout modes with different sensitivities. For example, +a binned camera mode might, with the same exposure and gains, produce +twice the signal level of the full resolution readout. This would be +signalled by the binned mode, when it is chosen, indicating a value here +that is twice that of the full resolution mode. This value will be valid +after the configure method has returned successfully. +" + } + PropertyId::SystemDevices => { + "A list of integer values of type dev_t denoting the major and minor +device numbers of the underlying devices used in the operation of this +camera. + +Different cameras may report identical devices. +" + } + #[cfg(feature = "vendor_draft")] + PropertyId::ColorFilterArrangement => { + "The arrangement of color filters on sensor; represents the colors in the +top-left 2x2 section of the sensor, in reading order. Currently +identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. +" + } + } + } +} +/// Camera mounting location +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum Location { + /// The camera is mounted on the front side of the device, facing the + /// user + CameraFront = 0, + /// The camera is mounted on the back side of the device, facing away + /// from the user + CameraBack = 1, + /// The camera is attached to the device in a way that allows it to + /// be moved freely + CameraExternal = 2, +} +impl TryFrom for Location { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: Location) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for Location { + const ID: u32 = PropertyId::Location as _; +} +impl Property for Location {} +/// The camera physical mounting rotation. It is expressed as the angular +/// difference in degrees between two reference systems, one relative to the +/// camera module, and one defined on the external world scene to be +/// captured when projected on the image sensor pixel array. +/// +/// A camera sensor has a 2-dimensional reference system 'Rc' defined by +/// its pixel array read-out order. The origin is set to the first pixel +/// being read out, the X-axis points along the column read-out direction +/// towards the last columns, and the Y-axis along the row read-out +/// direction towards the last row. +/// +/// A typical example for a sensor with a 2592x1944 pixel array matrix +/// observed from the front is +/// +/// ```text +/// 2591 X-axis 0 +/// <------------------------+ 0 +/// .......... ... ..........! +/// .......... ... ..........! Y-axis +/// ... ! +/// .......... ... ..........! +/// .......... ... ..........! 1943 +/// V +/// ``` +/// +/// +/// The external world scene reference system 'Rs' is a 2-dimensional +/// reference system on the focal plane of the camera module. The origin is +/// placed on the top-left corner of the visible scene, the X-axis points +/// towards the right, and the Y-axis points towards the bottom of the +/// scene. The top, bottom, left and right directions are intentionally not +/// defined and depend on the environment in which the camera is used. +/// +/// A typical example of a (very common) picture of a shark swimming from +/// left to right, as seen from the camera, is +/// +/// ```text +/// 0 X-axis +/// 0 +-------------------------------------> +/// ! +/// ! +/// ! +/// ! |\____)\___ +/// ! ) _____ __`< +/// ! |/ )/ +/// ! +/// ! +/// ! +/// V +/// Y-axis +/// ``` +/// +/// With the reference system 'Rs' placed on the camera focal plane. +/// +/// ```text +/// ¸.·˙! +/// ¸.·˙ ! +/// _ ¸.·˙ ! +/// +-/ \-+¸.·˙ ! +/// | (o) | ! Camera focal plane +/// +-----+˙·.¸ ! +/// ˙·.¸ ! +/// ˙·.¸ ! +/// ˙·.¸! +/// ``` +/// +/// When projected on the sensor's pixel array, the image and the associated +/// reference system 'Rs' are typically (but not always) inverted, due to +/// the camera module's lens optical inversion effect. +/// +/// Assuming the above represented scene of the swimming shark, the lens +/// inversion projects the scene and its reference system onto the sensor +/// pixel array, seen from the front of the camera sensor, as follow +/// +/// ```text +/// Y-axis +/// ^ +/// ! +/// ! +/// ! +/// ! |\_____)\__ +/// ! ) ____ ___.< +/// ! |/ )/ +/// ! +/// ! +/// ! +/// 0 +-------------------------------------> +/// 0 X-axis +/// ``` +/// +/// Note the shark being upside-down. +/// +/// The resulting projected reference system is named 'Rp'. +/// +/// The camera rotation property is then defined as the angular difference +/// in the counter-clockwise direction between the camera reference system +/// 'Rc' and the projected scene reference system 'Rp'. It is expressed in +/// degrees as a number in the range [0, 360[. +/// +/// Examples +/// +/// 0 degrees camera rotation +/// +/// +/// ```text +/// Y-Rp +/// ^ +/// Y-Rc ! +/// ^ ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// 0 +-------------------------------------> +/// 0 X-Rc +/// ``` +/// +/// +/// ```text +/// X-Rc 0 +/// <------------------------------------+ 0 +/// X-Rp 0 ! +/// <------------------------------------+ 0 ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rc +/// V +/// Y-Rp +/// ``` +/// +/// 90 degrees camera rotation +/// +/// ```text +/// 0 Y-Rc +/// 0 +--------------------> +/// ! Y-Rp +/// ! ^ +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// ! +/// ! +/// ! +/// ! +/// V +/// X-Rc +/// ``` +/// +/// 180 degrees camera rotation +/// +/// ```text +/// 0 +/// <------------------------------------+ 0 +/// X-Rc ! +/// Y-Rp ! +/// ^ ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rc +/// 0 +-------------------------------------> +/// 0 X-Rp +/// ``` +/// +/// 270 degrees camera rotation +/// +/// ```text +/// 0 Y-Rc +/// 0 +--------------------> +/// ! 0 +/// ! <-----------------------------------+ 0 +/// ! X-Rp ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rp +/// ! +/// ! +/// ! +/// ! +/// V +/// X-Rc +/// ``` +/// +/// +/// Example one - Webcam +/// +/// A camera module installed on the user facing part of a laptop screen +/// casing used for video calls. The captured images are meant to be +/// displayed in landscape mode (width > height) on the laptop screen. +/// +/// The camera is typically mounted upside-down to compensate the lens +/// optical inversion effect. +/// +/// ```text +/// Y-Rp +/// Y-Rc ^ +/// ^ ! +/// ! ! +/// ! ! |\_____)\__ +/// ! ! ) ____ ___.< +/// ! ! |/ )/ +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// 0 +-------------------------------------> +/// 0 X-Rc +/// ``` +/// +/// The two reference systems are aligned, the resulting camera rotation is +/// 0 degrees, no rotation correction needs to be applied to the resulting +/// image once captured to memory buffers to correctly display it to users. +/// +/// ```text +/// +--------------------------------------+ +/// ! ! +/// ! ! +/// ! ! +/// ! |\____)\___ ! +/// ! ) _____ __`< ! +/// ! |/ )/ ! +/// ! ! +/// ! ! +/// ! ! +/// +--------------------------------------+ +/// ``` +/// +/// If the camera sensor is not mounted upside-down to compensate for the +/// lens optical inversion, the two reference systems will not be aligned, +/// with 'Rp' being rotated 180 degrees relatively to 'Rc'. +/// +/// +/// ```text +/// X-Rc 0 +/// <------------------------------------+ 0 +/// ! +/// Y-Rp ! +/// ^ ! +/// ! ! +/// ! |\_____)\__ ! +/// ! ) ____ ___.< ! +/// ! |/ )/ ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rc +/// 0 +-------------------------------------> +/// 0 X-Rp +/// ``` +/// +/// The image once captured to memory will then be rotated by 180 degrees +/// +/// ```text +/// +--------------------------------------+ +/// ! ! +/// ! ! +/// ! ! +/// ! __/(_____/| ! +/// ! >.___ ____ ( ! +/// ! \( \| ! +/// ! ! +/// ! ! +/// ! ! +/// +--------------------------------------+ +/// ``` +/// +/// A software rotation correction of 180 degrees should be applied to +/// correctly display the image. +/// +/// ```text +/// +--------------------------------------+ +/// ! ! +/// ! ! +/// ! ! +/// ! |\____)\___ ! +/// ! ) _____ __`< ! +/// ! |/ )/ ! +/// ! ! +/// ! ! +/// ! ! +/// +--------------------------------------+ +/// ``` +/// +/// Example two - Phone camera +/// +/// A camera installed on the back side of a mobile device facing away from +/// the user. The captured images are meant to be displayed in portrait mode +/// (height > width) to match the device screen orientation and the device +/// usage orientation used when taking the picture. +/// +/// The camera sensor is typically mounted with its pixel array longer side +/// aligned to the device longer side, upside-down mounted to compensate for +/// the lens optical inversion effect. +/// +/// ```text +/// 0 Y-Rc +/// 0 +--------------------> +/// ! Y-Rp +/// ! ^ +/// ! ! +/// ! ! +/// ! ! +/// ! ! |\_____)\__ +/// ! ! ) ____ ___.< +/// ! ! |/ )/ +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// ! +/// ! +/// ! +/// ! +/// V +/// X-Rc +/// ``` +/// +/// The two reference systems are not aligned and the 'Rp' reference +/// system is rotated by 90 degrees in the counter-clockwise direction +/// relatively to the 'Rc' reference system. +/// +/// The image once captured to memory will be rotated. +/// +/// ```text +/// +-------------------------------------+ +/// | _ _ | +/// | \ / | +/// | | | | +/// | | | | +/// | | > | +/// | < | | +/// | | | | +/// | . | +/// | V | +/// +-------------------------------------+ +/// ``` +/// +/// A correction of 90 degrees in counter-clockwise direction has to be +/// applied to correctly display the image in portrait mode on the device +/// screen. +/// +/// ```text +/// +--------------------+ +/// | | +/// | | +/// | | +/// | | +/// | | +/// | | +/// | |\____)\___ | +/// | ) _____ __`< | +/// | |/ )/ | +/// | | +/// | | +/// | | +/// | | +/// | | +/// +--------------------+ +#[derive(Debug, Clone)] +pub struct Rotation(pub i32); +impl Deref for Rotation { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Rotation { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Rotation { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Rotation) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Rotation { + const ID: u32 = PropertyId::Rotation as _; +} +impl Property for Rotation {} +/// The model name shall to the extent possible describe the sensor. For +/// most devices this is the model name of the sensor. While for some +/// devices the sensor model is unavailable as the sensor or the entire +/// camera is part of a larger unit and exposed as a black-box to the +/// system. In such cases the model name of the smallest device that +/// contains the camera sensor shall be used. +/// +/// The model name is not meant to be a camera name displayed to the +/// end-user, but may be combined with other camera information to create a +/// camera name. +/// +/// The model name is not guaranteed to be unique in the system nor is +/// it guaranteed to be stable or have any other properties required to make +/// it a good candidate to be used as a permanent identifier of a camera. +/// +/// The model name shall describe the camera in a human readable format and +/// shall be encoded in ASCII. +/// +/// Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. +#[derive(Debug, Clone)] +pub struct Model(pub String); +impl Deref for Model { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Model { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Model { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Model) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Model { + const ID: u32 = PropertyId::Model as _; +} +impl Property for Model {} +/// The pixel unit cell physical size, in nanometers. +/// +/// The UnitCellSize properties defines the horizontal and vertical sizes of +/// a single pixel unit, including its active and non-active parts. In +/// other words, it expresses the horizontal and vertical distance between +/// the top-left corners of adjacent pixels. +/// +/// The property can be used to calculate the physical size of the sensor's +/// pixel array area and for calibration purposes. +#[derive(Debug, Clone)] +pub struct UnitCellSize(pub Size); +impl Deref for UnitCellSize { + type Target = Size; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for UnitCellSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for UnitCellSize { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: UnitCellSize) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for UnitCellSize { + const ID: u32 = PropertyId::UnitCellSize as _; +} +impl Property for UnitCellSize {} +/// The camera sensor pixel array readable area vertical and horizontal +/// sizes, in pixels. +/// +/// The PixelArraySize property defines the size in pixel units of the +/// readable part of full pixel array matrix, including optical black +/// pixels used for calibration, pixels which are not considered valid for +/// capture and active pixels containing valid image data. +/// +/// The property describes the maximum size of the raw data captured by the +/// camera, which might not correspond to the physical size of the sensor +/// pixel array matrix, as some portions of the physical pixel array matrix +/// are not accessible and cannot be transmitted out. +/// +/// For example, let's consider a pixel array matrix assembled as follows +/// +/// ```text +/// +--------------------------------------------------+ +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// ... ... ... ... ... +/// ``` +/// +/// ```text +/// ... ... ... ... ... +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// +--------------------------------------------------+ +/// ``` +/// +/// starting with two lines of non-readable pixels (x), followed by N lines +/// of readable data (D) surrounded by two columns of non-readable pixels on +/// each side, and ending with two more lines of non-readable pixels. Only +/// the readable portion is transmitted to the receiving side, defining the +/// sizes of the largest possible buffer of raw data that can be presented +/// to applications. +/// +/// ```text +/// PixelArraySize.width +/// /----------------------------------------------/ +/// +----------------------------------------------+ / +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height +/// ... ... ... ... ... +/// ... ... ... ... ... +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// +----------------------------------------------+ / +/// ``` +/// +/// This defines a rectangle whose top-left corner is placed in position (0, +/// 0) and whose vertical and horizontal sizes are defined by this property. +/// All other rectangles that describe portions of the pixel array, such as +/// the optical black pixels rectangles and active pixel areas, are defined +/// relatively to this rectangle. +/// +/// All the coordinates are expressed relative to the default sensor readout +/// direction, without any transformation (such as horizontal and vertical +/// flipping) applied. When mapping them to the raw pixel buffer, +/// applications shall take any configured transformation into account. +/// +/// \todo Rename this property to Size once we will have property +/// ```text +/// categories (i.e. Properties::PixelArray::Size) +#[derive(Debug, Clone)] +pub struct PixelArraySize(pub Size); +impl Deref for PixelArraySize { + type Target = Size; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for PixelArraySize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for PixelArraySize { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: PixelArraySize) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for PixelArraySize { + const ID: u32 = PropertyId::PixelArraySize as _; +} +impl Property for PixelArraySize {} +/// The pixel array region(s) which contain optical black pixels +/// considered valid for calibration purposes. +/// +/// This property describes the position and size of optical black pixel +/// regions in the raw data buffer as stored in memory, which might differ +/// from their actual physical location in the pixel array matrix. +/// +/// It is important to note, in fact, that camera sensors might +/// automatically reorder or skip portions of their pixels array matrix when +/// transmitting data to the receiver. For instance, a sensor may merge the +/// top and bottom optical black rectangles into a single rectangle, +/// transmitted at the beginning of the frame. +/// +/// The pixel array contains several areas with different purposes, +/// interleaved by lines and columns which are said not to be valid for +/// capturing purposes. Invalid lines and columns are defined as invalid as +/// they could be positioned too close to the chip margins or to the optical +/// black shielding placed on top of optical black pixels. +/// +/// ```text +/// PixelArraySize.width +/// /----------------------------------------------/ +/// x1 x2 +/// +--o---------------------------------------o---+ / +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | +/// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height +/// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | +/// ... ... ... ... ... +/// ... ... ... ... ... +/// y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// +----------------------------------------------+ / +/// ``` +/// +/// The readable pixel array matrix is composed by +/// 2 invalid lines (I) +/// 4 lines of valid optical black pixels (O) +/// 2 invalid lines (I) +/// n lines of valid pixel data (P) +/// 2 invalid lines (I) +/// +/// And the position of the optical black pixel rectangles is defined by +/// +/// ```text +/// PixelArrayOpticalBlackRectangles = { +/// { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, +/// { x1, y3, 2, y4 - y3 + 1 }, +/// { x2, y3, 2, y4 - y3 + 1 }, +/// }; +/// ``` +/// +/// If the camera, when capturing the full pixel array matrix, automatically +/// skips the invalid lines and columns, producing the following data +/// buffer, when captured to memory +/// +/// ```text +/// PixelArraySize.width +/// /----------------------------------------------/ +/// x1 +/// +--------------------------------------------o-+ / +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height +/// ... ... ... ... ... | +/// ... ... ... ... ... | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// +----------------------------------------------+ / +/// ``` +/// +/// then the invalid lines and columns should not be reported as part of the +/// PixelArraySize property in first place. +/// +/// In this case, the position of the black pixel rectangles will be +/// +/// ```text +/// PixelArrayOpticalBlackRectangles = { +/// { 0, 0, y1 + 1, PixelArraySize[0] }, +/// { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, +/// { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, +/// }; +/// ``` +/// +/// \todo Rename this property to Size once we will have property +/// ```text +/// categories (i.e. Properties::PixelArray::OpticalBlackRectangles) +#[derive(Debug, Clone)] +pub struct PixelArrayOpticalBlackRectangles(pub Vec); +impl Deref for PixelArrayOpticalBlackRectangles { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for PixelArrayOpticalBlackRectangles { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for PixelArrayOpticalBlackRectangles { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: PixelArrayOpticalBlackRectangles) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for PixelArrayOpticalBlackRectangles { + const ID: u32 = PropertyId::PixelArrayOpticalBlackRectangles as _; +} +impl Property for PixelArrayOpticalBlackRectangles {} +/// The PixelArrayActiveAreas property defines the (possibly multiple and +/// overlapping) portions of the camera sensor readable pixel matrix +/// which are considered valid for image acquisition purposes. +/// +/// This property describes an arbitrary number of overlapping rectangles, +/// with each rectangle representing the maximum image size that the camera +/// sensor can produce for a particular aspect ratio. They are defined +/// relatively to the PixelArraySize rectangle. +/// +/// When multiple rectangles are reported, they shall be ordered from the +/// tallest to the shortest. +/// +/// Example 1 +/// A camera sensor which only produces images in the 4:3 image resolution +/// will report a single PixelArrayActiveAreas rectangle, from which all +/// other image formats are obtained by either cropping the field-of-view +/// and/or applying pixel sub-sampling techniques such as pixel skipping or +/// binning. +/// +/// ```text +/// PixelArraySize.width +/// /----------------/ +/// x1 x2 +/// (0,0)-> +-o------------o-+ / +/// y1 o +------------+ | | +/// | |////////////| | | +/// | |////////////| | | PixelArraySize.height +/// | |////////////| | | +/// y2 o +------------+ | | +/// +----------------+ / +/// ``` +/// +/// The property reports a single rectangle +/// +/// ```text +/// PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) +/// ``` +/// +/// Example 2 +/// A camera sensor which can produce images in different native +/// resolutions will report several overlapping rectangles, one for each +/// natively supported resolution. +/// +/// ```text +/// PixelArraySize.width +/// /------------------/ +/// x1 x2 x3 x4 +/// (0,0)-> +o---o------o---o+ / +/// y1 o +------+ | | +/// | |//////| | | +/// y2 o+---+------+---+| | +/// ||///|//////|///|| | PixelArraySize.height +/// y3 o+---+------+---+| | +/// | |//////| | | +/// y4 o +------+ | | +/// +----+------+----+ / +/// ``` +/// +/// The property reports two rectangles +/// +/// ```text +/// PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), +/// (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) +/// ``` +/// +/// The first rectangle describes the maximum field-of-view of all image +/// formats in the 4:3 resolutions, while the second one describes the +/// maximum field of view for all image formats in the 16:9 resolutions. +/// +/// Multiple rectangles shall only be reported when the sensor can't capture +/// the pixels in the corner regions. If all the pixels in the (x1,y1) - +/// (x4,y4) area can be captured, the PixelArrayActiveAreas property shall +/// contains the single rectangle (x1,y1) - (x4,y4). +/// +/// \todo Rename this property to ActiveAreas once we will have property +/// ```text +/// categories (i.e. Properties::PixelArray::ActiveAreas) +#[derive(Debug, Clone)] +pub struct PixelArrayActiveAreas(pub Vec); +impl Deref for PixelArrayActiveAreas { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for PixelArrayActiveAreas { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for PixelArrayActiveAreas { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: PixelArrayActiveAreas) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for PixelArrayActiveAreas { + const ID: u32 = PropertyId::PixelArrayActiveAreas as _; +} +impl Property for PixelArrayActiveAreas {} +/// The maximum valid rectangle for the controls::ScalerCrop control. This +/// reflects the minimum mandatory cropping applied in the camera sensor and +/// the rest of the pipeline. Just as the ScalerCrop control, it defines a +/// rectangle taken from the sensor's active pixel array. +/// +/// This property is valid only after the camera has been successfully +/// configured and its value may change whenever a new configuration is +/// applied. +/// +/// \todo Turn this property into a "maximum control value" for the +/// ScalerCrop control once "dynamic" controls have been implemented. +#[derive(Debug, Clone)] +pub struct ScalerCropMaximum(pub Rectangle); +impl Deref for ScalerCropMaximum { + type Target = Rectangle; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ScalerCropMaximum { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ScalerCropMaximum { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ScalerCropMaximum) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ScalerCropMaximum { + const ID: u32 = PropertyId::ScalerCropMaximum as _; +} +impl Property for ScalerCropMaximum {} +/// The relative sensitivity of the chosen sensor mode. +/// +/// Some sensors have readout modes with different sensitivities. For example, +/// a binned camera mode might, with the same exposure and gains, produce +/// twice the signal level of the full resolution readout. This would be +/// signalled by the binned mode, when it is chosen, indicating a value here +/// that is twice that of the full resolution mode. This value will be valid +/// after the configure method has returned successfully. +#[derive(Debug, Clone)] +pub struct SensorSensitivity(pub f32); +impl Deref for SensorSensitivity { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorSensitivity { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorSensitivity { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorSensitivity) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorSensitivity { + const ID: u32 = PropertyId::SensorSensitivity as _; +} +impl Property for SensorSensitivity {} +/// A list of integer values of type dev_t denoting the major and minor +/// device numbers of the underlying devices used in the operation of this +/// camera. +/// +/// Different cameras may report identical devices. +#[derive(Debug, Clone)] +pub struct SystemDevices(pub Vec); +impl Deref for SystemDevices { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SystemDevices { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SystemDevices { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SystemDevices) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SystemDevices { + const ID: u32 = PropertyId::SystemDevices as _; +} +impl Property for SystemDevices {} +/// The arrangement of color filters on sensor; represents the colors in the +/// top-left 2x2 section of the sensor, in reading order. Currently +/// identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum ColorFilterArrangement { + /// RGGB Bayer pattern + RGGB = 0, + /// GRBG Bayer pattern + GRBG = 1, + /// GBRG Bayer pattern + GBRG = 2, + /// BGGR Bayer pattern + BGGR = 3, + /// Sensor is not Bayer; output has 3 16-bit values for each pixel, + /// instead of just 1 16-bit value per pixel. + RGB = 4, + /// Sensor is not Bayer; output consists of a single colour channel. + MONO = 5, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for ColorFilterArrangement { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: ColorFilterArrangement) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for ColorFilterArrangement { + const ID: u32 = PropertyId::ColorFilterArrangement as _; +} +#[cfg(feature = "vendor_draft")] +impl Property for ColorFilterArrangement {} +pub fn make_dyn( + id: PropertyId, + val: ControlValue, +) -> Result, ControlValueError> { + match id { + PropertyId::Location => Ok(Box::new(Location::try_from(val)?)), + PropertyId::Rotation => Ok(Box::new(Rotation::try_from(val)?)), + PropertyId::Model => Ok(Box::new(Model::try_from(val)?)), + PropertyId::UnitCellSize => Ok(Box::new(UnitCellSize::try_from(val)?)), + PropertyId::PixelArraySize => Ok(Box::new(PixelArraySize::try_from(val)?)), + PropertyId::PixelArrayOpticalBlackRectangles => { + Ok(Box::new(PixelArrayOpticalBlackRectangles::try_from(val)?)) + } + PropertyId::PixelArrayActiveAreas => { + Ok(Box::new(PixelArrayActiveAreas::try_from(val)?)) + } + PropertyId::ScalerCropMaximum => Ok(Box::new(ScalerCropMaximum::try_from(val)?)), + PropertyId::SensorSensitivity => Ok(Box::new(SensorSensitivity::try_from(val)?)), + PropertyId::SystemDevices => Ok(Box::new(SystemDevices::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + PropertyId::ColorFilterArrangement => { + Ok(Box::new(ColorFilterArrangement::try_from(val)?)) + } + } +} diff --git a/libcamera/versioned_files/0.5.2/property_ids_core.yaml b/libcamera/versioned_files/0.5.2/property_ids_core.yaml new file mode 100644 index 0000000..834454a --- /dev/null +++ b/libcamera/versioned_files/0.5.2/property_ids_core.yaml @@ -0,0 +1,704 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +vendor: libcamera +controls: + - Location: + type: int32_t + description: | + Camera mounting location + enum: + - name: CameraLocationFront + value: 0 + description: | + The camera is mounted on the front side of the device, facing the + user + - name: CameraLocationBack + value: 1 + description: | + The camera is mounted on the back side of the device, facing away + from the user + - name: CameraLocationExternal + value: 2 + description: | + The camera is attached to the device in a way that allows it to + be moved freely + + - Rotation: + type: int32_t + description: | + The camera physical mounting rotation. It is expressed as the angular + difference in degrees between two reference systems, one relative to the + camera module, and one defined on the external world scene to be + captured when projected on the image sensor pixel array. + + A camera sensor has a 2-dimensional reference system 'Rc' defined by + its pixel array read-out order. The origin is set to the first pixel + being read out, the X-axis points along the column read-out direction + towards the last columns, and the Y-axis along the row read-out + direction towards the last row. + + A typical example for a sensor with a 2592x1944 pixel array matrix + observed from the front is + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + + The external world scene reference system 'Rs' is a 2-dimensional + reference system on the focal plane of the camera module. The origin is + placed on the top-left corner of the visible scene, the X-axis points + towards the right, and the Y-axis points towards the bottom of the + scene. The top, bottom, left and right directions are intentionally not + defined and depend on the environment in which the camera is used. + + A typical example of a (very common) picture of a shark swimming from + left to right, as seen from the camera, is + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\____)\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + + With the reference system 'Rs' placed on the camera focal plane. + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + + When projected on the sensor's pixel array, the image and the associated + reference system 'Rs' are typically (but not always) inverted, due to + the camera module's lens optical inversion effect. + + Assuming the above represented scene of the swimming shark, the lens + inversion projects the scene and its reference system onto the sensor + pixel array, seen from the front of the camera sensor, as follow + + Y-axis + ^ + ! + ! + ! + ! |\_____)\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + + Note the shark being upside-down. + + The resulting projected reference system is named 'Rp'. + + The camera rotation property is then defined as the angular difference + in the counter-clockwise direction between the camera reference system + 'Rc' and the projected scene reference system 'Rp'. It is expressed in + degrees as a number in the range [0, 360[. + + Examples + + 0 degrees camera rotation + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + + 90 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + + 180 degrees camera rotation + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + + 270 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + + Example one - Webcam + + A camera module installed on the user facing part of a laptop screen + casing used for video calls. The captured images are meant to be + displayed in landscape mode (width > height) on the laptop screen. + + The camera is typically mounted upside-down to compensate the lens + optical inversion effect. + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\_____)\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + The two reference systems are aligned, the resulting camera rotation is + 0 degrees, no rotation correction needs to be applied to the resulting + image once captured to memory buffers to correctly display it to users. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\____)\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + If the camera sensor is not mounted upside-down to compensate for the + lens optical inversion, the two reference systems will not be aligned, + with 'Rp' being rotated 180 degrees relatively to 'Rc'. + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\_____)\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + + The image once captured to memory will then be rotated by 180 degrees + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \( \| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + A software rotation correction of 180 degrees should be applied to + correctly display the image. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\____)\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + Example two - Phone camera + + A camera installed on the back side of a mobile device facing away from + the user. The captured images are meant to be displayed in portrait mode + (height > width) to match the device screen orientation and the device + usage orientation used when taking the picture. + + The camera sensor is typically mounted with its pixel array longer side + aligned to the device longer side, upside-down mounted to compensate for + the lens optical inversion effect. + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\_____)\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + + The two reference systems are not aligned and the 'Rp' reference + system is rotated by 90 degrees in the counter-clockwise direction + relatively to the 'Rc' reference system. + + The image once captured to memory will be rotated. + + +-------------------------------------+ + | _ _ | + | \ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + + A correction of 90 degrees in counter-clockwise direction has to be + applied to correctly display the image in portrait mode on the device + screen. + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\____)\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ + + - Model: + type: string + description: | + The model name shall to the extent possible describe the sensor. For + most devices this is the model name of the sensor. While for some + devices the sensor model is unavailable as the sensor or the entire + camera is part of a larger unit and exposed as a black-box to the + system. In such cases the model name of the smallest device that + contains the camera sensor shall be used. + + The model name is not meant to be a camera name displayed to the + end-user, but may be combined with other camera information to create a + camera name. + + The model name is not guaranteed to be unique in the system nor is + it guaranteed to be stable or have any other properties required to make + it a good candidate to be used as a permanent identifier of a camera. + + The model name shall describe the camera in a human readable format and + shall be encoded in ASCII. + + Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. + + - UnitCellSize: + type: Size + description: | + The pixel unit cell physical size, in nanometers. + + The UnitCellSize properties defines the horizontal and vertical sizes of + a single pixel unit, including its active and non-active parts. In + other words, it expresses the horizontal and vertical distance between + the top-left corners of adjacent pixels. + + The property can be used to calculate the physical size of the sensor's + pixel array area and for calibration purposes. + + - PixelArraySize: + type: Size + description: | + The camera sensor pixel array readable area vertical and horizontal + sizes, in pixels. + + The PixelArraySize property defines the size in pixel units of the + readable part of full pixel array matrix, including optical black + pixels used for calibration, pixels which are not considered valid for + capture and active pixels containing valid image data. + + The property describes the maximum size of the raw data captured by the + camera, which might not correspond to the physical size of the sensor + pixel array matrix, as some portions of the physical pixel array matrix + are not accessible and cannot be transmitted out. + + For example, let's consider a pixel array matrix assembled as follows + + +--------------------------------------------------+ + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + ... ... ... ... ... + + ... ... ... ... ... + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + +--------------------------------------------------+ + + starting with two lines of non-readable pixels (x), followed by N lines + of readable data (D) surrounded by two columns of non-readable pixels on + each side, and ending with two more lines of non-readable pixels. Only + the readable portion is transmitted to the receiving side, defining the + sizes of the largest possible buffer of raw data that can be presented + to applications. + + PixelArraySize.width + /----------------------------------------------/ + +----------------------------------------------+ / + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + ... ... ... ... ... + ... ... ... ... ... + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + +----------------------------------------------+ / + + This defines a rectangle whose top-left corner is placed in position (0, + 0) and whose vertical and horizontal sizes are defined by this property. + All other rectangles that describe portions of the pixel array, such as + the optical black pixels rectangles and active pixel areas, are defined + relatively to this rectangle. + + All the coordinates are expressed relative to the default sensor readout + direction, without any transformation (such as horizontal and vertical + flipping) applied. When mapping them to the raw pixel buffer, + applications shall take any configured transformation into account. + + \todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::Size) + + - PixelArrayOpticalBlackRectangles: + type: Rectangle + size: [n] + description: | + The pixel array region(s) which contain optical black pixels + considered valid for calibration purposes. + + This property describes the position and size of optical black pixel + regions in the raw data buffer as stored in memory, which might differ + from their actual physical location in the pixel array matrix. + + It is important to note, in fact, that camera sensors might + automatically reorder or skip portions of their pixels array matrix when + transmitting data to the receiver. For instance, a sensor may merge the + top and bottom optical black rectangles into a single rectangle, + transmitted at the beginning of the frame. + + The pixel array contains several areas with different purposes, + interleaved by lines and columns which are said not to be valid for + capturing purposes. Invalid lines and columns are defined as invalid as + they could be positioned too close to the chip margins or to the optical + black shielding placed on top of optical black pixels. + + PixelArraySize.width + /----------------------------------------------/ + x1 x2 + +--o---------------------------------------o---+ / + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + ... ... ... ... ... + ... ... ... ... ... + y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + +----------------------------------------------+ / + + The readable pixel array matrix is composed by + 2 invalid lines (I) + 4 lines of valid optical black pixels (O) + 2 invalid lines (I) + n lines of valid pixel data (P) + 2 invalid lines (I) + + And the position of the optical black pixel rectangles is defined by + + PixelArrayOpticalBlackRectangles = { + { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + { x1, y3, 2, y4 - y3 + 1 }, + { x2, y3, 2, y4 - y3 + 1 }, + }; + + If the camera, when capturing the full pixel array matrix, automatically + skips the invalid lines and columns, producing the following data + buffer, when captured to memory + + PixelArraySize.width + /----------------------------------------------/ + x1 + +--------------------------------------------o-+ / + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + ... ... ... ... ... | + ... ... ... ... ... | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + +----------------------------------------------+ / + + then the invalid lines and columns should not be reported as part of the + PixelArraySize property in first place. + + In this case, the position of the black pixel rectangles will be + + PixelArrayOpticalBlackRectangles = { + { 0, 0, y1 + 1, PixelArraySize[0] }, + { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + }; + + \todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::OpticalBlackRectangles) + + - PixelArrayActiveAreas: + type: Rectangle + size: [n] + description: | + The PixelArrayActiveAreas property defines the (possibly multiple and + overlapping) portions of the camera sensor readable pixel matrix + which are considered valid for image acquisition purposes. + + This property describes an arbitrary number of overlapping rectangles, + with each rectangle representing the maximum image size that the camera + sensor can produce for a particular aspect ratio. They are defined + relatively to the PixelArraySize rectangle. + + When multiple rectangles are reported, they shall be ordered from the + tallest to the shortest. + + Example 1 + A camera sensor which only produces images in the 4:3 image resolution + will report a single PixelArrayActiveAreas rectangle, from which all + other image formats are obtained by either cropping the field-of-view + and/or applying pixel sub-sampling techniques such as pixel skipping or + binning. + + PixelArraySize.width + /----------------/ + x1 x2 + (0,0)-> +-o------------o-+ / + y1 o +------------+ | | + | |////////////| | | + | |////////////| | | PixelArraySize.height + | |////////////| | | + y2 o +------------+ | | + +----------------+ / + + The property reports a single rectangle + + PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + + Example 2 + A camera sensor which can produce images in different native + resolutions will report several overlapping rectangles, one for each + natively supported resolution. + + PixelArraySize.width + /------------------/ + x1 x2 x3 x4 + (0,0)-> +o---o------o---o+ / + y1 o +------+ | | + | |//////| | | + y2 o+---+------+---+| | + ||///|//////|///|| | PixelArraySize.height + y3 o+---+------+---+| | + | |//////| | | + y4 o +------+ | | + +----+------+----+ / + + The property reports two rectangles + + PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + + The first rectangle describes the maximum field-of-view of all image + formats in the 4:3 resolutions, while the second one describes the + maximum field of view for all image formats in the 16:9 resolutions. + + Multiple rectangles shall only be reported when the sensor can't capture + the pixels in the corner regions. If all the pixels in the (x1,y1) - + (x4,y4) area can be captured, the PixelArrayActiveAreas property shall + contains the single rectangle (x1,y1) - (x4,y4). + + \todo Rename this property to ActiveAreas once we will have property + categories (i.e. Properties::PixelArray::ActiveAreas) + + - ScalerCropMaximum: + type: Rectangle + description: | + The maximum valid rectangle for the controls::ScalerCrop control. This + reflects the minimum mandatory cropping applied in the camera sensor and + the rest of the pipeline. Just as the ScalerCrop control, it defines a + rectangle taken from the sensor's active pixel array. + + This property is valid only after the camera has been successfully + configured and its value may change whenever a new configuration is + applied. + + \todo Turn this property into a "maximum control value" for the + ScalerCrop control once "dynamic" controls have been implemented. + + - SensorSensitivity: + type: float + description: | + The relative sensitivity of the chosen sensor mode. + + Some sensors have readout modes with different sensitivities. For example, + a binned camera mode might, with the same exposure and gains, produce + twice the signal level of the full resolution readout. This would be + signalled by the binned mode, when it is chosen, indicating a value here + that is twice that of the full resolution mode. This value will be valid + after the configure method has returned successfully. + + - SystemDevices: + type: int64_t + size: [n] + description: | + A list of integer values of type dev_t denoting the major and minor + device numbers of the underlying devices used in the operation of this + camera. + + Different cameras may report identical devices. + +... diff --git a/libcamera/versioned_files/0.5.2/property_ids_draft.yaml b/libcamera/versioned_files/0.5.2/property_ids_draft.yaml new file mode 100644 index 0000000..62f0e24 --- /dev/null +++ b/libcamera/versioned_files/0.5.2/property_ids_draft.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +vendor: draft +controls: + - ColorFilterArrangement: + type: int32_t + vendor: draft + description: | + The arrangement of color filters on sensor; represents the colors in the + top-left 2x2 section of the sensor, in reading order. Currently + identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. + enum: + - name: RGGB + value: 0 + description: RGGB Bayer pattern + - name: GRBG + value: 1 + description: GRBG Bayer pattern + - name: GBRG + value: 2 + description: GBRG Bayer pattern + - name: BGGR + value: 3 + description: BGGR Bayer pattern + - name: RGB + value: 4 + description: | + Sensor is not Bayer; output has 3 16-bit values for each pixel, + instead of just 1 16-bit value per pixel. + - name: MONO + value: 5 + description: | + Sensor is not Bayer; output consists of a single colour channel. + +... diff --git a/libcamera/versioned_files/0.6.0/control_ids_core.yaml b/libcamera/versioned_files/0.6.0/control_ids_core.yaml new file mode 100644 index 0000000..3bcb475 --- /dev/null +++ b/libcamera/versioned_files/0.6.0/control_ids_core.yaml @@ -0,0 +1,1356 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +# Unless otherwise stated, all controls are bi-directional, i.e. they can be +# set through Request::controls() and returned out through Request::metadata(). +vendor: libcamera +controls: + - AeEnable: + type: bool + direction: in + description: | + Enable or disable the AEGC algorithm. When this control is set to true, + both ExposureTimeMode and AnalogueGainMode are set to auto, and if this + control is set to false then both are set to manual. + + If ExposureTimeMode or AnalogueGainMode are also set in the same + request as AeEnable, then the modes supplied by ExposureTimeMode or + AnalogueGainMode will take precedence. + + \sa ExposureTimeMode AnalogueGainMode + + - AeState: + type: int32_t + direction: out + description: | + Report the AEGC algorithm state. + + The AEGC algorithm computes the exposure time and the analogue gain + to be applied to the image sensor. + + The AEGC algorithm behaviour is controlled by the ExposureTimeMode and + AnalogueGainMode controls, which allow applications to decide how + the exposure time and gain are computed, in Auto or Manual mode, + independently from one another. + + The AeState control reports the AEGC algorithm state through a single + value and describes it as a single computation block which computes + both the exposure time and the analogue gain values. + + When both the exposure time and analogue gain values are configured to + be in Manual mode, the AEGC algorithm is quiescent and does not actively + compute any value and the AeState control will report AeStateIdle. + + When at least the exposure time or analogue gain are configured to be + computed by the AEGC algorithm, the AeState control will report if the + algorithm has converged to stable values for all of the controls set + to be computed in Auto mode. + + \sa AnalogueGainMode + \sa ExposureTimeMode + + enum: + - name: AeStateIdle + value: 0 + description: | + The AEGC algorithm is inactive. + + This state is returned when both AnalogueGainMode and + ExposureTimeMode are set to Manual and the algorithm is not + actively computing any value. + - name: AeStateSearching + value: 1 + description: | + The AEGC algorithm is actively computing new values, for either the + exposure time or the analogue gain, but has not converged to a + stable result yet. + + This state is returned if at least one of AnalogueGainMode or + ExposureTimeMode is auto and the algorithm hasn't converged yet. + + The AEGC algorithm converges once stable values are computed for + all of the controls set to be computed in Auto mode. Once the + algorithm converges the state is moved to AeStateConverged. + - name: AeStateConverged + value: 2 + description: | + The AEGC algorithm has converged. + + This state is returned if at least one of AnalogueGainMode or + ExposureTimeMode is Auto, and the AEGC algorithm has converged to a + stable value. + + If the measurements move too far away from the convergence point + then the AEGC algorithm might start adjusting again, in which case + the state is moved to AeStateSearching. + + # AeMeteringMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeMeteringMode: + type: int32_t + direction: inout + description: | + Specify a metering mode for the AE algorithm to use. + + The metering modes determine which parts of the image are used to + determine the scene brightness. Metering modes may be platform specific + and not all metering modes may be supported. + enum: + - name: MeteringCentreWeighted + value: 0 + description: Centre-weighted metering mode. + - name: MeteringSpot + value: 1 + description: Spot metering mode. + - name: MeteringMatrix + value: 2 + description: Matrix metering mode. + - name: MeteringCustom + value: 3 + description: Custom metering mode. + + # AeConstraintMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeConstraintMode: + type: int32_t + direction: inout + description: | + Specify a constraint mode for the AE algorithm to use. + + The constraint modes determine how the measured scene brightness is + adjusted to reach the desired target exposure. Constraint modes may be + platform specific, and not all constraint modes may be supported. + enum: + - name: ConstraintNormal + value: 0 + description: | + Default constraint mode. + + This mode aims to balance the exposure of different parts of the + image so as to reach a reasonable average level. However, highlights + in the image may appear over-exposed and lowlights may appear + under-exposed. + - name: ConstraintHighlight + value: 1 + description: | + Highlight constraint mode. + + This mode adjusts the exposure levels in order to try and avoid + over-exposing the brightest parts (highlights) of an image. + Other non-highlight parts of the image may appear under-exposed. + - name: ConstraintShadows + value: 2 + description: | + Shadows constraint mode. + + This mode adjusts the exposure levels in order to try and avoid + under-exposing the dark parts (shadows) of an image. Other normally + exposed parts of the image may appear over-exposed. + - name: ConstraintCustom + value: 3 + description: | + Custom constraint mode. + + # AeExposureMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AeExposureMode: + type: int32_t + direction: inout + description: | + Specify an exposure mode for the AE algorithm to use. + + The exposure modes specify how the desired total exposure is divided + between the exposure time and the sensor's analogue gain. They are + platform specific, and not all exposure modes may be supported. + + When one of AnalogueGainMode or ExposureTimeMode is set to Manual, + the fixed values will override any choices made by AeExposureMode. + + \sa AnalogueGainMode + \sa ExposureTimeMode + + enum: + - name: ExposureNormal + value: 0 + description: Default exposure mode. + - name: ExposureShort + value: 1 + description: Exposure mode allowing only short exposure times. + - name: ExposureLong + value: 2 + description: Exposure mode allowing long exposure times. + - name: ExposureCustom + value: 3 + description: Custom exposure mode. + + - ExposureValue: + type: float + direction: inout + description: | + Specify an Exposure Value (EV) parameter. + + The EV parameter will only be applied if the AE algorithm is currently + enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode + are in Auto mode. + + By convention EV adjusts the exposure as log2. For example + EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment + of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + + \sa AnalogueGainMode + \sa ExposureTimeMode + + - ExposureTime: + type: int32_t + direction: inout + description: | + Exposure time for the frame applied in the sensor device. + + This value is specified in microseconds. + + This control will only take effect if ExposureTimeMode is Manual. If + this control is set when ExposureTimeMode is Auto, the value will be + ignored and will not be retained. + + When reported in metadata, this control indicates what exposure time + was used for the current frame, regardless of ExposureTimeMode. + ExposureTimeMode will indicate the source of the exposure time value, + whether it came from the AE algorithm or not. + + \sa AnalogueGain + \sa ExposureTimeMode + + - ExposureTimeMode: + type: int32_t + direction: inout + description: | + Controls the source of the exposure time that is applied to the image + sensor. + + When set to Auto, the AE algorithm computes the exposure time and + configures the image sensor accordingly. When set to Manual, the value + of the ExposureTime control is used. + + When transitioning from Auto to Manual mode and no ExposureTime control + is provided by the application, the last value computed by the AE + algorithm when the mode was Auto will be used. If the ExposureTimeMode + was never set to Auto (either because the camera started in Manual mode, + or Auto is not supported by the camera), the camera should use a + best-effort default value. + + If ExposureTimeModeManual is supported, the ExposureTime control must + also be supported. + + Cameras that support manual control of the sensor shall support manual + mode for both ExposureTimeMode and AnalogueGainMode, and shall expose + the ExposureTime and AnalogueGain controls. If the camera also has an + AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall + support both manual and auto mode. If auto mode is available, it shall + be the default mode. These rules do not apply to black box cameras + such as UVC cameras, where the available gain and exposure modes are + completely dependent on what the device exposes. + + \par Flickerless exposure mode transitions + + Applications that wish to transition from ExposureTimeModeAuto to direct + control of the exposure time without causing extra flicker can do so by + selecting an ExposureTime value as close as possible to the last value + computed by the auto exposure algorithm in order to avoid any visible + flickering. + + To select the correct value to use as ExposureTime value, applications + should accommodate the natural delay in applying controls caused by the + capture pipeline frame depth. + + When switching to manual exposure mode, applications should not + immediately specify an ExposureTime value in the same request where + ExposureTimeMode is set to Manual. They should instead wait for the + first Request where ExposureTimeMode is reported as + ExposureTimeModeManual in the Request metadata, and use the reported + ExposureTime to populate the control value in the next Request to be + queued to the Camera. + + The implementation of the auto-exposure algorithm should equally try to + minimize flickering and when transitioning from manual exposure mode to + auto exposure use the last value provided by the application as starting + point. + + 1. Start with ExposureTimeMode set to Auto + + 2. Set ExposureTimeMode to Manual + + 3. Wait for the first completed request that has ExposureTimeMode + set to Manual + + 4. Copy the value reported in ExposureTime into a new request, and + submit it + + 5. Proceed to run manual exposure time as desired + + \sa ExposureTime + enum: + - name: ExposureTimeModeAuto + value: 0 + description: | + The exposure time will be calculated automatically and set by the + AE algorithm. + + If ExposureTime is set while this mode is active, it will be + ignored, and its value will not be retained. + + When transitioning from Manual to Auto mode, the AEGC should start + its adjustments based on the last set manual ExposureTime value. + - name: ExposureTimeModeManual + value: 1 + description: | + The exposure time will not be updated by the AE algorithm. + + When transitioning from Auto to Manual mode, the last computed + exposure value is used until a new value is specified through the + ExposureTime control. If an ExposureTime value is specified in the + same request where the ExposureTimeMode is changed from Auto to + Manual, the provided ExposureTime is applied immediately. + + - AnalogueGain: + type: float + direction: inout + description: | + Analogue gain value applied in the sensor device. + + The value of the control specifies the gain multiplier applied to all + colour channels. This value cannot be lower than 1.0. + + This control will only take effect if AnalogueGainMode is Manual. If + this control is set when AnalogueGainMode is Auto, the value will be + ignored and will not be retained. + + When reported in metadata, this control indicates what analogue gain + was used for the current request, regardless of AnalogueGainMode. + AnalogueGainMode will indicate the source of the analogue gain value, + whether it came from the AEGC algorithm or not. + + \sa ExposureTime + \sa AnalogueGainMode + + - AnalogueGainMode: + type: int32_t + direction: inout + description: | + Controls the source of the analogue gain that is applied to the image + sensor. + + When set to Auto, the AEGC algorithm computes the analogue gain and + configures the image sensor accordingly. When set to Manual, the value + of the AnalogueGain control is used. + + When transitioning from Auto to Manual mode and no AnalogueGain control + is provided by the application, the last value computed by the AEGC + algorithm when the mode was Auto will be used. If the AnalogueGainMode + was never set to Auto (either because the camera started in Manual mode, + or Auto is not supported by the camera), the camera should use a + best-effort default value. + + If AnalogueGainModeManual is supported, the AnalogueGain control must + also be supported. + + For cameras where we have control over the ISP, both ExposureTimeMode + and AnalogueGainMode are expected to support manual mode, and both + controls (as well as ExposureTimeMode and AnalogueGain) are expected to + be present. If the camera also has an AEGC implementation, both + ExposureTimeMode and AnalogueGainMode shall support both manual and + auto mode. If auto mode is available, it shall be the default mode. + These rules do not apply to black box cameras such as UVC cameras, + where the available gain and exposure modes are completely dependent on + what the hardware exposes. + + The same procedure described for performing flickerless transitions in + the ExposureTimeMode control documentation can be applied to analogue + gain. + + \sa ExposureTimeMode + \sa AnalogueGain + enum: + - name: AnalogueGainModeAuto + value: 0 + description: | + The analogue gain will be calculated automatically and set by the + AEGC algorithm. + + If AnalogueGain is set while this mode is active, it will be + ignored, and it will also not be retained. + + When transitioning from Manual to Auto mode, the AEGC should start + its adjustments based on the last set manual AnalogueGain value. + - name: AnalogueGainModeManual + value: 1 + description: | + The analogue gain will not be updated by the AEGC algorithm. + + When transitioning from Auto to Manual mode, the last computed + gain value is used until a new value is specified through the + AnalogueGain control. If an AnalogueGain value is specified in the + same request where the AnalogueGainMode is changed from Auto to + Manual, the provided AnalogueGain is applied immediately. + + - AeFlickerMode: + type: int32_t + direction: inout + description: | + Set the flicker avoidance mode for AGC/AEC. + + The flicker mode determines whether, and how, the AGC/AEC algorithm + attempts to hide flicker effects caused by the duty cycle of artificial + lighting. + + Although implementation dependent, many algorithms for "flicker + avoidance" work by restricting this exposure time to integer multiples + of the cycle period, wherever possible. + + Implementations may not support all of the flicker modes listed below. + + By default the system will start in FlickerAuto mode if this is + supported, otherwise the flicker mode will be set to FlickerOff. + + enum: + - name: FlickerOff + value: 0 + description: | + No flicker avoidance is performed. + - name: FlickerManual + value: 1 + description: | + Manual flicker avoidance. + + Suppress flicker effects caused by lighting running with a period + specified by the AeFlickerPeriod control. + \sa AeFlickerPeriod + - name: FlickerAuto + value: 2 + description: | + Automatic flicker period detection and avoidance. + + The system will automatically determine the most likely value of + flicker period, and avoid flicker of this frequency. Once flicker + is being corrected, it is implementation dependent whether the + system is still able to detect a change in the flicker period. + \sa AeFlickerDetected + + - AeFlickerPeriod: + type: int32_t + direction: inout + description: | + Manual flicker period in microseconds. + + This value sets the current flicker period to avoid. It is used when + AeFlickerMode is set to FlickerManual. + + To cancel 50Hz mains flicker, this should be set to 10000 (corresponding + to 100Hz), or 8333 (120Hz) for 60Hz mains. + + Setting the mode to FlickerManual when no AeFlickerPeriod has ever been + set means that no flicker cancellation occurs (until the value of this + control is updated). + + Switching to modes other than FlickerManual has no effect on the + value of the AeFlickerPeriod control. + + \sa AeFlickerMode + + - AeFlickerDetected: + type: int32_t + direction: out + description: | + Flicker period detected in microseconds. + + The value reported here indicates the currently detected flicker + period, or zero if no flicker at all is detected. + + When AeFlickerMode is set to FlickerAuto, there may be a period during + which the value reported here remains zero. Once a non-zero value is + reported, then this is the flicker period that has been detected and is + now being cancelled. + + In the case of 50Hz mains flicker, the value would be 10000 + (corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + + It is implementation dependent whether the system can continue to detect + flicker of different periods when another frequency is already being + cancelled. + + \sa AeFlickerMode + + - Brightness: + type: float + direction: inout + description: | + Specify a fixed brightness parameter. + + Positive values (up to 1.0) produce brighter images; negative values + (up to -1.0) produce darker images and 0.0 leaves pixels unchanged. + + - Contrast: + type: float + direction: inout + description: | + Specify a fixed contrast parameter. + + Normal contrast is given by the value 1.0; larger values produce images + with more contrast. + + - Lux: + type: float + direction: out + description: | + Report an estimate of the current illuminance level in lux. + + The Lux control can only be returned in metadata. + + - AwbEnable: + type: bool + direction: inout + description: | + Enable or disable the AWB. + + When AWB is enabled, the algorithm estimates the colour temperature of + the scene and computes colour gains and the colour correction matrix + automatically. The computed colour temperature, gains and correction + matrix are reported in metadata. The corresponding controls are ignored + if set in a request. + + When AWB is disabled, the colour temperature, gains and correction + matrix are not updated automatically and can be set manually in + requests. + + \sa ColourCorrectionMatrix + \sa ColourGains + \sa ColourTemperature + + # AwbMode needs further attention: + # - Auto-generate max enum value. + # - Better handling of custom types. + - AwbMode: + type: int32_t + direction: inout + description: | + Specify the range of illuminants to use for the AWB algorithm. + + The modes supported are platform specific, and not all modes may be + supported. + enum: + - name: AwbAuto + value: 0 + description: Search over the whole colour temperature range. + - name: AwbIncandescent + value: 1 + description: Incandescent AWB lamp mode. + - name: AwbTungsten + value: 2 + description: Tungsten AWB lamp mode. + - name: AwbFluorescent + value: 3 + description: Fluorescent AWB lamp mode. + - name: AwbIndoor + value: 4 + description: Indoor AWB lighting mode. + - name: AwbDaylight + value: 5 + description: Daylight AWB lighting mode. + - name: AwbCloudy + value: 6 + description: Cloudy AWB lighting mode. + - name: AwbCustom + value: 7 + description: Custom AWB mode. + + - AwbLocked: + type: bool + direction: out + description: | + Report the lock status of a running AWB algorithm. + + If the AWB algorithm is locked the value shall be set to true, if it's + converging it shall be set to false. If the AWB algorithm is not + running the control shall not be present in the metadata control list. + + \sa AwbEnable + + - ColourGains: + type: float + direction: inout + description: | + Pair of gain values for the Red and Blue colour channels, in that + order. + + ColourGains can only be applied in a Request when the AWB is disabled. + If ColourGains is set in a request but ColourTemperature is not, the + implementation shall calculate and set the ColourTemperature based on + the ColourGains. + + \sa AwbEnable + \sa ColourTemperature + size: [2] + + - ColourTemperature: + type: int32_t + direction: out + description: | + ColourTemperature of the frame, in kelvin. + + ColourTemperature can only be applied in a Request when the AWB is + disabled. + + If ColourTemperature is set in a request but ColourGains is not, the + implementation shall calculate and set the ColourGains based on the + given ColourTemperature. If ColourTemperature is set (either directly, + or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, + the ColourCorrectionMatrix is updated based on the ColourTemperature. + + The ColourTemperature used to process the frame is reported in metadata. + + \sa AwbEnable + \sa ColourCorrectionMatrix + \sa ColourGains + + - Saturation: + type: float + direction: inout + description: | + Specify a fixed saturation parameter. + + Normal saturation is given by the value 1.0; larger values produce more + saturated colours; 0.0 produces a greyscale image. + + - SensorBlackLevels: + type: int32_t + direction: out + description: | + Reports the sensor black levels used for processing a frame. + + The values are in the order R, Gr, Gb, B. They are returned as numbers + out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The + SensorBlackLevels control can only be returned in metadata. + size: [4] + + - Sharpness: + type: float + direction: inout + description: | + Intensity of the sharpening applied to the image. + + A value of 0.0 means no sharpening. The minimum value means + minimal sharpening, and shall be 0.0 unless the camera can't + disable sharpening completely. The default value shall give a + "reasonable" level of sharpening, suitable for most use cases. + The maximum value may apply extremely high levels of sharpening, + higher than anyone could reasonably want. Negative values are + not allowed. Note also that sharpening is not applied to raw + streams. + + - FocusFoM: + type: int32_t + direction: out + description: | + Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + + A larger FocusFoM value indicates a more in-focus frame. This singular + value may be based on a combination of statistics gathered from + multiple focus regions within an image. The number of focus regions and + method of combination is platform dependent. In this respect, it is not + necessarily aimed at providing a way to implement a focus algorithm by + the application, rather an indication of how in-focus a frame is. + + - ColourCorrectionMatrix: + type: float + direction: inout + description: | + The 3x3 matrix that converts camera RGB to sRGB within the imaging + pipeline. + + This should describe the matrix that is used after pixels have been + white-balanced, but before any gamma transformation. The 3x3 matrix is + stored in conventional reading order in an array of 9 floating point + values. + + ColourCorrectionMatrix can only be applied in a Request when the AWB is + disabled. + + \sa AwbEnable + \sa ColourTemperature + size: [3,3] + + - ScalerCrop: + type: Rectangle + direction: inout + description: | + Sets the image portion that will be scaled to form the whole of + the final output image. + + The (x,y) location of this rectangle is relative to the + PixelArrayActiveAreas that is being used. The units remain native + sensor pixels, even if the sensor is being used in a binning or + skipping mode. + + This control is only present when the pipeline supports scaling. Its + maximum valid value is given by the properties::ScalerCropMaximum + property, and the two can be used to implement digital zoom. + + - DigitalGain: + type: float + direction: inout + description: | + Digital gain value applied during the processing steps applied + to the image as captured from the sensor. + + The global digital gain factor is applied to all the colour channels + of the RAW image. Different pipeline models are free to + specify how the global gain factor applies to each separate + channel. + + If an imaging pipeline applies digital gain in distinct + processing steps, this value indicates their total sum. + Pipelines are free to decide how to adjust each processing + step to respect the received gain factor and shall report + their total value in the request metadata. + + - FrameDuration: + type: int64_t + direction: out + description: | + The instantaneous frame duration from start of frame exposure to start + of next exposure, expressed in microseconds. + + This control is meant to be returned in metadata. + + - FrameDurationLimits: + type: int64_t + direction: inout + description: | + The minimum and maximum (in that order) frame duration, expressed in + microseconds. + + When provided by applications, the control specifies the sensor frame + duration interval the pipeline has to use. This limits the largest + exposure time the sensor can use. For example, if a maximum frame + duration of 33ms is requested (corresponding to 30 frames per second), + the sensor will not be able to raise the exposure time above 33ms. + A fixed frame duration is achieved by setting the minimum and maximum + values to be the same. Setting both values to 0 reverts to using the + camera defaults. + + The maximum frame duration provides the absolute limit to the exposure + time computed by the AE algorithm and it overrides any exposure mode + setting specified with controls::AeExposureMode. Similarly, when a + manual exposure time is set through controls::ExposureTime, it also + gets clipped to the limits set by this control. When reported in + metadata, the control expresses the minimum and maximum frame durations + used after being clipped to the sensor provided frame duration limits. + + \sa AeExposureMode + \sa ExposureTime + + \todo Define how to calculate the capture frame rate by + defining controls to report additional delays introduced by + the capture pipeline or post-processing stages (ie JPEG + conversion, frame scaling). + + \todo Provide an explicit definition of default control values, for + this and all other controls. + + size: [2] + + - SensorTemperature: + type: float + direction: out + description: | + Temperature measure from the camera sensor in Celsius. + + This value is typically obtained by a thermal sensor present on-die or + in the camera module. The range of reported temperatures is device + dependent. + + The SensorTemperature control will only be returned in metadata if a + thermal sensor is present. + + - SensorTimestamp: + type: int64_t + direction: out + description: | + The time when the first row of the image sensor active array is exposed. + + The timestamp, expressed in nanoseconds, represents a monotonically + increasing counter since the system boot time, as defined by the + Linux-specific CLOCK_BOOTTIME clock id. + + The SensorTimestamp control can only be returned in metadata. + + \todo Define how the sensor timestamp has to be used in the reprocessing + use case. + + - AfMode: + type: int32_t + direction: inout + description: | + The mode of the AF (autofocus) algorithm. + + An implementation may choose not to implement all the modes. + + enum: + - name: AfModeManual + value: 0 + description: | + The AF algorithm is in manual mode. + + In this mode it will never perform any action nor move the lens of + its own accord, but an application can specify the desired lens + position using the LensPosition control. The AfState will always + report AfStateIdle. + + If the camera is started in AfModeManual, it will move the focus + lens to the position specified by the LensPosition control. + + This mode is the recommended default value for the AfMode control. + External cameras (as reported by the Location property set to + CameraLocationExternal) may use a different default value. + - name: AfModeAuto + value: 1 + description: | + The AF algorithm is in auto mode. + + In this mode the algorithm will never move the lens or change state + unless the AfTrigger control is used. The AfTrigger control can be + used to initiate a focus scan, the results of which will be + reported by AfState. + + If the autofocus algorithm is moved from AfModeAuto to another mode + while a scan is in progress, the scan is cancelled immediately, + without waiting for the scan to finish. + + When first entering this mode the AfState will report AfStateIdle. + When a trigger control is sent, AfState will report AfStateScanning + for a period before spontaneously changing to AfStateFocused or + AfStateFailed, depending on the outcome of the scan. It will remain + in this state until another scan is initiated by the AfTrigger + control. If a scan is cancelled (without changing to another mode), + AfState will return to AfStateIdle. + - name: AfModeContinuous + value: 2 + description: | + The AF algorithm is in continuous mode. + + In this mode the lens can re-start a scan spontaneously at any + moment, without any user intervention. The AfState still reports + whether the algorithm is currently scanning or not, though the + application has no ability to initiate or cancel scans, nor to move + the lens for itself. + + However, applications can pause the AF algorithm from continuously + scanning by using the AfPause control. This allows video or still + images to be captured whilst guaranteeing that the focus is fixed. + + When set to AfModeContinuous, the system will immediately initiate a + scan so AfState will report AfStateScanning, and will settle on one + of AfStateFocused or AfStateFailed, depending on the scan result. + + - AfRange: + type: int32_t + direction: inout + description: | + The range of focus distances that is scanned. + + An implementation may choose not to implement all the options here. + enum: + - name: AfRangeNormal + value: 0 + description: | + A wide range of focus distances is scanned. + + Scanned distances cover all the way from infinity down to close + distances, though depending on the implementation, possibly not + including the very closest macro positions. + - name: AfRangeMacro + value: 1 + description: | + Only close distances are scanned. + - name: AfRangeFull + value: 2 + description: | + The full range of focus distances is scanned. + + This range is similar to AfRangeNormal but includes the very + closest macro positions. + + - AfSpeed: + type: int32_t + direction: inout + description: | + Determine whether the AF is to move the lens as quickly as possible or + more steadily. + + For example, during video recording it may be desirable not to move the + lens too abruptly, but when in a preview mode (waiting for a still + capture) it may be helpful to move the lens as quickly as is reasonably + possible. + enum: + - name: AfSpeedNormal + value: 0 + description: Move the lens at its usual speed. + - name: AfSpeedFast + value: 1 + description: Move the lens more quickly. + + - AfMetering: + type: int32_t + direction: inout + description: | + The parts of the image used by the AF algorithm to measure focus. + enum: + - name: AfMeteringAuto + value: 0 + description: | + Let the AF algorithm decide for itself where it will measure focus. + - name: AfMeteringWindows + value: 1 + description: | + Use the rectangles defined by the AfWindows control to measure focus. + + If no windows are specified the behaviour is platform dependent. + + - AfWindows: + type: Rectangle + direction: inout + description: | + The focus windows used by the AF algorithm when AfMetering is set to + AfMeteringWindows. + + The units used are pixels within the rectangle returned by the + ScalerCropMaximum property. + + In order to be activated, a rectangle must be programmed with non-zero + width and height. Internally, these rectangles are intersected with the + ScalerCropMaximum rectangle. If the window becomes empty after this + operation, then the window is ignored. If all the windows end up being + ignored, then the behaviour is platform dependent. + + On platforms that support the ScalerCrop control (for implementing + digital zoom, for example), no automatic recalculation or adjustment of + AF windows is performed internally if the ScalerCrop is changed. If any + window lies outside the output image after the scaler crop has been + applied, it is up to the application to recalculate them. + + The details of how the windows are used are platform dependent. We note + that when there is more than one AF window, a typical implementation + might find the optimal focus position for each one and finally select + the window where the focal distance for the objects shown in that part + of the image are closest to the camera. + + size: [n] + + - AfTrigger: + type: int32_t + direction: in + description: | + Start an autofocus scan. + + This control starts an autofocus scan when AfMode is set to AfModeAuto, + and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It + can also be used to terminate a scan early. + + enum: + - name: AfTriggerStart + value: 0 + description: | + Start an AF scan. + + Setting the control to AfTriggerStart is ignored if a scan is in + progress. + - name: AfTriggerCancel + value: 1 + description: | + Cancel an AF scan. + + This does not cause the lens to move anywhere else. Ignored if no + scan is in progress. + + - AfPause: + type: int32_t + direction: in + description: | + Pause lens movements when in continuous autofocus mode. + + This control has no effect except when in continuous autofocus mode + (AfModeContinuous). It can be used to pause any lens movements while + (for example) images are captured. The algorithm remains inactive + until it is instructed to resume. + + enum: + - name: AfPauseImmediate + value: 0 + description: | + Pause the continuous autofocus algorithm immediately. + + The autofocus algorithm is paused whether or not any kind of scan + is underway. AfPauseState will subsequently report + AfPauseStatePaused. AfState may report any of AfStateScanning, + AfStateFocused or AfStateFailed, depending on the algorithm's state + when it received this control. + - name: AfPauseDeferred + value: 1 + description: | + Pause the continuous autofocus algorithm at the end of the scan. + + This is similar to AfPauseImmediate, and if the AfState is + currently reporting AfStateFocused or AfStateFailed it will remain + in that state and AfPauseState will report AfPauseStatePaused. + + However, if the algorithm is scanning (AfStateScanning), + AfPauseState will report AfPauseStatePausing until the scan is + finished, at which point AfState will report one of AfStateFocused + or AfStateFailed, and AfPauseState will change to + AfPauseStatePaused. + + - name: AfPauseResume + value: 2 + description: | + Resume continuous autofocus operation. + + The algorithm starts again from exactly where it left off, and + AfPauseState will report AfPauseStateRunning. + + - LensPosition: + type: float + direction: inout + description: | + Set and report the focus lens position. + + This control instructs the lens to move to a particular position and + also reports back the position of the lens for each frame. + + The LensPosition control is ignored unless the AfMode is set to + AfModeManual, though the value is reported back unconditionally in all + modes. + + This value, which is generally a non-integer, is the reciprocal of the + focal distance in metres, also known as dioptres. That is, to set a + focal distance D, the lens position LP is given by + + \f$LP = \frac{1\mathrm{m}}{D}\f$ + + For example: + + - 0 moves the lens to infinity. + - 0.5 moves the lens to focus on objects 2m away. + - 2 moves the lens to focus on objects 50cm away. + - And larger values will focus the lens closer. + + The default value of the control should indicate a good general + position for the lens, often corresponding to the hyperfocal distance + (the closest position for which objects at infinity are still + acceptably sharp). The minimum will often be zero (meaning infinity), + and the maximum value defines the closest focus position. + + \todo Define a property to report the Hyperfocal distance of calibrated + lenses. + + - AfState: + type: int32_t + direction: out + description: | + The current state of the AF algorithm. + + This control reports the current state of the AF algorithm in + conjunction with the reported AfMode value and (in continuous AF mode) + the AfPauseState value. The possible state changes are described below, + though we note the following state transitions that occur when the + AfMode is changed. + + If the AfMode is set to AfModeManual, then the AfState will always + report AfStateIdle (even if the lens is subsequently moved). Changing + to the AfModeManual state does not initiate any lens movement. + + If the AfMode is set to AfModeAuto then the AfState will report + AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent + together then AfState will omit AfStateIdle and move straight to + AfStateScanning (and start a scan). + + If the AfMode is set to AfModeContinuous then the AfState will + initially report AfStateScanning. + + enum: + - name: AfStateIdle + value: 0 + description: | + The AF algorithm is in manual mode (AfModeManual) or in auto mode + (AfModeAuto) and a scan has not yet been triggered, or an + in-progress scan was cancelled. + - name: AfStateScanning + value: 1 + description: | + The AF algorithm is in auto mode (AfModeAuto), and a scan has been + started using the AfTrigger control. + + The scan can be cancelled by sending AfTriggerCancel at which point + the algorithm will either move back to AfStateIdle or, if the scan + actually completes before the cancel request is processed, to one + of AfStateFocused or AfStateFailed. + + Alternatively the AF algorithm could be in continuous mode + (AfModeContinuous) at which point it may enter this state + spontaneously whenever it determines that a rescan is needed. + - name: AfStateFocused + value: 2 + description: | + The AF algorithm is in auto (AfModeAuto) or continuous + (AfModeContinuous) mode and a scan has completed with the result + that the algorithm believes the image is now in focus. + - name: AfStateFailed + value: 3 + description: | + The AF algorithm is in auto (AfModeAuto) or continuous + (AfModeContinuous) mode and a scan has completed with the result + that the algorithm did not find a good focus position. + + - AfPauseState: + type: int32_t + direction: out + description: | + Report whether the autofocus is currently running, paused or pausing. + + This control is only applicable in continuous (AfModeContinuous) mode, + and reports whether the algorithm is currently running, paused or + pausing (that is, will pause as soon as any in-progress scan + completes). + + Any change to AfMode will cause AfPauseStateRunning to be reported. + + enum: + - name: AfPauseStateRunning + value: 0 + description: | + Continuous AF is running and the algorithm may restart a scan + spontaneously. + - name: AfPauseStatePausing + value: 1 + description: | + Continuous AF has been sent an AfPauseDeferred control, and will + pause as soon as any in-progress scan completes. + + When the scan completes, the AfPauseState control will report + AfPauseStatePaused. No new scans will be start spontaneously until + the AfPauseResume control is sent. + - name: AfPauseStatePaused + value: 2 + description: | + Continuous AF is paused. + + No further state changes or lens movements will occur until the + AfPauseResume control is sent. + + - HdrMode: + type: int32_t + direction: inout + description: | + Set the mode to be used for High Dynamic Range (HDR) imaging. + + HDR techniques typically include multiple exposure, image fusion and + tone mapping techniques to improve the dynamic range of the resulting + images. + + When using an HDR mode, images are captured with different sets of AGC + settings called HDR channels. Channels indicate in particular the type + of exposure (short, medium or long) used to capture the raw image, + before fusion. Each HDR image is tagged with the corresponding channel + using the HdrChannel control. + + \sa HdrChannel + + enum: + - name: HdrModeOff + value: 0 + description: | + HDR is disabled. + + Metadata for this frame will not include the HdrChannel control. + - name: HdrModeMultiExposureUnmerged + value: 1 + description: | + Multiple exposures will be generated in an alternating fashion. + + The multiple exposures will not be merged together and will be + returned to the application as they are. Each image will be tagged + with the correct HDR channel, indicating what kind of exposure it + is. The tag should be the same as in the HdrModeMultiExposure case. + + The expectation is that an application using this mode would merge + the frames to create HDR images for itself if it requires them. + - name: HdrModeMultiExposure + value: 2 + description: | + Multiple exposures will be generated and merged to create HDR + images. + + Each image will be tagged with the HDR channel (long, medium or + short) that arrived and which caused this image to be output. + + Systems that use two channels for HDR will return images tagged + alternately as the short and long channel. Systems that use three + channels for HDR will cycle through the short, medium and long + channel before repeating. + - name: HdrModeSingleExposure + value: 3 + description: | + Multiple frames all at a single exposure will be used to create HDR + images. + + These images should be reported as all corresponding to the HDR + short channel. + - name: HdrModeNight + value: 4 + description: | + Multiple frames will be combined to produce "night mode" images. + + It is up to the implementation exactly which HDR channels it uses, + and the images will all be tagged accordingly with the correct HDR + channel information. + + - HdrChannel: + type: int32_t + direction: out + description: | + The HDR channel used to capture the frame. + + This value is reported back to the application so that it can discover + whether this capture corresponds to the short or long exposure image + (or any other image used by the HDR procedure). An application can + monitor the HDR channel to discover when the differently exposed images + have arrived. + + This metadata is only available when an HDR mode has been enabled. + + \sa HdrMode + + enum: + - name: HdrChannelNone + value: 0 + description: | + This image does not correspond to any of the captures used to create + an HDR image. + - name: HdrChannelShort + value: 1 + description: | + This is a short exposure image. + - name: HdrChannelMedium + value: 2 + description: | + This is a medium exposure image. + - name: HdrChannelLong + value: 3 + description: | + This is a long exposure image. + + - Gamma: + type: float + direction: inout + description: | + Specify a fixed gamma value. + + The default gamma value must be 2.2 which closely mimics sRGB gamma. + Note that this is camera gamma, so it is applied as 1.0/gamma. + + - DebugMetadataEnable: + type: bool + direction: inout + description: | + Enable or disable the debug metadata. + + - FrameWallClock: + type: int64_t + direction: out + description: | + This timestamp corresponds to the same moment in time as the + SensorTimestamp, but is represented as a wall clock time as measured by + the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is + expressed in nanoseconds. + + Being a wall clock measurement, it can be used to synchronise timing + across different devices. + + \sa SensorTimestamp + + The FrameWallClock control can only be returned in metadata. + - WdrMode: + type: int32_t + direction: inout + description: | + Set the WDR mode. + + The WDR mode is used to select the algorithm used for global tone + mapping. It will automatically reduce the exposure time of the sensor + so that there are only a small number of saturated pixels in the image. + The algorithm then compensates for the loss of brightness by applying a + global tone mapping curve to the image. + enum: + - name: WdrOff + value: 0 + description: Wdr is disabled. + - name: WdrLinear + value: 1 + description: + Apply a linear global tone mapping curve. + + A curve with two linear sections is applied. This produces good + results at the expense of a slightly artificial look. + - name: WdrPower + value: 2 + description: | + Apply a power global tone mapping curve. + + This curve has high gain values on the dark areas of an image and + high compression values on the bright area. It therefore tends to + produce noticeable noise artifacts. + - name: WdrExponential + value: 3 + description: | + Apply an exponential global tone mapping curve. + + This curve has lower gain values in dark areas compared to the power + curve but produces a more natural look compared to the linear curve. + It is therefore the best choice for most scenes. + - name: WdrHistogramEqualization + value: 4 + description: | + Apply histogram equalization. + + This curve preserves most of the information of the image at the + expense of a very artificial look. It is therefore best suited for + technical analysis. + - WdrStrength: + type: float + direction: in + description: | + Specify the strength of the wdr algorithm. The exact meaning of this + value is specific to the algorithm in use. Usually a value of 0 means no + global tone mapping is applied. A values of 1 is the default value and + the correct value for most scenes. A value above 1 increases the global + tone mapping effect and can lead to unrealistic image effects. + - WdrMaxBrightPixels: + type: float + direction: in + description: | + Percentage of allowed (nearly) saturated pixels. The WDR algorithm + reduces the WdrExposureValue until the amount of pixels that are close + to saturation is lower than this value. + + - LensDewarpEnable: + type: bool + direction: inout + description: | + Enable or disable lens dewarping. This control is only available if lens + dewarp parameters are configured in the tuning file. + +... diff --git a/libcamera/versioned_files/0.6.0/control_ids_debug.yaml b/libcamera/versioned_files/0.6.0/control_ids_debug.yaml new file mode 100644 index 0000000..7975327 --- /dev/null +++ b/libcamera/versioned_files/0.6.0/control_ids_debug.yaml @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +%YAML 1.1 +--- +vendor: debug +controls: [] diff --git a/libcamera/versioned_files/0.6.0/control_ids_draft.yaml b/libcamera/versioned_files/0.6.0/control_ids_draft.yaml new file mode 100644 index 0000000..03309ee --- /dev/null +++ b/libcamera/versioned_files/0.6.0/control_ids_draft.yaml @@ -0,0 +1,297 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +# Unless otherwise stated, all controls are bi-directional, i.e. they can be +# set through Request::controls() and returned out through Request::metadata(). +vendor: draft +controls: + - AePrecaptureTrigger: + type: int32_t + direction: inout + description: | + Control for AE metering trigger. Currently identical to + ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + + Whether the camera device will trigger a precapture metering sequence + when it processes this request. + enum: + - name: AePrecaptureTriggerIdle + value: 0 + description: The trigger is idle. + - name: AePrecaptureTriggerStart + value: 1 + description: The pre-capture AE metering is started by the camera. + - name: AePrecaptureTriggerCancel + value: 2 + description: | + The camera will cancel any active or completed metering sequence. + The AE algorithm is reset to its initial state. + + - NoiseReductionMode: + type: int32_t + direction: inout + description: | + Control to select the noise reduction algorithm mode. Currently + identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. + enum: + - name: NoiseReductionModeOff + value: 0 + description: No noise reduction is applied + - name: NoiseReductionModeFast + value: 1 + description: | + Noise reduction is applied without reducing the frame rate. + - name: NoiseReductionModeHighQuality + value: 2 + description: | + High quality noise reduction at the expense of frame rate. + - name: NoiseReductionModeMinimal + value: 3 + description: | + Minimal noise reduction is applied without reducing the frame rate. + - name: NoiseReductionModeZSL + value: 4 + description: | + Noise reduction is applied at different levels to different streams. + + - ColorCorrectionAberrationMode: + type: int32_t + direction: inout + description: | + Control to select the color correction aberration mode. Currently + identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. + enum: + - name: ColorCorrectionAberrationOff + value: 0 + description: No aberration correction is applied. + - name: ColorCorrectionAberrationFast + value: 1 + description: Aberration correction will not slow down the frame rate. + - name: ColorCorrectionAberrationHighQuality + value: 2 + description: | + High quality aberration correction which might reduce the frame + rate. + + - AwbState: + type: int32_t + direction: out + description: | + Control to report the current AWB algorithm state. Currently identical + to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. + enum: + - name: AwbStateInactive + value: 0 + description: The AWB algorithm is inactive. + - name: AwbStateSearching + value: 1 + description: The AWB algorithm has not converged yet. + - name: AwbConverged + value: 2 + description: The AWB algorithm has converged. + - name: AwbLocked + value: 3 + description: The AWB algorithm is locked. + + - SensorRollingShutterSkew: + type: int64_t + direction: out + description: | + Control to report the time between the start of exposure of the first + row and the start of exposure of the last row. Currently identical to + ANDROID_SENSOR_ROLLING_SHUTTER_SKEW + + - LensShadingMapMode: + type: int32_t + direction: inout + description: | + Control to report if the lens shading map is available. Currently + identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. + enum: + - name: LensShadingMapModeOff + value: 0 + description: No lens shading map mode is available. + - name: LensShadingMapModeOn + value: 1 + description: The lens shading map mode is available. + + - PipelineDepth: + type: int32_t + direction: out + description: | + Specifies the number of pipeline stages the frame went through from when + it was exposed to when the final completed result was available to the + framework. Always less than or equal to PipelineMaxDepth. Currently + identical to ANDROID_REQUEST_PIPELINE_DEPTH. + + The typical value for this control is 3 as a frame is first exposed, + captured and then processed in a single pass through the ISP. Any + additional processing step performed after the ISP pass (in example face + detection, additional format conversions etc) count as an additional + pipeline stage. + + - MaxLatency: + type: int32_t + direction: out + description: | + The maximum number of frames that can occur after a request (different + than the previous) has been submitted, and before the result's state + becomes synchronized. A value of -1 indicates unknown latency, and 0 + indicates per-frame control. Currently identical to + ANDROID_SYNC_MAX_LATENCY. + + - TestPatternMode: + type: int32_t + direction: inout + description: | + Control to select the test pattern mode. Currently identical to + ANDROID_SENSOR_TEST_PATTERN_MODE. + enum: + - name: TestPatternModeOff + value: 0 + description: | + No test pattern mode is used. The camera device returns frames from + the image sensor. + - name: TestPatternModeSolidColor + value: 1 + description: | + Each pixel in [R, G_even, G_odd, B] is replaced by its respective + color channel provided in test pattern data. + \todo Add control for test pattern data. + - name: TestPatternModeColorBars + value: 2 + description: | + All pixel data is replaced with an 8-bar color pattern. The vertical + bars (left-to-right) are as follows; white, yellow, cyan, green, + magenta, red, blue and black. Each bar should take up 1/8 of the + sensor pixel array width. When this is not possible, the bar size + should be rounded down to the nearest integer and the pattern can + repeat on the right side. Each bar's height must always take up the + full sensor pixel array height. + - name: TestPatternModeColorBarsFadeToGray + value: 3 + description: | + The test pattern is similar to TestPatternModeColorBars, + except that each bar should start at its specified color at the top + and fade to gray at the bottom. Furthermore each bar is further + subdevided into a left and right half. The left half should have a + smooth gradient, and the right half should have a quantized + gradient. In particular, the right half's should consist of blocks + of the same color for 1/16th active sensor pixel array width. The + least significant bits in the quantized gradient should be copied + from the most significant bits of the smooth gradient. The height of + each bar should always be a multiple of 128. When this is not the + case, the pattern should repeat at the bottom of the image. + - name: TestPatternModePn9 + value: 4 + description: | + All pixel data is replaced by a pseudo-random sequence generated + from a PN9 512-bit sequence (typically implemented in hardware with + a linear feedback shift register). The generator should be reset at + the beginning of each frame, and thus each subsequent raw frame with + this test pattern should be exactly the same as the last. + - name: TestPatternModeCustom1 + value: 256 + description: | + The first custom test pattern. All custom patterns that are + available only on this camera device are at least this numeric + value. All of the custom test patterns will be static (that is the + raw image must not vary from frame to frame). + + - FaceDetectMode: + type: int32_t + direction: inout + description: | + Control to select the face detection mode used by the pipeline. + + Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + + \sa FaceDetectFaceRectangles + \sa FaceDetectFaceScores + \sa FaceDetectFaceLandmarks + \sa FaceDetectFaceIds + + enum: + - name: FaceDetectModeOff + value: 0 + description: | + Pipeline doesn't perform face detection and doesn't report any + control related to face detection. + - name: FaceDetectModeSimple + value: 1 + description: | + Pipeline performs face detection and reports the + FaceDetectFaceRectangles and FaceDetectFaceScores controls for each + detected face. FaceDetectFaceLandmarks and FaceDetectFaceIds are + optional. + - name: FaceDetectModeFull + value: 2 + description: | + Pipeline performs face detection and reports all the controls + related to face detection including FaceDetectFaceRectangles, + FaceDetectFaceScores, FaceDetectFaceLandmarks, and + FaceDeteceFaceIds for each detected face. + + - FaceDetectFaceRectangles: + type: Rectangle + direction: out + description: | + Boundary rectangles of the detected faces. The number of values is + the number of detected faces. + + The FaceDetectFaceRectangles control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. + size: [n] + + - FaceDetectFaceScores: + type: uint8_t + direction: out + description: | + Confidence score of each of the detected faces. The range of score is + [0, 100]. The number of values should be the number of faces reported + in FaceDetectFaceRectangles. + + The FaceDetectFaceScores control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_SCORES. + size: [n] + + - FaceDetectFaceLandmarks: + type: Point + direction: out + description: | + Array of human face landmark coordinates in format [..., left_eye_i, + right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The + number of values should be 3 * the number of faces reported in + FaceDetectFaceRectangles. + + The FaceDetectFaceLandmarks control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. + size: [n] + + - FaceDetectFaceIds: + type: int32_t + direction: out + description: | + Each detected face is given a unique ID that is valid for as long as the + face is visible to the camera device. A face that leaves the field of + view and later returns may be assigned a new ID. The number of values + should be the number of faces reported in FaceDetectFaceRectangles. + + The FaceDetectFaceIds control can only be returned in metadata. + + Currently identical to ANDROID_STATISTICS_FACE_IDS. + size: [n] + +... diff --git a/libcamera/versioned_files/0.6.0/control_ids_rpi.yaml b/libcamera/versioned_files/0.6.0/control_ids_rpi.yaml new file mode 100644 index 0000000..a861511 --- /dev/null +++ b/libcamera/versioned_files/0.6.0/control_ids_rpi.yaml @@ -0,0 +1,186 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2023, Raspberry Pi Ltd +# +%YAML 1.1 +--- +# Raspberry Pi (VC4 and PiSP) specific vendor controls +vendor: rpi +controls: + - StatsOutputEnable: + type: bool + direction: inout + description: | + Toggles the Raspberry Pi IPA to output the hardware generated statistics. + + When this control is set to true, the IPA outputs a binary dump of the + hardware generated statistics through the Request metadata in the + Bcm2835StatsOutput control. + + \sa Bcm2835StatsOutput + + - Bcm2835StatsOutput: + type: uint8_t + size: [n] + direction: out + description: | + Span of the BCM2835 ISP generated statistics for the current frame. + + This is sent in the Request metadata if the StatsOutputEnable is set to + true. The statistics struct definition can be found in + include/linux/bcm2835-isp.h. + + \sa StatsOutputEnable + + - ScalerCrops: + type: Rectangle + size: [n] + direction: out + description: | + An array of rectangles, where each singular value has identical + functionality to the ScalerCrop control. This control allows the + Raspberry Pi pipeline handler to control individual scaler crops per + output stream. + + The order of rectangles passed into the control must match the order of + streams configured by the application. The pipeline handler will only + configure crop retangles up-to the number of output streams configured. + All subsequent rectangles passed into this control are ignored by the + pipeline handler. + + If both rpi::ScalerCrops and ScalerCrop controls are present in a + ControlList, the latter is discarded, and crops are obtained from this + control. + + Note that using different crop rectangles for each output stream with + this control is only applicable on the Pi5/PiSP platform. This control + should also be considered temporary/draft and will be replaced with + official libcamera API support for per-stream controls in the future. + + \sa ScalerCrop + + - PispStatsOutput: + type: uint8_t + direction: out + size: [n] + description: | + Span of the PiSP Frontend ISP generated statistics for the current + frame. This is sent in the Request metadata if the StatsOutputEnable is + set to true. The statistics struct definition can be found in + https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + + \sa StatsOutputEnable + + - SyncMode: + type: int32_t + direction: in + description: | + Enable or disable camera synchronisation ("sync") mode. + + When sync mode is enabled, a camera will synchronise frames temporally + with other cameras, either attached to the same device or a different + one. There should be one "server" device, which broadcasts timing + information to one or more "clients". Communication is one-way, from + server to clients only, and it is only clients that adjust their frame + timings to match the server. + + Sync mode requires all cameras to be running at (as far as possible) the + same fixed framerate. Clients may continue to make adjustments to keep + their cameras synchronised with the server for the duration of the + session, though any updates after the initial ones should remain small. + + \sa SyncReady + \sa SyncTimer + \sa SyncFrames + + enum: + - name: SyncModeOff + value: 0 + description: Disable sync mode. + - name: SyncModeServer + value: 1 + description: | + Enable sync mode, act as server. The server broadcasts timing + messages to any clients that are listening, so that the clients can + synchronise their camera frames with the server's. + - name: SyncModeClient + value: 2 + description: | + Enable sync mode, act as client. A client listens for any server + messages, and arranges for its camera frames to synchronise as + closely as possible with the server's. Many clients can listen out + for the same server. Clients can also be started ahead of any + servers, causing them merely to wait for the server to start. + + - SyncReady: + type: bool + direction: out + description: | + When using the camera synchronisation algorithm, the server broadcasts + timing information to the clients. This also includes the time (some + number of frames in the future, called the "ready time") at which the + server will signal its controlling application, using this control, to + start using the image frames. + + The client receives the "ready time" from the server, and will signal + its application to start using the frames at this same moment. + + While this control value is false, applications (on both client and + server) should continue to wait, and not use the frames. + + Once this value becomes true, it means that this is the first frame + where the server and its clients have agreed that they will both be + synchronised and that applications should begin consuming frames. + Thereafter, this control will continue to signal the value true for + the rest of the session. + + \sa SyncMode + \sa SyncTimer + \sa SyncFrames + + - SyncTimer: + type: int64_t + direction: out + description: | + This reports the amount of time, in microseconds, until the "ready + time", at which the server and client will signal their controlling + applications that the frames are now synchronised and should be + used. The value may be refined slightly over time, becoming more precise + as the "ready time" approaches. + + Servers always report this value, whereas clients will omit this control + until they have received a message from the server that enables them to + calculate it. + + Normally the value will start positive (the "ready time" is in the + future), and decrease towards zero, before becoming negative (the "ready + time" has elapsed). So there should be just one frame where the timer + value is, or is very close to, zero - the one for which the SyncReady + control becomes true. At this moment, the value indicates how closely + synchronised the client believes it is with the server. + + But note that if frames are being dropped, then the "near zero" valued + frame, or indeed any other, could be skipped. In these cases the timer + value allows an application to deduce that this has happened. + + \sa SyncMode + \sa SyncReady + \sa SyncFrames + + - SyncFrames: + type: int32_t + direction: in + description: | + The number of frames the server should wait, after enabling + SyncModeServer, before signalling (via the SyncReady control) that + frames should be used. This therefore determines the "ready time" for + all synchronised cameras. + + This control value should be set only for the device that is to act as + the server, before or at the same moment at which SyncModeServer is + enabled. + + \sa SyncMode + \sa SyncReady + \sa SyncTimer +... diff --git a/libcamera/versioned_files/0.6.0/controls.rs b/libcamera/versioned_files/0.6.0/controls.rs new file mode 100644 index 0000000..933c2ac --- /dev/null +++ b/libcamera/versioned_files/0.6.0/controls.rs @@ -0,0 +1,5211 @@ +use std::ops::{Deref, DerefMut}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +#[allow(unused_imports)] +use crate::control::{Control, Property, ControlEntry, DynControlEntry}; +use crate::control_value::{ControlValue, ControlValueError}; +#[allow(unused_imports)] +use crate::geometry::{Rectangle, Point, Size}; +#[allow(unused_imports)] +use libcamera_sys::*; +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(u32)] +pub enum ControlId { + /// Enable or disable the AEGC algorithm. When this control is set to true, + /// both ExposureTimeMode and AnalogueGainMode are set to auto, and if this + /// control is set to false then both are set to manual. + /// + /// If ExposureTimeMode or AnalogueGainMode are also set in the same + /// request as AeEnable, then the modes supplied by ExposureTimeMode or + /// AnalogueGainMode will take precedence. + /// + /// \sa ExposureTimeMode AnalogueGainMode + AeEnable = AE_ENABLE, + /// Report the AEGC algorithm state. + /// + /// The AEGC algorithm computes the exposure time and the analogue gain + /// to be applied to the image sensor. + /// + /// The AEGC algorithm behaviour is controlled by the ExposureTimeMode and + /// AnalogueGainMode controls, which allow applications to decide how + /// the exposure time and gain are computed, in Auto or Manual mode, + /// independently from one another. + /// + /// The AeState control reports the AEGC algorithm state through a single + /// value and describes it as a single computation block which computes + /// both the exposure time and the analogue gain values. + /// + /// When both the exposure time and analogue gain values are configured to + /// be in Manual mode, the AEGC algorithm is quiescent and does not actively + /// compute any value and the AeState control will report AeStateIdle. + /// + /// When at least the exposure time or analogue gain are configured to be + /// computed by the AEGC algorithm, the AeState control will report if the + /// algorithm has converged to stable values for all of the controls set + /// to be computed in Auto mode. + /// + /// \sa AnalogueGainMode + /// \sa ExposureTimeMode + AeState = AE_STATE, + /// Specify a metering mode for the AE algorithm to use. + /// + /// The metering modes determine which parts of the image are used to + /// determine the scene brightness. Metering modes may be platform specific + /// and not all metering modes may be supported. + AeMeteringMode = AE_METERING_MODE, + /// Specify a constraint mode for the AE algorithm to use. + /// + /// The constraint modes determine how the measured scene brightness is + /// adjusted to reach the desired target exposure. Constraint modes may be + /// platform specific, and not all constraint modes may be supported. + AeConstraintMode = AE_CONSTRAINT_MODE, + /// Specify an exposure mode for the AE algorithm to use. + /// + /// The exposure modes specify how the desired total exposure is divided + /// between the exposure time and the sensor's analogue gain. They are + /// platform specific, and not all exposure modes may be supported. + /// + /// When one of AnalogueGainMode or ExposureTimeMode is set to Manual, + /// the fixed values will override any choices made by AeExposureMode. + /// + /// \sa AnalogueGainMode + /// \sa ExposureTimeMode + AeExposureMode = AE_EXPOSURE_MODE, + /// Specify an Exposure Value (EV) parameter. + /// + /// The EV parameter will only be applied if the AE algorithm is currently + /// enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode + /// are in Auto mode. + /// + /// By convention EV adjusts the exposure as log2. For example + /// EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment + /// of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + /// + /// \sa AnalogueGainMode + /// \sa ExposureTimeMode + ExposureValue = EXPOSURE_VALUE, + /// Exposure time for the frame applied in the sensor device. + /// + /// This value is specified in microseconds. + /// + /// This control will only take effect if ExposureTimeMode is Manual. If + /// this control is set when ExposureTimeMode is Auto, the value will be + /// ignored and will not be retained. + /// + /// When reported in metadata, this control indicates what exposure time + /// was used for the current frame, regardless of ExposureTimeMode. + /// ExposureTimeMode will indicate the source of the exposure time value, + /// whether it came from the AE algorithm or not. + /// + /// \sa AnalogueGain + /// \sa ExposureTimeMode + ExposureTime = EXPOSURE_TIME, + /// Controls the source of the exposure time that is applied to the image + /// sensor. + /// + /// When set to Auto, the AE algorithm computes the exposure time and + /// configures the image sensor accordingly. When set to Manual, the value + /// of the ExposureTime control is used. + /// + /// When transitioning from Auto to Manual mode and no ExposureTime control + /// is provided by the application, the last value computed by the AE + /// algorithm when the mode was Auto will be used. If the ExposureTimeMode + /// was never set to Auto (either because the camera started in Manual mode, + /// or Auto is not supported by the camera), the camera should use a + /// best-effort default value. + /// + /// If ExposureTimeModeManual is supported, the ExposureTime control must + /// also be supported. + /// + /// Cameras that support manual control of the sensor shall support manual + /// mode for both ExposureTimeMode and AnalogueGainMode, and shall expose + /// the ExposureTime and AnalogueGain controls. If the camera also has an + /// AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall + /// support both manual and auto mode. If auto mode is available, it shall + /// be the default mode. These rules do not apply to black box cameras + /// such as UVC cameras, where the available gain and exposure modes are + /// completely dependent on what the device exposes. + /// + /// \par Flickerless exposure mode transitions + /// + /// Applications that wish to transition from ExposureTimeModeAuto to direct + /// control of the exposure time without causing extra flicker can do so by + /// selecting an ExposureTime value as close as possible to the last value + /// computed by the auto exposure algorithm in order to avoid any visible + /// flickering. + /// + /// To select the correct value to use as ExposureTime value, applications + /// should accommodate the natural delay in applying controls caused by the + /// capture pipeline frame depth. + /// + /// When switching to manual exposure mode, applications should not + /// immediately specify an ExposureTime value in the same request where + /// ExposureTimeMode is set to Manual. They should instead wait for the + /// first Request where ExposureTimeMode is reported as + /// ExposureTimeModeManual in the Request metadata, and use the reported + /// ExposureTime to populate the control value in the next Request to be + /// queued to the Camera. + /// + /// The implementation of the auto-exposure algorithm should equally try to + /// minimize flickering and when transitioning from manual exposure mode to + /// auto exposure use the last value provided by the application as starting + /// point. + /// + /// 1. Start with ExposureTimeMode set to Auto + /// + /// 2. Set ExposureTimeMode to Manual + /// + /// 3. Wait for the first completed request that has ExposureTimeMode + /// set to Manual + /// + /// 4. Copy the value reported in ExposureTime into a new request, and + /// submit it + /// + /// 5. Proceed to run manual exposure time as desired + /// + /// \sa ExposureTime + ExposureTimeMode = EXPOSURE_TIME_MODE, + /// Analogue gain value applied in the sensor device. + /// + /// The value of the control specifies the gain multiplier applied to all + /// colour channels. This value cannot be lower than 1.0. + /// + /// This control will only take effect if AnalogueGainMode is Manual. If + /// this control is set when AnalogueGainMode is Auto, the value will be + /// ignored and will not be retained. + /// + /// When reported in metadata, this control indicates what analogue gain + /// was used for the current request, regardless of AnalogueGainMode. + /// AnalogueGainMode will indicate the source of the analogue gain value, + /// whether it came from the AEGC algorithm or not. + /// + /// \sa ExposureTime + /// \sa AnalogueGainMode + AnalogueGain = ANALOGUE_GAIN, + /// Controls the source of the analogue gain that is applied to the image + /// sensor. + /// + /// When set to Auto, the AEGC algorithm computes the analogue gain and + /// configures the image sensor accordingly. When set to Manual, the value + /// of the AnalogueGain control is used. + /// + /// When transitioning from Auto to Manual mode and no AnalogueGain control + /// is provided by the application, the last value computed by the AEGC + /// algorithm when the mode was Auto will be used. If the AnalogueGainMode + /// was never set to Auto (either because the camera started in Manual mode, + /// or Auto is not supported by the camera), the camera should use a + /// best-effort default value. + /// + /// If AnalogueGainModeManual is supported, the AnalogueGain control must + /// also be supported. + /// + /// For cameras where we have control over the ISP, both ExposureTimeMode + /// and AnalogueGainMode are expected to support manual mode, and both + /// controls (as well as ExposureTimeMode and AnalogueGain) are expected to + /// be present. If the camera also has an AEGC implementation, both + /// ExposureTimeMode and AnalogueGainMode shall support both manual and + /// auto mode. If auto mode is available, it shall be the default mode. + /// These rules do not apply to black box cameras such as UVC cameras, + /// where the available gain and exposure modes are completely dependent on + /// what the hardware exposes. + /// + /// The same procedure described for performing flickerless transitions in + /// the ExposureTimeMode control documentation can be applied to analogue + /// gain. + /// + /// \sa ExposureTimeMode + /// \sa AnalogueGain + AnalogueGainMode = ANALOGUE_GAIN_MODE, + /// Set the flicker avoidance mode for AGC/AEC. + /// + /// The flicker mode determines whether, and how, the AGC/AEC algorithm + /// attempts to hide flicker effects caused by the duty cycle of artificial + /// lighting. + /// + /// Although implementation dependent, many algorithms for "flicker + /// avoidance" work by restricting this exposure time to integer multiples + /// of the cycle period, wherever possible. + /// + /// Implementations may not support all of the flicker modes listed below. + /// + /// By default the system will start in FlickerAuto mode if this is + /// supported, otherwise the flicker mode will be set to FlickerOff. + AeFlickerMode = AE_FLICKER_MODE, + /// Manual flicker period in microseconds. + /// + /// This value sets the current flicker period to avoid. It is used when + /// AeFlickerMode is set to FlickerManual. + /// + /// To cancel 50Hz mains flicker, this should be set to 10000 (corresponding + /// to 100Hz), or 8333 (120Hz) for 60Hz mains. + /// + /// Setting the mode to FlickerManual when no AeFlickerPeriod has ever been + /// set means that no flicker cancellation occurs (until the value of this + /// control is updated). + /// + /// Switching to modes other than FlickerManual has no effect on the + /// value of the AeFlickerPeriod control. + /// + /// \sa AeFlickerMode + AeFlickerPeriod = AE_FLICKER_PERIOD, + /// Flicker period detected in microseconds. + /// + /// The value reported here indicates the currently detected flicker + /// period, or zero if no flicker at all is detected. + /// + /// When AeFlickerMode is set to FlickerAuto, there may be a period during + /// which the value reported here remains zero. Once a non-zero value is + /// reported, then this is the flicker period that has been detected and is + /// now being cancelled. + /// + /// In the case of 50Hz mains flicker, the value would be 10000 + /// (corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + /// + /// It is implementation dependent whether the system can continue to detect + /// flicker of different periods when another frequency is already being + /// cancelled. + /// + /// \sa AeFlickerMode + AeFlickerDetected = AE_FLICKER_DETECTED, + /// Specify a fixed brightness parameter. + /// + /// Positive values (up to 1.0) produce brighter images; negative values + /// (up to -1.0) produce darker images and 0.0 leaves pixels unchanged. + Brightness = BRIGHTNESS, + /// Specify a fixed contrast parameter. + /// + /// Normal contrast is given by the value 1.0; larger values produce images + /// with more contrast. + Contrast = CONTRAST, + /// Report an estimate of the current illuminance level in lux. + /// + /// The Lux control can only be returned in metadata. + Lux = LUX, + /// Enable or disable the AWB. + /// + /// When AWB is enabled, the algorithm estimates the colour temperature of + /// the scene and computes colour gains and the colour correction matrix + /// automatically. The computed colour temperature, gains and correction + /// matrix are reported in metadata. The corresponding controls are ignored + /// if set in a request. + /// + /// When AWB is disabled, the colour temperature, gains and correction + /// matrix are not updated automatically and can be set manually in + /// requests. + /// + /// \sa ColourCorrectionMatrix + /// \sa ColourGains + /// \sa ColourTemperature + AwbEnable = AWB_ENABLE, + /// Specify the range of illuminants to use for the AWB algorithm. + /// + /// The modes supported are platform specific, and not all modes may be + /// supported. + AwbMode = AWB_MODE, + /// Report the lock status of a running AWB algorithm. + /// + /// If the AWB algorithm is locked the value shall be set to true, if it's + /// converging it shall be set to false. If the AWB algorithm is not + /// running the control shall not be present in the metadata control list. + /// + /// \sa AwbEnable + AwbLocked = AWB_LOCKED, + /// Pair of gain values for the Red and Blue colour channels, in that + /// order. + /// + /// ColourGains can only be applied in a Request when the AWB is disabled. + /// If ColourGains is set in a request but ColourTemperature is not, the + /// implementation shall calculate and set the ColourTemperature based on + /// the ColourGains. + /// + /// \sa AwbEnable + /// \sa ColourTemperature + ColourGains = COLOUR_GAINS, + /// ColourTemperature of the frame, in kelvin. + /// + /// ColourTemperature can only be applied in a Request when the AWB is + /// disabled. + /// + /// If ColourTemperature is set in a request but ColourGains is not, the + /// implementation shall calculate and set the ColourGains based on the + /// given ColourTemperature. If ColourTemperature is set (either directly, + /// or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, + /// the ColourCorrectionMatrix is updated based on the ColourTemperature. + /// + /// The ColourTemperature used to process the frame is reported in metadata. + /// + /// \sa AwbEnable + /// \sa ColourCorrectionMatrix + /// \sa ColourGains + ColourTemperature = COLOUR_TEMPERATURE, + /// Specify a fixed saturation parameter. + /// + /// Normal saturation is given by the value 1.0; larger values produce more + /// saturated colours; 0.0 produces a greyscale image. + Saturation = SATURATION, + /// Reports the sensor black levels used for processing a frame. + /// + /// The values are in the order R, Gr, Gb, B. They are returned as numbers + /// out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The + /// SensorBlackLevels control can only be returned in metadata. + SensorBlackLevels = SENSOR_BLACK_LEVELS, + /// Intensity of the sharpening applied to the image. + /// + /// A value of 0.0 means no sharpening. The minimum value means + /// minimal sharpening, and shall be 0.0 unless the camera can't + /// disable sharpening completely. The default value shall give a + /// "reasonable" level of sharpening, suitable for most use cases. + /// The maximum value may apply extremely high levels of sharpening, + /// higher than anyone could reasonably want. Negative values are + /// not allowed. Note also that sharpening is not applied to raw + /// streams. + Sharpness = SHARPNESS, + /// Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + /// + /// A larger FocusFoM value indicates a more in-focus frame. This singular + /// value may be based on a combination of statistics gathered from + /// multiple focus regions within an image. The number of focus regions and + /// method of combination is platform dependent. In this respect, it is not + /// necessarily aimed at providing a way to implement a focus algorithm by + /// the application, rather an indication of how in-focus a frame is. + FocusFoM = FOCUS_FO_M, + /// The 3x3 matrix that converts camera RGB to sRGB within the imaging + /// pipeline. + /// + /// This should describe the matrix that is used after pixels have been + /// white-balanced, but before any gamma transformation. The 3x3 matrix is + /// stored in conventional reading order in an array of 9 floating point + /// values. + /// + /// ColourCorrectionMatrix can only be applied in a Request when the AWB is + /// disabled. + /// + /// \sa AwbEnable + /// \sa ColourTemperature + ColourCorrectionMatrix = COLOUR_CORRECTION_MATRIX, + /// Sets the image portion that will be scaled to form the whole of + /// the final output image. + /// + /// The (x,y) location of this rectangle is relative to the + /// PixelArrayActiveAreas that is being used. The units remain native + /// sensor pixels, even if the sensor is being used in a binning or + /// skipping mode. + /// + /// This control is only present when the pipeline supports scaling. Its + /// maximum valid value is given by the properties::ScalerCropMaximum + /// property, and the two can be used to implement digital zoom. + ScalerCrop = SCALER_CROP, + /// Digital gain value applied during the processing steps applied + /// to the image as captured from the sensor. + /// + /// The global digital gain factor is applied to all the colour channels + /// of the RAW image. Different pipeline models are free to + /// specify how the global gain factor applies to each separate + /// channel. + /// + /// If an imaging pipeline applies digital gain in distinct + /// processing steps, this value indicates their total sum. + /// Pipelines are free to decide how to adjust each processing + /// step to respect the received gain factor and shall report + /// their total value in the request metadata. + DigitalGain = DIGITAL_GAIN, + /// The instantaneous frame duration from start of frame exposure to start + /// of next exposure, expressed in microseconds. + /// + /// This control is meant to be returned in metadata. + FrameDuration = FRAME_DURATION, + /// The minimum and maximum (in that order) frame duration, expressed in + /// microseconds. + /// + /// When provided by applications, the control specifies the sensor frame + /// duration interval the pipeline has to use. This limits the largest + /// exposure time the sensor can use. For example, if a maximum frame + /// duration of 33ms is requested (corresponding to 30 frames per second), + /// the sensor will not be able to raise the exposure time above 33ms. + /// A fixed frame duration is achieved by setting the minimum and maximum + /// values to be the same. Setting both values to 0 reverts to using the + /// camera defaults. + /// + /// The maximum frame duration provides the absolute limit to the exposure + /// time computed by the AE algorithm and it overrides any exposure mode + /// setting specified with controls::AeExposureMode. Similarly, when a + /// manual exposure time is set through controls::ExposureTime, it also + /// gets clipped to the limits set by this control. When reported in + /// metadata, the control expresses the minimum and maximum frame durations + /// used after being clipped to the sensor provided frame duration limits. + /// + /// \sa AeExposureMode + /// \sa ExposureTime + /// + /// \todo Define how to calculate the capture frame rate by + /// defining controls to report additional delays introduced by + /// the capture pipeline or post-processing stages (ie JPEG + /// conversion, frame scaling). + /// + /// \todo Provide an explicit definition of default control values, for + /// this and all other controls. + FrameDurationLimits = FRAME_DURATION_LIMITS, + /// Temperature measure from the camera sensor in Celsius. + /// + /// This value is typically obtained by a thermal sensor present on-die or + /// in the camera module. The range of reported temperatures is device + /// dependent. + /// + /// The SensorTemperature control will only be returned in metadata if a + /// thermal sensor is present. + SensorTemperature = SENSOR_TEMPERATURE, + /// The time when the first row of the image sensor active array is exposed. + /// + /// The timestamp, expressed in nanoseconds, represents a monotonically + /// increasing counter since the system boot time, as defined by the + /// Linux-specific CLOCK_BOOTTIME clock id. + /// + /// The SensorTimestamp control can only be returned in metadata. + /// + /// \todo Define how the sensor timestamp has to be used in the reprocessing + /// use case. + SensorTimestamp = SENSOR_TIMESTAMP, + /// The mode of the AF (autofocus) algorithm. + /// + /// An implementation may choose not to implement all the modes. + AfMode = AF_MODE, + /// The range of focus distances that is scanned. + /// + /// An implementation may choose not to implement all the options here. + AfRange = AF_RANGE, + /// Determine whether the AF is to move the lens as quickly as possible or + /// more steadily. + /// + /// For example, during video recording it may be desirable not to move the + /// lens too abruptly, but when in a preview mode (waiting for a still + /// capture) it may be helpful to move the lens as quickly as is reasonably + /// possible. + AfSpeed = AF_SPEED, + /// The parts of the image used by the AF algorithm to measure focus. + AfMetering = AF_METERING, + /// The focus windows used by the AF algorithm when AfMetering is set to + /// AfMeteringWindows. + /// + /// The units used are pixels within the rectangle returned by the + /// ScalerCropMaximum property. + /// + /// In order to be activated, a rectangle must be programmed with non-zero + /// width and height. Internally, these rectangles are intersected with the + /// ScalerCropMaximum rectangle. If the window becomes empty after this + /// operation, then the window is ignored. If all the windows end up being + /// ignored, then the behaviour is platform dependent. + /// + /// On platforms that support the ScalerCrop control (for implementing + /// digital zoom, for example), no automatic recalculation or adjustment of + /// AF windows is performed internally if the ScalerCrop is changed. If any + /// window lies outside the output image after the scaler crop has been + /// applied, it is up to the application to recalculate them. + /// + /// The details of how the windows are used are platform dependent. We note + /// that when there is more than one AF window, a typical implementation + /// might find the optimal focus position for each one and finally select + /// the window where the focal distance for the objects shown in that part + /// of the image are closest to the camera. + AfWindows = AF_WINDOWS, + /// Start an autofocus scan. + /// + /// This control starts an autofocus scan when AfMode is set to AfModeAuto, + /// and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It + /// can also be used to terminate a scan early. + AfTrigger = AF_TRIGGER, + /// Pause lens movements when in continuous autofocus mode. + /// + /// This control has no effect except when in continuous autofocus mode + /// (AfModeContinuous). It can be used to pause any lens movements while + /// (for example) images are captured. The algorithm remains inactive + /// until it is instructed to resume. + AfPause = AF_PAUSE, + /// Set and report the focus lens position. + /// + /// This control instructs the lens to move to a particular position and + /// also reports back the position of the lens for each frame. + /// + /// The LensPosition control is ignored unless the AfMode is set to + /// AfModeManual, though the value is reported back unconditionally in all + /// modes. + /// + /// This value, which is generally a non-integer, is the reciprocal of the + /// focal distance in metres, also known as dioptres. That is, to set a + /// focal distance D, the lens position LP is given by + /// + /// \f$LP = \frac{1\mathrm{m}}{D}\f$ + /// + /// For example: + /// + /// - 0 moves the lens to infinity. + /// - 0.5 moves the lens to focus on objects 2m away. + /// - 2 moves the lens to focus on objects 50cm away. + /// - And larger values will focus the lens closer. + /// + /// The default value of the control should indicate a good general + /// position for the lens, often corresponding to the hyperfocal distance + /// (the closest position for which objects at infinity are still + /// acceptably sharp). The minimum will often be zero (meaning infinity), + /// and the maximum value defines the closest focus position. + /// + /// \todo Define a property to report the Hyperfocal distance of calibrated + /// lenses. + LensPosition = LENS_POSITION, + /// The current state of the AF algorithm. + /// + /// This control reports the current state of the AF algorithm in + /// conjunction with the reported AfMode value and (in continuous AF mode) + /// the AfPauseState value. The possible state changes are described below, + /// though we note the following state transitions that occur when the + /// AfMode is changed. + /// + /// If the AfMode is set to AfModeManual, then the AfState will always + /// report AfStateIdle (even if the lens is subsequently moved). Changing + /// to the AfModeManual state does not initiate any lens movement. + /// + /// If the AfMode is set to AfModeAuto then the AfState will report + /// AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent + /// together then AfState will omit AfStateIdle and move straight to + /// AfStateScanning (and start a scan). + /// + /// If the AfMode is set to AfModeContinuous then the AfState will + /// initially report AfStateScanning. + AfState = AF_STATE, + /// Report whether the autofocus is currently running, paused or pausing. + /// + /// This control is only applicable in continuous (AfModeContinuous) mode, + /// and reports whether the algorithm is currently running, paused or + /// pausing (that is, will pause as soon as any in-progress scan + /// completes). + /// + /// Any change to AfMode will cause AfPauseStateRunning to be reported. + AfPauseState = AF_PAUSE_STATE, + /// Set the mode to be used for High Dynamic Range (HDR) imaging. + /// + /// HDR techniques typically include multiple exposure, image fusion and + /// tone mapping techniques to improve the dynamic range of the resulting + /// images. + /// + /// When using an HDR mode, images are captured with different sets of AGC + /// settings called HDR channels. Channels indicate in particular the type + /// of exposure (short, medium or long) used to capture the raw image, + /// before fusion. Each HDR image is tagged with the corresponding channel + /// using the HdrChannel control. + /// + /// \sa HdrChannel + HdrMode = HDR_MODE, + /// The HDR channel used to capture the frame. + /// + /// This value is reported back to the application so that it can discover + /// whether this capture corresponds to the short or long exposure image + /// (or any other image used by the HDR procedure). An application can + /// monitor the HDR channel to discover when the differently exposed images + /// have arrived. + /// + /// This metadata is only available when an HDR mode has been enabled. + /// + /// \sa HdrMode + HdrChannel = HDR_CHANNEL, + /// Specify a fixed gamma value. + /// + /// The default gamma value must be 2.2 which closely mimics sRGB gamma. + /// Note that this is camera gamma, so it is applied as 1.0/gamma. + Gamma = GAMMA, + /// Enable or disable the debug metadata. + DebugMetadataEnable = DEBUG_METADATA_ENABLE, + /// This timestamp corresponds to the same moment in time as the + /// SensorTimestamp, but is represented as a wall clock time as measured by + /// the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is + /// expressed in nanoseconds. + /// + /// Being a wall clock measurement, it can be used to synchronise timing + /// across different devices. + /// + /// \sa SensorTimestamp + /// + /// The FrameWallClock control can only be returned in metadata. + FrameWallClock = FRAME_WALL_CLOCK, + /// Set the WDR mode. + /// + /// The WDR mode is used to select the algorithm used for global tone + /// mapping. It will automatically reduce the exposure time of the sensor + /// so that there are only a small number of saturated pixels in the image. + /// The algorithm then compensates for the loss of brightness by applying a + /// global tone mapping curve to the image. + WdrMode = WDR_MODE, + /// Specify the strength of the wdr algorithm. The exact meaning of this + /// value is specific to the algorithm in use. Usually a value of 0 means no + /// global tone mapping is applied. A values of 1 is the default value and + /// the correct value for most scenes. A value above 1 increases the global + /// tone mapping effect and can lead to unrealistic image effects. + WdrStrength = WDR_STRENGTH, + /// Percentage of allowed (nearly) saturated pixels. The WDR algorithm + /// reduces the WdrExposureValue until the amount of pixels that are close + /// to saturation is lower than this value. + WdrMaxBrightPixels = WDR_MAX_BRIGHT_PIXELS, + /// Enable or disable lens dewarping. This control is only available if lens + /// dewarp parameters are configured in the tuning file. + LensDewarpEnable = LENS_DEWARP_ENABLE, + /// Control for AE metering trigger. Currently identical to + /// ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + /// + /// Whether the camera device will trigger a precapture metering sequence + /// when it processes this request. + #[cfg(feature = "vendor_draft")] + AePrecaptureTrigger = AE_PRECAPTURE_TRIGGER, + /// Control to select the noise reduction algorithm mode. Currently + /// identical to ANDROID_NOISE_REDUCTION_MODE. + /// + /// Mode of operation for the noise reduction algorithm. + #[cfg(feature = "vendor_draft")] + NoiseReductionMode = NOISE_REDUCTION_MODE, + /// Control to select the color correction aberration mode. Currently + /// identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + /// + /// Mode of operation for the chromatic aberration correction algorithm. + #[cfg(feature = "vendor_draft")] + ColorCorrectionAberrationMode = COLOR_CORRECTION_ABERRATION_MODE, + /// Control to report the current AWB algorithm state. Currently identical + /// to ANDROID_CONTROL_AWB_STATE. + /// + /// Current state of the AWB algorithm. + #[cfg(feature = "vendor_draft")] + AwbState = AWB_STATE, + /// Control to report the time between the start of exposure of the first + /// row and the start of exposure of the last row. Currently identical to + /// ANDROID_SENSOR_ROLLING_SHUTTER_SKEW + #[cfg(feature = "vendor_draft")] + SensorRollingShutterSkew = SENSOR_ROLLING_SHUTTER_SKEW, + /// Control to report if the lens shading map is available. Currently + /// identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. + #[cfg(feature = "vendor_draft")] + LensShadingMapMode = LENS_SHADING_MAP_MODE, + /// Specifies the number of pipeline stages the frame went through from when + /// it was exposed to when the final completed result was available to the + /// framework. Always less than or equal to PipelineMaxDepth. Currently + /// identical to ANDROID_REQUEST_PIPELINE_DEPTH. + /// + /// The typical value for this control is 3 as a frame is first exposed, + /// captured and then processed in a single pass through the ISP. Any + /// additional processing step performed after the ISP pass (in example face + /// detection, additional format conversions etc) count as an additional + /// pipeline stage. + #[cfg(feature = "vendor_draft")] + PipelineDepth = PIPELINE_DEPTH, + /// The maximum number of frames that can occur after a request (different + /// than the previous) has been submitted, and before the result's state + /// becomes synchronized. A value of -1 indicates unknown latency, and 0 + /// indicates per-frame control. Currently identical to + /// ANDROID_SYNC_MAX_LATENCY. + #[cfg(feature = "vendor_draft")] + MaxLatency = MAX_LATENCY, + /// Control to select the test pattern mode. Currently identical to + /// ANDROID_SENSOR_TEST_PATTERN_MODE. + #[cfg(feature = "vendor_draft")] + TestPatternMode = TEST_PATTERN_MODE, + /// Control to select the face detection mode used by the pipeline. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + /// + /// \sa FaceDetectFaceRectangles + /// \sa FaceDetectFaceScores + /// \sa FaceDetectFaceLandmarks + /// \sa FaceDetectFaceIds + #[cfg(feature = "vendor_draft")] + FaceDetectMode = FACE_DETECT_MODE, + /// Boundary rectangles of the detected faces. The number of values is + /// the number of detected faces. + /// + /// The FaceDetectFaceRectangles control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceRectangles = FACE_DETECT_FACE_RECTANGLES, + /// Confidence score of each of the detected faces. The range of score is + /// [0, 100]. The number of values should be the number of faces reported + /// in FaceDetectFaceRectangles. + /// + /// The FaceDetectFaceScores control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_SCORES. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceScores = FACE_DETECT_FACE_SCORES, + /// Array of human face landmark coordinates in format [..., left_eye_i, + /// right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The + /// number of values should be 3 * the number of faces reported in + /// FaceDetectFaceRectangles. + /// + /// The FaceDetectFaceLandmarks control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceLandmarks = FACE_DETECT_FACE_LANDMARKS, + /// Each detected face is given a unique ID that is valid for as long as the + /// face is visible to the camera device. A face that leaves the field of + /// view and later returns may be assigned a new ID. The number of values + /// should be the number of faces reported in FaceDetectFaceRectangles. + /// + /// The FaceDetectFaceIds control can only be returned in metadata. + /// + /// Currently identical to ANDROID_STATISTICS_FACE_IDS. + #[cfg(feature = "vendor_draft")] + FaceDetectFaceIds = FACE_DETECT_FACE_IDS, + /// Toggles the Raspberry Pi IPA to output the hardware generated statistics. + /// + /// When this control is set to true, the IPA outputs a binary dump of the + /// hardware generated statistics through the Request metadata in the + /// Bcm2835StatsOutput control. + /// + /// \sa Bcm2835StatsOutput + #[cfg(feature = "vendor_rpi")] + StatsOutputEnable = STATS_OUTPUT_ENABLE, + /// Span of the BCM2835 ISP generated statistics for the current frame. + /// + /// This is sent in the Request metadata if the StatsOutputEnable is set to + /// true. The statistics struct definition can be found in + /// include/linux/bcm2835-isp.h. + /// + /// \sa StatsOutputEnable + #[cfg(feature = "vendor_rpi")] + Bcm2835StatsOutput = BCM2835_STATS_OUTPUT, + /// An array of rectangles, where each singular value has identical + /// functionality to the ScalerCrop control. This control allows the + /// Raspberry Pi pipeline handler to control individual scaler crops per + /// output stream. + /// + /// The order of rectangles passed into the control must match the order of + /// streams configured by the application. The pipeline handler will only + /// configure crop retangles up-to the number of output streams configured. + /// All subsequent rectangles passed into this control are ignored by the + /// pipeline handler. + /// + /// If both rpi::ScalerCrops and ScalerCrop controls are present in a + /// ControlList, the latter is discarded, and crops are obtained from this + /// control. + /// + /// Note that using different crop rectangles for each output stream with + /// this control is only applicable on the Pi5/PiSP platform. This control + /// should also be considered temporary/draft and will be replaced with + /// official libcamera API support for per-stream controls in the future. + /// + /// \sa ScalerCrop + #[cfg(feature = "vendor_rpi")] + ScalerCrops = SCALER_CROPS, + /// Span of the PiSP Frontend ISP generated statistics for the current + /// frame. This is sent in the Request metadata if the StatsOutputEnable is + /// set to true. The statistics struct definition can be found in + /// https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + /// + /// \sa StatsOutputEnable + #[cfg(feature = "vendor_rpi")] + PispStatsOutput = PISP_STATS_OUTPUT, + /// Enable or disable camera synchronisation ("sync") mode. + /// + /// When sync mode is enabled, a camera will synchronise frames temporally + /// with other cameras, either attached to the same device or a different + /// one. There should be one "server" device, which broadcasts timing + /// information to one or more "clients". Communication is one-way, from + /// server to clients only, and it is only clients that adjust their frame + /// timings to match the server. + /// + /// Sync mode requires all cameras to be running at (as far as possible) the + /// same fixed framerate. Clients may continue to make adjustments to keep + /// their cameras synchronised with the server for the duration of the + /// session, though any updates after the initial ones should remain small. + /// + /// \sa SyncReady + /// \sa SyncTimer + /// \sa SyncFrames + #[cfg(feature = "vendor_rpi")] + SyncMode = SYNC_MODE, + /// When using the camera synchronisation algorithm, the server broadcasts + /// timing information to the clients. This also includes the time (some + /// number of frames in the future, called the "ready time") at which the + /// server will signal its controlling application, using this control, to + /// start using the image frames. + /// + /// The client receives the "ready time" from the server, and will signal + /// its application to start using the frames at this same moment. + /// + /// While this control value is false, applications (on both client and + /// server) should continue to wait, and not use the frames. + /// + /// Once this value becomes true, it means that this is the first frame + /// where the server and its clients have agreed that they will both be + /// synchronised and that applications should begin consuming frames. + /// Thereafter, this control will continue to signal the value true for + /// the rest of the session. + /// + /// \sa SyncMode + /// \sa SyncTimer + /// \sa SyncFrames + #[cfg(feature = "vendor_rpi")] + SyncReady = SYNC_READY, + /// This reports the amount of time, in microseconds, until the "ready + /// time", at which the server and client will signal their controlling + /// applications that the frames are now synchronised and should be + /// used. The value may be refined slightly over time, becoming more precise + /// as the "ready time" approaches. + /// + /// Servers always report this value, whereas clients will omit this control + /// until they have received a message from the server that enables them to + /// calculate it. + /// + /// Normally the value will start positive (the "ready time" is in the + /// future), and decrease towards zero, before becoming negative (the "ready + /// time" has elapsed). So there should be just one frame where the timer + /// value is, or is very close to, zero - the one for which the SyncReady + /// control becomes true. At this moment, the value indicates how closely + /// synchronised the client believes it is with the server. + /// + /// But note that if frames are being dropped, then the "near zero" valued + /// frame, or indeed any other, could be skipped. In these cases the timer + /// value allows an application to deduce that this has happened. + /// + /// \sa SyncMode + /// \sa SyncReady + /// \sa SyncFrames + #[cfg(feature = "vendor_rpi")] + SyncTimer = SYNC_TIMER, + /// The number of frames the server should wait, after enabling + /// SyncModeServer, before signalling (via the SyncReady control) that + /// frames should be used. This therefore determines the "ready time" for + /// all synchronised cameras. + /// + /// This control value should be set only for the device that is to act as + /// the server, before or at the same moment at which SyncModeServer is + /// enabled. + /// + /// \sa SyncMode + /// \sa SyncReady + /// \sa SyncTimer + #[cfg(feature = "vendor_rpi")] + SyncFrames = SYNC_FRAMES, +} +impl ControlId { + pub fn id(&self) -> u32 { + u32::from(*self) + } + pub fn description(&self) -> &'static str { + match self { + ControlId::AeEnable => { + "Enable or disable the AEGC algorithm. When this control is set to true, +both ExposureTimeMode and AnalogueGainMode are set to auto, and if this +control is set to false then both are set to manual. + +If ExposureTimeMode or AnalogueGainMode are also set in the same +request as AeEnable, then the modes supplied by ExposureTimeMode or +AnalogueGainMode will take precedence. + +\\sa ExposureTimeMode AnalogueGainMode +" + } + ControlId::AeState => { + "Report the AEGC algorithm state. + +The AEGC algorithm computes the exposure time and the analogue gain +to be applied to the image sensor. + +The AEGC algorithm behaviour is controlled by the ExposureTimeMode and +AnalogueGainMode controls, which allow applications to decide how +the exposure time and gain are computed, in Auto or Manual mode, +independently from one another. + +The AeState control reports the AEGC algorithm state through a single +value and describes it as a single computation block which computes +both the exposure time and the analogue gain values. + +When both the exposure time and analogue gain values are configured to +be in Manual mode, the AEGC algorithm is quiescent and does not actively +compute any value and the AeState control will report AeStateIdle. + +When at least the exposure time or analogue gain are configured to be +computed by the AEGC algorithm, the AeState control will report if the +algorithm has converged to stable values for all of the controls set +to be computed in Auto mode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::AeMeteringMode => { + "Specify a metering mode for the AE algorithm to use. + +The metering modes determine which parts of the image are used to +determine the scene brightness. Metering modes may be platform specific +and not all metering modes may be supported. +" + } + ControlId::AeConstraintMode => { + "Specify a constraint mode for the AE algorithm to use. + +The constraint modes determine how the measured scene brightness is +adjusted to reach the desired target exposure. Constraint modes may be +platform specific, and not all constraint modes may be supported. +" + } + ControlId::AeExposureMode => { + "Specify an exposure mode for the AE algorithm to use. + +The exposure modes specify how the desired total exposure is divided +between the exposure time and the sensor's analogue gain. They are +platform specific, and not all exposure modes may be supported. + +When one of AnalogueGainMode or ExposureTimeMode is set to Manual, +the fixed values will override any choices made by AeExposureMode. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureValue => { + "Specify an Exposure Value (EV) parameter. + +The EV parameter will only be applied if the AE algorithm is currently +enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode +are in Auto mode. + +By convention EV adjusts the exposure as log2. For example +EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment +of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. + +\\sa AnalogueGainMode +\\sa ExposureTimeMode +" + } + ControlId::ExposureTime => { + "Exposure time for the frame applied in the sensor device. + +This value is specified in microseconds. + +This control will only take effect if ExposureTimeMode is Manual. If +this control is set when ExposureTimeMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what exposure time +was used for the current frame, regardless of ExposureTimeMode. +ExposureTimeMode will indicate the source of the exposure time value, +whether it came from the AE algorithm or not. + +\\sa AnalogueGain +\\sa ExposureTimeMode +" + } + ControlId::ExposureTimeMode => { + "Controls the source of the exposure time that is applied to the image +sensor. + +When set to Auto, the AE algorithm computes the exposure time and +configures the image sensor accordingly. When set to Manual, the value +of the ExposureTime control is used. + +When transitioning from Auto to Manual mode and no ExposureTime control +is provided by the application, the last value computed by the AE +algorithm when the mode was Auto will be used. If the ExposureTimeMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If ExposureTimeModeManual is supported, the ExposureTime control must +also be supported. + +Cameras that support manual control of the sensor shall support manual +mode for both ExposureTimeMode and AnalogueGainMode, and shall expose +the ExposureTime and AnalogueGain controls. If the camera also has an +AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall +support both manual and auto mode. If auto mode is available, it shall +be the default mode. These rules do not apply to black box cameras +such as UVC cameras, where the available gain and exposure modes are +completely dependent on what the device exposes. + +\\par Flickerless exposure mode transitions + +Applications that wish to transition from ExposureTimeModeAuto to direct +control of the exposure time without causing extra flicker can do so by +selecting an ExposureTime value as close as possible to the last value +computed by the auto exposure algorithm in order to avoid any visible +flickering. + +To select the correct value to use as ExposureTime value, applications +should accommodate the natural delay in applying controls caused by the +capture pipeline frame depth. + +When switching to manual exposure mode, applications should not +immediately specify an ExposureTime value in the same request where +ExposureTimeMode is set to Manual. They should instead wait for the +first Request where ExposureTimeMode is reported as +ExposureTimeModeManual in the Request metadata, and use the reported +ExposureTime to populate the control value in the next Request to be +queued to the Camera. + +The implementation of the auto-exposure algorithm should equally try to +minimize flickering and when transitioning from manual exposure mode to +auto exposure use the last value provided by the application as starting +point. + +1. Start with ExposureTimeMode set to Auto + +2. Set ExposureTimeMode to Manual + +3. Wait for the first completed request that has ExposureTimeMode +set to Manual + +4. Copy the value reported in ExposureTime into a new request, and +submit it + +5. Proceed to run manual exposure time as desired + +\\sa ExposureTime +" + } + ControlId::AnalogueGain => { + "Analogue gain value applied in the sensor device. + +The value of the control specifies the gain multiplier applied to all +colour channels. This value cannot be lower than 1.0. + +This control will only take effect if AnalogueGainMode is Manual. If +this control is set when AnalogueGainMode is Auto, the value will be +ignored and will not be retained. + +When reported in metadata, this control indicates what analogue gain +was used for the current request, regardless of AnalogueGainMode. +AnalogueGainMode will indicate the source of the analogue gain value, +whether it came from the AEGC algorithm or not. + +\\sa ExposureTime +\\sa AnalogueGainMode +" + } + ControlId::AnalogueGainMode => { + "Controls the source of the analogue gain that is applied to the image +sensor. + +When set to Auto, the AEGC algorithm computes the analogue gain and +configures the image sensor accordingly. When set to Manual, the value +of the AnalogueGain control is used. + +When transitioning from Auto to Manual mode and no AnalogueGain control +is provided by the application, the last value computed by the AEGC +algorithm when the mode was Auto will be used. If the AnalogueGainMode +was never set to Auto (either because the camera started in Manual mode, +or Auto is not supported by the camera), the camera should use a +best-effort default value. + +If AnalogueGainModeManual is supported, the AnalogueGain control must +also be supported. + +For cameras where we have control over the ISP, both ExposureTimeMode +and AnalogueGainMode are expected to support manual mode, and both +controls (as well as ExposureTimeMode and AnalogueGain) are expected to +be present. If the camera also has an AEGC implementation, both +ExposureTimeMode and AnalogueGainMode shall support both manual and +auto mode. If auto mode is available, it shall be the default mode. +These rules do not apply to black box cameras such as UVC cameras, +where the available gain and exposure modes are completely dependent on +what the hardware exposes. + +The same procedure described for performing flickerless transitions in +the ExposureTimeMode control documentation can be applied to analogue +gain. + +\\sa ExposureTimeMode +\\sa AnalogueGain +" + } + ControlId::AeFlickerMode => { + "Set the flicker avoidance mode for AGC/AEC. + +The flicker mode determines whether, and how, the AGC/AEC algorithm +attempts to hide flicker effects caused by the duty cycle of artificial +lighting. + +Although implementation dependent, many algorithms for \"flicker +avoidance\" work by restricting this exposure time to integer multiples +of the cycle period, wherever possible. + +Implementations may not support all of the flicker modes listed below. + +By default the system will start in FlickerAuto mode if this is +supported, otherwise the flicker mode will be set to FlickerOff. +" + } + ControlId::AeFlickerPeriod => { + "Manual flicker period in microseconds. + +This value sets the current flicker period to avoid. It is used when +AeFlickerMode is set to FlickerManual. + +To cancel 50Hz mains flicker, this should be set to 10000 (corresponding +to 100Hz), or 8333 (120Hz) for 60Hz mains. + +Setting the mode to FlickerManual when no AeFlickerPeriod has ever been +set means that no flicker cancellation occurs (until the value of this +control is updated). + +Switching to modes other than FlickerManual has no effect on the +value of the AeFlickerPeriod control. + +\\sa AeFlickerMode +" + } + ControlId::AeFlickerDetected => { + "Flicker period detected in microseconds. + +The value reported here indicates the currently detected flicker +period, or zero if no flicker at all is detected. + +When AeFlickerMode is set to FlickerAuto, there may be a period during +which the value reported here remains zero. Once a non-zero value is +reported, then this is the flicker period that has been detected and is +now being cancelled. + +In the case of 50Hz mains flicker, the value would be 10000 +(corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. + +It is implementation dependent whether the system can continue to detect +flicker of different periods when another frequency is already being +cancelled. + +\\sa AeFlickerMode +" + } + ControlId::Brightness => { + "Specify a fixed brightness parameter. + +Positive values (up to 1.0) produce brighter images; negative values +(up to -1.0) produce darker images and 0.0 leaves pixels unchanged. +" + } + ControlId::Contrast => { + "Specify a fixed contrast parameter. + +Normal contrast is given by the value 1.0; larger values produce images +with more contrast. +" + } + ControlId::Lux => { + "Report an estimate of the current illuminance level in lux. + +The Lux control can only be returned in metadata. +" + } + ControlId::AwbEnable => { + "Enable or disable the AWB. + +When AWB is enabled, the algorithm estimates the colour temperature of +the scene and computes colour gains and the colour correction matrix +automatically. The computed colour temperature, gains and correction +matrix are reported in metadata. The corresponding controls are ignored +if set in a request. + +When AWB is disabled, the colour temperature, gains and correction +matrix are not updated automatically and can be set manually in +requests. + +\\sa ColourCorrectionMatrix +\\sa ColourGains +\\sa ColourTemperature +" + } + ControlId::AwbMode => { + "Specify the range of illuminants to use for the AWB algorithm. + +The modes supported are platform specific, and not all modes may be +supported. +" + } + ControlId::AwbLocked => { + "Report the lock status of a running AWB algorithm. + +If the AWB algorithm is locked the value shall be set to true, if it's +converging it shall be set to false. If the AWB algorithm is not +running the control shall not be present in the metadata control list. + +\\sa AwbEnable +" + } + ControlId::ColourGains => { + "Pair of gain values for the Red and Blue colour channels, in that +order. + +ColourGains can only be applied in a Request when the AWB is disabled. +If ColourGains is set in a request but ColourTemperature is not, the +implementation shall calculate and set the ColourTemperature based on +the ColourGains. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ColourTemperature => { + "ColourTemperature of the frame, in kelvin. + +ColourTemperature can only be applied in a Request when the AWB is +disabled. + +If ColourTemperature is set in a request but ColourGains is not, the +implementation shall calculate and set the ColourGains based on the +given ColourTemperature. If ColourTemperature is set (either directly, +or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, +the ColourCorrectionMatrix is updated based on the ColourTemperature. + +The ColourTemperature used to process the frame is reported in metadata. + +\\sa AwbEnable +\\sa ColourCorrectionMatrix +\\sa ColourGains +" + } + ControlId::Saturation => { + "Specify a fixed saturation parameter. + +Normal saturation is given by the value 1.0; larger values produce more +saturated colours; 0.0 produces a greyscale image. +" + } + ControlId::SensorBlackLevels => { + "Reports the sensor black levels used for processing a frame. + +The values are in the order R, Gr, Gb, B. They are returned as numbers +out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The +SensorBlackLevels control can only be returned in metadata. +" + } + ControlId::Sharpness => { + "Intensity of the sharpening applied to the image. + +A value of 0.0 means no sharpening. The minimum value means +minimal sharpening, and shall be 0.0 unless the camera can't +disable sharpening completely. The default value shall give a +\"reasonable\" level of sharpening, suitable for most use cases. +The maximum value may apply extremely high levels of sharpening, +higher than anyone could reasonably want. Negative values are +not allowed. Note also that sharpening is not applied to raw +streams. +" + } + ControlId::FocusFoM => { + "Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. + +A larger FocusFoM value indicates a more in-focus frame. This singular +value may be based on a combination of statistics gathered from +multiple focus regions within an image. The number of focus regions and +method of combination is platform dependent. In this respect, it is not +necessarily aimed at providing a way to implement a focus algorithm by +the application, rather an indication of how in-focus a frame is. +" + } + ControlId::ColourCorrectionMatrix => { + "The 3x3 matrix that converts camera RGB to sRGB within the imaging +pipeline. + +This should describe the matrix that is used after pixels have been +white-balanced, but before any gamma transformation. The 3x3 matrix is +stored in conventional reading order in an array of 9 floating point +values. + +ColourCorrectionMatrix can only be applied in a Request when the AWB is +disabled. + +\\sa AwbEnable +\\sa ColourTemperature +" + } + ControlId::ScalerCrop => { + "Sets the image portion that will be scaled to form the whole of +the final output image. + +The (x,y) location of this rectangle is relative to the +PixelArrayActiveAreas that is being used. The units remain native +sensor pixels, even if the sensor is being used in a binning or +skipping mode. + +This control is only present when the pipeline supports scaling. Its +maximum valid value is given by the properties::ScalerCropMaximum +property, and the two can be used to implement digital zoom. +" + } + ControlId::DigitalGain => { + "Digital gain value applied during the processing steps applied +to the image as captured from the sensor. + +The global digital gain factor is applied to all the colour channels +of the RAW image. Different pipeline models are free to +specify how the global gain factor applies to each separate +channel. + +If an imaging pipeline applies digital gain in distinct +processing steps, this value indicates their total sum. +Pipelines are free to decide how to adjust each processing +step to respect the received gain factor and shall report +their total value in the request metadata. +" + } + ControlId::FrameDuration => { + "The instantaneous frame duration from start of frame exposure to start +of next exposure, expressed in microseconds. + +This control is meant to be returned in metadata. +" + } + ControlId::FrameDurationLimits => { + "The minimum and maximum (in that order) frame duration, expressed in +microseconds. + +When provided by applications, the control specifies the sensor frame +duration interval the pipeline has to use. This limits the largest +exposure time the sensor can use. For example, if a maximum frame +duration of 33ms is requested (corresponding to 30 frames per second), +the sensor will not be able to raise the exposure time above 33ms. +A fixed frame duration is achieved by setting the minimum and maximum +values to be the same. Setting both values to 0 reverts to using the +camera defaults. + +The maximum frame duration provides the absolute limit to the exposure +time computed by the AE algorithm and it overrides any exposure mode +setting specified with controls::AeExposureMode. Similarly, when a +manual exposure time is set through controls::ExposureTime, it also +gets clipped to the limits set by this control. When reported in +metadata, the control expresses the minimum and maximum frame durations +used after being clipped to the sensor provided frame duration limits. + +\\sa AeExposureMode +\\sa ExposureTime + +\\todo Define how to calculate the capture frame rate by +defining controls to report additional delays introduced by +the capture pipeline or post-processing stages (ie JPEG +conversion, frame scaling). + +\\todo Provide an explicit definition of default control values, for +this and all other controls. +" + } + ControlId::SensorTemperature => { + "Temperature measure from the camera sensor in Celsius. + +This value is typically obtained by a thermal sensor present on-die or +in the camera module. The range of reported temperatures is device +dependent. + +The SensorTemperature control will only be returned in metadata if a +thermal sensor is present. +" + } + ControlId::SensorTimestamp => { + "The time when the first row of the image sensor active array is exposed. + +The timestamp, expressed in nanoseconds, represents a monotonically +increasing counter since the system boot time, as defined by the +Linux-specific CLOCK_BOOTTIME clock id. + +The SensorTimestamp control can only be returned in metadata. + +\\todo Define how the sensor timestamp has to be used in the reprocessing +use case. +" + } + ControlId::AfMode => { + "The mode of the AF (autofocus) algorithm. + +An implementation may choose not to implement all the modes. +" + } + ControlId::AfRange => { + "The range of focus distances that is scanned. + +An implementation may choose not to implement all the options here. +" + } + ControlId::AfSpeed => { + "Determine whether the AF is to move the lens as quickly as possible or +more steadily. + +For example, during video recording it may be desirable not to move the +lens too abruptly, but when in a preview mode (waiting for a still +capture) it may be helpful to move the lens as quickly as is reasonably +possible. +" + } + ControlId::AfMetering => { + "The parts of the image used by the AF algorithm to measure focus. +" + } + ControlId::AfWindows => { + "The focus windows used by the AF algorithm when AfMetering is set to +AfMeteringWindows. + +The units used are pixels within the rectangle returned by the +ScalerCropMaximum property. + +In order to be activated, a rectangle must be programmed with non-zero +width and height. Internally, these rectangles are intersected with the +ScalerCropMaximum rectangle. If the window becomes empty after this +operation, then the window is ignored. If all the windows end up being +ignored, then the behaviour is platform dependent. + +On platforms that support the ScalerCrop control (for implementing +digital zoom, for example), no automatic recalculation or adjustment of +AF windows is performed internally if the ScalerCrop is changed. If any +window lies outside the output image after the scaler crop has been +applied, it is up to the application to recalculate them. + +The details of how the windows are used are platform dependent. We note +that when there is more than one AF window, a typical implementation +might find the optimal focus position for each one and finally select +the window where the focal distance for the objects shown in that part +of the image are closest to the camera. +" + } + ControlId::AfTrigger => { + "Start an autofocus scan. + +This control starts an autofocus scan when AfMode is set to AfModeAuto, +and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It +can also be used to terminate a scan early. +" + } + ControlId::AfPause => { + "Pause lens movements when in continuous autofocus mode. + +This control has no effect except when in continuous autofocus mode +(AfModeContinuous). It can be used to pause any lens movements while +(for example) images are captured. The algorithm remains inactive +until it is instructed to resume. +" + } + ControlId::LensPosition => { + "Set and report the focus lens position. + +This control instructs the lens to move to a particular position and +also reports back the position of the lens for each frame. + +The LensPosition control is ignored unless the AfMode is set to +AfModeManual, though the value is reported back unconditionally in all +modes. + +This value, which is generally a non-integer, is the reciprocal of the +focal distance in metres, also known as dioptres. That is, to set a +focal distance D, the lens position LP is given by + +\\f$LP = \\frac{1\\mathrm{m}}{D}\\f$ + +For example: + +- 0 moves the lens to infinity. +- 0.5 moves the lens to focus on objects 2m away. +- 2 moves the lens to focus on objects 50cm away. +- And larger values will focus the lens closer. + +The default value of the control should indicate a good general +position for the lens, often corresponding to the hyperfocal distance +(the closest position for which objects at infinity are still +acceptably sharp). The minimum will often be zero (meaning infinity), +and the maximum value defines the closest focus position. + +\\todo Define a property to report the Hyperfocal distance of calibrated +lenses. +" + } + ControlId::AfState => { + "The current state of the AF algorithm. + +This control reports the current state of the AF algorithm in +conjunction with the reported AfMode value and (in continuous AF mode) +the AfPauseState value. The possible state changes are described below, +though we note the following state transitions that occur when the +AfMode is changed. + +If the AfMode is set to AfModeManual, then the AfState will always +report AfStateIdle (even if the lens is subsequently moved). Changing +to the AfModeManual state does not initiate any lens movement. + +If the AfMode is set to AfModeAuto then the AfState will report +AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent +together then AfState will omit AfStateIdle and move straight to +AfStateScanning (and start a scan). + +If the AfMode is set to AfModeContinuous then the AfState will +initially report AfStateScanning. +" + } + ControlId::AfPauseState => { + "Report whether the autofocus is currently running, paused or pausing. + +This control is only applicable in continuous (AfModeContinuous) mode, +and reports whether the algorithm is currently running, paused or +pausing (that is, will pause as soon as any in-progress scan +completes). + +Any change to AfMode will cause AfPauseStateRunning to be reported. +" + } + ControlId::HdrMode => { + "Set the mode to be used for High Dynamic Range (HDR) imaging. + +HDR techniques typically include multiple exposure, image fusion and +tone mapping techniques to improve the dynamic range of the resulting +images. + +When using an HDR mode, images are captured with different sets of AGC +settings called HDR channels. Channels indicate in particular the type +of exposure (short, medium or long) used to capture the raw image, +before fusion. Each HDR image is tagged with the corresponding channel +using the HdrChannel control. + +\\sa HdrChannel +" + } + ControlId::HdrChannel => { + "The HDR channel used to capture the frame. + +This value is reported back to the application so that it can discover +whether this capture corresponds to the short or long exposure image +(or any other image used by the HDR procedure). An application can +monitor the HDR channel to discover when the differently exposed images +have arrived. + +This metadata is only available when an HDR mode has been enabled. + +\\sa HdrMode +" + } + ControlId::Gamma => { + "Specify a fixed gamma value. + +The default gamma value must be 2.2 which closely mimics sRGB gamma. +Note that this is camera gamma, so it is applied as 1.0/gamma. +" + } + ControlId::DebugMetadataEnable => "Enable or disable the debug metadata. +", + ControlId::FrameWallClock => { + "This timestamp corresponds to the same moment in time as the +SensorTimestamp, but is represented as a wall clock time as measured by +the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is +expressed in nanoseconds. + +Being a wall clock measurement, it can be used to synchronise timing +across different devices. + +\\sa SensorTimestamp + +The FrameWallClock control can only be returned in metadata. +" + } + ControlId::WdrMode => { + "Set the WDR mode. + +The WDR mode is used to select the algorithm used for global tone +mapping. It will automatically reduce the exposure time of the sensor +so that there are only a small number of saturated pixels in the image. +The algorithm then compensates for the loss of brightness by applying a +global tone mapping curve to the image. +" + } + ControlId::WdrStrength => { + "Specify the strength of the wdr algorithm. The exact meaning of this +value is specific to the algorithm in use. Usually a value of 0 means no +global tone mapping is applied. A values of 1 is the default value and +the correct value for most scenes. A value above 1 increases the global +tone mapping effect and can lead to unrealistic image effects. +" + } + ControlId::WdrMaxBrightPixels => { + "Percentage of allowed (nearly) saturated pixels. The WDR algorithm +reduces the WdrExposureValue until the amount of pixels that are close +to saturation is lower than this value. +" + } + ControlId::LensDewarpEnable => { + "Enable or disable lens dewarping. This control is only available if lens +dewarp parameters are configured in the tuning file. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AePrecaptureTrigger => { + "Control for AE metering trigger. Currently identical to +ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. + +Whether the camera device will trigger a precapture metering sequence +when it processes this request. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::NoiseReductionMode => { + "Control to select the noise reduction algorithm mode. Currently +identical to ANDROID_NOISE_REDUCTION_MODE. + + Mode of operation for the noise reduction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::ColorCorrectionAberrationMode => { + "Control to select the color correction aberration mode. Currently +identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. + + Mode of operation for the chromatic aberration correction algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::AwbState => { + "Control to report the current AWB algorithm state. Currently identical +to ANDROID_CONTROL_AWB_STATE. + + Current state of the AWB algorithm. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::SensorRollingShutterSkew => { + "Control to report the time between the start of exposure of the first +row and the start of exposure of the last row. Currently identical to +ANDROID_SENSOR_ROLLING_SHUTTER_SKEW +" + } + #[cfg(feature = "vendor_draft")] + ControlId::LensShadingMapMode => { + "Control to report if the lens shading map is available. Currently +identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::PipelineDepth => { + "Specifies the number of pipeline stages the frame went through from when +it was exposed to when the final completed result was available to the +framework. Always less than or equal to PipelineMaxDepth. Currently +identical to ANDROID_REQUEST_PIPELINE_DEPTH. + +The typical value for this control is 3 as a frame is first exposed, +captured and then processed in a single pass through the ISP. Any +additional processing step performed after the ISP pass (in example face +detection, additional format conversions etc) count as an additional +pipeline stage. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::MaxLatency => { + "The maximum number of frames that can occur after a request (different +than the previous) has been submitted, and before the result's state +becomes synchronized. A value of -1 indicates unknown latency, and 0 +indicates per-frame control. Currently identical to +ANDROID_SYNC_MAX_LATENCY. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::TestPatternMode => { + "Control to select the test pattern mode. Currently identical to +ANDROID_SENSOR_TEST_PATTERN_MODE. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectMode => { + "Control to select the face detection mode used by the pipeline. + +Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. + +\\sa FaceDetectFaceRectangles +\\sa FaceDetectFaceScores +\\sa FaceDetectFaceLandmarks +\\sa FaceDetectFaceIds +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceRectangles => { + "Boundary rectangles of the detected faces. The number of values is +the number of detected faces. + +The FaceDetectFaceRectangles control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceScores => { + "Confidence score of each of the detected faces. The range of score is +[0, 100]. The number of values should be the number of faces reported +in FaceDetectFaceRectangles. + +The FaceDetectFaceScores control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_SCORES. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceLandmarks => { + "Array of human face landmark coordinates in format [..., left_eye_i, +right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The +number of values should be 3 * the number of faces reported in +FaceDetectFaceRectangles. + +The FaceDetectFaceLandmarks control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. +" + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceIds => { + "Each detected face is given a unique ID that is valid for as long as the +face is visible to the camera device. A face that leaves the field of +view and later returns may be assigned a new ID. The number of values +should be the number of faces reported in FaceDetectFaceRectangles. + +The FaceDetectFaceIds control can only be returned in metadata. + +Currently identical to ANDROID_STATISTICS_FACE_IDS. +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::StatsOutputEnable => { + "Toggles the Raspberry Pi IPA to output the hardware generated statistics. + +When this control is set to true, the IPA outputs a binary dump of the +hardware generated statistics through the Request metadata in the +Bcm2835StatsOutput control. + +\\sa Bcm2835StatsOutput +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::Bcm2835StatsOutput => { + "Span of the BCM2835 ISP generated statistics for the current frame. + +This is sent in the Request metadata if the StatsOutputEnable is set to +true. The statistics struct definition can be found in +include/linux/bcm2835-isp.h. + +\\sa StatsOutputEnable +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::ScalerCrops => { + "An array of rectangles, where each singular value has identical +functionality to the ScalerCrop control. This control allows the +Raspberry Pi pipeline handler to control individual scaler crops per +output stream. + +The order of rectangles passed into the control must match the order of +streams configured by the application. The pipeline handler will only +configure crop retangles up-to the number of output streams configured. +All subsequent rectangles passed into this control are ignored by the +pipeline handler. + +If both rpi::ScalerCrops and ScalerCrop controls are present in a +ControlList, the latter is discarded, and crops are obtained from this +control. + +Note that using different crop rectangles for each output stream with +this control is only applicable on the Pi5/PiSP platform. This control +should also be considered temporary/draft and will be replaced with +official libcamera API support for per-stream controls in the future. + +\\sa ScalerCrop +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::PispStatsOutput => { + "Span of the PiSP Frontend ISP generated statistics for the current +frame. This is sent in the Request metadata if the StatsOutputEnable is +set to true. The statistics struct definition can be found in +https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h + +\\sa StatsOutputEnable +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncMode => { + "Enable or disable camera synchronisation (\"sync\") mode. + +When sync mode is enabled, a camera will synchronise frames temporally +with other cameras, either attached to the same device or a different +one. There should be one \"server\" device, which broadcasts timing +information to one or more \"clients\". Communication is one-way, from +server to clients only, and it is only clients that adjust their frame +timings to match the server. + +Sync mode requires all cameras to be running at (as far as possible) the +same fixed framerate. Clients may continue to make adjustments to keep +their cameras synchronised with the server for the duration of the +session, though any updates after the initial ones should remain small. + +\\sa SyncReady +\\sa SyncTimer +\\sa SyncFrames +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncReady => { + "When using the camera synchronisation algorithm, the server broadcasts +timing information to the clients. This also includes the time (some +number of frames in the future, called the \"ready time\") at which the +server will signal its controlling application, using this control, to +start using the image frames. + +The client receives the \"ready time\" from the server, and will signal +its application to start using the frames at this same moment. + +While this control value is false, applications (on both client and +server) should continue to wait, and not use the frames. + +Once this value becomes true, it means that this is the first frame +where the server and its clients have agreed that they will both be +synchronised and that applications should begin consuming frames. +Thereafter, this control will continue to signal the value true for +the rest of the session. + +\\sa SyncMode +\\sa SyncTimer +\\sa SyncFrames +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncTimer => { + "This reports the amount of time, in microseconds, until the \"ready +time\", at which the server and client will signal their controlling +applications that the frames are now synchronised and should be +used. The value may be refined slightly over time, becoming more precise +as the \"ready time\" approaches. + +Servers always report this value, whereas clients will omit this control +until they have received a message from the server that enables them to +calculate it. + +Normally the value will start positive (the \"ready time\" is in the +future), and decrease towards zero, before becoming negative (the \"ready +time\" has elapsed). So there should be just one frame where the timer +value is, or is very close to, zero - the one for which the SyncReady +control becomes true. At this moment, the value indicates how closely +synchronised the client believes it is with the server. + +But note that if frames are being dropped, then the \"near zero\" valued +frame, or indeed any other, could be skipped. In these cases the timer +value allows an application to deduce that this has happened. + +\\sa SyncMode +\\sa SyncReady +\\sa SyncFrames +" + } + #[cfg(feature = "vendor_rpi")] + ControlId::SyncFrames => { + "The number of frames the server should wait, after enabling +SyncModeServer, before signalling (via the SyncReady control) that +frames should be used. This therefore determines the \"ready time\" for +all synchronised cameras. + +This control value should be set only for the device that is to act as +the server, before or at the same moment at which SyncModeServer is +enabled. + +\\sa SyncMode +\\sa SyncReady +\\sa SyncTimer +" + } + } + } +} +/// Enable or disable the AEGC algorithm. When this control is set to true, +/// both ExposureTimeMode and AnalogueGainMode are set to auto, and if this +/// control is set to false then both are set to manual. +/// +/// If ExposureTimeMode or AnalogueGainMode are also set in the same +/// request as AeEnable, then the modes supplied by ExposureTimeMode or +/// AnalogueGainMode will take precedence. +/// +/// \sa ExposureTimeMode AnalogueGainMode +#[derive(Debug, Clone)] +pub struct AeEnable(pub bool); +impl Deref for AeEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AeEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AeEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AeEnable) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AeEnable { + const ID: u32 = ControlId::AeEnable as _; +} +impl Control for AeEnable {} +/// Report the AEGC algorithm state. +/// +/// The AEGC algorithm computes the exposure time and the analogue gain +/// to be applied to the image sensor. +/// +/// The AEGC algorithm behaviour is controlled by the ExposureTimeMode and +/// AnalogueGainMode controls, which allow applications to decide how +/// the exposure time and gain are computed, in Auto or Manual mode, +/// independently from one another. +/// +/// The AeState control reports the AEGC algorithm state through a single +/// value and describes it as a single computation block which computes +/// both the exposure time and the analogue gain values. +/// +/// When both the exposure time and analogue gain values are configured to +/// be in Manual mode, the AEGC algorithm is quiescent and does not actively +/// compute any value and the AeState control will report AeStateIdle. +/// +/// When at least the exposure time or analogue gain are configured to be +/// computed by the AEGC algorithm, the AeState control will report if the +/// algorithm has converged to stable values for all of the controls set +/// to be computed in Auto mode. +/// +/// \sa AnalogueGainMode +/// \sa ExposureTimeMode +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeState { + /// The AEGC algorithm is inactive. + /// + /// This state is returned when both AnalogueGainMode and + /// ExposureTimeMode are set to Manual and the algorithm is not + /// actively computing any value. + Idle = 0, + /// The AEGC algorithm is actively computing new values, for either the + /// exposure time or the analogue gain, but has not converged to a + /// stable result yet. + /// + /// This state is returned if at least one of AnalogueGainMode or + /// ExposureTimeMode is auto and the algorithm hasn't converged yet. + /// + /// The AEGC algorithm converges once stable values are computed for + /// all of the controls set to be computed in Auto mode. Once the + /// algorithm converges the state is moved to AeStateConverged. + Searching = 1, + /// The AEGC algorithm has converged. + /// + /// This state is returned if at least one of AnalogueGainMode or + /// ExposureTimeMode is Auto, and the AEGC algorithm has converged to a + /// stable value. + /// + /// If the measurements move too far away from the convergence point + /// then the AEGC algorithm might start adjusting again, in which case + /// the state is moved to AeStateSearching. + Converged = 2, +} +impl TryFrom for AeState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeState) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeState { + const ID: u32 = ControlId::AeState as _; +} +impl Control for AeState {} +/// Specify a metering mode for the AE algorithm to use. +/// +/// The metering modes determine which parts of the image are used to +/// determine the scene brightness. Metering modes may be platform specific +/// and not all metering modes may be supported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeMeteringMode { + /// Centre-weighted metering mode. + MeteringCentreWeighted = 0, + /// Spot metering mode. + MeteringSpot = 1, + /// Matrix metering mode. + MeteringMatrix = 2, + /// Custom metering mode. + MeteringCustom = 3, +} +impl TryFrom for AeMeteringMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeMeteringMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeMeteringMode { + const ID: u32 = ControlId::AeMeteringMode as _; +} +impl Control for AeMeteringMode {} +/// Specify a constraint mode for the AE algorithm to use. +/// +/// The constraint modes determine how the measured scene brightness is +/// adjusted to reach the desired target exposure. Constraint modes may be +/// platform specific, and not all constraint modes may be supported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeConstraintMode { + /// Default constraint mode. + /// + /// This mode aims to balance the exposure of different parts of the + /// image so as to reach a reasonable average level. However, highlights + /// in the image may appear over-exposed and lowlights may appear + /// under-exposed. + ConstraintNormal = 0, + /// Highlight constraint mode. + /// + /// This mode adjusts the exposure levels in order to try and avoid + /// over-exposing the brightest parts (highlights) of an image. + /// Other non-highlight parts of the image may appear under-exposed. + ConstraintHighlight = 1, + /// Shadows constraint mode. + /// + /// This mode adjusts the exposure levels in order to try and avoid + /// under-exposing the dark parts (shadows) of an image. Other normally + /// exposed parts of the image may appear over-exposed. + ConstraintShadows = 2, + /// Custom constraint mode. + ConstraintCustom = 3, +} +impl TryFrom for AeConstraintMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeConstraintMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeConstraintMode { + const ID: u32 = ControlId::AeConstraintMode as _; +} +impl Control for AeConstraintMode {} +/// Specify an exposure mode for the AE algorithm to use. +/// +/// The exposure modes specify how the desired total exposure is divided +/// between the exposure time and the sensor's analogue gain. They are +/// platform specific, and not all exposure modes may be supported. +/// +/// When one of AnalogueGainMode or ExposureTimeMode is set to Manual, +/// the fixed values will override any choices made by AeExposureMode. +/// +/// \sa AnalogueGainMode +/// \sa ExposureTimeMode +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeExposureMode { + /// Default exposure mode. + ExposureNormal = 0, + /// Exposure mode allowing only short exposure times. + ExposureShort = 1, + /// Exposure mode allowing long exposure times. + ExposureLong = 2, + /// Custom exposure mode. + ExposureCustom = 3, +} +impl TryFrom for AeExposureMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeExposureMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeExposureMode { + const ID: u32 = ControlId::AeExposureMode as _; +} +impl Control for AeExposureMode {} +/// Specify an Exposure Value (EV) parameter. +/// +/// The EV parameter will only be applied if the AE algorithm is currently +/// enabled, that is, at least one of AnalogueGainMode and ExposureTimeMode +/// are in Auto mode. +/// +/// By convention EV adjusts the exposure as log2. For example +/// EV = [-2, -1, -0.5, 0, 0.5, 1, 2] results in an exposure adjustment +/// of [1/4x, 1/2x, 1/sqrt(2)x, 1x, sqrt(2)x, 2x, 4x]. +/// +/// \sa AnalogueGainMode +/// \sa ExposureTimeMode +#[derive(Debug, Clone)] +pub struct ExposureValue(pub f32); +impl Deref for ExposureValue { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ExposureValue { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ExposureValue { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ExposureValue) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ExposureValue { + const ID: u32 = ControlId::ExposureValue as _; +} +impl Control for ExposureValue {} +/// Exposure time for the frame applied in the sensor device. +/// +/// This value is specified in microseconds. +/// +/// This control will only take effect if ExposureTimeMode is Manual. If +/// this control is set when ExposureTimeMode is Auto, the value will be +/// ignored and will not be retained. +/// +/// When reported in metadata, this control indicates what exposure time +/// was used for the current frame, regardless of ExposureTimeMode. +/// ExposureTimeMode will indicate the source of the exposure time value, +/// whether it came from the AE algorithm or not. +/// +/// \sa AnalogueGain +/// \sa ExposureTimeMode +#[derive(Debug, Clone)] +pub struct ExposureTime(pub i32); +impl Deref for ExposureTime { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ExposureTime { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ExposureTime { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ExposureTime) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ExposureTime { + const ID: u32 = ControlId::ExposureTime as _; +} +impl Control for ExposureTime {} +/// Controls the source of the exposure time that is applied to the image +/// sensor. +/// +/// When set to Auto, the AE algorithm computes the exposure time and +/// configures the image sensor accordingly. When set to Manual, the value +/// of the ExposureTime control is used. +/// +/// When transitioning from Auto to Manual mode and no ExposureTime control +/// is provided by the application, the last value computed by the AE +/// algorithm when the mode was Auto will be used. If the ExposureTimeMode +/// was never set to Auto (either because the camera started in Manual mode, +/// or Auto is not supported by the camera), the camera should use a +/// best-effort default value. +/// +/// If ExposureTimeModeManual is supported, the ExposureTime control must +/// also be supported. +/// +/// Cameras that support manual control of the sensor shall support manual +/// mode for both ExposureTimeMode and AnalogueGainMode, and shall expose +/// the ExposureTime and AnalogueGain controls. If the camera also has an +/// AEGC implementation, both ExposureTimeMode and AnalogueGainMode shall +/// support both manual and auto mode. If auto mode is available, it shall +/// be the default mode. These rules do not apply to black box cameras +/// such as UVC cameras, where the available gain and exposure modes are +/// completely dependent on what the device exposes. +/// +/// \par Flickerless exposure mode transitions +/// +/// Applications that wish to transition from ExposureTimeModeAuto to direct +/// control of the exposure time without causing extra flicker can do so by +/// selecting an ExposureTime value as close as possible to the last value +/// computed by the auto exposure algorithm in order to avoid any visible +/// flickering. +/// +/// To select the correct value to use as ExposureTime value, applications +/// should accommodate the natural delay in applying controls caused by the +/// capture pipeline frame depth. +/// +/// When switching to manual exposure mode, applications should not +/// immediately specify an ExposureTime value in the same request where +/// ExposureTimeMode is set to Manual. They should instead wait for the +/// first Request where ExposureTimeMode is reported as +/// ExposureTimeModeManual in the Request metadata, and use the reported +/// ExposureTime to populate the control value in the next Request to be +/// queued to the Camera. +/// +/// The implementation of the auto-exposure algorithm should equally try to +/// minimize flickering and when transitioning from manual exposure mode to +/// auto exposure use the last value provided by the application as starting +/// point. +/// +/// 1. Start with ExposureTimeMode set to Auto +/// +/// 2. Set ExposureTimeMode to Manual +/// +/// 3. Wait for the first completed request that has ExposureTimeMode +/// set to Manual +/// +/// 4. Copy the value reported in ExposureTime into a new request, and +/// submit it +/// +/// 5. Proceed to run manual exposure time as desired +/// +/// \sa ExposureTime +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum ExposureTimeMode { + /// The exposure time will be calculated automatically and set by the + /// AE algorithm. + /// + /// If ExposureTime is set while this mode is active, it will be + /// ignored, and its value will not be retained. + /// + /// When transitioning from Manual to Auto mode, the AEGC should start + /// its adjustments based on the last set manual ExposureTime value. + Auto = 0, + /// The exposure time will not be updated by the AE algorithm. + /// + /// When transitioning from Auto to Manual mode, the last computed + /// exposure value is used until a new value is specified through the + /// ExposureTime control. If an ExposureTime value is specified in the + /// same request where the ExposureTimeMode is changed from Auto to + /// Manual, the provided ExposureTime is applied immediately. + Manual = 1, +} +impl TryFrom for ExposureTimeMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: ExposureTimeMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for ExposureTimeMode { + const ID: u32 = ControlId::ExposureTimeMode as _; +} +impl Control for ExposureTimeMode {} +/// Analogue gain value applied in the sensor device. +/// +/// The value of the control specifies the gain multiplier applied to all +/// colour channels. This value cannot be lower than 1.0. +/// +/// This control will only take effect if AnalogueGainMode is Manual. If +/// this control is set when AnalogueGainMode is Auto, the value will be +/// ignored and will not be retained. +/// +/// When reported in metadata, this control indicates what analogue gain +/// was used for the current request, regardless of AnalogueGainMode. +/// AnalogueGainMode will indicate the source of the analogue gain value, +/// whether it came from the AEGC algorithm or not. +/// +/// \sa ExposureTime +/// \sa AnalogueGainMode +#[derive(Debug, Clone)] +pub struct AnalogueGain(pub f32); +impl Deref for AnalogueGain { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AnalogueGain { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AnalogueGain { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AnalogueGain) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AnalogueGain { + const ID: u32 = ControlId::AnalogueGain as _; +} +impl Control for AnalogueGain {} +/// Controls the source of the analogue gain that is applied to the image +/// sensor. +/// +/// When set to Auto, the AEGC algorithm computes the analogue gain and +/// configures the image sensor accordingly. When set to Manual, the value +/// of the AnalogueGain control is used. +/// +/// When transitioning from Auto to Manual mode and no AnalogueGain control +/// is provided by the application, the last value computed by the AEGC +/// algorithm when the mode was Auto will be used. If the AnalogueGainMode +/// was never set to Auto (either because the camera started in Manual mode, +/// or Auto is not supported by the camera), the camera should use a +/// best-effort default value. +/// +/// If AnalogueGainModeManual is supported, the AnalogueGain control must +/// also be supported. +/// +/// For cameras where we have control over the ISP, both ExposureTimeMode +/// and AnalogueGainMode are expected to support manual mode, and both +/// controls (as well as ExposureTimeMode and AnalogueGain) are expected to +/// be present. If the camera also has an AEGC implementation, both +/// ExposureTimeMode and AnalogueGainMode shall support both manual and +/// auto mode. If auto mode is available, it shall be the default mode. +/// These rules do not apply to black box cameras such as UVC cameras, +/// where the available gain and exposure modes are completely dependent on +/// what the hardware exposes. +/// +/// The same procedure described for performing flickerless transitions in +/// the ExposureTimeMode control documentation can be applied to analogue +/// gain. +/// +/// \sa ExposureTimeMode +/// \sa AnalogueGain +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AnalogueGainMode { + /// The analogue gain will be calculated automatically and set by the + /// AEGC algorithm. + /// + /// If AnalogueGain is set while this mode is active, it will be + /// ignored, and it will also not be retained. + /// + /// When transitioning from Manual to Auto mode, the AEGC should start + /// its adjustments based on the last set manual AnalogueGain value. + Auto = 0, + /// The analogue gain will not be updated by the AEGC algorithm. + /// + /// When transitioning from Auto to Manual mode, the last computed + /// gain value is used until a new value is specified through the + /// AnalogueGain control. If an AnalogueGain value is specified in the + /// same request where the AnalogueGainMode is changed from Auto to + /// Manual, the provided AnalogueGain is applied immediately. + Manual = 1, +} +impl TryFrom for AnalogueGainMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AnalogueGainMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AnalogueGainMode { + const ID: u32 = ControlId::AnalogueGainMode as _; +} +impl Control for AnalogueGainMode {} +/// Set the flicker avoidance mode for AGC/AEC. +/// +/// The flicker mode determines whether, and how, the AGC/AEC algorithm +/// attempts to hide flicker effects caused by the duty cycle of artificial +/// lighting. +/// +/// Although implementation dependent, many algorithms for "flicker +/// avoidance" work by restricting this exposure time to integer multiples +/// of the cycle period, wherever possible. +/// +/// Implementations may not support all of the flicker modes listed below. +/// +/// By default the system will start in FlickerAuto mode if this is +/// supported, otherwise the flicker mode will be set to FlickerOff. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AeFlickerMode { + /// No flicker avoidance is performed. + FlickerOff = 0, + /// Manual flicker avoidance. + /// + /// Suppress flicker effects caused by lighting running with a period + /// specified by the AeFlickerPeriod control. + /// \sa AeFlickerPeriod + FlickerManual = 1, + /// Automatic flicker period detection and avoidance. + /// + /// The system will automatically determine the most likely value of + /// flicker period, and avoid flicker of this frequency. Once flicker + /// is being corrected, it is implementation dependent whether the + /// system is still able to detect a change in the flicker period. + /// \sa AeFlickerDetected + FlickerAuto = 2, +} +impl TryFrom for AeFlickerMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AeFlickerMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AeFlickerMode { + const ID: u32 = ControlId::AeFlickerMode as _; +} +impl Control for AeFlickerMode {} +/// Manual flicker period in microseconds. +/// +/// This value sets the current flicker period to avoid. It is used when +/// AeFlickerMode is set to FlickerManual. +/// +/// To cancel 50Hz mains flicker, this should be set to 10000 (corresponding +/// to 100Hz), or 8333 (120Hz) for 60Hz mains. +/// +/// Setting the mode to FlickerManual when no AeFlickerPeriod has ever been +/// set means that no flicker cancellation occurs (until the value of this +/// control is updated). +/// +/// Switching to modes other than FlickerManual has no effect on the +/// value of the AeFlickerPeriod control. +/// +/// \sa AeFlickerMode +#[derive(Debug, Clone)] +pub struct AeFlickerPeriod(pub i32); +impl Deref for AeFlickerPeriod { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AeFlickerPeriod { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AeFlickerPeriod { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AeFlickerPeriod) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AeFlickerPeriod { + const ID: u32 = ControlId::AeFlickerPeriod as _; +} +impl Control for AeFlickerPeriod {} +/// Flicker period detected in microseconds. +/// +/// The value reported here indicates the currently detected flicker +/// period, or zero if no flicker at all is detected. +/// +/// When AeFlickerMode is set to FlickerAuto, there may be a period during +/// which the value reported here remains zero. Once a non-zero value is +/// reported, then this is the flicker period that has been detected and is +/// now being cancelled. +/// +/// In the case of 50Hz mains flicker, the value would be 10000 +/// (corresponding to 100Hz), or 8333 (120Hz) for 60Hz mains flicker. +/// +/// It is implementation dependent whether the system can continue to detect +/// flicker of different periods when another frequency is already being +/// cancelled. +/// +/// \sa AeFlickerMode +#[derive(Debug, Clone)] +pub struct AeFlickerDetected(pub i32); +impl Deref for AeFlickerDetected { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AeFlickerDetected { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AeFlickerDetected { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AeFlickerDetected) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AeFlickerDetected { + const ID: u32 = ControlId::AeFlickerDetected as _; +} +impl Control for AeFlickerDetected {} +/// Specify a fixed brightness parameter. +/// +/// Positive values (up to 1.0) produce brighter images; negative values +/// (up to -1.0) produce darker images and 0.0 leaves pixels unchanged. +#[derive(Debug, Clone)] +pub struct Brightness(pub f32); +impl Deref for Brightness { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Brightness { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Brightness { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Brightness) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Brightness { + const ID: u32 = ControlId::Brightness as _; +} +impl Control for Brightness {} +/// Specify a fixed contrast parameter. +/// +/// Normal contrast is given by the value 1.0; larger values produce images +/// with more contrast. +#[derive(Debug, Clone)] +pub struct Contrast(pub f32); +impl Deref for Contrast { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Contrast { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Contrast { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Contrast) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Contrast { + const ID: u32 = ControlId::Contrast as _; +} +impl Control for Contrast {} +/// Report an estimate of the current illuminance level in lux. +/// +/// The Lux control can only be returned in metadata. +#[derive(Debug, Clone)] +pub struct Lux(pub f32); +impl Deref for Lux { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Lux { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Lux { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Lux) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Lux { + const ID: u32 = ControlId::Lux as _; +} +impl Control for Lux {} +/// Enable or disable the AWB. +/// +/// When AWB is enabled, the algorithm estimates the colour temperature of +/// the scene and computes colour gains and the colour correction matrix +/// automatically. The computed colour temperature, gains and correction +/// matrix are reported in metadata. The corresponding controls are ignored +/// if set in a request. +/// +/// When AWB is disabled, the colour temperature, gains and correction +/// matrix are not updated automatically and can be set manually in +/// requests. +/// +/// \sa ColourCorrectionMatrix +/// \sa ColourGains +/// \sa ColourTemperature +#[derive(Debug, Clone)] +pub struct AwbEnable(pub bool); +impl Deref for AwbEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AwbEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AwbEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AwbEnable) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AwbEnable { + const ID: u32 = ControlId::AwbEnable as _; +} +impl Control for AwbEnable {} +/// Specify the range of illuminants to use for the AWB algorithm. +/// +/// The modes supported are platform specific, and not all modes may be +/// supported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AwbMode { + /// Search over the whole colour temperature range. + AwbAuto = 0, + /// Incandescent AWB lamp mode. + AwbIncandescent = 1, + /// Tungsten AWB lamp mode. + AwbTungsten = 2, + /// Fluorescent AWB lamp mode. + AwbFluorescent = 3, + /// Indoor AWB lighting mode. + AwbIndoor = 4, + /// Daylight AWB lighting mode. + AwbDaylight = 5, + /// Cloudy AWB lighting mode. + AwbCloudy = 6, + /// Custom AWB mode. + AwbCustom = 7, +} +impl TryFrom for AwbMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AwbMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AwbMode { + const ID: u32 = ControlId::AwbMode as _; +} +impl Control for AwbMode {} +/// Report the lock status of a running AWB algorithm. +/// +/// If the AWB algorithm is locked the value shall be set to true, if it's +/// converging it shall be set to false. If the AWB algorithm is not +/// running the control shall not be present in the metadata control list. +/// +/// \sa AwbEnable +#[derive(Debug, Clone)] +pub struct AwbLocked(pub bool); +impl Deref for AwbLocked { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AwbLocked { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AwbLocked { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AwbLocked) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AwbLocked { + const ID: u32 = ControlId::AwbLocked as _; +} +impl Control for AwbLocked {} +/// Pair of gain values for the Red and Blue colour channels, in that +/// order. +/// +/// ColourGains can only be applied in a Request when the AWB is disabled. +/// If ColourGains is set in a request but ColourTemperature is not, the +/// implementation shall calculate and set the ColourTemperature based on +/// the ColourGains. +/// +/// \sa AwbEnable +/// \sa ColourTemperature +#[derive(Debug, Clone)] +pub struct ColourGains(pub [f32; 2]); +impl Deref for ColourGains { + type Target = [f32; 2]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ColourGains { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ColourGains { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[f32; 2]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ColourGains) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ColourGains { + const ID: u32 = ControlId::ColourGains as _; +} +impl Control for ColourGains {} +/// ColourTemperature of the frame, in kelvin. +/// +/// ColourTemperature can only be applied in a Request when the AWB is +/// disabled. +/// +/// If ColourTemperature is set in a request but ColourGains is not, the +/// implementation shall calculate and set the ColourGains based on the +/// given ColourTemperature. If ColourTemperature is set (either directly, +/// or indirectly by setting ColourGains) but ColourCorrectionMatrix is not, +/// the ColourCorrectionMatrix is updated based on the ColourTemperature. +/// +/// The ColourTemperature used to process the frame is reported in metadata. +/// +/// \sa AwbEnable +/// \sa ColourCorrectionMatrix +/// \sa ColourGains +#[derive(Debug, Clone)] +pub struct ColourTemperature(pub i32); +impl Deref for ColourTemperature { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ColourTemperature { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ColourTemperature { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ColourTemperature) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ColourTemperature { + const ID: u32 = ControlId::ColourTemperature as _; +} +impl Control for ColourTemperature {} +/// Specify a fixed saturation parameter. +/// +/// Normal saturation is given by the value 1.0; larger values produce more +/// saturated colours; 0.0 produces a greyscale image. +#[derive(Debug, Clone)] +pub struct Saturation(pub f32); +impl Deref for Saturation { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Saturation { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Saturation { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Saturation) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Saturation { + const ID: u32 = ControlId::Saturation as _; +} +impl Control for Saturation {} +/// Reports the sensor black levels used for processing a frame. +/// +/// The values are in the order R, Gr, Gb, B. They are returned as numbers +/// out of a 16-bit pixel range (as if pixels ranged from 0 to 65535). The +/// SensorBlackLevels control can only be returned in metadata. +#[derive(Debug, Clone)] +pub struct SensorBlackLevels(pub [i32; 4]); +impl Deref for SensorBlackLevels { + type Target = [i32; 4]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorBlackLevels { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorBlackLevels { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[i32; 4]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorBlackLevels) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorBlackLevels { + const ID: u32 = ControlId::SensorBlackLevels as _; +} +impl Control for SensorBlackLevels {} +/// Intensity of the sharpening applied to the image. +/// +/// A value of 0.0 means no sharpening. The minimum value means +/// minimal sharpening, and shall be 0.0 unless the camera can't +/// disable sharpening completely. The default value shall give a +/// "reasonable" level of sharpening, suitable for most use cases. +/// The maximum value may apply extremely high levels of sharpening, +/// higher than anyone could reasonably want. Negative values are +/// not allowed. Note also that sharpening is not applied to raw +/// streams. +#[derive(Debug, Clone)] +pub struct Sharpness(pub f32); +impl Deref for Sharpness { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Sharpness { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Sharpness { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Sharpness) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Sharpness { + const ID: u32 = ControlId::Sharpness as _; +} +impl Control for Sharpness {} +/// Reports a Figure of Merit (FoM) to indicate how in-focus the frame is. +/// +/// A larger FocusFoM value indicates a more in-focus frame. This singular +/// value may be based on a combination of statistics gathered from +/// multiple focus regions within an image. The number of focus regions and +/// method of combination is platform dependent. In this respect, it is not +/// necessarily aimed at providing a way to implement a focus algorithm by +/// the application, rather an indication of how in-focus a frame is. +#[derive(Debug, Clone)] +pub struct FocusFoM(pub i32); +impl Deref for FocusFoM { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FocusFoM { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FocusFoM { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FocusFoM) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FocusFoM { + const ID: u32 = ControlId::FocusFoM as _; +} +impl Control for FocusFoM {} +/// The 3x3 matrix that converts camera RGB to sRGB within the imaging +/// pipeline. +/// +/// This should describe the matrix that is used after pixels have been +/// white-balanced, but before any gamma transformation. The 3x3 matrix is +/// stored in conventional reading order in an array of 9 floating point +/// values. +/// +/// ColourCorrectionMatrix can only be applied in a Request when the AWB is +/// disabled. +/// +/// \sa AwbEnable +/// \sa ColourTemperature +#[derive(Debug, Clone)] +pub struct ColourCorrectionMatrix(pub [[f32; 3]; 3]); +impl Deref for ColourCorrectionMatrix { + type Target = [[f32; 3]; 3]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ColourCorrectionMatrix { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ColourCorrectionMatrix { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[[f32; 3]; 3]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ColourCorrectionMatrix) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ColourCorrectionMatrix { + const ID: u32 = ControlId::ColourCorrectionMatrix as _; +} +impl Control for ColourCorrectionMatrix {} +/// Sets the image portion that will be scaled to form the whole of +/// the final output image. +/// +/// The (x,y) location of this rectangle is relative to the +/// PixelArrayActiveAreas that is being used. The units remain native +/// sensor pixels, even if the sensor is being used in a binning or +/// skipping mode. +/// +/// This control is only present when the pipeline supports scaling. Its +/// maximum valid value is given by the properties::ScalerCropMaximum +/// property, and the two can be used to implement digital zoom. +#[derive(Debug, Clone)] +pub struct ScalerCrop(pub Rectangle); +impl Deref for ScalerCrop { + type Target = Rectangle; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ScalerCrop { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ScalerCrop { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ScalerCrop) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ScalerCrop { + const ID: u32 = ControlId::ScalerCrop as _; +} +impl Control for ScalerCrop {} +/// Digital gain value applied during the processing steps applied +/// to the image as captured from the sensor. +/// +/// The global digital gain factor is applied to all the colour channels +/// of the RAW image. Different pipeline models are free to +/// specify how the global gain factor applies to each separate +/// channel. +/// +/// If an imaging pipeline applies digital gain in distinct +/// processing steps, this value indicates their total sum. +/// Pipelines are free to decide how to adjust each processing +/// step to respect the received gain factor and shall report +/// their total value in the request metadata. +#[derive(Debug, Clone)] +pub struct DigitalGain(pub f32); +impl Deref for DigitalGain { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for DigitalGain { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for DigitalGain { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: DigitalGain) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for DigitalGain { + const ID: u32 = ControlId::DigitalGain as _; +} +impl Control for DigitalGain {} +/// The instantaneous frame duration from start of frame exposure to start +/// of next exposure, expressed in microseconds. +/// +/// This control is meant to be returned in metadata. +#[derive(Debug, Clone)] +pub struct FrameDuration(pub i64); +impl Deref for FrameDuration { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FrameDuration { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FrameDuration { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FrameDuration) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FrameDuration { + const ID: u32 = ControlId::FrameDuration as _; +} +impl Control for FrameDuration {} +/// The minimum and maximum (in that order) frame duration, expressed in +/// microseconds. +/// +/// When provided by applications, the control specifies the sensor frame +/// duration interval the pipeline has to use. This limits the largest +/// exposure time the sensor can use. For example, if a maximum frame +/// duration of 33ms is requested (corresponding to 30 frames per second), +/// the sensor will not be able to raise the exposure time above 33ms. +/// A fixed frame duration is achieved by setting the minimum and maximum +/// values to be the same. Setting both values to 0 reverts to using the +/// camera defaults. +/// +/// The maximum frame duration provides the absolute limit to the exposure +/// time computed by the AE algorithm and it overrides any exposure mode +/// setting specified with controls::AeExposureMode. Similarly, when a +/// manual exposure time is set through controls::ExposureTime, it also +/// gets clipped to the limits set by this control. When reported in +/// metadata, the control expresses the minimum and maximum frame durations +/// used after being clipped to the sensor provided frame duration limits. +/// +/// \sa AeExposureMode +/// \sa ExposureTime +/// +/// \todo Define how to calculate the capture frame rate by +/// defining controls to report additional delays introduced by +/// the capture pipeline or post-processing stages (ie JPEG +/// conversion, frame scaling). +/// +/// \todo Provide an explicit definition of default control values, for +/// this and all other controls. +#[derive(Debug, Clone)] +pub struct FrameDurationLimits(pub [i64; 2]); +impl Deref for FrameDurationLimits { + type Target = [i64; 2]; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FrameDurationLimits { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FrameDurationLimits { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(<[i64; 2]>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FrameDurationLimits) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FrameDurationLimits { + const ID: u32 = ControlId::FrameDurationLimits as _; +} +impl Control for FrameDurationLimits {} +/// Temperature measure from the camera sensor in Celsius. +/// +/// This value is typically obtained by a thermal sensor present on-die or +/// in the camera module. The range of reported temperatures is device +/// dependent. +/// +/// The SensorTemperature control will only be returned in metadata if a +/// thermal sensor is present. +#[derive(Debug, Clone)] +pub struct SensorTemperature(pub f32); +impl Deref for SensorTemperature { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorTemperature { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorTemperature { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorTemperature) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorTemperature { + const ID: u32 = ControlId::SensorTemperature as _; +} +impl Control for SensorTemperature {} +/// The time when the first row of the image sensor active array is exposed. +/// +/// The timestamp, expressed in nanoseconds, represents a monotonically +/// increasing counter since the system boot time, as defined by the +/// Linux-specific CLOCK_BOOTTIME clock id. +/// +/// The SensorTimestamp control can only be returned in metadata. +/// +/// \todo Define how the sensor timestamp has to be used in the reprocessing +/// use case. +#[derive(Debug, Clone)] +pub struct SensorTimestamp(pub i64); +impl Deref for SensorTimestamp { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorTimestamp { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorTimestamp { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorTimestamp) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorTimestamp { + const ID: u32 = ControlId::SensorTimestamp as _; +} +impl Control for SensorTimestamp {} +/// The mode of the AF (autofocus) algorithm. +/// +/// An implementation may choose not to implement all the modes. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfMode { + /// The AF algorithm is in manual mode. + /// + /// In this mode it will never perform any action nor move the lens of + /// its own accord, but an application can specify the desired lens + /// position using the LensPosition control. The AfState will always + /// report AfStateIdle. + /// + /// If the camera is started in AfModeManual, it will move the focus + /// lens to the position specified by the LensPosition control. + /// + /// This mode is the recommended default value for the AfMode control. + /// External cameras (as reported by the Location property set to + /// CameraLocationExternal) may use a different default value. + Manual = 0, + /// The AF algorithm is in auto mode. + /// + /// In this mode the algorithm will never move the lens or change state + /// unless the AfTrigger control is used. The AfTrigger control can be + /// used to initiate a focus scan, the results of which will be + /// reported by AfState. + /// + /// If the autofocus algorithm is moved from AfModeAuto to another mode + /// while a scan is in progress, the scan is cancelled immediately, + /// without waiting for the scan to finish. + /// + /// When first entering this mode the AfState will report AfStateIdle. + /// When a trigger control is sent, AfState will report AfStateScanning + /// for a period before spontaneously changing to AfStateFocused or + /// AfStateFailed, depending on the outcome of the scan. It will remain + /// in this state until another scan is initiated by the AfTrigger + /// control. If a scan is cancelled (without changing to another mode), + /// AfState will return to AfStateIdle. + Auto = 1, + /// The AF algorithm is in continuous mode. + /// + /// In this mode the lens can re-start a scan spontaneously at any + /// moment, without any user intervention. The AfState still reports + /// whether the algorithm is currently scanning or not, though the + /// application has no ability to initiate or cancel scans, nor to move + /// the lens for itself. + /// + /// However, applications can pause the AF algorithm from continuously + /// scanning by using the AfPause control. This allows video or still + /// images to be captured whilst guaranteeing that the focus is fixed. + /// + /// When set to AfModeContinuous, the system will immediately initiate a + /// scan so AfState will report AfStateScanning, and will settle on one + /// of AfStateFocused or AfStateFailed, depending on the scan result. + Continuous = 2, +} +impl TryFrom for AfMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfMode { + const ID: u32 = ControlId::AfMode as _; +} +impl Control for AfMode {} +/// The range of focus distances that is scanned. +/// +/// An implementation may choose not to implement all the options here. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfRange { + /// A wide range of focus distances is scanned. + /// + /// Scanned distances cover all the way from infinity down to close + /// distances, though depending on the implementation, possibly not + /// including the very closest macro positions. + Normal = 0, + /// Only close distances are scanned. + Macro = 1, + /// The full range of focus distances is scanned. + /// + /// This range is similar to AfRangeNormal but includes the very + /// closest macro positions. + Full = 2, +} +impl TryFrom for AfRange { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfRange) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfRange { + const ID: u32 = ControlId::AfRange as _; +} +impl Control for AfRange {} +/// Determine whether the AF is to move the lens as quickly as possible or +/// more steadily. +/// +/// For example, during video recording it may be desirable not to move the +/// lens too abruptly, but when in a preview mode (waiting for a still +/// capture) it may be helpful to move the lens as quickly as is reasonably +/// possible. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfSpeed { + /// Move the lens at its usual speed. + Normal = 0, + /// Move the lens more quickly. + Fast = 1, +} +impl TryFrom for AfSpeed { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfSpeed) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfSpeed { + const ID: u32 = ControlId::AfSpeed as _; +} +impl Control for AfSpeed {} +/// The parts of the image used by the AF algorithm to measure focus. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfMetering { + /// Let the AF algorithm decide for itself where it will measure focus. + Auto = 0, + /// Use the rectangles defined by the AfWindows control to measure focus. + /// + /// If no windows are specified the behaviour is platform dependent. + Windows = 1, +} +impl TryFrom for AfMetering { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfMetering) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfMetering { + const ID: u32 = ControlId::AfMetering as _; +} +impl Control for AfMetering {} +/// The focus windows used by the AF algorithm when AfMetering is set to +/// AfMeteringWindows. +/// +/// The units used are pixels within the rectangle returned by the +/// ScalerCropMaximum property. +/// +/// In order to be activated, a rectangle must be programmed with non-zero +/// width and height. Internally, these rectangles are intersected with the +/// ScalerCropMaximum rectangle. If the window becomes empty after this +/// operation, then the window is ignored. If all the windows end up being +/// ignored, then the behaviour is platform dependent. +/// +/// On platforms that support the ScalerCrop control (for implementing +/// digital zoom, for example), no automatic recalculation or adjustment of +/// AF windows is performed internally if the ScalerCrop is changed. If any +/// window lies outside the output image after the scaler crop has been +/// applied, it is up to the application to recalculate them. +/// +/// The details of how the windows are used are platform dependent. We note +/// that when there is more than one AF window, a typical implementation +/// might find the optimal focus position for each one and finally select +/// the window where the focal distance for the objects shown in that part +/// of the image are closest to the camera. +#[derive(Debug, Clone)] +pub struct AfWindows(pub Vec); +impl Deref for AfWindows { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for AfWindows { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for AfWindows { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: AfWindows) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for AfWindows { + const ID: u32 = ControlId::AfWindows as _; +} +impl Control for AfWindows {} +/// Start an autofocus scan. +/// +/// This control starts an autofocus scan when AfMode is set to AfModeAuto, +/// and is ignored if AfMode is set to AfModeManual or AfModeContinuous. It +/// can also be used to terminate a scan early. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfTrigger { + /// Start an AF scan. + /// + /// Setting the control to AfTriggerStart is ignored if a scan is in + /// progress. + Start = 0, + /// Cancel an AF scan. + /// + /// This does not cause the lens to move anywhere else. Ignored if no + /// scan is in progress. + Cancel = 1, +} +impl TryFrom for AfTrigger { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfTrigger) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfTrigger { + const ID: u32 = ControlId::AfTrigger as _; +} +impl Control for AfTrigger {} +/// Pause lens movements when in continuous autofocus mode. +/// +/// This control has no effect except when in continuous autofocus mode +/// (AfModeContinuous). It can be used to pause any lens movements while +/// (for example) images are captured. The algorithm remains inactive +/// until it is instructed to resume. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfPause { + /// Pause the continuous autofocus algorithm immediately. + /// + /// The autofocus algorithm is paused whether or not any kind of scan + /// is underway. AfPauseState will subsequently report + /// AfPauseStatePaused. AfState may report any of AfStateScanning, + /// AfStateFocused or AfStateFailed, depending on the algorithm's state + /// when it received this control. + Immediate = 0, + /// Pause the continuous autofocus algorithm at the end of the scan. + /// + /// This is similar to AfPauseImmediate, and if the AfState is + /// currently reporting AfStateFocused or AfStateFailed it will remain + /// in that state and AfPauseState will report AfPauseStatePaused. + /// + /// However, if the algorithm is scanning (AfStateScanning), + /// AfPauseState will report AfPauseStatePausing until the scan is + /// finished, at which point AfState will report one of AfStateFocused + /// or AfStateFailed, and AfPauseState will change to + /// AfPauseStatePaused. + Deferred = 1, + /// Resume continuous autofocus operation. + /// + /// The algorithm starts again from exactly where it left off, and + /// AfPauseState will report AfPauseStateRunning. + Resume = 2, +} +impl TryFrom for AfPause { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfPause) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfPause { + const ID: u32 = ControlId::AfPause as _; +} +impl Control for AfPause {} +/// Set and report the focus lens position. +/// +/// This control instructs the lens to move to a particular position and +/// also reports back the position of the lens for each frame. +/// +/// The LensPosition control is ignored unless the AfMode is set to +/// AfModeManual, though the value is reported back unconditionally in all +/// modes. +/// +/// This value, which is generally a non-integer, is the reciprocal of the +/// focal distance in metres, also known as dioptres. That is, to set a +/// focal distance D, the lens position LP is given by +/// +/// \f$LP = \frac{1\mathrm{m}}{D}\f$ +/// +/// For example: +/// +/// - 0 moves the lens to infinity. +/// - 0.5 moves the lens to focus on objects 2m away. +/// - 2 moves the lens to focus on objects 50cm away. +/// - And larger values will focus the lens closer. +/// +/// The default value of the control should indicate a good general +/// position for the lens, often corresponding to the hyperfocal distance +/// (the closest position for which objects at infinity are still +/// acceptably sharp). The minimum will often be zero (meaning infinity), +/// and the maximum value defines the closest focus position. +/// +/// \todo Define a property to report the Hyperfocal distance of calibrated +/// lenses. +#[derive(Debug, Clone)] +pub struct LensPosition(pub f32); +impl Deref for LensPosition { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for LensPosition { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for LensPosition { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: LensPosition) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for LensPosition { + const ID: u32 = ControlId::LensPosition as _; +} +impl Control for LensPosition {} +/// The current state of the AF algorithm. +/// +/// This control reports the current state of the AF algorithm in +/// conjunction with the reported AfMode value and (in continuous AF mode) +/// the AfPauseState value. The possible state changes are described below, +/// though we note the following state transitions that occur when the +/// AfMode is changed. +/// +/// If the AfMode is set to AfModeManual, then the AfState will always +/// report AfStateIdle (even if the lens is subsequently moved). Changing +/// to the AfModeManual state does not initiate any lens movement. +/// +/// If the AfMode is set to AfModeAuto then the AfState will report +/// AfStateIdle. However, if AfModeAuto and AfTriggerStart are sent +/// together then AfState will omit AfStateIdle and move straight to +/// AfStateScanning (and start a scan). +/// +/// If the AfMode is set to AfModeContinuous then the AfState will +/// initially report AfStateScanning. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfState { + /// The AF algorithm is in manual mode (AfModeManual) or in auto mode + /// (AfModeAuto) and a scan has not yet been triggered, or an + /// in-progress scan was cancelled. + Idle = 0, + /// The AF algorithm is in auto mode (AfModeAuto), and a scan has been + /// started using the AfTrigger control. + /// + /// The scan can be cancelled by sending AfTriggerCancel at which point + /// the algorithm will either move back to AfStateIdle or, if the scan + /// actually completes before the cancel request is processed, to one + /// of AfStateFocused or AfStateFailed. + /// + /// Alternatively the AF algorithm could be in continuous mode + /// (AfModeContinuous) at which point it may enter this state + /// spontaneously whenever it determines that a rescan is needed. + Scanning = 1, + /// The AF algorithm is in auto (AfModeAuto) or continuous + /// (AfModeContinuous) mode and a scan has completed with the result + /// that the algorithm believes the image is now in focus. + Focused = 2, + /// The AF algorithm is in auto (AfModeAuto) or continuous + /// (AfModeContinuous) mode and a scan has completed with the result + /// that the algorithm did not find a good focus position. + Failed = 3, +} +impl TryFrom for AfState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfState) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfState { + const ID: u32 = ControlId::AfState as _; +} +impl Control for AfState {} +/// Report whether the autofocus is currently running, paused or pausing. +/// +/// This control is only applicable in continuous (AfModeContinuous) mode, +/// and reports whether the algorithm is currently running, paused or +/// pausing (that is, will pause as soon as any in-progress scan +/// completes). +/// +/// Any change to AfMode will cause AfPauseStateRunning to be reported. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AfPauseState { + /// Continuous AF is running and the algorithm may restart a scan + /// spontaneously. + Running = 0, + /// Continuous AF has been sent an AfPauseDeferred control, and will + /// pause as soon as any in-progress scan completes. + /// + /// When the scan completes, the AfPauseState control will report + /// AfPauseStatePaused. No new scans will be start spontaneously until + /// the AfPauseResume control is sent. + Pausing = 1, + /// Continuous AF is paused. + /// + /// No further state changes or lens movements will occur until the + /// AfPauseResume control is sent. + Paused = 2, +} +impl TryFrom for AfPauseState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: AfPauseState) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for AfPauseState { + const ID: u32 = ControlId::AfPauseState as _; +} +impl Control for AfPauseState {} +/// Set the mode to be used for High Dynamic Range (HDR) imaging. +/// +/// HDR techniques typically include multiple exposure, image fusion and +/// tone mapping techniques to improve the dynamic range of the resulting +/// images. +/// +/// When using an HDR mode, images are captured with different sets of AGC +/// settings called HDR channels. Channels indicate in particular the type +/// of exposure (short, medium or long) used to capture the raw image, +/// before fusion. Each HDR image is tagged with the corresponding channel +/// using the HdrChannel control. +/// +/// \sa HdrChannel +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum HdrMode { + /// HDR is disabled. + /// + /// Metadata for this frame will not include the HdrChannel control. + Off = 0, + /// Multiple exposures will be generated in an alternating fashion. + /// + /// The multiple exposures will not be merged together and will be + /// returned to the application as they are. Each image will be tagged + /// with the correct HDR channel, indicating what kind of exposure it + /// is. The tag should be the same as in the HdrModeMultiExposure case. + /// + /// The expectation is that an application using this mode would merge + /// the frames to create HDR images for itself if it requires them. + MultiExposureUnmerged = 1, + /// Multiple exposures will be generated and merged to create HDR + /// images. + /// + /// Each image will be tagged with the HDR channel (long, medium or + /// short) that arrived and which caused this image to be output. + /// + /// Systems that use two channels for HDR will return images tagged + /// alternately as the short and long channel. Systems that use three + /// channels for HDR will cycle through the short, medium and long + /// channel before repeating. + MultiExposure = 2, + /// Multiple frames all at a single exposure will be used to create HDR + /// images. + /// + /// These images should be reported as all corresponding to the HDR + /// short channel. + SingleExposure = 3, + /// Multiple frames will be combined to produce "night mode" images. + /// + /// It is up to the implementation exactly which HDR channels it uses, + /// and the images will all be tagged accordingly with the correct HDR + /// channel information. + Night = 4, +} +impl TryFrom for HdrMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: HdrMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for HdrMode { + const ID: u32 = ControlId::HdrMode as _; +} +impl Control for HdrMode {} +/// The HDR channel used to capture the frame. +/// +/// This value is reported back to the application so that it can discover +/// whether this capture corresponds to the short or long exposure image +/// (or any other image used by the HDR procedure). An application can +/// monitor the HDR channel to discover when the differently exposed images +/// have arrived. +/// +/// This metadata is only available when an HDR mode has been enabled. +/// +/// \sa HdrMode +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum HdrChannel { + /// This image does not correspond to any of the captures used to create + /// an HDR image. + None = 0, + /// This is a short exposure image. + Short = 1, + /// This is a medium exposure image. + Medium = 2, + /// This is a long exposure image. + Long = 3, +} +impl TryFrom for HdrChannel { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: HdrChannel) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for HdrChannel { + const ID: u32 = ControlId::HdrChannel as _; +} +impl Control for HdrChannel {} +/// Specify a fixed gamma value. +/// +/// The default gamma value must be 2.2 which closely mimics sRGB gamma. +/// Note that this is camera gamma, so it is applied as 1.0/gamma. +#[derive(Debug, Clone)] +pub struct Gamma(pub f32); +impl Deref for Gamma { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Gamma { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Gamma { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Gamma) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Gamma { + const ID: u32 = ControlId::Gamma as _; +} +impl Control for Gamma {} +/// Enable or disable the debug metadata. +#[derive(Debug, Clone)] +pub struct DebugMetadataEnable(pub bool); +impl Deref for DebugMetadataEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for DebugMetadataEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for DebugMetadataEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: DebugMetadataEnable) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for DebugMetadataEnable { + const ID: u32 = ControlId::DebugMetadataEnable as _; +} +impl Control for DebugMetadataEnable {} +/// This timestamp corresponds to the same moment in time as the +/// SensorTimestamp, but is represented as a wall clock time as measured by +/// the CLOCK_REALTIME clock. Like SensorTimestamp, the timestamp value is +/// expressed in nanoseconds. +/// +/// Being a wall clock measurement, it can be used to synchronise timing +/// across different devices. +/// +/// \sa SensorTimestamp +/// +/// The FrameWallClock control can only be returned in metadata. +#[derive(Debug, Clone)] +pub struct FrameWallClock(pub i64); +impl Deref for FrameWallClock { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for FrameWallClock { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for FrameWallClock { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: FrameWallClock) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for FrameWallClock { + const ID: u32 = ControlId::FrameWallClock as _; +} +impl Control for FrameWallClock {} +/// Set the WDR mode. +/// +/// The WDR mode is used to select the algorithm used for global tone +/// mapping. It will automatically reduce the exposure time of the sensor +/// so that there are only a small number of saturated pixels in the image. +/// The algorithm then compensates for the loss of brightness by applying a +/// global tone mapping curve to the image. +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum WdrMode { + /// Wdr is disabled. + WdrOff = 0, + /// Apply a linear global tone mapping curve. + /// A curve with two linear sections is applied. This produces good results at the expense of a slightly artificial look. + WdrLinear = 1, + /// Apply a power global tone mapping curve. + /// + /// This curve has high gain values on the dark areas of an image and + /// high compression values on the bright area. It therefore tends to + /// produce noticeable noise artifacts. + WdrPower = 2, + /// Apply an exponential global tone mapping curve. + /// + /// This curve has lower gain values in dark areas compared to the power + /// curve but produces a more natural look compared to the linear curve. + /// It is therefore the best choice for most scenes. + WdrExponential = 3, + /// Apply histogram equalization. + /// + /// This curve preserves most of the information of the image at the + /// expense of a very artificial look. It is therefore best suited for + /// technical analysis. + WdrHistogramEqualization = 4, +} +impl TryFrom for WdrMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: WdrMode) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for WdrMode { + const ID: u32 = ControlId::WdrMode as _; +} +impl Control for WdrMode {} +/// Specify the strength of the wdr algorithm. The exact meaning of this +/// value is specific to the algorithm in use. Usually a value of 0 means no +/// global tone mapping is applied. A values of 1 is the default value and +/// the correct value for most scenes. A value above 1 increases the global +/// tone mapping effect and can lead to unrealistic image effects. +#[derive(Debug, Clone)] +pub struct WdrStrength(pub f32); +impl Deref for WdrStrength { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for WdrStrength { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for WdrStrength { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: WdrStrength) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for WdrStrength { + const ID: u32 = ControlId::WdrStrength as _; +} +impl Control for WdrStrength {} +/// Percentage of allowed (nearly) saturated pixels. The WDR algorithm +/// reduces the WdrExposureValue until the amount of pixels that are close +/// to saturation is lower than this value. +#[derive(Debug, Clone)] +pub struct WdrMaxBrightPixels(pub f32); +impl Deref for WdrMaxBrightPixels { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for WdrMaxBrightPixels { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for WdrMaxBrightPixels { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: WdrMaxBrightPixels) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for WdrMaxBrightPixels { + const ID: u32 = ControlId::WdrMaxBrightPixels as _; +} +impl Control for WdrMaxBrightPixels {} +/// Enable or disable lens dewarping. This control is only available if lens +/// dewarp parameters are configured in the tuning file. +#[derive(Debug, Clone)] +pub struct LensDewarpEnable(pub bool); +impl Deref for LensDewarpEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for LensDewarpEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for LensDewarpEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: LensDewarpEnable) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for LensDewarpEnable { + const ID: u32 = ControlId::LensDewarpEnable as _; +} +impl Control for LensDewarpEnable {} +/// Control for AE metering trigger. Currently identical to +/// ANDROID_CONTROL_AE_PRECAPTURE_TRIGGER. +/// +/// Whether the camera device will trigger a precapture metering sequence +/// when it processes this request. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AePrecaptureTrigger { + /// The trigger is idle. + Idle = 0, + /// The pre-capture AE metering is started by the camera. + Start = 1, + /// The camera will cancel any active or completed metering sequence. + /// The AE algorithm is reset to its initial state. + Cancel = 2, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for AePrecaptureTrigger { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: AePrecaptureTrigger) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for AePrecaptureTrigger { + const ID: u32 = ControlId::AePrecaptureTrigger as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for AePrecaptureTrigger {} +/// Control to select the noise reduction algorithm mode. Currently +/// identical to ANDROID_NOISE_REDUCTION_MODE. +/// +/// Mode of operation for the noise reduction algorithm. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum NoiseReductionMode { + /// No noise reduction is applied + Off = 0, + /// Noise reduction is applied without reducing the frame rate. + Fast = 1, + /// High quality noise reduction at the expense of frame rate. + HighQuality = 2, + /// Minimal noise reduction is applied without reducing the frame rate. + Minimal = 3, + /// Noise reduction is applied at different levels to different streams. + ZSL = 4, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for NoiseReductionMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: NoiseReductionMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for NoiseReductionMode { + const ID: u32 = ControlId::NoiseReductionMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for NoiseReductionMode {} +/// Control to select the color correction aberration mode. Currently +/// identical to ANDROID_COLOR_CORRECTION_ABERRATION_MODE. +/// +/// Mode of operation for the chromatic aberration correction algorithm. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum ColorCorrectionAberrationMode { + /// No aberration correction is applied. + ColorCorrectionAberrationOff = 0, + /// Aberration correction will not slow down the frame rate. + ColorCorrectionAberrationFast = 1, + /// High quality aberration correction which might reduce the frame + /// rate. + ColorCorrectionAberrationHighQuality = 2, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for ColorCorrectionAberrationMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: ColorCorrectionAberrationMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for ColorCorrectionAberrationMode { + const ID: u32 = ControlId::ColorCorrectionAberrationMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for ColorCorrectionAberrationMode {} +/// Control to report the current AWB algorithm state. Currently identical +/// to ANDROID_CONTROL_AWB_STATE. +/// +/// Current state of the AWB algorithm. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum AwbState { + /// The AWB algorithm is inactive. + Inactive = 0, + /// The AWB algorithm has not converged yet. + Searching = 1, + /// The AWB algorithm has converged. + AwbConverged = 2, + /// The AWB algorithm is locked. + AwbLocked = 3, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for AwbState { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: AwbState) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for AwbState { + const ID: u32 = ControlId::AwbState as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for AwbState {} +/// Control to report the time between the start of exposure of the first +/// row and the start of exposure of the last row. Currently identical to +/// ANDROID_SENSOR_ROLLING_SHUTTER_SKEW +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct SensorRollingShutterSkew(pub i64); +#[cfg(feature = "vendor_draft")] +impl Deref for SensorRollingShutterSkew { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for SensorRollingShutterSkew { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for SensorRollingShutterSkew { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: SensorRollingShutterSkew) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for SensorRollingShutterSkew { + const ID: u32 = ControlId::SensorRollingShutterSkew as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for SensorRollingShutterSkew {} +/// Control to report if the lens shading map is available. Currently +/// identical to ANDROID_STATISTICS_LENS_SHADING_MAP_MODE. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum LensShadingMapMode { + /// No lens shading map mode is available. + Off = 0, + /// The lens shading map mode is available. + On = 1, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for LensShadingMapMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: LensShadingMapMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for LensShadingMapMode { + const ID: u32 = ControlId::LensShadingMapMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for LensShadingMapMode {} +/// Specifies the number of pipeline stages the frame went through from when +/// it was exposed to when the final completed result was available to the +/// framework. Always less than or equal to PipelineMaxDepth. Currently +/// identical to ANDROID_REQUEST_PIPELINE_DEPTH. +/// +/// The typical value for this control is 3 as a frame is first exposed, +/// captured and then processed in a single pass through the ISP. Any +/// additional processing step performed after the ISP pass (in example face +/// detection, additional format conversions etc) count as an additional +/// pipeline stage. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct PipelineDepth(pub i32); +#[cfg(feature = "vendor_draft")] +impl Deref for PipelineDepth { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for PipelineDepth { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for PipelineDepth { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: PipelineDepth) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for PipelineDepth { + const ID: u32 = ControlId::PipelineDepth as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for PipelineDepth {} +/// The maximum number of frames that can occur after a request (different +/// than the previous) has been submitted, and before the result's state +/// becomes synchronized. A value of -1 indicates unknown latency, and 0 +/// indicates per-frame control. Currently identical to +/// ANDROID_SYNC_MAX_LATENCY. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct MaxLatency(pub i32); +#[cfg(feature = "vendor_draft")] +impl Deref for MaxLatency { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for MaxLatency { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for MaxLatency { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: MaxLatency) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for MaxLatency { + const ID: u32 = ControlId::MaxLatency as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for MaxLatency {} +/// Control to select the test pattern mode. Currently identical to +/// ANDROID_SENSOR_TEST_PATTERN_MODE. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum TestPatternMode { + /// No test pattern mode is used. The camera device returns frames from + /// the image sensor. + Off = 0, + /// Each pixel in [R, G_even, G_odd, B] is replaced by its respective + /// color channel provided in test pattern data. + /// \todo Add control for test pattern data. + SolidColor = 1, + /// All pixel data is replaced with an 8-bar color pattern. The vertical + /// bars (left-to-right) are as follows; white, yellow, cyan, green, + /// magenta, red, blue and black. Each bar should take up 1/8 of the + /// sensor pixel array width. When this is not possible, the bar size + /// should be rounded down to the nearest integer and the pattern can + /// repeat on the right side. Each bar's height must always take up the + /// full sensor pixel array height. + ColorBars = 2, + /// The test pattern is similar to TestPatternModeColorBars, + /// except that each bar should start at its specified color at the top + /// and fade to gray at the bottom. Furthermore each bar is further + /// subdevided into a left and right half. The left half should have a + /// smooth gradient, and the right half should have a quantized + /// gradient. In particular, the right half's should consist of blocks + /// of the same color for 1/16th active sensor pixel array width. The + /// least significant bits in the quantized gradient should be copied + /// from the most significant bits of the smooth gradient. The height of + /// each bar should always be a multiple of 128. When this is not the + /// case, the pattern should repeat at the bottom of the image. + ColorBarsFadeToGray = 3, + /// All pixel data is replaced by a pseudo-random sequence generated + /// from a PN9 512-bit sequence (typically implemented in hardware with + /// a linear feedback shift register). The generator should be reset at + /// the beginning of each frame, and thus each subsequent raw frame with + /// this test pattern should be exactly the same as the last. + Pn9 = 4, + /// The first custom test pattern. All custom patterns that are + /// available only on this camera device are at least this numeric + /// value. All of the custom test patterns will be static (that is the + /// raw image must not vary from frame to frame). + Custom1 = 256, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for TestPatternMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: TestPatternMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for TestPatternMode { + const ID: u32 = ControlId::TestPatternMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for TestPatternMode {} +/// Control to select the face detection mode used by the pipeline. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_DETECT_MODE. +/// +/// \sa FaceDetectFaceRectangles +/// \sa FaceDetectFaceScores +/// \sa FaceDetectFaceLandmarks +/// \sa FaceDetectFaceIds +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum FaceDetectMode { + /// Pipeline doesn't perform face detection and doesn't report any + /// control related to face detection. + Off = 0, + /// Pipeline performs face detection and reports the + /// FaceDetectFaceRectangles and FaceDetectFaceScores controls for each + /// detected face. FaceDetectFaceLandmarks and FaceDetectFaceIds are + /// optional. + Simple = 1, + /// Pipeline performs face detection and reports all the controls + /// related to face detection including FaceDetectFaceRectangles, + /// FaceDetectFaceScores, FaceDetectFaceLandmarks, and + /// FaceDeteceFaceIds for each detected face. + Full = 2, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectMode { + const ID: u32 = ControlId::FaceDetectMode as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectMode {} +/// Boundary rectangles of the detected faces. The number of values is +/// the number of detected faces. +/// +/// The FaceDetectFaceRectangles control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_RECTANGLES. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceRectangles(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceRectangles { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceRectangles { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceRectangles { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceRectangles) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceRectangles { + const ID: u32 = ControlId::FaceDetectFaceRectangles as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceRectangles {} +/// Confidence score of each of the detected faces. The range of score is +/// [0, 100]. The number of values should be the number of faces reported +/// in FaceDetectFaceRectangles. +/// +/// The FaceDetectFaceScores control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_SCORES. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceScores(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceScores { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceScores { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceScores { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceScores) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceScores { + const ID: u32 = ControlId::FaceDetectFaceScores as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceScores {} +/// Array of human face landmark coordinates in format [..., left_eye_i, +/// right_eye_i, mouth_i, left_eye_i+1, ...], with i = index of face. The +/// number of values should be 3 * the number of faces reported in +/// FaceDetectFaceRectangles. +/// +/// The FaceDetectFaceLandmarks control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_LANDMARKS. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceLandmarks(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceLandmarks { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceLandmarks { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceLandmarks { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceLandmarks) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceLandmarks { + const ID: u32 = ControlId::FaceDetectFaceLandmarks as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceLandmarks {} +/// Each detected face is given a unique ID that is valid for as long as the +/// face is visible to the camera device. A face that leaves the field of +/// view and later returns may be assigned a new ID. The number of values +/// should be the number of faces reported in FaceDetectFaceRectangles. +/// +/// The FaceDetectFaceIds control can only be returned in metadata. +/// +/// Currently identical to ANDROID_STATISTICS_FACE_IDS. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone)] +pub struct FaceDetectFaceIds(pub Vec); +#[cfg(feature = "vendor_draft")] +impl Deref for FaceDetectFaceIds { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl DerefMut for FaceDetectFaceIds { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for FaceDetectFaceIds { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: FaceDetectFaceIds) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for FaceDetectFaceIds { + const ID: u32 = ControlId::FaceDetectFaceIds as _; +} +#[cfg(feature = "vendor_draft")] +impl Control for FaceDetectFaceIds {} +/// Toggles the Raspberry Pi IPA to output the hardware generated statistics. +/// +/// When this control is set to true, the IPA outputs a binary dump of the +/// hardware generated statistics through the Request metadata in the +/// Bcm2835StatsOutput control. +/// +/// \sa Bcm2835StatsOutput +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct StatsOutputEnable(pub bool); +#[cfg(feature = "vendor_rpi")] +impl Deref for StatsOutputEnable { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for StatsOutputEnable { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for StatsOutputEnable { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: StatsOutputEnable) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for StatsOutputEnable { + const ID: u32 = ControlId::StatsOutputEnable as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for StatsOutputEnable {} +/// Span of the BCM2835 ISP generated statistics for the current frame. +/// +/// This is sent in the Request metadata if the StatsOutputEnable is set to +/// true. The statistics struct definition can be found in +/// include/linux/bcm2835-isp.h. +/// +/// \sa StatsOutputEnable +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct Bcm2835StatsOutput(pub Vec); +#[cfg(feature = "vendor_rpi")] +impl Deref for Bcm2835StatsOutput { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for Bcm2835StatsOutput { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for Bcm2835StatsOutput { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: Bcm2835StatsOutput) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for Bcm2835StatsOutput { + const ID: u32 = ControlId::Bcm2835StatsOutput as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for Bcm2835StatsOutput {} +/// An array of rectangles, where each singular value has identical +/// functionality to the ScalerCrop control. This control allows the +/// Raspberry Pi pipeline handler to control individual scaler crops per +/// output stream. +/// +/// The order of rectangles passed into the control must match the order of +/// streams configured by the application. The pipeline handler will only +/// configure crop retangles up-to the number of output streams configured. +/// All subsequent rectangles passed into this control are ignored by the +/// pipeline handler. +/// +/// If both rpi::ScalerCrops and ScalerCrop controls are present in a +/// ControlList, the latter is discarded, and crops are obtained from this +/// control. +/// +/// Note that using different crop rectangles for each output stream with +/// this control is only applicable on the Pi5/PiSP platform. This control +/// should also be considered temporary/draft and will be replaced with +/// official libcamera API support for per-stream controls in the future. +/// +/// \sa ScalerCrop +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct ScalerCrops(pub Vec); +#[cfg(feature = "vendor_rpi")] +impl Deref for ScalerCrops { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for ScalerCrops { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for ScalerCrops { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: ScalerCrops) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for ScalerCrops { + const ID: u32 = ControlId::ScalerCrops as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for ScalerCrops {} +/// Span of the PiSP Frontend ISP generated statistics for the current +/// frame. This is sent in the Request metadata if the StatsOutputEnable is +/// set to true. The statistics struct definition can be found in +/// https://github.com/raspberrypi/libpisp/blob/main/src/libpisp/frontend/pisp_statistics.h +/// +/// \sa StatsOutputEnable +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct PispStatsOutput(pub Vec); +#[cfg(feature = "vendor_rpi")] +impl Deref for PispStatsOutput { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for PispStatsOutput { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for PispStatsOutput { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: PispStatsOutput) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for PispStatsOutput { + const ID: u32 = ControlId::PispStatsOutput as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for PispStatsOutput {} +/// Enable or disable camera synchronisation ("sync") mode. +/// +/// When sync mode is enabled, a camera will synchronise frames temporally +/// with other cameras, either attached to the same device or a different +/// one. There should be one "server" device, which broadcasts timing +/// information to one or more "clients". Communication is one-way, from +/// server to clients only, and it is only clients that adjust their frame +/// timings to match the server. +/// +/// Sync mode requires all cameras to be running at (as far as possible) the +/// same fixed framerate. Clients may continue to make adjustments to keep +/// their cameras synchronised with the server for the duration of the +/// session, though any updates after the initial ones should remain small. +/// +/// \sa SyncReady +/// \sa SyncTimer +/// \sa SyncFrames +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum SyncMode { + /// Disable sync mode. + Off = 0, + /// Enable sync mode, act as server. The server broadcasts timing + /// messages to any clients that are listening, so that the clients can + /// synchronise their camera frames with the server's. + Server = 1, + /// Enable sync mode, act as client. A client listens for any server + /// messages, and arranges for its camera frames to synchronise as + /// closely as possible with the server's. Many clients can listen out + /// for the same server. Clients can also be started ahead of any + /// servers, causing them merely to wait for the server to start. + Client = 2, +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncMode { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncMode) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncMode { + const ID: u32 = ControlId::SyncMode as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncMode {} +/// When using the camera synchronisation algorithm, the server broadcasts +/// timing information to the clients. This also includes the time (some +/// number of frames in the future, called the "ready time") at which the +/// server will signal its controlling application, using this control, to +/// start using the image frames. +/// +/// The client receives the "ready time" from the server, and will signal +/// its application to start using the frames at this same moment. +/// +/// While this control value is false, applications (on both client and +/// server) should continue to wait, and not use the frames. +/// +/// Once this value becomes true, it means that this is the first frame +/// where the server and its clients have agreed that they will both be +/// synchronised and that applications should begin consuming frames. +/// Thereafter, this control will continue to signal the value true for +/// the rest of the session. +/// +/// \sa SyncMode +/// \sa SyncTimer +/// \sa SyncFrames +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct SyncReady(pub bool); +#[cfg(feature = "vendor_rpi")] +impl Deref for SyncReady { + type Target = bool; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for SyncReady { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncReady { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncReady) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncReady { + const ID: u32 = ControlId::SyncReady as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncReady {} +/// This reports the amount of time, in microseconds, until the "ready +/// time", at which the server and client will signal their controlling +/// applications that the frames are now synchronised and should be +/// used. The value may be refined slightly over time, becoming more precise +/// as the "ready time" approaches. +/// +/// Servers always report this value, whereas clients will omit this control +/// until they have received a message from the server that enables them to +/// calculate it. +/// +/// Normally the value will start positive (the "ready time" is in the +/// future), and decrease towards zero, before becoming negative (the "ready +/// time" has elapsed). So there should be just one frame where the timer +/// value is, or is very close to, zero - the one for which the SyncReady +/// control becomes true. At this moment, the value indicates how closely +/// synchronised the client believes it is with the server. +/// +/// But note that if frames are being dropped, then the "near zero" valued +/// frame, or indeed any other, could be skipped. In these cases the timer +/// value allows an application to deduce that this has happened. +/// +/// \sa SyncMode +/// \sa SyncReady +/// \sa SyncFrames +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct SyncTimer(pub i64); +#[cfg(feature = "vendor_rpi")] +impl Deref for SyncTimer { + type Target = i64; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for SyncTimer { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncTimer { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncTimer) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncTimer { + const ID: u32 = ControlId::SyncTimer as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncTimer {} +/// The number of frames the server should wait, after enabling +/// SyncModeServer, before signalling (via the SyncReady control) that +/// frames should be used. This therefore determines the "ready time" for +/// all synchronised cameras. +/// +/// This control value should be set only for the device that is to act as +/// the server, before or at the same moment at which SyncModeServer is +/// enabled. +/// +/// \sa SyncMode +/// \sa SyncReady +/// \sa SyncTimer +#[cfg(feature = "vendor_rpi")] +#[derive(Debug, Clone)] +pub struct SyncFrames(pub i32); +#[cfg(feature = "vendor_rpi")] +impl Deref for SyncFrames { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl DerefMut for SyncFrames { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +#[cfg(feature = "vendor_rpi")] +impl TryFrom for SyncFrames { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +#[cfg(feature = "vendor_rpi")] +impl From for ControlValue { + fn from(val: SyncFrames) -> Self { + ControlValue::from(val.0) + } +} +#[cfg(feature = "vendor_rpi")] +impl ControlEntry for SyncFrames { + const ID: u32 = ControlId::SyncFrames as _; +} +#[cfg(feature = "vendor_rpi")] +impl Control for SyncFrames {} +pub fn make_dyn( + id: ControlId, + val: ControlValue, +) -> Result, ControlValueError> { + match id { + ControlId::AeEnable => Ok(Box::new(AeEnable::try_from(val)?)), + ControlId::AeState => Ok(Box::new(AeState::try_from(val)?)), + ControlId::AeMeteringMode => Ok(Box::new(AeMeteringMode::try_from(val)?)), + ControlId::AeConstraintMode => Ok(Box::new(AeConstraintMode::try_from(val)?)), + ControlId::AeExposureMode => Ok(Box::new(AeExposureMode::try_from(val)?)), + ControlId::ExposureValue => Ok(Box::new(ExposureValue::try_from(val)?)), + ControlId::ExposureTime => Ok(Box::new(ExposureTime::try_from(val)?)), + ControlId::ExposureTimeMode => Ok(Box::new(ExposureTimeMode::try_from(val)?)), + ControlId::AnalogueGain => Ok(Box::new(AnalogueGain::try_from(val)?)), + ControlId::AnalogueGainMode => Ok(Box::new(AnalogueGainMode::try_from(val)?)), + ControlId::AeFlickerMode => Ok(Box::new(AeFlickerMode::try_from(val)?)), + ControlId::AeFlickerPeriod => Ok(Box::new(AeFlickerPeriod::try_from(val)?)), + ControlId::AeFlickerDetected => Ok(Box::new(AeFlickerDetected::try_from(val)?)), + ControlId::Brightness => Ok(Box::new(Brightness::try_from(val)?)), + ControlId::Contrast => Ok(Box::new(Contrast::try_from(val)?)), + ControlId::Lux => Ok(Box::new(Lux::try_from(val)?)), + ControlId::AwbEnable => Ok(Box::new(AwbEnable::try_from(val)?)), + ControlId::AwbMode => Ok(Box::new(AwbMode::try_from(val)?)), + ControlId::AwbLocked => Ok(Box::new(AwbLocked::try_from(val)?)), + ControlId::ColourGains => Ok(Box::new(ColourGains::try_from(val)?)), + ControlId::ColourTemperature => Ok(Box::new(ColourTemperature::try_from(val)?)), + ControlId::Saturation => Ok(Box::new(Saturation::try_from(val)?)), + ControlId::SensorBlackLevels => Ok(Box::new(SensorBlackLevels::try_from(val)?)), + ControlId::Sharpness => Ok(Box::new(Sharpness::try_from(val)?)), + ControlId::FocusFoM => Ok(Box::new(FocusFoM::try_from(val)?)), + ControlId::ColourCorrectionMatrix => { + Ok(Box::new(ColourCorrectionMatrix::try_from(val)?)) + } + ControlId::ScalerCrop => Ok(Box::new(ScalerCrop::try_from(val)?)), + ControlId::DigitalGain => Ok(Box::new(DigitalGain::try_from(val)?)), + ControlId::FrameDuration => Ok(Box::new(FrameDuration::try_from(val)?)), + ControlId::FrameDurationLimits => { + Ok(Box::new(FrameDurationLimits::try_from(val)?)) + } + ControlId::SensorTemperature => Ok(Box::new(SensorTemperature::try_from(val)?)), + ControlId::SensorTimestamp => Ok(Box::new(SensorTimestamp::try_from(val)?)), + ControlId::AfMode => Ok(Box::new(AfMode::try_from(val)?)), + ControlId::AfRange => Ok(Box::new(AfRange::try_from(val)?)), + ControlId::AfSpeed => Ok(Box::new(AfSpeed::try_from(val)?)), + ControlId::AfMetering => Ok(Box::new(AfMetering::try_from(val)?)), + ControlId::AfWindows => Ok(Box::new(AfWindows::try_from(val)?)), + ControlId::AfTrigger => Ok(Box::new(AfTrigger::try_from(val)?)), + ControlId::AfPause => Ok(Box::new(AfPause::try_from(val)?)), + ControlId::LensPosition => Ok(Box::new(LensPosition::try_from(val)?)), + ControlId::AfState => Ok(Box::new(AfState::try_from(val)?)), + ControlId::AfPauseState => Ok(Box::new(AfPauseState::try_from(val)?)), + ControlId::HdrMode => Ok(Box::new(HdrMode::try_from(val)?)), + ControlId::HdrChannel => Ok(Box::new(HdrChannel::try_from(val)?)), + ControlId::Gamma => Ok(Box::new(Gamma::try_from(val)?)), + ControlId::DebugMetadataEnable => { + Ok(Box::new(DebugMetadataEnable::try_from(val)?)) + } + ControlId::FrameWallClock => Ok(Box::new(FrameWallClock::try_from(val)?)), + ControlId::WdrMode => Ok(Box::new(WdrMode::try_from(val)?)), + ControlId::WdrStrength => Ok(Box::new(WdrStrength::try_from(val)?)), + ControlId::WdrMaxBrightPixels => Ok(Box::new(WdrMaxBrightPixels::try_from(val)?)), + ControlId::LensDewarpEnable => Ok(Box::new(LensDewarpEnable::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::AePrecaptureTrigger => { + Ok(Box::new(AePrecaptureTrigger::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::NoiseReductionMode => Ok(Box::new(NoiseReductionMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::ColorCorrectionAberrationMode => { + Ok(Box::new(ColorCorrectionAberrationMode::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::AwbState => Ok(Box::new(AwbState::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::SensorRollingShutterSkew => { + Ok(Box::new(SensorRollingShutterSkew::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::LensShadingMapMode => Ok(Box::new(LensShadingMapMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::PipelineDepth => Ok(Box::new(PipelineDepth::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::MaxLatency => Ok(Box::new(MaxLatency::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::TestPatternMode => Ok(Box::new(TestPatternMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectMode => Ok(Box::new(FaceDetectMode::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceRectangles => { + Ok(Box::new(FaceDetectFaceRectangles::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceScores => { + Ok(Box::new(FaceDetectFaceScores::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceLandmarks => { + Ok(Box::new(FaceDetectFaceLandmarks::try_from(val)?)) + } + #[cfg(feature = "vendor_draft")] + ControlId::FaceDetectFaceIds => Ok(Box::new(FaceDetectFaceIds::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::StatsOutputEnable => Ok(Box::new(StatsOutputEnable::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::Bcm2835StatsOutput => Ok(Box::new(Bcm2835StatsOutput::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::ScalerCrops => Ok(Box::new(ScalerCrops::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::PispStatsOutput => Ok(Box::new(PispStatsOutput::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncMode => Ok(Box::new(SyncMode::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncReady => Ok(Box::new(SyncReady::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncTimer => Ok(Box::new(SyncTimer::try_from(val)?)), + #[cfg(feature = "vendor_rpi")] + ControlId::SyncFrames => Ok(Box::new(SyncFrames::try_from(val)?)), + } +} diff --git a/libcamera/versioned_files/0.6.0/pixel_format_info.rs b/libcamera/versioned_files/0.6.0/pixel_format_info.rs new file mode 100644 index 0000000..16d3ddb --- /dev/null +++ b/libcamera/versioned_files/0.6.0/pixel_format_info.rs @@ -0,0 +1,103 @@ + +// Auto-generated from libcamera/src/libcamera/formats.cpp +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatPlaneInfoData { + pub bytes_per_group: u32, + pub vertical_sub_sampling: u32, +} + +#[derive(Clone, Copy)] +pub(crate) struct PixelFormatInfoData { + pub name: &'static str, + pub fourcc: u32, + pub modifier: u64, + pub bits_per_pixel: u32, + pub colour_encoding: u8, + pub packed: bool, + pub pixels_per_group: u32, + pub planes: &'static [PixelFormatPlaneInfoData], + pub v4l2_formats: &'static [u32], +} + +pub(crate) static PIXEL_FORMAT_INFO: &[PixelFormatInfoData] = &[ + PixelFormatInfoData { name: "RGB565", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50424752], }, + PixelFormatInfoData { name: "RGB565_BE", fourcc: 0xb6314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52424752], }, + PixelFormatInfoData { name: "BGR888", fourcc: 0x34324742, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33424752], }, + PixelFormatInfoData { name: "RGB888", fourcc: 0x34324752, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x33524742], }, + PixelFormatInfoData { name: "XRGB8888", fourcc: 0x34325258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325258], }, + PixelFormatInfoData { name: "XBGR8888", fourcc: 0x34324258, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324258], }, + PixelFormatInfoData { name: "RGBX8888", fourcc: 0x34325852, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325852], }, + PixelFormatInfoData { name: "BGRX8888", fourcc: 0x34325842, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325842], }, + PixelFormatInfoData { name: "ABGR8888", fourcc: 0x34324241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324241], }, + PixelFormatInfoData { name: "ARGB8888", fourcc: 0x34325241, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34325241], }, + PixelFormatInfoData { name: "BGRA8888", fourcc: 0x34324142, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324142], }, + PixelFormatInfoData { name: "RGBA8888", fourcc: 0x34324152, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324152], }, + PixelFormatInfoData { name: "BGR161616", fourcc: 0x38344742, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36424752], }, + PixelFormatInfoData { name: "RGB161616", fourcc: 0x38344752, modifier: 0x0000000000000000, bits_per_pixel: 48, colour_encoding: 0, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36524742], }, + PixelFormatInfoData { name: "YUYV", fourcc: 0x56595559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x56595559], }, + PixelFormatInfoData { name: "YVYU", fourcc: 0x55595659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x55595659], }, + PixelFormatInfoData { name: "UYVY", fourcc: 0x59565955, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59565955], }, + PixelFormatInfoData { name: "VYUY", fourcc: 0x59555956, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59555956], }, + PixelFormatInfoData { name: "AVUY8888", fourcc: 0x59555641, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41565559], }, + PixelFormatInfoData { name: "XVUY8888", fourcc: 0x59555658, modifier: 0x0000000000000000, bits_per_pixel: 32, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x58565559], }, + PixelFormatInfoData { name: "NV12", fourcc: 0x3231564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3231564e, 0x32314d4e], }, + PixelFormatInfoData { name: "NV21", fourcc: 0x3132564e, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3132564e, 0x31324d4e], }, + PixelFormatInfoData { name: "NV16", fourcc: 0x3631564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3631564e, 0x36314d4e], }, + PixelFormatInfoData { name: "NV61", fourcc: 0x3136564e, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3136564e, 0x31364d4e], }, + PixelFormatInfoData { name: "NV24", fourcc: 0x3432564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3432564e], }, + PixelFormatInfoData { name: "NV42", fourcc: 0x3234564e, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x3234564e], }, + PixelFormatInfoData { name: "YUV420", fourcc: 0x32315559, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315559, 0x32314d59], }, + PixelFormatInfoData { name: "YVU420", fourcc: 0x32315659, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32315659, 0x31324d59], }, + PixelFormatInfoData { name: "YUV422", fourcc: 0x36315559, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323234, 0x36314d59], }, + PixelFormatInfoData { name: "YVU422", fourcc: 0x36315659, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31364d59], }, + PixelFormatInfoData { name: "YUV444", fourcc: 0x34325559, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34324d59], }, + PixelFormatInfoData { name: "YVU444", fourcc: 0x34325659, modifier: 0x0000000000000000, bits_per_pixel: 24, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32344d59], }, + PixelFormatInfoData { name: "R8", fourcc: 0x20203852, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x59455247], }, + PixelFormatInfoData { name: "R10", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20303159], }, + PixelFormatInfoData { name: "R10_CSI2P", fourcc: 0x20303152, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 1, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50303159], }, + PixelFormatInfoData { name: "R12_CSI2P", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x50323159], }, + PixelFormatInfoData { name: "R12", fourcc: 0x20323152, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20323159], }, + PixelFormatInfoData { name: "R16", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x20363159], }, + PixelFormatInfoData { name: "MONO_PISP_COMP1", fourcc: 0x20363152, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 1, packed: true, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x4d314350], }, + PixelFormatInfoData { name: "SBGGR8", fourcc: 0x31384142, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x31384142], }, + PixelFormatInfoData { name: "SGBRG8", fourcc: 0x47524247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47524247], }, + PixelFormatInfoData { name: "SGRBG8", fourcc: 0x47425247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47425247], }, + PixelFormatInfoData { name: "SRGGB8", fourcc: 0x42474752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42474752], }, + PixelFormatInfoData { name: "SBGGR10", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314742], }, + PixelFormatInfoData { name: "SGBRG10", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314247], }, + PixelFormatInfoData { name: "SGRBG10", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314142], }, + PixelFormatInfoData { name: "SRGGB10", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x30314752], }, + PixelFormatInfoData { name: "SBGGR10_CSI2P", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414270], }, + PixelFormatInfoData { name: "SGBRG10_CSI2P", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41414770], }, + PixelFormatInfoData { name: "SGRBG10_CSI2P", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41416770], }, + PixelFormatInfoData { name: "SRGGB10_CSI2P", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x41415270], }, + PixelFormatInfoData { name: "SBGGR12", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314742], }, + PixelFormatInfoData { name: "SGBRG12", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314247], }, + PixelFormatInfoData { name: "SGRBG12", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314142], }, + PixelFormatInfoData { name: "SRGGB12", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32314752], }, + PixelFormatInfoData { name: "SBGGR12_CSI2P", fourcc: 0x32314742, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434270], }, + PixelFormatInfoData { name: "SGBRG12_CSI2P", fourcc: 0x32314247, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43434770], }, + PixelFormatInfoData { name: "SGRBG12_CSI2P", fourcc: 0x32314142, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43436770], }, + PixelFormatInfoData { name: "SRGGB12_CSI2P", fourcc: 0x32314752, modifier: 0x0000000000000000, bits_per_pixel: 12, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x43435270], }, + PixelFormatInfoData { name: "SBGGR14", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314742], }, + PixelFormatInfoData { name: "SGBRG14", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314247], }, + PixelFormatInfoData { name: "SGRBG14", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34315247], }, + PixelFormatInfoData { name: "SRGGB14", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x34314752], }, + PixelFormatInfoData { name: "SBGGR14_CSI2P", fourcc: 0x34314742, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454270], }, + PixelFormatInfoData { name: "SGBRG14_CSI2P", fourcc: 0x34314247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45454770], }, + PixelFormatInfoData { name: "SGRBG14_CSI2P", fourcc: 0x34315247, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45456770], }, + PixelFormatInfoData { name: "SRGGB14_CSI2P", fourcc: 0x34314752, modifier: 0x0000000000000000, bits_per_pixel: 14, colour_encoding: 2, packed: true, pixels_per_group: 4, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x45455270], }, + PixelFormatInfoData { name: "SBGGR16", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x32525942], }, + PixelFormatInfoData { name: "SGBRG16", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314247], }, + PixelFormatInfoData { name: "SGRBG16", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36315247], }, + PixelFormatInfoData { name: "SRGGB16", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 16, colour_encoding: 2, packed: false, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x36314752], }, + PixelFormatInfoData { name: "SBGGR10_IPU3", fourcc: 0x30314742, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x62337069], }, + PixelFormatInfoData { name: "SGBRG10_IPU3", fourcc: 0x30314247, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67337069], }, + PixelFormatInfoData { name: "SGRBG10_IPU3", fourcc: 0x30314142, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47337069], }, + PixelFormatInfoData { name: "SRGGB10_IPU3", fourcc: 0x30314752, modifier: 0x0000000000000000, bits_per_pixel: 10, colour_encoding: 2, packed: true, pixels_per_group: 25, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x72337069], }, + PixelFormatInfoData { name: "BGGR_PISP_COMP1", fourcc: 0x32525942, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x42314350], }, + PixelFormatInfoData { name: "GBRG_PISP_COMP1", fourcc: 0x36314247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x67314350], }, + PixelFormatInfoData { name: "GRBG_PISP_COMP1", fourcc: 0x36315247, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47314350], }, + PixelFormatInfoData { name: "RGGB_PISP_COMP1", fourcc: 0x36314752, modifier: 0x0000000000000000, bits_per_pixel: 8, colour_encoding: 2, packed: true, pixels_per_group: 2, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x52314350], }, + PixelFormatInfoData { name: "MJPEG", fourcc: 0x47504a4d, modifier: 0x0000000000000000, bits_per_pixel: 0, colour_encoding: 1, packed: false, pixels_per_group: 1, planes: &[PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }, PixelFormatPlaneInfoData { bytes_per_group: 0, vertical_sub_sampling: 0 }], v4l2_formats: &[0x47504a4d, 0x4745504a], }, +]; diff --git a/libcamera/versioned_files/0.6.0/properties.rs b/libcamera/versioned_files/0.6.0/properties.rs new file mode 100644 index 0000000..e373566 --- /dev/null +++ b/libcamera/versioned_files/0.6.0/properties.rs @@ -0,0 +1,2443 @@ +use std::ops::{Deref, DerefMut}; +use num_enum::{IntoPrimitive, TryFromPrimitive}; +#[allow(unused_imports)] +use crate::control::{Control, Property, ControlEntry, DynControlEntry}; +use crate::control_value::{ControlValue, ControlValueError}; +#[allow(unused_imports)] +use crate::geometry::{Rectangle, Point, Size}; +#[allow(unused_imports)] +use libcamera_sys::*; +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(u32)] +pub enum PropertyId { + /// Camera mounting location + Location = LOCATION, + /// The camera physical mounting rotation. It is expressed as the angular + /// difference in degrees between two reference systems, one relative to the + /// camera module, and one defined on the external world scene to be + /// captured when projected on the image sensor pixel array. + /// + /// A camera sensor has a 2-dimensional reference system 'Rc' defined by + /// its pixel array read-out order. The origin is set to the first pixel + /// being read out, the X-axis points along the column read-out direction + /// towards the last columns, and the Y-axis along the row read-out + /// direction towards the last row. + /// + /// A typical example for a sensor with a 2592x1944 pixel array matrix + /// observed from the front is + /// + /// ```text + /// 2591 X-axis 0 + /// <------------------------+ 0 + /// .......... ... ..........! + /// .......... ... ..........! Y-axis + /// ... ! + /// .......... ... ..........! + /// .......... ... ..........! 1943 + /// V + /// ``` + /// + /// + /// The external world scene reference system 'Rs' is a 2-dimensional + /// reference system on the focal plane of the camera module. The origin is + /// placed on the top-left corner of the visible scene, the X-axis points + /// towards the right, and the Y-axis points towards the bottom of the + /// scene. The top, bottom, left and right directions are intentionally not + /// defined and depend on the environment in which the camera is used. + /// + /// A typical example of a (very common) picture of a shark swimming from + /// left to right, as seen from the camera, is + /// + /// ```text + /// 0 X-axis + /// 0 +-------------------------------------> + /// ! + /// ! + /// ! + /// ! |\____)\___ + /// ! ) _____ __`< + /// ! |/ )/ + /// ! + /// ! + /// ! + /// V + /// Y-axis + /// ``` + /// + /// With the reference system 'Rs' placed on the camera focal plane. + /// + /// ```text + /// ¸.·˙! + /// ¸.·˙ ! + /// _ ¸.·˙ ! + /// +-/ \-+¸.·˙ ! + /// | (o) | ! Camera focal plane + /// +-----+˙·.¸ ! + /// ˙·.¸ ! + /// ˙·.¸ ! + /// ˙·.¸! + /// ``` + /// + /// When projected on the sensor's pixel array, the image and the associated + /// reference system 'Rs' are typically (but not always) inverted, due to + /// the camera module's lens optical inversion effect. + /// + /// Assuming the above represented scene of the swimming shark, the lens + /// inversion projects the scene and its reference system onto the sensor + /// pixel array, seen from the front of the camera sensor, as follow + /// + /// ```text + /// Y-axis + /// ^ + /// ! + /// ! + /// ! + /// ! |\_____)\__ + /// ! ) ____ ___.< + /// ! |/ )/ + /// ! + /// ! + /// ! + /// 0 +-------------------------------------> + /// 0 X-axis + /// ``` + /// + /// Note the shark being upside-down. + /// + /// The resulting projected reference system is named 'Rp'. + /// + /// The camera rotation property is then defined as the angular difference + /// in the counter-clockwise direction between the camera reference system + /// 'Rc' and the projected scene reference system 'Rp'. It is expressed in + /// degrees as a number in the range [0, 360[. + /// + /// Examples + /// + /// 0 degrees camera rotation + /// + /// + /// ```text + /// Y-Rp + /// ^ + /// Y-Rc ! + /// ^ ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// 0 +-------------------------------------> + /// 0 X-Rc + /// ``` + /// + /// + /// ```text + /// X-Rc 0 + /// <------------------------------------+ 0 + /// X-Rp 0 ! + /// <------------------------------------+ 0 ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rc + /// V + /// Y-Rp + /// ``` + /// + /// 90 degrees camera rotation + /// + /// ```text + /// 0 Y-Rc + /// 0 +--------------------> + /// ! Y-Rp + /// ! ^ + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// ! + /// ! + /// ! + /// ! + /// V + /// X-Rc + /// ``` + /// + /// 180 degrees camera rotation + /// + /// ```text + /// 0 + /// <------------------------------------+ 0 + /// X-Rc ! + /// Y-Rp ! + /// ^ ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rc + /// 0 +-------------------------------------> + /// 0 X-Rp + /// ``` + /// + /// 270 degrees camera rotation + /// + /// ```text + /// 0 Y-Rc + /// 0 +--------------------> + /// ! 0 + /// ! <-----------------------------------+ 0 + /// ! X-Rp ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rp + /// ! + /// ! + /// ! + /// ! + /// V + /// X-Rc + /// ``` + /// + /// + /// Example one - Webcam + /// + /// A camera module installed on the user facing part of a laptop screen + /// casing used for video calls. The captured images are meant to be + /// displayed in landscape mode (width > height) on the laptop screen. + /// + /// The camera is typically mounted upside-down to compensate the lens + /// optical inversion effect. + /// + /// ```text + /// Y-Rp + /// Y-Rc ^ + /// ^ ! + /// ! ! + /// ! ! |\_____)\__ + /// ! ! ) ____ ___.< + /// ! ! |/ )/ + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// 0 +-------------------------------------> + /// 0 X-Rc + /// ``` + /// + /// The two reference systems are aligned, the resulting camera rotation is + /// 0 degrees, no rotation correction needs to be applied to the resulting + /// image once captured to memory buffers to correctly display it to users. + /// + /// ```text + /// +--------------------------------------+ + /// ! ! + /// ! ! + /// ! ! + /// ! |\____)\___ ! + /// ! ) _____ __`< ! + /// ! |/ )/ ! + /// ! ! + /// ! ! + /// ! ! + /// +--------------------------------------+ + /// ``` + /// + /// If the camera sensor is not mounted upside-down to compensate for the + /// lens optical inversion, the two reference systems will not be aligned, + /// with 'Rp' being rotated 180 degrees relatively to 'Rc'. + /// + /// + /// ```text + /// X-Rc 0 + /// <------------------------------------+ 0 + /// ! + /// Y-Rp ! + /// ^ ! + /// ! ! + /// ! |\_____)\__ ! + /// ! ) ____ ___.< ! + /// ! |/ )/ ! + /// ! ! + /// ! ! + /// ! V + /// ! Y-Rc + /// 0 +-------------------------------------> + /// 0 X-Rp + /// ``` + /// + /// The image once captured to memory will then be rotated by 180 degrees + /// + /// ```text + /// +--------------------------------------+ + /// ! ! + /// ! ! + /// ! ! + /// ! __/(_____/| ! + /// ! >.___ ____ ( ! + /// ! \( \| ! + /// ! ! + /// ! ! + /// ! ! + /// +--------------------------------------+ + /// ``` + /// + /// A software rotation correction of 180 degrees should be applied to + /// correctly display the image. + /// + /// ```text + /// +--------------------------------------+ + /// ! ! + /// ! ! + /// ! ! + /// ! |\____)\___ ! + /// ! ) _____ __`< ! + /// ! |/ )/ ! + /// ! ! + /// ! ! + /// ! ! + /// +--------------------------------------+ + /// ``` + /// + /// Example two - Phone camera + /// + /// A camera installed on the back side of a mobile device facing away from + /// the user. The captured images are meant to be displayed in portrait mode + /// (height > width) to match the device screen orientation and the device + /// usage orientation used when taking the picture. + /// + /// The camera sensor is typically mounted with its pixel array longer side + /// aligned to the device longer side, upside-down mounted to compensate for + /// the lens optical inversion effect. + /// + /// ```text + /// 0 Y-Rc + /// 0 +--------------------> + /// ! Y-Rp + /// ! ^ + /// ! ! + /// ! ! + /// ! ! + /// ! ! |\_____)\__ + /// ! ! ) ____ ___.< + /// ! ! |/ )/ + /// ! ! + /// ! ! + /// ! ! + /// ! 0 +-------------------------------------> + /// ! 0 X-Rp + /// ! + /// ! + /// ! + /// ! + /// V + /// X-Rc + /// ``` + /// + /// The two reference systems are not aligned and the 'Rp' reference + /// system is rotated by 90 degrees in the counter-clockwise direction + /// relatively to the 'Rc' reference system. + /// + /// The image once captured to memory will be rotated. + /// + /// ```text + /// +-------------------------------------+ + /// | _ _ | + /// | \ / | + /// | | | | + /// | | | | + /// | | > | + /// | < | | + /// | | | | + /// | . | + /// | V | + /// +-------------------------------------+ + /// ``` + /// + /// A correction of 90 degrees in counter-clockwise direction has to be + /// applied to correctly display the image in portrait mode on the device + /// screen. + /// + /// ```text + /// +--------------------+ + /// | | + /// | | + /// | | + /// | | + /// | | + /// | | + /// | |\____)\___ | + /// | ) _____ __`< | + /// | |/ )/ | + /// | | + /// | | + /// | | + /// | | + /// | | + /// +--------------------+ + Rotation = ROTATION, + /// The model name shall to the extent possible describe the sensor. For + /// most devices this is the model name of the sensor. While for some + /// devices the sensor model is unavailable as the sensor or the entire + /// camera is part of a larger unit and exposed as a black-box to the + /// system. In such cases the model name of the smallest device that + /// contains the camera sensor shall be used. + /// + /// The model name is not meant to be a camera name displayed to the + /// end-user, but may be combined with other camera information to create a + /// camera name. + /// + /// The model name is not guaranteed to be unique in the system nor is + /// it guaranteed to be stable or have any other properties required to make + /// it a good candidate to be used as a permanent identifier of a camera. + /// + /// The model name shall describe the camera in a human readable format and + /// shall be encoded in ASCII. + /// + /// Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. + Model = MODEL, + /// The pixel unit cell physical size, in nanometers. + /// + /// The UnitCellSize properties defines the horizontal and vertical sizes of + /// a single pixel unit, including its active and non-active parts. In + /// other words, it expresses the horizontal and vertical distance between + /// the top-left corners of adjacent pixels. + /// + /// The property can be used to calculate the physical size of the sensor's + /// pixel array area and for calibration purposes. + UnitCellSize = UNIT_CELL_SIZE, + /// The camera sensor pixel array readable area vertical and horizontal + /// sizes, in pixels. + /// + /// The PixelArraySize property defines the size in pixel units of the + /// readable part of full pixel array matrix, including optical black + /// pixels used for calibration, pixels which are not considered valid for + /// capture and active pixels containing valid image data. + /// + /// The property describes the maximum size of the raw data captured by the + /// camera, which might not correspond to the physical size of the sensor + /// pixel array matrix, as some portions of the physical pixel array matrix + /// are not accessible and cannot be transmitted out. + /// + /// For example, let's consider a pixel array matrix assembled as follows + /// + /// ```text + /// +--------------------------------------------------+ + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// ... ... ... ... ... + /// ``` + /// + /// ```text + /// ... ... ... ... ... + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + /// +--------------------------------------------------+ + /// ``` + /// + /// starting with two lines of non-readable pixels (x), followed by N lines + /// of readable data (D) surrounded by two columns of non-readable pixels on + /// each side, and ending with two more lines of non-readable pixels. Only + /// the readable portion is transmitted to the receiving side, defining the + /// sizes of the largest possible buffer of raw data that can be presented + /// to applications. + /// + /// ```text + /// PixelArraySize.width + /// /----------------------------------------------/ + /// +----------------------------------------------+ / + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + /// ... ... ... ... ... + /// ... ... ... ... ... + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + /// +----------------------------------------------+ / + /// ``` + /// + /// This defines a rectangle whose top-left corner is placed in position (0, + /// 0) and whose vertical and horizontal sizes are defined by this property. + /// All other rectangles that describe portions of the pixel array, such as + /// the optical black pixels rectangles and active pixel areas, are defined + /// relatively to this rectangle. + /// + /// All the coordinates are expressed relative to the default sensor readout + /// direction, without any transformation (such as horizontal and vertical + /// flipping) applied. When mapping them to the raw pixel buffer, + /// applications shall take any configured transformation into account. + /// + /// \todo Rename this property to Size once we will have property + /// ```text + /// categories (i.e. Properties::PixelArray::Size) + PixelArraySize = PIXEL_ARRAY_SIZE, + /// The pixel array region(s) which contain optical black pixels + /// considered valid for calibration purposes. + /// + /// This property describes the position and size of optical black pixel + /// regions in the raw data buffer as stored in memory, which might differ + /// from their actual physical location in the pixel array matrix. + /// + /// It is important to note, in fact, that camera sensors might + /// automatically reorder or skip portions of their pixels array matrix when + /// transmitting data to the receiver. For instance, a sensor may merge the + /// top and bottom optical black rectangles into a single rectangle, + /// transmitted at the beginning of the frame. + /// + /// The pixel array contains several areas with different purposes, + /// interleaved by lines and columns which are said not to be valid for + /// capturing purposes. Invalid lines and columns are defined as invalid as + /// they could be positioned too close to the chip margins or to the optical + /// black shielding placed on top of optical black pixels. + /// + /// ```text + /// PixelArraySize.width + /// /----------------------------------------------/ + /// x1 x2 + /// +--o---------------------------------------o---+ / + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + /// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + /// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + /// ... ... ... ... ... + /// ... ... ... ... ... + /// y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + /// +----------------------------------------------+ / + /// ``` + /// + /// The readable pixel array matrix is composed by + /// 2 invalid lines (I) + /// 4 lines of valid optical black pixels (O) + /// 2 invalid lines (I) + /// n lines of valid pixel data (P) + /// 2 invalid lines (I) + /// + /// And the position of the optical black pixel rectangles is defined by + /// + /// ```text + /// PixelArrayOpticalBlackRectangles = { + /// { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + /// { x1, y3, 2, y4 - y3 + 1 }, + /// { x2, y3, 2, y4 - y3 + 1 }, + /// }; + /// ``` + /// + /// If the camera, when capturing the full pixel array matrix, automatically + /// skips the invalid lines and columns, producing the following data + /// buffer, when captured to memory + /// + /// ```text + /// PixelArraySize.width + /// /----------------------------------------------/ + /// x1 + /// +--------------------------------------------o-+ / + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + /// y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + /// ... ... ... ... ... | + /// ... ... ... ... ... | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + /// +----------------------------------------------+ / + /// ``` + /// + /// then the invalid lines and columns should not be reported as part of the + /// PixelArraySize property in first place. + /// + /// In this case, the position of the black pixel rectangles will be + /// + /// ```text + /// PixelArrayOpticalBlackRectangles = { + /// { 0, 0, y1 + 1, PixelArraySize[0] }, + /// { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + /// { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + /// }; + /// ``` + /// + /// \todo Rename this property to Size once we will have property + /// ```text + /// categories (i.e. Properties::PixelArray::OpticalBlackRectangles) + PixelArrayOpticalBlackRectangles = PIXEL_ARRAY_OPTICAL_BLACK_RECTANGLES, + /// The PixelArrayActiveAreas property defines the (possibly multiple and + /// overlapping) portions of the camera sensor readable pixel matrix + /// which are considered valid for image acquisition purposes. + /// + /// This property describes an arbitrary number of overlapping rectangles, + /// with each rectangle representing the maximum image size that the camera + /// sensor can produce for a particular aspect ratio. They are defined + /// relatively to the PixelArraySize rectangle. + /// + /// When multiple rectangles are reported, they shall be ordered from the + /// tallest to the shortest. + /// + /// Example 1 + /// A camera sensor which only produces images in the 4:3 image resolution + /// will report a single PixelArrayActiveAreas rectangle, from which all + /// other image formats are obtained by either cropping the field-of-view + /// and/or applying pixel sub-sampling techniques such as pixel skipping or + /// binning. + /// + /// ```text + /// PixelArraySize.width + /// /----------------/ + /// x1 x2 + /// (0,0)-> +-o------------o-+ / + /// y1 o +------------+ | | + /// | |////////////| | | + /// | |////////////| | | PixelArraySize.height + /// | |////////////| | | + /// y2 o +------------+ | | + /// +----------------+ / + /// ``` + /// + /// The property reports a single rectangle + /// + /// ```text + /// PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + /// ``` + /// + /// Example 2 + /// A camera sensor which can produce images in different native + /// resolutions will report several overlapping rectangles, one for each + /// natively supported resolution. + /// + /// ```text + /// PixelArraySize.width + /// /------------------/ + /// x1 x2 x3 x4 + /// (0,0)-> +o---o------o---o+ / + /// y1 o +------+ | | + /// | |//////| | | + /// y2 o+---+------+---+| | + /// ||///|//////|///|| | PixelArraySize.height + /// y3 o+---+------+---+| | + /// | |//////| | | + /// y4 o +------+ | | + /// +----+------+----+ / + /// ``` + /// + /// The property reports two rectangles + /// + /// ```text + /// PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + /// (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + /// ``` + /// + /// The first rectangle describes the maximum field-of-view of all image + /// formats in the 4:3 resolutions, while the second one describes the + /// maximum field of view for all image formats in the 16:9 resolutions. + /// + /// Multiple rectangles shall only be reported when the sensor can't capture + /// the pixels in the corner regions. If all the pixels in the (x1,y1) - + /// (x4,y4) area can be captured, the PixelArrayActiveAreas property shall + /// contains the single rectangle (x1,y1) - (x4,y4). + /// + /// \todo Rename this property to ActiveAreas once we will have property + /// ```text + /// categories (i.e. Properties::PixelArray::ActiveAreas) + PixelArrayActiveAreas = PIXEL_ARRAY_ACTIVE_AREAS, + /// The maximum valid rectangle for the controls::ScalerCrop control. This + /// reflects the minimum mandatory cropping applied in the camera sensor and + /// the rest of the pipeline. Just as the ScalerCrop control, it defines a + /// rectangle taken from the sensor's active pixel array. + /// + /// This property is valid only after the camera has been successfully + /// configured and its value may change whenever a new configuration is + /// applied. + /// + /// \todo Turn this property into a "maximum control value" for the + /// ScalerCrop control once "dynamic" controls have been implemented. + ScalerCropMaximum = SCALER_CROP_MAXIMUM, + /// The relative sensitivity of the chosen sensor mode. + /// + /// Some sensors have readout modes with different sensitivities. For example, + /// a binned camera mode might, with the same exposure and gains, produce + /// twice the signal level of the full resolution readout. This would be + /// signalled by the binned mode, when it is chosen, indicating a value here + /// that is twice that of the full resolution mode. This value will be valid + /// after the configure method has returned successfully. + SensorSensitivity = SENSOR_SENSITIVITY, + /// A list of integer values of type dev_t denoting the major and minor + /// device numbers of the underlying devices used in the operation of this + /// camera. + /// + /// Different cameras may report identical devices. + SystemDevices = SYSTEM_DEVICES, + /// The arrangement of color filters on sensor; represents the colors in the + /// top-left 2x2 section of the sensor, in reading order. Currently + /// identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. + #[cfg(feature = "vendor_draft")] + ColorFilterArrangement = COLOR_FILTER_ARRANGEMENT, +} +impl PropertyId { + pub fn id(&self) -> u32 { + u32::from(*self) + } + pub fn description(&self) -> &'static str { + match self { + PropertyId::Location => "Camera mounting location +", + PropertyId::Rotation => { + "The camera physical mounting rotation. It is expressed as the angular +difference in degrees between two reference systems, one relative to the +camera module, and one defined on the external world scene to be +captured when projected on the image sensor pixel array. + +A camera sensor has a 2-dimensional reference system 'Rc' defined by +its pixel array read-out order. The origin is set to the first pixel +being read out, the X-axis points along the column read-out direction +towards the last columns, and the Y-axis along the row read-out +direction towards the last row. + +A typical example for a sensor with a 2592x1944 pixel array matrix +observed from the front is + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + +The external world scene reference system 'Rs' is a 2-dimensional +reference system on the focal plane of the camera module. The origin is +placed on the top-left corner of the visible scene, the X-axis points +towards the right, and the Y-axis points towards the bottom of the +scene. The top, bottom, left and right directions are intentionally not +defined and depend on the environment in which the camera is used. + +A typical example of a (very common) picture of a shark swimming from +left to right, as seen from the camera, is + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\\____)\\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + +With the reference system 'Rs' placed on the camera focal plane. + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \\-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + +When projected on the sensor's pixel array, the image and the associated +reference system 'Rs' are typically (but not always) inverted, due to +the camera module's lens optical inversion effect. + +Assuming the above represented scene of the swimming shark, the lens +inversion projects the scene and its reference system onto the sensor +pixel array, seen from the front of the camera sensor, as follow + + Y-axis + ^ + ! + ! + ! + ! |\\_____)\\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + +Note the shark being upside-down. + +The resulting projected reference system is named 'Rp'. + +The camera rotation property is then defined as the angular difference +in the counter-clockwise direction between the camera reference system +'Rc' and the projected scene reference system 'Rp'. It is expressed in +degrees as a number in the range [0, 360[. + +Examples + +0 degrees camera rotation + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + +90 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +180 degrees camera rotation + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +270 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + +Example one - Webcam + +A camera module installed on the user facing part of a laptop screen +casing used for video calls. The captured images are meant to be +displayed in landscape mode (width > height) on the laptop screen. + +The camera is typically mounted upside-down to compensate the lens +optical inversion effect. + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + +The two reference systems are aligned, the resulting camera rotation is +0 degrees, no rotation correction needs to be applied to the resulting +image once captured to memory buffers to correctly display it to users. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +If the camera sensor is not mounted upside-down to compensate for the +lens optical inversion, the two reference systems will not be aligned, +with 'Rp' being rotated 180 degrees relatively to 'Rc'. + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\\_____)\\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + +The image once captured to memory will then be rotated by 180 degrees + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \\( \\| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +A software rotation correction of 180 degrees should be applied to +correctly display the image. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\\____)\\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + +Example two - Phone camera + +A camera installed on the back side of a mobile device facing away from +the user. The captured images are meant to be displayed in portrait mode +(height > width) to match the device screen orientation and the device +usage orientation used when taking the picture. + +The camera sensor is typically mounted with its pixel array longer side +aligned to the device longer side, upside-down mounted to compensate for +the lens optical inversion effect. + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\\_____)\\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + +The two reference systems are not aligned and the 'Rp' reference +system is rotated by 90 degrees in the counter-clockwise direction +relatively to the 'Rc' reference system. + +The image once captured to memory will be rotated. + + +-------------------------------------+ + | _ _ | + | \\ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + +A correction of 90 degrees in counter-clockwise direction has to be +applied to correctly display the image in portrait mode on the device +screen. + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\\____)\\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ +" + } + PropertyId::Model => { + "The model name shall to the extent possible describe the sensor. For +most devices this is the model name of the sensor. While for some +devices the sensor model is unavailable as the sensor or the entire +camera is part of a larger unit and exposed as a black-box to the +system. In such cases the model name of the smallest device that +contains the camera sensor shall be used. + +The model name is not meant to be a camera name displayed to the +end-user, but may be combined with other camera information to create a +camera name. + +The model name is not guaranteed to be unique in the system nor is +it guaranteed to be stable or have any other properties required to make +it a good candidate to be used as a permanent identifier of a camera. + +The model name shall describe the camera in a human readable format and +shall be encoded in ASCII. + +Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. +" + } + PropertyId::UnitCellSize => { + "The pixel unit cell physical size, in nanometers. + +The UnitCellSize properties defines the horizontal and vertical sizes of +a single pixel unit, including its active and non-active parts. In +other words, it expresses the horizontal and vertical distance between +the top-left corners of adjacent pixels. + +The property can be used to calculate the physical size of the sensor's +pixel array area and for calibration purposes. +" + } + PropertyId::PixelArraySize => { + "The camera sensor pixel array readable area vertical and horizontal +sizes, in pixels. + +The PixelArraySize property defines the size in pixel units of the +readable part of full pixel array matrix, including optical black +pixels used for calibration, pixels which are not considered valid for +capture and active pixels containing valid image data. + +The property describes the maximum size of the raw data captured by the +camera, which might not correspond to the physical size of the sensor +pixel array matrix, as some portions of the physical pixel array matrix +are not accessible and cannot be transmitted out. + +For example, let's consider a pixel array matrix assembled as follows + + +--------------------------------------------------+ + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + ... ... ... ... ... + + ... ... ... ... ... + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + +--------------------------------------------------+ + +starting with two lines of non-readable pixels (x), followed by N lines +of readable data (D) surrounded by two columns of non-readable pixels on +each side, and ending with two more lines of non-readable pixels. Only +the readable portion is transmitted to the receiving side, defining the +sizes of the largest possible buffer of raw data that can be presented +to applications. + + PixelArraySize.width + /----------------------------------------------/ + +----------------------------------------------+ / + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + ... ... ... ... ... + ... ... ... ... ... + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + +----------------------------------------------+ / + +This defines a rectangle whose top-left corner is placed in position (0, +0) and whose vertical and horizontal sizes are defined by this property. +All other rectangles that describe portions of the pixel array, such as +the optical black pixels rectangles and active pixel areas, are defined +relatively to this rectangle. + +All the coordinates are expressed relative to the default sensor readout +direction, without any transformation (such as horizontal and vertical +flipping) applied. When mapping them to the raw pixel buffer, +applications shall take any configured transformation into account. + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::Size) +" + } + PropertyId::PixelArrayOpticalBlackRectangles => { + "The pixel array region(s) which contain optical black pixels +considered valid for calibration purposes. + +This property describes the position and size of optical black pixel +regions in the raw data buffer as stored in memory, which might differ +from their actual physical location in the pixel array matrix. + +It is important to note, in fact, that camera sensors might +automatically reorder or skip portions of their pixels array matrix when +transmitting data to the receiver. For instance, a sensor may merge the +top and bottom optical black rectangles into a single rectangle, +transmitted at the beginning of the frame. + +The pixel array contains several areas with different purposes, +interleaved by lines and columns which are said not to be valid for +capturing purposes. Invalid lines and columns are defined as invalid as +they could be positioned too close to the chip margins or to the optical +black shielding placed on top of optical black pixels. + + PixelArraySize.width + /----------------------------------------------/ + x1 x2 + +--o---------------------------------------o---+ / + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + ... ... ... ... ... + ... ... ... ... ... + y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + +----------------------------------------------+ / + +The readable pixel array matrix is composed by +2 invalid lines (I) +4 lines of valid optical black pixels (O) +2 invalid lines (I) +n lines of valid pixel data (P) +2 invalid lines (I) + +And the position of the optical black pixel rectangles is defined by + + PixelArrayOpticalBlackRectangles = { + { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + { x1, y3, 2, y4 - y3 + 1 }, + { x2, y3, 2, y4 - y3 + 1 }, + }; + +If the camera, when capturing the full pixel array matrix, automatically +skips the invalid lines and columns, producing the following data +buffer, when captured to memory + + PixelArraySize.width + /----------------------------------------------/ + x1 + +--------------------------------------------o-+ / + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + ... ... ... ... ... | + ... ... ... ... ... | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + +----------------------------------------------+ / + +then the invalid lines and columns should not be reported as part of the +PixelArraySize property in first place. + +In this case, the position of the black pixel rectangles will be + + PixelArrayOpticalBlackRectangles = { + { 0, 0, y1 + 1, PixelArraySize[0] }, + { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + }; + +\\todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::OpticalBlackRectangles) +" + } + PropertyId::PixelArrayActiveAreas => { + "The PixelArrayActiveAreas property defines the (possibly multiple and +overlapping) portions of the camera sensor readable pixel matrix +which are considered valid for image acquisition purposes. + +This property describes an arbitrary number of overlapping rectangles, +with each rectangle representing the maximum image size that the camera +sensor can produce for a particular aspect ratio. They are defined +relatively to the PixelArraySize rectangle. + +When multiple rectangles are reported, they shall be ordered from the +tallest to the shortest. + +Example 1 +A camera sensor which only produces images in the 4:3 image resolution +will report a single PixelArrayActiveAreas rectangle, from which all +other image formats are obtained by either cropping the field-of-view +and/or applying pixel sub-sampling techniques such as pixel skipping or +binning. + + PixelArraySize.width + /----------------/ + x1 x2 + (0,0)-> +-o------------o-+ / + y1 o +------------+ | | + | |////////////| | | + | |////////////| | | PixelArraySize.height + | |////////////| | | + y2 o +------------+ | | + +----------------+ / + +The property reports a single rectangle + + PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + +Example 2 +A camera sensor which can produce images in different native +resolutions will report several overlapping rectangles, one for each +natively supported resolution. + + PixelArraySize.width + /------------------/ + x1 x2 x3 x4 + (0,0)-> +o---o------o---o+ / + y1 o +------+ | | + | |//////| | | + y2 o+---+------+---+| | + ||///|//////|///|| | PixelArraySize.height + y3 o+---+------+---+| | + | |//////| | | + y4 o +------+ | | + +----+------+----+ / + +The property reports two rectangles + + PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + +The first rectangle describes the maximum field-of-view of all image +formats in the 4:3 resolutions, while the second one describes the +maximum field of view for all image formats in the 16:9 resolutions. + +Multiple rectangles shall only be reported when the sensor can't capture +the pixels in the corner regions. If all the pixels in the (x1,y1) - +(x4,y4) area can be captured, the PixelArrayActiveAreas property shall +contains the single rectangle (x1,y1) - (x4,y4). + +\\todo Rename this property to ActiveAreas once we will have property + categories (i.e. Properties::PixelArray::ActiveAreas) +" + } + PropertyId::ScalerCropMaximum => { + "The maximum valid rectangle for the controls::ScalerCrop control. This +reflects the minimum mandatory cropping applied in the camera sensor and +the rest of the pipeline. Just as the ScalerCrop control, it defines a +rectangle taken from the sensor's active pixel array. + +This property is valid only after the camera has been successfully +configured and its value may change whenever a new configuration is +applied. + +\\todo Turn this property into a \"maximum control value\" for the +ScalerCrop control once \"dynamic\" controls have been implemented. +" + } + PropertyId::SensorSensitivity => { + "The relative sensitivity of the chosen sensor mode. + +Some sensors have readout modes with different sensitivities. For example, +a binned camera mode might, with the same exposure and gains, produce +twice the signal level of the full resolution readout. This would be +signalled by the binned mode, when it is chosen, indicating a value here +that is twice that of the full resolution mode. This value will be valid +after the configure method has returned successfully. +" + } + PropertyId::SystemDevices => { + "A list of integer values of type dev_t denoting the major and minor +device numbers of the underlying devices used in the operation of this +camera. + +Different cameras may report identical devices. +" + } + #[cfg(feature = "vendor_draft")] + PropertyId::ColorFilterArrangement => { + "The arrangement of color filters on sensor; represents the colors in the +top-left 2x2 section of the sensor, in reading order. Currently +identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. +" + } + } + } +} +/// Camera mounting location +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum Location { + /// The camera is mounted on the front side of the device, facing the + /// user + CameraFront = 0, + /// The camera is mounted on the back side of the device, facing away + /// from the user + CameraBack = 1, + /// The camera is attached to the device in a way that allows it to + /// be moved freely + CameraExternal = 2, +} +impl TryFrom for Location { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +impl From for ControlValue { + fn from(val: Location) -> Self { + ControlValue::from(::from(val)) + } +} +impl ControlEntry for Location { + const ID: u32 = PropertyId::Location as _; +} +impl Property for Location {} +/// The camera physical mounting rotation. It is expressed as the angular +/// difference in degrees between two reference systems, one relative to the +/// camera module, and one defined on the external world scene to be +/// captured when projected on the image sensor pixel array. +/// +/// A camera sensor has a 2-dimensional reference system 'Rc' defined by +/// its pixel array read-out order. The origin is set to the first pixel +/// being read out, the X-axis points along the column read-out direction +/// towards the last columns, and the Y-axis along the row read-out +/// direction towards the last row. +/// +/// A typical example for a sensor with a 2592x1944 pixel array matrix +/// observed from the front is +/// +/// ```text +/// 2591 X-axis 0 +/// <------------------------+ 0 +/// .......... ... ..........! +/// .......... ... ..........! Y-axis +/// ... ! +/// .......... ... ..........! +/// .......... ... ..........! 1943 +/// V +/// ``` +/// +/// +/// The external world scene reference system 'Rs' is a 2-dimensional +/// reference system on the focal plane of the camera module. The origin is +/// placed on the top-left corner of the visible scene, the X-axis points +/// towards the right, and the Y-axis points towards the bottom of the +/// scene. The top, bottom, left and right directions are intentionally not +/// defined and depend on the environment in which the camera is used. +/// +/// A typical example of a (very common) picture of a shark swimming from +/// left to right, as seen from the camera, is +/// +/// ```text +/// 0 X-axis +/// 0 +-------------------------------------> +/// ! +/// ! +/// ! +/// ! |\____)\___ +/// ! ) _____ __`< +/// ! |/ )/ +/// ! +/// ! +/// ! +/// V +/// Y-axis +/// ``` +/// +/// With the reference system 'Rs' placed on the camera focal plane. +/// +/// ```text +/// ¸.·˙! +/// ¸.·˙ ! +/// _ ¸.·˙ ! +/// +-/ \-+¸.·˙ ! +/// | (o) | ! Camera focal plane +/// +-----+˙·.¸ ! +/// ˙·.¸ ! +/// ˙·.¸ ! +/// ˙·.¸! +/// ``` +/// +/// When projected on the sensor's pixel array, the image and the associated +/// reference system 'Rs' are typically (but not always) inverted, due to +/// the camera module's lens optical inversion effect. +/// +/// Assuming the above represented scene of the swimming shark, the lens +/// inversion projects the scene and its reference system onto the sensor +/// pixel array, seen from the front of the camera sensor, as follow +/// +/// ```text +/// Y-axis +/// ^ +/// ! +/// ! +/// ! +/// ! |\_____)\__ +/// ! ) ____ ___.< +/// ! |/ )/ +/// ! +/// ! +/// ! +/// 0 +-------------------------------------> +/// 0 X-axis +/// ``` +/// +/// Note the shark being upside-down. +/// +/// The resulting projected reference system is named 'Rp'. +/// +/// The camera rotation property is then defined as the angular difference +/// in the counter-clockwise direction between the camera reference system +/// 'Rc' and the projected scene reference system 'Rp'. It is expressed in +/// degrees as a number in the range [0, 360[. +/// +/// Examples +/// +/// 0 degrees camera rotation +/// +/// +/// ```text +/// Y-Rp +/// ^ +/// Y-Rc ! +/// ^ ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// 0 +-------------------------------------> +/// 0 X-Rc +/// ``` +/// +/// +/// ```text +/// X-Rc 0 +/// <------------------------------------+ 0 +/// X-Rp 0 ! +/// <------------------------------------+ 0 ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rc +/// V +/// Y-Rp +/// ``` +/// +/// 90 degrees camera rotation +/// +/// ```text +/// 0 Y-Rc +/// 0 +--------------------> +/// ! Y-Rp +/// ! ^ +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// ! +/// ! +/// ! +/// ! +/// V +/// X-Rc +/// ``` +/// +/// 180 degrees camera rotation +/// +/// ```text +/// 0 +/// <------------------------------------+ 0 +/// X-Rc ! +/// Y-Rp ! +/// ^ ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rc +/// 0 +-------------------------------------> +/// 0 X-Rp +/// ``` +/// +/// 270 degrees camera rotation +/// +/// ```text +/// 0 Y-Rc +/// 0 +--------------------> +/// ! 0 +/// ! <-----------------------------------+ 0 +/// ! X-Rp ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rp +/// ! +/// ! +/// ! +/// ! +/// V +/// X-Rc +/// ``` +/// +/// +/// Example one - Webcam +/// +/// A camera module installed on the user facing part of a laptop screen +/// casing used for video calls. The captured images are meant to be +/// displayed in landscape mode (width > height) on the laptop screen. +/// +/// The camera is typically mounted upside-down to compensate the lens +/// optical inversion effect. +/// +/// ```text +/// Y-Rp +/// Y-Rc ^ +/// ^ ! +/// ! ! +/// ! ! |\_____)\__ +/// ! ! ) ____ ___.< +/// ! ! |/ )/ +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// 0 +-------------------------------------> +/// 0 X-Rc +/// ``` +/// +/// The two reference systems are aligned, the resulting camera rotation is +/// 0 degrees, no rotation correction needs to be applied to the resulting +/// image once captured to memory buffers to correctly display it to users. +/// +/// ```text +/// +--------------------------------------+ +/// ! ! +/// ! ! +/// ! ! +/// ! |\____)\___ ! +/// ! ) _____ __`< ! +/// ! |/ )/ ! +/// ! ! +/// ! ! +/// ! ! +/// +--------------------------------------+ +/// ``` +/// +/// If the camera sensor is not mounted upside-down to compensate for the +/// lens optical inversion, the two reference systems will not be aligned, +/// with 'Rp' being rotated 180 degrees relatively to 'Rc'. +/// +/// +/// ```text +/// X-Rc 0 +/// <------------------------------------+ 0 +/// ! +/// Y-Rp ! +/// ^ ! +/// ! ! +/// ! |\_____)\__ ! +/// ! ) ____ ___.< ! +/// ! |/ )/ ! +/// ! ! +/// ! ! +/// ! V +/// ! Y-Rc +/// 0 +-------------------------------------> +/// 0 X-Rp +/// ``` +/// +/// The image once captured to memory will then be rotated by 180 degrees +/// +/// ```text +/// +--------------------------------------+ +/// ! ! +/// ! ! +/// ! ! +/// ! __/(_____/| ! +/// ! >.___ ____ ( ! +/// ! \( \| ! +/// ! ! +/// ! ! +/// ! ! +/// +--------------------------------------+ +/// ``` +/// +/// A software rotation correction of 180 degrees should be applied to +/// correctly display the image. +/// +/// ```text +/// +--------------------------------------+ +/// ! ! +/// ! ! +/// ! ! +/// ! |\____)\___ ! +/// ! ) _____ __`< ! +/// ! |/ )/ ! +/// ! ! +/// ! ! +/// ! ! +/// +--------------------------------------+ +/// ``` +/// +/// Example two - Phone camera +/// +/// A camera installed on the back side of a mobile device facing away from +/// the user. The captured images are meant to be displayed in portrait mode +/// (height > width) to match the device screen orientation and the device +/// usage orientation used when taking the picture. +/// +/// The camera sensor is typically mounted with its pixel array longer side +/// aligned to the device longer side, upside-down mounted to compensate for +/// the lens optical inversion effect. +/// +/// ```text +/// 0 Y-Rc +/// 0 +--------------------> +/// ! Y-Rp +/// ! ^ +/// ! ! +/// ! ! +/// ! ! +/// ! ! |\_____)\__ +/// ! ! ) ____ ___.< +/// ! ! |/ )/ +/// ! ! +/// ! ! +/// ! ! +/// ! 0 +-------------------------------------> +/// ! 0 X-Rp +/// ! +/// ! +/// ! +/// ! +/// V +/// X-Rc +/// ``` +/// +/// The two reference systems are not aligned and the 'Rp' reference +/// system is rotated by 90 degrees in the counter-clockwise direction +/// relatively to the 'Rc' reference system. +/// +/// The image once captured to memory will be rotated. +/// +/// ```text +/// +-------------------------------------+ +/// | _ _ | +/// | \ / | +/// | | | | +/// | | | | +/// | | > | +/// | < | | +/// | | | | +/// | . | +/// | V | +/// +-------------------------------------+ +/// ``` +/// +/// A correction of 90 degrees in counter-clockwise direction has to be +/// applied to correctly display the image in portrait mode on the device +/// screen. +/// +/// ```text +/// +--------------------+ +/// | | +/// | | +/// | | +/// | | +/// | | +/// | | +/// | |\____)\___ | +/// | ) _____ __`< | +/// | |/ )/ | +/// | | +/// | | +/// | | +/// | | +/// | | +/// +--------------------+ +#[derive(Debug, Clone)] +pub struct Rotation(pub i32); +impl Deref for Rotation { + type Target = i32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Rotation { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Rotation { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Rotation) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Rotation { + const ID: u32 = PropertyId::Rotation as _; +} +impl Property for Rotation {} +/// The model name shall to the extent possible describe the sensor. For +/// most devices this is the model name of the sensor. While for some +/// devices the sensor model is unavailable as the sensor or the entire +/// camera is part of a larger unit and exposed as a black-box to the +/// system. In such cases the model name of the smallest device that +/// contains the camera sensor shall be used. +/// +/// The model name is not meant to be a camera name displayed to the +/// end-user, but may be combined with other camera information to create a +/// camera name. +/// +/// The model name is not guaranteed to be unique in the system nor is +/// it guaranteed to be stable or have any other properties required to make +/// it a good candidate to be used as a permanent identifier of a camera. +/// +/// The model name shall describe the camera in a human readable format and +/// shall be encoded in ASCII. +/// +/// Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. +#[derive(Debug, Clone)] +pub struct Model(pub String); +impl Deref for Model { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for Model { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for Model { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: Model) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for Model { + const ID: u32 = PropertyId::Model as _; +} +impl Property for Model {} +/// The pixel unit cell physical size, in nanometers. +/// +/// The UnitCellSize properties defines the horizontal and vertical sizes of +/// a single pixel unit, including its active and non-active parts. In +/// other words, it expresses the horizontal and vertical distance between +/// the top-left corners of adjacent pixels. +/// +/// The property can be used to calculate the physical size of the sensor's +/// pixel array area and for calibration purposes. +#[derive(Debug, Clone)] +pub struct UnitCellSize(pub Size); +impl Deref for UnitCellSize { + type Target = Size; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for UnitCellSize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for UnitCellSize { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: UnitCellSize) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for UnitCellSize { + const ID: u32 = PropertyId::UnitCellSize as _; +} +impl Property for UnitCellSize {} +/// The camera sensor pixel array readable area vertical and horizontal +/// sizes, in pixels. +/// +/// The PixelArraySize property defines the size in pixel units of the +/// readable part of full pixel array matrix, including optical black +/// pixels used for calibration, pixels which are not considered valid for +/// capture and active pixels containing valid image data. +/// +/// The property describes the maximum size of the raw data captured by the +/// camera, which might not correspond to the physical size of the sensor +/// pixel array matrix, as some portions of the physical pixel array matrix +/// are not accessible and cannot be transmitted out. +/// +/// For example, let's consider a pixel array matrix assembled as follows +/// +/// ```text +/// +--------------------------------------------------+ +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// ... ... ... ... ... +/// ``` +/// +/// ```text +/// ... ... ... ... ... +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| +/// +--------------------------------------------------+ +/// ``` +/// +/// starting with two lines of non-readable pixels (x), followed by N lines +/// of readable data (D) surrounded by two columns of non-readable pixels on +/// each side, and ending with two more lines of non-readable pixels. Only +/// the readable portion is transmitted to the receiving side, defining the +/// sizes of the largest possible buffer of raw data that can be presented +/// to applications. +/// +/// ```text +/// PixelArraySize.width +/// /----------------------------------------------/ +/// +----------------------------------------------+ / +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height +/// ... ... ... ... ... +/// ... ... ... ... ... +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | +/// +----------------------------------------------+ / +/// ``` +/// +/// This defines a rectangle whose top-left corner is placed in position (0, +/// 0) and whose vertical and horizontal sizes are defined by this property. +/// All other rectangles that describe portions of the pixel array, such as +/// the optical black pixels rectangles and active pixel areas, are defined +/// relatively to this rectangle. +/// +/// All the coordinates are expressed relative to the default sensor readout +/// direction, without any transformation (such as horizontal and vertical +/// flipping) applied. When mapping them to the raw pixel buffer, +/// applications shall take any configured transformation into account. +/// +/// \todo Rename this property to Size once we will have property +/// ```text +/// categories (i.e. Properties::PixelArray::Size) +#[derive(Debug, Clone)] +pub struct PixelArraySize(pub Size); +impl Deref for PixelArraySize { + type Target = Size; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for PixelArraySize { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for PixelArraySize { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: PixelArraySize) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for PixelArraySize { + const ID: u32 = PropertyId::PixelArraySize as _; +} +impl Property for PixelArraySize {} +/// The pixel array region(s) which contain optical black pixels +/// considered valid for calibration purposes. +/// +/// This property describes the position and size of optical black pixel +/// regions in the raw data buffer as stored in memory, which might differ +/// from their actual physical location in the pixel array matrix. +/// +/// It is important to note, in fact, that camera sensors might +/// automatically reorder or skip portions of their pixels array matrix when +/// transmitting data to the receiver. For instance, a sensor may merge the +/// top and bottom optical black rectangles into a single rectangle, +/// transmitted at the beginning of the frame. +/// +/// The pixel array contains several areas with different purposes, +/// interleaved by lines and columns which are said not to be valid for +/// capturing purposes. Invalid lines and columns are defined as invalid as +/// they could be positioned too close to the chip margins or to the optical +/// black shielding placed on top of optical black pixels. +/// +/// ```text +/// PixelArraySize.width +/// /----------------------------------------------/ +/// x1 x2 +/// +--o---------------------------------------o---+ / +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | +/// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height +/// |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | +/// ... ... ... ... ... +/// ... ... ... ... ... +/// y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | +/// +----------------------------------------------+ / +/// ``` +/// +/// The readable pixel array matrix is composed by +/// 2 invalid lines (I) +/// 4 lines of valid optical black pixels (O) +/// 2 invalid lines (I) +/// n lines of valid pixel data (P) +/// 2 invalid lines (I) +/// +/// And the position of the optical black pixel rectangles is defined by +/// +/// ```text +/// PixelArrayOpticalBlackRectangles = { +/// { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, +/// { x1, y3, 2, y4 - y3 + 1 }, +/// { x2, y3, 2, y4 - y3 + 1 }, +/// }; +/// ``` +/// +/// If the camera, when capturing the full pixel array matrix, automatically +/// skips the invalid lines and columns, producing the following data +/// buffer, when captured to memory +/// +/// ```text +/// PixelArraySize.width +/// /----------------------------------------------/ +/// x1 +/// +--------------------------------------------o-+ / +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | +/// y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height +/// ... ... ... ... ... | +/// ... ... ... ... ... | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | +/// +----------------------------------------------+ / +/// ``` +/// +/// then the invalid lines and columns should not be reported as part of the +/// PixelArraySize property in first place. +/// +/// In this case, the position of the black pixel rectangles will be +/// +/// ```text +/// PixelArrayOpticalBlackRectangles = { +/// { 0, 0, y1 + 1, PixelArraySize[0] }, +/// { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, +/// { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, +/// }; +/// ``` +/// +/// \todo Rename this property to Size once we will have property +/// ```text +/// categories (i.e. Properties::PixelArray::OpticalBlackRectangles) +#[derive(Debug, Clone)] +pub struct PixelArrayOpticalBlackRectangles(pub Vec); +impl Deref for PixelArrayOpticalBlackRectangles { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for PixelArrayOpticalBlackRectangles { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for PixelArrayOpticalBlackRectangles { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: PixelArrayOpticalBlackRectangles) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for PixelArrayOpticalBlackRectangles { + const ID: u32 = PropertyId::PixelArrayOpticalBlackRectangles as _; +} +impl Property for PixelArrayOpticalBlackRectangles {} +/// The PixelArrayActiveAreas property defines the (possibly multiple and +/// overlapping) portions of the camera sensor readable pixel matrix +/// which are considered valid for image acquisition purposes. +/// +/// This property describes an arbitrary number of overlapping rectangles, +/// with each rectangle representing the maximum image size that the camera +/// sensor can produce for a particular aspect ratio. They are defined +/// relatively to the PixelArraySize rectangle. +/// +/// When multiple rectangles are reported, they shall be ordered from the +/// tallest to the shortest. +/// +/// Example 1 +/// A camera sensor which only produces images in the 4:3 image resolution +/// will report a single PixelArrayActiveAreas rectangle, from which all +/// other image formats are obtained by either cropping the field-of-view +/// and/or applying pixel sub-sampling techniques such as pixel skipping or +/// binning. +/// +/// ```text +/// PixelArraySize.width +/// /----------------/ +/// x1 x2 +/// (0,0)-> +-o------------o-+ / +/// y1 o +------------+ | | +/// | |////////////| | | +/// | |////////////| | | PixelArraySize.height +/// | |////////////| | | +/// y2 o +------------+ | | +/// +----------------+ / +/// ``` +/// +/// The property reports a single rectangle +/// +/// ```text +/// PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) +/// ``` +/// +/// Example 2 +/// A camera sensor which can produce images in different native +/// resolutions will report several overlapping rectangles, one for each +/// natively supported resolution. +/// +/// ```text +/// PixelArraySize.width +/// /------------------/ +/// x1 x2 x3 x4 +/// (0,0)-> +o---o------o---o+ / +/// y1 o +------+ | | +/// | |//////| | | +/// y2 o+---+------+---+| | +/// ||///|//////|///|| | PixelArraySize.height +/// y3 o+---+------+---+| | +/// | |//////| | | +/// y4 o +------+ | | +/// +----+------+----+ / +/// ``` +/// +/// The property reports two rectangles +/// +/// ```text +/// PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), +/// (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) +/// ``` +/// +/// The first rectangle describes the maximum field-of-view of all image +/// formats in the 4:3 resolutions, while the second one describes the +/// maximum field of view for all image formats in the 16:9 resolutions. +/// +/// Multiple rectangles shall only be reported when the sensor can't capture +/// the pixels in the corner regions. If all the pixels in the (x1,y1) - +/// (x4,y4) area can be captured, the PixelArrayActiveAreas property shall +/// contains the single rectangle (x1,y1) - (x4,y4). +/// +/// \todo Rename this property to ActiveAreas once we will have property +/// ```text +/// categories (i.e. Properties::PixelArray::ActiveAreas) +#[derive(Debug, Clone)] +pub struct PixelArrayActiveAreas(pub Vec); +impl Deref for PixelArrayActiveAreas { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for PixelArrayActiveAreas { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for PixelArrayActiveAreas { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: PixelArrayActiveAreas) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for PixelArrayActiveAreas { + const ID: u32 = PropertyId::PixelArrayActiveAreas as _; +} +impl Property for PixelArrayActiveAreas {} +/// The maximum valid rectangle for the controls::ScalerCrop control. This +/// reflects the minimum mandatory cropping applied in the camera sensor and +/// the rest of the pipeline. Just as the ScalerCrop control, it defines a +/// rectangle taken from the sensor's active pixel array. +/// +/// This property is valid only after the camera has been successfully +/// configured and its value may change whenever a new configuration is +/// applied. +/// +/// \todo Turn this property into a "maximum control value" for the +/// ScalerCrop control once "dynamic" controls have been implemented. +#[derive(Debug, Clone)] +pub struct ScalerCropMaximum(pub Rectangle); +impl Deref for ScalerCropMaximum { + type Target = Rectangle; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for ScalerCropMaximum { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for ScalerCropMaximum { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: ScalerCropMaximum) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for ScalerCropMaximum { + const ID: u32 = PropertyId::ScalerCropMaximum as _; +} +impl Property for ScalerCropMaximum {} +/// The relative sensitivity of the chosen sensor mode. +/// +/// Some sensors have readout modes with different sensitivities. For example, +/// a binned camera mode might, with the same exposure and gains, produce +/// twice the signal level of the full resolution readout. This would be +/// signalled by the binned mode, when it is chosen, indicating a value here +/// that is twice that of the full resolution mode. This value will be valid +/// after the configure method has returned successfully. +#[derive(Debug, Clone)] +pub struct SensorSensitivity(pub f32); +impl Deref for SensorSensitivity { + type Target = f32; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SensorSensitivity { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SensorSensitivity { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SensorSensitivity) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SensorSensitivity { + const ID: u32 = PropertyId::SensorSensitivity as _; +} +impl Property for SensorSensitivity {} +/// A list of integer values of type dev_t denoting the major and minor +/// device numbers of the underlying devices used in the operation of this +/// camera. +/// +/// Different cameras may report identical devices. +#[derive(Debug, Clone)] +pub struct SystemDevices(pub Vec); +impl Deref for SystemDevices { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl DerefMut for SystemDevices { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +impl TryFrom for SystemDevices { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Ok(Self(>::try_from(value)?)) + } +} +impl From for ControlValue { + fn from(val: SystemDevices) -> Self { + ControlValue::from(val.0) + } +} +impl ControlEntry for SystemDevices { + const ID: u32 = PropertyId::SystemDevices as _; +} +impl Property for SystemDevices {} +/// The arrangement of color filters on sensor; represents the colors in the +/// top-left 2x2 section of the sensor, in reading order. Currently +/// identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. +#[cfg(feature = "vendor_draft")] +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(i32)] +pub enum ColorFilterArrangement { + /// RGGB Bayer pattern + RGGB = 0, + /// GRBG Bayer pattern + GRBG = 1, + /// GBRG Bayer pattern + GBRG = 2, + /// BGGR Bayer pattern + BGGR = 3, + /// Sensor is not Bayer; output has 3 16-bit values for each pixel, + /// instead of just 1 16-bit value per pixel. + RGB = 4, + /// Sensor is not Bayer; output consists of a single colour channel. + MONO = 5, +} +#[cfg(feature = "vendor_draft")] +impl TryFrom for ColorFilterArrangement { + type Error = ControlValueError; + fn try_from(value: ControlValue) -> Result { + Self::try_from(i32::try_from(value.clone())?) + .map_err(|_| ControlValueError::UnknownVariant(value)) + } +} +#[cfg(feature = "vendor_draft")] +impl From for ControlValue { + fn from(val: ColorFilterArrangement) -> Self { + ControlValue::from(::from(val)) + } +} +#[cfg(feature = "vendor_draft")] +impl ControlEntry for ColorFilterArrangement { + const ID: u32 = PropertyId::ColorFilterArrangement as _; +} +#[cfg(feature = "vendor_draft")] +impl Property for ColorFilterArrangement {} +pub fn make_dyn( + id: PropertyId, + val: ControlValue, +) -> Result, ControlValueError> { + match id { + PropertyId::Location => Ok(Box::new(Location::try_from(val)?)), + PropertyId::Rotation => Ok(Box::new(Rotation::try_from(val)?)), + PropertyId::Model => Ok(Box::new(Model::try_from(val)?)), + PropertyId::UnitCellSize => Ok(Box::new(UnitCellSize::try_from(val)?)), + PropertyId::PixelArraySize => Ok(Box::new(PixelArraySize::try_from(val)?)), + PropertyId::PixelArrayOpticalBlackRectangles => { + Ok(Box::new(PixelArrayOpticalBlackRectangles::try_from(val)?)) + } + PropertyId::PixelArrayActiveAreas => { + Ok(Box::new(PixelArrayActiveAreas::try_from(val)?)) + } + PropertyId::ScalerCropMaximum => Ok(Box::new(ScalerCropMaximum::try_from(val)?)), + PropertyId::SensorSensitivity => Ok(Box::new(SensorSensitivity::try_from(val)?)), + PropertyId::SystemDevices => Ok(Box::new(SystemDevices::try_from(val)?)), + #[cfg(feature = "vendor_draft")] + PropertyId::ColorFilterArrangement => { + Ok(Box::new(ColorFilterArrangement::try_from(val)?)) + } + } +} diff --git a/libcamera/versioned_files/0.6.0/property_ids_core.yaml b/libcamera/versioned_files/0.6.0/property_ids_core.yaml new file mode 100644 index 0000000..834454a --- /dev/null +++ b/libcamera/versioned_files/0.6.0/property_ids_core.yaml @@ -0,0 +1,704 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +vendor: libcamera +controls: + - Location: + type: int32_t + description: | + Camera mounting location + enum: + - name: CameraLocationFront + value: 0 + description: | + The camera is mounted on the front side of the device, facing the + user + - name: CameraLocationBack + value: 1 + description: | + The camera is mounted on the back side of the device, facing away + from the user + - name: CameraLocationExternal + value: 2 + description: | + The camera is attached to the device in a way that allows it to + be moved freely + + - Rotation: + type: int32_t + description: | + The camera physical mounting rotation. It is expressed as the angular + difference in degrees between two reference systems, one relative to the + camera module, and one defined on the external world scene to be + captured when projected on the image sensor pixel array. + + A camera sensor has a 2-dimensional reference system 'Rc' defined by + its pixel array read-out order. The origin is set to the first pixel + being read out, the X-axis points along the column read-out direction + towards the last columns, and the Y-axis along the row read-out + direction towards the last row. + + A typical example for a sensor with a 2592x1944 pixel array matrix + observed from the front is + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + + The external world scene reference system 'Rs' is a 2-dimensional + reference system on the focal plane of the camera module. The origin is + placed on the top-left corner of the visible scene, the X-axis points + towards the right, and the Y-axis points towards the bottom of the + scene. The top, bottom, left and right directions are intentionally not + defined and depend on the environment in which the camera is used. + + A typical example of a (very common) picture of a shark swimming from + left to right, as seen from the camera, is + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\____)\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + + With the reference system 'Rs' placed on the camera focal plane. + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + + When projected on the sensor's pixel array, the image and the associated + reference system 'Rs' are typically (but not always) inverted, due to + the camera module's lens optical inversion effect. + + Assuming the above represented scene of the swimming shark, the lens + inversion projects the scene and its reference system onto the sensor + pixel array, seen from the front of the camera sensor, as follow + + Y-axis + ^ + ! + ! + ! + ! |\_____)\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + + Note the shark being upside-down. + + The resulting projected reference system is named 'Rp'. + + The camera rotation property is then defined as the angular difference + in the counter-clockwise direction between the camera reference system + 'Rc' and the projected scene reference system 'Rp'. It is expressed in + degrees as a number in the range [0, 360[. + + Examples + + 0 degrees camera rotation + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + + 90 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + + 180 degrees camera rotation + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + + 270 degrees camera rotation + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + + Example one - Webcam + + A camera module installed on the user facing part of a laptop screen + casing used for video calls. The captured images are meant to be + displayed in landscape mode (width > height) on the laptop screen. + + The camera is typically mounted upside-down to compensate the lens + optical inversion effect. + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\_____)\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + The two reference systems are aligned, the resulting camera rotation is + 0 degrees, no rotation correction needs to be applied to the resulting + image once captured to memory buffers to correctly display it to users. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\____)\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + If the camera sensor is not mounted upside-down to compensate for the + lens optical inversion, the two reference systems will not be aligned, + with 'Rp' being rotated 180 degrees relatively to 'Rc'. + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\_____)\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + + The image once captured to memory will then be rotated by 180 degrees + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \( \| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + A software rotation correction of 180 degrees should be applied to + correctly display the image. + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\____)\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + Example two - Phone camera + + A camera installed on the back side of a mobile device facing away from + the user. The captured images are meant to be displayed in portrait mode + (height > width) to match the device screen orientation and the device + usage orientation used when taking the picture. + + The camera sensor is typically mounted with its pixel array longer side + aligned to the device longer side, upside-down mounted to compensate for + the lens optical inversion effect. + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\_____)\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + + The two reference systems are not aligned and the 'Rp' reference + system is rotated by 90 degrees in the counter-clockwise direction + relatively to the 'Rc' reference system. + + The image once captured to memory will be rotated. + + +-------------------------------------+ + | _ _ | + | \ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + + A correction of 90 degrees in counter-clockwise direction has to be + applied to correctly display the image in portrait mode on the device + screen. + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\____)\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ + + - Model: + type: string + description: | + The model name shall to the extent possible describe the sensor. For + most devices this is the model name of the sensor. While for some + devices the sensor model is unavailable as the sensor or the entire + camera is part of a larger unit and exposed as a black-box to the + system. In such cases the model name of the smallest device that + contains the camera sensor shall be used. + + The model name is not meant to be a camera name displayed to the + end-user, but may be combined with other camera information to create a + camera name. + + The model name is not guaranteed to be unique in the system nor is + it guaranteed to be stable or have any other properties required to make + it a good candidate to be used as a permanent identifier of a camera. + + The model name shall describe the camera in a human readable format and + shall be encoded in ASCII. + + Example model names are 'ov5670', 'imx219' or 'Logitech Webcam C930e'. + + - UnitCellSize: + type: Size + description: | + The pixel unit cell physical size, in nanometers. + + The UnitCellSize properties defines the horizontal and vertical sizes of + a single pixel unit, including its active and non-active parts. In + other words, it expresses the horizontal and vertical distance between + the top-left corners of adjacent pixels. + + The property can be used to calculate the physical size of the sensor's + pixel array area and for calibration purposes. + + - PixelArraySize: + type: Size + description: | + The camera sensor pixel array readable area vertical and horizontal + sizes, in pixels. + + The PixelArraySize property defines the size in pixel units of the + readable part of full pixel array matrix, including optical black + pixels used for calibration, pixels which are not considered valid for + capture and active pixels containing valid image data. + + The property describes the maximum size of the raw data captured by the + camera, which might not correspond to the physical size of the sensor + pixel array matrix, as some portions of the physical pixel array matrix + are not accessible and cannot be transmitted out. + + For example, let's consider a pixel array matrix assembled as follows + + +--------------------------------------------------+ + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + ... ... ... ... ... + + ... ... ... ... ... + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + |xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| + +--------------------------------------------------+ + + starting with two lines of non-readable pixels (x), followed by N lines + of readable data (D) surrounded by two columns of non-readable pixels on + each side, and ending with two more lines of non-readable pixels. Only + the readable portion is transmitted to the receiving side, defining the + sizes of the largest possible buffer of raw data that can be presented + to applications. + + PixelArraySize.width + /----------------------------------------------/ + +----------------------------------------------+ / + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | PixelArraySize.height + ... ... ... ... ... + ... ... ... ... ... + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + |DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD| | + +----------------------------------------------+ / + + This defines a rectangle whose top-left corner is placed in position (0, + 0) and whose vertical and horizontal sizes are defined by this property. + All other rectangles that describe portions of the pixel array, such as + the optical black pixels rectangles and active pixel areas, are defined + relatively to this rectangle. + + All the coordinates are expressed relative to the default sensor readout + direction, without any transformation (such as horizontal and vertical + flipping) applied. When mapping them to the raw pixel buffer, + applications shall take any configured transformation into account. + + \todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::Size) + + - PixelArrayOpticalBlackRectangles: + type: Rectangle + size: [n] + description: | + The pixel array region(s) which contain optical black pixels + considered valid for calibration purposes. + + This property describes the position and size of optical black pixel + regions in the raw data buffer as stored in memory, which might differ + from their actual physical location in the pixel array matrix. + + It is important to note, in fact, that camera sensors might + automatically reorder or skip portions of their pixels array matrix when + transmitting data to the receiver. For instance, a sensor may merge the + top and bottom optical black rectangles into a single rectangle, + transmitted at the beginning of the frame. + + The pixel array contains several areas with different purposes, + interleaved by lines and columns which are said not to be valid for + capturing purposes. Invalid lines and columns are defined as invalid as + they could be positioned too close to the chip margins or to the optical + black shielding placed on top of optical black pixels. + + PixelArraySize.width + /----------------------------------------------/ + x1 x2 + +--o---------------------------------------o---+ / + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y1 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + y2 oIIOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + y3 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | PixelArraySize.height + |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + ... ... ... ... ... + ... ... ... ... ... + y4 |IIOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOOII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + |IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII| | + +----------------------------------------------+ / + + The readable pixel array matrix is composed by + 2 invalid lines (I) + 4 lines of valid optical black pixels (O) + 2 invalid lines (I) + n lines of valid pixel data (P) + 2 invalid lines (I) + + And the position of the optical black pixel rectangles is defined by + + PixelArrayOpticalBlackRectangles = { + { x1, y1, x2 - x1 + 1, y2 - y1 + 1 }, + { x1, y3, 2, y4 - y3 + 1 }, + { x2, y3, 2, y4 - y3 + 1 }, + }; + + If the camera, when capturing the full pixel array matrix, automatically + skips the invalid lines and columns, producing the following data + buffer, when captured to memory + + PixelArraySize.width + /----------------------------------------------/ + x1 + +--------------------------------------------o-+ / + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + |OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO| | + y1 oOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | PixelArraySize.height + ... ... ... ... ... | + ... ... ... ... ... | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + |OOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOO| | + +----------------------------------------------+ / + + then the invalid lines and columns should not be reported as part of the + PixelArraySize property in first place. + + In this case, the position of the black pixel rectangles will be + + PixelArrayOpticalBlackRectangles = { + { 0, 0, y1 + 1, PixelArraySize[0] }, + { 0, y1, 2, PixelArraySize[1] - y1 + 1 }, + { x1, y1, 2, PixelArraySize[1] - y1 + 1 }, + }; + + \todo Rename this property to Size once we will have property + categories (i.e. Properties::PixelArray::OpticalBlackRectangles) + + - PixelArrayActiveAreas: + type: Rectangle + size: [n] + description: | + The PixelArrayActiveAreas property defines the (possibly multiple and + overlapping) portions of the camera sensor readable pixel matrix + which are considered valid for image acquisition purposes. + + This property describes an arbitrary number of overlapping rectangles, + with each rectangle representing the maximum image size that the camera + sensor can produce for a particular aspect ratio. They are defined + relatively to the PixelArraySize rectangle. + + When multiple rectangles are reported, they shall be ordered from the + tallest to the shortest. + + Example 1 + A camera sensor which only produces images in the 4:3 image resolution + will report a single PixelArrayActiveAreas rectangle, from which all + other image formats are obtained by either cropping the field-of-view + and/or applying pixel sub-sampling techniques such as pixel skipping or + binning. + + PixelArraySize.width + /----------------/ + x1 x2 + (0,0)-> +-o------------o-+ / + y1 o +------------+ | | + | |////////////| | | + | |////////////| | | PixelArraySize.height + | |////////////| | | + y2 o +------------+ | | + +----------------+ / + + The property reports a single rectangle + + PixelArrayActiveAreas = (x1, y1, x2 - x1 + 1, y2 - y1 + 1) + + Example 2 + A camera sensor which can produce images in different native + resolutions will report several overlapping rectangles, one for each + natively supported resolution. + + PixelArraySize.width + /------------------/ + x1 x2 x3 x4 + (0,0)-> +o---o------o---o+ / + y1 o +------+ | | + | |//////| | | + y2 o+---+------+---+| | + ||///|//////|///|| | PixelArraySize.height + y3 o+---+------+---+| | + | |//////| | | + y4 o +------+ | | + +----+------+----+ / + + The property reports two rectangles + + PixelArrayActiveAreas = ((x2, y1, x3 - x2 + 1, y4 - y1 + 1), + (x1, y2, x4 - x1 + 1, y3 - y2 + 1)) + + The first rectangle describes the maximum field-of-view of all image + formats in the 4:3 resolutions, while the second one describes the + maximum field of view for all image formats in the 16:9 resolutions. + + Multiple rectangles shall only be reported when the sensor can't capture + the pixels in the corner regions. If all the pixels in the (x1,y1) - + (x4,y4) area can be captured, the PixelArrayActiveAreas property shall + contains the single rectangle (x1,y1) - (x4,y4). + + \todo Rename this property to ActiveAreas once we will have property + categories (i.e. Properties::PixelArray::ActiveAreas) + + - ScalerCropMaximum: + type: Rectangle + description: | + The maximum valid rectangle for the controls::ScalerCrop control. This + reflects the minimum mandatory cropping applied in the camera sensor and + the rest of the pipeline. Just as the ScalerCrop control, it defines a + rectangle taken from the sensor's active pixel array. + + This property is valid only after the camera has been successfully + configured and its value may change whenever a new configuration is + applied. + + \todo Turn this property into a "maximum control value" for the + ScalerCrop control once "dynamic" controls have been implemented. + + - SensorSensitivity: + type: float + description: | + The relative sensitivity of the chosen sensor mode. + + Some sensors have readout modes with different sensitivities. For example, + a binned camera mode might, with the same exposure and gains, produce + twice the signal level of the full resolution readout. This would be + signalled by the binned mode, when it is chosen, indicating a value here + that is twice that of the full resolution mode. This value will be valid + after the configure method has returned successfully. + + - SystemDevices: + type: int64_t + size: [n] + description: | + A list of integer values of type dev_t denoting the major and minor + device numbers of the underlying devices used in the operation of this + camera. + + Different cameras may report identical devices. + +... diff --git a/libcamera/versioned_files/0.6.0/property_ids_draft.yaml b/libcamera/versioned_files/0.6.0/property_ids_draft.yaml new file mode 100644 index 0000000..62f0e24 --- /dev/null +++ b/libcamera/versioned_files/0.6.0/property_ids_draft.yaml @@ -0,0 +1,39 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Copyright (C) 2019, Google Inc. +# +%YAML 1.1 +--- +vendor: draft +controls: + - ColorFilterArrangement: + type: int32_t + vendor: draft + description: | + The arrangement of color filters on sensor; represents the colors in the + top-left 2x2 section of the sensor, in reading order. Currently + identical to ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT. + enum: + - name: RGGB + value: 0 + description: RGGB Bayer pattern + - name: GRBG + value: 1 + description: GRBG Bayer pattern + - name: GBRG + value: 2 + description: GBRG Bayer pattern + - name: BGGR + value: 3 + description: BGGR Bayer pattern + - name: RGB + value: 4 + description: | + Sensor is not Bayer; output has 3 16-bit values for each pixel, + instead of just 1 16-bit value per pixel. + - name: MONO + value: 5 + description: | + Sensor is not Bayer; output consists of a single colour channel. + +...