1 //! Provides types related to dequeuing buffers from a `Queue` object. 2 use super::{ 3 buffer::BufferInfo, 4 direction::{Capture, Direction}, 5 BufferStateFuse, BuffersAllocated, Queue, 6 }; 7 use crate::ioctl::{self, PlaneMapping}; 8 use crate::{ 9 device::Device, 10 memory::{BufferHandles, Mappable, PrimitiveBufferHandles}, 11 }; 12 use std::{ 13 fmt::Debug, 14 sync::{Arc, Weak}, 15 }; 16 17 pub type DropCallback<D, P> = Box<dyn FnOnce(&mut DqBuffer<D, P>) + Send>; 18 19 /// Represents the information of a dequeued buffer. This is basically the same 20 /// information as what the `ioctl` interface provides, but it also includes 21 /// the plane handles that have been provided when the buffer was queued to 22 /// return their ownership to the user. 23 pub struct DqBuffer<D: Direction, P: BufferHandles> { 24 /// Dequeued buffer information as reported by V4L2. 25 pub data: ioctl::V4l2Buffer, 26 /// The backing memory that has been provided for this buffer. 27 plane_handles: Option<P>, 28 29 device: Weak<Device>, 30 buffer_info: Weak<BufferInfo<P>>, 31 /// Callbacks to be run when the object is dropped. 32 drop_callbacks: Vec<DropCallback<D, P>>, 33 /// Fuse that will put the buffer back into the `Free` state when this 34 /// object is destroyed. 35 fuse: BufferStateFuse<P>, 36 _d: std::marker::PhantomData<D>, 37 } 38 39 impl<D: Direction, P: BufferHandles> Debug for DqBuffer<D, P> { fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result40 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 41 self.data.fmt(f) 42 } 43 } 44 45 impl<D: Direction, P: BufferHandles> DqBuffer<D, P> { new( queue: &Queue<D, BuffersAllocated<P>>, buffer: &Arc<BufferInfo<P>>, plane_handles: P, data: ioctl::V4l2Buffer, fuse: BufferStateFuse<P>, ) -> Self46 pub(super) fn new( 47 queue: &Queue<D, BuffersAllocated<P>>, 48 buffer: &Arc<BufferInfo<P>>, 49 plane_handles: P, 50 data: ioctl::V4l2Buffer, 51 fuse: BufferStateFuse<P>, 52 ) -> Self { 53 DqBuffer { 54 plane_handles: Some(plane_handles), 55 data, 56 device: Arc::downgrade(&queue.inner.device), 57 buffer_info: Arc::downgrade(buffer), 58 fuse, 59 drop_callbacks: Default::default(), 60 _d: std::marker::PhantomData, 61 } 62 } 63 64 /// Attach a callback that will be called when the DQBuffer is destroyed, 65 /// and after the buffer has been returned to the free list. 66 /// This method can be called several times, the callback will be run in 67 /// the inverse order that they were added. add_drop_callback<F: FnOnce(&mut Self) + Send + 'static>(&mut self, callback: F)68 pub fn add_drop_callback<F: FnOnce(&mut Self) + Send + 'static>(&mut self, callback: F) { 69 self.drop_callbacks.push(Box::new(callback)); 70 } 71 72 /// Return the plane handles of the buffer. This method is guaranteed to 73 /// return Some() the first time it is called, and None any subsequent times. take_handles(&mut self) -> Option<P>74 pub fn take_handles(&mut self) -> Option<P> { 75 self.plane_handles.take() 76 } 77 } 78 79 impl<P> DqBuffer<Capture, P> 80 where 81 P: PrimitiveBufferHandles, 82 P::HandleType: Mappable, 83 { 84 // TODO returned mapping should be read-only! get_plane_mapping(&self, plane_index: usize) -> Option<PlaneMapping>85 pub fn get_plane_mapping(&self, plane_index: usize) -> Option<PlaneMapping> { 86 // We can only obtain a mapping if this buffer has not been deleted. 87 let buffer_info = self.buffer_info.upgrade()?; 88 let plane = buffer_info.features.planes.get(plane_index)?; 89 let plane_data = self.data.planes_iter().nth(plane_index)?; 90 // If the buffer info was alive, then the device must also be. 91 let device = self.device.upgrade()?; 92 93 let start = *plane_data.data_offset.unwrap_or(&0) as usize; 94 let end = start + *plane_data.bytesused as usize; 95 96 Some(P::HandleType::map(device.as_ref(), plane)?.restrict(start, end)) 97 } 98 } 99 100 impl<D: Direction, P: BufferHandles> Drop for DqBuffer<D, P> { drop(&mut self)101 fn drop(&mut self) { 102 // Make sure the buffer is returned to the free state before we call 103 // the callbacks. 104 self.fuse.trigger(); 105 while let Some(callback) = self.drop_callbacks.pop() { 106 callback(self); 107 } 108 } 109 } 110