libcamera/
framebuffer.rs

1use std::{marker::PhantomData, ptr::NonNull};
2
3use libcamera_sys::*;
4use num_enum::{IntoPrimitive, TryFromPrimitive};
5
6use crate::utils::Immutable;
7
8#[derive(Debug, Clone, Copy, Eq, PartialEq, TryFromPrimitive, IntoPrimitive)]
9#[repr(u32)]
10pub enum FrameMetadataStatus {
11    Success = libcamera_frame_metadata_status::LIBCAMERA_FRAME_METADATA_STATUS_SUCCESS,
12    Error = libcamera_frame_metadata_status::LIBCAMERA_FRAME_METADATA_STATUS_ERROR,
13    Cancelled = libcamera_frame_metadata_status::LIBCAMERA_FRAME_METADATA_STATUS_CANCELLED,
14}
15
16pub type FrameMetadataPlane = libcamera_frame_metadata_plane_t;
17
18pub struct FrameMetadataPlanes {
19    pub(crate) ptr: NonNull<libcamera_frame_metadata_planes_t>,
20}
21
22impl FrameMetadataPlanes {
23    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_frame_metadata_planes_t>) -> Self {
24        Self { ptr }
25    }
26
27    /// Number of planes within framebuffer metadata.
28    ///
29    /// Should be consistent with other planes within framebuffer.
30    pub fn len(&self) -> usize {
31        unsafe { libcamera_frame_metadata_planes_size(self.ptr.as_ptr()) as _ }
32    }
33
34    /// Returns `true` if there are no planes.
35    pub fn is_empty(&self) -> bool {
36        self.len() == 0
37    }
38
39    /// Returns framebuffer plane metadata at a given index.
40    ///
41    /// Return None if given index is out of range of available planes.
42    pub fn get(&self, index: usize) -> Option<FrameMetadataPlane> {
43        if index >= self.len() {
44            None
45        } else {
46            Some(unsafe { libcamera_frame_metadata_planes_at(self.ptr.as_ptr(), index as _).read() })
47        }
48    }
49}
50
51impl core::fmt::Debug for FrameMetadataPlanes {
52    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53        let mut list = f.debug_list();
54        for plane in self.into_iter() {
55            list.entry(&plane);
56        }
57        list.finish()
58    }
59}
60
61impl Drop for FrameMetadataPlanes {
62    fn drop(&mut self) {
63        unsafe { libcamera_frame_metadata_planes_destroy(self.ptr.as_ptr()) }
64    }
65}
66
67impl<'d> IntoIterator for &'d FrameMetadataPlanes {
68    type Item = FrameMetadataPlane;
69
70    type IntoIter = FrameMetadataPlanesIterator<'d>;
71
72    fn into_iter(self) -> Self::IntoIter {
73        FrameMetadataPlanesIterator { planes: self, index: 0 }
74    }
75}
76
77pub struct FrameMetadataPlanesIterator<'d> {
78    planes: &'d FrameMetadataPlanes,
79    index: usize,
80}
81
82impl Iterator for FrameMetadataPlanesIterator<'_> {
83    type Item = FrameMetadataPlane;
84
85    fn next(&mut self) -> Option<Self::Item> {
86        if let Some(plane) = self.planes.get(self.index) {
87            self.index += 1;
88            Some(plane)
89        } else {
90            None
91        }
92    }
93}
94
95pub struct FrameMetadataRef<'d> {
96    pub(crate) ptr: NonNull<libcamera_frame_metadata_t>,
97    _phantom: PhantomData<&'d ()>,
98}
99
100impl FrameMetadataRef<'_> {
101    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_frame_metadata_t>) -> Self {
102        Self {
103            ptr,
104            _phantom: Default::default(),
105        }
106    }
107
108    pub fn status(&self) -> FrameMetadataStatus {
109        FrameMetadataStatus::try_from(unsafe { libcamera_frame_metadata_status(self.ptr.as_ptr()) }).unwrap()
110    }
111
112    pub fn sequence(&self) -> u32 {
113        unsafe { libcamera_frame_metadata_sequence(self.ptr.as_ptr()) }
114    }
115
116    pub fn timestamp(&self) -> u64 {
117        unsafe { libcamera_frame_metadata_timestamp(self.ptr.as_ptr()) }
118    }
119
120    pub fn planes(&self) -> FrameMetadataPlanes {
121        unsafe {
122            FrameMetadataPlanes::from_ptr(NonNull::new(libcamera_frame_metadata_planes(self.ptr.as_ptr())).unwrap())
123        }
124    }
125}
126
127impl core::fmt::Debug for FrameMetadataRef<'_> {
128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129        f.debug_struct("FrameMetadataRef")
130            .field("status", &self.status())
131            .field("sequence", &self.sequence())
132            .field("timestamp", &self.timestamp())
133            .field("planes", &self.planes())
134            .finish()
135    }
136}
137
138pub struct FrameBufferPlaneRef<'d> {
139    pub(crate) ptr: NonNull<libcamera_framebuffer_plane_t>,
140    _phantom: PhantomData<&'d ()>,
141}
142
143impl FrameBufferPlaneRef<'_> {
144    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_framebuffer_plane_t>) -> Self {
145        Self {
146            ptr,
147            _phantom: Default::default(),
148        }
149    }
150
151    /// File descriptor to the framebuffer plane data.
152    ///
153    /// Multiple planes may point to the same file descriptor at different offsets.
154    pub fn fd(&self) -> i32 {
155        unsafe { libcamera_framebuffer_plane_fd(self.ptr.as_ptr()) }
156    }
157
158    /// Offset of data within the file descriptor.
159    pub fn offset(&self) -> Option<usize> {
160        if unsafe { libcamera_framebuffer_plane_offset_valid(self.ptr.as_ptr()) } {
161            Some(unsafe { libcamera_framebuffer_plane_offset(self.ptr.as_ptr()) as _ })
162        } else {
163            None
164        }
165    }
166
167    /// Data length of the plane in bytes
168    pub fn len(&self) -> usize {
169        unsafe { libcamera_framebuffer_plane_length(self.ptr.as_ptr()) as _ }
170    }
171
172    /// Returns `true` if plane has no data
173    pub fn is_empty(&self) -> bool {
174        self.len() == 0
175    }
176}
177
178impl core::fmt::Debug for FrameBufferPlaneRef<'_> {
179    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
180        f.debug_struct("FrameBufferPlaneRef")
181            .field("fd", &self.fd())
182            .field("offset", &self.offset())
183            .field("len", &self.len())
184            .finish()
185    }
186}
187
188pub struct FrameBufferPlanesRef<'d> {
189    pub(crate) ptr: NonNull<libcamera_framebuffer_planes_t>,
190    _phantom: PhantomData<&'d ()>,
191}
192
193impl FrameBufferPlanesRef<'_> {
194    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_framebuffer_planes_t>) -> Self {
195        Self {
196            ptr,
197            _phantom: Default::default(),
198        }
199    }
200
201    /// Number of planes within framebuffer
202    pub fn len(&self) -> usize {
203        unsafe { libcamera_framebuffer_planes_size(self.ptr.as_ptr()) as _ }
204    }
205
206    /// Returns `true` if framebuffer has no planes
207    pub fn is_empty(&self) -> bool {
208        self.len() == 0
209    }
210
211    /// Returns framebuffer plane at a given index
212    pub fn get(&self, index: usize) -> Option<Immutable<FrameBufferPlaneRef<'_>>> {
213        if index >= self.len() {
214            None
215        } else {
216            Some(Immutable(unsafe {
217                FrameBufferPlaneRef::from_ptr(
218                    NonNull::new(libcamera_framebuffer_planes_at(self.ptr.as_ptr(), index as _)).unwrap(),
219                )
220            }))
221        }
222    }
223}
224
225impl core::fmt::Debug for FrameBufferPlanesRef<'_> {
226    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
227        let mut list = f.debug_list();
228        for plane in self.into_iter() {
229            list.entry(&plane);
230        }
231        list.finish()
232    }
233}
234
235impl<'d> IntoIterator for &'d FrameBufferPlanesRef<'d> {
236    type Item = Immutable<FrameBufferPlaneRef<'d>>;
237
238    type IntoIter = FrameBufferPlanesRefIterator<'d>;
239
240    fn into_iter(self) -> Self::IntoIter {
241        FrameBufferPlanesRefIterator { planes: self, index: 0 }
242    }
243}
244
245pub struct FrameBufferPlanesRefIterator<'d> {
246    planes: &'d FrameBufferPlanesRef<'d>,
247    index: usize,
248}
249
250impl<'d> Iterator for FrameBufferPlanesRefIterator<'d> {
251    type Item = Immutable<FrameBufferPlaneRef<'d>>;
252
253    fn next(&mut self) -> Option<Self::Item> {
254        if let Some(plane) = self.planes.get(self.index) {
255            self.index += 1;
256            Some(plane)
257        } else {
258            None
259        }
260    }
261}
262
263pub trait AsFrameBuffer: Send {
264    /// Returns raw framebuffer used by libcamera.
265    ///
266    /// It is expected that metadata status field is initialized with u32::MAX on a new buffer, which indicates that
267    /// metadata is not yet available. This "hackfix" prevents read of uninitialized data in [Self::metadata()].
268    ///
269    /// # Safety
270    ///
271    /// This function must return a valid instance of `libcamera::FrameBuffer`.
272    unsafe fn ptr(&self) -> NonNull<libcamera_framebuffer_t>;
273
274    /// Returns framebuffer metadata information.
275    ///
276    /// Only available after associated [Request](crate::request::Request) has completed.
277    fn metadata(&self) -> Option<Immutable<FrameMetadataRef<'_>>> {
278        let ptr = NonNull::new(unsafe { libcamera_framebuffer_metadata(self.ptr().as_ptr()) }.cast_mut()).unwrap();
279        if unsafe { libcamera_frame_metadata_status(ptr.as_ptr()) } != u32::MAX {
280            Some(unsafe { Immutable(FrameMetadataRef::from_ptr(ptr)) })
281        } else {
282            None
283        }
284    }
285
286    /// Provides access to framebuffer data by exposing file descriptors, offsets and lengths of the planes.
287    fn planes(&self) -> Immutable<FrameBufferPlanesRef<'_>> {
288        unsafe {
289            Immutable(FrameBufferPlanesRef::from_ptr(
290                NonNull::new(libcamera_framebuffer_planes(self.ptr().as_ptr()).cast_mut()).unwrap(),
291            ))
292        }
293    }
294}