use std::{io, mem, sync::Arc};
use crate::buffer;
use crate::device::Handle;
use crate::memory::Memory;
use crate::v4l2;
use crate::v4l_sys::*;
pub struct Arena {
handle: Arc<Handle>,
pub bufs: Vec<Vec<u8>>,
pub buf_type: buffer::Type,
}
impl Arena {
pub fn new(handle: Arc<Handle>, buf_type: buffer::Type) -> Self {
Arena {
handle,
bufs: Vec::new(),
buf_type,
}
}
fn requestbuffers_desc(&self) -> v4l2_requestbuffers {
v4l2_requestbuffers {
type_: self.buf_type as u32,
memory: Memory::UserPtr as u32,
..unsafe { mem::zeroed() }
}
}
pub fn allocate(&mut self, count: u32) -> io::Result<u32> {
let mut v4l2_fmt = v4l2_format {
type_: self.buf_type as u32,
..unsafe { mem::zeroed() }
};
unsafe {
v4l2::ioctl(
self.handle.fd(),
v4l2::vidioc::VIDIOC_G_FMT,
&mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void,
)?;
}
#[cfg(feature = "v4l-sys")]
eprintln!(
"\n### WARNING ###\n\
As of early 2020, libv4l2 still does not support USERPTR buffers!\n\
You may want to use this crate with the raw v4l2 FFI bindings instead!\n"
);
let mut v4l2_reqbufs = v4l2_requestbuffers {
count,
..self.requestbuffers_desc()
};
unsafe {
v4l2::ioctl(
self.handle.fd(),
v4l2::vidioc::VIDIOC_REQBUFS,
&mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void,
)?;
}
self.bufs.resize(v4l2_reqbufs.count as usize, Vec::new());
for i in 0..v4l2_reqbufs.count {
let buf = &mut self.bufs[i as usize];
unsafe {
buf.resize(v4l2_fmt.fmt.pix.sizeimage as usize, 0);
}
}
Ok(v4l2_reqbufs.count)
}
pub fn release(&mut self) -> io::Result<()> {
let mut v4l2_reqbufs = v4l2_requestbuffers {
count: 0,
..self.requestbuffers_desc()
};
unsafe {
v4l2::ioctl(
self.handle.fd(),
v4l2::vidioc::VIDIOC_REQBUFS,
&mut v4l2_reqbufs as *mut _ as *mut std::os::raw::c_void,
)
}
}
}
impl Drop for Arena {
fn drop(&mut self) {
if self.bufs.is_empty() {
return;
}
if let Err(e) = self.release() {
if let Some(code) = e.raw_os_error() {
if code == 19 {
return;
}
}
panic!("{:?}", e)
}
}
}