libcamera/
framebuffer_allocator.rs

1use std::{
2    io,
3    ptr::NonNull,
4    sync::{Arc, Mutex},
5};
6
7use libcamera_sys::*;
8
9use crate::{camera::Camera, framebuffer::AsFrameBuffer, stream::Stream};
10
11/// Buffers are stored inside `libcamera_framebuffer_allocator_t` so we use Arc<FrameBufferAllocatorInstance>
12/// to keep the allocator alive as long as there are active buffers.
13struct FrameBufferAllocatorInstance {
14    ptr: NonNull<libcamera_framebuffer_allocator_t>,
15    /// List of streams for which buffers were allocated.
16    /// We use this list to free buffers on drop.
17    allocated_streams: Vec<NonNull<libcamera_stream_t>>,
18}
19
20unsafe impl Send for FrameBufferAllocatorInstance {}
21
22impl Drop for FrameBufferAllocatorInstance {
23    fn drop(&mut self) {
24        // Free allocated streams
25        for stream in self.allocated_streams.drain(..) {
26            unsafe {
27                libcamera_framebuffer_allocator_free(self.ptr.as_ptr(), stream.as_ptr());
28            }
29        }
30
31        unsafe { libcamera_framebuffer_allocator_destroy(self.ptr.as_ptr()) }
32    }
33}
34
35pub struct FrameBufferAllocator {
36    inner: Arc<Mutex<FrameBufferAllocatorInstance>>,
37}
38
39impl FrameBufferAllocator {
40    pub fn new(cam: &Camera<'_>) -> Self {
41        Self {
42            inner: Arc::new(Mutex::new(FrameBufferAllocatorInstance {
43                ptr: NonNull::new(unsafe { libcamera_framebuffer_allocator_create(cam.ptr.as_ptr()) }).unwrap(),
44                allocated_streams: Vec::new(),
45            })),
46        }
47    }
48
49    /// Allocate N buffers for a given stream, where N is equal to
50    /// [StreamConfigurationRef::get_buffer_count()](crate::stream::StreamConfigurationRef::get_buffer_count).
51    pub fn alloc(&mut self, stream: &Stream) -> io::Result<Vec<FrameBuffer>> {
52        let mut inner = self.inner.lock().unwrap();
53
54        let ret = unsafe { libcamera_framebuffer_allocator_allocate(inner.ptr.as_ptr(), stream.ptr.as_ptr()) };
55        if ret < 0 {
56            Err(io::Error::from_raw_os_error(ret))
57        } else {
58            inner.allocated_streams.push(stream.ptr);
59
60            let buffers = unsafe { libcamera_framebuffer_allocator_buffers(inner.ptr.as_ptr(), stream.ptr.as_ptr()) };
61
62            let len = unsafe { libcamera_framebuffer_list_size(buffers) };
63
64            Ok((0..len)
65                .map(|i| unsafe { libcamera_framebuffer_list_get(buffers, i) })
66                .map(|ptr| NonNull::new(ptr.cast_mut()).unwrap())
67                .map(|ptr| {
68                    // This is very very unsafe.
69                    // Setting first field of metadata (status) to u32::MAX, which is used as an indication that
70                    // metadata is unavailable. Otherwise all metadata fields are uninitialized and
71                    // there is no way to detect availability.
72                    unsafe {
73                        libcamera_framebuffer_metadata(ptr.as_ptr())
74                            .cast_mut()
75                            .cast::<u32>()
76                            .write(u32::MAX)
77                    };
78
79                    FrameBuffer {
80                        ptr,
81                        _alloc: self.inner.clone(),
82                    }
83                })
84                .collect())
85        }
86    }
87}
88
89pub struct FrameBuffer {
90    ptr: NonNull<libcamera_framebuffer_t>,
91    _alloc: Arc<Mutex<FrameBufferAllocatorInstance>>,
92}
93
94impl core::fmt::Debug for FrameBuffer {
95    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
96        f.debug_struct("FrameBuffer")
97            .field("metadata", &self.metadata())
98            .field("planes", &self.planes())
99            .finish()
100    }
101}
102
103unsafe impl Send for FrameBuffer {}
104
105impl AsFrameBuffer for FrameBuffer {
106    unsafe fn ptr(&self) -> NonNull<libcamera_framebuffer_t> {
107        self.ptr
108    }
109}