1 //! Safe wrapper for the `VIDIOC_REQBUFS` ioctl.
2 use crate::bindings;
3 use crate::bindings::v4l2_create_buffers;
4 use crate::bindings::v4l2_format;
5 use crate::bindings::v4l2_requestbuffers;
6 use crate::memory::MemoryType;
7 use crate::QueueType;
8 use bitflags::bitflags;
9 use nix::{self, errno::Errno};
10 use std::os::unix::io::AsRawFd;
11 use thiserror::Error;
12
13 bitflags! {
14 /// Flags returned by the `VIDIOC_REQBUFS` ioctl into the `capabilities`
15 /// field of `struct v4l2_requestbuffers`.
16 #[derive(Clone, Copy, Debug)]
17 pub struct BufferCapabilities: u32 {
18 const SUPPORTS_MMAP = bindings::V4L2_BUF_CAP_SUPPORTS_MMAP;
19 const SUPPORTS_USERPTR = bindings::V4L2_BUF_CAP_SUPPORTS_USERPTR;
20 const SUPPORTS_DMABUF = bindings::V4L2_BUF_CAP_SUPPORTS_DMABUF;
21 const SUPPORTS_REQUESTS = bindings::V4L2_BUF_CAP_SUPPORTS_REQUESTS;
22 const SUPPORTS_ORPHANED_BUFS = bindings::V4L2_BUF_CAP_SUPPORTS_ORPHANED_BUFS;
23 //const SUPPORTS_M2M_HOLD_CAPTURE_BUF = bindings::V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF;
24 }
25 }
26
27 impl From<v4l2_requestbuffers> for () {
from(_reqbufs: v4l2_requestbuffers) -> Self28 fn from(_reqbufs: v4l2_requestbuffers) -> Self {}
29 }
30
31 /// In case we are just interested in the number of buffers that `reqbufs`
32 /// created.
33 impl From<v4l2_requestbuffers> for usize {
from(reqbufs: v4l2_requestbuffers) -> Self34 fn from(reqbufs: v4l2_requestbuffers) -> Self {
35 reqbufs.count as usize
36 }
37 }
38
39 /// If we just want to query the buffer capabilities.
40 impl From<v4l2_requestbuffers> for BufferCapabilities {
from(reqbufs: v4l2_requestbuffers) -> Self41 fn from(reqbufs: v4l2_requestbuffers) -> Self {
42 BufferCapabilities::from_bits_truncate(reqbufs.capabilities)
43 }
44 }
45
46 /// Full result of the `reqbufs` ioctl.
47 pub struct RequestBuffers {
48 pub count: u32,
49 pub capabilities: BufferCapabilities,
50 }
51
52 impl From<v4l2_requestbuffers> for RequestBuffers {
from(reqbufs: v4l2_requestbuffers) -> Self53 fn from(reqbufs: v4l2_requestbuffers) -> Self {
54 RequestBuffers {
55 count: reqbufs.count,
56 capabilities: BufferCapabilities::from_bits_truncate(reqbufs.capabilities),
57 }
58 }
59 }
60
61 #[doc(hidden)]
62 mod ioctl {
63 use crate::bindings::v4l2_create_buffers;
64 use crate::bindings::v4l2_requestbuffers;
65
66 nix::ioctl_readwrite!(vidioc_reqbufs, b'V', 8, v4l2_requestbuffers);
67 nix::ioctl_readwrite!(vidioc_create_bufs, b'V', 92, v4l2_create_buffers);
68 }
69
70 #[derive(Debug, Error)]
71 pub enum ReqbufsError {
72 #[error("invalid buffer ({0}) or memory type ({1:?}) requested")]
73 InvalidBufferType(QueueType, MemoryType),
74 #[error("ioctl error: {0}")]
75 IoctlError(nix::Error),
76 }
77
78 impl From<ReqbufsError> for Errno {
from(err: ReqbufsError) -> Self79 fn from(err: ReqbufsError) -> Self {
80 match err {
81 ReqbufsError::InvalidBufferType(_, _) => Errno::EINVAL,
82 ReqbufsError::IoctlError(e) => e,
83 }
84 }
85 }
86
87 /// Safe wrapper around the `VIDIOC_REQBUFS` ioctl.
reqbufs<O: From<v4l2_requestbuffers>>( fd: &impl AsRawFd, queue: QueueType, memory: MemoryType, count: u32, ) -> Result<O, ReqbufsError>88 pub fn reqbufs<O: From<v4l2_requestbuffers>>(
89 fd: &impl AsRawFd,
90 queue: QueueType,
91 memory: MemoryType,
92 count: u32,
93 ) -> Result<O, ReqbufsError> {
94 let mut reqbufs = v4l2_requestbuffers {
95 count,
96 type_: queue as u32,
97 memory: memory as u32,
98 ..Default::default()
99 };
100
101 match unsafe { ioctl::vidioc_reqbufs(fd.as_raw_fd(), &mut reqbufs) } {
102 Ok(_) => Ok(O::from(reqbufs)),
103 Err(Errno::EINVAL) => Err(ReqbufsError::InvalidBufferType(queue, memory)),
104 Err(e) => Err(ReqbufsError::IoctlError(e)),
105 }
106 }
107
108 #[derive(Debug, Error)]
109 pub enum CreateBufsError {
110 #[error("no memory available to allocate MMAP buffers")]
111 NoMem,
112 #[error("invalid format or memory type requested")]
113 Invalid,
114 #[error("ioctl error: {0}")]
115 IoctlError(nix::Error),
116 }
117
118 impl From<CreateBufsError> for Errno {
from(err: CreateBufsError) -> Self119 fn from(err: CreateBufsError) -> Self {
120 match err {
121 CreateBufsError::NoMem => Errno::ENOMEM,
122 CreateBufsError::Invalid => Errno::EINVAL,
123 CreateBufsError::IoctlError(e) => e,
124 }
125 }
126 }
127
128 /// Safe wrapper around the `VIDIOC_CREATE_BUFS` ioctl.
create_bufs<F: Into<v4l2_format>, O: From<v4l2_create_buffers>>( fd: &impl AsRawFd, count: u32, memory: MemoryType, format: F, ) -> Result<O, CreateBufsError>129 pub fn create_bufs<F: Into<v4l2_format>, O: From<v4l2_create_buffers>>(
130 fd: &impl AsRawFd,
131 count: u32,
132 memory: MemoryType,
133 format: F,
134 ) -> Result<O, CreateBufsError> {
135 let mut create_bufs = v4l2_create_buffers {
136 count,
137 memory: memory as u32,
138 format: format.into(),
139 ..Default::default()
140 };
141
142 match unsafe { ioctl::vidioc_create_bufs(fd.as_raw_fd(), &mut create_bufs) } {
143 Ok(_) => Ok(O::from(create_bufs)),
144 Err(Errno::ENOMEM) => Err(CreateBufsError::NoMem),
145 Err(Errno::EINVAL) => Err(CreateBufsError::Invalid),
146 Err(e) => Err(CreateBufsError::IoctlError(e)),
147 }
148 }
149