blob: 4bb73993fd62283a2be0283ac622343e85bd6779 [file] [log] [blame]
use std::os::unix::io::AsRawFd;
use thiserror::Error;
use crate::{bindings, PixelFormat};
pub trait FrameIntervals {
fn from(input: bindings::v4l2_frmivalenum) -> Self;
}
impl FrameIntervals for bindings::v4l2_frmivalenum {
fn from(input: bindings::v4l2_frmivalenum) -> Self {
input
}
}
/// 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 bindings::v4l2_frmivalenum {
/// Safely access the intervals member of the struct based on the
/// returned index.
pub fn intervals(&self) -> Option<FrmIvalTypes> {
match self.index {
// SAFETY: the member of the union that gets used by the driver
// is determined by the index
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 index
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),
}
pub fn enum_frame_intervals<T: FrameIntervals>(
fd: &impl AsRawFd,
index: u32,
pixel_format: PixelFormat,
width: u32,
height: u32,
) -> Result<T, FrameIntervalsError> {
let mut frame_interval = bindings::v4l2_frmivalenum {
index,
pixel_format: pixel_format.into(),
width,
height,
..unsafe { std::mem::zeroed() }
};
match unsafe { ioctl::vidioc_enum_frameintervals(fd.as_raw_fd(), &mut frame_interval) } {
Ok(_) => Ok(T::from(frame_interval)),
Err(e) => Err(FrameIntervalsError::IoctlError(e)),
}
}