//! Abstracts the different kinds of backing memory (`MMAP`, `USERPTR`, //! `DMABUF`) supported by V4L2. //! //! V4L2 allows to use either memory that is provided by the device itself //! (MMAP) or memory imported via user allocation (USERPTR) or the dma-buf //! subsystem (DMABUF). This results in 2 very different behaviors and 3 memory //! types that we need to model. //! //! The `Memory` trait represents these memory types and is thus implemented //! by exacly 3 types: `MMAP`, `UserPtr`, and `DMABuf`. These types do very //! little apart from providing a constant with the corresponding V4L2 memory //! type they model, and implement the `SelfBacked` (for MMAP) or `Imported` //! (for `UserPtr` and `DMABuf`) traits to indicate where their memory comes //! from. //! //! The `PlaneHandle` trait is used by types which can bind to one of these //! memory types, i.e. a type that can represent a single memory plane of a //! buffer. For `MMAP` memory this is a void type (since `MMAP` provides its //! own memory). `UserPtr`, a `Vec` can adequately be used as backing //! memory, and for `DMABuf` we will use a file descriptor. For handles that //! can be mapped into the user address-space (and indeed for `MMAP` this is //! the only way to access the memory), the `Mappable` trait can be implemented. //! //! The set of handles that make all the planes for a given buffer is //! represented by the `BufferHandles` trait. This trait is more abstract since //! we may want to decide at runtime the kind of memory we want to use ; //! therefore this trait does not have any particular kind of memory attached to //! it. `PrimitiveBufferHandles` is used to represent plane handles which memory //! type is known at compilation time, and thus includes a reference to a //! `PlaneHandle` type and by transition its `Memory` type. mod dmabuf; mod mmap; mod userptr; pub use dmabuf::*; pub use mmap::*; pub use userptr::*; use crate::{ bindings::{self, v4l2_buffer__bindgen_ty_1, v4l2_plane__bindgen_ty_1}, ioctl::{PlaneMapping, QueryBufPlane}, }; use enumn::N; use std::fmt::Debug; use std::os::unix::io::AsFd; /// All the supported V4L2 memory types. #[derive(Debug, Clone, Copy, PartialEq, Eq, N)] #[repr(u32)] pub enum MemoryType { Mmap = bindings::v4l2_memory_V4L2_MEMORY_MMAP, UserPtr = bindings::v4l2_memory_V4L2_MEMORY_USERPTR, Overlay = bindings::v4l2_memory_V4L2_MEMORY_OVERLAY, DmaBuf = bindings::v4l2_memory_V4L2_MEMORY_DMABUF, } /// Trait describing a memory type that can be used to back V4L2 buffers. pub trait Memory: 'static { /// The memory type represented. const MEMORY_TYPE: MemoryType; /// The final type of the memory backing information in `struct v4l2_buffer` or `struct /// v4l2_plane`. type RawBacking; /// Returns a reference to the memory backing information for `m` that is relevant for this /// memory type. /// /// # Safety /// /// The caller must ensure that `m` indeed belongs to a buffer of this memory type. unsafe fn get_plane_buffer_backing(m: &bindings::v4l2_plane__bindgen_ty_1) -> &Self::RawBacking; /// Returns a reference to the memory backing information for `m` that is relevant for this memory type. /// /// # Safety /// /// The caller must ensure that `m` indeed belongs to a buffer of this memory type. unsafe fn get_single_planar_buffer_backing( m: &bindings::v4l2_buffer__bindgen_ty_1, ) -> &Self::RawBacking; /// Returns a mutable reference to the memory backing information for `m` that is relevant for /// this memory type. /// /// # Safety /// /// The caller must ensure that `m` indeed belongs to a buffer of this memory type. unsafe fn get_plane_buffer_backing_mut( m: &mut bindings::v4l2_plane__bindgen_ty_1, ) -> &mut Self::RawBacking; /// Returns a mutable reference to the memory backing information for `m` that is relevant for /// this memory type. /// /// # Safety /// /// The caller must ensure that `m` indeed belongs to a buffer of this memory type. unsafe fn get_single_planar_buffer_backing_mut( m: &mut bindings::v4l2_buffer__bindgen_ty_1, ) -> &mut Self::RawBacking; } /// Trait for memory types that provide their own memory, i.e. MMAP. pub trait SelfBacked: Memory + Default {} /// Trait for memory types to which external memory must be attached to, i.e. UserPtr and /// DMABuf. pub trait Imported: Memory {} /// Trait for a handle that represents actual data for a single place. A buffer /// will have as many of these as it has planes. pub trait PlaneHandle: Debug + Send + 'static { /// The kind of memory the handle attaches to. type Memory: Memory; /// Fill a plane of a multi-planar V4L2 buffer with the handle's information. fn fill_v4l2_plane(&self, plane: &mut bindings::v4l2_plane); } // Trait for plane handles that provide access to their content through a map() // method (typically, MMAP buffers). pub trait Mappable: PlaneHandle { /// Return a `PlaneMapping` enabling access to the memory of this handle. fn map(device: &D, plane_info: &QueryBufPlane) -> Option; } /// Trait for structures providing all the handles of a single buffer. pub trait BufferHandles: Send + Debug + 'static { /// Enumeration of all the `MemoryType` supported by this type. Typically /// a subset of `MemoryType` or `MemoryType` itself. type SupportedMemoryType: Into + Send + Clone + Copy; /// Number of planes. fn len(&self) -> usize; /// Fill a plane of a multi-planar V4L2 buffer with the `index` handle's information. fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane); /// Returns true if there are no handles here (unlikely). fn is_empty(&self) -> bool { self.len() == 0 } } /// Implementation of `BufferHandles` for all vectors of `PlaneHandle`. This is /// The simplest way to use primitive handles. impl BufferHandles for Vec

{ type SupportedMemoryType = MemoryType; fn len(&self) -> usize { self.len() } fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane) { self[index].fill_v4l2_plane(plane); } } /// Trait for plane handles for which the final memory type is known at compile /// time. pub trait PrimitiveBufferHandles: BufferHandles { type HandleType: PlaneHandle; const MEMORY_TYPE: Self::SupportedMemoryType; } /// Implementation of `PrimitiveBufferHandles` for all vectors of `PlaneHandle`. impl PrimitiveBufferHandles for Vec

{ type HandleType = P; const MEMORY_TYPE: Self::SupportedMemoryType = P::Memory::MEMORY_TYPE; } /// Conversion from `v4l2_buffer`'s backing information to `v4l2_plane`'s. impl From<(&v4l2_buffer__bindgen_ty_1, MemoryType)> for v4l2_plane__bindgen_ty_1 { fn from((m, memory): (&v4l2_buffer__bindgen_ty_1, MemoryType)) -> Self { match memory { MemoryType::Mmap => v4l2_plane__bindgen_ty_1 { // Safe because the buffer type is determined to be MMAP. mem_offset: unsafe { m.offset }, }, MemoryType::UserPtr => v4l2_plane__bindgen_ty_1 { // Safe because the buffer type is determined to be USERPTR. userptr: unsafe { m.userptr }, }, MemoryType::DmaBuf => v4l2_plane__bindgen_ty_1 { // Safe because the buffer type is determined to be DMABUF. fd: unsafe { m.fd }, }, MemoryType::Overlay => Default::default(), } } } /// Conversion from `v4l2_plane`'s backing information to `v4l2_buffer`'s. impl From<(&v4l2_plane__bindgen_ty_1, MemoryType)> for v4l2_buffer__bindgen_ty_1 { fn from((m, memory): (&v4l2_plane__bindgen_ty_1, MemoryType)) -> Self { match memory { MemoryType::Mmap => v4l2_buffer__bindgen_ty_1 { // Safe because the buffer type is determined to be MMAP. offset: unsafe { m.mem_offset }, }, MemoryType::UserPtr => v4l2_buffer__bindgen_ty_1 { // Safe because the buffer type is determined to be USERPTR. userptr: unsafe { m.userptr }, }, MemoryType::DmaBuf => v4l2_buffer__bindgen_ty_1 { // Safe because the buffer type is determined to be DMABUF. fd: unsafe { m.fd }, }, MemoryType::Overlay => Default::default(), } } } #[cfg(test)] mod tests { use crate::bindings::v4l2_buffer__bindgen_ty_1; use crate::bindings::v4l2_plane__bindgen_ty_1; use crate::memory::MemoryType; #[test] // Purpose of this test is dubious as the members are overlapping anyway. fn plane_m_to_buffer_m() { let plane_m = v4l2_plane__bindgen_ty_1 { mem_offset: 0xfeedc0fe, }; assert_eq!( unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::Mmap)).offset }, 0xfeedc0fe ); let plane_m = v4l2_plane__bindgen_ty_1 { userptr: 0xfeedc0fe, }; assert_eq!( unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::UserPtr)).userptr }, 0xfeedc0fe ); let plane_m = v4l2_plane__bindgen_ty_1 { fd: 0x76543210 }; assert_eq!( unsafe { v4l2_buffer__bindgen_ty_1::from((&plane_m, MemoryType::DmaBuf)).fd }, 0x76543210 ); } #[test] // Purpose of this test is dubious as the members are overlapping anyway. fn buffer_m_to_plane_m() { let buffer_m = v4l2_buffer__bindgen_ty_1 { offset: 0xfeedc0fe }; assert_eq!( unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::Mmap)).mem_offset }, 0xfeedc0fe ); let buffer_m = v4l2_buffer__bindgen_ty_1 { userptr: 0xfeedc0fe, }; assert_eq!( unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::UserPtr)).userptr }, 0xfeedc0fe ); let buffer_m = v4l2_buffer__bindgen_ty_1 { fd: 0x76543210 }; assert_eq!( unsafe { v4l2_plane__bindgen_ty_1::from((&buffer_m, MemoryType::DmaBuf)).fd }, 0x76543210 ); } }