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 CameraConfiguration {
62 ptr: NonNull<libcamera_camera_configuration_t>,
63}
64
65impl CameraConfiguration {
66 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_configuration_t>) -> Self {
67 Self { ptr }
68 }
69
70 pub fn get(&self, index: usize) -> Option<Immutable<StreamConfigurationRef<'_>>> {
76 let ptr = unsafe { libcamera_camera_configuration_at(self.ptr.as_ptr(), index as _) };
77 NonNull::new(ptr).map(|p| Immutable(unsafe { StreamConfigurationRef::from_ptr(p) }))
78 }
79
80 pub fn get_mut(&mut self, index: usize) -> Option<StreamConfigurationRef<'_>> {
86 let ptr = unsafe { libcamera_camera_configuration_at(self.ptr.as_ptr(), index as _) };
87 NonNull::new(ptr).map(|p| unsafe { StreamConfigurationRef::from_ptr(p) })
88 }
89
90 pub fn len(&self) -> usize {
92 unsafe { libcamera_camera_configuration_size(self.ptr.as_ptr()) }
93 }
94
95 pub fn is_empty(&self) -> bool {
97 self.len() == 0
98 }
99
100 pub fn validate(&mut self) -> CameraConfigurationStatus {
102 unsafe { libcamera_camera_configuration_validate(self.ptr.as_ptr()) }
103 .try_into()
104 .unwrap()
105 }
106}
107
108impl core::fmt::Debug for CameraConfiguration {
109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
110 let mut list = f.debug_list();
111 for i in 0..self.len() {
112 list.entry(&self.get(i).unwrap().0);
113 }
114 list.finish()
115 }
116}
117
118impl Drop for CameraConfiguration {
119 fn drop(&mut self) {
120 unsafe { libcamera_camera_configuration_destroy(self.ptr.as_ptr()) }
121 }
122}
123
124pub struct Camera<'d> {
129 pub(crate) ptr: NonNull<libcamera_camera_t>,
130 _phantom: PhantomData<&'d ()>,
131}
132
133impl Camera<'_> {
134 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_t>) -> Self {
135 Self {
136 ptr,
137 _phantom: Default::default(),
138 }
139 }
140
141 pub fn id(&self) -> &str {
147 unsafe { CStr::from_ptr(libcamera_camera_id(self.ptr.as_ptr())) }
148 .to_str()
149 .unwrap()
150 }
151
152 pub fn controls(&self) -> &ControlInfoMap {
154 unsafe {
155 ControlInfoMap::from_ptr(NonNull::new(libcamera_camera_controls(self.ptr.as_ptr()).cast_mut()).unwrap())
156 }
157 }
158
159 pub fn properties(&self) -> &PropertyList {
163 unsafe {
164 PropertyList::from_ptr(NonNull::new(libcamera_camera_properties(self.ptr.as_ptr()).cast_mut()).unwrap())
165 }
166 }
167
168 pub fn generate_configuration(&self, roles: &[StreamRole]) -> Option<CameraConfiguration> {
174 let roles: Vec<libcamera_stream_role::Type> = roles.iter().map(|r| (*r).into()).collect();
175 let cfg =
176 unsafe { libcamera_camera_generate_configuration(self.ptr.as_ptr(), roles.as_ptr(), roles.len() as _) };
177 NonNull::new(cfg).map(|p| unsafe { CameraConfiguration::from_ptr(p) })
178 }
179
180 pub fn acquire(&self) -> io::Result<ActiveCamera<'_>> {
182 let ret = unsafe { libcamera_camera_acquire(self.ptr.as_ptr()) };
183 if ret < 0 {
184 Err(io::Error::from_raw_os_error(ret))
185 } else {
186 Ok(unsafe { ActiveCamera::from_ptr(NonNull::new(libcamera_camera_copy(self.ptr.as_ptr())).unwrap()) })
187 }
188 }
189}
190
191impl Drop for Camera<'_> {
192 fn drop(&mut self) {
193 unsafe { libcamera_camera_destroy(self.ptr.as_ptr()) }
194 }
195}
196
197extern "C" fn camera_request_completed_cb(ptr: *mut core::ffi::c_void, req: *mut libcamera_request_t) {
198 let mut state = unsafe { &*(ptr as *const Mutex<ActiveCameraState<'_>>) }
199 .lock()
200 .unwrap();
201 let req = state.requests.remove(&req).unwrap();
202
203 if let Some(cb) = &mut state.request_completed_cb {
204 cb(req);
205 }
206}
207
208#[derive(Default)]
209struct ActiveCameraState<'d> {
210 requests: HashMap<*mut libcamera_request_t, Request>,
213 request_completed_cb: Option<Box<dyn FnMut(Request) + Send + 'd>>,
215}
216
217pub struct ActiveCamera<'d> {
223 cam: Camera<'d>,
224 request_completed_handle: *mut libcamera_callback_handle_t,
226 state: Box<Mutex<ActiveCameraState<'d>>>,
228}
229
230impl<'d> ActiveCamera<'d> {
231 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_camera_t>) -> Self {
232 let mut state = Box::new(Mutex::new(ActiveCameraState::default()));
233
234 let request_completed_handle = unsafe {
235 libcamera_camera_request_completed_connect(
236 ptr.as_ptr(),
237 Some(camera_request_completed_cb),
238 state.as_mut() as *mut Mutex<ActiveCameraState<'_>> as *mut _,
240 )
241 };
242
243 Self {
244 cam: Camera::from_ptr(ptr),
245 request_completed_handle,
246 state,
247 }
248 }
249
250 pub fn on_request_completed(&mut self, cb: impl FnMut(Request) + Send + 'd) {
258 let mut state = self.state.lock().unwrap();
259 state.request_completed_cb = Some(Box::new(cb));
260 }
261
262 pub fn configure(&mut self, config: &mut CameraConfiguration) -> io::Result<()> {
266 let ret = unsafe { libcamera_camera_configure(self.ptr.as_ptr(), config.ptr.as_ptr()) };
267 if ret < 0 {
268 Err(io::Error::from_raw_os_error(ret))
269 } else {
270 Ok(())
271 }
272 }
273
274 pub fn create_request(&mut self, cookie: Option<u64>) -> Option<Request> {
284 let req = unsafe { libcamera_camera_create_request(self.ptr.as_ptr(), cookie.unwrap_or(0)) };
285 NonNull::new(req).map(|p| unsafe { Request::from_ptr(p) })
286 }
287
288 pub fn queue_request(&self, req: Request) -> io::Result<()> {
293 let ptr = req.ptr.as_ptr();
294 self.state.lock().unwrap().requests.insert(ptr, req);
295
296 let ret = unsafe { libcamera_camera_queue_request(self.ptr.as_ptr(), ptr) };
297
298 if ret < 0 {
299 Err(io::Error::from_raw_os_error(ret))
300 } else {
301 Ok(())
302 }
303 }
304
305 pub fn start(&mut self, controls: Option<&ControlList>) -> io::Result<()> {
309 let ctrl_ptr = controls.map(|c| c.ptr()).unwrap_or(core::ptr::null_mut());
310 let ret = unsafe { libcamera_camera_start(self.ptr.as_ptr(), ctrl_ptr) };
311 if ret < 0 {
312 Err(io::Error::from_raw_os_error(ret))
313 } else {
314 Ok(())
315 }
316 }
317
318 pub fn stop(&mut self) -> io::Result<()> {
322 let ret = unsafe { libcamera_camera_stop(self.ptr.as_ptr()) };
323 if ret < 0 {
324 Err(io::Error::from_raw_os_error(ret))
325 } else {
326 Ok(())
327 }
328 }
329}
330
331impl<'d> Deref for ActiveCamera<'d> {
332 type Target = Camera<'d>;
333
334 fn deref(&self) -> &Self::Target {
335 &self.cam
336 }
337}
338
339impl DerefMut for ActiveCamera<'_> {
340 fn deref_mut(&mut self) -> &mut Self::Target {
341 &mut self.cam
342 }
343}
344
345impl Drop for ActiveCamera<'_> {
346 fn drop(&mut self) {
347 unsafe {
348 libcamera_camera_request_completed_disconnect(self.ptr.as_ptr(), self.request_completed_handle);
349 libcamera_camera_stop(self.ptr.as_ptr());
350 libcamera_camera_release(self.ptr.as_ptr());
351 }
352 }
353}