| //! 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<u8>` 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<D: AsFd>(device: &D, plane_info: &QueryBufPlane) -> Option<PlaneMapping>; |
| } |
| |
| /// 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<MemoryType> + 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<P: PlaneHandle> BufferHandles for Vec<P> { |
| 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<P: PlaneHandle> PrimitiveBufferHandles for Vec<P> { |
| 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 |
| ); |
| } |
| } |