1use std::{
2 io,
3 marker::PhantomData,
4 os::fd::{IntoRawFd, OwnedFd},
5 ptr::NonNull,
6};
7
8use libcamera_sys::*;
9use num_enum::{IntoPrimitive, TryFromPrimitive};
10
11use crate::{fence::Fence, utils::Immutable};
12
13#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
14#[repr(u32)]
15pub enum FrameMetadataStatus {
16 Success = libcamera_frame_metadata_status::LIBCAMERA_FRAME_METADATA_STATUS_SUCCESS,
17 Error = libcamera_frame_metadata_status::LIBCAMERA_FRAME_METADATA_STATUS_ERROR,
18 Cancelled = libcamera_frame_metadata_status::LIBCAMERA_FRAME_METADATA_STATUS_CANCELLED,
19 Startup = libcamera_frame_metadata_status::LIBCAMERA_FRAME_METADATA_STATUS_STARTUP,
20}
21
22pub type FrameMetadataPlane = libcamera_frame_metadata_plane_t;
23
24pub struct FrameMetadataPlanes {
25 pub(crate) ptr: NonNull<libcamera_frame_metadata_planes_t>,
26}
27
28impl FrameMetadataPlanes {
29 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_frame_metadata_planes_t>) -> Self {
30 Self { ptr }
31 }
32
33 pub fn len(&self) -> usize {
37 unsafe { libcamera_frame_metadata_planes_size(self.ptr.as_ptr()) as _ }
38 }
39
40 pub fn is_empty(&self) -> bool {
42 self.len() == 0
43 }
44
45 pub fn get(&self, index: usize) -> Option<FrameMetadataPlane> {
49 if index >= self.len() {
50 None
51 } else {
52 Some(unsafe { libcamera_frame_metadata_planes_at(self.ptr.as_ptr(), index as _).read() })
53 }
54 }
55}
56
57impl core::fmt::Debug for FrameMetadataPlanes {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 let mut list = f.debug_list();
60 for plane in self.into_iter() {
61 list.entry(&plane);
62 }
63 list.finish()
64 }
65}
66
67impl Drop for FrameMetadataPlanes {
68 fn drop(&mut self) {
69 unsafe { libcamera_frame_metadata_planes_destroy(self.ptr.as_ptr()) }
70 }
71}
72
73impl<'d> IntoIterator for &'d FrameMetadataPlanes {
74 type Item = FrameMetadataPlane;
75
76 type IntoIter = FrameMetadataPlanesIterator<'d>;
77
78 fn into_iter(self) -> Self::IntoIter {
79 FrameMetadataPlanesIterator { planes: self, index: 0 }
80 }
81}
82
83pub struct FrameMetadataPlanesIterator<'d> {
84 planes: &'d FrameMetadataPlanes,
85 index: usize,
86}
87
88impl Iterator for FrameMetadataPlanesIterator<'_> {
89 type Item = FrameMetadataPlane;
90
91 fn next(&mut self) -> Option<Self::Item> {
92 if let Some(plane) = self.planes.get(self.index) {
93 self.index += 1;
94 Some(plane)
95 } else {
96 None
97 }
98 }
99}
100
101pub struct FrameMetadataRef<'d> {
102 pub(crate) ptr: NonNull<libcamera_frame_metadata_t>,
103 _phantom: PhantomData<&'d ()>,
104}
105
106impl FrameMetadataRef<'_> {
107 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_frame_metadata_t>) -> Self {
108 Self {
109 ptr,
110 _phantom: Default::default(),
111 }
112 }
113
114 pub fn status(&self) -> FrameMetadataStatus {
115 FrameMetadataStatus::try_from(unsafe { libcamera_frame_metadata_status(self.ptr.as_ptr()) }).unwrap()
116 }
117
118 pub fn sequence(&self) -> u32 {
119 unsafe { libcamera_frame_metadata_sequence(self.ptr.as_ptr()) }
120 }
121
122 pub fn timestamp(&self) -> u64 {
123 unsafe { libcamera_frame_metadata_timestamp(self.ptr.as_ptr()) }
124 }
125
126 pub fn planes(&self) -> FrameMetadataPlanes {
127 unsafe {
128 FrameMetadataPlanes::from_ptr(NonNull::new(libcamera_frame_metadata_planes(self.ptr.as_ptr())).unwrap())
129 }
130 }
131}
132
133impl core::fmt::Debug for FrameMetadataRef<'_> {
134 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135 f.debug_struct("FrameMetadataRef")
136 .field("status", &self.status())
137 .field("sequence", &self.sequence())
138 .field("timestamp", &self.timestamp())
139 .field("planes", &self.planes())
140 .finish()
141 }
142}
143
144pub struct FrameBufferPlaneRef<'d> {
145 pub(crate) ptr: NonNull<libcamera_framebuffer_plane_t>,
146 _phantom: PhantomData<&'d ()>,
147}
148
149impl FrameBufferPlaneRef<'_> {
150 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_framebuffer_plane_t>) -> Self {
151 Self {
152 ptr,
153 _phantom: Default::default(),
154 }
155 }
156
157 pub fn fd(&self) -> i32 {
161 unsafe { libcamera_framebuffer_plane_fd(self.ptr.as_ptr()) }
162 }
163
164 pub fn offset(&self) -> Option<usize> {
166 if unsafe { libcamera_framebuffer_plane_offset_valid(self.ptr.as_ptr()) } {
167 Some(unsafe { libcamera_framebuffer_plane_offset(self.ptr.as_ptr()) as _ })
168 } else {
169 None
170 }
171 }
172
173 pub fn len(&self) -> usize {
175 unsafe { libcamera_framebuffer_plane_length(self.ptr.as_ptr()) as _ }
176 }
177
178 pub fn is_empty(&self) -> bool {
180 self.len() == 0
181 }
182}
183
184impl core::fmt::Debug for FrameBufferPlaneRef<'_> {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 f.debug_struct("FrameBufferPlaneRef")
187 .field("fd", &self.fd())
188 .field("offset", &self.offset())
189 .field("len", &self.len())
190 .finish()
191 }
192}
193
194pub struct FrameBufferPlanesRef<'d> {
195 pub(crate) ptr: NonNull<libcamera_framebuffer_planes_t>,
196 _phantom: PhantomData<&'d ()>,
197}
198
199impl FrameBufferPlanesRef<'_> {
200 pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_framebuffer_planes_t>) -> Self {
201 Self {
202 ptr,
203 _phantom: Default::default(),
204 }
205 }
206
207 pub fn len(&self) -> usize {
209 unsafe { libcamera_framebuffer_planes_size(self.ptr.as_ptr()) as _ }
210 }
211
212 pub fn is_empty(&self) -> bool {
214 self.len() == 0
215 }
216
217 pub fn get(&self, index: usize) -> Option<Immutable<FrameBufferPlaneRef<'_>>> {
219 if index >= self.len() {
220 None
221 } else {
222 Some(Immutable(unsafe {
223 FrameBufferPlaneRef::from_ptr(
224 NonNull::new(libcamera_framebuffer_planes_at(self.ptr.as_ptr(), index as _)).unwrap(),
225 )
226 }))
227 }
228 }
229}
230
231impl core::fmt::Debug for FrameBufferPlanesRef<'_> {
232 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
233 let mut list = f.debug_list();
234 for plane in self.into_iter() {
235 list.entry(&plane);
236 }
237 list.finish()
238 }
239}
240
241impl Drop for FrameBufferPlanesRef<'_> {
242 fn drop(&mut self) {
243 unsafe { libcamera_framebuffer_planes_destroy(self.ptr.as_ptr()) }
244 }
245}
246
247impl<'d> IntoIterator for &'d FrameBufferPlanesRef<'d> {
248 type Item = Immutable<FrameBufferPlaneRef<'d>>;
249
250 type IntoIter = FrameBufferPlanesRefIterator<'d>;
251
252 fn into_iter(self) -> Self::IntoIter {
253 FrameBufferPlanesRefIterator { planes: self, index: 0 }
254 }
255}
256
257pub struct FrameBufferPlanesRefIterator<'d> {
258 planes: &'d FrameBufferPlanesRef<'d>,
259 index: usize,
260}
261
262impl<'d> Iterator for FrameBufferPlanesRefIterator<'d> {
263 type Item = Immutable<FrameBufferPlaneRef<'d>>;
264
265 fn next(&mut self) -> Option<Self::Item> {
266 if let Some(plane) = self.planes.get(self.index) {
267 self.index += 1;
268 Some(plane)
269 } else {
270 None
271 }
272 }
273}
274
275pub trait AsFrameBuffer: Send {
276 unsafe fn ptr(&self) -> NonNull<libcamera_framebuffer_t>;
285
286 fn metadata(&self) -> Option<Immutable<FrameMetadataRef<'_>>> {
290 let ptr = NonNull::new(unsafe { libcamera_framebuffer_metadata(self.ptr().as_ptr()) }.cast_mut()).unwrap();
291 if unsafe { libcamera_frame_metadata_status(ptr.as_ptr()) } != u32::MAX {
292 Some(unsafe { Immutable(FrameMetadataRef::from_ptr(ptr)) })
293 } else {
294 None
295 }
296 }
297
298 fn planes(&self) -> Immutable<FrameBufferPlanesRef<'_>> {
300 unsafe {
301 Immutable(FrameBufferPlanesRef::from_ptr(
302 NonNull::new(libcamera_framebuffer_planes(self.ptr().as_ptr())).unwrap(),
303 ))
304 }
305 }
306
307 fn cookie(&self) -> u64 {
309 unsafe { libcamera_framebuffer_cookie(self.ptr().as_ptr()) }
310 }
311
312 fn set_cookie(&self, cookie: u64) {
314 unsafe { libcamera_framebuffer_set_cookie(self.ptr().as_ptr(), cookie) }
315 }
316
317 fn release_fence(&self) -> Option<Fence> {
321 unsafe { Fence::from_ptr(libcamera_framebuffer_release_fence_handle(self.ptr().as_ptr())) }
322 }
323
324 fn request(&self) -> Option<crate::request::RequestRef<'_>> {
326 let ptr = unsafe { libcamera_framebuffer_request(self.ptr().as_ptr()) };
327 NonNull::new(ptr).map(|p| unsafe { crate::request::RequestRef::from_ptr(p) })
328 }
329}
330
331pub struct FrameBufferPlane {
333 pub fd: OwnedFd,
334 pub offset: u32,
335 pub length: u32,
336}
337
338pub struct OwnedFrameBuffer {
340 ptr: NonNull<libcamera_framebuffer_t>,
341}
342
343unsafe impl Send for OwnedFrameBuffer {}
344
345impl OwnedFrameBuffer {
346 pub fn new(planes: Vec<FrameBufferPlane>, cookie: Option<u64>) -> io::Result<Self> {
348 if planes.is_empty() {
349 return Err(io::Error::new(io::ErrorKind::InvalidInput, "no planes provided"));
350 }
351
352 let mut infos: Vec<libcamera_framebuffer_plane_info> = Vec::with_capacity(planes.len());
353 let mut raw_fds = Vec::with_capacity(planes.len());
354
355 for plane in planes {
356 if plane.offset == u32::MAX || plane.length == 0 {
357 return Err(io::Error::new(
358 io::ErrorKind::InvalidInput,
359 "plane offset/length must be valid and non-zero",
360 ));
361 }
362 let fd = plane.fd.into_raw_fd();
363 raw_fds.push(fd);
364 infos.push(libcamera_framebuffer_plane_info {
365 fd,
366 offset: plane.offset,
367 length: plane.length,
368 });
369 }
370
371 let ptr = unsafe { libcamera_framebuffer_create(infos.as_ptr(), infos.len(), cookie.unwrap_or(0)) };
372
373 if let Some(ptr) = NonNull::new(ptr) {
374 unsafe {
376 libcamera_framebuffer_metadata(ptr.as_ptr())
377 .cast_mut()
378 .cast::<u32>()
379 .write(u32::MAX)
380 };
381 Ok(Self { ptr })
382 } else {
383 for fd in raw_fds {
384 unsafe { libc::close(fd) };
385 }
386 Err(io::Error::last_os_error())
387 }
388 }
389}
390
391impl AsFrameBuffer for OwnedFrameBuffer {
392 unsafe fn ptr(&self) -> NonNull<libcamera_framebuffer_t> {
393 self.ptr
394 }
395}
396
397impl OwnedFrameBuffer {
398 pub fn is_contiguous(&self) -> bool {
400 let planes = self.planes();
401 if planes.is_empty() {
402 return false;
403 }
404 let mut entries: Vec<(i32, usize, usize)> = planes
406 .into_iter()
407 .filter_map(|p| p.offset().map(|off| (p.fd(), off, p.len())))
408 .collect();
409 if entries
411 .iter()
412 .map(|e| e.0)
413 .collect::<std::collections::HashSet<_>>()
414 .len()
415 != 1
416 {
417 return false;
418 }
419 entries.sort_by_key(|e| e.1);
420 let mut expected = entries[0].1;
422 for (_, off, len) in entries {
423 if off != expected {
424 return false;
425 }
426 expected = off + len;
427 }
428 true
429 }
430}
431
432impl core::fmt::Debug for OwnedFrameBuffer {
433 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
434 f.debug_struct("OwnedFrameBuffer")
435 .field("cookie", &self.cookie())
436 .field("planes", &self.planes())
437 .finish()
438 }
439}
440
441impl Drop for OwnedFrameBuffer {
442 fn drop(&mut self) {
443 unsafe { libcamera_framebuffer_destroy(self.ptr.as_ptr()) }
444 }
445}