v4l2r 0.0.7

Safe and flexible abstraction over V4L2
Documentation
use nix::errno::Errno;
use std::os::unix::io::AsRawFd;
use thiserror::Error;

use crate::bindings;
use crate::bindings::v4l2_frmivalenum;
use crate::PixelFormat;

/// A wrapper for the 'v4l2_frmivalenum' union member types
#[derive(Debug)]
pub enum FrmIvalTypes<'a> {
    Discrete(&'a bindings::v4l2_fract),
    StepWise(&'a bindings::v4l2_frmival_stepwise),
}

impl v4l2_frmivalenum {
    /// Safely access the intervals member of the struct based on the
    /// returned type.
    pub fn intervals(&self) -> Option<FrmIvalTypes> {
        match self.type_ {
            // SAFETY: the member of the union that gets used by the driver
            // is determined by the type
            bindings::v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_DISCRETE => {
                Some(FrmIvalTypes::Discrete(unsafe {
                    &self.__bindgen_anon_1.discrete
                }))
            }

            // SAFETY: the member of the union that gets used by the driver
            // is determined by the type
            bindings::v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_CONTINUOUS
            | bindings::v4l2_frmivaltypes_V4L2_FRMIVAL_TYPE_STEPWISE => {
                Some(FrmIvalTypes::StepWise(unsafe {
                    &self.__bindgen_anon_1.stepwise
                }))
            }

            _ => None,
        }
    }
}

#[doc(hidden)]
mod ioctl {
    use crate::bindings::v4l2_frmivalenum;
    nix::ioctl_readwrite!(vidioc_enum_frameintervals, b'V', 75, v4l2_frmivalenum);
}

#[derive(Debug, Error)]
pub enum FrameIntervalsError {
    #[error("Unexpected ioctl error: {0}")]
    IoctlError(nix::Error),
}

impl From<FrameIntervalsError> for Errno {
    fn from(err: FrameIntervalsError) -> Self {
        match err {
            FrameIntervalsError::IoctlError(e) => e,
        }
    }
}
/// Safe wrapper around the `VIDIOC_ENUM_FRAMEINTERVALS` ioctl.
pub fn enum_frame_intervals<O: From<v4l2_frmivalenum>>(
    fd: &impl AsRawFd,
    index: u32,
    pixel_format: PixelFormat,
    width: u32,
    height: u32,
) -> Result<O, FrameIntervalsError> {
    let mut frame_interval = v4l2_frmivalenum {
        index,
        pixel_format: pixel_format.into(),
        width,
        height,
        ..Default::default()
    };

    match unsafe { ioctl::vidioc_enum_frameintervals(fd.as_raw_fd(), &mut frame_interval) } {
        Ok(_) => Ok(O::from(frame_interval)),
        Err(e) => Err(FrameIntervalsError::IoctlError(e)),
    }
}