diff --git a/libcamera-sys/c_api/controls.cpp b/libcamera-sys/c_api/controls.cpp index f29ec01..b1da424 100644 --- a/libcamera-sys/c_api/controls.cpp +++ b/libcamera-sys/c_api/controls.cpp @@ -13,10 +13,76 @@ const char *libcamera_control_name(libcamera_control_id_t *control){ return control->name().c_str(); } -enum libcamera_control_type libcamera_control_type(libcamera_control_id_t *control) { +enum libcamera_control_type libcamera_control_id_type(libcamera_control_id_t *control) { return (enum libcamera_control_type) control->type(); } +const char *libcamera_control_id_vendor(libcamera_control_id_t *control) { + return control->vendor().c_str(); +} + +enum libcamera_control_direction libcamera_control_id_direction(libcamera_control_id_t *control) { + using Underlying = std::underlying_type_t; + Underlying bits = static_cast(control->direction()); + + // …then cast that integer into your C enum + return static_cast(bits); +} + +bool libcamera_control_id_is_input(libcamera_control_id_t *control) { + return control->isInput(); +} + +bool libcamera_control_id_is_output(libcamera_control_id_t *control) { + return control->isOutput(); +} + +bool libcamera_control_id_is_array(libcamera_control_id_t *control) { + return control->isArray(); +} + +size_t libcamera_control_id_size(libcamera_control_id_t *control) { + return control->size(); +} + +libcamera_control_id_enumerators_iter_t *libcamera_control_id_enumerators_iter_create(libcamera_control_id_t *ctrl) { + if (!ctrl) + return nullptr; + auto iter = new libcamera_control_id_enumerators_iter_t(); + iter->current = ctrl->enumerators().begin(); + iter->end = ctrl->enumerators().end(); + return iter; +} + +bool libcamera_control_id_enumerators_iter_has_next(const libcamera_control_id_enumerators_iter_t *iter) { + if (!iter) + return false; + return iter->current != iter->end; +} + +int32_t libcamera_control_id_enumerators_iter_key(const libcamera_control_id_enumerators_iter_t *iter) { + if (!iter || iter->current == iter->end) + return 0; + return iter->current->first; +} + +const char *libcamera_control_id_enumerators_iter_value(const libcamera_control_id_enumerators_iter_t *iter) { + if (!iter || iter->current == iter->end) + return nullptr; + return iter->current->second.c_str(); +} + +void libcamera_control_id_enumerators_iter_next(libcamera_control_id_enumerators_iter_t *iter) { + if (!iter || iter->current == iter->end) + return; + ++(iter->current); +} + +void libcamera_control_id_enumerators_iter_destroy(libcamera_control_id_enumerators_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); if (it != libcamera::controls::controls.end()) diff --git a/libcamera-sys/c_api/controls.h b/libcamera-sys/c_api/controls.h index 0a20c9d..419382c 100644 --- a/libcamera-sys/c_api/controls.h +++ b/libcamera-sys/c_api/controls.h @@ -18,6 +18,10 @@ struct libcamera_control_info_map_iter { libcamera::ControlInfoMap::const_iterator end; }; +struct libcamera_control_id_enumerators_iter { + std::map::const_iterator current; + std::map::const_iterator end; +}; typedef libcamera::ControlValue libcamera_control_value_t; typedef libcamera::ControlList libcamera_control_list_t; @@ -38,9 +42,12 @@ typedef struct libcamera_control_info_map libcamera_control_info_map_t; 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; #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 }; @@ -59,6 +66,10 @@ enum libcamera_control_type { LIBCAMERA_CONTROL_TYPE_POINT, }; +enum libcamera_control_direction { + LIBCAMERA_CONTROL_DIRECTION_IN = (1 << 0), + LIBCAMERA_CONTROL_DIRECTION_OUT = (1 << 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); @@ -66,7 +77,22 @@ enum libcamera_control_type libcamera_control_type_from_id(enum libcamera_contro enum libcamera_control_id_enum libcamera_control_id(libcamera_control_id_t *control); const char *libcamera_control_name(libcamera_control_id_t *control); -enum libcamera_control_type libcamera_control_type(libcamera_control_id_t *control); +enum libcamera_control_type libcamera_control_id_type(libcamera_control_id_t *control); +const char *libcamera_control_id_vendor(libcamera_control_id_t *control); +enum libcamera_control_direction libcamera_control_id_direction(libcamera_control_id_t *control); +bool libcamera_control_id_is_input(libcamera_control_id_t *control); +bool libcamera_control_id_is_output(libcamera_control_id_t *control); +bool libcamera_control_id_is_array(libcamera_control_id_t *control); +size_t libcamera_control_id_size(libcamera_control_id_t *control); + +// --- libcamera_control_id_enumerators_iter_t --- +libcamera_control_id_enumerators_iter_t *libcamera_control_id_enumerators_iter_create(libcamera_control_id_t *control); +bool libcamera_control_id_enumerators_iter_has_next(const libcamera_control_id_enumerators_iter_t *iter); +int32_t libcamera_control_id_enumerators_iter_key(const libcamera_control_id_enumerators_iter_t *iter); +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_property_id --- const char *libcamera_property_name_from_id(enum libcamera_property_id id); enum libcamera_control_type libcamera_property_type_from_id(enum libcamera_property_id id); diff --git a/libcamera/examples/camera_control_id_info.rs b/libcamera/examples/camera_control_id_info.rs new file mode 100644 index 0000000..709b969 --- /dev/null +++ b/libcamera/examples/camera_control_id_info.rs @@ -0,0 +1,26 @@ +use libcamera::{camera_manager::CameraManager, controls::ControlId, logging::LoggingLevel}; + +fn main() { + let mgr = CameraManager::new().unwrap(); + + mgr.log_set_level("Camera", LoggingLevel::Error); + + let cameras = mgr.cameras(); + + for cam in cameras.iter() { + println!("ID: {}", cam.id()); + + for (id, _) in cam.controls() { + let id = ControlId::from_id(id).unwrap(); + println!("{:#?}", id.name()); + println!(" Vendor: {:#?}", id.vendor()); + println!(" Control Type: {:#?}", id.control_type()); + println!(" Size: {:#?}", id.size()); + println!(" Direction: {:#?}", id.direction()); + println!(" Is Array: {:#?}", id.is_array()); + println!(" Is Input: {:#?}", id.is_input()); + println!(" Is Output: {:#?}", id.is_output()); + println!(" Enumarators: {:?}", id.enumerators_map()); + } + } +} diff --git a/libcamera/src/control.rs b/libcamera/src/control.rs index 281fbe8..bdcb9b8 100644 --- a/libcamera/src/control.rs +++ b/libcamera/src/control.rs @@ -1,10 +1,12 @@ -use std::{ffi::CStr, marker::PhantomData, ptr::NonNull}; +use std::{collections::HashMap, ffi::CStr, marker::PhantomData, ptr::NonNull}; +use libcamera_control_direction::*; use libcamera_sys::*; +use num_enum::{IntoPrimitive, TryFromPrimitive}; use thiserror::Error; use crate::{ - control_value::{ControlValue, ControlValueError}, + control_value::{ControlType, ControlValue, ControlValueError}, controls::{self, ControlId}, properties::{self, PropertyId}, utils::{UniquePtr, UniquePtrTarget}, @@ -187,7 +189,7 @@ impl core::fmt::Debug for ControlInfoMap { let mut dm = f.debug_map(); for (key, value) in self.into_iter() { match ControlId::try_from(key) { - Ok(id) => dm.entry(&id, value), + Ok(id) => dm.entry(&id.name(), value), Err(_) => dm.entry(&key, value), }; } @@ -456,6 +458,68 @@ impl<'a> Drop for ControlInfoMapIter<'a> { } } +pub struct ControlIdEnumeratorsIter<'a> { + iter: *mut libcamera_control_id_enumerators_iter_t, + marker: PhantomData<&'a ControlId>, +} + +impl<'a> ControlIdEnumeratorsIter<'a> { + fn new(id: &'a ControlId) -> Option { + unsafe { + let iter = libcamera_control_id_enumerators_iter_create(id.as_ptr()); + if iter.is_null() { + None + } else { + Some(ControlIdEnumeratorsIter { + iter, + marker: PhantomData, + }) + } + } + } +} + +impl Iterator for ControlIdEnumeratorsIter<'_> { + type Item = (i32, String); + + fn next(&mut self) -> Option { + unsafe { + if libcamera_control_id_enumerators_iter_has_next(self.iter) { + let key = libcamera_control_id_enumerators_iter_key(self.iter); + let val_ptr = libcamera_control_id_enumerators_iter_value(self.iter); + if val_ptr.is_null() { + None + } else { + let name = CStr::from_ptr(val_ptr).to_string_lossy().into_owned(); + libcamera_control_id_enumerators_iter_next(self.iter); + Some((key, name)) + } + } else { + None + } + } + } +} + +impl Drop for ControlIdEnumeratorsIter<'_> { + fn drop(&mut self) { + unsafe { + libcamera_control_id_enumerators_iter_destroy(self.iter); + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)] +#[repr(u32)] +pub enum ControlDirection { + /// Input flag (1<<0) + In = LIBCAMERA_CONTROL_DIRECTION_IN, + /// Output flag (1<<1) + Out = LIBCAMERA_CONTROL_DIRECTION_OUT, + /// Input and output flags combined (1<<0 | 1<<1) + InOut = LIBCAMERA_CONTROL_DIRECTION_IN | LIBCAMERA_CONTROL_DIRECTION_OUT, +} + impl ControlId { pub fn name(&self) -> String { unsafe { CStr::from_ptr(libcamera_control_name_from_id(self.id())) } @@ -463,6 +527,65 @@ impl ControlId { .unwrap() .into() } + + fn as_ptr(&self) -> *mut libcamera_control_id_t { + let ptr = unsafe { libcamera_control_from_id(self.id()) as *mut libcamera_control_id_t }; + assert!(!ptr.is_null(), "libcamera_control_from_id returned null"); + ptr + } + + pub fn vendor(&self) -> String { + unsafe { + let ctrl = self.as_ptr(); + if ctrl.is_null() { + String::new() + } else { + let ptr = libcamera_control_id_vendor(ctrl); + CStr::from_ptr(ptr).to_string_lossy().to_string() + } + } + } + + pub fn control_type(&self) -> ControlType { + let raw = unsafe { libcamera_control_id_type(self.as_ptr()) } as u32; + ControlType::try_from(raw).expect("Unknown ControlType") + } + + pub fn direction(&self) -> ControlDirection { + let raw = unsafe { libcamera_control_id_direction(self.as_ptr()) } as u32; + ControlDirection::try_from(raw).expect("Unknown libcamera_control_direction value") + } + + pub fn is_input(&self) -> bool { + unsafe { libcamera_control_id_is_input(self.as_ptr()) } + } + + pub fn is_output(&self) -> bool { + unsafe { libcamera_control_id_is_output(self.as_ptr()) } + } + + pub fn is_array(&self) -> bool { + unsafe { libcamera_control_id_is_array(self.as_ptr()) } + } + + pub fn size(&self) -> usize { + unsafe { libcamera_control_id_size(self.as_ptr()) } + } + + pub fn enumerators(&self) -> Option> { + ControlIdEnumeratorsIter::new(self) + } + + pub fn enumerators_map(&self) -> HashMap { + match self.enumerators() { + Some(iter) => iter.collect(), + None => HashMap::new(), + } + } + + pub fn from_id(id: u32) -> Option { + ControlId::try_from(id).ok() + } } impl PropertyId { diff --git a/libcamera/src/control_value.rs b/libcamera/src/control_value.rs index 3c4f643..fcbf8a5 100644 --- a/libcamera/src/control_value.rs +++ b/libcamera/src/control_value.rs @@ -1,5 +1,6 @@ use std::ptr::NonNull; +use libcamera_control_type::*; use libcamera_sys::*; use smallvec::{smallvec, SmallVec}; use thiserror::Error; @@ -21,7 +22,6 @@ pub enum ControlValueError { #[error("Unknown enum variant {0:?}")] UnknownVariant(ControlValue), } - /// A value of a control or a property. #[derive(Debug, Clone)] pub enum ControlValue { @@ -224,7 +224,6 @@ impl ControlValue { let num_elements = unsafe { libcamera_control_value_num_elements(val.as_ptr()) }; let data = unsafe { libcamera_control_value_get(val.as_ptr()) }; - use libcamera_control_type::*; match ty { LIBCAMERA_CONTROL_TYPE_NONE => Ok(Self::None), LIBCAMERA_CONTROL_TYPE_BOOL => { @@ -321,3 +320,83 @@ impl ControlValue { } } } + +#[derive(Error, Debug)] +pub enum ControlTypeError { + /// Control type is not recognized + #[error("Unknown control type {0}")] + UnknownType(u32), +} + +#[derive(Debug, Clone)] +#[repr(u32)] +pub enum ControlType { + None = LIBCAMERA_CONTROL_TYPE_NONE, + Bool = LIBCAMERA_CONTROL_TYPE_BOOL, + Byte = LIBCAMERA_CONTROL_TYPE_BYTE, + Uint16 = LIBCAMERA_CONTROL_TYPE_UINT16, + Uint32 = LIBCAMERA_CONTROL_TYPE_UINT32, + Int32 = LIBCAMERA_CONTROL_TYPE_INT32, + Int64 = LIBCAMERA_CONTROL_TYPE_INT64, + Float = LIBCAMERA_CONTROL_TYPE_FLOAT, + String = LIBCAMERA_CONTROL_TYPE_STRING, + Rectangle = LIBCAMERA_CONTROL_TYPE_RECTANGLE, + Size = LIBCAMERA_CONTROL_TYPE_SIZE, + Point = LIBCAMERA_CONTROL_TYPE_POINT, +} + +impl TryFrom for ControlType { + type Error = ControlTypeError; + + fn try_from(value: u32) -> Result { + use libcamera_control_type::*; + match value { + LIBCAMERA_CONTROL_TYPE_NONE => Ok(ControlType::None), + LIBCAMERA_CONTROL_TYPE_BOOL => Ok(ControlType::Bool), + LIBCAMERA_CONTROL_TYPE_BYTE => Ok(ControlType::Byte), + LIBCAMERA_CONTROL_TYPE_UINT16 => Ok(ControlType::Uint16), + LIBCAMERA_CONTROL_TYPE_UINT32 => Ok(ControlType::Uint32), + LIBCAMERA_CONTROL_TYPE_INT32 => Ok(ControlType::Int32), + LIBCAMERA_CONTROL_TYPE_INT64 => Ok(ControlType::Int64), + LIBCAMERA_CONTROL_TYPE_FLOAT => Ok(ControlType::Float), + LIBCAMERA_CONTROL_TYPE_STRING => Ok(ControlType::String), + LIBCAMERA_CONTROL_TYPE_RECTANGLE => Ok(ControlType::Rectangle), + LIBCAMERA_CONTROL_TYPE_SIZE => Ok(ControlType::Size), + LIBCAMERA_CONTROL_TYPE_POINT => Ok(ControlType::Point), + unknown => Err(ControlTypeError::UnknownType(unknown)), + } + } +} + +impl From for u32 { + fn from(control_type: ControlType) -> Self { + control_type as u32 + } +} + +impl From<&ControlValue> for ControlType { + fn from(control_value: &ControlValue) -> Self { + match control_value { + ControlValue::None => ControlType::None, + ControlValue::Bool(_) => ControlType::Bool, + ControlValue::Byte(_) => ControlType::Byte, + ControlValue::Uint16(_) => ControlType::Uint16, + ControlValue::Uint32(_) => ControlType::Uint32, + ControlValue::Int32(_) => ControlType::Int32, + ControlValue::Int64(_) => ControlType::Int64, + ControlValue::Float(_) => ControlType::Float, + ControlValue::String(_) => ControlType::String, + ControlValue::Rectangle(_) => ControlType::Rectangle, + ControlValue::Size(_) => ControlType::Size, + ControlValue::Point(_) => ControlType::Point, + } + } +} + +impl TryFrom for ControlType { + type Error = ControlTypeError; + + fn try_from(value: ControlValue) -> Result { + Ok(ControlType::from(&value)) + } +}