1 //! This module provides safer versions of the V4L2 ioctls through simple functions working on a
2 //! `RawFd`, and safer variants of the main V4L2 structures. This module can be used directly, but
3 //! the `device` module is very likely to be a better fit for application code.
4 //!
5 //! V4L2 ioctls are usually called with a single structure as argument, which serves to store both
6 //! the input and output of the ioctl. This is quite error-prone as the user needs to remember
7 //! which parts of the structure they are supposed to fill, and which parts the driver will update.
8 //!
9 //! To alleviate this issue, this module tries to provide, for each ioctl:
10 //!
11 //! Consequently, each ioctl proxy function is designed as follows:
12 //!
13 //! * A function that takes the relevant input as parameters and not the entire input/output
14 //!   structure. This lifts any ambiguity as to which parts of the structure userspace is supposed to
15 //!   fill.
16 //! * Safe variants of V4L2 structures used in ioctls that can be build from their C counterparts
17 //!   (and vice-versa) and include a validation step, to be used as return values.
18 //!
19 //! For instance, the `VIDIOC_G_FMT` ioctl takes a `struct v4l2_format` as argument, but only the
20 //! its `type` field is set by user-space - the rest of the structure is to be filled by the
21 //! driver.
22 //!
23 //! Therefore, our [`crate::ioctl::g_fmt()`] ioctl function takes the requested queue type as
24 //! argument and takes care of managing the `struct v4l2_format` to be passed to the kernel. The
25 //! filled structure is then converted into the type desired by the caller using
26 //! `TryFrom<v4l2_format>`:
27 //!
28 //! ```text
29 //! pub fn g_fmt<O: TryFrom<bindings::v4l2_format>>(
30 //!     fd: &impl AsRawFd,
31 //!     queue: QueueType,
32 //! ) -> Result<O, GFmtError>;
33 //! ```
34 //!
35 //! Since `struct v4l2_format` has C unions that are unsafe to use in Rust, the [`crate::Format`]
36 //! type can be used as the output type of this function, to validate the `struct v4l2_format`
37 //! returned by the kernel and convert it to a safe type.
38 //!
39 //! Most ioctls also have their own error type: this helps discern scenarios where the ioctl
40 //! returned non-zero, but the situation is not necessarily an error. For instance, `VIDIOC_DQBUF`
41 //! can return -EAGAIN if no buffer is available to dequeue, which is not an error and thus is
42 //! represented by its own variant. Actual errors are captured by the `IoctlError` variant, and all
43 //! error types can be converted to their original error code using their `Into<Errno>`
44 //! implementation.
45 
46 mod decoder_cmd;
47 mod dqbuf;
48 mod encoder_cmd;
49 mod enum_fmt;
50 mod expbuf;
51 mod frameintervals;
52 mod framesizes;
53 mod g_audio;
54 mod g_dv_timings;
55 mod g_ext_ctrls;
56 mod g_fmt;
57 mod g_input;
58 mod g_jpegcomp;
59 mod g_parm;
60 mod g_selection;
61 mod mmap;
62 mod qbuf;
63 mod querybuf;
64 mod querycap;
65 mod queryctrl;
66 mod reqbufs;
67 mod request;
68 mod streamon;
69 mod subscribe_event;
70 
71 pub use decoder_cmd::*;
72 pub use dqbuf::*;
73 pub use encoder_cmd::*;
74 pub use enum_fmt::*;
75 pub use expbuf::*;
76 pub use frameintervals::*;
77 pub use framesizes::*;
78 pub use g_audio::*;
79 pub use g_dv_timings::*;
80 pub use g_ext_ctrls::*;
81 pub use g_fmt::*;
82 pub use g_input::*;
83 pub use g_jpegcomp::*;
84 pub use g_parm::*;
85 pub use g_selection::*;
86 pub use mmap::*;
87 pub use qbuf::*;
88 pub use querybuf::*;
89 pub use querycap::*;
90 pub use queryctrl::*;
91 pub use reqbufs::*;
92 pub use request::*;
93 pub use streamon::*;
94 pub use subscribe_event::*;
95 
96 use std::convert::Infallible;
97 use std::convert::TryFrom;
98 use std::ffi::CStr;
99 use std::ffi::FromBytesWithNulError;
100 use std::fmt::Debug;
101 use std::ops::Deref;
102 use std::ops::DerefMut;
103 
104 use bitflags::bitflags;
105 use enumn::N;
106 use nix::errno::Errno;
107 use thiserror::Error;
108 
109 use crate::bindings;
110 use crate::memory::DmaBuf;
111 use crate::memory::Memory;
112 use crate::memory::MemoryType;
113 use crate::memory::Mmap;
114 use crate::memory::UserPtr;
115 use crate::Colorspace;
116 use crate::PixelFormat;
117 use crate::Quantization;
118 use crate::QueueDirection;
119 use crate::QueueType;
120 use crate::XferFunc;
121 use crate::YCbCrEncoding;
122 
123 /// Utility function for sub-modules.
124 /// Constructs an owned String instance from a slice containing a nul-terminated
125 /// C string, after checking that the passed slice indeed contains a nul
126 /// character.
string_from_cstr(c_str: &[u8]) -> Result<String, FromBytesWithNulError>127 fn string_from_cstr(c_str: &[u8]) -> Result<String, FromBytesWithNulError> {
128     // Make sure that our string contains a nul character.
129     let slice = match c_str.iter().position(|x| *x == b'\0') {
130         // Pass the full slice, `from_bytes_with_nul` will return an error.
131         None => c_str,
132         Some(pos) => &c_str[..pos + 1],
133     };
134 
135     Ok(CStr::from_bytes_with_nul(slice)?
136         .to_string_lossy()
137         .into_owned())
138 }
139 
140 /// Extension trait for allowing easy conversion of ioctl errors into their originating error code.
141 pub trait IntoErrno {
into_errno(self) -> i32142     fn into_errno(self) -> i32;
143 }
144 
145 impl<T> IntoErrno for T
146 where
147     T: Into<Errno>,
148 {
into_errno(self) -> i32149     fn into_errno(self) -> i32 {
150         self.into() as i32
151     }
152 }
153 
154 /// Error type for a "run ioctl and try to convert to safer type" operation.
155 ///
156 /// [`IoctlError`] means that the ioctl itself has failed, while [`ConversionError`] indicates that
157 /// the output of the ioctl could not be converted to the desired output type for the ioctl
158 #[derive(Debug, Error)]
159 pub enum IoctlConvertError<IE: Debug, CE: Debug> {
160     #[error("error during ioctl: {0}")]
161     IoctlError(#[from] IE),
162     #[error("error while converting ioctl result: {0}")]
163     ConversionError(CE),
164 }
165 
166 impl<IE, CE> IntoErrno for IoctlConvertError<IE, CE>
167 where
168     IE: Debug + Into<Errno>,
169     CE: Debug,
170 {
into_errno(self) -> i32171     fn into_errno(self) -> i32 {
172         match self {
173             IoctlConvertError::IoctlError(e) => e.into_errno(),
174             IoctlConvertError::ConversionError(_) => Errno::EINVAL as i32,
175         }
176     }
177 }
178 
179 // We need a bound here, otherwise we cannot use `O::Error`.
180 #[allow(type_alias_bounds)]
181 pub type IoctlConvertResult<O, IE, CE> = Result<O, IoctlConvertError<IE, CE>>;
182 
183 /// Tries to convert the raw output of an ioctl to a safer type.
184 ///
185 /// Ioctl wrappers always return a raw C type that most of the case is potentially invalid: for
186 /// instance C enums might have invalid values.
187 ///
188 /// This function takes a raw ioctl result and, if successful, attempts to convert its output to a
189 /// safer type using [`TryFrom`]. If either the ioctl or the conversion fails, then the appropriate
190 /// variant of [`IoctlConvertError`] is returned.
ioctl_and_convert<I, O, IE>(res: Result<I, IE>) -> IoctlConvertResult<O, IE, O::Error> where IE: std::fmt::Debug, O: TryFrom<I>, O::Error: std::fmt::Debug,191 fn ioctl_and_convert<I, O, IE>(res: Result<I, IE>) -> IoctlConvertResult<O, IE, O::Error>
192 where
193     IE: std::fmt::Debug,
194     O: TryFrom<I>,
195     O::Error: std::fmt::Debug,
196 {
197     res.map_err(IoctlConvertError::IoctlError)
198         .and_then(|o| O::try_from(o).map_err(IoctlConvertError::ConversionError))
199 }
200 
201 /// A fully owned V4L2 buffer obtained from some untrusted place (typically an ioctl), or created
202 /// with the purpose of receiving the result of an ioctl.
203 ///
204 /// For any serious use it should be converted into something safer like [`V4l2Buffer`].
205 pub struct UncheckedV4l2Buffer(pub bindings::v4l2_buffer, pub Option<V4l2BufferPlanes>);
206 
207 impl UncheckedV4l2Buffer {
208     /// Returns a new buffer with the queue type set to `queue` and its index to `index`.
209     ///
210     /// If `queue` is multiplanar, then the number of planes will be set to `VIDEO_MAX_PLANES` so
211     /// the buffer can receive the result of ioctl that write into a `v4l2_buffer` such as
212     /// `VIDIOC_QUERYBUF` or `VIDIOC_DQBUF`. [`as_mut`] can be called in order to obtain a
213     /// reference to the buffer with its `planes` pointer properly set.
new_for_querybuf(queue: QueueType, index: Option<u32>) -> Self214     pub fn new_for_querybuf(queue: QueueType, index: Option<u32>) -> Self {
215         let multiplanar = queue.is_multiplanar();
216 
217         UncheckedV4l2Buffer(
218             bindings::v4l2_buffer {
219                 index: index.unwrap_or_default(),
220                 type_: queue as u32,
221                 length: if multiplanar {
222                     bindings::VIDEO_MAX_PLANES
223                 } else {
224                     Default::default()
225                 },
226                 ..Default::default()
227             },
228             if multiplanar {
229                 Some(Default::default())
230             } else {
231                 None
232             },
233         )
234     }
235 }
236 
237 /// For cases where we are not interested in the result of `qbuf`
238 impl TryFrom<UncheckedV4l2Buffer> for () {
239     type Error = Infallible;
240 
try_from(_: UncheckedV4l2Buffer) -> Result<Self, Self::Error>241     fn try_from(_: UncheckedV4l2Buffer) -> Result<Self, Self::Error> {
242         Ok(())
243     }
244 }
245 
246 impl From<V4l2Buffer> for UncheckedV4l2Buffer {
from(buffer: V4l2Buffer) -> Self247     fn from(buffer: V4l2Buffer) -> Self {
248         let is_multiplanar = buffer.queue().is_multiplanar();
249 
250         Self(
251             buffer.buffer,
252             if is_multiplanar {
253                 Some(buffer.planes)
254             } else {
255                 None
256             },
257         )
258     }
259 }
260 
261 /// Returns a mutable pointer to the buffer after making sure its plane pointer is valid, if the
262 /// buffer is multiplanar.
263 ///
264 /// This should be used to make sure the buffer is not going to move as long as the reference is
265 /// alive.
266 impl AsMut<bindings::v4l2_buffer> for UncheckedV4l2Buffer {
as_mut(&mut self) -> &mut bindings::v4l2_buffer267     fn as_mut(&mut self) -> &mut bindings::v4l2_buffer {
268         match (QueueType::n(self.0.type_), &mut self.1) {
269             (Some(queue), Some(planes)) if queue.is_multiplanar() => {
270                 self.0.m.planes = planes.as_mut_ptr()
271             }
272             _ => (),
273         }
274 
275         &mut self.0
276     }
277 }
278 
279 /// A memory area we can pass to ioctls in order to get/set plane information
280 /// with the multi-planar API.
281 type V4l2BufferPlanes = [bindings::v4l2_plane; bindings::VIDEO_MAX_PLANES as usize];
282 
283 bitflags! {
284     #[derive(Clone, Copy, Debug, Default)]
285     /// `flags` member of `struct `v4l2_buffer`.
286     pub struct BufferFlags: u32 {
287         const MAPPED = bindings::V4L2_BUF_FLAG_MAPPED;
288         const QUEUED = bindings::V4L2_BUF_FLAG_QUEUED;
289         const DONE = bindings::V4L2_BUF_FLAG_DONE;
290         const ERROR = bindings::V4L2_BUF_FLAG_ERROR;
291         const KEYFRAME = bindings::V4L2_BUF_FLAG_KEYFRAME;
292         const PFRAME = bindings::V4L2_BUF_FLAG_PFRAME;
293         const BFRAME = bindings::V4L2_BUF_FLAG_BFRAME;
294         const TIMECODE = bindings::V4L2_BUF_FLAG_TIMECODE;
295         const PREPARED = bindings::V4L2_BUF_FLAG_PREPARED;
296         const NO_CACHE_INVALIDATE = bindings::V4L2_BUF_FLAG_NO_CACHE_CLEAN;
297         const NO_CACHE_CLEAN = bindings::V4L2_BUF_FLAG_NO_CACHE_INVALIDATE;
298         const LAST = bindings::V4L2_BUF_FLAG_LAST;
299         const TIMESTAMP_MONOTONIC = bindings::V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
300         const TIMESTAMP_COPY = bindings::V4L2_BUF_FLAG_TIMESTAMP_COPY;
301         const TSTAMP_SRC_EOF = bindings::V4L2_BUF_FLAG_TSTAMP_SRC_EOF;
302         const TSTAMP_SRC_SOE = bindings::V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
303         const REQUEST_FD = bindings::V4L2_BUF_FLAG_REQUEST_FD;
304     }
305 }
306 
307 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, N)]
308 #[repr(u32)]
309 pub enum BufferField {
310     #[default]
311     Any = bindings::v4l2_field_V4L2_FIELD_ANY,
312     None = bindings::v4l2_field_V4L2_FIELD_NONE,
313     Top = bindings::v4l2_field_V4L2_FIELD_TOP,
314     Interlaced = bindings::v4l2_field_V4L2_FIELD_INTERLACED,
315     SeqTb = bindings::v4l2_field_V4L2_FIELD_SEQ_TB,
316     SeqBt = bindings::v4l2_field_V4L2_FIELD_SEQ_BT,
317     Alternate = bindings::v4l2_field_V4L2_FIELD_ALTERNATE,
318     InterlacedTb = bindings::v4l2_field_V4L2_FIELD_INTERLACED_TB,
319     InterlacedBt = bindings::v4l2_field_V4L2_FIELD_INTERLACED_BT,
320 }
321 
322 #[derive(Debug, Error)]
323 pub enum V4l2BufferResizePlanesError {
324     #[error("zero planes requested")]
325     ZeroPlanesRequested,
326     #[error("buffer is single planar and can only accomodate one plane")]
327     SinglePlanar,
328     #[error("more than VIDEO_MAX_PLANES have been requested")]
329     TooManyPlanes,
330 }
331 
332 /// Safe-ish representation of a `struct v4l2_buffer`. It owns its own planes array and can only be
333 /// constructed from valid data.
334 ///
335 /// This structure guarantees the following invariants:
336 ///
337 /// * The buffer's queue type is valid and cannot change,
338 /// * The buffer's memory type is valid and cannot change,
339 /// * The memory backing (MMAP offset/user pointer/DMABUF) can only be read and set according to
340 ///   the memory type of the buffer. I.e. it is impossible to mistakenly set `fd` unless the
341 ///   buffer's memory type is `DMABUF`.
342 /// * Single-planar buffers can only have exactly one and only one plane.
343 ///
344 /// Planes management is a bit complicated due to the existence of the single-planar and a
345 /// multi-planar buffer representations. There are situations where one wants to access plane
346 /// information regardless of the representation used, and others where one wants to access the
347 /// actual array of `struct v4l2_plane`, provided it exists.
348 ///
349 /// For the first situation, use the `planes_iter` and `planes_iter_mut` methods. They return an
350 /// iterator to an accessor to plane data that is identical whether the buffer is single or multi
351 /// planar (or course, for single-planar buffers the length of the iterator will be exactly 1).
352 ///
353 /// For the second situation, the `as_v4l2_planes` method returns an actual slice of `struct
354 /// v4l2_plane` with the plane information if the buffer is multi-planar (and an empty slice if the
355 /// it is single-planar).
356 #[derive(Clone)]
357 #[repr(C)]
358 pub struct V4l2Buffer {
359     buffer: bindings::v4l2_buffer,
360     planes: V4l2BufferPlanes,
361 }
362 
363 /// V4l2Buffer is safe to send across threads. `v4l2_buffer` is !Send & !Sync
364 /// because it contains a pointer, but we are making sure to use it safely here.
365 unsafe impl Send for V4l2Buffer {}
366 unsafe impl Sync for V4l2Buffer {}
367 
368 impl Debug for V4l2Buffer {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result369     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
370         f.debug_struct("V4l2Buffer")
371             .field("index", &self.index())
372             .field("flags", &self.flags())
373             .field("sequence", &self.sequence())
374             .finish()
375     }
376 }
377 
378 impl V4l2Buffer {
new(queue: QueueType, index: u32, memory: MemoryType) -> Self379     pub fn new(queue: QueueType, index: u32, memory: MemoryType) -> Self {
380         Self {
381             buffer: bindings::v4l2_buffer {
382                 index,
383                 type_: queue as u32,
384                 memory: memory as u32,
385                 // Make sure that a multiplanar buffer always has at least one plane.
386                 length: if queue.is_multiplanar() {
387                     1
388                 } else {
389                     Default::default()
390                 },
391                 ..Default::default()
392             },
393             planes: Default::default(),
394         }
395     }
396 
index(&self) -> u32397     pub fn index(&self) -> u32 {
398         self.buffer.index
399     }
400 
queue(&self) -> QueueType401     pub fn queue(&self) -> QueueType {
402         QueueType::n(self.buffer.type_).unwrap()
403     }
404 
memory(&self) -> MemoryType405     pub fn memory(&self) -> MemoryType {
406         MemoryType::n(self.buffer.memory).unwrap()
407     }
408 
409     /// Returns the currently set flags for this buffer.
flags(&self) -> BufferFlags410     pub fn flags(&self) -> BufferFlags {
411         BufferFlags::from_bits_truncate(self.buffer.flags)
412     }
413 
414     /// Sets the flags of this buffer.
set_flags(&mut self, flags: BufferFlags)415     pub fn set_flags(&mut self, flags: BufferFlags) {
416         self.buffer.flags = flags.bits();
417     }
418 
419     /// Add `flags` to the set of flags for this buffer.
add_flags(&mut self, flags: BufferFlags)420     pub fn add_flags(&mut self, flags: BufferFlags) {
421         self.set_flags(self.flags() | flags);
422     }
423 
424     /// Remove `flags` from the set of flags for this buffer.
clear_flags(&mut self, flags: BufferFlags)425     pub fn clear_flags(&mut self, flags: BufferFlags) {
426         self.set_flags(self.flags() - flags);
427     }
428 
field(&self) -> BufferField429     pub fn field(&self) -> BufferField {
430         BufferField::n(self.buffer.field).unwrap()
431     }
432 
set_field(&mut self, field: BufferField)433     pub fn set_field(&mut self, field: BufferField) {
434         self.buffer.field = field as u32;
435     }
436 
is_last(&self) -> bool437     pub fn is_last(&self) -> bool {
438         self.flags().contains(BufferFlags::LAST)
439     }
440 
timestamp(&self) -> bindings::timeval441     pub fn timestamp(&self) -> bindings::timeval {
442         self.buffer.timestamp
443     }
444 
set_timestamp(&mut self, timestamp: bindings::timeval)445     pub fn set_timestamp(&mut self, timestamp: bindings::timeval) {
446         self.buffer.timestamp = timestamp;
447     }
448 
sequence(&self) -> u32449     pub fn sequence(&self) -> u32 {
450         self.buffer.sequence
451     }
452 
set_sequence(&mut self, sequence: u32)453     pub fn set_sequence(&mut self, sequence: u32) {
454         self.buffer.sequence = sequence;
455     }
456 
num_planes(&self) -> usize457     pub fn num_planes(&self) -> usize {
458         if self.queue().is_multiplanar() {
459             self.buffer.length as usize
460         } else {
461             1
462         }
463     }
464 
465     /// Sets the number of planes for this buffer to `num_planes`, which must be between `1` and
466     /// `VIDEO_MAX_PLANES`.
467     ///
468     /// This method only makes sense for multi-planar buffers. For single-planar buffers, any
469     /// `num_planes` value different from `1` will return an error.
set_num_planes(&mut self, num_planes: usize) -> Result<(), V4l2BufferResizePlanesError>470     pub fn set_num_planes(&mut self, num_planes: usize) -> Result<(), V4l2BufferResizePlanesError> {
471         match (num_planes, self.queue().is_multiplanar()) {
472             (0, _) => Err(V4l2BufferResizePlanesError::ZeroPlanesRequested),
473             (n, _) if n > bindings::VIDEO_MAX_PLANES as usize => {
474                 Err(V4l2BufferResizePlanesError::TooManyPlanes)
475             }
476             (1, false) => Ok(()),
477             (_, false) => Err(V4l2BufferResizePlanesError::SinglePlanar),
478             (num_planes, true) => {
479                 // If we are sizing down, clear the planes we are removing.
480                 for plane in &mut self.planes[num_planes..self.buffer.length as usize] {
481                     *plane = Default::default();
482                 }
483                 self.buffer.length = num_planes as u32;
484                 Ok(())
485             }
486         }
487     }
488 
489     /// Returns the first plane of the buffer. This method is guaranteed to
490     /// succeed because every buffer has at least one plane.
get_first_plane(&self) -> V4l2PlaneAccessor491     pub fn get_first_plane(&self) -> V4l2PlaneAccessor {
492         self.planes_iter().next().unwrap()
493     }
494 
495     /// Returns the first plane of the buffer. This method is guaranteed to
496     /// succeed because every buffer has at least one plane.
get_first_plane_mut(&mut self) -> V4l2PlaneMutAccessor497     pub fn get_first_plane_mut(&mut self) -> V4l2PlaneMutAccessor {
498         self.planes_iter_mut().next().unwrap()
499     }
500 
501     /// Returns a non-mutable reference to the internal `v4l2_buffer`.
502     ///
503     /// The returned value is not suitable for passing to C functions or ioctls (which anyway
504     /// require a mutable pointer), but can be useful to construct other values.
505     ///
506     /// In particular, if the buffer is multi-planar, then the `planes` pointer will be invalid.
507     /// Dereferencing it would require an `unsafe` block anyway.
508     ///
509     /// If you need to access the `v4l2_planes` of this buffer, use `as_v4l2_planes`.
510     ///
511     /// If you need to pass the `v4l2_buffer` to a C function or ioctl and need a valid `planes`
512     /// pointer, use `as_mut_ptr` and read the warning in its documentation.
as_v4l2_buffer(&self) -> &bindings::v4l2_buffer513     pub fn as_v4l2_buffer(&self) -> &bindings::v4l2_buffer {
514         &self.buffer
515     }
516 
517     /// Returns a slice of this buffer's `v4l2_plane`s, if the buffer is multi-planar.
518     ///
519     /// If it is single-planar, an empty slice is returned.
520     ///
521     /// This method only exists for the rare case when one needs to access the original plane data.
522     /// For this reason there is no `v4l2_planes_mut` - use of the `planes_iter*_mut` methods
523     /// instead if you need to modify plane information.
as_v4l2_planes(&self) -> &[bindings::v4l2_plane]524     pub fn as_v4l2_planes(&self) -> &[bindings::v4l2_plane] {
525         let planes_upper = if self.queue().is_multiplanar() {
526             self.buffer.length as usize
527         } else {
528             0
529         };
530 
531         &self.planes[0..planes_upper]
532     }
533 
534     /// Returns a pointer to the internal `v4l2_buffer`.
535     ///
536     /// If this buffer is multi-planar then the `planes` pointer will be updated so the returned
537     /// data is valid if passed to a C function or an ioctl.
538     ///
539     /// Beware that as a consequence the returned pointer is only valid as long as the `V4l2Buffer`
540     /// is not moved anywhere.
541     ///
542     /// Also, any unsafe code called on this pointer must maintain the invariants listed in
543     /// [`V4l2Buffer`]'s documentation.
544     ///
545     /// Use with extreme caution.
as_mut_ptr(&mut self) -> *mut bindings::v4l2_buffer546     pub fn as_mut_ptr(&mut self) -> *mut bindings::v4l2_buffer {
547         if self.queue().is_multiplanar() && self.buffer.length > 0 {
548             self.buffer.m.planes = self.planes.as_mut_ptr();
549         }
550 
551         &mut self.buffer as *mut _
552     }
553 
554     /// Returns planar information in a way that is consistent between single-planar and
555     /// multi-planar buffers.
planes_iter(&self) -> impl Iterator<Item = V4l2PlaneAccessor>556     pub fn planes_iter(&self) -> impl Iterator<Item = V4l2PlaneAccessor> {
557         let multiplanar = self.queue().is_multiplanar();
558         let planes_iter = self.as_v4l2_planes().iter();
559 
560         // In order to return a consistent type for both single-planar and multi-planar buffers,
561         // we chain the single-planar iterator to the multi-planar one. If the buffer is
562         // single-planar, then the multi-planar iterator will be empty. If the buffer is
563         // multi-planar, we skip the first entry which is the (invalid) single-planar iterator.
564         std::iter::once(V4l2PlaneAccessor::new_single_planar(&self.buffer))
565             .chain(planes_iter.map(V4l2PlaneAccessor::new_multi_planar))
566             .skip(if multiplanar { 1 } else { 0 })
567     }
568 
569     /// Returns planar information in a way that is consistent between single-planar and
570     /// multi-planar buffers.
planes_iter_mut(&mut self) -> impl Iterator<Item = V4l2PlaneMutAccessor>571     pub fn planes_iter_mut(&mut self) -> impl Iterator<Item = V4l2PlaneMutAccessor> {
572         let multiplanar = self.queue().is_multiplanar();
573         let planes_upper = if multiplanar {
574             self.buffer.length as usize
575         } else {
576             0
577         };
578         let planes_iter = self.planes[0..planes_upper].iter_mut();
579 
580         // In order to return a consistent type for both single-planar and multi-planar buffers,
581         // we chain the single-planar iterator to the multi-planar one. If the buffer is
582         // single-planar, then the multi-planar iterator will be empty. If the buffer is
583         // multi-planar, we skip the first entry which is the (invalid) single-planar iterator.
584         std::iter::once(V4l2PlaneMutAccessor::new_single_planar(&mut self.buffer))
585             .chain(planes_iter.map(V4l2PlaneMutAccessor::new_multi_planar))
586             .skip(if multiplanar { 1 } else { 0 })
587     }
588 
589     /// Build a plane iterator including the memory backings for memory type `M`.
590     ///
591     /// # Safety
592     ///
593     /// The caller must be sure that the buffer's memory type is indeed `M`.
planes_iter_with_backing<M: Memory>( &self, ) -> impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<M>>594     unsafe fn planes_iter_with_backing<M: Memory>(
595         &self,
596     ) -> impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<M>> {
597         let is_multiplanar = self.queue().is_multiplanar();
598         let planes_length = if is_multiplanar {
599             self.buffer.length as usize
600         } else {
601             0
602         };
603         let planes = &self.planes[0..planes_length];
604         // In order to return a consistent type for both single-planar and multi-planar buffers,
605         // we chain the single-planar iterator to the multi-planar one. If the buffer is
606         // single-planar, then the multi-planar iterator will be empty. If the buffer is
607         // multi-planar, we skip the first entry which is the (invalid) single-planar iterator.
608         std::iter::once(V4l2PlaneAccessorWithRawBacking::new_single_planar(
609             &self.buffer,
610         ))
611         .chain(
612             planes
613                 .iter()
614                 .map(|p| V4l2PlaneAccessorWithRawBacking::new_multi_planar(p)),
615         )
616         .skip(if self.queue().is_multiplanar() { 1 } else { 0 })
617     }
618 
planes_with_backing_iter( &self, ) -> V4l2PlanesWithBacking< impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<Mmap>>, impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<UserPtr>>, impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<DmaBuf>>, >619     pub fn planes_with_backing_iter(
620         &self,
621     ) -> V4l2PlanesWithBacking<
622         impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<Mmap>>,
623         impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<UserPtr>>,
624         impl Iterator<Item = V4l2PlaneAccessorWithRawBacking<DmaBuf>>,
625     > {
626         match self.memory() {
627             MemoryType::Mmap => {
628                 V4l2PlanesWithBacking::Mmap(unsafe { self.planes_iter_with_backing() })
629             }
630             MemoryType::UserPtr => {
631                 V4l2PlanesWithBacking::UserPtr(unsafe { self.planes_iter_with_backing() })
632             }
633             MemoryType::DmaBuf => {
634                 V4l2PlanesWithBacking::DmaBuf(unsafe { self.planes_iter_with_backing() })
635             }
636             MemoryType::Overlay => V4l2PlanesWithBacking::Overlay,
637         }
638     }
639 
640     /// Build a mutable plane iterator including the memory backings for memory type `M`.
641     ///
642     /// # Safety
643     ///
644     /// The caller must be sure that the buffer's memory type is indeed `M`.
planes_iter_with_backing_mut<M: Memory>( &mut self, ) -> impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<M>>645     unsafe fn planes_iter_with_backing_mut<M: Memory>(
646         &mut self,
647     ) -> impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<M>> {
648         let is_multiplanar = self.queue().is_multiplanar();
649         let planes_length = if is_multiplanar {
650             self.buffer.length as usize
651         } else {
652             0
653         };
654         let planes = &mut self.planes[0..planes_length];
655 
656         // In order to return a consistent type for both single-planar and multi-planar buffers,
657         // we chain the single-planar iterator to the multi-planar one. If the buffer is
658         // single-planar, then the multi-planar iterator will be empty. If the buffer is
659         // multi-planar, we skip the first entry which is the (invalid) single-planar iterator.
660         std::iter::once(V4l2PlaneMutAccessorWithRawBacking::new_single_planar(
661             &mut self.buffer,
662         ))
663         .chain(
664             planes
665                 .iter_mut()
666                 .map(|p| V4l2PlaneMutAccessorWithRawBacking::new_multi_planar(p)),
667         )
668         .skip(if is_multiplanar { 1 } else { 0 })
669     }
670 
planes_with_backing_iter_mut( &mut self, ) -> V4l2PlanesWithBackingMut< impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<Mmap>>, impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<UserPtr>>, impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<DmaBuf>>, >671     pub fn planes_with_backing_iter_mut(
672         &mut self,
673     ) -> V4l2PlanesWithBackingMut<
674         impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<Mmap>>,
675         impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<UserPtr>>,
676         impl Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<DmaBuf>>,
677     > {
678         match self.memory() {
679             MemoryType::Mmap => {
680                 V4l2PlanesWithBackingMut::Mmap(unsafe { self.planes_iter_with_backing_mut() })
681             }
682             MemoryType::UserPtr => {
683                 V4l2PlanesWithBackingMut::UserPtr(unsafe { self.planes_iter_with_backing_mut() })
684             }
685             MemoryType::DmaBuf => {
686                 V4l2PlanesWithBackingMut::DmaBuf(unsafe { self.planes_iter_with_backing_mut() })
687             }
688             MemoryType::Overlay => V4l2PlanesWithBackingMut::Overlay,
689         }
690     }
691 }
692 
693 /// Accessor to a buffer's plane information.
694 ///
695 /// This is just a set of references, that are set to point to the right location depending on
696 /// whether the buffer is single or multi-planar.
697 pub struct V4l2PlaneAccessor<'a> {
698     pub bytesused: &'a u32,
699     pub length: &'a u32,
700     pub data_offset: Option<&'a u32>,
701 }
702 
703 impl<'a> V4l2PlaneAccessor<'a> {
new_single_planar(buffer: &'a bindings::v4l2_buffer) -> Self704     fn new_single_planar(buffer: &'a bindings::v4l2_buffer) -> Self {
705         Self {
706             bytesused: &buffer.bytesused,
707             length: &buffer.length,
708             data_offset: None,
709         }
710     }
711 
new_multi_planar(plane: &'a bindings::v4l2_plane) -> Self712     fn new_multi_planar(plane: &'a bindings::v4l2_plane) -> Self {
713         Self {
714             bytesused: &plane.bytesused,
715             length: &plane.length,
716             data_offset: Some(&plane.data_offset),
717         }
718     }
719 }
720 
721 /// Mutable accessor to a buffer's plane information.
722 ///
723 /// This is just a set of references, that are set to point to the right location depending on
724 /// whether the buffer is single or multi-planar.
725 pub struct V4l2PlaneMutAccessor<'a> {
726     pub bytesused: &'a mut u32,
727     pub length: &'a mut u32,
728     pub data_offset: Option<&'a mut u32>,
729 }
730 
731 impl<'a> V4l2PlaneMutAccessor<'a> {
new_single_planar(buffer: &'a mut bindings::v4l2_buffer) -> Self732     fn new_single_planar(buffer: &'a mut bindings::v4l2_buffer) -> Self {
733         Self {
734             bytesused: &mut buffer.bytesused,
735             length: &mut buffer.length,
736             data_offset: None,
737         }
738     }
739 
new_multi_planar(plane: &'a mut bindings::v4l2_plane) -> Self740     fn new_multi_planar(plane: &'a mut bindings::v4l2_plane) -> Self {
741         Self {
742             bytesused: &mut plane.bytesused,
743             length: &mut plane.length,
744             data_offset: Some(&mut plane.data_offset),
745         }
746     }
747 }
748 
749 pub struct V4l2PlaneAccessorWithRawBacking<'a, M: Memory> {
750     data: V4l2PlaneAccessor<'a>,
751     backing: &'a M::RawBacking,
752 }
753 
754 impl<'a, M: Memory> Deref for V4l2PlaneAccessorWithRawBacking<'a, M> {
755     type Target = V4l2PlaneAccessor<'a>;
756 
deref(&self) -> &Self::Target757     fn deref(&self) -> &Self::Target {
758         &self.data
759     }
760 }
761 
762 impl<'a, M: Memory> V4l2PlaneAccessorWithRawBacking<'a, M> {
763     /// Create a new plane accessor for memory type `M`.
764     ///
765     /// # Safety
766     ///
767     /// `v4l2_buffer` must be of a single-planar type and use memory type `M`.
new_single_planar(buffer: &'a bindings::v4l2_buffer) -> Self768     pub unsafe fn new_single_planar(buffer: &'a bindings::v4l2_buffer) -> Self {
769         Self {
770             data: V4l2PlaneAccessor::new_single_planar(buffer),
771             backing: M::get_single_planar_buffer_backing(&buffer.m),
772         }
773     }
774 
775     /// Create a new plane accessor for memory type `M`.
776     ///
777     /// # Safety
778     ///
779     /// `v4l2_plane` must come from a multi-planar buffer using memory type `M`.
new_multi_planar(plane: &'a bindings::v4l2_plane) -> Self780     pub unsafe fn new_multi_planar(plane: &'a bindings::v4l2_plane) -> Self {
781         Self {
782             data: V4l2PlaneAccessor::new_multi_planar(plane),
783             backing: M::get_plane_buffer_backing(&plane.m),
784         }
785     }
786 }
787 
788 impl<'a> V4l2PlaneAccessorWithRawBacking<'a, Mmap> {
mem_offset(&self) -> <Mmap as Memory>::RawBacking789     pub fn mem_offset(&self) -> <Mmap as Memory>::RawBacking {
790         *self.backing
791     }
792 }
793 
794 impl<'a> V4l2PlaneAccessorWithRawBacking<'a, UserPtr> {
userptr(&self) -> <UserPtr as Memory>::RawBacking795     pub fn userptr(&self) -> <UserPtr as Memory>::RawBacking {
796         *self.backing
797     }
798 }
799 
800 impl<'a> V4l2PlaneAccessorWithRawBacking<'a, DmaBuf> {
fd(&self) -> <DmaBuf as Memory>::RawBacking801     pub fn fd(&self) -> <DmaBuf as Memory>::RawBacking {
802         *self.backing
803     }
804 }
805 
806 pub enum V4l2PlanesWithBacking<
807     'a,
808     M: Iterator<Item = V4l2PlaneAccessorWithRawBacking<'a, Mmap>>,
809     U: Iterator<Item = V4l2PlaneAccessorWithRawBacking<'a, UserPtr>>,
810     D: Iterator<Item = V4l2PlaneAccessorWithRawBacking<'a, DmaBuf>>,
811 > {
812     Mmap(M),
813     UserPtr(U),
814     DmaBuf(D),
815     Overlay,
816 }
817 
818 pub struct V4l2PlaneMutAccessorWithRawBacking<'a, M: Memory> {
819     data: V4l2PlaneMutAccessor<'a>,
820     backing: &'a mut M::RawBacking,
821 }
822 
823 impl<'a, M: Memory> Deref for V4l2PlaneMutAccessorWithRawBacking<'a, M> {
824     type Target = V4l2PlaneMutAccessor<'a>;
825 
deref(&self) -> &Self::Target826     fn deref(&self) -> &Self::Target {
827         &self.data
828     }
829 }
830 
831 impl<'a, M: Memory> DerefMut for V4l2PlaneMutAccessorWithRawBacking<'a, M> {
deref_mut(&mut self) -> &mut Self::Target832     fn deref_mut(&mut self) -> &mut Self::Target {
833         &mut self.data
834     }
835 }
836 
837 impl<'a, M: Memory> V4l2PlaneMutAccessorWithRawBacking<'a, M> {
838     /// Create a new plane accessor for memory type `M`.
839     ///
840     /// # Safety
841     ///
842     /// `v4l2_buffer` must be of a single-planar type and use memory type `M`.
new_single_planar(buffer: &'a mut bindings::v4l2_buffer) -> Self843     pub unsafe fn new_single_planar(buffer: &'a mut bindings::v4l2_buffer) -> Self {
844         Self {
845             data: V4l2PlaneMutAccessor {
846                 bytesused: &mut buffer.bytesused,
847                 length: &mut buffer.length,
848                 data_offset: None,
849             },
850             backing: M::get_single_planar_buffer_backing_mut(&mut buffer.m),
851         }
852     }
853 
854     /// Create a new plane accessor for memory type `M`.
855     ///
856     /// # Safety
857     ///
858     /// `v4l2_plane` must come from a multi-planar buffer using memory type `M`.
new_multi_planar(plane: &'a mut bindings::v4l2_plane) -> Self859     pub unsafe fn new_multi_planar(plane: &'a mut bindings::v4l2_plane) -> Self {
860         Self {
861             data: V4l2PlaneMutAccessor {
862                 bytesused: &mut plane.bytesused,
863                 length: &mut plane.length,
864                 data_offset: Some(&mut plane.data_offset),
865             },
866             backing: M::get_plane_buffer_backing_mut(&mut plane.m),
867         }
868     }
869 }
870 
871 impl<'a> V4l2PlaneMutAccessorWithRawBacking<'a, Mmap> {
mem_offset(&self) -> <Mmap as Memory>::RawBacking872     pub fn mem_offset(&self) -> <Mmap as Memory>::RawBacking {
873         *self.backing
874     }
875 
set_mem_offset(&mut self, mem_offset: <Mmap as Memory>::RawBacking)876     pub fn set_mem_offset(&mut self, mem_offset: <Mmap as Memory>::RawBacking) {
877         *self.backing = mem_offset;
878     }
879 }
880 
881 impl<'a> V4l2PlaneMutAccessorWithRawBacking<'a, UserPtr> {
userptr(&self) -> <UserPtr as Memory>::RawBacking882     pub fn userptr(&self) -> <UserPtr as Memory>::RawBacking {
883         *self.backing
884     }
885 
set_userptr(&mut self, userptr: <UserPtr as Memory>::RawBacking)886     pub fn set_userptr(&mut self, userptr: <UserPtr as Memory>::RawBacking) {
887         *self.backing = userptr;
888     }
889 }
890 
891 impl<'a> V4l2PlaneMutAccessorWithRawBacking<'a, DmaBuf> {
fd(&self) -> <DmaBuf as Memory>::RawBacking892     pub fn fd(&self) -> <DmaBuf as Memory>::RawBacking {
893         *self.backing
894     }
895 
set_fd(&mut self, fd: <DmaBuf as Memory>::RawBacking)896     pub fn set_fd(&mut self, fd: <DmaBuf as Memory>::RawBacking) {
897         *self.backing = fd;
898     }
899 }
900 
901 pub enum V4l2PlanesWithBackingMut<
902     'a,
903     M: Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<'a, Mmap>>,
904     U: Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<'a, UserPtr>>,
905     D: Iterator<Item = V4l2PlaneMutAccessorWithRawBacking<'a, DmaBuf>>,
906 > {
907     Mmap(M),
908     UserPtr(U),
909     DmaBuf(D),
910     Overlay,
911 }
912 
913 #[derive(Debug, Error)]
914 pub enum V4l2BufferFromError {
915     #[error("unknown queue type {0}")]
916     UnknownQueueType(u32),
917     #[error("unknown memory type {0}")]
918     UnknownMemoryType(u32),
919 }
920 
921 impl TryFrom<UncheckedV4l2Buffer> for V4l2Buffer {
922     type Error = V4l2BufferFromError;
923 
924     /// Do some consistency checks to ensure methods of `V4l2Buffer` that do an `unwrap` can never
925     /// fail.
try_from(buffer: UncheckedV4l2Buffer) -> Result<Self, Self::Error>926     fn try_from(buffer: UncheckedV4l2Buffer) -> Result<Self, Self::Error> {
927         let v4l2_buf = buffer.0;
928         let v4l2_planes = buffer.1;
929         QueueType::n(v4l2_buf.type_)
930             .ok_or(V4l2BufferFromError::UnknownQueueType(v4l2_buf.type_))?;
931         MemoryType::n(v4l2_buf.memory)
932             .ok_or(V4l2BufferFromError::UnknownMemoryType(v4l2_buf.memory))?;
933 
934         Ok(Self {
935             buffer: v4l2_buf,
936             planes: v4l2_planes.unwrap_or_default(),
937         })
938     }
939 }
940 
941 /// Representation of a validated multi-planar `struct v4l2_format`. It provides accessors returning proper
942 /// types instead of `u32`s.
943 #[derive(Clone)]
944 #[repr(transparent)]
945 pub struct V4l2MplaneFormat(bindings::v4l2_format);
946 
947 impl AsRef<bindings::v4l2_format> for V4l2MplaneFormat {
as_ref(&self) -> &bindings::v4l2_format948     fn as_ref(&self) -> &bindings::v4l2_format {
949         &self.0
950     }
951 }
952 
953 impl AsRef<bindings::v4l2_pix_format_mplane> for V4l2MplaneFormat {
as_ref(&self) -> &bindings::v4l2_pix_format_mplane954     fn as_ref(&self) -> &bindings::v4l2_pix_format_mplane {
955         // SAFETY: safe because we verify that the format is pixel multiplanar at construction
956         // time.
957         unsafe { &self.0.fmt.pix_mp }
958     }
959 }
960 
961 #[derive(Debug, Error)]
962 pub enum V4l2MplaneFormatFromError {
963     #[error("format is not multi-planar")]
964     NotMultiPlanar,
965     #[error("invalid field type {0}")]
966     InvalidField(u32),
967     #[error("invalid colorspace {0}")]
968     InvalidColorSpace(u32),
969     #[error("invalid number of planes {0}")]
970     InvalidPlanesNumber(u8),
971     #[error("invalid YCbCr encoding {0}")]
972     InvalidYCbCr(u8),
973     #[error("invalid quantization {0}")]
974     InvalidQuantization(u8),
975     #[error("invalid Xfer func {0}")]
976     InvalidXferFunc(u8),
977 }
978 
979 /// Turn a `struct v4l2_format` into its validated version, returning an error if any of the fields
980 /// cannot be validated.
981 impl TryFrom<bindings::v4l2_format> for V4l2MplaneFormat {
982     type Error = V4l2MplaneFormatFromError;
983 
try_from(format: bindings::v4l2_format) -> Result<Self, Self::Error>984     fn try_from(format: bindings::v4l2_format) -> Result<Self, Self::Error> {
985         if !matches!(
986             QueueType::n(format.type_),
987             Some(QueueType::VideoCaptureMplane) | Some(QueueType::VideoOutputMplane)
988         ) {
989             return Err(V4l2MplaneFormatFromError::NotMultiPlanar);
990         }
991         let pix_mp = unsafe { &format.fmt.pix_mp };
992 
993         if pix_mp.num_planes == 0 || pix_mp.num_planes > bindings::VIDEO_MAX_PLANES as u8 {
994             return Err(V4l2MplaneFormatFromError::InvalidPlanesNumber(
995                 pix_mp.num_planes,
996             ));
997         }
998 
999         let _ = BufferField::n(pix_mp.field)
1000             .ok_or(V4l2MplaneFormatFromError::InvalidField(pix_mp.field))?;
1001         let _ = Colorspace::n(pix_mp.colorspace).ok_or(
1002             V4l2MplaneFormatFromError::InvalidColorSpace(pix_mp.colorspace),
1003         )?;
1004         let ycbcr_enc = unsafe { pix_mp.__bindgen_anon_1.ycbcr_enc };
1005         let _ = YCbCrEncoding::n(ycbcr_enc as u32)
1006             .ok_or(V4l2MplaneFormatFromError::InvalidYCbCr(ycbcr_enc));
1007 
1008         let _ = Quantization::n(pix_mp.quantization as u32).ok_or(
1009             V4l2MplaneFormatFromError::InvalidQuantization(pix_mp.quantization),
1010         )?;
1011         let _ = XferFunc::n(pix_mp.xfer_func as u32)
1012             .ok_or(V4l2MplaneFormatFromError::InvalidXferFunc(pix_mp.xfer_func))?;
1013 
1014         Ok(Self(format))
1015     }
1016 }
1017 
1018 /// Turn a `struct v4l2_pix_format_mplane` into its validated version, turning any field that can
1019 /// not be validated into its default value.
1020 impl From<(QueueDirection, bindings::v4l2_pix_format_mplane)> for V4l2MplaneFormat {
from((direction, mut pix_mp): (QueueDirection, bindings::v4l2_pix_format_mplane)) -> Self1021     fn from((direction, mut pix_mp): (QueueDirection, bindings::v4l2_pix_format_mplane)) -> Self {
1022         pix_mp.field = BufferField::n(pix_mp.field).unwrap_or_default() as u32;
1023         pix_mp.colorspace = Colorspace::n(pix_mp.colorspace).unwrap_or_default() as u32;
1024         let ycbcr_enc = unsafe { pix_mp.__bindgen_anon_1.ycbcr_enc };
1025         pix_mp.__bindgen_anon_1.ycbcr_enc =
1026             YCbCrEncoding::n(ycbcr_enc as u32).unwrap_or_default() as u8;
1027         pix_mp.quantization = Quantization::n(pix_mp.quantization as u32).unwrap_or_default() as u8;
1028         pix_mp.xfer_func = XferFunc::n(pix_mp.xfer_func as u32).unwrap_or_default() as u8;
1029 
1030         Self(bindings::v4l2_format {
1031             type_: QueueType::from_dir_and_class(direction, crate::QueueClass::VideoMplane) as u32,
1032             fmt: bindings::v4l2_format__bindgen_ty_1 { pix_mp },
1033         })
1034     }
1035 }
1036 
1037 impl V4l2MplaneFormat {
1038     /// Returns the direction of the MPLANE queue this format applies to.
direction(&self) -> QueueDirection1039     pub fn direction(&self) -> QueueDirection {
1040         QueueType::n(self.0.type_).unwrap().direction()
1041     }
1042 
size(&self) -> (u32, u32)1043     pub fn size(&self) -> (u32, u32) {
1044         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1045         (pix_mp.width, pix_mp.height)
1046     }
1047 
pixelformat(&self) -> PixelFormat1048     pub fn pixelformat(&self) -> PixelFormat {
1049         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1050         PixelFormat::from_u32(pix_mp.pixelformat)
1051     }
1052 
field(&self) -> BufferField1053     pub fn field(&self) -> BufferField {
1054         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1055         // Safe because we checked the boundaries at construction time.
1056         BufferField::n(pix_mp.field).unwrap()
1057     }
1058 
colorspace(&self) -> Colorspace1059     pub fn colorspace(&self) -> Colorspace {
1060         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1061         // Safe because we checked the boundaries at construction time.
1062         Colorspace::n(pix_mp.colorspace).unwrap()
1063     }
1064 
ycbcr_enc(&self) -> YCbCrEncoding1065     pub fn ycbcr_enc(&self) -> YCbCrEncoding {
1066         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1067         // Safe because we checked the boundaries at construction time.
1068         YCbCrEncoding::n(unsafe { pix_mp.__bindgen_anon_1.ycbcr_enc as u32 }).unwrap()
1069     }
1070 
quantization(&self) -> Quantization1071     pub fn quantization(&self) -> Quantization {
1072         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1073         Quantization::n(pix_mp.quantization as u32).unwrap()
1074     }
1075 
xfer_func(&self) -> XferFunc1076     pub fn xfer_func(&self) -> XferFunc {
1077         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1078         XferFunc::n(pix_mp.xfer_func as u32).unwrap()
1079     }
1080 
planes(&self) -> &[bindings::v4l2_plane_pix_format]1081     pub fn planes(&self) -> &[bindings::v4l2_plane_pix_format] {
1082         let pix_mp: &bindings::v4l2_pix_format_mplane = self.as_ref();
1083         &pix_mp.plane_fmt[0..pix_mp.num_planes.min(bindings::VIDEO_MAX_PLANES as u8) as usize]
1084     }
1085 }
1086 
1087 #[cfg(test)]
1088 mod tests {
1089     use crate::{bindings, QueueType};
1090 
1091     use super::UncheckedV4l2Buffer;
1092 
1093     #[test]
test_string_from_cstr()1094     fn test_string_from_cstr() {
1095         use super::string_from_cstr;
1096 
1097         // Nul-terminated slice.
1098         assert_eq!(string_from_cstr(b"Hello\0"), Ok(String::from("Hello")));
1099 
1100         // Slice with nul in the middle and not nul-terminated.
1101         assert_eq!(string_from_cstr(b"Hi\0lo"), Ok(String::from("Hi")));
1102 
1103         // Slice with nul in the middle and nul-terminated.
1104         assert_eq!(string_from_cstr(b"Hi\0lo\0"), Ok(String::from("Hi")));
1105 
1106         // Slice starting with nul.
1107         assert_eq!(string_from_cstr(b"\0ello"), Ok(String::from("")));
1108 
1109         // Slice without nul.
1110         match string_from_cstr(b"Hello") {
1111             Err(_) => {}
1112             Ok(_) => panic!(),
1113         };
1114 
1115         // Empty slice.
1116         match string_from_cstr(b"") {
1117             Err(_) => {}
1118             Ok(_) => panic!(),
1119         };
1120     }
1121 
1122     #[test]
test_unchecked_v4l2_buffer()1123     fn test_unchecked_v4l2_buffer() {
1124         // Single-planar.
1125         let mut v4l2_buf = UncheckedV4l2Buffer::new_for_querybuf(QueueType::VideoCapture, Some(2));
1126         assert_eq!(v4l2_buf.0.type_, QueueType::VideoCapture as u32);
1127         assert_eq!(v4l2_buf.0.index, 2);
1128         assert_eq!(v4l2_buf.0.length, 0);
1129         assert!(v4l2_buf.1.is_none());
1130         assert_eq!(unsafe { v4l2_buf.as_mut().m.planes }, std::ptr::null_mut());
1131 
1132         // Multi-planar.
1133         let mut v4l2_buf =
1134             UncheckedV4l2Buffer::new_for_querybuf(QueueType::VideoCaptureMplane, None);
1135         assert_eq!(v4l2_buf.0.type_, QueueType::VideoCaptureMplane as u32);
1136         assert_eq!(v4l2_buf.0.index, 0);
1137         assert_eq!(v4l2_buf.0.length, bindings::VIDEO_MAX_PLANES);
1138         assert!(v4l2_buf.1.is_some());
1139         let planes_ptr = v4l2_buf.1.as_mut().map(|p| p.as_mut_ptr()).unwrap();
1140         let v4l2_buf_ref = v4l2_buf.as_mut();
1141         assert_eq!(unsafe { v4l2_buf_ref.m.planes }, planes_ptr);
1142     }
1143 }
1144