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