blob: c0c74919f96099df385c60e8d585a7aa4974ce6d [file] [log] [blame]
#![allow(non_camel_case_types)]
use log::{error, trace};
use std::{
collections::VecDeque,
os::{
fd::{AsFd, BorrowedFd},
raw::c_int,
unix::io::{AsRawFd, RawFd},
},
sync::{Arc, Mutex},
task::Wake,
};
use v4l2r::{
bindings,
device::{
poller::Waker,
queue::{
handles_provider::{GetSuitableBufferError, HandlesProvider},
qbuf::{
get_free::GetFreeCaptureBuffer, get_indexed::GetCaptureBufferByIndex,
CaptureQueueableProvider,
},
},
},
memory::{BufferHandles, DmaBufHandle, DmaBufSource, MemoryType, PrimitiveBufferHandles},
};
/// The simplest type used to represent a DMABUF fd. It does not take ownership
/// of the FD at any time and does not close it ; thus the using code is
/// responsible for managing the given FD's lifetime.
///
/// Since no ownership is taken at all, this is mostly useful for using DMABUFs
/// managed from unsafe code, i.e. code that calls into us using the C ffi.
#[derive(Debug)]
pub struct DmaBufFd {
fd: RawFd,
len: u64,
}
impl DmaBufFd {
/// Create a new `RawFd` to be used with the DMABUF API.
/// `fd` is the unix raw fd, `len` is the size of the memory behind it (not
/// just the amound of used data, but the whole size of the buffer).
/// No ownership is taken over `fd`, which will not be closed as the `RawFd`
/// is dropped ; thus the caller is responsible for managing its lifetime.
pub fn new(fd: RawFd, len: u64) -> DmaBufFd {
DmaBufFd { fd, len }
}
}
impl AsFd for DmaBufFd {
fn as_fd(&self) -> BorrowedFd {
unsafe { BorrowedFd::borrow_raw(self.fd) }
}
}
impl AsRawFd for DmaBufFd {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl DmaBufSource for DmaBufFd {
fn len(&self) -> u64 {
self.len
}
}
/// A struct representing a set of buffers to which decoded frames will be
/// output.
#[derive(Debug, Default)]
#[repr(C)]
pub struct v4l2r_video_frame {
/// Identifier of the frame. Each frame of the provider must have a unique
/// identifier the between 0 and 31 included, and that identifier must
/// persist across reuse of the same frame.
pub id: u32,
/// Number of entries in `fds`, e.g. the number of planes in this frame.
pub num_planes: usize,
/// DMABUF FDs of the planes for this frame.
pub planes: [c_int; 4],
}
#[derive(Debug, Clone, Copy, Default)]
pub struct VideoFrameMemoryType;
impl From<VideoFrameMemoryType> for MemoryType {
fn from(_: VideoFrameMemoryType) -> Self {
MemoryType::DmaBuf
}
}
impl BufferHandles for v4l2r_video_frame {
type SupportedMemoryType = VideoFrameMemoryType;
fn len(&self) -> usize {
self.num_planes
}
fn fill_v4l2_plane(&self, index: usize, plane: &mut bindings::v4l2_plane) {
plane.m.fd = self.planes[index];
// We don't need to set plane.m.length as these buffers are meant for
// the CAPTURE queue.
}
}
impl PrimitiveBufferHandles for v4l2r_video_frame {
// TODO: Uh? This is bullocks but somehow it compiles??
type HandleType = DmaBufHandle<DmaBufFd>;
const MEMORY_TYPE: Self::SupportedMemoryType = VideoFrameMemoryType;
}
struct VideoFrameProviderInternal {
frames: VecDeque<v4l2r_video_frame>,
waker: Option<Arc<Waker>>,
}
/// A way for the client-side to provide frames to be decoded into in the form
/// of video frames. A new provider will be passed by the output format change
/// callback every time the output format is changing. The client must pass
/// valid frames of the format specified by the format change callback using
/// [`v4l2r_video_frame_provider_queue_frame`]. These frames will be decoded
/// into and then passed as parameters of the frame output callback.
pub struct v4l2r_video_frame_provider {
d: Mutex<VideoFrameProviderInternal>,
}
impl v4l2r_video_frame_provider {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
v4l2r_video_frame_provider {
d: Mutex::new(VideoFrameProviderInternal {
frames: VecDeque::new(),
waker: None,
}),
}
}
}
impl HandlesProvider for v4l2r_video_frame_provider {
type HandleType = v4l2r_video_frame;
// TODO BUG: if the V4L2 buffer queue fails for some reason, there
// is no guarantee that the handles will return to the provider, and
// they might be definitively lost!
// In this case this is probably not too serious as the C side, which
// manages the DMABUFs, should receive and error and cancel decoding.
// Ideally the handles would be a C++ object that we just pass around,
// and which destructor would be called even if the Rust side drops it.
fn get_handles(&self, waker: &Arc<Waker>) -> Option<Self::HandleType> {
let mut d = self.d.lock().unwrap();
match d.frames.pop_front() {
Some(handles) => Some(handles),
None => {
d.waker = Some(Arc::clone(waker));
None
}
}
}
fn get_suitable_buffer_for<'a, Q>(
&self,
handles: &Self::HandleType,
queue: &'a Q,
) -> Result<
<Q as CaptureQueueableProvider<'a, Self::HandleType>>::Queueable,
GetSuitableBufferError,
>
where
Q: GetCaptureBufferByIndex<'a, Self::HandleType>
+ GetFreeCaptureBuffer<'a, Self::HandleType>,
{
trace!("Getting suitable buffer for frame {}", handles.id);
// Try to get the buffer with the same id as our frame. If that is not
// possible, fall back to returning any free buffer.
let buffer = queue.try_get_buffer(handles.id as usize).or_else(|e| {
error!(
"failed to obtain CAPTURE buffer {} by index: {}",
handles.id, e
);
error!("falling back to getting the first available buffer.");
queue.try_get_free_buffer()
})?;
Ok(buffer)
}
}
/// Make `frame` available to `provider` for being decoded into.
///
/// `frame` must be a valid frame of the format provided by the output format
/// change callback from which `provider` originated. `frame` will reappear as
/// an argument of the frame output callback once it has been decoded into, and
/// will remain untouched by the decoder until the client passes it to this
/// function again.
///
/// Returns `true` upon success, `false` if the provided frame had an invalid
/// index or the decoder thread could not be awakened.
///
/// This function can safely be called from any thread.
///
/// # Safety
///
/// `provider` must be a valid pointer provided by the resolution change
/// callback. It must *not* be used after the resolution change callback is
/// called again.
#[no_mangle]
pub unsafe extern "C" fn v4l2r_video_frame_provider_queue_frame(
provider: *const v4l2r_video_frame_provider,
frame: v4l2r_video_frame,
) -> bool {
trace!("Queueing output frame: {:?}", frame);
assert!(!provider.is_null());
let provider = &*provider;
if frame.id >= bindings::VIDEO_MAX_FRAME {
error!("Invalid frame id {}, aborting queue.", frame.id);
return false;
}
let mut provider = provider.d.lock().unwrap();
provider.frames.push_back(frame);
if let Some(waker) = provider.waker.take() {
waker.wake_by_ref();
}
true
}
/// Delete a video frame provider.
///
/// # Safety
///
/// `provider` must be a provider previously passed through the
/// `v4l2r_decoder_format_changed_event`. There are only two times when calling
/// this function is valid:
///
/// 1) After another `v4l2r_decoder_format_changed_event` has been received, the
/// old provider can be disposed of after the client is sure it won't make
/// any access.
/// 2) After the video decoder has been stopped and destroyed, the client must
/// drop the last provider it received (if any) itself.
#[no_mangle]
pub unsafe extern "C" fn v4l2r_video_frame_provider_drop(
provider: *const v4l2r_video_frame_provider,
) {
trace!("Destroying video frame provider: {:p}", provider);
assert!(!provider.is_null());
Arc::from_raw(provider);
}