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