blob: 153a55c2f73b134451d7b0c9729cf3e1fdbe3ed3 [file] [log] [blame]
use super::{is_multi_planar, BufferFlags, PlaneData};
use crate::bindings;
use crate::QueueType;
use crate::Result;
use std::mem;
use std::os::unix::io::AsRawFd;
/// Implementors can receive the result from the `querybuf` ioctl.
pub trait QueryBuf: Sized {
/// Try to retrieve the data from `v4l2_buf`. If `v4l2_planes` is `None`,
/// then the buffer is single-planar. If it has data, the buffer is
/// multi-planar and the array of `struct v4l2_plane` shall be used to
/// retrieve the plane data.
fn from_v4l2_buffer(
v4l2_buf: &bindings::v4l2_buffer,
v4l2_planes: Option<&PlaneData>,
) -> Result<Self>;
}
#[derive(Debug)]
pub struct QueryBufPlane {
/// Offset to pass to `mmap()` in order to obtain a mapping for this plane.
pub mem_offset: u32,
/// Length of this plane.
pub length: u32,
}
/// Contains all the information that makes sense when using `querybuf`.
#[derive(Debug)]
pub struct QueryBuffer {
pub index: usize,
pub flags: BufferFlags,
pub planes: Vec<QueryBufPlane>,
}
impl QueryBuf for QueryBuffer {
fn from_v4l2_buffer(
v4l2_buf: &bindings::v4l2_buffer,
v4l2_planes: Option<&PlaneData>,
) -> Result<Self> {
let planes = match v4l2_planes {
None => vec![QueryBufPlane {
mem_offset: unsafe { v4l2_buf.m.offset },
length: v4l2_buf.length,
}],
Some(v4l2_planes) => v4l2_planes
.iter()
.take(v4l2_buf.length as usize)
.map(|v4l2_plane| QueryBufPlane {
mem_offset: unsafe { v4l2_plane.m.mem_offset },
length: v4l2_plane.length,
})
.collect(),
};
Ok(QueryBuffer {
index: v4l2_buf.index as usize,
flags: BufferFlags::from_bits_truncate(v4l2_buf.flags),
planes,
})
}
}
#[doc(hidden)]
mod ioctl {
use crate::bindings::v4l2_buffer;
nix::ioctl_readwrite!(vidioc_querybuf, b'V', 9, v4l2_buffer);
}
/// Safe wrapper around the `VIDIOC_QUERYBUF` ioctl.
pub fn querybuf<T: QueryBuf, F: AsRawFd>(fd: &F, queue: QueueType, index: usize) -> Result<T> {
let mut v4l2_buf = bindings::v4l2_buffer {
index: index as u32,
type_: queue as u32,
..unsafe { mem::zeroed() }
};
if is_multi_planar(queue) {
let mut plane_data: PlaneData = Default::default();
v4l2_buf.m.planes = plane_data.as_mut_ptr();
v4l2_buf.length = plane_data.len() as u32;
unsafe { ioctl::vidioc_querybuf(fd.as_raw_fd(), &mut v4l2_buf) }?;
Ok(T::from_v4l2_buffer(&v4l2_buf, Some(&plane_data))?)
} else {
unsafe { ioctl::vidioc_querybuf(fd.as_raw_fd(), &mut v4l2_buf) }?;
Ok(T::from_v4l2_buffer(&v4l2_buf, None)?)
}
}