1 use nix::errno::Errno;
2 use std::os::unix::io::AsRawFd;
3 use thiserror::Error;
4 
5 use crate::bindings;
6 use crate::bindings::v4l2_frmivalenum;
7 use crate::PixelFormat;
8 
9 /// A wrapper for the 'v4l2_frmivalenum' union member types
10 #[derive(Debug)]
11 pub enum FrmIvalTypes<'a> {
12     Discrete(&'a bindings::v4l2_fract),
13     StepWise(&'a bindings::v4l2_frmival_stepwise),
14 }
15 
16 impl v4l2_frmivalenum {
17     /// Safely access the intervals member of the struct based on the
18     /// returned type.
intervals(&self) -> Option<FrmIvalTypes>19     pub fn intervals(&self) -> Option<FrmIvalTypes> {
20         match self.type_ {
21             // SAFETY: the member of the union that gets used by the driver
22             // is determined by the type
23             bindings::v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_DISCRETE => {
24                 Some(FrmIvalTypes::Discrete(unsafe {
25                     &self.__bindgen_anon_1.discrete
26                 }))
27             }
28 
29             // SAFETY: the member of the union that gets used by the driver
30             // is determined by the type
31             bindings::v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_CONTINUOUS
32             | bindings::v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_STEPWISE => {
33                 Some(FrmIvalTypes::StepWise(unsafe {
34                     &self.__bindgen_anon_1.stepwise
35                 }))
36             }
37 
38             _ => None,
39         }
40     }
41 }
42 
43 #[doc(hidden)]
44 mod ioctl {
45     use crate::bindings::v4l2_frmivalenum;
46     nix::ioctl_readwrite!(vidioc_enum_frameintervals, b'V', 75, v4l2_frmivalenum);
47 }
48 
49 #[derive(Debug, Error)]
50 pub enum FrameIntervalsError {
51     #[error("Unexpected ioctl error: {0}")]
52     IoctlError(nix::Error),
53 }
54 
55 impl From<FrameIntervalsError> for Errno {
from(err: FrameIntervalsError) -> Self56     fn from(err: FrameIntervalsError) -> Self {
57         match err {
58             FrameIntervalsError::IoctlError(e) => e,
59         }
60     }
61 }
62 /// Safe wrapper around the `VIDIOC_ENUM_FRAMEINTERVALS` ioctl.
enum_frame_intervals<O: From<v4l2_frmivalenum>>( fd: &impl AsRawFd, index: u32, pixel_format: PixelFormat, width: u32, height: u32, ) -> Result<O, FrameIntervalsError>63 pub fn enum_frame_intervals<O: From<v4l2_frmivalenum>>(
64     fd: &impl AsRawFd,
65     index: u32,
66     pixel_format: PixelFormat,
67     width: u32,
68     height: u32,
69 ) -> Result<O, FrameIntervalsError> {
70     let mut frame_interval = v4l2_frmivalenum {
71         index,
72         pixel_format: pixel_format.into(),
73         width,
74         height,
75         ..Default::default()
76     };
77 
78     match unsafe { ioctl::vidioc_enum_frameintervals(fd.as_raw_fd(), &mut frame_interval) } {
79         Ok(_) => Ok(O::from(frame_interval)),
80         Err(e) => Err(FrameIntervalsError::IoctlError(e)),
81     }
82 }
83