libcamera/
control.rs

1use std::{collections::HashMap, ffi::CStr, marker::PhantomData, ptr::NonNull};
2
3use libcamera_control_direction::*;
4use libcamera_sys::*;
5use num_enum::{IntoPrimitive, TryFromPrimitive};
6use thiserror::Error;
7
8use crate::{
9    control_value::{ControlType, ControlValue, ControlValueError},
10    controls::{self, ControlId},
11    properties::{self, PropertyId},
12    utils::{UniquePtr, UniquePtrTarget},
13};
14
15#[derive(Debug, Error)]
16pub enum ControlError {
17    #[error("Control id {0} not found")]
18    NotFound(u32),
19    #[error("Control value error: {0}")]
20    ValueError(#[from] ControlValueError),
21}
22
23pub trait ControlEntry:
24    Clone + Into<ControlValue> + TryFrom<ControlValue, Error = ControlValueError> + core::fmt::Debug
25{
26    const ID: u32;
27}
28
29pub trait Control: ControlEntry {}
30pub trait Property: ControlEntry {}
31
32/// Dynamic Control, which does not have strong typing.
33pub trait DynControlEntry: core::fmt::Debug {
34    fn id(&self) -> u32;
35    fn value(&self) -> ControlValue;
36}
37
38impl<T: ControlEntry> DynControlEntry for T {
39    fn id(&self) -> u32 {
40        Self::ID
41    }
42
43    fn value(&self) -> ControlValue {
44        self.clone().into()
45    }
46}
47
48#[repr(transparent)]
49pub struct ControlInfo(libcamera_control_info_t);
50
51impl ControlInfo {
52    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_info_t>) -> &'a mut Self {
53        // Safety: we can cast it because of `#[repr(transparent)]`
54        &mut *(ptr.as_ptr() as *mut Self)
55    }
56
57    pub(crate) fn ptr(&self) -> *const libcamera_control_info_t {
58        // Safety: we can cast it because of `#[repr(transparent)]`
59        &self.0 as *const libcamera_control_info_t
60    }
61
62    pub fn min(&self) -> ControlValue {
63        unsafe {
64            ControlValue::read(NonNull::new(libcamera_control_info_min(self.ptr().cast_mut()).cast_mut()).unwrap())
65                .unwrap()
66        }
67    }
68
69    pub fn max(&self) -> ControlValue {
70        unsafe {
71            ControlValue::read(NonNull::new(libcamera_control_info_max(self.ptr().cast_mut()).cast_mut()).unwrap())
72                .unwrap()
73        }
74    }
75
76    pub fn def(&self) -> ControlValue {
77        unsafe {
78            ControlValue::read(NonNull::new(libcamera_control_info_def(self.ptr().cast_mut()).cast_mut()).unwrap())
79                .unwrap()
80        }
81    }
82
83    pub fn values(&self) -> Vec<ControlValue> {
84        unsafe {
85            let mut size: usize = 0;
86            let values_ptr = libcamera_control_info_values(self.ptr(), &mut size as *mut usize);
87
88            if values_ptr.is_null() || size == 0 {
89                return Vec::new();
90            }
91
92            // Determine the size of libcamera_control_value_t
93            let control_value_size = libcamera_control_value_size();
94
95            // Cast the pointer to *const u8 for byte-wise pointer arithmetic
96            let base_ptr = values_ptr as *const u8;
97
98            let mut control_values = Vec::with_capacity(size);
99            for i in 0..size {
100                // Calculate the pointer to the i-th ControlValue
101                let offset = i * control_value_size;
102                let val_ptr = base_ptr.add(offset) as *const libcamera_control_value_t;
103
104                if val_ptr.is_null() {
105                    eprintln!("ControlValue at index {i} is null");
106                    continue;
107                }
108
109                // Read and convert the ControlValue
110                match ControlValue::read(NonNull::new(val_ptr.cast_mut()).unwrap()) {
111                    Ok(control_val) => control_values.push(control_val),
112                    Err(e) => {
113                        eprintln!("Failed to read ControlValue at index {i}: {e:?}");
114                    }
115                }
116            }
117
118            control_values
119        }
120    }
121}
122
123impl core::fmt::Debug for ControlInfo {
124    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
125        f.debug_struct("ControlInfo")
126            .field("min", &self.min())
127            .field("max", &self.max())
128            .field("def", &self.def())
129            .field("values", &self.values())
130            .finish()
131    }
132}
133
134#[repr(transparent)]
135pub struct ControlInfoMap(libcamera_control_info_map_t);
136
137impl ControlInfoMap {
138    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_info_map_t>) -> &'a mut Self {
139        // Safety: we can cast it because of `#[repr(transparent)]`
140        &mut *(ptr.as_ptr() as *mut Self)
141    }
142
143    pub(crate) fn ptr(&self) -> *const libcamera_control_info_map_t {
144        // Safety: we can cast it because of `#[repr(transparent)]`
145        &self.0 as *const libcamera_control_info_map_t
146    }
147
148    pub fn at(&self, key: u32) -> Result<&ControlInfo, ControlError> {
149        unsafe {
150            let ptr = NonNull::new(libcamera_control_info_map_at(self.ptr().cast_mut(), key).cast_mut());
151            match ptr {
152                Some(ptr) => Ok(ControlInfo::from_ptr(ptr)),
153                None => Err(ControlError::NotFound(key)),
154            }
155        }
156    }
157
158    pub fn count(&self, key: u32) -> usize {
159        unsafe { libcamera_control_info_map_count(self.ptr().cast_mut(), key) }
160    }
161
162    pub fn find(&self, key: u32) -> Result<&ControlInfo, ControlError> {
163        unsafe {
164            let ptr = NonNull::new(libcamera_control_info_map_find(self.ptr().cast_mut(), key).cast_mut());
165
166            match ptr {
167                Some(ptr) => Ok(ControlInfo::from_ptr(ptr)),
168                None => Err(ControlError::NotFound(key)),
169            }
170        }
171    }
172
173    pub fn size(&self) -> usize {
174        unsafe { libcamera_control_info_map_size(self.ptr().cast_mut()) }
175    }
176}
177
178impl<'a> IntoIterator for &'a ControlInfoMap {
179    type Item = (u32, &'a ControlInfo);
180    type IntoIter = ControlInfoMapIter<'a>;
181
182    fn into_iter(self) -> Self::IntoIter {
183        ControlInfoMapIter::new(self).expect("Failed to create ControlInfoMap iterator")
184    }
185}
186
187impl core::fmt::Debug for ControlInfoMap {
188    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189        let mut dm = f.debug_map();
190        for (key, value) in self.into_iter() {
191            match ControlId::try_from(key) {
192                Ok(id) => dm.entry(&id.name(), value),
193                Err(_) => dm.entry(&key, value),
194            };
195        }
196        dm.finish()
197    }
198}
199
200#[repr(transparent)]
201pub struct ControlList(libcamera_control_list_t);
202
203impl UniquePtrTarget for ControlList {
204    unsafe fn ptr_new() -> *mut Self {
205        libcamera_control_list_create() as *mut Self
206    }
207
208    unsafe fn ptr_drop(ptr: *mut Self) {
209        libcamera_control_list_destroy(ptr as *mut libcamera_control_list_t)
210    }
211}
212
213impl ControlList {
214    pub fn new() -> UniquePtr<Self> {
215        UniquePtr::new()
216    }
217
218    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_list_t>) -> &'a mut Self {
219        // Safety: we can cast it because of `#[repr(transparent)]`
220        &mut *(ptr.as_ptr() as *mut Self)
221    }
222
223    pub(crate) fn ptr(&self) -> *const libcamera_control_list_t {
224        // Safety: we can cast it because of `#[repr(transparent)]`
225        &self.0 as *const libcamera_control_list_t
226    }
227
228    pub fn get<C: Control>(&self) -> Result<C, ControlError> {
229        let val_ptr = NonNull::new(unsafe { libcamera_control_list_get(self.ptr().cast_mut(), C::ID as _).cast_mut() })
230            .ok_or(ControlError::NotFound(C::ID))?;
231
232        let val = unsafe { ControlValue::read(val_ptr) }?;
233        Ok(C::try_from(val)?)
234    }
235
236    /// Sets control value.
237    ///
238    /// This can fail if control is not supported by the camera, but due to libcamera API limitations an error will not
239    /// be returned. Use [ControlList::get] if you need to ensure that value was set.
240    pub fn set<C: Control>(&mut self, val: C) -> Result<(), ControlError> {
241        let ctrl_val: ControlValue = val.into();
242
243        unsafe {
244            let val_ptr = NonNull::new(libcamera_control_value_create()).unwrap();
245            ctrl_val.write(val_ptr);
246            libcamera_control_list_set(self.ptr().cast_mut(), C::ID as _, val_ptr.as_ptr());
247            libcamera_control_value_destroy(val_ptr.as_ptr());
248        }
249
250        Ok(())
251    }
252
253    /// Sets control value.
254    ///
255    /// This can fail if control is not supported by the camera, but due to libcamera API limitations an error will not
256    /// be returned. Use [ControlList::get] if you need to ensure that value was set.
257    pub fn set_raw(&mut self, id: u32, val: ControlValue) -> Result<(), ControlError> {
258        unsafe {
259            let val_ptr = NonNull::new(libcamera_control_value_create()).unwrap();
260            val.write(val_ptr);
261            libcamera_control_list_set(self.ptr().cast_mut(), id as _, val_ptr.as_ptr());
262            libcamera_control_value_destroy(val_ptr.as_ptr());
263        }
264
265        Ok(())
266    }
267
268    pub fn get_raw(&mut self, id: u32) -> Result<ControlValue, ControlError> {
269        let val_ptr = NonNull::new(unsafe { libcamera_control_list_get(self.ptr().cast_mut(), id as _).cast_mut() })
270            .ok_or(ControlError::NotFound(id))?;
271
272        let val = unsafe { ControlValue::read(val_ptr) }?;
273        Ok(val)
274    }
275}
276
277impl<'d> IntoIterator for &'d ControlList {
278    type Item = (u32, ControlValue);
279
280    type IntoIter = ControlListRefIterator<'d>;
281
282    fn into_iter(self) -> Self::IntoIter {
283        ControlListRefIterator {
284            it: NonNull::new(unsafe { libcamera_control_list_iter(self.ptr().cast_mut()) }).unwrap(),
285            _phantom: Default::default(),
286        }
287    }
288}
289
290impl core::fmt::Debug for ControlList {
291    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292        let mut map = f.debug_map();
293        for (id, val) in self.into_iter() {
294            match ControlId::try_from(id) {
295                // Try to parse dynamic control, if not successful, just display the raw ControlValue
296                Ok(id) => match controls::make_dyn(id, val.clone()) {
297                    Ok(val) => map.entry(&id, &val),
298                    Err(_) => map.entry(&id, &val),
299                },
300                // If ControlId is unknown just use u32 as key
301                Err(_) => map.entry(&id, &val),
302            };
303        }
304        map.finish()
305    }
306}
307
308#[repr(transparent)]
309pub struct PropertyList(libcamera_control_list_t);
310
311impl PropertyList {
312    pub(crate) unsafe fn from_ptr<'a>(ptr: NonNull<libcamera_control_list_t>) -> &'a mut Self {
313        // Safety: we can cast it because of `#[repr(transparent)]`
314        &mut *(ptr.as_ptr() as *mut Self)
315    }
316
317    pub(crate) fn ptr(&self) -> *const libcamera_control_list_t {
318        // Safety: we can cast it because of `#[repr(transparent)]`
319        &self.0 as *const libcamera_control_list_t
320    }
321
322    pub fn get<C: Property>(&self) -> Result<C, ControlError> {
323        let val_ptr = NonNull::new(unsafe { libcamera_control_list_get(self.ptr().cast_mut(), C::ID as _).cast_mut() })
324            .ok_or(ControlError::NotFound(C::ID))?;
325
326        let val = unsafe { ControlValue::read(val_ptr) }?;
327
328        Ok(C::try_from(val)?)
329    }
330
331    /// Sets property value.
332    ///
333    /// This can fail if property is not supported by the camera, but due to libcamera API limitations an error will not
334    /// be returned. Use [PropertyList::get] if you need to ensure that value was set.
335    pub fn set<C: Property>(&mut self, val: C) -> Result<(), ControlError> {
336        let ctrl_val: ControlValue = val.into();
337
338        unsafe {
339            let val_ptr = NonNull::new(libcamera_control_value_create()).unwrap();
340            ctrl_val.write(val_ptr);
341            libcamera_control_list_set(self.ptr().cast_mut(), C::ID as _, val_ptr.as_ptr());
342            libcamera_control_value_destroy(val_ptr.as_ptr());
343        }
344
345        Ok(())
346    }
347}
348
349impl<'d> IntoIterator for &'d PropertyList {
350    type Item = (u32, ControlValue);
351
352    type IntoIter = ControlListRefIterator<'d>;
353
354    fn into_iter(self) -> Self::IntoIter {
355        ControlListRefIterator {
356            it: NonNull::new(unsafe { libcamera_control_list_iter(self.ptr().cast_mut()) }).unwrap(),
357            _phantom: Default::default(),
358        }
359    }
360}
361
362impl core::fmt::Debug for PropertyList {
363    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
364        let mut map = f.debug_map();
365        for (id, val) in self.into_iter() {
366            match PropertyId::try_from(id) {
367                // Try to parse dynamic property, if not successful, just display the raw ControlValue
368                Ok(id) => match properties::make_dyn(id, val.clone()) {
369                    Ok(val) => map.entry(&id, &val),
370                    Err(_) => map.entry(&id, &val),
371                },
372                // If PropertyId is unknown just use u32 as key
373                Err(_) => map.entry(&id, &val),
374            };
375        }
376        map.finish()
377    }
378}
379
380pub struct ControlListRefIterator<'d> {
381    it: NonNull<libcamera_control_list_iter_t>,
382    _phantom: PhantomData<&'d ()>,
383}
384
385impl Iterator for ControlListRefIterator<'_> {
386    type Item = (u32, ControlValue);
387
388    fn next(&mut self) -> Option<Self::Item> {
389        if unsafe { libcamera_control_list_iter_end(self.it.as_ptr()) } {
390            None
391        } else {
392            let id = unsafe { libcamera_control_list_iter_id(self.it.as_ptr()) };
393            let val_ptr =
394                NonNull::new(unsafe { libcamera_control_list_iter_value(self.it.as_ptr()).cast_mut() }).unwrap();
395            let val = unsafe { ControlValue::read(val_ptr) }.unwrap();
396
397            unsafe { libcamera_control_list_iter_next(self.it.as_ptr()) };
398
399            Some((id, val))
400        }
401    }
402}
403
404impl Drop for ControlListRefIterator<'_> {
405    fn drop(&mut self) {
406        unsafe { libcamera_control_list_iter_destroy(self.it.as_ptr()) }
407    }
408}
409
410pub struct ControlInfoMapIter<'a> {
411    iter: *mut libcamera_control_info_map_iter_t,
412    marker: PhantomData<&'a libcamera_control_info_map_t>,
413}
414
415impl<'a> ControlInfoMapIter<'a> {
416    pub fn new(map: &'a ControlInfoMap) -> Option<Self> {
417        unsafe {
418            let iter = libcamera_control_info_map_iter_create(map.ptr());
419            if iter.is_null() {
420                None
421            } else {
422                Some(ControlInfoMapIter {
423                    iter,
424                    marker: PhantomData,
425                })
426            }
427        }
428    }
429}
430
431impl<'a> Iterator for ControlInfoMapIter<'a> {
432    type Item = (u32, &'a ControlInfo);
433
434    fn next(&mut self) -> Option<Self::Item> {
435        unsafe {
436            if libcamera_control_info_map_iter_has_next(self.iter) {
437                let key = libcamera_control_info_map_iter_key(self.iter);
438                let value_ptr = libcamera_control_info_map_iter_value(self.iter);
439                if value_ptr.is_null() {
440                    None
441                } else {
442                    let control_info = &*(value_ptr as *const ControlInfo);
443                    libcamera_control_info_map_iter_next(self.iter);
444                    Some((key, control_info))
445                }
446            } else {
447                None
448            }
449        }
450    }
451}
452
453impl<'a> Drop for ControlInfoMapIter<'a> {
454    fn drop(&mut self) {
455        unsafe {
456            libcamera_control_info_map_iter_destroy(self.iter);
457        }
458    }
459}
460
461pub struct ControlIdEnumeratorsIter<'a> {
462    iter: *mut libcamera_control_id_enumerators_iter_t,
463    marker: PhantomData<&'a ControlId>,
464}
465
466impl<'a> ControlIdEnumeratorsIter<'a> {
467    fn new(id: &'a ControlId) -> Option<Self> {
468        unsafe {
469            let iter = libcamera_control_id_enumerators_iter_create(id.as_ptr());
470            if iter.is_null() {
471                None
472            } else {
473                Some(ControlIdEnumeratorsIter {
474                    iter,
475                    marker: PhantomData,
476                })
477            }
478        }
479    }
480}
481
482impl Iterator for ControlIdEnumeratorsIter<'_> {
483    type Item = (i32, String);
484
485    fn next(&mut self) -> Option<Self::Item> {
486        unsafe {
487            if libcamera_control_id_enumerators_iter_has_next(self.iter) {
488                let key = libcamera_control_id_enumerators_iter_key(self.iter);
489                let val_ptr = libcamera_control_id_enumerators_iter_value(self.iter);
490                if val_ptr.is_null() {
491                    None
492                } else {
493                    let name = CStr::from_ptr(val_ptr).to_string_lossy().into_owned();
494                    libcamera_control_id_enumerators_iter_next(self.iter);
495                    Some((key, name))
496                }
497            } else {
498                None
499            }
500        }
501    }
502}
503
504impl Drop for ControlIdEnumeratorsIter<'_> {
505    fn drop(&mut self) {
506        unsafe {
507            libcamera_control_id_enumerators_iter_destroy(self.iter);
508        }
509    }
510}
511
512#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
513#[repr(u32)]
514pub enum ControlDirection {
515    /// Input flag (1<<0)
516    In = LIBCAMERA_CONTROL_DIRECTION_IN,
517    /// Output flag (1<<1)
518    Out = LIBCAMERA_CONTROL_DIRECTION_OUT,
519    /// Input and output flags combined (1<<0 | 1<<1)
520    InOut = LIBCAMERA_CONTROL_DIRECTION_IN | LIBCAMERA_CONTROL_DIRECTION_OUT,
521}
522
523impl ControlId {
524    pub fn name(&self) -> String {
525        unsafe { CStr::from_ptr(libcamera_control_name_from_id(self.id())) }
526            .to_str()
527            .unwrap()
528            .into()
529    }
530
531    fn as_ptr(&self) -> *mut libcamera_control_id_t {
532        let ptr = unsafe { libcamera_control_from_id(self.id()) as *mut libcamera_control_id_t };
533        assert!(!ptr.is_null(), "libcamera_control_from_id returned null");
534        ptr
535    }
536
537    pub fn vendor(&self) -> String {
538        unsafe {
539            let ctrl = self.as_ptr();
540            if ctrl.is_null() {
541                String::new()
542            } else {
543                let ptr = libcamera_control_id_vendor(ctrl);
544                CStr::from_ptr(ptr).to_string_lossy().to_string()
545            }
546        }
547    }
548
549    pub fn control_type(&self) -> ControlType {
550        let raw = unsafe { libcamera_control_id_type(self.as_ptr()) } as u32;
551        ControlType::try_from(raw).expect("Unknown ControlType")
552    }
553
554    pub fn direction(&self) -> ControlDirection {
555        let raw = unsafe { libcamera_control_id_direction(self.as_ptr()) } as u32;
556        ControlDirection::try_from(raw).expect("Unknown libcamera_control_direction value")
557    }
558
559    pub fn is_input(&self) -> bool {
560        unsafe { libcamera_control_id_is_input(self.as_ptr()) }
561    }
562
563    pub fn is_output(&self) -> bool {
564        unsafe { libcamera_control_id_is_output(self.as_ptr()) }
565    }
566
567    pub fn is_array(&self) -> bool {
568        unsafe { libcamera_control_id_is_array(self.as_ptr()) }
569    }
570
571    pub fn size(&self) -> usize {
572        unsafe { libcamera_control_id_size(self.as_ptr()) }
573    }
574
575    pub fn enumerators(&self) -> Option<ControlIdEnumeratorsIter<'_>> {
576        ControlIdEnumeratorsIter::new(self)
577    }
578
579    pub fn enumerators_map(&self) -> HashMap<i32, String> {
580        match self.enumerators() {
581            Some(iter) => iter.collect(),
582            None => HashMap::new(),
583        }
584    }
585
586    pub fn from_id(id: u32) -> Option<Self> {
587        ControlId::try_from(id).ok()
588    }
589}
590
591impl PropertyId {
592    pub fn name(&self) -> String {
593        unsafe { CStr::from_ptr(libcamera_property_name_from_id(self.id())) }
594            .to_str()
595            .unwrap()
596            .into()
597    }
598}