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