Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion libcamera-sys/c_api/controls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<libcamera::ControlId::Direction>;
Underlying bits = static_cast<Underlying>(control->direction());

// …then cast that integer into your C enum
return static_cast<enum libcamera_control_direction>(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())
Expand Down
28 changes: 27 additions & 1 deletion libcamera-sys/c_api/controls.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ struct libcamera_control_info_map_iter {
libcamera::ControlInfoMap::const_iterator end;
};

struct libcamera_control_id_enumerators_iter {
std::map<int32_t, std::string>::const_iterator current;
std::map<int32_t, std::string>::const_iterator end;
};

typedef libcamera::ControlValue libcamera_control_value_t;
typedef libcamera::ControlList libcamera_control_list_t;
Expand All @@ -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 };

Expand All @@ -59,14 +66,33 @@ 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);
enum libcamera_control_type libcamera_control_type_from_id(enum libcamera_control_id_enum id);

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);
Expand Down
26 changes: 26 additions & 0 deletions libcamera/examples/camera_control_id_info.rs
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
129 changes: 126 additions & 3 deletions libcamera/src/control.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -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),
};
}
Expand Down Expand Up @@ -456,13 +458,134 @@ 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<Self> {
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<Self::Item> {
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())) }
.to_str()
.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<'_>> {
ControlIdEnumeratorsIter::new(self)
}

pub fn enumerators_map(&self) -> HashMap<i32, String> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would work better as an iterator, see ControlListRefIterator implementation to iterate a C++ map. Current implementation will cost O(2n log n) to collect everything into hashmap, because std::advance(it, index) is O(log n) for C++ map, which is called for each entry twice. I know that this is not a performance critical path, but I would like it to be consistent inside the repo. A separate convenience function can just .collect() rust iterator into a HashMap<i32, String>.

match self.enumerators() {
Some(iter) => iter.collect(),
None => HashMap::new(),
}
}

pub fn from_id(id: u32) -> Option<Self> {
ControlId::try_from(id).ok()
}
}

impl PropertyId {
Expand Down
Loading