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
10pub 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 pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> {
55 RequestBufferMapIter::new(self.ptr)
56 }
57
58 pub fn sequence(&self) -> u32 {
60 unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
61 }
62
63 pub fn cookie(&self) -> u64 {
68 unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
69 }
70
71 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81pub enum RequestStatus {
82 Pending,
84 Complete,
86 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 pub struct ReuseFlag: u32 {
106 const REUSE_BUFFERS = 1 << 0;
108 }
109}
110
111pub 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 pub fn controls(&self) -> &ControlList {
135 unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
136 }
137
138 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 pub fn metadata(&self) -> &ControlList {
149 unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_metadata(self.ptr.as_ptr())).unwrap()) }
150 }
151
152 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 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 pub fn buffer<T: 'static>(&self, stream: &Stream) -> Option<&T> {
196 self.buffers.get(stream).and_then(|b| b.downcast_ref())
197 }
198
199 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 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 pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> {
235 RequestBufferMapIter::new(self.ptr)
236 }
237
238 pub fn sequence(&self) -> u32 {
240 unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
241 }
242
243 pub fn cookie(&self) -> u64 {
248 unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
249 }
250
251 pub fn status(&self) -> RequestStatus {
253 RequestStatus::try_from(unsafe { libcamera_request_status(self.ptr.as_ptr()) }).unwrap()
254 }
255
256 pub fn reuse(&mut self, flags: ReuseFlag) {
263 unsafe { libcamera_request_reuse(self.ptr.as_ptr(), flags.bits()) }
264 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}