libcamera/
request.rs

1#![allow(clippy::manual_strip)]
2
3use std::{any::Any, collections::HashMap, io, marker::PhantomData, ptr::NonNull};
4
5use bitflags::bitflags;
6use libcamera_sys::*;
7
8use crate::{control::ControlList, fence::Fence, framebuffer::AsFrameBuffer, stream::Stream};
9
10/// Non-owning view of a libcamera request.
11pub struct RequestRef<'d> {
12    pub(crate) ptr: NonNull<libcamera_request_t>,
13    _phantom: PhantomData<&'d ()>,
14}
15
16impl<'d> RequestRef<'d> {
17    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_request_t>) -> Self {
18        Self {
19            ptr,
20            _phantom: Default::default(),
21        }
22    }
23
24    pub fn controls(&self) -> &ControlList {
25        unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
26    }
27
28    pub fn metadata(&self) -> &ControlList {
29        unsafe {
30            ControlList::from_ptr(NonNull::new(libcamera_request_metadata(self.ptr.as_ptr()).cast_mut()).unwrap())
31        }
32    }
33
34    pub fn find_buffer(&self, stream: &Stream) -> Option<*mut libcamera_framebuffer_t> {
35        let ptr = unsafe { libcamera_request_find_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr()) };
36        NonNull::new(ptr).map(|p| p.as_ptr())
37    }
38
39    pub fn has_pending_buffers(&self) -> bool {
40        unsafe { libcamera_request_has_pending_buffers(self.ptr.as_ptr()) }
41    }
42
43    pub fn to_string_repr(&self) -> String {
44        unsafe {
45            let ptr = libcamera_request_to_string(self.ptr.as_ptr());
46            if ptr.is_null() {
47                return String::new();
48            }
49            let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned();
50            libc::free(ptr.cast());
51            s
52        }
53    }
54
55    /// Iterate over buffers attached to this request as (Stream, framebuffer pointer).
56    pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> {
57        RequestBufferMapIter::new(self.ptr)
58    }
59
60    /// Returns auto-incrementing sequence number of the capture
61    pub fn sequence(&self) -> u32 {
62        unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
63    }
64
65    /// Returns request identifier that was provided in
66    /// [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request).
67    ///
68    /// Returns zero if cookie was not provided.
69    pub fn cookie(&self) -> u64 {
70        unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
71    }
72
73    /// Capture request status
74    pub fn status(&self) -> RequestStatus {
75        RequestStatus::try_from(unsafe { libcamera_request_status(self.ptr.as_ptr()) }).unwrap()
76    }
77}
78
79unsafe impl Send for RequestRef<'_> {}
80
81/// Status of [Request]
82#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub enum RequestStatus {
84    /// Request is ready to be executed by [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request)
85    Pending,
86    /// Request was executed successfully
87    Complete,
88    /// Request was cancelled, most likely due to call to [ActiveCamera::stop()](crate::camera::ActiveCamera::stop)
89    Cancelled,
90}
91
92impl TryFrom<libcamera_request_status_t> for RequestStatus {
93    type Error = String;
94
95    fn try_from(value: libcamera_request_status_t) -> Result<Self, Self::Error> {
96        match value {
97            libcamera_request_status::LIBCAMERA_REQUEST_STATUS_PENDING => Ok(Self::Pending),
98            libcamera_request_status::LIBCAMERA_REQUEST_STATUS_COMPLETE => Ok(Self::Complete),
99            libcamera_request_status::LIBCAMERA_REQUEST_STATUS_CANCELLED => Ok(Self::Cancelled),
100            _ => Err(format!("Unknown libcamera_request_status: {value}")),
101        }
102    }
103}
104
105bitflags! {
106    /// Flags to control the behaviour of [Request::reuse()].
107    pub struct ReuseFlag: u32 {
108        /// Reuse the buffers that were previously added by [Request::add_buffer()].
109        const REUSE_BUFFERS = 1 << 0;
110    }
111}
112
113/// A camera capture request.
114///
115/// Capture requests are created by [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request)
116/// and scheduled for execution by [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request).
117/// Completed requests are returned by request completed callback (see
118/// [ActiveCamera::on_request_completed()](crate::camera::ActiveCamera::on_request_completed)) and can (should) be
119/// reused by calling [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request) again.
120pub struct Request {
121    pub(crate) ptr: NonNull<libcamera_request_t>,
122    buffers: HashMap<Stream, Box<dyn Any + 'static>>,
123}
124
125impl Request {
126    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_request_t>) -> Self {
127        Self {
128            ptr,
129            buffers: Default::default(),
130        }
131    }
132
133    /// Returns an immutable reference of request controls.
134    ///
135    /// See [controls](crate::controls) for available items.
136    pub fn controls(&self) -> &ControlList {
137        unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
138    }
139
140    /// Returns a mutable reference of request controls.
141    ///
142    /// See [controls](crate::controls) for available items.
143    pub fn controls_mut(&mut self) -> &mut ControlList {
144        unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
145    }
146
147    /// Returns request metadata, which contains information relevant to the request execution (i.e. capture timestamp).
148    ///
149    /// See [controls](crate::controls) for available items.
150    pub fn metadata(&self) -> &ControlList {
151        unsafe {
152            ControlList::from_ptr(NonNull::new(libcamera_request_metadata(self.ptr.as_ptr()).cast_mut()).unwrap())
153        }
154    }
155
156    /// Attaches framebuffer to the request.
157    ///
158    /// Buffers can only be attached once. To access framebuffer after executing request use [Self::buffer()] or
159    /// [Self::buffer_mut()].
160    pub fn add_buffer<T: AsFrameBuffer + Any>(&mut self, stream: &Stream, buffer: T) -> io::Result<()> {
161        let ret =
162            unsafe { libcamera_request_add_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr(), buffer.ptr().as_ptr()) };
163        if ret < 0 {
164            Err(io::Error::from_raw_os_error(-ret))
165        } else {
166            self.buffers.insert(*stream, Box::new(buffer));
167            Ok(())
168        }
169    }
170
171    /// Attaches framebuffer to the request with an optional acquire fence (fd is consumed).
172    pub fn add_buffer_with_fence<T: AsFrameBuffer + Any>(
173        &mut self,
174        stream: &Stream,
175        buffer: T,
176        fence: Option<Fence>,
177    ) -> io::Result<()> {
178        let fence_ptr = fence.map(Fence::into_raw).unwrap_or(std::ptr::null_mut());
179
180        let ret = unsafe {
181            libcamera_request_add_buffer_with_fence(
182                self.ptr.as_ptr(),
183                stream.ptr.as_ptr(),
184                buffer.ptr().as_ptr(),
185                fence_ptr,
186            )
187        };
188        if ret < 0 {
189            Err(io::Error::from_raw_os_error(-ret))
190        } else {
191            self.buffers.insert(*stream, Box::new(buffer));
192            Ok(())
193        }
194    }
195
196    /// Returns a reference to the buffer that was attached with [Self::add_buffer()].
197    ///
198    /// `T` must be equal to the type used in [Self::add_buffer()], otherwise this will return None.
199    pub fn buffer<T: 'static>(&self, stream: &Stream) -> Option<&T> {
200        self.buffers.get(stream).and_then(|b| b.downcast_ref())
201    }
202
203    /// Returns a mutable reference to the buffer that was attached with [Self::add_buffer()].
204    ///
205    /// `T` must be equal to the type used in [Self::add_buffer()], otherwise this will return None.
206    pub fn buffer_mut<T: 'static>(&mut self, stream: &Stream) -> Option<&mut T> {
207        self.buffers.get_mut(stream).and_then(|b| b.downcast_mut())
208    }
209
210    pub(crate) fn stream_for_buffer_ptr(&self, fb_ptr: *mut libcamera_framebuffer_t) -> Option<Stream> {
211        self.buffers_iter()
212            .find_map(|(s, ptr)| if ptr == fb_ptr { Some(s) } else { None })
213    }
214
215    /// Returns the buffer attached to a stream (raw pointer).
216    pub fn find_buffer(&self, stream: &Stream) -> Option<*mut libcamera_framebuffer_t> {
217        let ptr = unsafe { libcamera_request_find_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr()) };
218        NonNull::new(ptr).map(|p| p.as_ptr())
219    }
220
221    pub fn has_pending_buffers(&self) -> bool {
222        unsafe { libcamera_request_has_pending_buffers(self.ptr.as_ptr()) }
223    }
224
225    pub fn to_string_repr(&self) -> String {
226        unsafe {
227            let ptr = libcamera_request_to_string(self.ptr.as_ptr());
228            if ptr.is_null() {
229                return String::new();
230            }
231            let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned();
232            libc::free(ptr.cast());
233            s
234        }
235    }
236
237    /// Iterate over buffers attached to this request as (Stream, framebuffer pointer).
238    pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> {
239        RequestBufferMapIter::new(self.ptr)
240    }
241
242    /// Returns auto-incrementing sequence number of the capture
243    pub fn sequence(&self) -> u32 {
244        unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
245    }
246
247    /// Returns request identifier that was provided in
248    /// [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request).
249    ///
250    /// Returns zero if cookie was not provided.
251    pub fn cookie(&self) -> u64 {
252        unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
253    }
254
255    /// Capture request status
256    pub fn status(&self) -> RequestStatus {
257        RequestStatus::try_from(unsafe { libcamera_request_status(self.ptr.as_ptr()) }).unwrap()
258    }
259
260    /// Reset the request for reuse.
261    ///
262    /// Reset the status and controls associated with the request, to allow it to be reused and requeued without
263    /// destruction. This function shall be called prior to queueing the request to the camera, in lieu of
264    /// constructing a new request. The application can reuse the buffers that were previously added to the request
265    /// via [Self::add_buffer()] by setting flags to [ReuseFlag::REUSE_BUFFERS].
266    pub fn reuse(&mut self, flags: ReuseFlag) {
267        unsafe { libcamera_request_reuse(self.ptr.as_ptr(), flags.bits()) }
268        // Mirror libcamera behaviour: unless REUSE_BUFFERS is set, drop our buffer map so callbacks
269        // and buffer() lookups can't return stale handles.
270        if !flags.contains(ReuseFlag::REUSE_BUFFERS) {
271            self.buffers.clear();
272        }
273    }
274}
275
276impl core::fmt::Debug for Request {
277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278        f.write_str(&self.to_string_repr())
279    }
280}
281
282impl Drop for Request {
283    fn drop(&mut self) {
284        unsafe { libcamera_request_destroy(self.ptr.as_ptr()) }
285    }
286}
287
288unsafe impl Send for Request {}
289
290pub struct RequestBufferMapIter<'d> {
291    iter: NonNull<libcamera_request_buffer_map_iter_t>,
292    _phantom: core::marker::PhantomData<&'d libcamera_request_buffer_map_t>,
293}
294
295impl<'d> RequestBufferMapIter<'d> {
296    pub fn new(req_ptr: NonNull<libcamera_request_t>) -> Self {
297        let map = unsafe { libcamera_request_buffers(req_ptr.as_ptr()) };
298        let iter = NonNull::new(unsafe { libcamera_request_buffer_map_iter(map.cast_mut()) }).unwrap();
299        Self {
300            iter,
301            _phantom: Default::default(),
302        }
303    }
304}
305
306impl<'d> Iterator for RequestBufferMapIter<'d> {
307    type Item = (Stream, *mut libcamera_framebuffer_t);
308
309    fn next(&mut self) -> Option<Self::Item> {
310        if unsafe { libcamera_request_buffer_map_iter_end(self.iter.as_ptr()) } {
311            return None;
312        }
313        let stream = unsafe {
314            Stream::from_ptr(
315                NonNull::new(libcamera_request_buffer_map_iter_stream(self.iter.as_ptr()) as *mut _).unwrap(),
316            )
317        };
318        let buffer = unsafe { libcamera_request_buffer_map_iter_buffer(self.iter.as_ptr()) };
319        unsafe { libcamera_request_buffer_map_iter_next(self.iter.as_ptr()) };
320        Some((stream, buffer))
321    }
322}
323
324impl Drop for RequestBufferMapIter<'_> {
325    fn drop(&mut self) {
326        unsafe { libcamera_request_buffer_map_iter_destroy(self.iter.as_ptr()) }
327    }
328}