libcamera/
stream.rs

1use std::{marker::PhantomData, ptr::NonNull};
2
3use libcamera_sys::*;
4
5use crate::{
6    color_space::ColorSpace,
7    geometry::{Size, SizeRange},
8    pixel_format::{PixelFormat, PixelFormats},
9    utils::Immutable,
10};
11
12/// Stream role hint for generating configuration.
13///
14/// Used in [Camera::generate_configuration()](crate::camera::Camera::generate_configuration).
15#[derive(Debug, Clone, Copy)]
16pub enum StreamRole {
17    Raw,
18    StillCapture,
19    VideoRecording,
20    ViewFinder,
21}
22
23impl TryFrom<libcamera_stream_role::Type> for StreamRole {
24    type Error = ();
25
26    fn try_from(value: libcamera_stream_role::Type) -> Result<Self, Self::Error> {
27        match value {
28            libcamera_stream_role::LIBCAMERA_STREAM_ROLE_RAW => Ok(StreamRole::Raw),
29            libcamera_stream_role::LIBCAMERA_STREAM_ROLE_STILL_CAPTURE => Ok(StreamRole::StillCapture),
30            libcamera_stream_role::LIBCAMERA_STREAM_ROLE_VIDEO_RECORDING => Ok(StreamRole::VideoRecording),
31            libcamera_stream_role::LIBCAMERA_STREAM_ROLE_VIEW_FINDER => Ok(StreamRole::ViewFinder),
32            _ => Err(()),
33        }
34    }
35}
36
37impl From<StreamRole> for libcamera_stream_role::Type {
38    fn from(role: StreamRole) -> Self {
39        match role {
40            StreamRole::Raw => libcamera_stream_role::LIBCAMERA_STREAM_ROLE_RAW,
41            StreamRole::StillCapture => libcamera_stream_role::LIBCAMERA_STREAM_ROLE_STILL_CAPTURE,
42            StreamRole::VideoRecording => libcamera_stream_role::LIBCAMERA_STREAM_ROLE_VIDEO_RECORDING,
43            StreamRole::ViewFinder => libcamera_stream_role::LIBCAMERA_STREAM_ROLE_VIEW_FINDER,
44        }
45    }
46}
47
48/// A list of available stream formats.
49pub struct StreamFormatsRef<'d> {
50    ptr: NonNull<libcamera_stream_formats_t>,
51    _phantom: PhantomData<&'d ()>,
52}
53
54impl StreamFormatsRef<'_> {
55    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_stream_formats_t>) -> Self {
56        Self {
57            ptr,
58            _phantom: Default::default(),
59        }
60    }
61
62    /// Returns all available [PixelFormat]s.
63    pub fn pixel_formats(&self) -> Immutable<PixelFormats> {
64        Immutable(unsafe {
65            PixelFormats::from_ptr(NonNull::new(libcamera_stream_formats_pixel_formats(self.ptr.as_ptr())).unwrap())
66        })
67    }
68
69    /// Returns all supported stream [Size]s for a given [PixelFormat].
70    pub fn sizes(&self, pixel_format: PixelFormat) -> Vec<Size> {
71        let sizes = unsafe { libcamera_stream_formats_sizes(self.ptr.as_ptr(), &pixel_format.0) };
72        let len = unsafe { libcamera_sizes_size(sizes) };
73
74        let out = (0..len)
75            .map(|i| Size::from(unsafe { *libcamera_sizes_at(sizes, i as _) }))
76            .collect();
77
78        unsafe { libcamera_sizes_destroy(sizes) };
79
80        out
81    }
82
83    /// Returns a [SizeRange] of supported stream sizes for a given [PixelFormat].
84    pub fn range(&self, pixel_format: PixelFormat) -> SizeRange {
85        SizeRange::from(unsafe { libcamera_stream_formats_range(self.ptr.as_ptr(), &pixel_format.0) })
86    }
87}
88
89impl core::fmt::Debug for StreamFormatsRef<'_> {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        let mut map = f.debug_map();
92        for pixel_format in self.pixel_formats().into_iter() {
93            map.entry(&pixel_format, &self.sizes(pixel_format));
94        }
95        map.finish()
96    }
97}
98
99pub struct StreamConfigurationRef<'d> {
100    ptr: NonNull<libcamera_stream_configuration_t>,
101    _phantom: PhantomData<&'d ()>,
102}
103
104impl StreamConfigurationRef<'_> {
105    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_stream_configuration_t>) -> Self {
106        Self {
107            ptr,
108            _phantom: Default::default(),
109        }
110    }
111
112    pub(crate) fn as_ptr(&self) -> *const libcamera_stream_configuration_t {
113        self.ptr.as_ptr()
114    }
115
116    pub fn get_pixel_format(&self) -> PixelFormat {
117        PixelFormat(unsafe { self.ptr.as_ref() }.pixel_format)
118    }
119
120    pub fn set_pixel_format(&mut self, pixel_format: PixelFormat) {
121        unsafe { self.ptr.as_mut() }.pixel_format = pixel_format.0;
122    }
123
124    pub fn get_size(&self) -> Size {
125        unsafe { self.ptr.as_ref() }.size.into()
126    }
127
128    pub fn set_size(&mut self, size: Size) {
129        unsafe { self.ptr.as_mut() }.size = size.into()
130    }
131
132    pub fn get_stride(&self) -> u32 {
133        unsafe { self.ptr.as_ref() }.stride
134    }
135
136    /// Stride is typically populated by libcamera after validate(); overriding manually is advanced use.
137    pub fn set_stride(&mut self, stride: u32) {
138        unsafe { self.ptr.as_mut() }.stride = stride
139    }
140
141    pub fn get_frame_size(&self) -> u32 {
142        unsafe { self.ptr.as_ref() }.frame_size
143    }
144
145    /// Frame size is typically populated by libcamera after validate(); overriding manually is advanced use.
146    pub fn set_frame_size(&mut self, frame_size: u32) {
147        unsafe { self.ptr.as_mut() }.frame_size = frame_size
148    }
149
150    pub fn get_buffer_count(&self) -> u32 {
151        unsafe { self.ptr.as_ref() }.buffer_count
152    }
153
154    pub fn set_buffer_count(&mut self, buffer_count: u32) {
155        unsafe { self.ptr.as_mut() }.buffer_count = buffer_count;
156    }
157
158    /// Returns the configured color space, if any.
159    pub fn get_color_space(&self) -> Option<ColorSpace> {
160        if unsafe { libcamera_stream_configuration_has_color_space(self.ptr.as_ptr()) } {
161            Some(ColorSpace::from(unsafe {
162                libcamera_stream_configuration_get_color_space(self.ptr.as_ptr())
163            }))
164        } else {
165            None
166        }
167    }
168
169    /// Sets the color space for this stream configuration. Pass `None` to clear it.
170    pub fn set_color_space(&mut self, color_space: Option<ColorSpace>) {
171        unsafe {
172            match color_space {
173                Some(cs) => libcamera_stream_configuration_set_color_space(self.ptr.as_ptr(), &cs.into()),
174                None => libcamera_stream_configuration_set_color_space(self.ptr.as_ptr(), core::ptr::null()),
175            }
176        }
177    }
178
179    /// Returns initialized [Stream] for this configuration.
180    ///
181    /// Stream is only available once this configuration is applied with
182    /// [ActiveCamera::configure()](crate::camera::ActiveCamera::configure). It is invalidated if camera is
183    /// reconfigured.
184    pub fn stream(&self) -> Option<Stream> {
185        let stream = unsafe { libcamera_stream_configuration_stream(self.ptr.as_ptr()) };
186        // Stream is valid after camera->configure(), but might be invalidated after following reconfigurations.
187        // Unfortunatelly, it's hard to handle it with lifetimes so invalid StreamRef's are possible.
188        NonNull::new(stream).map(|p| unsafe { Stream::from_ptr(p) })
189    }
190
191    /// Returns a list of available stream formats for this configuration.
192    pub fn formats(&self) -> StreamFormatsRef<'_> {
193        unsafe {
194            StreamFormatsRef::from_ptr(
195                NonNull::new(libcamera_stream_configuration_formats(self.ptr.as_ptr()).cast_mut()).unwrap(),
196            )
197        }
198    }
199
200    /// Return the libcamera textual representation of this configuration.
201    pub fn to_string_repr(&self) -> String {
202        unsafe {
203            let ptr = libcamera_stream_configuration_to_string(self.ptr.as_ptr());
204            if ptr.is_null() {
205                return String::new();
206            }
207            let s = std::ffi::CStr::from_ptr(ptr).to_string_lossy().into_owned();
208            libc::free(ptr.cast());
209            s
210        }
211    }
212}
213
214impl core::fmt::Debug for StreamConfigurationRef<'_> {
215    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
216        f.debug_struct("StreamConfigurationRef")
217            .field("pixel_format", &self.get_pixel_format())
218            .field("size", &self.get_size())
219            .field("stride", &self.get_stride())
220            .field("frame_size", &self.get_frame_size())
221            .field("buffer_count", &self.get_buffer_count())
222            .field("color_space", &self.get_color_space())
223            .finish()
224    }
225}
226
227/// Handle to a camera stream.
228///
229/// Obtained from [StreamConfigurationRef::stream()] and is valid as long as camera configuration is unchanged.
230#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
231pub struct Stream {
232    /// libcamera_stream_t is used as unique key across various libcamera structures
233    /// and adding a lifetime would be really inconvenient. Dangling pointer should not
234    /// cause any harm by itself as collection loopup will fail gracefully, however,
235    /// it is important to never dereference this pointer to obtain libcamera_stream_configuration_t.
236    pub(crate) ptr: NonNull<libcamera_stream_t>,
237}
238
239impl Stream {
240    pub(crate) unsafe fn from_ptr(ptr: NonNull<libcamera_stream_t>) -> Self {
241        Self { ptr }
242    }
243
244    /// Returns the active [StreamConfigurationRef] for this stream, if available.
245    pub fn configuration(&self) -> Option<Immutable<StreamConfigurationRef<'_>>> {
246        let cfg = unsafe { libcamera_stream_get_configuration(self.ptr.as_ptr()) };
247        NonNull::new(cfg as *mut libcamera_stream_configuration_t)
248            .map(|p| Immutable(unsafe { StreamConfigurationRef::from_ptr(p) }))
249    }
250}
251
252unsafe impl Send for Stream {}