blob: 43f68d11aa436f4d2ad309a38138b51cb0a254f3 [file] [log] [blame]
use crate::bindings::v4l2_buffer;
use crate::ioctl::is_multi_planar;
use crate::ioctl::QueryBuf;
use crate::ioctl::V4l2BufferPlanes;
use crate::QueueType;
use std::fmt::Debug;
use std::mem;
use std::os::unix::io::AsRawFd;
use nix::errno::Errno;
use thiserror::Error;
#[doc(hidden)]
mod ioctl {
use crate::bindings::v4l2_buffer;
nix::ioctl_readwrite!(vidioc_dqbuf, b'V', 17, v4l2_buffer);
}
#[derive(Debug, Error)]
pub enum DqBufError<Q: QueryBuf> {
#[error("error while converting from v4l2_buffer: {0}")]
ConvertionError(Q::Error),
#[error("end-of-stream reached")]
Eos,
#[error("no buffer ready for dequeue")]
NotReady,
#[error("ioctl error: {0}")]
IoctlError(Errno),
}
impl<Q: QueryBuf> From<Errno> for DqBufError<Q> {
fn from(error: Errno) -> Self {
match error {
Errno::EAGAIN => Self::NotReady,
Errno::EPIPE => Self::Eos,
error => Self::IoctlError(error),
}
}
}
impl<Q: QueryBuf> From<DqBufError<Q>> for Errno {
fn from(err: DqBufError<Q>) -> Self {
match err {
DqBufError::ConvertionError(_) => Errno::EINVAL,
DqBufError::Eos => Errno::EPIPE,
DqBufError::NotReady => Errno::EAGAIN,
DqBufError::IoctlError(e) => e,
}
}
}
pub type DqBufResult<T, Q> = Result<T, DqBufError<Q>>;
/// Safe wrapper around the `VIDIOC_DQBUF` ioctl.
pub fn dqbuf<T: QueryBuf>(fd: &impl AsRawFd, queue: QueueType) -> DqBufResult<T, T> {
let mut v4l2_buf = v4l2_buffer {
type_: queue as u32,
..unsafe { mem::zeroed() }
};
let dequeued_buffer = if is_multi_planar(queue) {
let mut plane_data: V4l2BufferPlanes = Default::default();
v4l2_buf.m.planes = plane_data.as_mut_ptr();
v4l2_buf.length = plane_data.len() as u32;
unsafe { ioctl::vidioc_dqbuf(fd.as_raw_fd(), &mut v4l2_buf) }?;
T::try_from_v4l2_buffer(v4l2_buf, Some(plane_data)).map_err(DqBufError::ConvertionError)?
} else {
unsafe { ioctl::vidioc_dqbuf(fd.as_raw_fd(), &mut v4l2_buf) }?;
T::try_from_v4l2_buffer(v4l2_buf, None).map_err(DqBufError::ConvertionError)?
};
Ok(dequeued_buffer)
}