From 7391c14a279e56ec50df38a34805bc5688881a4c Mon Sep 17 00:00:00 2001 From: Michael Eden Date: Wed, 3 May 2023 09:58:23 -0400 Subject: [PATCH] multiplane capture stream --- src/buffer.rs | 9 ++++++ src/io/mmap/arena.rs | 66 ++++++++++++++++++++++++++++++++++--------- src/io/mmap/stream.rs | 32 +++++++++++++-------- 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index 7bdb2a3..4c30dcd 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -30,6 +30,15 @@ pub enum Type { Private = 0x80, } +impl Type { + pub fn planar(&self) -> bool { + match self { + Type::VideoCaptureMplane | Type::VideoOutputMplane => true, + _ => false, + } + } +} + bitflags! { #[allow(clippy::unreadable_literal)] pub struct Flags: u32 { diff --git a/src/io/mmap/arena.rs b/src/io/mmap/arena.rs index 9fae806..2d6dd97 100644 --- a/src/io/mmap/arena.rs +++ b/src/io/mmap/arena.rs @@ -12,8 +12,9 @@ use crate::v4l_sys::*; /// In case of errors during unmapping, we panic because there is memory corruption going on. pub struct Arena<'a> { handle: Arc, - pub bufs: Vec<&'a mut [u8]>, + pub bufs: Vec>, pub buf_type: buffer::Type, + pub planes: Vec>, } impl<'a> Arena<'a> { @@ -31,6 +32,7 @@ impl<'a> Arena<'a> { handle, bufs: Vec::new(), buf_type, + planes: Vec::new(), } } @@ -51,6 +53,24 @@ impl<'a> Arena<'a> { } pub fn allocate(&mut self, count: u32) -> io::Result { + let num_planes = if !self.buf_type.planar() { + 1 + } else { + // we need to get the number of image planes from the format + let mut v4l2_fmt: v4l2_format; + unsafe { + v4l2_fmt = mem::zeroed(); + v4l2_fmt.type_ = self.buf_type as u32; + v4l2::ioctl( + self.handle.fd(), + v4l2::vidioc::VIDIOC_G_FMT, + &mut v4l2_fmt as *mut _ as *mut std::os::raw::c_void, + )?; + + v4l2_fmt.fmt.pix_mp.num_planes as usize + } + }; + let mut v4l2_reqbufs = v4l2_requestbuffers { count, ..self.requestbuffers_desc() @@ -64,10 +84,18 @@ impl<'a> Arena<'a> { } for index in 0..v4l2_reqbufs.count { + let mut v4l2_planes: Vec = Vec::new(); + unsafe { + v4l2_planes.resize(num_planes as usize, mem::zeroed()); + } let mut v4l2_buf = v4l2_buffer { index, ..self.buffer_desc() }; + if self.buf_type.planar() { + v4l2_buf.length = num_planes as u32; + v4l2_buf.m.planes = v4l2_planes.as_mut_ptr(); + } unsafe { v4l2::ioctl( self.handle.fd(), @@ -75,18 +103,26 @@ impl<'a> Arena<'a> { &mut v4l2_buf as *mut _ as *mut std::os::raw::c_void, )?; - let ptr = v4l2::mmap( - ptr::null_mut(), - v4l2_buf.length as usize, - libc::PROT_READ | libc::PROT_WRITE, - libc::MAP_SHARED, - self.handle.fd(), - v4l2_buf.m.offset as libc::off_t, - )?; + // each plane has to be mapped separately + let mut planes = Vec::new(); + for plane in &v4l2_planes { + let ptr = v4l2::mmap( + ptr::null_mut(), + plane.length as usize, + libc::PROT_READ | libc::PROT_WRITE, + libc::MAP_SHARED, + self.handle.fd(), + plane.m.mem_offset as libc::off_t, + )?; + + planes.push(slice::from_raw_parts_mut::( + ptr as *mut u8, plane.length as usize + )); + } - let slice = - slice::from_raw_parts_mut::(ptr as *mut u8, v4l2_buf.length as usize); - self.bufs.push(slice); + // finally, add the buffer (with all its planes) to the set + self.bufs.push(planes); + self.planes.push(v4l2_planes); } } @@ -95,8 +131,10 @@ impl<'a> Arena<'a> { pub fn release(&mut self) -> io::Result<()> { for buf in &self.bufs { - unsafe { - v4l2::munmap(buf.as_ptr() as *mut core::ffi::c_void, buf.len())?; + for plane in buf { + unsafe { + v4l2::munmap(plane.as_ptr() as *mut core::ffi::c_void, buf.len())?; + } } } diff --git a/src/io/mmap/stream.rs b/src/io/mmap/stream.rs index cd666bd..6db2c43 100644 --- a/src/io/mmap/stream.rs +++ b/src/io/mmap/stream.rs @@ -3,7 +3,7 @@ use std::time::Duration; use std::{io, mem, sync::Arc}; use crate::buffer::{Metadata, Type}; -use crate::device::{Device, Handle}; +use crate::device::{PlanarDevice, Handle}; use crate::io::mmap::arena::Arena; use crate::io::traits::{CaptureStream, OutputStream, Stream as StreamTrait}; use crate::memory::Memory; @@ -44,11 +44,15 @@ impl<'a> Stream<'a> { /// let stream = Stream::new(&dev, Type::VideoCapture); /// } /// ``` - pub fn new(dev: &Device, buf_type: Type) -> io::Result { + pub fn new( + dev: &PlanarDevice, buf_type: Type + ) -> io::Result { Stream::with_buffers(dev, buf_type, 4) } - pub fn with_buffers(dev: &Device, buf_type: Type, buf_count: u32) -> io::Result { + pub fn with_buffers( + dev: &PlanarDevice, buf_type: Type, buf_count: u32 + ) -> io::Result { let mut arena = Arena::new(dev.handle(), buf_type); let count = arena.allocate(buf_count)?; let mut buf_meta = Vec::new(); @@ -80,12 +84,18 @@ impl<'a> Stream<'a> { self.timeout = None; } - fn buffer_desc(&self) -> v4l2_buffer { - v4l2_buffer { + fn buffer_desc(&mut self, index: usize) -> v4l2_buffer { + let mut v4l2_buf = v4l2_buffer { + index: index as u32, type_: self.buf_type as u32, memory: Memory::Mmap as u32, ..unsafe { mem::zeroed() } + }; + if self.buf_type.planar() { + v4l2_buf.length = self.arena.planes[index].len() as u32; + v4l2_buf.m.planes = self.arena.planes[index].as_mut_ptr(); } + v4l2_buf } } @@ -108,7 +118,7 @@ impl<'a> Drop for Stream<'a> { } impl<'a> StreamTrait for Stream<'a> { - type Item = [u8]; + type Item = Vec<&'a mut [u8]>; fn start(&mut self) -> io::Result<()> { unsafe { @@ -142,8 +152,7 @@ impl<'a> StreamTrait for Stream<'a> { impl<'a, 'b> CaptureStream<'b> for Stream<'a> { fn queue(&mut self, index: usize) -> io::Result<()> { let mut v4l2_buf = v4l2_buffer { - index: index as u32, - ..self.buffer_desc() + ..self.buffer_desc(index) }; unsafe { @@ -158,7 +167,7 @@ impl<'a, 'b> CaptureStream<'b> for Stream<'a> { } fn dequeue(&mut self) -> io::Result { - let mut v4l2_buf = self.buffer_desc(); + let mut v4l2_buf = self.buffer_desc(0); if self.handle.poll(libc::POLLIN, self.timeout.unwrap_or(-1))? == 0 { // This condition can only happen if there was a timeout. @@ -212,8 +221,7 @@ impl<'a, 'b> CaptureStream<'b> for Stream<'a> { impl<'a, 'b> OutputStream<'b> for Stream<'a> { fn queue(&mut self, index: usize) -> io::Result<()> { let mut v4l2_buf = v4l2_buffer { - index: index as u32, - ..self.buffer_desc() + ..self.buffer_desc(index) }; unsafe { // output settings @@ -244,7 +252,7 @@ impl<'a, 'b> OutputStream<'b> for Stream<'a> { } fn dequeue(&mut self) -> io::Result { - let mut v4l2_buf = self.buffer_desc(); + let mut v4l2_buf = self.buffer_desc(0); unsafe { v4l2::ioctl(