blob: 15c764ae7c6c8bd47a1701233683e2ec8e140d97 [file] [log] [blame]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::cell::RefCell;
use std::fs::File;
use std::os::fd::AsRawFd;
use std::rc::{Rc, Weak};
use v4l2r::controls::ExtControlTrait;
use v4l2r::controls::SafeExtControl;
use v4l2r::ioctl;
use v4l2r::memory::DmaBufHandle;
use crate::backend::v4l2::decoder::stateless::V4l2Picture;
use crate::device::v4l2::stateless::device::V4l2Device;
use crate::device::v4l2::stateless::queue::V4l2CaptureBuffer;
use crate::device::v4l2::stateless::queue::V4l2OutputBuffer;
struct InitRequestHandle {
device: V4l2Device,
timestamp: u64,
handle: ioctl::Request,
output_buffer: V4l2OutputBuffer,
picture: Weak<RefCell<V4l2Picture>>,
}
impl InitRequestHandle {
fn new(
device: V4l2Device,
timestamp: u64,
handle: ioctl::Request,
output_buffer: V4l2OutputBuffer,
) -> Self {
Self { device, timestamp, handle, output_buffer, picture: Weak::new() }
}
fn which(&self) -> ioctl::CtrlWhich {
ioctl::CtrlWhich::Request(self.handle.as_raw_fd())
}
fn ioctl<C, T>(&mut self, ctrl: C) -> &mut Self
where
C: Into<SafeExtControl<T>>,
T: ExtControlTrait,
{
let mut ctrl: SafeExtControl<T> = ctrl.into();
ioctl::s_ext_ctrls(&self.device, self.which(), &mut ctrl)
.expect("Failed to set output control");
self
}
fn write(&mut self, data: &[u8]) -> &mut Self {
self.output_buffer.write(data);
self
}
fn submit(self) -> PendingRequestHandle {
self.output_buffer
.submit(self.timestamp, self.handle.as_raw_fd())
.expect("error needs handling");
self.handle.queue().expect("Failed to queue request handle");
PendingRequestHandle {
device: self.device.clone(),
timestamp: self.timestamp,
picture: self.picture,
}
}
fn set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture>>) {
self.picture = picture;
}
}
struct PendingRequestHandle {
device: V4l2Device,
timestamp: u64,
picture: Weak<RefCell<V4l2Picture>>,
}
impl PendingRequestHandle {
fn sync(self) -> DoneRequestHandle {
DoneRequestHandle {
capture_buffer: Rc::new(RefCell::new(self.device.sync(self.timestamp))),
}
}
}
struct DoneRequestHandle {
capture_buffer: Rc<RefCell<V4l2CaptureBuffer<DmaBufHandle<File>>>>,
}
impl DoneRequestHandle {
fn result(&self) -> V4l2Result {
V4l2Result { capture_buffer: self.capture_buffer.clone() }
}
}
#[derive(Default)]
enum RequestHandle {
Init(InitRequestHandle),
Pending(PendingRequestHandle),
Done(DoneRequestHandle),
#[default]
Unknown,
}
impl RequestHandle {
fn new(
device: V4l2Device,
timestamp: u64,
handle: ioctl::Request,
output_buffer: V4l2OutputBuffer,
) -> Self {
Self::Init(InitRequestHandle::new(device, timestamp, handle, output_buffer))
}
fn timestamp(&self) -> u64 {
match self {
Self::Init(handle) => handle.timestamp,
Self::Pending(handle) => handle.timestamp,
Self::Done(handle) => handle.capture_buffer.borrow().timestamp(),
_ => panic!("ERROR"),
}
}
fn which(&self) -> ioctl::CtrlWhich {
match self {
Self::Init(handle) => handle.which(),
_ => panic!("ERROR"),
}
}
fn ioctl<C, T>(&mut self, ctrl: C) -> &mut Self
where
C: Into<SafeExtControl<T>>,
T: ExtControlTrait,
{
match self {
Self::Init(handle) => handle.ioctl(ctrl),
_ => panic!("ERROR"),
};
self
}
fn write(&mut self, data: &[u8]) -> &mut Self {
match self {
Self::Init(handle) => handle.write(data),
_ => panic!("ERROR"),
};
self
}
// This method can modify in-place instead of returning a new value. This removes the need for
// a RefCell in V4l2Request.
fn submit(&mut self) {
match std::mem::take(self) {
Self::Init(handle) => *self = Self::Pending(handle.submit()),
_ => panic!("ERROR"),
}
}
fn sync(&mut self) {
match std::mem::take(self) {
Self::Pending(handle) => *self = Self::Done(handle.sync()),
s @ Self::Done(_) => *self = s,
_ => panic!("ERROR"),
}
}
fn result(&self) -> V4l2Result {
match self {
Self::Done(handle) => handle.result(),
_ => panic!("ERROR"),
}
}
fn set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture>>) {
match self {
Self::Init(handle) => handle.set_picture_ref(picture),
_ => panic!("ERROR"),
}
}
fn picture(&mut self) -> Weak<RefCell<V4l2Picture>> {
match self {
Self::Pending(handle) => handle.picture.clone(),
_ => panic!("ERROR"),
}
}
}
pub struct V4l2Request(RequestHandle);
impl V4l2Request {
pub fn new(
device: V4l2Device,
timestamp: u64,
handle: ioctl::Request,
output_buffer: V4l2OutputBuffer,
) -> Self {
Self(RequestHandle::new(device, timestamp, handle, output_buffer))
}
pub fn timestamp(&self) -> u64 {
self.0.timestamp()
}
pub fn which(&self) -> ioctl::CtrlWhich {
self.0.which()
}
pub fn ioctl<C, T>(&mut self, ctrl: C) -> &mut Self
where
C: Into<SafeExtControl<T>>,
T: ExtControlTrait,
{
self.0.ioctl(ctrl);
self
}
pub fn write(&mut self, data: &[u8]) -> &mut Self {
self.0.write(data);
self
}
pub fn submit(&mut self) {
self.0.submit();
}
pub fn sync(&mut self) {
self.0.sync();
}
pub fn result(&self) -> V4l2Result {
self.0.result()
}
pub fn set_picture_ref(&mut self, picture: Weak<RefCell<V4l2Picture>>) {
self.0.set_picture_ref(picture);
}
pub fn picture(&mut self) -> Weak<RefCell<V4l2Picture>> {
self.0.picture()
}
}
pub struct V4l2Result {
capture_buffer: Rc<RefCell<V4l2CaptureBuffer<DmaBufHandle<File>>>>,
}
impl V4l2Result {
pub fn length(&self) -> usize {
self.capture_buffer.borrow().length()
}
pub fn read(&mut self, data: &mut [u8]) {
self.capture_buffer.borrow_mut().read(data)
}
}