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 {
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 pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> {
57 RequestBufferMapIter::new(self.ptr)
58 }
59
60 pub fn sequence(&self) -> u32 {
62 unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
63 }
64
65 pub fn cookie(&self) -> u64 {
70 unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
71 }
72
73 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
83pub enum RequestStatus {
84 Pending,
86 Complete,
88 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 pub struct ReuseFlag: u32 {
108 const REUSE_BUFFERS = 1 << 0;
110 }
111}
112
113pub 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 pub fn controls(&self) -> &ControlList {
137 unsafe { ControlList::from_ptr(NonNull::new(libcamera_request_controls(self.ptr.as_ptr())).unwrap()) }
138 }
139
140 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 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 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 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 pub fn buffer<T: 'static>(&self, stream: &Stream) -> Option<&T> {
200 self.buffers.get(stream).and_then(|b| b.downcast_ref())
201 }
202
203 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 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 pub fn buffers_iter(&self) -> RequestBufferMapIter<'_> {
239 RequestBufferMapIter::new(self.ptr)
240 }
241
242 pub fn sequence(&self) -> u32 {
244 unsafe { libcamera_request_sequence(self.ptr.as_ptr()) }
245 }
246
247 pub fn cookie(&self) -> u64 {
252 unsafe { libcamera_request_cookie(self.ptr.as_ptr()) }
253 }
254
255 pub fn status(&self) -> RequestStatus {
257 RequestStatus::try_from(unsafe { libcamera_request_status(self.ptr.as_ptr()) }).unwrap()
258 }
259
260 pub fn reuse(&mut self, flags: ReuseFlag) {
267 unsafe { libcamera_request_reuse(self.ptr.as_ptr(), flags.bits()) }
268 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}