libcamera/request.rs
1#![allow(clippy::manual_strip)]
2
3use std::{any::Any, collections::HashMap, io, ptr::NonNull};
4
5use bitflags::bitflags;
6use libcamera_sys::*;
7
8use crate::{control::ControlList, framebuffer::AsFrameBuffer, stream::Stream};
9
10/// Status of [Request]
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum RequestStatus {
13 /// Request is ready to be executed by [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request)
14 Pending,
15 /// Request was executed successfully
16 Complete,
17 /// Request was cancelled, most likely due to call to [ActiveCamera::stop()](crate::camera::ActiveCamera::stop)
18 Cancelled,
19}
20
21impl TryFrom<libcamera_request_status_t> for RequestStatus {
22 type Error = String;
23
24 fn try_from(value: libcamera_request_status_t) -> Result<Self, Self::Error> {
25 match value {
26 libcamera_request_status::LIBCAMERA_REQUEST_STATUS_PENDING => Ok(Self::Pending),
27 libcamera_request_status::LIBCAMERA_REQUEST_STATUS_COMPLETE => Ok(Self::Complete),
28 libcamera_request_status::LIBCAMERA_REQUEST_STATUS_CANCELLED => Ok(Self::Cancelled),
29 _ => Err(format!("Unknown libcamera_request_status: {}", value)),
30 }
31 }
32}
33
34bitflags! {
35 /// Flags to control the behaviour of [Request::reuse()].
36 pub struct ReuseFlag: u32 {
37 /// Reuse the buffers that were previously added by [Request::add_buffer()].
38 const REUSE_BUFFERS = 1 << 0;
39 }
40}
41
42/// A camera capture request.
43///
44/// Capture requests are created by [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request)
45/// and scheduled for execution by [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request).
46/// Completed requests are returned by request completed callback (see
47/// [ActiveCamera::on_request_completed()](crate::camera::ActiveCamera::on_request_completed)) and can (should) be
48/// reused by calling [ActiveCamera::queue_request()](crate::camera::ActiveCamera::queue_request) again.
49pub struct Request {
50 pub(crate) ptr: NonNull<libcamera_request_t>,
51 buffers: HashMap<Stream, Box<dyn Any + 'static>>,
52}
53
54impl Request {
55 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_request_t>) -> Self {
56 Self {
57 ptr,
58 buffers: Default::default(),
59 }
60 }
61
62 /// Returns an immutable reference of request controls.
63 ///
64 /// See [controls](crate::controls) for available items.
65 pub fn controls(&self) -> &ControlList {
66 unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
67 }
68
69 /// Returns a mutable reference of request controls.
70 ///
71 /// See [controls](crate::controls) for available items.
72 pub fn controls_mut(&mut self) -> &mut ControlList {
73 unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
74 }
75
76 /// Returns request metadata, which contains information relevant to the request execution (i.e. capture timestamp).
77 ///
78 /// See [controls](crate::controls) for available items.
79 pub fn metadata(&self) -> &ControlList {
80 unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_metadata(self.ptr.as_ptr())).unwrap()) }
81 }
82
83 /// Attaches framebuffer to the request.
84 ///
85 /// Buffers can only be attached once. To access framebuffer after executing request use [Self::buffer()] or
86 /// [Self::buffer_mut()].
87 pub fn add_buffer<T: AsFrameBuffer + Any>(&mut self, stream: &Stream, buffer: T) -> io::Result<()> {
88 let ret =
89 unsafe { libcamera_request_add_buffer(self.ptr.as_ptr(), stream.ptr.as_ptr(), buffer.ptr().as_ptr()) };
90 if ret < 0 {
91 Err(io::Error::from_raw_os_error(ret))
92 } else {
93 self.buffers.insert(*stream, Box::new(buffer));
94 Ok(())
95 }
96 }
97
98 /// Returns a reference to the buffer that was attached with [Self::add_buffer()].
99 ///
100 /// `T` must be equal to the type used in [Self::add_buffer()], otherwise this will return None.
101 pub fn buffer<T: 'static>(&self, stream: &Stream) -> Option<&T> {
102 self.buffers.get(stream).and_then(|b| b.downcast_ref())
103 }
104
105 /// Returns a mutable reference to the buffer that was attached with [Self::add_buffer()].
106 ///
107 /// `T` must be equal to the type used in [Self::add_buffer()], otherwise this will return None.
108 pub fn buffer_mut<T: 'static>(&mut self, stream: &Stream) -> Option<&mut T> {
109 self.buffers.get_mut(stream).and_then(|b| b.downcast_mut())
110 }
111
112 /// Returns auto-incrementing sequence number of the capture
113 pub fn sequence(&self) -> u32 {
114 unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
115 }
116
117 /// Returns request identifier that was provided in
118 /// [ActiveCamera::create_request()](crate::camera::ActiveCamera::create_request).
119 ///
120 /// Returns zero if cookie was not provided.
121 pub fn cookie(&self) -> u64 {
122 unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
123 }
124
125 /// Capture request status
126 pub fn status(&self) -> RequestStatus {
127 RequestStatus::try_from(unsafe { libcamera_request_status(self.ptr.as_ptr()) }).unwrap()
128 }
129
130 /// Reset the request for reuse.
131 ///
132 /// Reset the status and controls associated with the request, to allow it to be reused and requeued without
133 /// destruction. This function shall be called prior to queueing the request to the camera, in lieu of
134 /// constructing a new request. The application can reuse the buffers that were previously added to the request
135 /// via [Self::add_buffer()] by setting flags to [ReuseFlag::REUSE_BUFFERS].
136 pub fn reuse(&mut self, flags: ReuseFlag) {
137 unsafe { libcamera_request_reuse(self.ptr.as_ptr(), flags.bits()) }
138 }
139}
140
141impl core::fmt::Debug for Request {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 f.debug_struct("Request")
144 .field("seq", &self.sequence())
145 .field("status", &self.status())
146 .field("cookie", &self.cookie())
147 .finish()
148 }
149}
150
151impl Drop for Request {
152 fn drop(&mut self) {
153 unsafe { libcamera_request_destroy(self.ptr.as_ptr()) }
154 }
155}
156
157unsafe impl Send for Request {}