1use std::{
2 collections::HashMap,
3 ffi::CStr,
4 io,
5 marker::PhantomData,
6 ops::{Deref, DerefMut},
7 ptr::NonNull,
8 sync::Mutex,
9};
10
11use libcamera_sys::*;
12
13use crate::{
14 control::{ControlInfoMap, ControlList, PropertyList},
15 request::Request,
16 stream::{StreamConfigurationRef, StreamRole},
17 utils::Immutable,
18};
19
20#[derive(Debug, Clone, Copy)]
22pub enum CameraConfigurationStatus {
23 Valid,
25 Adjusted,
27 Invalid,
29}
30
31impl CameraConfigurationStatus {
32 pub fn is_valid(&self) -> bool {
33 matches!(self, Self::Valid)
34 }
35
36 pub fn is_adjusted(&self) -> bool {
37 matches!(self, Self::Adjusted)
38 }
39
40 pub fn is_invalid(&self) -> bool {
41 matches!(self, Self::Invalid)
42 }
43}
44
45impl TryFrom<libcamera_camera_configuration_status_t> for CameraConfigurationStatus {
46 type Error = ();
47
48 fn try_from(value: libcamera_camera_configuration_status_t) -> Result<Self, Self::Error> {
49 match value {
50 libcamera_camera_configuration_status::LIBCAMERA_CAMERA_CONFIGURATION_STATUS_VALID => Ok(Self::Valid),
51 libcamera_camera_configuration_status::LIBCAMERA_CAMERA_CONFIGURATION_STATUS_ADJUSTED => Ok(Self::Adjusted),
52 libcamera_camera_configuration_status::LIBCAMERA_CAMERA_CONFIGURATION_STATUS_INVALID => Ok(Self::Invalid),
53 _ => Err(()),
54 }
55 }
56}
57
58pub struct SensorConfiguration {
59 item: NonNull<libcamera_sensor_configuration_t>,
60}
61
62impl SensorConfiguration {
63 pub fn new() -> Self {
64 let ptr = NonNull::new(unsafe { libcamera_sensor_configuration_create() }).unwrap();
65 Self { item: ptr }
66 }
67
68 pub fn from_ptr(ptr: NonNull<libcamera_sensor_configuration_t>) -> Self {
69 Self { item: ptr }
70 }
71
72 pub fn set_bit_depth(&mut self, depth: u32) {
73 unsafe { libcamera_sensor_configuration_set_bit_depth(self.item.as_ptr(), depth) }
74 }
75
76 pub fn set_output_size(&mut self, width: u32, height: u32) {
77 unsafe { libcamera_sensor_configuration_set_output_size(self.item.as_ptr(), width, height) }
78 }
79}
80
81impl Default for SensorConfiguration {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87impl Drop for SensorConfiguration {
88 fn drop(&mut self) {
89 unsafe { libcamera_sensor_configuration_destroy(self.item.as_ptr()) }
90 }
91}
92
93pub struct CameraConfiguration {
97 ptr: NonNull<libcamera_camera_configuration_t>,
98}
99
100impl CameraConfiguration {
101 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_configuration_t>) -> Self {
102 Self { ptr }
103 }
104
105 pub fn get(&self, index: usize) -> Option<Immutable<StreamConfigurationRef<'_>>> {
111 let ptr = unsafe { libcamera_camera_configuration_at(self.ptr.as_ptr(), index as _) };
112 NonNull::new(ptr).map(|p| Immutable(unsafe { StreamConfigurationRef::from_ptr(p) }))
113 }
114
115 pub fn get_mut(&mut self, index: usize) -> Option<StreamConfigurationRef<'_>> {
121 let ptr = unsafe { libcamera_camera_configuration_at(self.ptr.as_ptr(), index as _) };
122 NonNull::new(ptr).map(|p| unsafe { StreamConfigurationRef::from_ptr(p) })
123 }
124
125 pub fn set_sensor_configuration(&mut self, mode: SensorConfiguration) {
126 unsafe { libcamera_camera_set_sensor_configuration(self.ptr.as_ptr(), mode.item.as_ptr()) }
127 }
128
129 pub fn len(&self) -> usize {
131 unsafe { libcamera_camera_configuration_size(self.ptr.as_ptr()) }
132 }
133
134 pub fn is_empty(&self) -> bool {
136 self.len() == 0
137 }
138
139 pub fn validate(&mut self) -> CameraConfigurationStatus {
141 unsafe { libcamera_camera_configuration_validate(self.ptr.as_ptr()) }
142 .try_into()
143 .unwrap()
144 }
145}
146
147impl core::fmt::Debug for CameraConfiguration {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 let mut list = f.debug_list();
150 for i in 0..self.len() {
151 list.entry(&self.get(i).unwrap().0);
152 }
153 list.finish()
154 }
155}
156
157impl Drop for CameraConfiguration {
158 fn drop(&mut self) {
159 unsafe { libcamera_camera_configuration_destroy(self.ptr.as_ptr()) }
160 }
161}
162
163pub struct Camera<'d> {
168 pub(crate) ptr: NonNull<libcamera_camera_t>,
169 _phantom: PhantomData<&'d ()>,
170}
171
172impl<'d> Camera<'d> {
173 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_t>) -> Self {
174 Self {
175 ptr,
176 _phantom: Default::default(),
177 }
178 }
179
180 pub fn id(&self) -> &str {
186 unsafe { CStr::from_ptr(libcamera_camera_id(self.ptr.as_ptr())) }
187 .to_str()
188 .unwrap()
189 }
190
191 pub fn controls(&self) -> &ControlInfoMap {
193 unsafe {
194 ControlInfoMap::from_ptr(NonNull::new(libcamera_camera_controls(self.ptr.as_ptr()).cast_mut()).unwrap())
195 }
196 }
197
198 pub fn properties(&self) -> &PropertyList {
202 unsafe {
203 PropertyList::from_ptr(NonNull::new(libcamera_camera_properties(self.ptr.as_ptr()).cast_mut()).unwrap())
204 }
205 }
206
207 pub fn generate_configuration(&self, roles: &[StreamRole]) -> Option<CameraConfiguration> {
213 let roles: Vec<libcamera_stream_role::Type> = roles.iter().map(|r| (*r).into()).collect();
214 let cfg =
215 unsafe { libcamera_camera_generate_configuration(self.ptr.as_ptr(), roles.as_ptr(), roles.len() as _) };
216 NonNull::new(cfg).map(|p| unsafe { CameraConfiguration::from_ptr(p) })
217 }
218
219 pub fn acquire(&self) -> io::Result<ActiveCamera<'d>> {
221 let ret = unsafe { libcamera_camera_acquire(self.ptr.as_ptr()) };
222 if ret < 0 {
223 Err(io::Error::from_raw_os_error(ret))
224 } else {
225 Ok(unsafe { ActiveCamera::from_ptr(NonNull::new(libcamera_camera_copy(self.ptr.as_ptr())).unwrap()) })
226 }
227 }
228}
229
230impl Drop for Camera<'_> {
231 fn drop(&mut self) {
232 unsafe { libcamera_camera_destroy(self.ptr.as_ptr()) }
233 }
234}
235
236extern "C" fn camera_request_completed_cb(ptr: *mut core::ffi::c_void, req: *mut libcamera_request_t) {
237 let mut state = unsafe { &*(ptr as *const Mutex<ActiveCameraState<'_>>) }
238 .lock()
239 .unwrap();
240 let req = state.requests.remove(&req).unwrap();
241
242 if let Some(cb) = &mut state.request_completed_cb {
243 cb(req);
244 }
245}
246
247#[derive(Default)]
248struct ActiveCameraState<'d> {
249 requests: HashMap<*mut libcamera_request_t, Request>,
252 request_completed_cb: Option<Box<dyn FnMut(Request) + Send + 'd>>,
254}
255
256pub struct ActiveCamera<'d> {
262 cam: Camera<'d>,
263 request_completed_handle: *mut libcamera_callback_handle_t,
265 state: Box<Mutex<ActiveCameraState<'d>>>,
267}
268
269impl<'d> ActiveCamera<'d> {
270 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_t>) -> Self {
271 let mut state = Box::new(Mutex::new(ActiveCameraState::default()));
272
273 let request_completed_handle = unsafe {
274 libcamera_camera_request_completed_connect(
275 ptr.as_ptr(),
276 Some(camera_request_completed_cb),
277 state.as_mut() as *mut Mutex<ActiveCameraState<'_>> as *mut _,
279 )
280 };
281
282 Self {
283 cam: Camera::from_ptr(ptr),
284 request_completed_handle,
285 state,
286 }
287 }
288
289 pub fn on_request_completed(&mut self, cb: impl FnMut(Request) + Send + 'd) {
297 let mut state = self.state.lock().unwrap();
298 state.request_completed_cb = Some(Box::new(cb));
299 }
300
301 pub fn configure(&mut self, config: &mut CameraConfiguration) -> io::Result<()> {
305 let ret = unsafe { libcamera_camera_configure(self.ptr.as_ptr(), config.ptr.as_ptr()) };
306 if ret < 0 {
307 Err(io::Error::from_raw_os_error(ret))
308 } else {
309 Ok(())
310 }
311 }
312
313 pub fn create_request(&mut self, cookie: Option<u64>) -> Option<Request> {
323 let req = unsafe { libcamera_camera_create_request(self.ptr.as_ptr(), cookie.unwrap_or(0)) };
324 NonNull::new(req).map(|p| unsafe { Request::from_ptr(p) })
325 }
326
327 pub fn queue_request(&self, req: Request) -> io::Result<()> {
332 let ptr = req.ptr.as_ptr();
333 self.state.lock().unwrap().requests.insert(ptr, req);
334
335 let ret = unsafe { libcamera_camera_queue_request(self.ptr.as_ptr(), ptr) };
336
337 if ret < 0 {
338 Err(io::Error::from_raw_os_error(ret))
339 } else {
340 Ok(())
341 }
342 }
343
344 pub fn start(&mut self, controls: Option<&ControlList>) -> io::Result<()> {
348 let ctrl_ptr = controls.map(|c| c.ptr()).unwrap_or(core::ptr::null_mut());
349 let ret = unsafe { libcamera_camera_start(self.ptr.as_ptr(), ctrl_ptr) };
350 if ret < 0 {
351 Err(io::Error::from_raw_os_error(ret))
352 } else {
353 Ok(())
354 }
355 }
356
357 pub fn stop(&mut self) -> io::Result<()> {
361 let ret = unsafe { libcamera_camera_stop(self.ptr.as_ptr()) };
362 if ret < 0 {
363 Err(io::Error::from_raw_os_error(ret))
364 } else {
365 Ok(())
366 }
367 }
368}
369
370impl<'d> Deref for ActiveCamera<'d> {
371 type Target = Camera<'d>;
372
373 fn deref(&self) -> &Self::Target {
374 &self.cam
375 }
376}
377
378impl DerefMut for ActiveCamera<'_> {
379 fn deref_mut(&mut self) -> &mut Self::Target {
380 &mut self.cam
381 }
382}
383
384impl Drop for ActiveCamera<'_> {
385 fn drop(&mut self) {
386 unsafe {
387 libcamera_camera_request_completed_disconnect(self.ptr.as_ptr(), self.request_completed_handle);
388 libcamera_camera_stop(self.ptr.as_ptr());
389 libcamera_camera_release(self.ptr.as_ptr());
390 }
391 }
392}