1use std::os::unix::io::AsRawFd;
2
3use nix::errno::Errno;
4use thiserror::Error;
5
6use crate::bindings::v4l2_standard;
7use crate::bindings::v4l2_std_id;
8use crate::bindings::v4l2_streamparm;
9use crate::QueueType;
10
11#[doc(hidden)]
12mod ioctl {
13 use crate::bindings::v4l2_standard;
14 use crate::bindings::v4l2_std_id;
15 use crate::bindings::v4l2_streamparm;
16
17 nix::ioctl_readwrite!(vidioc_g_parm, b'V', 21, v4l2_streamparm);
18 nix::ioctl_readwrite!(vidioc_s_parm, b'V', 22, v4l2_streamparm);
19 nix::ioctl_read!(vidioc_g_std, b'V', 23, v4l2_std_id);
20 nix::ioctl_write_ptr!(vidioc_s_std, b'V', 24, v4l2_std_id);
21 nix::ioctl_readwrite!(vidioc_enumstd, b'V', 25, v4l2_standard);
22 nix::ioctl_read!(vidioc_querystd, b'V', 63, v4l2_std_id);
23}
24
25#[derive(Debug, Error)]
26pub enum GParmError {
27 #[error("ioctl error: {0}")]
28 IoctlError(Errno),
29}
30
31impl From<GParmError> for Errno {
32 fn from(err: GParmError) -> Self {
33 match err {
34 GParmError::IoctlError(e) => e,
35 }
36 }
37}
38
39pub fn g_parm<O: From<v4l2_streamparm>>(
41 fd: &impl AsRawFd,
42 queue: QueueType,
43) -> Result<O, GParmError> {
44 let mut parm = v4l2_streamparm {
45 type_: queue as u32,
46 ..Default::default()
47 };
48
49 match unsafe { ioctl::vidioc_g_parm(fd.as_raw_fd(), &mut parm) } {
50 Ok(_) => Ok(O::from(parm)),
51 Err(e) => Err(GParmError::IoctlError(e)),
52 }
53}
54
55pub fn s_parm<I: Into<v4l2_streamparm>, O: From<v4l2_streamparm>>(
57 fd: &impl AsRawFd,
58 parm: I,
59) -> Result<O, GParmError> {
60 let mut parm = parm.into();
61
62 match unsafe { ioctl::vidioc_s_parm(fd.as_raw_fd(), &mut parm) } {
63 Ok(_) => Ok(O::from(parm)),
64 Err(e) => Err(GParmError::IoctlError(e)),
65 }
66}
67
68pub fn g_std<O: From<v4l2_std_id>>(fd: &impl AsRawFd) -> Result<O, GParmError> {
70 let mut std_id: v4l2_std_id = 0;
71
72 match unsafe { ioctl::vidioc_g_std(fd.as_raw_fd(), &mut std_id) } {
73 Ok(_) => Ok(O::from(std_id)),
74 Err(e) => Err(GParmError::IoctlError(e)),
75 }
76}
77
78#[derive(Debug, Error)]
79pub enum SStdError {
80 #[error("unsupported standard requested")]
81 Unsupported,
82 #[error("ioctl error: {0}")]
83 IoctlError(Errno),
84}
85
86impl From<SStdError> for Errno {
87 fn from(err: SStdError) -> Self {
88 match err {
89 SStdError::Unsupported => Errno::EINVAL,
90 SStdError::IoctlError(e) => e,
91 }
92 }
93}
94
95pub fn s_std<I: Into<v4l2_std_id>>(fd: &impl AsRawFd, std_id: I) -> Result<(), SStdError> {
97 let std_id = std_id.into();
98
99 match unsafe { ioctl::vidioc_s_std(fd.as_raw_fd(), &std_id) } {
100 Ok(_) => Ok(()),
101 Err(Errno::EINVAL) => Err(SStdError::Unsupported),
102 Err(e) => Err(SStdError::IoctlError(e)),
103 }
104}
105
106#[derive(Debug, Error)]
107pub enum EnumStdError {
108 #[error("requested index is out of bounds")]
109 OutOfBounds,
110 #[error("standard video timings are not supported for this input or output")]
111 Unsupported,
112 #[error("ioctl error: {0}")]
113 IoctlError(Errno),
114}
115
116impl From<EnumStdError> for Errno {
117 fn from(err: EnumStdError) -> Self {
118 match err {
119 EnumStdError::OutOfBounds => Errno::EINVAL,
120 EnumStdError::Unsupported => Errno::ENODATA,
121 EnumStdError::IoctlError(e) => e,
122 }
123 }
124}
125
126pub fn enumstd<O: From<v4l2_standard>>(fd: &impl AsRawFd, index: u32) -> Result<O, EnumStdError> {
128 let mut standard = v4l2_standard {
129 index,
130 ..Default::default()
131 };
132
133 match unsafe { ioctl::vidioc_enumstd(fd.as_raw_fd(), &mut standard) } {
134 Ok(_) => Ok(O::from(standard)),
135 Err(Errno::EINVAL) => Err(EnumStdError::OutOfBounds),
136 Err(Errno::ENODATA) => Err(EnumStdError::Unsupported),
137 Err(e) => Err(EnumStdError::IoctlError(e)),
138 }
139}
140
141pub fn querystd<O: From<v4l2_std_id>>(fd: &impl AsRawFd) -> Result<O, GParmError> {
143 let mut std_id: v4l2_std_id = 0;
144
145 match unsafe { ioctl::vidioc_querystd(fd.as_raw_fd(), &mut std_id) } {
146 Ok(_) => Ok(O::from(std_id)),
147 Err(e) => Err(GParmError::IoctlError(e)),
148 }
149}