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