xref: /aosp_15_r20/external/virtio-media/device/src/devices/video_decoder.rs (revision 1b4853f54772485c5dd4001ae33a7a958bcc97a1)
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