1*1b4853f5SAndroid Build Coastguard Worker // Copyright 2024 The ChromiumOS Authors 2*1b4853f5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*1b4853f5SAndroid Build Coastguard Worker // found in the LICENSE file. 4*1b4853f5SAndroid Build Coastguard Worker 5*1b4853f5SAndroid Build Coastguard Worker use std::ops::Deref; 6*1b4853f5SAndroid Build Coastguard Worker use std::os::fd::BorrowedFd; 7*1b4853f5SAndroid Build Coastguard Worker 8*1b4853f5SAndroid Build Coastguard Worker use v4l2r::bindings; 9*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::BufferCapabilities; 10*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::BufferField; 11*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::BufferFlags; 12*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::DecoderCmd; 13*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::EventType; 14*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::SelectionTarget; 15*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::SelectionType; 16*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::SrcChanges; 17*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::V4l2Buffer; 18*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::V4l2MplaneFormat; 19*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::V4l2PlanesWithBacking; 20*1b4853f5SAndroid Build Coastguard Worker use v4l2r::ioctl::V4l2PlanesWithBackingMut; 21*1b4853f5SAndroid Build Coastguard Worker use v4l2r::memory::MemoryType; 22*1b4853f5SAndroid Build Coastguard Worker use v4l2r::Colorspace; 23*1b4853f5SAndroid Build Coastguard Worker use v4l2r::Quantization; 24*1b4853f5SAndroid Build Coastguard Worker use v4l2r::QueueClass; 25*1b4853f5SAndroid Build Coastguard Worker use v4l2r::QueueDirection; 26*1b4853f5SAndroid Build Coastguard Worker use v4l2r::QueueType; 27*1b4853f5SAndroid Build Coastguard Worker use v4l2r::XferFunc; 28*1b4853f5SAndroid Build Coastguard Worker use v4l2r::YCbCrEncoding; 29*1b4853f5SAndroid Build Coastguard Worker 30*1b4853f5SAndroid Build Coastguard Worker use crate::ioctl::virtio_media_dispatch_ioctl; 31*1b4853f5SAndroid Build Coastguard Worker use crate::ioctl::IoctlResult; 32*1b4853f5SAndroid Build Coastguard Worker use crate::ioctl::VirtioMediaIoctlHandler; 33*1b4853f5SAndroid Build Coastguard Worker use crate::mmap::MmapMappingManager; 34*1b4853f5SAndroid Build Coastguard Worker use crate::DequeueBufferEvent; 35*1b4853f5SAndroid Build Coastguard Worker use crate::SessionEvent; 36*1b4853f5SAndroid Build Coastguard Worker use crate::SgEntry; 37*1b4853f5SAndroid Build Coastguard Worker use crate::V4l2Event; 38*1b4853f5SAndroid Build Coastguard Worker use crate::V4l2Ioctl; 39*1b4853f5SAndroid Build Coastguard Worker use crate::VirtioMediaDevice; 40*1b4853f5SAndroid Build Coastguard Worker use crate::VirtioMediaDeviceSession; 41*1b4853f5SAndroid Build Coastguard Worker use crate::VirtioMediaEventQueue; 42*1b4853f5SAndroid Build Coastguard Worker use crate::VirtioMediaHostMemoryMapper; 43*1b4853f5SAndroid Build Coastguard Worker use crate::VIRTIO_MEDIA_MMAP_FLAG_RW; 44*1b4853f5SAndroid Build Coastguard Worker 45*1b4853f5SAndroid Build Coastguard Worker /// Backing MMAP memory for `VirtioVideoMediaDecoderBuffer`. 46*1b4853f5SAndroid Build Coastguard Worker pub trait VideoDecoderBufferBacking { new(queue: QueueType, index: u32, sizes: &[usize]) -> IoctlResult<Self> where Self: Sized47*1b4853f5SAndroid Build Coastguard Worker fn new(queue: QueueType, index: u32, sizes: &[usize]) -> IoctlResult<Self> 48*1b4853f5SAndroid Build Coastguard Worker where 49*1b4853f5SAndroid Build Coastguard Worker Self: Sized; 50*1b4853f5SAndroid Build Coastguard Worker fd_for_plane(&self, plane_idx: usize) -> Option<BorrowedFd>51*1b4853f5SAndroid Build Coastguard Worker fn fd_for_plane(&self, plane_idx: usize) -> Option<BorrowedFd>; 52*1b4853f5SAndroid Build Coastguard Worker } 53*1b4853f5SAndroid Build Coastguard Worker 54*1b4853f5SAndroid Build Coastguard Worker pub struct VideoDecoderBuffer<S: VideoDecoderBufferBacking> { 55*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer: V4l2Buffer, 56*1b4853f5SAndroid Build Coastguard Worker 57*1b4853f5SAndroid Build Coastguard Worker /// Backend-specific storage. 58*1b4853f5SAndroid Build Coastguard Worker pub backing: S, 59*1b4853f5SAndroid Build Coastguard Worker } 60*1b4853f5SAndroid Build Coastguard Worker 61*1b4853f5SAndroid Build Coastguard Worker impl<S: VideoDecoderBufferBacking> VideoDecoderBuffer<S> { new( queue: QueueType, index: u32, sizes: &[usize], mmap_offset: u32, ) -> IoctlResult<Self>62*1b4853f5SAndroid Build Coastguard Worker fn new( 63*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 64*1b4853f5SAndroid Build Coastguard Worker index: u32, 65*1b4853f5SAndroid Build Coastguard Worker sizes: &[usize], 66*1b4853f5SAndroid Build Coastguard Worker // TODO: need as many offsets as there are planes. 67*1b4853f5SAndroid Build Coastguard Worker mmap_offset: u32, 68*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<Self> { 69*1b4853f5SAndroid Build Coastguard Worker let backing = S::new(queue, index, sizes)?; 70*1b4853f5SAndroid Build Coastguard Worker 71*1b4853f5SAndroid Build Coastguard Worker let mut v4l2_buffer = V4l2Buffer::new(queue, index, MemoryType::Mmap); 72*1b4853f5SAndroid Build Coastguard Worker if let V4l2PlanesWithBackingMut::Mmap(mut planes) = 73*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer.planes_with_backing_iter_mut() 74*1b4853f5SAndroid Build Coastguard Worker { 75*1b4853f5SAndroid Build Coastguard Worker // SAFETY: every buffer has at least one plane. 76*1b4853f5SAndroid Build Coastguard Worker let mut plane = planes.next().unwrap(); 77*1b4853f5SAndroid Build Coastguard Worker plane.set_mem_offset(mmap_offset); 78*1b4853f5SAndroid Build Coastguard Worker *plane.length = sizes[0] as u32; 79*1b4853f5SAndroid Build Coastguard Worker } else { 80*1b4853f5SAndroid Build Coastguard Worker // SAFETY: we have just set the buffer type to MMAP. Reaching this point means a bug in 81*1b4853f5SAndroid Build Coastguard Worker // the code. 82*1b4853f5SAndroid Build Coastguard Worker panic!() 83*1b4853f5SAndroid Build Coastguard Worker } 84*1b4853f5SAndroid Build Coastguard Worker 85*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer.set_flags(BufferFlags::TIMESTAMP_MONOTONIC); 86*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer.set_field(BufferField::None); 87*1b4853f5SAndroid Build Coastguard Worker 88*1b4853f5SAndroid Build Coastguard Worker Ok(Self { 89*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer, 90*1b4853f5SAndroid Build Coastguard Worker backing, 91*1b4853f5SAndroid Build Coastguard Worker }) 92*1b4853f5SAndroid Build Coastguard Worker } 93*1b4853f5SAndroid Build Coastguard Worker index(&self) -> u3294*1b4853f5SAndroid Build Coastguard Worker pub fn index(&self) -> u32 { 95*1b4853f5SAndroid Build Coastguard Worker self.v4l2_buffer.index() 96*1b4853f5SAndroid Build Coastguard Worker } 97*1b4853f5SAndroid Build Coastguard Worker timestamp(&self) -> bindings::timeval98*1b4853f5SAndroid Build Coastguard Worker pub fn timestamp(&self) -> bindings::timeval { 99*1b4853f5SAndroid Build Coastguard Worker self.v4l2_buffer.timestamp() 100*1b4853f5SAndroid Build Coastguard Worker } 101*1b4853f5SAndroid Build Coastguard Worker } 102*1b4853f5SAndroid Build Coastguard Worker 103*1b4853f5SAndroid Build Coastguard Worker /// Events reported by the [`VideoDecoderBackendSession::next_event`] method. 104*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, Clone, PartialEq, Eq)] 105*1b4853f5SAndroid Build Coastguard Worker pub enum VideoDecoderBackendEvent { 106*1b4853f5SAndroid Build Coastguard Worker /// Sent whenever the format of the stream has changed. The new format can be read using 107*1b4853f5SAndroid Build Coastguard Worker /// [`VideoDecoderBackendSession::current_format`]. 108*1b4853f5SAndroid Build Coastguard Worker StreamFormatChanged, 109*1b4853f5SAndroid Build Coastguard Worker /// Sent whenever an `OUTPUT` buffer is done processing and can be reused. 110*1b4853f5SAndroid Build Coastguard Worker InputBufferDone(u32), 111*1b4853f5SAndroid Build Coastguard Worker /// Sent whenever a decoded frame is ready on the `CAPTURE` queue. 112*1b4853f5SAndroid Build Coastguard Worker FrameCompleted { 113*1b4853f5SAndroid Build Coastguard Worker buffer_id: u32, 114*1b4853f5SAndroid Build Coastguard Worker timestamp: bindings::timeval, 115*1b4853f5SAndroid Build Coastguard Worker bytes_used: Vec<u32>, 116*1b4853f5SAndroid Build Coastguard Worker is_last: bool, 117*1b4853f5SAndroid Build Coastguard Worker }, 118*1b4853f5SAndroid Build Coastguard Worker } 119*1b4853f5SAndroid Build Coastguard Worker 120*1b4853f5SAndroid Build Coastguard Worker /// Description of the current stream parameters, as parsed from the input. 121*1b4853f5SAndroid Build Coastguard Worker #[derive(Clone)] 122*1b4853f5SAndroid Build Coastguard Worker pub struct StreamParams { 123*1b4853f5SAndroid Build Coastguard Worker /// Minimum number of output buffers necessary to decode the stream. 124*1b4853f5SAndroid Build Coastguard Worker pub min_output_buffers: u32, 125*1b4853f5SAndroid Build Coastguard Worker /// Coded size of the stream. 126*1b4853f5SAndroid Build Coastguard Worker pub coded_size: (u32, u32), 127*1b4853f5SAndroid Build Coastguard Worker /// Visible rectangle containing the part of the frame to display. 128*1b4853f5SAndroid Build Coastguard Worker pub visible_rect: v4l2r::Rect, 129*1b4853f5SAndroid Build Coastguard Worker } 130*1b4853f5SAndroid Build Coastguard Worker 131*1b4853f5SAndroid Build Coastguard Worker /// Trait for a video decoding session. 132*1b4853f5SAndroid Build Coastguard Worker pub trait VideoDecoderBackendSession { 133*1b4853f5SAndroid Build Coastguard Worker type BufferStorage: VideoDecoderBufferBacking; 134*1b4853f5SAndroid Build Coastguard Worker 135*1b4853f5SAndroid Build Coastguard Worker /// Decode the encoded stream in `input`, of length `bytes_used`, which corresponds to 136*1b4853f5SAndroid Build Coastguard Worker /// OUTPUT buffer `index`. 137*1b4853f5SAndroid Build Coastguard Worker /// 138*1b4853f5SAndroid Build Coastguard Worker /// `timestamp` is the timestamp of the frame, to be reported in any frame produced from this 139*1b4853f5SAndroid Build Coastguard Worker /// call. decode( &mut self, input: &Self::BufferStorage, index: u32, timestamp: bindings::timeval, bytes_used: u32, ) -> IoctlResult<()>140*1b4853f5SAndroid Build Coastguard Worker fn decode( 141*1b4853f5SAndroid Build Coastguard Worker &mut self, 142*1b4853f5SAndroid Build Coastguard Worker input: &Self::BufferStorage, 143*1b4853f5SAndroid Build Coastguard Worker index: u32, 144*1b4853f5SAndroid Build Coastguard Worker timestamp: bindings::timeval, 145*1b4853f5SAndroid Build Coastguard Worker bytes_used: u32, 146*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<()>; 147*1b4853f5SAndroid Build Coastguard Worker 148*1b4853f5SAndroid Build Coastguard Worker /// Use `backing` as the backing storage for output buffer `index`. use_as_output(&mut self, index: u32, backing: &mut Self::BufferStorage) -> IoctlResult<()>149*1b4853f5SAndroid Build Coastguard Worker fn use_as_output(&mut self, index: u32, backing: &mut Self::BufferStorage) -> IoctlResult<()>; 150*1b4853f5SAndroid Build Coastguard Worker 151*1b4853f5SAndroid Build Coastguard Worker /// Start draining the decoder pipeline for all buffers still in it. 152*1b4853f5SAndroid Build Coastguard Worker /// 153*1b4853f5SAndroid Build Coastguard Worker /// The backend will report a frame with the `V4L2_BUF_FLAG_LAST` once the drain 154*1b4853f5SAndroid Build Coastguard Worker /// process is completed. drain(&mut self) -> IoctlResult<()>155*1b4853f5SAndroid Build Coastguard Worker fn drain(&mut self) -> IoctlResult<()>; 156*1b4853f5SAndroid Build Coastguard Worker 157*1b4853f5SAndroid Build Coastguard Worker /// Remove any output buffer that has been previously added using [`use_as_output`]. clear_output_buffers(&mut self) -> IoctlResult<()>158*1b4853f5SAndroid Build Coastguard Worker fn clear_output_buffers(&mut self) -> IoctlResult<()>; 159*1b4853f5SAndroid Build Coastguard Worker 160*1b4853f5SAndroid Build Coastguard Worker /// Returns the next pending event if there is one, or `None` if there aren't any. next_event(&mut self) -> Option<VideoDecoderBackendEvent>161*1b4853f5SAndroid Build Coastguard Worker fn next_event(&mut self) -> Option<VideoDecoderBackendEvent>; 162*1b4853f5SAndroid Build Coastguard Worker 163*1b4853f5SAndroid Build Coastguard Worker /// Returns the current format set for the given `direction`, in a form suitable as a reply to 164*1b4853f5SAndroid Build Coastguard Worker /// `VIDIOC_G_FMT`. current_format(&self, direction: QueueDirection) -> V4l2MplaneFormat165*1b4853f5SAndroid Build Coastguard Worker fn current_format(&self, direction: QueueDirection) -> V4l2MplaneFormat; 166*1b4853f5SAndroid Build Coastguard Worker 167*1b4853f5SAndroid Build Coastguard Worker /// Returns the stream parameters as read from the input. stream_params(&self) -> StreamParams168*1b4853f5SAndroid Build Coastguard Worker fn stream_params(&self) -> StreamParams; 169*1b4853f5SAndroid Build Coastguard Worker 170*1b4853f5SAndroid Build Coastguard Worker /// Called whenever the decoder device has allocated buffers for a given queue. 171*1b4853f5SAndroid Build Coastguard Worker /// 172*1b4853f5SAndroid Build Coastguard Worker /// This can be useful for some backends that need to know how many buffers they will work 173*1b4853f5SAndroid Build Coastguard Worker /// with. The default implementation does nothing, which should be suitable for backends that 174*1b4853f5SAndroid Build Coastguard Worker /// don't care. buffers_allocated(&mut self, _direction: QueueDirection, _num_buffers: u32)175*1b4853f5SAndroid Build Coastguard Worker fn buffers_allocated(&mut self, _direction: QueueDirection, _num_buffers: u32) {} 176*1b4853f5SAndroid Build Coastguard Worker 177*1b4853f5SAndroid Build Coastguard Worker /// Returns a file descriptor that signals `POLLIN` whenever an event is pending and can be 178*1b4853f5SAndroid Build Coastguard Worker /// read using [`next_event`], or `None` if the backend does not support this. poll_fd(&self) -> Option<BorrowedFd>179*1b4853f5SAndroid Build Coastguard Worker fn poll_fd(&self) -> Option<BorrowedFd> { 180*1b4853f5SAndroid Build Coastguard Worker None 181*1b4853f5SAndroid Build Coastguard Worker } 182*1b4853f5SAndroid Build Coastguard Worker 183*1b4853f5SAndroid Build Coastguard Worker /// Optional hook called whenever the streaming state of a queue changes. Some backends may 184*1b4853f5SAndroid Build Coastguard Worker /// need this information to operate properly. streaming_state(&mut self, _direction: QueueDirection, _streaming: bool)185*1b4853f5SAndroid Build Coastguard Worker fn streaming_state(&mut self, _direction: QueueDirection, _streaming: bool) {} 186*1b4853f5SAndroid Build Coastguard Worker 187*1b4853f5SAndroid Build Coastguard Worker /// Optional hook called by the decoder to signal it has processed a pausing event 188*1b4853f5SAndroid Build Coastguard Worker /// sent by the backend. 189*1b4853f5SAndroid Build Coastguard Worker /// 190*1b4853f5SAndroid Build Coastguard Worker /// Pausing event are currently limited to [`VideoDecoderBackendEvent::StreamFormatChanged`]. 191*1b4853f5SAndroid Build Coastguard Worker /// Whenever the resolution changes, the backend must stop processing until the decoder has 192*1b4853f5SAndroid Build Coastguard Worker /// adapted its conditions for decoding to resume (e.g. CAPTURE buffers of the proper size and 193*1b4853f5SAndroid Build Coastguard Worker /// format have been allocated). resume(&mut self)194*1b4853f5SAndroid Build Coastguard Worker fn resume(&mut self) {} 195*1b4853f5SAndroid Build Coastguard Worker } 196*1b4853f5SAndroid Build Coastguard Worker 197*1b4853f5SAndroid Build Coastguard Worker /// State of a session. 198*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug)] 199*1b4853f5SAndroid Build Coastguard Worker enum VideoDecoderStreamingState { 200*1b4853f5SAndroid Build Coastguard Worker /// Initial state, and state after a `STOP` command or a successful drain. Contains the 201*1b4853f5SAndroid Build Coastguard Worker /// state of both streaming queues. 202*1b4853f5SAndroid Build Coastguard Worker Stopped { 203*1b4853f5SAndroid Build Coastguard Worker input_streaming: bool, 204*1b4853f5SAndroid Build Coastguard Worker output_streaming: bool, 205*1b4853f5SAndroid Build Coastguard Worker }, 206*1b4853f5SAndroid Build Coastguard Worker /// State when both queues are streaming. 207*1b4853f5SAndroid Build Coastguard Worker Running, 208*1b4853f5SAndroid Build Coastguard Worker /// State when a `PAUSE` command has been received. Both queues are streaming in this state. 209*1b4853f5SAndroid Build Coastguard Worker Paused, 210*1b4853f5SAndroid Build Coastguard Worker } 211*1b4853f5SAndroid Build Coastguard Worker 212*1b4853f5SAndroid Build Coastguard Worker impl Default for VideoDecoderStreamingState { default() -> Self213*1b4853f5SAndroid Build Coastguard Worker fn default() -> Self { 214*1b4853f5SAndroid Build Coastguard Worker Self::Stopped { 215*1b4853f5SAndroid Build Coastguard Worker input_streaming: false, 216*1b4853f5SAndroid Build Coastguard Worker output_streaming: false, 217*1b4853f5SAndroid Build Coastguard Worker } 218*1b4853f5SAndroid Build Coastguard Worker } 219*1b4853f5SAndroid Build Coastguard Worker } 220*1b4853f5SAndroid Build Coastguard Worker 221*1b4853f5SAndroid Build Coastguard Worker impl VideoDecoderStreamingState { input_streamon(&mut self)222*1b4853f5SAndroid Build Coastguard Worker fn input_streamon(&mut self) { 223*1b4853f5SAndroid Build Coastguard Worker match self { 224*1b4853f5SAndroid Build Coastguard Worker Self::Stopped { 225*1b4853f5SAndroid Build Coastguard Worker ref mut input_streaming, 226*1b4853f5SAndroid Build Coastguard Worker output_streaming, 227*1b4853f5SAndroid Build Coastguard Worker } if !(*input_streaming) => { 228*1b4853f5SAndroid Build Coastguard Worker *input_streaming = true; 229*1b4853f5SAndroid Build Coastguard Worker // If we switch to a state where both queues are streaming, then the device is 230*1b4853f5SAndroid Build Coastguard Worker // running. 231*1b4853f5SAndroid Build Coastguard Worker if *output_streaming { 232*1b4853f5SAndroid Build Coastguard Worker *self = Self::Running; 233*1b4853f5SAndroid Build Coastguard Worker } 234*1b4853f5SAndroid Build Coastguard Worker } 235*1b4853f5SAndroid Build Coastguard Worker Self::Stopped { .. } | Self::Running | Self::Paused => (), 236*1b4853f5SAndroid Build Coastguard Worker } 237*1b4853f5SAndroid Build Coastguard Worker } 238*1b4853f5SAndroid Build Coastguard Worker input_streamoff(&mut self)239*1b4853f5SAndroid Build Coastguard Worker fn input_streamoff(&mut self) { 240*1b4853f5SAndroid Build Coastguard Worker match self { 241*1b4853f5SAndroid Build Coastguard Worker Self::Stopped { 242*1b4853f5SAndroid Build Coastguard Worker ref mut input_streaming, 243*1b4853f5SAndroid Build Coastguard Worker .. 244*1b4853f5SAndroid Build Coastguard Worker } => *input_streaming = false, 245*1b4853f5SAndroid Build Coastguard Worker Self::Running | Self::Paused => { 246*1b4853f5SAndroid Build Coastguard Worker *self = Self::Stopped { 247*1b4853f5SAndroid Build Coastguard Worker input_streaming: false, 248*1b4853f5SAndroid Build Coastguard Worker output_streaming: true, 249*1b4853f5SAndroid Build Coastguard Worker } 250*1b4853f5SAndroid Build Coastguard Worker } 251*1b4853f5SAndroid Build Coastguard Worker } 252*1b4853f5SAndroid Build Coastguard Worker } 253*1b4853f5SAndroid Build Coastguard Worker output_streamon(&mut self)254*1b4853f5SAndroid Build Coastguard Worker fn output_streamon(&mut self) { 255*1b4853f5SAndroid Build Coastguard Worker match self { 256*1b4853f5SAndroid Build Coastguard Worker Self::Stopped { 257*1b4853f5SAndroid Build Coastguard Worker input_streaming, 258*1b4853f5SAndroid Build Coastguard Worker ref mut output_streaming, 259*1b4853f5SAndroid Build Coastguard Worker } if !(*output_streaming) => { 260*1b4853f5SAndroid Build Coastguard Worker *output_streaming = true; 261*1b4853f5SAndroid Build Coastguard Worker // If we switch to a state where both queues are streaming, then the device is 262*1b4853f5SAndroid Build Coastguard Worker // running. 263*1b4853f5SAndroid Build Coastguard Worker if *input_streaming { 264*1b4853f5SAndroid Build Coastguard Worker *self = Self::Running; 265*1b4853f5SAndroid Build Coastguard Worker } 266*1b4853f5SAndroid Build Coastguard Worker } 267*1b4853f5SAndroid Build Coastguard Worker Self::Stopped { .. } | Self::Running | Self::Paused => (), 268*1b4853f5SAndroid Build Coastguard Worker } 269*1b4853f5SAndroid Build Coastguard Worker } 270*1b4853f5SAndroid Build Coastguard Worker output_streamoff(&mut self)271*1b4853f5SAndroid Build Coastguard Worker fn output_streamoff(&mut self) { 272*1b4853f5SAndroid Build Coastguard Worker match self { 273*1b4853f5SAndroid Build Coastguard Worker Self::Stopped { 274*1b4853f5SAndroid Build Coastguard Worker ref mut output_streaming, 275*1b4853f5SAndroid Build Coastguard Worker .. 276*1b4853f5SAndroid Build Coastguard Worker } => *output_streaming = false, 277*1b4853f5SAndroid Build Coastguard Worker Self::Running | Self::Paused => { 278*1b4853f5SAndroid Build Coastguard Worker *self = Self::Stopped { 279*1b4853f5SAndroid Build Coastguard Worker input_streaming: true, 280*1b4853f5SAndroid Build Coastguard Worker output_streaming: false, 281*1b4853f5SAndroid Build Coastguard Worker } 282*1b4853f5SAndroid Build Coastguard Worker } 283*1b4853f5SAndroid Build Coastguard Worker } 284*1b4853f5SAndroid Build Coastguard Worker } 285*1b4853f5SAndroid Build Coastguard Worker is_output_streaming(&mut self) -> bool286*1b4853f5SAndroid Build Coastguard Worker fn is_output_streaming(&mut self) -> bool { 287*1b4853f5SAndroid Build Coastguard Worker matches!( 288*1b4853f5SAndroid Build Coastguard Worker self, 289*1b4853f5SAndroid Build Coastguard Worker Self::Running 290*1b4853f5SAndroid Build Coastguard Worker | Self::Stopped { 291*1b4853f5SAndroid Build Coastguard Worker output_streaming: true, 292*1b4853f5SAndroid Build Coastguard Worker .. 293*1b4853f5SAndroid Build Coastguard Worker } 294*1b4853f5SAndroid Build Coastguard Worker ) 295*1b4853f5SAndroid Build Coastguard Worker } 296*1b4853f5SAndroid Build Coastguard Worker } 297*1b4853f5SAndroid Build Coastguard Worker 298*1b4853f5SAndroid Build Coastguard Worker /// Management of the crop rectangle. 299*1b4853f5SAndroid Build Coastguard Worker /// 300*1b4853f5SAndroid Build Coastguard Worker /// There are two ways this parameter can be set: 301*1b4853f5SAndroid Build Coastguard Worker /// 302*1b4853f5SAndroid Build Coastguard Worker /// * Manually by the client, by calling `VIDIOC_S_SELECTION` with `V4L2_SEL_TGT_COMPOSE`. This has 303*1b4853f5SAndroid Build Coastguard Worker /// an effect only before the first resolution change event is emitted, and is the only way to 304*1b4853f5SAndroid Build Coastguard Worker /// properly set the crop rectangle for codecs/hardware that don't support DRC detection. 305*1b4853f5SAndroid Build Coastguard Worker /// 306*1b4853f5SAndroid Build Coastguard Worker /// * From the information contained in the stream, signaled via a 307*1b4853f5SAndroid Build Coastguard Worker /// [`VideoDecoderBackendEvent::StreamFormatChanged`] event. Once this event has been emitted, the 308*1b4853f5SAndroid Build Coastguard Worker /// crop rectangle is fixed and determined by the stream. 309*1b4853f5SAndroid Build Coastguard Worker enum CropRectangle { 310*1b4853f5SAndroid Build Coastguard Worker /// Crop rectangle has not been determined from the stream yet and can be set by the client. 311*1b4853f5SAndroid Build Coastguard Worker Settable(v4l2r::Rect), 312*1b4853f5SAndroid Build Coastguard Worker /// Crop rectangle has been determined from the stream and cannot be modified. 313*1b4853f5SAndroid Build Coastguard Worker FromStream(v4l2r::Rect), 314*1b4853f5SAndroid Build Coastguard Worker } 315*1b4853f5SAndroid Build Coastguard Worker 316*1b4853f5SAndroid Build Coastguard Worker impl Deref for CropRectangle { 317*1b4853f5SAndroid Build Coastguard Worker type Target = v4l2r::Rect; 318*1b4853f5SAndroid Build Coastguard Worker deref(&self) -> &Self::Target319*1b4853f5SAndroid Build Coastguard Worker fn deref(&self) -> &Self::Target { 320*1b4853f5SAndroid Build Coastguard Worker match self { 321*1b4853f5SAndroid Build Coastguard Worker CropRectangle::Settable(r) => r, 322*1b4853f5SAndroid Build Coastguard Worker CropRectangle::FromStream(r) => r, 323*1b4853f5SAndroid Build Coastguard Worker } 324*1b4853f5SAndroid Build Coastguard Worker } 325*1b4853f5SAndroid Build Coastguard Worker } 326*1b4853f5SAndroid Build Coastguard Worker 327*1b4853f5SAndroid Build Coastguard Worker /// Struct containing validated colorspace information for a format. 328*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy)] 329*1b4853f5SAndroid Build Coastguard Worker struct V4l2FormatColorspace { 330*1b4853f5SAndroid Build Coastguard Worker colorspace: Colorspace, 331*1b4853f5SAndroid Build Coastguard Worker xfer_func: XferFunc, 332*1b4853f5SAndroid Build Coastguard Worker ycbcr_enc: YCbCrEncoding, 333*1b4853f5SAndroid Build Coastguard Worker quantization: Quantization, 334*1b4853f5SAndroid Build Coastguard Worker } 335*1b4853f5SAndroid Build Coastguard Worker 336*1b4853f5SAndroid Build Coastguard Worker impl Default for V4l2FormatColorspace { default() -> Self337*1b4853f5SAndroid Build Coastguard Worker fn default() -> Self { 338*1b4853f5SAndroid Build Coastguard Worker Self { 339*1b4853f5SAndroid Build Coastguard Worker colorspace: Colorspace::Rec709, 340*1b4853f5SAndroid Build Coastguard Worker xfer_func: XferFunc::None, 341*1b4853f5SAndroid Build Coastguard Worker ycbcr_enc: YCbCrEncoding::E709, 342*1b4853f5SAndroid Build Coastguard Worker quantization: Quantization::LimRange, 343*1b4853f5SAndroid Build Coastguard Worker } 344*1b4853f5SAndroid Build Coastguard Worker } 345*1b4853f5SAndroid Build Coastguard Worker } 346*1b4853f5SAndroid Build Coastguard Worker 347*1b4853f5SAndroid Build Coastguard Worker impl V4l2FormatColorspace { 348*1b4853f5SAndroid Build Coastguard Worker /// Apply the colorspace information of this object to `pix_mp`. apply(self, pix_mp: &mut bindings::v4l2_pix_format_mplane)349*1b4853f5SAndroid Build Coastguard Worker fn apply(self, pix_mp: &mut bindings::v4l2_pix_format_mplane) { 350*1b4853f5SAndroid Build Coastguard Worker pix_mp.colorspace = self.colorspace as u32; 351*1b4853f5SAndroid Build Coastguard Worker pix_mp.__bindgen_anon_1 = bindings::v4l2_pix_format_mplane__bindgen_ty_1 { 352*1b4853f5SAndroid Build Coastguard Worker ycbcr_enc: self.ycbcr_enc as u8, 353*1b4853f5SAndroid Build Coastguard Worker }; 354*1b4853f5SAndroid Build Coastguard Worker pix_mp.quantization = self.quantization as u8; 355*1b4853f5SAndroid Build Coastguard Worker pix_mp.xfer_func = self.xfer_func as u8; 356*1b4853f5SAndroid Build Coastguard Worker } 357*1b4853f5SAndroid Build Coastguard Worker } 358*1b4853f5SAndroid Build Coastguard Worker 359*1b4853f5SAndroid Build Coastguard Worker pub struct VideoDecoderSession<S: VideoDecoderBackendSession> { 360*1b4853f5SAndroid Build Coastguard Worker id: u32, 361*1b4853f5SAndroid Build Coastguard Worker 362*1b4853f5SAndroid Build Coastguard Worker state: VideoDecoderStreamingState, 363*1b4853f5SAndroid Build Coastguard Worker 364*1b4853f5SAndroid Build Coastguard Worker input_buffers: Vec<VideoDecoderBuffer<S::BufferStorage>>, 365*1b4853f5SAndroid Build Coastguard Worker output_buffers: Vec<VideoDecoderBuffer<S::BufferStorage>>, 366*1b4853f5SAndroid Build Coastguard Worker /// Indices of CAPTURE buffers that are queued but not send to the backend yet because the 367*1b4853f5SAndroid Build Coastguard Worker /// decoder is not running. 368*1b4853f5SAndroid Build Coastguard Worker pending_output_buffers: Vec<u32>, 369*1b4853f5SAndroid Build Coastguard Worker 370*1b4853f5SAndroid Build Coastguard Worker sequence_cpt: u32, 371*1b4853f5SAndroid Build Coastguard Worker 372*1b4853f5SAndroid Build Coastguard Worker /// Whether the input source change event has been subscribed to by the driver. If `true` then 373*1b4853f5SAndroid Build Coastguard Worker /// the device will emit resolution change events. 374*1b4853f5SAndroid Build Coastguard Worker src_change_subscribed: bool, 375*1b4853f5SAndroid Build Coastguard Worker /// Whether the EOS event has been subscribed to by the driver. If `true` then the device will 376*1b4853f5SAndroid Build Coastguard Worker /// emit EOS events. 377*1b4853f5SAndroid Build Coastguard Worker eos_subscribed: bool, 378*1b4853f5SAndroid Build Coastguard Worker 379*1b4853f5SAndroid Build Coastguard Worker crop_rectangle: CropRectangle, 380*1b4853f5SAndroid Build Coastguard Worker 381*1b4853f5SAndroid Build Coastguard Worker /// Current colorspace information of the format. 382*1b4853f5SAndroid Build Coastguard Worker colorspace: V4l2FormatColorspace, 383*1b4853f5SAndroid Build Coastguard Worker 384*1b4853f5SAndroid Build Coastguard Worker /// Adapter-specific data. 385*1b4853f5SAndroid Build Coastguard Worker backend_session: S, 386*1b4853f5SAndroid Build Coastguard Worker } 387*1b4853f5SAndroid Build Coastguard Worker 388*1b4853f5SAndroid Build Coastguard Worker impl<S: VideoDecoderBackendSession> VirtioMediaDeviceSession for VideoDecoderSession<S> { poll_fd(&self) -> Option<BorrowedFd>389*1b4853f5SAndroid Build Coastguard Worker fn poll_fd(&self) -> Option<BorrowedFd> { 390*1b4853f5SAndroid Build Coastguard Worker self.backend_session.poll_fd() 391*1b4853f5SAndroid Build Coastguard Worker } 392*1b4853f5SAndroid Build Coastguard Worker } 393*1b4853f5SAndroid Build Coastguard Worker 394*1b4853f5SAndroid Build Coastguard Worker impl<S: VideoDecoderBackendSession> VideoDecoderSession<S> { 395*1b4853f5SAndroid Build Coastguard Worker /// Returns the current format for `direction`. 396*1b4853f5SAndroid Build Coastguard Worker /// 397*1b4853f5SAndroid Build Coastguard Worker /// This is essentially like calling the backend's corresponding 398*1b4853f5SAndroid Build Coastguard Worker /// [`VideoDecoderBackendSession::current_format`] method, but also applies the colorspace 399*1b4853f5SAndroid Build Coastguard Worker /// information potentially set by the user. current_format(&self, direction: QueueDirection) -> V4l2MplaneFormat400*1b4853f5SAndroid Build Coastguard Worker fn current_format(&self, direction: QueueDirection) -> V4l2MplaneFormat { 401*1b4853f5SAndroid Build Coastguard Worker let format = self.backend_session.current_format(direction); 402*1b4853f5SAndroid Build Coastguard Worker 403*1b4853f5SAndroid Build Coastguard Worker let mut pix_mp = 404*1b4853f5SAndroid Build Coastguard Worker *<V4l2MplaneFormat as AsRef<bindings::v4l2_pix_format_mplane>>::as_ref(&format); 405*1b4853f5SAndroid Build Coastguard Worker 406*1b4853f5SAndroid Build Coastguard Worker self.colorspace.apply(&mut pix_mp); 407*1b4853f5SAndroid Build Coastguard Worker 408*1b4853f5SAndroid Build Coastguard Worker V4l2MplaneFormat::from((direction, pix_mp)) 409*1b4853f5SAndroid Build Coastguard Worker } 410*1b4853f5SAndroid Build Coastguard Worker try_decoder_cmd(&self, cmd: DecoderCmd) -> IoctlResult<DecoderCmd>411*1b4853f5SAndroid Build Coastguard Worker fn try_decoder_cmd(&self, cmd: DecoderCmd) -> IoctlResult<DecoderCmd> { 412*1b4853f5SAndroid Build Coastguard Worker match cmd { 413*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Stop { .. } => Ok(DecoderCmd::stop()), 414*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Start { .. } => Ok(DecoderCmd::start()), 415*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Pause { .. } => { 416*1b4853f5SAndroid Build Coastguard Worker match &self.state { 417*1b4853f5SAndroid Build Coastguard Worker // The V4L2 documentation says this should return `EPERM`, but v4l2-compliance 418*1b4853f5SAndroid Build Coastguard Worker // requires `EINVAL`... 419*1b4853f5SAndroid Build Coastguard Worker VideoDecoderStreamingState::Stopped { .. } => Err(libc::EINVAL), 420*1b4853f5SAndroid Build Coastguard Worker VideoDecoderStreamingState::Running | VideoDecoderStreamingState::Paused => { 421*1b4853f5SAndroid Build Coastguard Worker Ok(DecoderCmd::pause()) 422*1b4853f5SAndroid Build Coastguard Worker } 423*1b4853f5SAndroid Build Coastguard Worker } 424*1b4853f5SAndroid Build Coastguard Worker } 425*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Resume => { 426*1b4853f5SAndroid Build Coastguard Worker match &self.state { 427*1b4853f5SAndroid Build Coastguard Worker // The V4L2 documentation says this should return `EPERM`, but v4l2-compliance 428*1b4853f5SAndroid Build Coastguard Worker // requires `EINVAL`... 429*1b4853f5SAndroid Build Coastguard Worker VideoDecoderStreamingState::Stopped { .. } => Err(libc::EINVAL), 430*1b4853f5SAndroid Build Coastguard Worker VideoDecoderStreamingState::Paused | VideoDecoderStreamingState::Running => { 431*1b4853f5SAndroid Build Coastguard Worker Ok(DecoderCmd::resume()) 432*1b4853f5SAndroid Build Coastguard Worker } 433*1b4853f5SAndroid Build Coastguard Worker } 434*1b4853f5SAndroid Build Coastguard Worker } 435*1b4853f5SAndroid Build Coastguard Worker } 436*1b4853f5SAndroid Build Coastguard Worker } 437*1b4853f5SAndroid Build Coastguard Worker 438*1b4853f5SAndroid Build Coastguard Worker /// Send all the output buffers that are pending to the backend, if the decoder is running. 439*1b4853f5SAndroid Build Coastguard Worker /// 440*1b4853f5SAndroid Build Coastguard Worker /// In the adapter backend, if we receive buffers this means both queues are streaming - IOW we 441*1b4853f5SAndroid Build Coastguard Worker /// can queue them as soon as the condition is good. 442*1b4853f5SAndroid Build Coastguard Worker /// 443*1b4853f5SAndroid Build Coastguard Worker /// In the decoder device, we need to keep them until both queues are streaming. Same applies 444*1b4853f5SAndroid Build Coastguard Worker /// to input buffers BTW. try_send_pending_output_buffers(&mut self)445*1b4853f5SAndroid Build Coastguard Worker fn try_send_pending_output_buffers(&mut self) { 446*1b4853f5SAndroid Build Coastguard Worker if !self.state.is_output_streaming() { 447*1b4853f5SAndroid Build Coastguard Worker return; 448*1b4853f5SAndroid Build Coastguard Worker } 449*1b4853f5SAndroid Build Coastguard Worker 450*1b4853f5SAndroid Build Coastguard Worker for i in self.pending_output_buffers.drain(..) { 451*1b4853f5SAndroid Build Coastguard Worker let buffer = self.output_buffers.get_mut(i as usize).unwrap(); 452*1b4853f5SAndroid Build Coastguard Worker self.backend_session 453*1b4853f5SAndroid Build Coastguard Worker .use_as_output(buffer.index(), &mut buffer.backing) 454*1b4853f5SAndroid Build Coastguard Worker .unwrap(); 455*1b4853f5SAndroid Build Coastguard Worker } 456*1b4853f5SAndroid Build Coastguard Worker } 457*1b4853f5SAndroid Build Coastguard Worker } 458*1b4853f5SAndroid Build Coastguard Worker 459*1b4853f5SAndroid Build Coastguard Worker /// Trait for actual implementations of video decoding, to be used with [`VideoDecoder`]. 460*1b4853f5SAndroid Build Coastguard Worker /// 461*1b4853f5SAndroid Build Coastguard Worker /// [`VideoDecoder`] takes care of (mostly) abstracting V4L2 away ; implementors of this trait are 462*1b4853f5SAndroid Build Coastguard Worker /// the ones that provide the actual video decoding service. 463*1b4853f5SAndroid Build Coastguard Worker pub trait VideoDecoderBackend: Sized { 464*1b4853f5SAndroid Build Coastguard Worker type Session: VideoDecoderBackendSession; 465*1b4853f5SAndroid Build Coastguard Worker 466*1b4853f5SAndroid Build Coastguard Worker /// Create a new session with the provided `id`. new_session(&mut self, id: u32) -> IoctlResult<Self::Session>467*1b4853f5SAndroid Build Coastguard Worker fn new_session(&mut self, id: u32) -> IoctlResult<Self::Session>; 468*1b4853f5SAndroid Build Coastguard Worker /// Close and destroy `session`. close_session(&mut self, session: Self::Session)469*1b4853f5SAndroid Build Coastguard Worker fn close_session(&mut self, session: Self::Session); 470*1b4853f5SAndroid Build Coastguard Worker 471*1b4853f5SAndroid Build Coastguard Worker /// Returns the format at `index` for the given queue `direction`, or None if `index` is out of 472*1b4853f5SAndroid Build Coastguard Worker /// bounds. enum_formats( &self, session: &VideoDecoderSession<Self::Session>, direction: QueueDirection, index: u32, ) -> Option<bindings::v4l2_fmtdesc>473*1b4853f5SAndroid Build Coastguard Worker fn enum_formats( 474*1b4853f5SAndroid Build Coastguard Worker &self, 475*1b4853f5SAndroid Build Coastguard Worker session: &VideoDecoderSession<Self::Session>, 476*1b4853f5SAndroid Build Coastguard Worker direction: QueueDirection, 477*1b4853f5SAndroid Build Coastguard Worker index: u32, 478*1b4853f5SAndroid Build Coastguard Worker ) -> Option<bindings::v4l2_fmtdesc>; 479*1b4853f5SAndroid Build Coastguard Worker /// Returns the supported frame sizes for `pixel_format`, or None if the format is not 480*1b4853f5SAndroid Build Coastguard Worker /// supported. frame_sizes(&self, pixel_format: u32) -> Option<bindings::v4l2_frmsize_stepwise>481*1b4853f5SAndroid Build Coastguard Worker fn frame_sizes(&self, pixel_format: u32) -> Option<bindings::v4l2_frmsize_stepwise>; 482*1b4853f5SAndroid Build Coastguard Worker 483*1b4853f5SAndroid Build Coastguard Worker /// Adjust `format` to make it applicable to the queue with the given `direction` for the current `session`. 484*1b4853f5SAndroid Build Coastguard Worker /// 485*1b4853f5SAndroid Build Coastguard Worker /// This method doesn't fail, implementations must return the closest acceptable format that 486*1b4853f5SAndroid Build Coastguard Worker /// can be applied unchanged with [`Self::apply_format`]. adjust_format( &self, session: &Self::Session, direction: QueueDirection, format: V4l2MplaneFormat, ) -> V4l2MplaneFormat487*1b4853f5SAndroid Build Coastguard Worker fn adjust_format( 488*1b4853f5SAndroid Build Coastguard Worker &self, 489*1b4853f5SAndroid Build Coastguard Worker session: &Self::Session, 490*1b4853f5SAndroid Build Coastguard Worker direction: QueueDirection, 491*1b4853f5SAndroid Build Coastguard Worker format: V4l2MplaneFormat, 492*1b4853f5SAndroid Build Coastguard Worker ) -> V4l2MplaneFormat; 493*1b4853f5SAndroid Build Coastguard Worker 494*1b4853f5SAndroid Build Coastguard Worker /// Applies `format` to the queue of the given `direction`. The format is adjusted if needed. apply_format( &self, session: &mut Self::Session, direction: QueueDirection, format: &V4l2MplaneFormat, )495*1b4853f5SAndroid Build Coastguard Worker fn apply_format( 496*1b4853f5SAndroid Build Coastguard Worker &self, 497*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 498*1b4853f5SAndroid Build Coastguard Worker direction: QueueDirection, 499*1b4853f5SAndroid Build Coastguard Worker format: &V4l2MplaneFormat, 500*1b4853f5SAndroid Build Coastguard Worker ); 501*1b4853f5SAndroid Build Coastguard Worker } 502*1b4853f5SAndroid Build Coastguard Worker 503*1b4853f5SAndroid Build Coastguard Worker pub struct VideoDecoder< 504*1b4853f5SAndroid Build Coastguard Worker D: VideoDecoderBackend, 505*1b4853f5SAndroid Build Coastguard Worker Q: VirtioMediaEventQueue, 506*1b4853f5SAndroid Build Coastguard Worker HM: VirtioMediaHostMemoryMapper, 507*1b4853f5SAndroid Build Coastguard Worker > { 508*1b4853f5SAndroid Build Coastguard Worker backend: D, 509*1b4853f5SAndroid Build Coastguard Worker event_queue: Q, 510*1b4853f5SAndroid Build Coastguard Worker host_mapper: MmapMappingManager<HM>, 511*1b4853f5SAndroid Build Coastguard Worker } 512*1b4853f5SAndroid Build Coastguard Worker 513*1b4853f5SAndroid Build Coastguard Worker impl<B, Q, HM> VideoDecoder<B, Q, HM> 514*1b4853f5SAndroid Build Coastguard Worker where 515*1b4853f5SAndroid Build Coastguard Worker B: VideoDecoderBackend, 516*1b4853f5SAndroid Build Coastguard Worker Q: VirtioMediaEventQueue, 517*1b4853f5SAndroid Build Coastguard Worker HM: VirtioMediaHostMemoryMapper, 518*1b4853f5SAndroid Build Coastguard Worker { new(backend: B, event_queue: Q, host_mapper: HM) -> Self519*1b4853f5SAndroid Build Coastguard Worker pub fn new(backend: B, event_queue: Q, host_mapper: HM) -> Self { 520*1b4853f5SAndroid Build Coastguard Worker Self { 521*1b4853f5SAndroid Build Coastguard Worker backend, 522*1b4853f5SAndroid Build Coastguard Worker event_queue, 523*1b4853f5SAndroid Build Coastguard Worker host_mapper: MmapMappingManager::from(host_mapper), 524*1b4853f5SAndroid Build Coastguard Worker } 525*1b4853f5SAndroid Build Coastguard Worker } 526*1b4853f5SAndroid Build Coastguard Worker 527*1b4853f5SAndroid Build Coastguard Worker /// Validate `format` for `queue` and return the adjusted format. try_format( &self, session: &VideoDecoderSession<B::Session>, queue: QueueType, format: bindings::v4l2_format, ) -> IoctlResult<V4l2MplaneFormat>528*1b4853f5SAndroid Build Coastguard Worker fn try_format( 529*1b4853f5SAndroid Build Coastguard Worker &self, 530*1b4853f5SAndroid Build Coastguard Worker session: &VideoDecoderSession<B::Session>, 531*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 532*1b4853f5SAndroid Build Coastguard Worker format: bindings::v4l2_format, 533*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<V4l2MplaneFormat> { 534*1b4853f5SAndroid Build Coastguard Worker if queue.class() != QueueClass::VideoMplane { 535*1b4853f5SAndroid Build Coastguard Worker return Err(libc::EINVAL); 536*1b4853f5SAndroid Build Coastguard Worker } 537*1b4853f5SAndroid Build Coastguard Worker 538*1b4853f5SAndroid Build Coastguard Worker // SAFETY: safe because we have just confirmed the queue type is mplane. 539*1b4853f5SAndroid Build Coastguard Worker let pix_mp = unsafe { format.fmt.pix_mp }; 540*1b4853f5SAndroid Build Coastguard Worker 541*1b4853f5SAndroid Build Coastguard Worker // Process the colorspace now so we can restore it after applying the backend adjustment. 542*1b4853f5SAndroid Build Coastguard Worker let colorspace = if queue.direction() == QueueDirection::Output { 543*1b4853f5SAndroid Build Coastguard Worker V4l2FormatColorspace { 544*1b4853f5SAndroid Build Coastguard Worker colorspace: Colorspace::n(pix_mp.colorspace) 545*1b4853f5SAndroid Build Coastguard Worker .unwrap_or(session.colorspace.colorspace), 546*1b4853f5SAndroid Build Coastguard Worker xfer_func: XferFunc::n(pix_mp.xfer_func as u32) 547*1b4853f5SAndroid Build Coastguard Worker .unwrap_or(session.colorspace.xfer_func), 548*1b4853f5SAndroid Build Coastguard Worker // TODO: safe because... 549*1b4853f5SAndroid Build Coastguard Worker ycbcr_enc: YCbCrEncoding::n(unsafe { pix_mp.__bindgen_anon_1.ycbcr_enc as u32 }) 550*1b4853f5SAndroid Build Coastguard Worker .unwrap_or(session.colorspace.ycbcr_enc), 551*1b4853f5SAndroid Build Coastguard Worker quantization: Quantization::n(pix_mp.quantization as u32) 552*1b4853f5SAndroid Build Coastguard Worker .unwrap_or(session.colorspace.quantization), 553*1b4853f5SAndroid Build Coastguard Worker } 554*1b4853f5SAndroid Build Coastguard Worker } else { 555*1b4853f5SAndroid Build Coastguard Worker session.colorspace 556*1b4853f5SAndroid Build Coastguard Worker }; 557*1b4853f5SAndroid Build Coastguard Worker 558*1b4853f5SAndroid Build Coastguard Worker let format = V4l2MplaneFormat::from((queue.direction(), pix_mp)); 559*1b4853f5SAndroid Build Coastguard Worker 560*1b4853f5SAndroid Build Coastguard Worker let format = 561*1b4853f5SAndroid Build Coastguard Worker self.backend 562*1b4853f5SAndroid Build Coastguard Worker .adjust_format(&session.backend_session, queue.direction(), format); 563*1b4853f5SAndroid Build Coastguard Worker 564*1b4853f5SAndroid Build Coastguard Worker let mut pix_mp = 565*1b4853f5SAndroid Build Coastguard Worker *<V4l2MplaneFormat as AsRef<bindings::v4l2_pix_format_mplane>>::as_ref(&format); 566*1b4853f5SAndroid Build Coastguard Worker 567*1b4853f5SAndroid Build Coastguard Worker colorspace.apply(&mut pix_mp); 568*1b4853f5SAndroid Build Coastguard Worker 569*1b4853f5SAndroid Build Coastguard Worker Ok(V4l2MplaneFormat::from((queue.direction(), pix_mp))) 570*1b4853f5SAndroid Build Coastguard Worker } 571*1b4853f5SAndroid Build Coastguard Worker } 572*1b4853f5SAndroid Build Coastguard Worker 573*1b4853f5SAndroid Build Coastguard Worker impl<B, Q, HM, Reader, Writer> VirtioMediaDevice<Reader, Writer> for VideoDecoder<B, Q, HM> 574*1b4853f5SAndroid Build Coastguard Worker where 575*1b4853f5SAndroid Build Coastguard Worker B: VideoDecoderBackend, 576*1b4853f5SAndroid Build Coastguard Worker Q: VirtioMediaEventQueue, 577*1b4853f5SAndroid Build Coastguard Worker HM: VirtioMediaHostMemoryMapper, 578*1b4853f5SAndroid Build Coastguard Worker Reader: std::io::Read, 579*1b4853f5SAndroid Build Coastguard Worker Writer: std::io::Write, 580*1b4853f5SAndroid Build Coastguard Worker { 581*1b4853f5SAndroid Build Coastguard Worker type Session = <Self as VirtioMediaIoctlHandler>::Session; 582*1b4853f5SAndroid Build Coastguard Worker new_session(&mut self, session_id: u32) -> Result<Self::Session, i32>583*1b4853f5SAndroid Build Coastguard Worker fn new_session(&mut self, session_id: u32) -> Result<Self::Session, i32> { 584*1b4853f5SAndroid Build Coastguard Worker let backend_session = self.backend.new_session(session_id)?; 585*1b4853f5SAndroid Build Coastguard Worker 586*1b4853f5SAndroid Build Coastguard Worker Ok(VideoDecoderSession { 587*1b4853f5SAndroid Build Coastguard Worker id: session_id, 588*1b4853f5SAndroid Build Coastguard Worker backend_session, 589*1b4853f5SAndroid Build Coastguard Worker state: Default::default(), 590*1b4853f5SAndroid Build Coastguard Worker input_buffers: Default::default(), 591*1b4853f5SAndroid Build Coastguard Worker output_buffers: Default::default(), 592*1b4853f5SAndroid Build Coastguard Worker pending_output_buffers: Default::default(), 593*1b4853f5SAndroid Build Coastguard Worker sequence_cpt: 0, 594*1b4853f5SAndroid Build Coastguard Worker src_change_subscribed: false, 595*1b4853f5SAndroid Build Coastguard Worker eos_subscribed: false, 596*1b4853f5SAndroid Build Coastguard Worker crop_rectangle: CropRectangle::Settable(v4l2r::Rect::new(0, 0, 0, 0)), 597*1b4853f5SAndroid Build Coastguard Worker colorspace: Default::default(), 598*1b4853f5SAndroid Build Coastguard Worker }) 599*1b4853f5SAndroid Build Coastguard Worker } 600*1b4853f5SAndroid Build Coastguard Worker close_session(&mut self, session: Self::Session)601*1b4853f5SAndroid Build Coastguard Worker fn close_session(&mut self, session: Self::Session) { 602*1b4853f5SAndroid Build Coastguard Worker // Unregister all MMAP buffers. 603*1b4853f5SAndroid Build Coastguard Worker for buffer in session 604*1b4853f5SAndroid Build Coastguard Worker .input_buffers 605*1b4853f5SAndroid Build Coastguard Worker .iter() 606*1b4853f5SAndroid Build Coastguard Worker .chain(session.output_buffers.iter()) 607*1b4853f5SAndroid Build Coastguard Worker { 608*1b4853f5SAndroid Build Coastguard Worker if let V4l2PlanesWithBacking::Mmap(planes) = 609*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.planes_with_backing_iter() 610*1b4853f5SAndroid Build Coastguard Worker { 611*1b4853f5SAndroid Build Coastguard Worker for plane in planes { 612*1b4853f5SAndroid Build Coastguard Worker self.host_mapper.unregister_buffer(plane.mem_offset()); 613*1b4853f5SAndroid Build Coastguard Worker } 614*1b4853f5SAndroid Build Coastguard Worker } 615*1b4853f5SAndroid Build Coastguard Worker } 616*1b4853f5SAndroid Build Coastguard Worker } 617*1b4853f5SAndroid Build Coastguard Worker do_ioctl( &mut self, session: &mut Self::Session, ioctl: V4l2Ioctl, reader: &mut Reader, writer: &mut Writer, ) -> std::io::Result<()>618*1b4853f5SAndroid Build Coastguard Worker fn do_ioctl( 619*1b4853f5SAndroid Build Coastguard Worker &mut self, 620*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 621*1b4853f5SAndroid Build Coastguard Worker ioctl: V4l2Ioctl, 622*1b4853f5SAndroid Build Coastguard Worker reader: &mut Reader, 623*1b4853f5SAndroid Build Coastguard Worker writer: &mut Writer, 624*1b4853f5SAndroid Build Coastguard Worker ) -> std::io::Result<()> { 625*1b4853f5SAndroid Build Coastguard Worker virtio_media_dispatch_ioctl(self, session, ioctl, reader, writer) 626*1b4853f5SAndroid Build Coastguard Worker } 627*1b4853f5SAndroid Build Coastguard Worker do_mmap( &mut self, session: &mut Self::Session, flags: u32, offset: u32, ) -> Result<(u64, u64), i32>628*1b4853f5SAndroid Build Coastguard Worker fn do_mmap( 629*1b4853f5SAndroid Build Coastguard Worker &mut self, 630*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 631*1b4853f5SAndroid Build Coastguard Worker flags: u32, 632*1b4853f5SAndroid Build Coastguard Worker offset: u32, 633*1b4853f5SAndroid Build Coastguard Worker ) -> Result<(u64, u64), i32> { 634*1b4853f5SAndroid Build Coastguard Worker // Search for a MMAP plane with the right offset. 635*1b4853f5SAndroid Build Coastguard Worker // TODO: O(n), not critical but not great either. 636*1b4853f5SAndroid Build Coastguard Worker let (buffer, plane_idx) = session 637*1b4853f5SAndroid Build Coastguard Worker .input_buffers 638*1b4853f5SAndroid Build Coastguard Worker .iter() 639*1b4853f5SAndroid Build Coastguard Worker .chain(session.output_buffers.iter()) 640*1b4853f5SAndroid Build Coastguard Worker .filter_map(|b| { 641*1b4853f5SAndroid Build Coastguard Worker if let V4l2PlanesWithBacking::Mmap(planes) = 642*1b4853f5SAndroid Build Coastguard Worker b.v4l2_buffer.planes_with_backing_iter() 643*1b4853f5SAndroid Build Coastguard Worker { 644*1b4853f5SAndroid Build Coastguard Worker Some(std::iter::repeat(b).zip(planes.enumerate())) 645*1b4853f5SAndroid Build Coastguard Worker } else { 646*1b4853f5SAndroid Build Coastguard Worker None 647*1b4853f5SAndroid Build Coastguard Worker } 648*1b4853f5SAndroid Build Coastguard Worker }) 649*1b4853f5SAndroid Build Coastguard Worker .flatten() 650*1b4853f5SAndroid Build Coastguard Worker .find(|(_, (_, p))| p.mem_offset() == offset) 651*1b4853f5SAndroid Build Coastguard Worker .map(|(b, (i, _))| (b, i)) 652*1b4853f5SAndroid Build Coastguard Worker .ok_or(libc::EINVAL)?; 653*1b4853f5SAndroid Build Coastguard Worker let rw = (flags & VIRTIO_MEDIA_MMAP_FLAG_RW) != 0; 654*1b4853f5SAndroid Build Coastguard Worker 655*1b4853f5SAndroid Build Coastguard Worker let fd = buffer.backing.fd_for_plane(plane_idx).unwrap(); 656*1b4853f5SAndroid Build Coastguard Worker 657*1b4853f5SAndroid Build Coastguard Worker self.host_mapper 658*1b4853f5SAndroid Build Coastguard Worker .create_mapping(offset, fd, rw) 659*1b4853f5SAndroid Build Coastguard Worker .map_err(|e| { 660*1b4853f5SAndroid Build Coastguard Worker log::error!( 661*1b4853f5SAndroid Build Coastguard Worker "failed to map MMAP buffer at offset 0x{:x}: {:#}", 662*1b4853f5SAndroid Build Coastguard Worker offset, 663*1b4853f5SAndroid Build Coastguard Worker e 664*1b4853f5SAndroid Build Coastguard Worker ); 665*1b4853f5SAndroid Build Coastguard Worker libc::EINVAL 666*1b4853f5SAndroid Build Coastguard Worker }) 667*1b4853f5SAndroid Build Coastguard Worker } 668*1b4853f5SAndroid Build Coastguard Worker do_munmap(&mut self, guest_addr: u64) -> Result<(), i32>669*1b4853f5SAndroid Build Coastguard Worker fn do_munmap(&mut self, guest_addr: u64) -> Result<(), i32> { 670*1b4853f5SAndroid Build Coastguard Worker self.host_mapper 671*1b4853f5SAndroid Build Coastguard Worker .remove_mapping(guest_addr) 672*1b4853f5SAndroid Build Coastguard Worker .map(|_| ()) 673*1b4853f5SAndroid Build Coastguard Worker .map_err(|_| libc::EINVAL) 674*1b4853f5SAndroid Build Coastguard Worker } 675*1b4853f5SAndroid Build Coastguard Worker process_events(&mut self, session: &mut Self::Session) -> Result<(), i32>676*1b4853f5SAndroid Build Coastguard Worker fn process_events(&mut self, session: &mut Self::Session) -> Result<(), i32> { 677*1b4853f5SAndroid Build Coastguard Worker let has_event = if let Some(event) = session.backend_session.next_event() { 678*1b4853f5SAndroid Build Coastguard Worker match event { 679*1b4853f5SAndroid Build Coastguard Worker VideoDecoderBackendEvent::InputBufferDone(id) => { 680*1b4853f5SAndroid Build Coastguard Worker let Some(buffer) = session.input_buffers.get_mut(id as usize) else { 681*1b4853f5SAndroid Build Coastguard Worker log::error!("no matching OUTPUT buffer with id {} to process event", id); 682*1b4853f5SAndroid Build Coastguard Worker return Ok(()); 683*1b4853f5SAndroid Build Coastguard Worker }; 684*1b4853f5SAndroid Build Coastguard Worker 685*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.clear_flags(BufferFlags::QUEUED); 686*1b4853f5SAndroid Build Coastguard Worker 687*1b4853f5SAndroid Build Coastguard Worker self.event_queue 688*1b4853f5SAndroid Build Coastguard Worker .send_event(V4l2Event::DequeueBuffer(DequeueBufferEvent::new( 689*1b4853f5SAndroid Build Coastguard Worker session.id, 690*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.clone(), 691*1b4853f5SAndroid Build Coastguard Worker ))); 692*1b4853f5SAndroid Build Coastguard Worker } 693*1b4853f5SAndroid Build Coastguard Worker VideoDecoderBackendEvent::StreamFormatChanged => { 694*1b4853f5SAndroid Build Coastguard Worker let stream_params = session.backend_session.stream_params(); 695*1b4853f5SAndroid Build Coastguard Worker 696*1b4853f5SAndroid Build Coastguard Worker // The crop rectangle is now determined by the stream and cannot be changed. 697*1b4853f5SAndroid Build Coastguard Worker session.crop_rectangle = CropRectangle::FromStream(stream_params.visible_rect); 698*1b4853f5SAndroid Build Coastguard Worker 699*1b4853f5SAndroid Build Coastguard Worker if session.src_change_subscribed { 700*1b4853f5SAndroid Build Coastguard Worker self.event_queue 701*1b4853f5SAndroid Build Coastguard Worker .send_event(V4l2Event::Event(SessionEvent::new( 702*1b4853f5SAndroid Build Coastguard Worker session.id, 703*1b4853f5SAndroid Build Coastguard Worker bindings::v4l2_event { 704*1b4853f5SAndroid Build Coastguard Worker type_: bindings::V4L2_EVENT_SOURCE_CHANGE, 705*1b4853f5SAndroid Build Coastguard Worker u: bindings::v4l2_event__bindgen_ty_1 { 706*1b4853f5SAndroid Build Coastguard Worker src_change: bindings::v4l2_event_src_change { 707*1b4853f5SAndroid Build Coastguard Worker changes: SrcChanges::RESOLUTION.bits(), 708*1b4853f5SAndroid Build Coastguard Worker }, 709*1b4853f5SAndroid Build Coastguard Worker }, 710*1b4853f5SAndroid Build Coastguard Worker // TODO: fill pending, sequence, and timestamp. 711*1b4853f5SAndroid Build Coastguard Worker ..Default::default() 712*1b4853f5SAndroid Build Coastguard Worker }, 713*1b4853f5SAndroid Build Coastguard Worker ))) 714*1b4853f5SAndroid Build Coastguard Worker } 715*1b4853f5SAndroid Build Coastguard Worker } 716*1b4853f5SAndroid Build Coastguard Worker VideoDecoderBackendEvent::FrameCompleted { 717*1b4853f5SAndroid Build Coastguard Worker buffer_id, 718*1b4853f5SAndroid Build Coastguard Worker timestamp, 719*1b4853f5SAndroid Build Coastguard Worker bytes_used, 720*1b4853f5SAndroid Build Coastguard Worker is_last, 721*1b4853f5SAndroid Build Coastguard Worker } => { 722*1b4853f5SAndroid Build Coastguard Worker let Some(buffer) = session.output_buffers.get_mut(buffer_id as usize) else { 723*1b4853f5SAndroid Build Coastguard Worker log::error!( 724*1b4853f5SAndroid Build Coastguard Worker "no matching CAPTURE buffer with id {} to process event", 725*1b4853f5SAndroid Build Coastguard Worker buffer_id 726*1b4853f5SAndroid Build Coastguard Worker ); 727*1b4853f5SAndroid Build Coastguard Worker return Ok(()); 728*1b4853f5SAndroid Build Coastguard Worker }; 729*1b4853f5SAndroid Build Coastguard Worker 730*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.clear_flags(BufferFlags::QUEUED); 731*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.set_flags(BufferFlags::TIMESTAMP_COPY); 732*1b4853f5SAndroid Build Coastguard Worker if is_last { 733*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.set_flags(BufferFlags::LAST); 734*1b4853f5SAndroid Build Coastguard Worker } 735*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.set_sequence(session.sequence_cpt); 736*1b4853f5SAndroid Build Coastguard Worker session.sequence_cpt += 1; 737*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.set_timestamp(timestamp); 738*1b4853f5SAndroid Build Coastguard Worker let first_plane = buffer.v4l2_buffer.get_first_plane_mut(); 739*1b4853f5SAndroid Build Coastguard Worker *first_plane.bytesused = bytes_used.first().copied().unwrap_or(0); 740*1b4853f5SAndroid Build Coastguard Worker self.event_queue 741*1b4853f5SAndroid Build Coastguard Worker .send_event(V4l2Event::DequeueBuffer(DequeueBufferEvent::new( 742*1b4853f5SAndroid Build Coastguard Worker session.id, 743*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.clone(), 744*1b4853f5SAndroid Build Coastguard Worker ))); 745*1b4853f5SAndroid Build Coastguard Worker 746*1b4853f5SAndroid Build Coastguard Worker if is_last && session.eos_subscribed { 747*1b4853f5SAndroid Build Coastguard Worker self.event_queue 748*1b4853f5SAndroid Build Coastguard Worker .send_event(V4l2Event::Event(SessionEvent::new( 749*1b4853f5SAndroid Build Coastguard Worker session.id, 750*1b4853f5SAndroid Build Coastguard Worker bindings::v4l2_event { 751*1b4853f5SAndroid Build Coastguard Worker type_: bindings::V4L2_EVENT_EOS, 752*1b4853f5SAndroid Build Coastguard Worker ..Default::default() 753*1b4853f5SAndroid Build Coastguard Worker }, 754*1b4853f5SAndroid Build Coastguard Worker ))) 755*1b4853f5SAndroid Build Coastguard Worker } 756*1b4853f5SAndroid Build Coastguard Worker } 757*1b4853f5SAndroid Build Coastguard Worker } 758*1b4853f5SAndroid Build Coastguard Worker true 759*1b4853f5SAndroid Build Coastguard Worker } else { 760*1b4853f5SAndroid Build Coastguard Worker false 761*1b4853f5SAndroid Build Coastguard Worker }; 762*1b4853f5SAndroid Build Coastguard Worker 763*1b4853f5SAndroid Build Coastguard Worker if !has_event { 764*1b4853f5SAndroid Build Coastguard Worker log::warn!("process_events called but no event was pending"); 765*1b4853f5SAndroid Build Coastguard Worker } 766*1b4853f5SAndroid Build Coastguard Worker 767*1b4853f5SAndroid Build Coastguard Worker Ok(()) 768*1b4853f5SAndroid Build Coastguard Worker } 769*1b4853f5SAndroid Build Coastguard Worker } 770*1b4853f5SAndroid Build Coastguard Worker 771*1b4853f5SAndroid Build Coastguard Worker impl<B, Q, HM> VirtioMediaIoctlHandler for VideoDecoder<B, Q, HM> 772*1b4853f5SAndroid Build Coastguard Worker where 773*1b4853f5SAndroid Build Coastguard Worker B: VideoDecoderBackend, 774*1b4853f5SAndroid Build Coastguard Worker Q: VirtioMediaEventQueue, 775*1b4853f5SAndroid Build Coastguard Worker HM: VirtioMediaHostMemoryMapper, 776*1b4853f5SAndroid Build Coastguard Worker { 777*1b4853f5SAndroid Build Coastguard Worker type Session = VideoDecoderSession<B::Session>; 778*1b4853f5SAndroid Build Coastguard Worker enum_fmt( &mut self, session: &Self::Session, queue: QueueType, index: u32, ) -> IoctlResult<bindings::v4l2_fmtdesc>779*1b4853f5SAndroid Build Coastguard Worker fn enum_fmt( 780*1b4853f5SAndroid Build Coastguard Worker &mut self, 781*1b4853f5SAndroid Build Coastguard Worker session: &Self::Session, 782*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 783*1b4853f5SAndroid Build Coastguard Worker index: u32, 784*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_fmtdesc> { 785*1b4853f5SAndroid Build Coastguard Worker match queue { 786*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoOutputMplane | QueueType::VideoCaptureMplane => { 787*1b4853f5SAndroid Build Coastguard Worker self.backend.enum_formats(session, queue.direction(), index) 788*1b4853f5SAndroid Build Coastguard Worker } 789*1b4853f5SAndroid Build Coastguard Worker _ => None, 790*1b4853f5SAndroid Build Coastguard Worker } 791*1b4853f5SAndroid Build Coastguard Worker .ok_or(libc::EINVAL) 792*1b4853f5SAndroid Build Coastguard Worker } 793*1b4853f5SAndroid Build Coastguard Worker enum_framesizes( &mut self, _session: &Self::Session, index: u32, pixel_format: u32, ) -> IoctlResult<bindings::v4l2_frmsizeenum>794*1b4853f5SAndroid Build Coastguard Worker fn enum_framesizes( 795*1b4853f5SAndroid Build Coastguard Worker &mut self, 796*1b4853f5SAndroid Build Coastguard Worker _session: &Self::Session, 797*1b4853f5SAndroid Build Coastguard Worker index: u32, 798*1b4853f5SAndroid Build Coastguard Worker pixel_format: u32, 799*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_frmsizeenum> { 800*1b4853f5SAndroid Build Coastguard Worker // We only support step-wise frame sizes. 801*1b4853f5SAndroid Build Coastguard Worker if index != 0 { 802*1b4853f5SAndroid Build Coastguard Worker return Err(libc::EINVAL); 803*1b4853f5SAndroid Build Coastguard Worker } 804*1b4853f5SAndroid Build Coastguard Worker 805*1b4853f5SAndroid Build Coastguard Worker Ok(bindings::v4l2_frmsizeenum { 806*1b4853f5SAndroid Build Coastguard Worker index: 0, 807*1b4853f5SAndroid Build Coastguard Worker pixel_format, 808*1b4853f5SAndroid Build Coastguard Worker type_: bindings::v4l2_frmsizetypes_V4L2_FRMSIZE_TYPE_STEPWISE, 809*1b4853f5SAndroid Build Coastguard Worker __bindgen_anon_1: bindings::v4l2_frmsizeenum__bindgen_ty_1 { 810*1b4853f5SAndroid Build Coastguard Worker stepwise: self.backend.frame_sizes(pixel_format).ok_or(libc::EINVAL)?, 811*1b4853f5SAndroid Build Coastguard Worker }, 812*1b4853f5SAndroid Build Coastguard Worker ..Default::default() 813*1b4853f5SAndroid Build Coastguard Worker }) 814*1b4853f5SAndroid Build Coastguard Worker } 815*1b4853f5SAndroid Build Coastguard Worker g_fmt( &mut self, session: &Self::Session, queue: QueueType, ) -> IoctlResult<bindings::v4l2_format>816*1b4853f5SAndroid Build Coastguard Worker fn g_fmt( 817*1b4853f5SAndroid Build Coastguard Worker &mut self, 818*1b4853f5SAndroid Build Coastguard Worker session: &Self::Session, 819*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 820*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_format> { 821*1b4853f5SAndroid Build Coastguard Worker if !matches!( 822*1b4853f5SAndroid Build Coastguard Worker queue, 823*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoOutputMplane | QueueType::VideoCaptureMplane, 824*1b4853f5SAndroid Build Coastguard Worker ) { 825*1b4853f5SAndroid Build Coastguard Worker return Err(libc::EINVAL); 826*1b4853f5SAndroid Build Coastguard Worker } 827*1b4853f5SAndroid Build Coastguard Worker 828*1b4853f5SAndroid Build Coastguard Worker let format = session.current_format(queue.direction()); 829*1b4853f5SAndroid Build Coastguard Worker let v4l2_format: &bindings::v4l2_format = format.as_ref(); 830*1b4853f5SAndroid Build Coastguard Worker Ok(*v4l2_format) 831*1b4853f5SAndroid Build Coastguard Worker } 832*1b4853f5SAndroid Build Coastguard Worker try_fmt( &mut self, session: &Self::Session, queue: QueueType, format: bindings::v4l2_format, ) -> IoctlResult<bindings::v4l2_format>833*1b4853f5SAndroid Build Coastguard Worker fn try_fmt( 834*1b4853f5SAndroid Build Coastguard Worker &mut self, 835*1b4853f5SAndroid Build Coastguard Worker session: &Self::Session, 836*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 837*1b4853f5SAndroid Build Coastguard Worker format: bindings::v4l2_format, 838*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_format> { 839*1b4853f5SAndroid Build Coastguard Worker let format = self.try_format(session, queue, format)?; 840*1b4853f5SAndroid Build Coastguard Worker 841*1b4853f5SAndroid Build Coastguard Worker let v4l2_format: &bindings::v4l2_format = format.as_ref(); 842*1b4853f5SAndroid Build Coastguard Worker Ok(*v4l2_format) 843*1b4853f5SAndroid Build Coastguard Worker } 844*1b4853f5SAndroid Build Coastguard Worker s_fmt( &mut self, session: &mut Self::Session, queue: QueueType, format: bindings::v4l2_format, ) -> IoctlResult<bindings::v4l2_format>845*1b4853f5SAndroid Build Coastguard Worker fn s_fmt( 846*1b4853f5SAndroid Build Coastguard Worker &mut self, 847*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 848*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 849*1b4853f5SAndroid Build Coastguard Worker format: bindings::v4l2_format, 850*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_format> { 851*1b4853f5SAndroid Build Coastguard Worker let format = self.try_format(session, queue, format)?; 852*1b4853f5SAndroid Build Coastguard Worker 853*1b4853f5SAndroid Build Coastguard Worker self.backend 854*1b4853f5SAndroid Build Coastguard Worker .apply_format(&mut session.backend_session, queue.direction(), &format); 855*1b4853f5SAndroid Build Coastguard Worker 856*1b4853f5SAndroid Build Coastguard Worker // Setting the colorspace information on the `OUTPUT` queue sets it for both queues. 857*1b4853f5SAndroid Build Coastguard Worker if queue.direction() == QueueDirection::Output { 858*1b4853f5SAndroid Build Coastguard Worker session.colorspace.colorspace = format.colorspace(); 859*1b4853f5SAndroid Build Coastguard Worker session.colorspace.xfer_func = format.xfer_func(); 860*1b4853f5SAndroid Build Coastguard Worker session.colorspace.ycbcr_enc = format.ycbcr_enc(); 861*1b4853f5SAndroid Build Coastguard Worker session.colorspace.quantization = format.quantization(); 862*1b4853f5SAndroid Build Coastguard Worker } 863*1b4853f5SAndroid Build Coastguard Worker 864*1b4853f5SAndroid Build Coastguard Worker // If the crop rectangle is still settable, adjust it to the size of the new format. 865*1b4853f5SAndroid Build Coastguard Worker if let CropRectangle::Settable(rect) = &mut session.crop_rectangle { 866*1b4853f5SAndroid Build Coastguard Worker let (width, height) = format.size(); 867*1b4853f5SAndroid Build Coastguard Worker *rect = v4l2r::Rect::new(0, 0, width, height); 868*1b4853f5SAndroid Build Coastguard Worker } 869*1b4853f5SAndroid Build Coastguard Worker 870*1b4853f5SAndroid Build Coastguard Worker let v4l2_format: &bindings::v4l2_format = format.as_ref(); 871*1b4853f5SAndroid Build Coastguard Worker Ok(*v4l2_format) 872*1b4853f5SAndroid Build Coastguard Worker } 873*1b4853f5SAndroid Build Coastguard Worker reqbufs( &mut self, session: &mut Self::Session, queue: QueueType, memory: MemoryType, count: u32, ) -> IoctlResult<bindings::v4l2_requestbuffers>874*1b4853f5SAndroid Build Coastguard Worker fn reqbufs( 875*1b4853f5SAndroid Build Coastguard Worker &mut self, 876*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 877*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 878*1b4853f5SAndroid Build Coastguard Worker memory: MemoryType, 879*1b4853f5SAndroid Build Coastguard Worker count: u32, 880*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_requestbuffers> { 881*1b4853f5SAndroid Build Coastguard Worker if memory != MemoryType::Mmap { 882*1b4853f5SAndroid Build Coastguard Worker return Err(libc::EINVAL); 883*1b4853f5SAndroid Build Coastguard Worker } 884*1b4853f5SAndroid Build Coastguard Worker // TODO: fail if streaming? 885*1b4853f5SAndroid Build Coastguard Worker 886*1b4853f5SAndroid Build Coastguard Worker let (buffers, count) = match queue { 887*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoOutputMplane => (&mut session.input_buffers, count), 888*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoCaptureMplane => ( 889*1b4853f5SAndroid Build Coastguard Worker &mut session.output_buffers, 890*1b4853f5SAndroid Build Coastguard Worker // TODO: no no, we need to reallocate all the buffers if the queue parameters have 891*1b4853f5SAndroid Build Coastguard Worker // changed... especially if the new format won't fit into the old buffers! 892*1b4853f5SAndroid Build Coastguard Worker // count.max(session.backend_session.stream_params().min_output_buffers), 893*1b4853f5SAndroid Build Coastguard Worker count, 894*1b4853f5SAndroid Build Coastguard Worker ), 895*1b4853f5SAndroid Build Coastguard Worker _ => return Err(libc::EINVAL), 896*1b4853f5SAndroid Build Coastguard Worker }; 897*1b4853f5SAndroid Build Coastguard Worker 898*1b4853f5SAndroid Build Coastguard Worker if (count as usize) < buffers.len() { 899*1b4853f5SAndroid Build Coastguard Worker for buffer in &buffers[count as usize..] { 900*1b4853f5SAndroid Build Coastguard Worker if let V4l2PlanesWithBacking::Mmap(planes) = 901*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.planes_with_backing_iter() 902*1b4853f5SAndroid Build Coastguard Worker { 903*1b4853f5SAndroid Build Coastguard Worker for plane in planes { 904*1b4853f5SAndroid Build Coastguard Worker self.host_mapper.unregister_buffer(plane.mem_offset()); 905*1b4853f5SAndroid Build Coastguard Worker } 906*1b4853f5SAndroid Build Coastguard Worker } 907*1b4853f5SAndroid Build Coastguard Worker } 908*1b4853f5SAndroid Build Coastguard Worker buffers.truncate(count as usize); 909*1b4853f5SAndroid Build Coastguard Worker } else { 910*1b4853f5SAndroid Build Coastguard Worker let sizeimage = session 911*1b4853f5SAndroid Build Coastguard Worker .backend_session 912*1b4853f5SAndroid Build Coastguard Worker .current_format(queue.direction()) 913*1b4853f5SAndroid Build Coastguard Worker .planes() 914*1b4853f5SAndroid Build Coastguard Worker .first() 915*1b4853f5SAndroid Build Coastguard Worker .ok_or(libc::EINVAL)? 916*1b4853f5SAndroid Build Coastguard Worker .sizeimage; 917*1b4853f5SAndroid Build Coastguard Worker let new_buffers = (buffers.len()..count as usize) 918*1b4853f5SAndroid Build Coastguard Worker .map(|i| { 919*1b4853f5SAndroid Build Coastguard Worker let mmap_offset = self 920*1b4853f5SAndroid Build Coastguard Worker .host_mapper 921*1b4853f5SAndroid Build Coastguard Worker .register_buffer(None, sizeimage) 922*1b4853f5SAndroid Build Coastguard Worker .map_err(|_| libc::EINVAL)?; 923*1b4853f5SAndroid Build Coastguard Worker 924*1b4853f5SAndroid Build Coastguard Worker VideoDecoderBuffer::new( 925*1b4853f5SAndroid Build Coastguard Worker queue, 926*1b4853f5SAndroid Build Coastguard Worker i as u32, 927*1b4853f5SAndroid Build Coastguard Worker // TODO: only single-planar formats supported. 928*1b4853f5SAndroid Build Coastguard Worker &[sizeimage as usize], 929*1b4853f5SAndroid Build Coastguard Worker mmap_offset, 930*1b4853f5SAndroid Build Coastguard Worker ) 931*1b4853f5SAndroid Build Coastguard Worker .map_err(|e| { 932*1b4853f5SAndroid Build Coastguard Worker // TODO: no, we need to unregister all the buffers and restore the 933*1b4853f5SAndroid Build Coastguard Worker // previous state? 934*1b4853f5SAndroid Build Coastguard Worker self.host_mapper.unregister_buffer(mmap_offset); 935*1b4853f5SAndroid Build Coastguard Worker e 936*1b4853f5SAndroid Build Coastguard Worker }) 937*1b4853f5SAndroid Build Coastguard Worker }) 938*1b4853f5SAndroid Build Coastguard Worker .collect::<IoctlResult<Vec<_>>>()?; 939*1b4853f5SAndroid Build Coastguard Worker buffers.extend(new_buffers); 940*1b4853f5SAndroid Build Coastguard Worker } 941*1b4853f5SAndroid Build Coastguard Worker 942*1b4853f5SAndroid Build Coastguard Worker session 943*1b4853f5SAndroid Build Coastguard Worker .backend_session 944*1b4853f5SAndroid Build Coastguard Worker .buffers_allocated(queue.direction(), count); 945*1b4853f5SAndroid Build Coastguard Worker 946*1b4853f5SAndroid Build Coastguard Worker Ok(bindings::v4l2_requestbuffers { 947*1b4853f5SAndroid Build Coastguard Worker count, 948*1b4853f5SAndroid Build Coastguard Worker type_: queue as u32, 949*1b4853f5SAndroid Build Coastguard Worker memory: memory as u32, 950*1b4853f5SAndroid Build Coastguard Worker capabilities: (BufferCapabilities::SUPPORTS_MMAP 951*1b4853f5SAndroid Build Coastguard Worker | BufferCapabilities::SUPPORTS_ORPHANED_BUFS) 952*1b4853f5SAndroid Build Coastguard Worker .bits(), 953*1b4853f5SAndroid Build Coastguard Worker flags: 0, 954*1b4853f5SAndroid Build Coastguard Worker reserved: Default::default(), 955*1b4853f5SAndroid Build Coastguard Worker }) 956*1b4853f5SAndroid Build Coastguard Worker } 957*1b4853f5SAndroid Build Coastguard Worker querybuf( &mut self, session: &Self::Session, queue: QueueType, index: u32, ) -> IoctlResult<V4l2Buffer>958*1b4853f5SAndroid Build Coastguard Worker fn querybuf( 959*1b4853f5SAndroid Build Coastguard Worker &mut self, 960*1b4853f5SAndroid Build Coastguard Worker session: &Self::Session, 961*1b4853f5SAndroid Build Coastguard Worker queue: QueueType, 962*1b4853f5SAndroid Build Coastguard Worker index: u32, 963*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<V4l2Buffer> { 964*1b4853f5SAndroid Build Coastguard Worker let buffers = match queue { 965*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoOutputMplane => &session.input_buffers, 966*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoCaptureMplane => &session.output_buffers, 967*1b4853f5SAndroid Build Coastguard Worker _ => return Err(libc::EINVAL), 968*1b4853f5SAndroid Build Coastguard Worker }; 969*1b4853f5SAndroid Build Coastguard Worker let buffer = buffers.get(index as usize).ok_or(libc::EINVAL)?; 970*1b4853f5SAndroid Build Coastguard Worker 971*1b4853f5SAndroid Build Coastguard Worker Ok(buffer.v4l2_buffer.clone()) 972*1b4853f5SAndroid Build Coastguard Worker } 973*1b4853f5SAndroid Build Coastguard Worker subscribe_event( &mut self, session: &mut Self::Session, event: v4l2r::ioctl::EventType, _flags: v4l2r::ioctl::SubscribeEventFlags, ) -> IoctlResult<()>974*1b4853f5SAndroid Build Coastguard Worker fn subscribe_event( 975*1b4853f5SAndroid Build Coastguard Worker &mut self, 976*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 977*1b4853f5SAndroid Build Coastguard Worker event: v4l2r::ioctl::EventType, 978*1b4853f5SAndroid Build Coastguard Worker _flags: v4l2r::ioctl::SubscribeEventFlags, 979*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<()> { 980*1b4853f5SAndroid Build Coastguard Worker match event { 981*1b4853f5SAndroid Build Coastguard Worker EventType::SourceChange(0) => { 982*1b4853f5SAndroid Build Coastguard Worker session.src_change_subscribed = true; 983*1b4853f5SAndroid Build Coastguard Worker Ok(()) 984*1b4853f5SAndroid Build Coastguard Worker } 985*1b4853f5SAndroid Build Coastguard Worker EventType::Eos => { 986*1b4853f5SAndroid Build Coastguard Worker session.eos_subscribed = true; 987*1b4853f5SAndroid Build Coastguard Worker Ok(()) 988*1b4853f5SAndroid Build Coastguard Worker } 989*1b4853f5SAndroid Build Coastguard Worker _ => Err(libc::EINVAL), 990*1b4853f5SAndroid Build Coastguard Worker } 991*1b4853f5SAndroid Build Coastguard Worker } 992*1b4853f5SAndroid Build Coastguard Worker 993*1b4853f5SAndroid Build Coastguard Worker // TODO: parse the event and use an enum value to signal ALL or single event? unsubscribe_event( &mut self, session: &mut Self::Session, event: bindings::v4l2_event_subscription, ) -> IoctlResult<()>994*1b4853f5SAndroid Build Coastguard Worker fn unsubscribe_event( 995*1b4853f5SAndroid Build Coastguard Worker &mut self, 996*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 997*1b4853f5SAndroid Build Coastguard Worker event: bindings::v4l2_event_subscription, 998*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<()> { 999*1b4853f5SAndroid Build Coastguard Worker let mut valid = false; 1000*1b4853f5SAndroid Build Coastguard Worker 1001*1b4853f5SAndroid Build Coastguard Worker if event.type_ == 0 || matches!(EventType::try_from(&event), Ok(EventType::SourceChange(0))) 1002*1b4853f5SAndroid Build Coastguard Worker { 1003*1b4853f5SAndroid Build Coastguard Worker session.src_change_subscribed = false; 1004*1b4853f5SAndroid Build Coastguard Worker valid = true; 1005*1b4853f5SAndroid Build Coastguard Worker } 1006*1b4853f5SAndroid Build Coastguard Worker if event.type_ == 0 || matches!(EventType::try_from(&event), Ok(EventType::Eos)) { 1007*1b4853f5SAndroid Build Coastguard Worker session.eos_subscribed = false; 1008*1b4853f5SAndroid Build Coastguard Worker valid = true; 1009*1b4853f5SAndroid Build Coastguard Worker } 1010*1b4853f5SAndroid Build Coastguard Worker 1011*1b4853f5SAndroid Build Coastguard Worker if valid { 1012*1b4853f5SAndroid Build Coastguard Worker Ok(()) 1013*1b4853f5SAndroid Build Coastguard Worker } else { 1014*1b4853f5SAndroid Build Coastguard Worker Err(libc::EINVAL) 1015*1b4853f5SAndroid Build Coastguard Worker } 1016*1b4853f5SAndroid Build Coastguard Worker } 1017*1b4853f5SAndroid Build Coastguard Worker streamon(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()>1018*1b4853f5SAndroid Build Coastguard Worker fn streamon(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()> { 1019*1b4853f5SAndroid Build Coastguard Worker let buffers = match queue { 1020*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoOutputMplane => &session.input_buffers, 1021*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoCaptureMplane => &session.output_buffers, 1022*1b4853f5SAndroid Build Coastguard Worker _ => return Err(libc::EINVAL), 1023*1b4853f5SAndroid Build Coastguard Worker }; 1024*1b4853f5SAndroid Build Coastguard Worker 1025*1b4853f5SAndroid Build Coastguard Worker let already_running = matches!(session.state, VideoDecoderStreamingState::Running); 1026*1b4853f5SAndroid Build Coastguard Worker 1027*1b4853f5SAndroid Build Coastguard Worker // Cannot stream if no buffers allocated. 1028*1b4853f5SAndroid Build Coastguard Worker if buffers.is_empty() { 1029*1b4853f5SAndroid Build Coastguard Worker return Err(libc::EINVAL); 1030*1b4853f5SAndroid Build Coastguard Worker } 1031*1b4853f5SAndroid Build Coastguard Worker 1032*1b4853f5SAndroid Build Coastguard Worker match queue.direction() { 1033*1b4853f5SAndroid Build Coastguard Worker QueueDirection::Output => session.state.input_streamon(), 1034*1b4853f5SAndroid Build Coastguard Worker QueueDirection::Capture => session.state.output_streamon(), 1035*1b4853f5SAndroid Build Coastguard Worker } 1036*1b4853f5SAndroid Build Coastguard Worker 1037*1b4853f5SAndroid Build Coastguard Worker session 1038*1b4853f5SAndroid Build Coastguard Worker .backend_session 1039*1b4853f5SAndroid Build Coastguard Worker .streaming_state(queue.direction(), true); 1040*1b4853f5SAndroid Build Coastguard Worker 1041*1b4853f5SAndroid Build Coastguard Worker if !already_running && matches!(session.state, VideoDecoderStreamingState::Running) { 1042*1b4853f5SAndroid Build Coastguard Worker // TODO: start queueing pending buffers? 1043*1b4853f5SAndroid Build Coastguard Worker } 1044*1b4853f5SAndroid Build Coastguard Worker 1045*1b4853f5SAndroid Build Coastguard Worker session.try_send_pending_output_buffers(); 1046*1b4853f5SAndroid Build Coastguard Worker 1047*1b4853f5SAndroid Build Coastguard Worker Ok(()) 1048*1b4853f5SAndroid Build Coastguard Worker } 1049*1b4853f5SAndroid Build Coastguard Worker streamoff(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()>1050*1b4853f5SAndroid Build Coastguard Worker fn streamoff(&mut self, session: &mut Self::Session, queue: QueueType) -> IoctlResult<()> { 1051*1b4853f5SAndroid Build Coastguard Worker let buffers = match queue.direction() { 1052*1b4853f5SAndroid Build Coastguard Worker QueueDirection::Output => { 1053*1b4853f5SAndroid Build Coastguard Worker // TODO: something to do on the backend? 1054*1b4853f5SAndroid Build Coastguard Worker session.state.input_streamoff(); 1055*1b4853f5SAndroid Build Coastguard Worker 1056*1b4853f5SAndroid Build Coastguard Worker &mut session.input_buffers 1057*1b4853f5SAndroid Build Coastguard Worker } 1058*1b4853f5SAndroid Build Coastguard Worker QueueDirection::Capture => { 1059*1b4853f5SAndroid Build Coastguard Worker session.backend_session.clear_output_buffers()?; 1060*1b4853f5SAndroid Build Coastguard Worker session.state.output_streamoff(); 1061*1b4853f5SAndroid Build Coastguard Worker session.pending_output_buffers.clear(); 1062*1b4853f5SAndroid Build Coastguard Worker 1063*1b4853f5SAndroid Build Coastguard Worker &mut session.output_buffers 1064*1b4853f5SAndroid Build Coastguard Worker } 1065*1b4853f5SAndroid Build Coastguard Worker }; 1066*1b4853f5SAndroid Build Coastguard Worker 1067*1b4853f5SAndroid Build Coastguard Worker for buffer in buffers { 1068*1b4853f5SAndroid Build Coastguard Worker buffer.v4l2_buffer.clear_flags(BufferFlags::QUEUED); 1069*1b4853f5SAndroid Build Coastguard Worker } 1070*1b4853f5SAndroid Build Coastguard Worker 1071*1b4853f5SAndroid Build Coastguard Worker session 1072*1b4853f5SAndroid Build Coastguard Worker .backend_session 1073*1b4853f5SAndroid Build Coastguard Worker .streaming_state(queue.direction(), false); 1074*1b4853f5SAndroid Build Coastguard Worker 1075*1b4853f5SAndroid Build Coastguard Worker Ok(()) 1076*1b4853f5SAndroid Build Coastguard Worker } 1077*1b4853f5SAndroid Build Coastguard Worker g_selection( &mut self, session: &Self::Session, sel_type: SelectionType, sel_target: SelectionTarget, ) -> IoctlResult<bindings::v4l2_rect>1078*1b4853f5SAndroid Build Coastguard Worker fn g_selection( 1079*1b4853f5SAndroid Build Coastguard Worker &mut self, 1080*1b4853f5SAndroid Build Coastguard Worker session: &Self::Session, 1081*1b4853f5SAndroid Build Coastguard Worker sel_type: SelectionType, 1082*1b4853f5SAndroid Build Coastguard Worker sel_target: SelectionTarget, 1083*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_rect> { 1084*1b4853f5SAndroid Build Coastguard Worker match (sel_type, sel_target) { 1085*1b4853f5SAndroid Build Coastguard Worker // Coded resolution of the stream. 1086*1b4853f5SAndroid Build Coastguard Worker (SelectionType::Capture, SelectionTarget::CropBounds) => { 1087*1b4853f5SAndroid Build Coastguard Worker let coded_size = session.backend_session.stream_params().coded_size; 1088*1b4853f5SAndroid Build Coastguard Worker Ok(v4l2r::Rect::new(0, 0, coded_size.0, coded_size.1).into()) 1089*1b4853f5SAndroid Build Coastguard Worker } 1090*1b4853f5SAndroid Build Coastguard Worker // Visible area of CAPTURE buffers. 1091*1b4853f5SAndroid Build Coastguard Worker ( 1092*1b4853f5SAndroid Build Coastguard Worker SelectionType::Capture, 1093*1b4853f5SAndroid Build Coastguard Worker SelectionTarget::Crop 1094*1b4853f5SAndroid Build Coastguard Worker | SelectionTarget::CropDefault 1095*1b4853f5SAndroid Build Coastguard Worker | SelectionTarget::ComposeDefault 1096*1b4853f5SAndroid Build Coastguard Worker | SelectionTarget::ComposeBounds 1097*1b4853f5SAndroid Build Coastguard Worker | SelectionTarget::Compose, 1098*1b4853f5SAndroid Build Coastguard Worker ) => { 1099*1b4853f5SAndroid Build Coastguard Worker //Ok(session.backend_session.stream_params().visible_rect.into()) 1100*1b4853f5SAndroid Build Coastguard Worker Ok((*session.crop_rectangle).into()) 1101*1b4853f5SAndroid Build Coastguard Worker } 1102*1b4853f5SAndroid Build Coastguard Worker _ => Err(libc::EINVAL), 1103*1b4853f5SAndroid Build Coastguard Worker } 1104*1b4853f5SAndroid Build Coastguard Worker } 1105*1b4853f5SAndroid Build Coastguard Worker s_selection( &mut self, session: &mut Self::Session, sel_type: SelectionType, sel_target: SelectionTarget, mut sel_rect: bindings::v4l2_rect, _sel_flags: v4l2r::ioctl::SelectionFlags, ) -> IoctlResult<bindings::v4l2_rect>1106*1b4853f5SAndroid Build Coastguard Worker fn s_selection( 1107*1b4853f5SAndroid Build Coastguard Worker &mut self, 1108*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 1109*1b4853f5SAndroid Build Coastguard Worker sel_type: SelectionType, 1110*1b4853f5SAndroid Build Coastguard Worker sel_target: SelectionTarget, 1111*1b4853f5SAndroid Build Coastguard Worker mut sel_rect: bindings::v4l2_rect, 1112*1b4853f5SAndroid Build Coastguard Worker _sel_flags: v4l2r::ioctl::SelectionFlags, 1113*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_rect> { 1114*1b4853f5SAndroid Build Coastguard Worker if !matches!( 1115*1b4853f5SAndroid Build Coastguard Worker (sel_type, sel_target), 1116*1b4853f5SAndroid Build Coastguard Worker (SelectionType::Capture, SelectionTarget::Compose) 1117*1b4853f5SAndroid Build Coastguard Worker ) { 1118*1b4853f5SAndroid Build Coastguard Worker return Err(libc::EINVAL); 1119*1b4853f5SAndroid Build Coastguard Worker } 1120*1b4853f5SAndroid Build Coastguard Worker 1121*1b4853f5SAndroid Build Coastguard Worker // If the crop rectangle is still settable, allow its modification within the bounds of the 1122*1b4853f5SAndroid Build Coastguard Worker // coded resolution. 1123*1b4853f5SAndroid Build Coastguard Worker if let CropRectangle::Settable(rect) = &mut session.crop_rectangle { 1124*1b4853f5SAndroid Build Coastguard Worker let coded_size = session 1125*1b4853f5SAndroid Build Coastguard Worker .backend_session 1126*1b4853f5SAndroid Build Coastguard Worker .current_format(QueueDirection::Capture) 1127*1b4853f5SAndroid Build Coastguard Worker .size(); 1128*1b4853f5SAndroid Build Coastguard Worker sel_rect.left = std::cmp::max(0, sel_rect.left); 1129*1b4853f5SAndroid Build Coastguard Worker sel_rect.top = std::cmp::max(0, sel_rect.top); 1130*1b4853f5SAndroid Build Coastguard Worker sel_rect.width = std::cmp::min(coded_size.0, sel_rect.width - sel_rect.left as u32); 1131*1b4853f5SAndroid Build Coastguard Worker sel_rect.height = std::cmp::min(coded_size.0, sel_rect.height - sel_rect.top as u32); 1132*1b4853f5SAndroid Build Coastguard Worker 1133*1b4853f5SAndroid Build Coastguard Worker *rect = sel_rect.into(); 1134*1b4853f5SAndroid Build Coastguard Worker } 1135*1b4853f5SAndroid Build Coastguard Worker 1136*1b4853f5SAndroid Build Coastguard Worker self.g_selection(session, sel_type, sel_target) 1137*1b4853f5SAndroid Build Coastguard Worker } 1138*1b4853f5SAndroid Build Coastguard Worker qbuf( &mut self, session: &mut Self::Session, buffer: V4l2Buffer, _guest_regions: Vec<Vec<SgEntry>>, ) -> IoctlResult<V4l2Buffer>1139*1b4853f5SAndroid Build Coastguard Worker fn qbuf( 1140*1b4853f5SAndroid Build Coastguard Worker &mut self, 1141*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 1142*1b4853f5SAndroid Build Coastguard Worker buffer: V4l2Buffer, 1143*1b4853f5SAndroid Build Coastguard Worker _guest_regions: Vec<Vec<SgEntry>>, 1144*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<V4l2Buffer> { 1145*1b4853f5SAndroid Build Coastguard Worker let buffers = match buffer.queue() { 1146*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoOutputMplane => &mut session.input_buffers, 1147*1b4853f5SAndroid Build Coastguard Worker QueueType::VideoCaptureMplane => &mut session.output_buffers, 1148*1b4853f5SAndroid Build Coastguard Worker _ => return Err(libc::EINVAL), 1149*1b4853f5SAndroid Build Coastguard Worker }; 1150*1b4853f5SAndroid Build Coastguard Worker let host_buffer = buffers 1151*1b4853f5SAndroid Build Coastguard Worker .get_mut(buffer.index() as usize) 1152*1b4853f5SAndroid Build Coastguard Worker .ok_or(libc::EINVAL)?; 1153*1b4853f5SAndroid Build Coastguard Worker 1154*1b4853f5SAndroid Build Coastguard Worker // Check that the buffer's memory type corresponds to the one requested during allocation. 1155*1b4853f5SAndroid Build Coastguard Worker if buffer.memory() != host_buffer.v4l2_buffer.memory() { 1156*1b4853f5SAndroid Build Coastguard Worker return Err(libc::EINVAL); 1157*1b4853f5SAndroid Build Coastguard Worker } 1158*1b4853f5SAndroid Build Coastguard Worker 1159*1b4853f5SAndroid Build Coastguard Worker match buffer.queue().direction() { 1160*1b4853f5SAndroid Build Coastguard Worker QueueDirection::Output => { 1161*1b4853f5SAndroid Build Coastguard Worker // Update buffer state 1162*1b4853f5SAndroid Build Coastguard Worker let v4l2_buffer = &mut host_buffer.v4l2_buffer; 1163*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer.set_field(BufferField::None); 1164*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer.set_timestamp(buffer.timestamp()); 1165*1b4853f5SAndroid Build Coastguard Worker let first_plane = buffer.get_first_plane(); 1166*1b4853f5SAndroid Build Coastguard Worker *v4l2_buffer.get_first_plane_mut().bytesused = *first_plane.bytesused; 1167*1b4853f5SAndroid Build Coastguard Worker let host_first_plane = v4l2_buffer.get_first_plane_mut(); 1168*1b4853f5SAndroid Build Coastguard Worker *host_first_plane.length = *first_plane.length; 1169*1b4853f5SAndroid Build Coastguard Worker *host_first_plane.bytesused = *first_plane.bytesused; 1170*1b4853f5SAndroid Build Coastguard Worker if let Some(data_offset) = host_first_plane.data_offset { 1171*1b4853f5SAndroid Build Coastguard Worker *data_offset = first_plane.data_offset.copied().unwrap_or(0); 1172*1b4853f5SAndroid Build Coastguard Worker } 1173*1b4853f5SAndroid Build Coastguard Worker 1174*1b4853f5SAndroid Build Coastguard Worker let bytes_used = { 1175*1b4853f5SAndroid Build Coastguard Worker let first_plane = host_buffer.v4l2_buffer.get_first_plane(); 1176*1b4853f5SAndroid Build Coastguard Worker // V4L2's spec mentions that if `bytes_used == 0` then the whole buffer is considered to be 1177*1b4853f5SAndroid Build Coastguard Worker // used. 1178*1b4853f5SAndroid Build Coastguard Worker if *first_plane.bytesused == 0 { 1179*1b4853f5SAndroid Build Coastguard Worker *first_plane.length 1180*1b4853f5SAndroid Build Coastguard Worker } else { 1181*1b4853f5SAndroid Build Coastguard Worker *first_plane.bytesused 1182*1b4853f5SAndroid Build Coastguard Worker } 1183*1b4853f5SAndroid Build Coastguard Worker }; 1184*1b4853f5SAndroid Build Coastguard Worker 1185*1b4853f5SAndroid Build Coastguard Worker session.backend_session.decode( 1186*1b4853f5SAndroid Build Coastguard Worker &host_buffer.backing, 1187*1b4853f5SAndroid Build Coastguard Worker host_buffer.index(), 1188*1b4853f5SAndroid Build Coastguard Worker host_buffer.timestamp(), 1189*1b4853f5SAndroid Build Coastguard Worker bytes_used, 1190*1b4853f5SAndroid Build Coastguard Worker )?; 1191*1b4853f5SAndroid Build Coastguard Worker 1192*1b4853f5SAndroid Build Coastguard Worker host_buffer.v4l2_buffer.add_flags(BufferFlags::QUEUED); 1193*1b4853f5SAndroid Build Coastguard Worker 1194*1b4853f5SAndroid Build Coastguard Worker Ok(host_buffer.v4l2_buffer.clone()) 1195*1b4853f5SAndroid Build Coastguard Worker } 1196*1b4853f5SAndroid Build Coastguard Worker QueueDirection::Capture => { 1197*1b4853f5SAndroid Build Coastguard Worker // Update buffer state 1198*1b4853f5SAndroid Build Coastguard Worker let v4l2_buffer = &mut host_buffer.v4l2_buffer; 1199*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer.add_flags(BufferFlags::QUEUED); 1200*1b4853f5SAndroid Build Coastguard Worker v4l2_buffer.clear_flags(BufferFlags::LAST); 1201*1b4853f5SAndroid Build Coastguard Worker let host_first_plane = v4l2_buffer.get_first_plane_mut(); 1202*1b4853f5SAndroid Build Coastguard Worker let first_plane = buffer.get_first_plane(); 1203*1b4853f5SAndroid Build Coastguard Worker *host_first_plane.length = *first_plane.length; 1204*1b4853f5SAndroid Build Coastguard Worker *host_first_plane.bytesused = *first_plane.bytesused; 1205*1b4853f5SAndroid Build Coastguard Worker if let Some(data_offset) = host_first_plane.data_offset { 1206*1b4853f5SAndroid Build Coastguard Worker *data_offset = first_plane.data_offset.copied().unwrap_or(0); 1207*1b4853f5SAndroid Build Coastguard Worker } 1208*1b4853f5SAndroid Build Coastguard Worker 1209*1b4853f5SAndroid Build Coastguard Worker let res = v4l2_buffer.clone(); 1210*1b4853f5SAndroid Build Coastguard Worker 1211*1b4853f5SAndroid Build Coastguard Worker session.pending_output_buffers.push(buffer.index()); 1212*1b4853f5SAndroid Build Coastguard Worker session.try_send_pending_output_buffers(); 1213*1b4853f5SAndroid Build Coastguard Worker 1214*1b4853f5SAndroid Build Coastguard Worker Ok(res) 1215*1b4853f5SAndroid Build Coastguard Worker } 1216*1b4853f5SAndroid Build Coastguard Worker } 1217*1b4853f5SAndroid Build Coastguard Worker } 1218*1b4853f5SAndroid Build Coastguard Worker try_decoder_cmd( &mut self, session: &Self::Session, cmd: bindings::v4l2_decoder_cmd, ) -> IoctlResult<bindings::v4l2_decoder_cmd>1219*1b4853f5SAndroid Build Coastguard Worker fn try_decoder_cmd( 1220*1b4853f5SAndroid Build Coastguard Worker &mut self, 1221*1b4853f5SAndroid Build Coastguard Worker session: &Self::Session, 1222*1b4853f5SAndroid Build Coastguard Worker cmd: bindings::v4l2_decoder_cmd, 1223*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_decoder_cmd> { 1224*1b4853f5SAndroid Build Coastguard Worker let cmd = DecoderCmd::try_from(cmd).map_err(|_| libc::EINVAL)?; 1225*1b4853f5SAndroid Build Coastguard Worker session.try_decoder_cmd(cmd).map(Into::into) 1226*1b4853f5SAndroid Build Coastguard Worker } 1227*1b4853f5SAndroid Build Coastguard Worker decoder_cmd( &mut self, session: &mut Self::Session, cmd: bindings::v4l2_decoder_cmd, ) -> IoctlResult<bindings::v4l2_decoder_cmd>1228*1b4853f5SAndroid Build Coastguard Worker fn decoder_cmd( 1229*1b4853f5SAndroid Build Coastguard Worker &mut self, 1230*1b4853f5SAndroid Build Coastguard Worker session: &mut Self::Session, 1231*1b4853f5SAndroid Build Coastguard Worker cmd: bindings::v4l2_decoder_cmd, 1232*1b4853f5SAndroid Build Coastguard Worker ) -> IoctlResult<bindings::v4l2_decoder_cmd> { 1233*1b4853f5SAndroid Build Coastguard Worker let cmd = DecoderCmd::try_from(cmd).map_err(|_| libc::EINVAL)?; 1234*1b4853f5SAndroid Build Coastguard Worker let cmd = session.try_decoder_cmd(cmd)?; 1235*1b4853f5SAndroid Build Coastguard Worker 1236*1b4853f5SAndroid Build Coastguard Worker // The command is valid, apply it. 1237*1b4853f5SAndroid Build Coastguard Worker match cmd { 1238*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Stop { .. } => { 1239*1b4853f5SAndroid Build Coastguard Worker // Switch to stopped state if we aren't already there. 1240*1b4853f5SAndroid Build Coastguard Worker if !matches!(session.state, VideoDecoderStreamingState::Stopped { .. }) { 1241*1b4853f5SAndroid Build Coastguard Worker session.state = VideoDecoderStreamingState::Stopped { 1242*1b4853f5SAndroid Build Coastguard Worker input_streaming: true, 1243*1b4853f5SAndroid Build Coastguard Worker output_streaming: true, 1244*1b4853f5SAndroid Build Coastguard Worker }; 1245*1b4853f5SAndroid Build Coastguard Worker 1246*1b4853f5SAndroid Build Coastguard Worker // Start the `DRAIN` sequence. 1247*1b4853f5SAndroid Build Coastguard Worker session.backend_session.drain()?; 1248*1b4853f5SAndroid Build Coastguard Worker } 1249*1b4853f5SAndroid Build Coastguard Worker } 1250*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Start { .. } => { 1251*1b4853f5SAndroid Build Coastguard Worker // Restart the decoder if we were in the stopped state with both queues streaming. 1252*1b4853f5SAndroid Build Coastguard Worker if let VideoDecoderStreamingState::Stopped { 1253*1b4853f5SAndroid Build Coastguard Worker input_streaming, 1254*1b4853f5SAndroid Build Coastguard Worker output_streaming, 1255*1b4853f5SAndroid Build Coastguard Worker } = &session.state 1256*1b4853f5SAndroid Build Coastguard Worker { 1257*1b4853f5SAndroid Build Coastguard Worker if *input_streaming && *output_streaming { 1258*1b4853f5SAndroid Build Coastguard Worker session.state = VideoDecoderStreamingState::Running; 1259*1b4853f5SAndroid Build Coastguard Worker session 1260*1b4853f5SAndroid Build Coastguard Worker .backend_session 1261*1b4853f5SAndroid Build Coastguard Worker .streaming_state(QueueDirection::Capture, true); 1262*1b4853f5SAndroid Build Coastguard Worker } 1263*1b4853f5SAndroid Build Coastguard Worker session.try_send_pending_output_buffers(); 1264*1b4853f5SAndroid Build Coastguard Worker } 1265*1b4853f5SAndroid Build Coastguard Worker } 1266*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Pause { .. } => { 1267*1b4853f5SAndroid Build Coastguard Worker if matches!(session.state, VideoDecoderStreamingState::Running) { 1268*1b4853f5SAndroid Build Coastguard Worker session.state = VideoDecoderStreamingState::Paused; 1269*1b4853f5SAndroid Build Coastguard Worker } 1270*1b4853f5SAndroid Build Coastguard Worker } 1271*1b4853f5SAndroid Build Coastguard Worker DecoderCmd::Resume => { 1272*1b4853f5SAndroid Build Coastguard Worker if matches!(session.state, VideoDecoderStreamingState::Paused) { 1273*1b4853f5SAndroid Build Coastguard Worker session.state = VideoDecoderStreamingState::Running; 1274*1b4853f5SAndroid Build Coastguard Worker } 1275*1b4853f5SAndroid Build Coastguard Worker } 1276*1b4853f5SAndroid Build Coastguard Worker } 1277*1b4853f5SAndroid Build Coastguard Worker 1278*1b4853f5SAndroid Build Coastguard Worker Ok(cmd.into()) 1279*1b4853f5SAndroid Build Coastguard Worker } 1280*1b4853f5SAndroid Build Coastguard Worker } 1281