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