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_frmsizeenum;
7 use crate::PixelFormat;
8 
9 /// A wrapper for the 'v4l2_frmsizeenum' union member types
10 #[derive(Debug)]
11 pub enum FrmSizeTypes<'a> {
12     Discrete(&'a bindings::v4l2_frmsize_discrete),
13     StepWise(&'a bindings::v4l2_frmsize_stepwise),
14 }
15 
16 impl v4l2_frmsizeenum {
17     /// Safely access the size member of the struct based on the
18     /// returned type.
size(&self) -> Option<FrmSizeTypes>19     pub fn size(&self) -> Option<FrmSizeTypes> {
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_frmsizetypes_V4L2_FRMSIZE_TYPE_DISCRETE => {
24                 Some(FrmSizeTypes::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_frmsizetypes_V4L2_FRMSIZE_TYPE_CONTINUOUS
32             | bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_STEPWISE => {
33                 Some(FrmSizeTypes::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_frmsizeenum;
46     nix::ioctl_readwrite!(vidioc_enum_framesizes, b'V', 74, v4l2_frmsizeenum);
47 }
48 
49 #[derive(Debug, Error)]
50 pub enum FrameSizeError {
51     #[error("Unexpected ioctl error: {0}")]
52     IoctlError(nix::Error),
53 }
54 
55 impl From<FrameSizeError> for Errno {
from(err: FrameSizeError) -> Self56     fn from(err: FrameSizeError) -> Self {
57         match err {
58             FrameSizeError::IoctlError(e) => e,
59         }
60     }
61 }
62 
63 /// Safe wrapper around the `VIDIOC_ENUM_FRAMESIZES` ioctl.
enum_frame_sizes<O: From<v4l2_frmsizeenum>>( fd: &impl AsRawFd, index: u32, pixel_format: PixelFormat, ) -> Result<O, FrameSizeError>64 pub fn enum_frame_sizes<O: From<v4l2_frmsizeenum>>(
65     fd: &impl AsRawFd,
66     index: u32,
67     pixel_format: PixelFormat,
68 ) -> Result<O, FrameSizeError> {
69     let mut frame_size = v4l2_frmsizeenum {
70         index,
71         pixel_format: pixel_format.into(),
72         ..Default::default()
73     };
74 
75     match unsafe { ioctl::vidioc_enum_framesizes(fd.as_raw_fd(), &mut frame_size) } {
76         Ok(_) => Ok(O::from(frame_size)),
77         Err(e) => Err(FrameSizeError::IoctlError(e)),
78     }
79 }
80