1 use std::convert::Infallible;
2 use std::convert::TryFrom;
3 use std::os::unix::io::AsRawFd;
4
5 use nix::errno::Errno;
6 use thiserror::Error;
7
8 use crate::ioctl::ioctl_and_convert;
9 use crate::ioctl::BufferFlags;
10 use crate::ioctl::IoctlConvertError;
11 use crate::ioctl::IoctlConvertResult;
12 use crate::ioctl::UncheckedV4l2Buffer;
13 use crate::QueueType;
14
15 #[derive(Debug)]
16 pub struct QueryBufPlane {
17 /// Offset to pass to `mmap()` in order to obtain a mapping for this plane.
18 pub mem_offset: u32,
19 /// Length of this plane.
20 pub length: u32,
21 }
22
23 /// Contains information about a buffer's layout, as obtained from [`crate::ioctl::querybuf`].
24 ///
25 /// It is a subset of [`crate::ioctl::V4l2Buffer`], only more convenient on occasion because its
26 /// conversion from an unchecked v4l2_buffer cannot fail.
27 ///
28 /// Single-planar buffers have one entry in [`planes`] representing the layout of their unique
29 /// plane.
30 #[derive(Debug)]
31 pub struct QueryBuffer {
32 pub index: usize,
33 pub flags: BufferFlags,
34 pub planes: Vec<QueryBufPlane>,
35 }
36
37 impl TryFrom<UncheckedV4l2Buffer> for QueryBuffer {
38 type Error = Infallible;
39
try_from(buffer: UncheckedV4l2Buffer) -> Result<Self, Self::Error>40 fn try_from(buffer: UncheckedV4l2Buffer) -> Result<Self, Self::Error> {
41 let v4l2_buf = buffer.0;
42 let planes = match buffer.1 {
43 None => vec![QueryBufPlane {
44 mem_offset: unsafe { v4l2_buf.m.offset },
45 length: v4l2_buf.length,
46 }],
47 Some(v4l2_planes) => v4l2_planes
48 .iter()
49 .take(v4l2_buf.length as usize)
50 .map(|v4l2_plane| QueryBufPlane {
51 mem_offset: unsafe { v4l2_plane.m.mem_offset },
52 length: v4l2_plane.length,
53 })
54 .collect(),
55 };
56
57 Ok(QueryBuffer {
58 index: v4l2_buf.index as usize,
59 flags: BufferFlags::from_bits_truncate(v4l2_buf.flags),
60 planes,
61 })
62 }
63 }
64
65 #[doc(hidden)]
66 mod ioctl {
67 use crate::bindings::v4l2_buffer;
68 nix::ioctl_readwrite!(vidioc_querybuf, b'V', 9, v4l2_buffer);
69 }
70
71 #[derive(Debug, Error)]
72 pub enum QueryBufIoctlError {
73 #[error("unsupported queue or out-of-bounds index")]
74 InvalidInput,
75 #[error("unexpected ioctl error: {0}")]
76 Other(Errno),
77 }
78
79 impl From<Errno> for QueryBufIoctlError {
from(err: Errno) -> Self80 fn from(err: Errno) -> Self {
81 match err {
82 Errno::EINVAL => QueryBufIoctlError::InvalidInput,
83 e => QueryBufIoctlError::Other(e),
84 }
85 }
86 }
87
88 impl From<QueryBufIoctlError> for Errno {
from(err: QueryBufIoctlError) -> Self89 fn from(err: QueryBufIoctlError) -> Self {
90 match err {
91 QueryBufIoctlError::InvalidInput => Errno::EINVAL,
92 QueryBufIoctlError::Other(e) => e,
93 }
94 }
95 }
96
97 pub type QueryBufError<CE> = IoctlConvertError<QueryBufIoctlError, CE>;
98 pub type QueryBufResult<O, CE> = IoctlConvertResult<O, QueryBufIoctlError, CE>;
99
100 /// Safe wrapper around the `VIDIOC_QUERYBUF` ioctl.
querybuf<O>(fd: &impl AsRawFd, queue: QueueType, index: usize) -> QueryBufResult<O, O::Error> where O: TryFrom<UncheckedV4l2Buffer>, O::Error: std::fmt::Debug,101 pub fn querybuf<O>(fd: &impl AsRawFd, queue: QueueType, index: usize) -> QueryBufResult<O, O::Error>
102 where
103 O: TryFrom<UncheckedV4l2Buffer>,
104 O::Error: std::fmt::Debug,
105 {
106 let mut v4l2_buf = UncheckedV4l2Buffer::new_for_querybuf(queue, Some(index as u32));
107
108 ioctl_and_convert(
109 unsafe { ioctl::vidioc_querybuf(fd.as_raw_fd(), v4l2_buf.as_mut()) }
110 .map(|_| v4l2_buf)
111 .map_err(Into::into),
112 )
113 }
114