// 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 anyhow::anyhow; use std::cell::RefCell; use std::convert::Infallible; use std::rc::Rc; use std::sync::Arc; use thiserror::Error; use v4l2r::bindings::v4l2_format; use v4l2r::device::queue::direction; use v4l2r::device::queue::direction::Capture; use v4l2r::device::queue::direction::Output; use v4l2r::device::queue::dqbuf::DqBuffer; use v4l2r::device::queue::qbuf::QBuffer; use v4l2r::device::queue::BuffersAllocated; use v4l2r::device::queue::CaptureQueueable; use v4l2r::device::queue::CreateQueueError; use v4l2r::device::queue::GetFreeBufferError; use v4l2r::device::queue::GetFreeCaptureBuffer; use v4l2r::device::queue::GetFreeOutputBuffer; use v4l2r::device::queue::Queue; use v4l2r::device::queue::QueueInit; use v4l2r::device::queue::RequestBuffersError; use v4l2r::device::AllocatedQueue; use v4l2r::device::Device; use v4l2r::device::Stream; use v4l2r::device::TryDequeue; use v4l2r::ioctl::GFmtError; use v4l2r::ioctl::IoctlConvertError; use v4l2r::ioctl::QBufIoctlError; use v4l2r::ioctl::SFmtError; use v4l2r::ioctl::StreamOnError; use v4l2r::memory::BufferHandles; use v4l2r::memory::Memory; use v4l2r::memory::MemoryType; use v4l2r::memory::MmapHandle; use v4l2r::memory::PlaneHandle; use v4l2r::nix::sys::time::TimeVal; use v4l2r::Format; use v4l2r::PlaneLayout; use crate::decoder::stateless::DecodeError; use crate::decoder::stateless::NewStatelessDecoderError; use crate::decoder::stateless::StatelessBackendError; use crate::utils::buffer_size_for_area; use crate::video_frame::V4l2VideoFrame; use crate::video_frame::VideoFrame; use crate::Fourcc; use crate::Resolution; //TODO: handle memory backends other than mmap //TODO: handle video formats other than h264 //TODO: handle synced buffers in Streaming state #[derive(Default)] enum V4l2OutputQueueHandle { Init(Queue), Streaming(Rc>>>), #[default] Unknown, } #[derive(Default)] enum V4l2CaptureQueueHandle { Init(Queue), Streaming(Rc>>>), #[default] Unknown, } #[derive(Debug, Error)] pub enum QueueError { #[error("unable to create queue.")] Creation, #[error("failed to get format for queue.")] FormatGet, #[error("failed to set format for queue.")] FormatSet, #[error("failed requesting buffers.")] RequestBuffers, #[error("unable to stream on.")] StreamOn, #[error("driver does not support {0}.")] UnsupportedPixelFormat(Fourcc), #[error("operation can not be performed in this state.")] State, #[error("no buffer to dequeue.")] BufferDequeue, #[error("failed to queue buffer.")] BufferQueue, #[error("requested {0} buffers, only {1} allocated")] NotEnoughRequestedBuffers(usize, usize), #[error("failed to stream off.")] StreamOff, #[error("failed to get queue handle.")] QueueHandle, #[error("failed to free buffers.")] FreeBuffer, #[error("failed to reset OUTPUT queue.")] ResetOutputQueue, #[error("failed to reset CAPTURE queue.")] ResetCaptureQueue, } impl From for DecodeError { fn from(err: QueueError) -> Self { DecodeError::BackendError(StatelessBackendError::Other(anyhow::anyhow!(err))) } } impl From> for QueueError { fn from(_err: v4l2r::device::queue::qbuf::QueueError) -> Self { QueueError::BufferQueue } } impl From for QueueError { fn from(_err: CreateQueueError) -> Self { QueueError::Creation } } impl From for QueueError { fn from(_err: GFmtError) -> Self { QueueError::FormatGet } } impl From for QueueError { fn from(_err: SFmtError) -> Self { QueueError::FormatSet } } impl From for QueueError { fn from(_err: RequestBuffersError) -> Self { QueueError::RequestBuffers } } impl From for QueueError { fn from(_err: StreamOnError) -> Self { QueueError::StreamOn } } impl From for QueueError { fn from(_err: GetFreeBufferError) -> Self { QueueError::BufferDequeue } } impl From> for QueueError { fn from(_err: IoctlConvertError) -> Self { QueueError::BufferQueue } } fn check_requested_buffer_count(requested: u32, received: usize) -> Result<(), QueueError> { if received < requested as usize { return Err(QueueError::NotEnoughRequestedBuffers(requested as usize, received)); } Ok(()) } //TODO: handle memory backends other than mmap pub struct V4l2OutputBuffer { queue: V4l2OutputQueue, handle: QBuffer< Output, Vec, Vec, Rc>>>, >, length: usize, } impl V4l2OutputBuffer { fn new( queue: V4l2OutputQueue, handle: QBuffer< Output, Vec, Vec, Rc>>>, >, ) -> Self { Self { queue, handle, length: 0 } } pub fn index(&self) -> usize { self.handle.index() } pub fn length(&self) -> usize { self.length } pub fn write(&mut self, data: &[u8]) -> &mut Self { let mut mapping = self.handle.get_plane_mapping(0).expect("Failed to mmap output buffer"); mapping.as_mut()[self.length..self.length + data.len()].copy_from_slice(data); self.length += data.len(); drop(mapping); self } pub fn submit(self, timestamp: u64, request_fd: i32) -> Result<(), QueueError> { let handle = &*self.queue.handle.borrow(); match handle { V4l2OutputQueueHandle::Streaming(_) => { self.handle .set_timestamp(TimeVal::new(/* FIXME: sec */ 0, timestamp as i64)) .set_request(request_fd) .queue(&[self.length])?; Ok(()) } _ => Err(QueueError::State), } } } #[derive(Clone)] pub struct V4l2OutputQueue { handle: Rc>>, } const NUM_OUTPUT_BUFFERS: u32 = 2; impl V4l2OutputQueue { pub fn new(device: Arc) -> Result { let handle = Queue::get_output_mplane_queue(device) .map_err(|_| NewStatelessDecoderError::DriverInitialization)?; log::debug!("output queue created"); let handle = Rc::new(RefCell::new(V4l2OutputQueueHandle::Init(handle))); Ok(Self { handle }) } pub fn reset(&mut self, device: Arc) -> Result<(), QueueError> { let handle = self.handle.take(); let (ret, handle) = match handle { V4l2OutputQueueHandle::Streaming(handle) => { handle.stream_off().map_err(|_| QueueError::StreamOff)?; (Rc::into_inner(handle).ok_or(QueueError::QueueHandle)?) .free_buffers() .map_err(|_| QueueError::FreeBuffer)?; let queue_handle = Queue::get_output_mplane_queue(device.clone()) .map_err(|_| QueueError::QueueHandle); (Ok(()), V4l2OutputQueueHandle::Init(queue_handle?)) } _ => (Err(QueueError::State), handle), }; self.handle.replace(handle); ret } pub fn initialize( &mut self, fourcc: Fourcc, resolution: Resolution, ) -> Result<&mut Self, QueueError> { self.handle.replace(match self.handle.take() { V4l2OutputQueueHandle::Init(mut handle) => { let (width, height) = resolution.into(); handle .change_format()? .set_size(width as usize, height as usize) .set_pixelformat(fourcc) .set_planes_layout(vec![PlaneLayout { sizeimage: buffer_size_for_area(width, height), ..Default::default() }]) .apply::()?; let format: Format = handle.get_format()?; if format.pixelformat != fourcc.into() { return Err(QueueError::UnsupportedPixelFormat(fourcc)); } let handle = handle.request_buffers_generic::>( MemoryType::Mmap, NUM_OUTPUT_BUFFERS, )?; check_requested_buffer_count(NUM_OUTPUT_BUFFERS, handle.num_free_buffers())?; handle.stream_on()?; V4l2OutputQueueHandle::Streaming(handle.into()) } _ => return Err(QueueError::State), }); Ok(self) } pub fn num_free_buffers(&self) -> usize { let handle = &*self.handle.borrow(); match handle { V4l2OutputQueueHandle::Streaming(handle) => handle.num_free_buffers(), _ => 0, } } pub fn alloc_buffer(&self) -> Result { let handle = &*self.handle.borrow(); match handle { V4l2OutputQueueHandle::Streaming(handle) => match handle.try_get_free_buffer() { Ok(buffer) => Ok(V4l2OutputBuffer::new(self.clone(), buffer)), Err(_) => Err(DecodeError::NotEnoughOutputBuffers(1)), }, _ => Err(DecodeError::DecoderError(anyhow!("Invalid hardware handle"))), } } pub fn dequeue_buffer(&self) -> Result<(), QueueError> { let handle = &*self.handle.borrow(); match handle { V4l2OutputQueueHandle::Streaming(handle) => { handle.try_dequeue().map_err(|_| QueueError::BufferDequeue)?; Ok(()) } _ => Err(QueueError::State), } } } pub struct V4l2CaptureBuffer { pub frame: Arc, handle: DqBuffer>, } impl V4l2CaptureBuffer { fn new(frame: Arc, handle: DqBuffer>) -> Self { Self { frame, handle } } pub fn timestamp(&self) -> u64 { self.handle.data.timestamp().tv_usec as u64 } // TODO enable once upstream v4l2r has rolled // pub fn has_error(&self) -> bool { // self.handle.data.has_error() as u64 // } } pub struct V4l2CaptureQueue { format: Format, handle: RefCell>, num_buffers: u32, device: Arc, } impl V4l2CaptureQueue { pub fn new(device: Arc) -> Result { let handle = Queue::get_capture_mplane_queue(device.clone()) .map_err(|_| NewStatelessDecoderError::DriverInitialization)?; log::debug!("capture queue created"); let handle = RefCell::new(V4l2CaptureQueueHandle::Init(handle)); Ok(Self { handle, num_buffers: 0, format: Default::default(), device: device }) } pub fn reset(&mut self, device: Arc) -> Result<(), QueueError> { let handle = self.handle.take(); let (ret, handle) = match handle { V4l2CaptureQueueHandle::Streaming(handle) => { handle.stream_off().map_err(|_| QueueError::StreamOff)?; (Rc::into_inner(handle).ok_or(QueueError::QueueHandle)?) .free_buffers() .map_err(|_| QueueError::FreeBuffer)?; let queue_handle = Queue::get_capture_mplane_queue(device.clone()) .map_err(|_| QueueError::QueueHandle); (Ok(()), V4l2CaptureQueueHandle::Init(queue_handle?)) } _ => (Err(QueueError::State), handle), }; self.handle.replace(handle); ret } pub fn initialize(&mut self, requested_num_buffers: u32) -> Result<&mut Self, QueueError> { // +2 due to HCMP1_HHI_A.h264 needing more let requested_num_buffers = requested_num_buffers + 2; self.handle.replace(match self.handle.take() { V4l2CaptureQueueHandle::Init(handle) => { // TODO: check if decoded format is supported. self.format = handle.get_format()?; // TODO: handle 10 bit format negotiation. let handle = handle.request_buffers_generic::>( ::Memory::MEMORY_TYPE, requested_num_buffers, )?; check_requested_buffer_count(requested_num_buffers, handle.num_free_buffers())?; self.num_buffers = requested_num_buffers; handle.stream_on()?; V4l2CaptureQueueHandle::Streaming(handle.into()) } _ => return Err(QueueError::State), }); Ok(self) } pub fn dequeue_buffer(&self) -> Result>, QueueError> { let handle = &*self.handle.borrow(); match handle { V4l2CaptureQueueHandle::Streaming(handle) => match handle.try_dequeue() { Ok(mut buffer) => { log::debug!("capture buffer {} dequeued", buffer.data.index()); // TODO handle buffer dequeuing successfully, but having an error // buffer.data.has_error(); let mut frame = buffer.take_handles().expect("Missing handle on dequeue!").0; frame.process_dqbuf(self.device.clone(), &self.format, &buffer.data); Ok(Some(V4l2CaptureBuffer::new(Arc::new(frame), buffer))) } _ => Ok(None), }, _ => Err(QueueError::State), } } // TODO: Plumb in VideoFrames from external Gralloc frame pool instead of reallocating every // frame every time. pub fn queue_buffer(&self, frame: V) -> Result<(), QueueError> { let handle = &*self.handle.borrow(); match handle { V4l2CaptureQueueHandle::Streaming(handle) => { let buffer = handle.try_get_free_buffer()?; log::debug!("capture buffer {} queued", buffer.index()); buffer.queue_with_handles(frame.into())?; } _ => return Err(QueueError::State), } Ok(()) } pub fn num_free_buffers(&self) -> usize { let handle = &*self.handle.borrow(); match handle { V4l2CaptureQueueHandle::Streaming(handle) => handle.num_free_buffers(), _ => 0, } } }