libcamera/
framebuffer_allocator.rs

1use std::{
2    collections::HashMap,
3    io,
4    ptr::NonNull,
5    sync::{Arc, Mutex},
6};
7
8use libcamera_sys::*;
9
10use crate::{camera::Camera, framebuffer::AsFrameBuffer, stream::Stream};
11
12/// Buffers are stored inside `libcamera_framebuffer_allocator_t` so we use Arc<FrameBufferAllocatorInstance>
13/// to keep the allocator alive as long as there are active buffers.
14struct FrameBufferAllocatorInstance {
15    ptr: NonNull<libcamera_framebuffer_allocator_t>,
16    /// Active allocations per stream pointer.
17    streams: HashMap<usize, StreamAllocState>,
18}
19
20#[derive(Debug)]
21struct StreamAllocState {
22    count: usize,
23    free_requested: bool,
24}
25
26unsafe impl Send for FrameBufferAllocatorInstance {}
27
28impl Drop for FrameBufferAllocatorInstance {
29    fn drop(&mut self) {
30        // Free any remaining streams.
31        for (stream_ptr, _) in self.streams.drain() {
32            unsafe { libcamera_framebuffer_allocator_free(self.ptr.as_ptr(), stream_ptr as *mut _) };
33        }
34
35        unsafe { libcamera_framebuffer_allocator_destroy(self.ptr.as_ptr()) }
36    }
37}
38
39pub struct FrameBufferAllocator {
40    inner: Arc<Mutex<FrameBufferAllocatorInstance>>,
41}
42
43impl FrameBufferAllocator {
44    pub fn new(cam: &Camera<'_>) -> Self {
45        Self {
46            inner: Arc::new(Mutex::new(FrameBufferAllocatorInstance {
47                ptr: NonNull::new(unsafe { libcamera_framebuffer_allocator_create(cam.ptr.as_ptr()) }).unwrap(),
48                streams: HashMap::new(),
49            })),
50        }
51    }
52
53    /// Allocate N buffers for a given stream, where N is equal to
54    /// [StreamConfigurationRef::get_buffer_count()](crate::stream::StreamConfigurationRef::get_buffer_count).
55    pub fn alloc(&mut self, stream: &Stream) -> io::Result<Vec<FrameBuffer>> {
56        let mut inner = self.inner.lock().unwrap();
57        let key = stream.ptr.as_ptr() as usize;
58        if inner.streams.contains_key(&key) {
59            return Err(io::Error::new(
60                io::ErrorKind::AlreadyExists,
61                "buffers already allocated for this stream",
62            ));
63        }
64
65        let ret = unsafe { libcamera_framebuffer_allocator_allocate(inner.ptr.as_ptr(), stream.ptr.as_ptr()) };
66        if ret < 0 {
67            Err(io::Error::from_raw_os_error(-ret))
68        } else {
69            let buffers = unsafe { libcamera_framebuffer_allocator_buffers(inner.ptr.as_ptr(), stream.ptr.as_ptr()) };
70
71            let len = unsafe { libcamera_framebuffer_list_size(buffers) };
72
73            inner.streams.insert(
74                key,
75                StreamAllocState {
76                    count: len,
77                    free_requested: false,
78                },
79            );
80
81            Ok((0..len)
82                .map(|i| unsafe { libcamera_framebuffer_list_get(buffers, i) })
83                .map(|ptr| NonNull::new(ptr.cast_mut()).unwrap())
84                .map(|ptr| {
85                    // This is very very unsafe.
86                    // Setting first field of metadata (status) to u32::MAX, which is used as an indication that
87                    // metadata is unavailable. Otherwise all metadata fields are uninitialized and
88                    // there is no way to detect availability.
89                    unsafe {
90                        libcamera_framebuffer_metadata(ptr.as_ptr())
91                            .cast_mut()
92                            .cast::<u32>()
93                            .write(u32::MAX)
94                    };
95
96                    FrameBuffer {
97                        ptr,
98                        stream_key: key,
99                        _alloc: self.inner.clone(),
100                    }
101                })
102                .collect())
103        }
104    }
105
106    /// Free buffers for a stream.
107    pub fn free(&mut self, stream: &Stream) -> io::Result<()> {
108        let mut inner = self.inner.lock().unwrap();
109        let key = stream.ptr.as_ptr() as usize;
110        let state = inner
111            .streams
112            .get_mut(&key)
113            .ok_or_else(|| io::Error::new(io::ErrorKind::NotFound, "no buffers allocated for stream"))?;
114
115        state.free_requested = true;
116        if state.count == 0 {
117            let ret = unsafe { libcamera_framebuffer_allocator_free(inner.ptr.as_ptr(), stream.ptr.as_ptr()) };
118            if ret < 0 {
119                return Err(io::Error::from_raw_os_error(-ret));
120            }
121            inner.streams.remove(&key);
122        }
123        Ok(())
124    }
125
126    /// Returns true if any buffers are allocated.
127    pub fn allocated(&self) -> bool {
128        let inner = self.inner.lock().unwrap();
129        unsafe { libcamera_framebuffer_allocator_allocated(inner.ptr.as_ptr()) }
130    }
131}
132
133pub struct FrameBuffer {
134    ptr: NonNull<libcamera_framebuffer_t>,
135    stream_key: usize,
136    _alloc: Arc<Mutex<FrameBufferAllocatorInstance>>,
137}
138
139impl core::fmt::Debug for FrameBuffer {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        f.debug_struct("FrameBuffer")
142            .field("metadata", &self.metadata())
143            .field("planes", &self.planes())
144            .finish()
145    }
146}
147
148unsafe impl Send for FrameBuffer {}
149
150impl AsFrameBuffer for FrameBuffer {
151    unsafe fn ptr(&self) -> NonNull<libcamera_framebuffer_t> {
152        self.ptr
153    }
154}
155
156impl FrameBuffer {
157    /// Retrieve the user cookie associated with this buffer.
158    pub fn cookie(&self) -> u64 {
159        unsafe { libcamera_framebuffer_cookie(self.ptr.as_ptr()) }
160    }
161
162    /// Set a user cookie for this buffer.
163    pub fn set_cookie(&self, cookie: u64) {
164        unsafe { libcamera_framebuffer_set_cookie(self.ptr.as_ptr(), cookie) }
165    }
166}
167
168impl Drop for FrameBuffer {
169    fn drop(&mut self) {
170        let mut inner = self._alloc.lock().unwrap();
171        if let Some(state) = inner.streams.get_mut(&self.stream_key) {
172            if state.count > 0 {
173                state.count -= 1;
174            }
175            if state.count == 0 && state.free_requested {
176                unsafe {
177                    let _ = libcamera_framebuffer_allocator_free(inner.ptr.as_ptr(), self.stream_key as *mut _);
178                }
179                inner.streams.remove(&self.stream_key);
180            }
181        }
182    }
183}