use super::{
buffer::BufferInfo,
direction::{Capture, Direction},
BufferStateFuse, BuffersAllocated, Queue,
};
use crate::ioctl::{self, PlaneMapping};
use crate::{
device::Device,
memory::{BufferHandles, Mappable, PrimitiveBufferHandles},
};
use std::{
fmt::Debug,
sync::{Arc, Weak},
};
pub type DropCallback<D, P> = Box<dyn FnOnce(&mut DqBuffer<D, P>) + Send>;
pub struct DqBuffer<D: Direction, P: BufferHandles> {
pub data: ioctl::V4l2Buffer,
plane_handles: Option<P>,
device: Weak<Device>,
buffer_info: Weak<BufferInfo<P>>,
drop_callbacks: Vec<DropCallback<D, P>>,
fuse: BufferStateFuse<P>,
_d: std::marker::PhantomData<D>,
}
impl<D: Direction, P: BufferHandles> Debug for DqBuffer<D, P> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.data.fmt(f)
}
}
impl<D: Direction, P: BufferHandles> DqBuffer<D, P> {
pub(super) fn new(
queue: &Queue<D, BuffersAllocated<P>>,
buffer: &Arc<BufferInfo<P>>,
plane_handles: P,
data: ioctl::V4l2Buffer,
fuse: BufferStateFuse<P>,
) -> Self {
DqBuffer {
plane_handles: Some(plane_handles),
data,
device: Arc::downgrade(&queue.inner.device),
buffer_info: Arc::downgrade(buffer),
fuse,
drop_callbacks: Default::default(),
_d: std::marker::PhantomData,
}
}
pub fn add_drop_callback<F: FnOnce(&mut Self) + Send + 'static>(&mut self, callback: F) {
self.drop_callbacks.push(Box::new(callback));
}
pub fn take_handles(&mut self) -> Option<P> {
self.plane_handles.take()
}
}
impl<P> DqBuffer<Capture, P>
where
P: PrimitiveBufferHandles,
P::HandleType: Mappable,
{
pub fn get_plane_mapping(&self, plane_index: usize) -> Option<PlaneMapping> {
let buffer_info = self.buffer_info.upgrade()?;
let plane = buffer_info.features.planes.get(plane_index)?;
let plane_data = self.data.planes_iter().nth(plane_index)?;
let device = self.device.upgrade()?;
let start = *plane_data.data_offset.unwrap_or(&0) as usize;
let end = *plane_data.bytesused as usize;
Some(P::HandleType::map(device.as_ref(), plane)?.restrict(start, end))
}
}
impl<D: Direction, P: BufferHandles> Drop for DqBuffer<D, P> {
fn drop(&mut self) {
self.fuse.trigger();
while let Some(callback) = self.drop_callbacks.pop() {
callback(self);
}
}
}