xref: /aosp_15_r20/external/virtio-media/extras/ffmpeg-decoder/src/lib.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 mod event_queue;
6*1b4853f5SAndroid Build Coastguard Worker pub mod ffmpeg;
7*1b4853f5SAndroid Build Coastguard Worker 
8*1b4853f5SAndroid Build Coastguard Worker use std::collections::BTreeMap;
9*1b4853f5SAndroid Build Coastguard Worker use std::collections::VecDeque;
10*1b4853f5SAndroid Build Coastguard Worker use std::io::Read;
11*1b4853f5SAndroid Build Coastguard Worker use std::io::Seek;
12*1b4853f5SAndroid Build Coastguard Worker use std::io::SeekFrom;
13*1b4853f5SAndroid Build Coastguard Worker use std::os::fd::AsFd;
14*1b4853f5SAndroid Build Coastguard Worker use std::os::fd::BorrowedFd;
15*1b4853f5SAndroid Build Coastguard Worker 
16*1b4853f5SAndroid Build Coastguard Worker use enumn::N;
17*1b4853f5SAndroid Build Coastguard Worker use event_queue::EventQueue;
18*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvBuffer;
19*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvBufferSource;
20*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvCodec;
21*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvCodecContext;
22*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvCodecIterator;
23*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvCodecOpenError;
24*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvError;
25*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvFrame;
26*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvFrameError;
27*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvPacket;
28*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AvPixelFormat;
29*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::Dimensions;
30*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::PlaneDescriptor;
31*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::TryReceiveResult;
32*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AV_PIXEL_FORMAT_NV12;
33*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::avcodec::AV_PIXEL_FORMAT_YUV420P;
34*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::swscale::ConversionError;
35*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::swscale::SwConverter;
36*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::swscale::SwConverterCreationError;
37*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::AVERROR_EOF;
38*1b4853f5SAndroid Build Coastguard Worker use ffmpeg::AVERROR_INVALIDDATA;
39*1b4853f5SAndroid Build Coastguard Worker use nix::errno::Errno;
40*1b4853f5SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
41*1b4853f5SAndroid Build Coastguard Worker use virtio_media::devices::video_decoder::StreamParams;
42*1b4853f5SAndroid Build Coastguard Worker use virtio_media::devices::video_decoder::VideoDecoderBackend;
43*1b4853f5SAndroid Build Coastguard Worker use virtio_media::devices::video_decoder::VideoDecoderBackendEvent;
44*1b4853f5SAndroid Build Coastguard Worker use virtio_media::devices::video_decoder::VideoDecoderBackendSession;
45*1b4853f5SAndroid Build Coastguard Worker use virtio_media::devices::video_decoder::VideoDecoderBufferBacking;
46*1b4853f5SAndroid Build Coastguard Worker use virtio_media::devices::video_decoder::VideoDecoderSession;
47*1b4853f5SAndroid Build Coastguard Worker use virtio_media::ioctl::IoctlResult;
48*1b4853f5SAndroid Build Coastguard Worker use virtio_media::memfd::MemFdBuffer;
49*1b4853f5SAndroid Build Coastguard Worker use virtio_media::memfd::MemFdMapping;
50*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r;
51*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r::bindings;
52*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r::ioctl::V4l2MplaneFormat;
53*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r::PixelFormat;
54*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r::QueueClass;
55*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r::QueueDirection;
56*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r::QueueType;
57*1b4853f5SAndroid Build Coastguard Worker use virtio_media::v4l2r::Rect;
58*1b4853f5SAndroid Build Coastguard Worker 
59*1b4853f5SAndroid Build Coastguard Worker use crate::ffmpeg::AV_CODEC_CAP_DR1;
60*1b4853f5SAndroid Build Coastguard Worker 
61*1b4853f5SAndroid Build Coastguard Worker type BufferPlanesFmt = [bindings::v4l2_plane_pix_format; bindings::VIDEO_MAX_PLANES as usize];
62*1b4853f5SAndroid Build Coastguard Worker 
63*1b4853f5SAndroid Build Coastguard Worker impl AvBufferSource for MemFdMapping {
as_ptr(&self) -> *const u864*1b4853f5SAndroid Build Coastguard Worker     fn as_ptr(&self) -> *const u8 {
65*1b4853f5SAndroid Build Coastguard Worker         self.as_ref().as_ptr()
66*1b4853f5SAndroid Build Coastguard Worker     }
67*1b4853f5SAndroid Build Coastguard Worker 
as_mut_ptr(&mut self) -> *mut u868*1b4853f5SAndroid Build Coastguard Worker     fn as_mut_ptr(&mut self) -> *mut u8 {
69*1b4853f5SAndroid Build Coastguard Worker         self.as_mut().as_mut_ptr()
70*1b4853f5SAndroid Build Coastguard Worker     }
71*1b4853f5SAndroid Build Coastguard Worker 
len(&self) -> usize72*1b4853f5SAndroid Build Coastguard Worker     fn len(&self) -> usize {
73*1b4853f5SAndroid Build Coastguard Worker         self.size()
74*1b4853f5SAndroid Build Coastguard Worker     }
75*1b4853f5SAndroid Build Coastguard Worker }
76*1b4853f5SAndroid Build Coastguard Worker 
77*1b4853f5SAndroid Build Coastguard Worker pub struct FfmpegDecoderBuffer {
78*1b4853f5SAndroid Build Coastguard Worker     // Plane backing memory, for MMAP buffers only.
79*1b4853f5SAndroid Build Coastguard Worker     fds: Vec<MemFdBuffer>,
80*1b4853f5SAndroid Build Coastguard Worker }
81*1b4853f5SAndroid Build Coastguard Worker 
82*1b4853f5SAndroid Build Coastguard Worker // TODO: technically this is a Mmap backing? For other buffer types we provide the backing
83*1b4853f5SAndroid Build Coastguard Worker // externally...
84*1b4853f5SAndroid Build Coastguard Worker impl VideoDecoderBufferBacking for FfmpegDecoderBuffer {
new(_queue: QueueType, _index: u32, sizes: &[usize]) -> IoctlResult<Self> where Self: Sized,85*1b4853f5SAndroid Build Coastguard Worker     fn new(_queue: QueueType, _index: u32, sizes: &[usize]) -> IoctlResult<Self>
86*1b4853f5SAndroid Build Coastguard Worker     where
87*1b4853f5SAndroid Build Coastguard Worker         Self: Sized,
88*1b4853f5SAndroid Build Coastguard Worker     {
89*1b4853f5SAndroid Build Coastguard Worker         let fds = sizes
90*1b4853f5SAndroid Build Coastguard Worker             .iter()
91*1b4853f5SAndroid Build Coastguard Worker             .map(|size| MemFdBuffer::new(*size as u64))
92*1b4853f5SAndroid Build Coastguard Worker             .collect::<Result<_, _>>()
93*1b4853f5SAndroid Build Coastguard Worker             .map_err(|_| libc::ENOMEM)?;
94*1b4853f5SAndroid Build Coastguard Worker 
95*1b4853f5SAndroid Build Coastguard Worker         Ok(Self { fds })
96*1b4853f5SAndroid Build Coastguard Worker     }
97*1b4853f5SAndroid Build Coastguard Worker 
fd_for_plane(&self, plane_idx: usize) -> Option<BorrowedFd>98*1b4853f5SAndroid Build Coastguard Worker     fn fd_for_plane(&self, plane_idx: usize) -> Option<BorrowedFd> {
99*1b4853f5SAndroid Build Coastguard Worker         self.fds.get(plane_idx).map(|memfd| memfd.as_file().as_fd())
100*1b4853f5SAndroid Build Coastguard Worker     }
101*1b4853f5SAndroid Build Coastguard Worker }
102*1b4853f5SAndroid Build Coastguard Worker 
103*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, Default, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, N)]
104*1b4853f5SAndroid Build Coastguard Worker #[repr(u32)]
105*1b4853f5SAndroid Build Coastguard Worker pub enum OutputFormat {
106*1b4853f5SAndroid Build Coastguard Worker     #[default]
107*1b4853f5SAndroid Build Coastguard Worker     H264 = PixelFormat::from_fourcc(b"H264").to_u32(),
108*1b4853f5SAndroid Build Coastguard Worker     VP8 = PixelFormat::from_fourcc(b"VP80").to_u32(),
109*1b4853f5SAndroid Build Coastguard Worker     VP9 = PixelFormat::from_fourcc(b"VP90").to_u32(),
110*1b4853f5SAndroid Build Coastguard Worker     HEVC = PixelFormat::from_fourcc(b"HEVC").to_u32(),
111*1b4853f5SAndroid Build Coastguard Worker }
112*1b4853f5SAndroid Build Coastguard Worker 
113*1b4853f5SAndroid Build Coastguard Worker impl OutputFormat {
into_v4l2_pix_format(self, coded_size: (u32, u32)) -> bindings::v4l2_pix_format_mplane114*1b4853f5SAndroid Build Coastguard Worker     fn into_v4l2_pix_format(self, coded_size: (u32, u32)) -> bindings::v4l2_pix_format_mplane {
115*1b4853f5SAndroid Build Coastguard Worker         // TODO: use `coded_size` to infer a reasonable size?
116*1b4853f5SAndroid Build Coastguard Worker         const INPUT_SIZEIMAGE: u32 = 1024 * 1024;
117*1b4853f5SAndroid Build Coastguard Worker 
118*1b4853f5SAndroid Build Coastguard Worker         let mut plane_fmt: BufferPlanesFmt = Default::default();
119*1b4853f5SAndroid Build Coastguard Worker         plane_fmt[0] = bindings::v4l2_plane_pix_format {
120*1b4853f5SAndroid Build Coastguard Worker             bytesperline: 0,
121*1b4853f5SAndroid Build Coastguard Worker             sizeimage: INPUT_SIZEIMAGE,
122*1b4853f5SAndroid Build Coastguard Worker             reserved: Default::default(),
123*1b4853f5SAndroid Build Coastguard Worker         };
124*1b4853f5SAndroid Build Coastguard Worker 
125*1b4853f5SAndroid Build Coastguard Worker         bindings::v4l2_pix_format_mplane {
126*1b4853f5SAndroid Build Coastguard Worker             width: coded_size.0,
127*1b4853f5SAndroid Build Coastguard Worker             height: coded_size.1,
128*1b4853f5SAndroid Build Coastguard Worker             pixelformat: self as u32,
129*1b4853f5SAndroid Build Coastguard Worker             plane_fmt,
130*1b4853f5SAndroid Build Coastguard Worker             num_planes: 1,
131*1b4853f5SAndroid Build Coastguard Worker             ..format_filler()
132*1b4853f5SAndroid Build Coastguard Worker         }
133*1b4853f5SAndroid Build Coastguard Worker     }
134*1b4853f5SAndroid Build Coastguard Worker }
135*1b4853f5SAndroid Build Coastguard Worker 
136*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Clone, Copy, N)]
137*1b4853f5SAndroid Build Coastguard Worker #[repr(u32)]
138*1b4853f5SAndroid Build Coastguard Worker pub enum CaptureFormat {
139*1b4853f5SAndroid Build Coastguard Worker     NV12 = PixelFormat::from_fourcc(b"NV12").to_u32(),
140*1b4853f5SAndroid Build Coastguard Worker }
141*1b4853f5SAndroid Build Coastguard Worker 
142*1b4853f5SAndroid Build Coastguard Worker impl From<CaptureFormat> for AvPixelFormat {
from(format: CaptureFormat) -> Self143*1b4853f5SAndroid Build Coastguard Worker     fn from(format: CaptureFormat) -> Self {
144*1b4853f5SAndroid Build Coastguard Worker         AvPixelFormat(match format {
145*1b4853f5SAndroid Build Coastguard Worker             CaptureFormat::NV12 => AV_PIXEL_FORMAT_NV12.into(),
146*1b4853f5SAndroid Build Coastguard Worker         })
147*1b4853f5SAndroid Build Coastguard Worker     }
148*1b4853f5SAndroid Build Coastguard Worker }
149*1b4853f5SAndroid Build Coastguard Worker 
150*1b4853f5SAndroid Build Coastguard Worker impl CaptureFormat {
into_v4l2_pix_format(self, coded_size: (u32, u32)) -> bindings::v4l2_pix_format_mplane151*1b4853f5SAndroid Build Coastguard Worker     fn into_v4l2_pix_format(self, coded_size: (u32, u32)) -> bindings::v4l2_pix_format_mplane {
152*1b4853f5SAndroid Build Coastguard Worker         let mut plane_fmt: BufferPlanesFmt = Default::default();
153*1b4853f5SAndroid Build Coastguard Worker         let av_format = AvPixelFormat::from(self);
154*1b4853f5SAndroid Build Coastguard Worker 
155*1b4853f5SAndroid Build Coastguard Worker         let num_planes = match self {
156*1b4853f5SAndroid Build Coastguard Worker             CaptureFormat::NV12 => {
157*1b4853f5SAndroid Build Coastguard Worker                 let plane = &mut plane_fmt[0];
158*1b4853f5SAndroid Build Coastguard Worker                 let line_size = av_format.line_size(coded_size.0, 0) as u32;
159*1b4853f5SAndroid Build Coastguard Worker                 plane.bytesperline = line_size;
160*1b4853f5SAndroid Build Coastguard Worker                 plane.sizeimage = av_format
161*1b4853f5SAndroid Build Coastguard Worker                     .plane_sizes([line_size, line_size], coded_size.1)
162*1b4853f5SAndroid Build Coastguard Worker                     .into_iter()
163*1b4853f5SAndroid Build Coastguard Worker                     .sum::<usize>() as u32;
164*1b4853f5SAndroid Build Coastguard Worker                 1
165*1b4853f5SAndroid Build Coastguard Worker             }
166*1b4853f5SAndroid Build Coastguard Worker         };
167*1b4853f5SAndroid Build Coastguard Worker 
168*1b4853f5SAndroid Build Coastguard Worker         bindings::v4l2_pix_format_mplane {
169*1b4853f5SAndroid Build Coastguard Worker             width: coded_size.0,
170*1b4853f5SAndroid Build Coastguard Worker             height: coded_size.1,
171*1b4853f5SAndroid Build Coastguard Worker             pixelformat: self as u32,
172*1b4853f5SAndroid Build Coastguard Worker             plane_fmt,
173*1b4853f5SAndroid Build Coastguard Worker             num_planes,
174*1b4853f5SAndroid Build Coastguard Worker             ..format_filler()
175*1b4853f5SAndroid Build Coastguard Worker         }
176*1b4853f5SAndroid Build Coastguard Worker     }
177*1b4853f5SAndroid Build Coastguard Worker }
178*1b4853f5SAndroid Build Coastguard Worker 
179*1b4853f5SAndroid Build Coastguard Worker enum FfmpegDecoderJob {
180*1b4853f5SAndroid Build Coastguard Worker     Decode {
181*1b4853f5SAndroid Build Coastguard Worker         /// Ffmpeg packet containing the input data.
182*1b4853f5SAndroid Build Coastguard Worker         ///
183*1b4853f5SAndroid Build Coastguard Worker         /// TODO: we can probably avoid the copy by keeping the input, mapping it, and using the
184*1b4853f5SAndroid Build Coastguard Worker         /// mapping as the source of the AvPacket?
185*1b4853f5SAndroid Build Coastguard Worker         packet: AvPacket<'static>,
186*1b4853f5SAndroid Build Coastguard Worker         /// Index of the input buffer from which the input was received.
187*1b4853f5SAndroid Build Coastguard Worker         input_index: u32,
188*1b4853f5SAndroid Build Coastguard Worker     },
189*1b4853f5SAndroid Build Coastguard Worker     Drain,
190*1b4853f5SAndroid Build Coastguard Worker }
191*1b4853f5SAndroid Build Coastguard Worker 
192*1b4853f5SAndroid Build Coastguard Worker /// State for a session that is actively decoding.
193*1b4853f5SAndroid Build Coastguard Worker struct DecodingContext {
194*1b4853f5SAndroid Build Coastguard Worker     /// FIFO of input buffers waiting to be submitted.
195*1b4853f5SAndroid Build Coastguard Worker     jobs: VecDeque<FfmpegDecoderJob>,
196*1b4853f5SAndroid Build Coastguard Worker     /// Decoder context, dependent on the input format.
197*1b4853f5SAndroid Build Coastguard Worker     av_context: AvCodecContext,
198*1b4853f5SAndroid Build Coastguard Worker     /// Converter from the current AVCodec output format to the format expected by the client.
199*1b4853f5SAndroid Build Coastguard Worker     converter: SwConverter,
200*1b4853f5SAndroid Build Coastguard Worker     /// Set when
201*1b4853f5SAndroid Build Coastguard Worker     accepting_output_buffers: bool,
202*1b4853f5SAndroid Build Coastguard Worker     /// Latest `AvFrame` received from ffmpeg.
203*1b4853f5SAndroid Build Coastguard Worker     avframe: Option<AvFrame>,
204*1b4853f5SAndroid Build Coastguard Worker     /// Whether the context is currently draining.
205*1b4853f5SAndroid Build Coastguard Worker     drain_state: DrainState,
206*1b4853f5SAndroid Build Coastguard Worker }
207*1b4853f5SAndroid Build Coastguard Worker 
208*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
209*1b4853f5SAndroid Build Coastguard Worker pub enum NewDecodingContextError {
210*1b4853f5SAndroid Build Coastguard Worker     #[error("cannot create decoder: {0}")]
211*1b4853f5SAndroid Build Coastguard Worker     DecoderCreation(#[from] AvCodecOpenError),
212*1b4853f5SAndroid Build Coastguard Worker     #[error("cannot create sw decoder: {0}")]
213*1b4853f5SAndroid Build Coastguard Worker     SwConverter(#[from] SwConverterCreationError),
214*1b4853f5SAndroid Build Coastguard Worker }
215*1b4853f5SAndroid Build Coastguard Worker 
216*1b4853f5SAndroid Build Coastguard Worker impl DecodingContext {
217*1b4853f5SAndroid Build Coastguard Worker     /// Build a new decoding context for `codec`.
new( codec: AvCodec, output_format: CaptureFormat, coded_size: (u32, u32), ) -> Result<Self, NewDecodingContextError>218*1b4853f5SAndroid Build Coastguard Worker     fn new(
219*1b4853f5SAndroid Build Coastguard Worker         codec: AvCodec,
220*1b4853f5SAndroid Build Coastguard Worker         output_format: CaptureFormat,
221*1b4853f5SAndroid Build Coastguard Worker         coded_size: (u32, u32),
222*1b4853f5SAndroid Build Coastguard Worker     ) -> Result<Self, NewDecodingContextError> {
223*1b4853f5SAndroid Build Coastguard Worker         let av_context = codec.build_decoder().and_then(|b| {
224*1b4853f5SAndroid Build Coastguard Worker             b.set_initial_format(coded_size, AV_PIXEL_FORMAT_YUV420P);
225*1b4853f5SAndroid Build Coastguard Worker             b.build()
226*1b4853f5SAndroid Build Coastguard Worker         })?;
227*1b4853f5SAndroid Build Coastguard Worker 
228*1b4853f5SAndroid Build Coastguard Worker         let converter = Self::create_converter_from_context(&av_context, output_format)?;
229*1b4853f5SAndroid Build Coastguard Worker 
230*1b4853f5SAndroid Build Coastguard Worker         Ok(DecodingContext {
231*1b4853f5SAndroid Build Coastguard Worker             jobs: Default::default(),
232*1b4853f5SAndroid Build Coastguard Worker             av_context,
233*1b4853f5SAndroid Build Coastguard Worker             // We accept CAPTURE buffers tentatively, as the client might know the stream format.
234*1b4853f5SAndroid Build Coastguard Worker             accepting_output_buffers: true,
235*1b4853f5SAndroid Build Coastguard Worker             converter,
236*1b4853f5SAndroid Build Coastguard Worker             avframe: None,
237*1b4853f5SAndroid Build Coastguard Worker             drain_state: DrainState::None,
238*1b4853f5SAndroid Build Coastguard Worker         })
239*1b4853f5SAndroid Build Coastguard Worker     }
240*1b4853f5SAndroid Build Coastguard Worker 
create_converter_from_context( av_context: &AvCodecContext, output_format: CaptureFormat, ) -> Result<SwConverter, SwConverterCreationError>241*1b4853f5SAndroid Build Coastguard Worker     fn create_converter_from_context(
242*1b4853f5SAndroid Build Coastguard Worker         av_context: &AvCodecContext,
243*1b4853f5SAndroid Build Coastguard Worker         output_format: CaptureFormat,
244*1b4853f5SAndroid Build Coastguard Worker     ) -> Result<SwConverter, SwConverterCreationError> {
245*1b4853f5SAndroid Build Coastguard Worker         let avcontext = av_context.as_ref();
246*1b4853f5SAndroid Build Coastguard Worker         let dst_pix_fmt: AvPixelFormat = output_format.into();
247*1b4853f5SAndroid Build Coastguard Worker         log::info!(
248*1b4853f5SAndroid Build Coastguard Worker             "creating SW converter from {}x{} {} to {:?}",
249*1b4853f5SAndroid Build Coastguard Worker             avcontext.width,
250*1b4853f5SAndroid Build Coastguard Worker             avcontext.height,
251*1b4853f5SAndroid Build Coastguard Worker             avcontext.pix_fmt,
252*1b4853f5SAndroid Build Coastguard Worker             dst_pix_fmt
253*1b4853f5SAndroid Build Coastguard Worker         );
254*1b4853f5SAndroid Build Coastguard Worker 
255*1b4853f5SAndroid Build Coastguard Worker         SwConverter::new(
256*1b4853f5SAndroid Build Coastguard Worker             avcontext.width as usize,
257*1b4853f5SAndroid Build Coastguard Worker             avcontext.height as usize,
258*1b4853f5SAndroid Build Coastguard Worker             avcontext.pix_fmt,
259*1b4853f5SAndroid Build Coastguard Worker             dst_pix_fmt.0,
260*1b4853f5SAndroid Build Coastguard Worker         )
261*1b4853f5SAndroid Build Coastguard Worker     }
262*1b4853f5SAndroid Build Coastguard Worker 
263*1b4853f5SAndroid Build Coastguard Worker     /// Recreate the frame converter for this context. This should be called whenever the stream
264*1b4853f5SAndroid Build Coastguard Worker     /// format changes.
update_converter( &mut self, output_format: CaptureFormat, ) -> Result<(), SwConverterCreationError>265*1b4853f5SAndroid Build Coastguard Worker     fn update_converter(
266*1b4853f5SAndroid Build Coastguard Worker         &mut self,
267*1b4853f5SAndroid Build Coastguard Worker         output_format: CaptureFormat,
268*1b4853f5SAndroid Build Coastguard Worker     ) -> Result<(), SwConverterCreationError> {
269*1b4853f5SAndroid Build Coastguard Worker         self.converter = Self::create_converter_from_context(&self.av_context, output_format)?;
270*1b4853f5SAndroid Build Coastguard Worker 
271*1b4853f5SAndroid Build Coastguard Worker         Ok(())
272*1b4853f5SAndroid Build Coastguard Worker     }
273*1b4853f5SAndroid Build Coastguard Worker }
274*1b4853f5SAndroid Build Coastguard Worker 
275*1b4853f5SAndroid Build Coastguard Worker /// An output frame ready to be decoded into.
276*1b4853f5SAndroid Build Coastguard Worker struct AvailableOutputFrame {
277*1b4853f5SAndroid Build Coastguard Worker     /// V4L2 buffer index for this frame.
278*1b4853f5SAndroid Build Coastguard Worker     index: u32,
279*1b4853f5SAndroid Build Coastguard Worker     /// CPU mappings for all the planes.
280*1b4853f5SAndroid Build Coastguard Worker     planes: Vec<MemFdMapping>,
281*1b4853f5SAndroid Build Coastguard Worker }
282*1b4853f5SAndroid Build Coastguard Worker 
283*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, PartialEq, Eq)]
284*1b4853f5SAndroid Build Coastguard Worker enum DrainState {
285*1b4853f5SAndroid Build Coastguard Worker     /// No drain at the moment.
286*1b4853f5SAndroid Build Coastguard Worker     None,
287*1b4853f5SAndroid Build Coastguard Worker     /// Drain has started, we are waiting for all input to be processed.
288*1b4853f5SAndroid Build Coastguard Worker     Initiated,
289*1b4853f5SAndroid Build Coastguard Worker     /// Ffmpeg has been flushed, we are waiting for a frame to signal with the LAST flag.
290*1b4853f5SAndroid Build Coastguard Worker     AwaitingFinalFrame,
291*1b4853f5SAndroid Build Coastguard Worker }
292*1b4853f5SAndroid Build Coastguard Worker 
293*1b4853f5SAndroid Build Coastguard Worker pub struct FfmpegDecoderSession {
294*1b4853f5SAndroid Build Coastguard Worker     /// Input format currently exposed to the client. This can be changed until the first buffer is
295*1b4853f5SAndroid Build Coastguard Worker     /// queued on the OUTPUT queue.
296*1b4853f5SAndroid Build Coastguard Worker     input_format: (OutputFormat, AvCodec),
297*1b4853f5SAndroid Build Coastguard Worker     /// Output format currently exposed to the client.
298*1b4853f5SAndroid Build Coastguard Worker     output_format: CaptureFormat,
299*1b4853f5SAndroid Build Coastguard Worker     /// Coded size set for CAPTURE buffers. Can be larger than the one reported in `stream_params`.
300*1b4853f5SAndroid Build Coastguard Worker     coded_size: (u32, u32),
301*1b4853f5SAndroid Build Coastguard Worker     /// TODO: actually we should be able to change the stream's coded size by setting the OUTPUT
302*1b4853f5SAndroid Build Coastguard Worker     /// resolution. This would adjust the CAPTURE resolution too, and trigger a DRC event if the
303*1b4853f5SAndroid Build Coastguard Worker     /// format is not large enough when the next input buffer is submitted.
304*1b4853f5SAndroid Build Coastguard Worker     stream_params: StreamParams,
305*1b4853f5SAndroid Build Coastguard Worker 
306*1b4853f5SAndroid Build Coastguard Worker     /// Initialize once the input codec has been determined.
307*1b4853f5SAndroid Build Coastguard Worker     context: Option<DecodingContext>,
308*1b4853f5SAndroid Build Coastguard Worker 
309*1b4853f5SAndroid Build Coastguard Worker     /// FIFO of output frames we can decode into.
310*1b4853f5SAndroid Build Coastguard Worker     available_output_frames: VecDeque<AvailableOutputFrame>,
311*1b4853f5SAndroid Build Coastguard Worker 
312*1b4853f5SAndroid Build Coastguard Worker     /// FIFO of decoder events waiting to be dequeued.
313*1b4853f5SAndroid Build Coastguard Worker     events: EventQueue<VideoDecoderBackendEvent>,
314*1b4853f5SAndroid Build Coastguard Worker }
315*1b4853f5SAndroid Build Coastguard Worker 
316*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
317*1b4853f5SAndroid Build Coastguard Worker enum TrySendInputError {
318*1b4853f5SAndroid Build Coastguard Worker     #[error("decoder context has not been created yet")]
319*1b4853f5SAndroid Build Coastguard Worker     NoContext,
320*1b4853f5SAndroid Build Coastguard Worker     #[error("error while sending input packet to libavcodec: {0}")]
321*1b4853f5SAndroid Build Coastguard Worker     AvError(#[from] AvError),
322*1b4853f5SAndroid Build Coastguard Worker     #[error("error while queueing input buffer done event: {0}")]
323*1b4853f5SAndroid Build Coastguard Worker     EventQueue(Errno),
324*1b4853f5SAndroid Build Coastguard Worker }
325*1b4853f5SAndroid Build Coastguard Worker 
326*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
327*1b4853f5SAndroid Build Coastguard Worker enum TryReceiveFrameError {
328*1b4853f5SAndroid Build Coastguard Worker     #[error("decoder context has not been created yet")]
329*1b4853f5SAndroid Build Coastguard Worker     // TODO: get the context in a caller method so we can deduplicate? Or better, set the context
330*1b4853f5SAndroid Build Coastguard Worker     // as part of the state of the decoder?
331*1b4853f5SAndroid Build Coastguard Worker     NoContext,
332*1b4853f5SAndroid Build Coastguard Worker     #[error("cannot create AvFrame")]
333*1b4853f5SAndroid Build Coastguard Worker     CannotCreateAvFrame(#[from] AvFrameError),
334*1b4853f5SAndroid Build Coastguard Worker     #[error("decoding error: {0}")]
335*1b4853f5SAndroid Build Coastguard Worker     DecodingError(AvError),
336*1b4853f5SAndroid Build Coastguard Worker     #[error("error while queueing input completed event: {0}")]
337*1b4853f5SAndroid Build Coastguard Worker     EventQueue(Errno),
338*1b4853f5SAndroid Build Coastguard Worker     #[error("error while creating SW converter: {0}")]
339*1b4853f5SAndroid Build Coastguard Worker     SwConverter(#[from] SwConverterCreationError),
340*1b4853f5SAndroid Build Coastguard Worker     #[error("drain operation failed")]
341*1b4853f5SAndroid Build Coastguard Worker     DrainFailed,
342*1b4853f5SAndroid Build Coastguard Worker }
343*1b4853f5SAndroid Build Coastguard Worker 
344*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
345*1b4853f5SAndroid Build Coastguard Worker enum TryOutputFrameError {
346*1b4853f5SAndroid Build Coastguard Worker     #[error("decoder context has not been created yet")]
347*1b4853f5SAndroid Build Coastguard Worker     NoContext,
348*1b4853f5SAndroid Build Coastguard Worker     #[error("error while creating output AvFrame")]
349*1b4853f5SAndroid Build Coastguard Worker     AvFrame(#[from] AvFrameError),
350*1b4853f5SAndroid Build Coastguard Worker     #[error("error while queueing frame decoded event: {0}")]
351*1b4853f5SAndroid Build Coastguard Worker     EventQueue(Errno),
352*1b4853f5SAndroid Build Coastguard Worker     #[error("not enough planes in target frame")]
353*1b4853f5SAndroid Build Coastguard Worker     NotEnoughPlanes,
354*1b4853f5SAndroid Build Coastguard Worker     #[error("error while building AvFrame: {0}")]
355*1b4853f5SAndroid Build Coastguard Worker     CannotBuild(AvFrameError),
356*1b4853f5SAndroid Build Coastguard Worker     #[error("error while converting frame: {0}")]
357*1b4853f5SAndroid Build Coastguard Worker     ConversionError(ConversionError),
358*1b4853f5SAndroid Build Coastguard Worker }
359*1b4853f5SAndroid Build Coastguard Worker 
360*1b4853f5SAndroid Build Coastguard Worker #[derive(Debug, ThisError)]
361*1b4853f5SAndroid Build Coastguard Worker enum TryDecodeError {
362*1b4853f5SAndroid Build Coastguard Worker     #[error("error while sending input: {0}")]
363*1b4853f5SAndroid Build Coastguard Worker     SendInput(#[from] TrySendInputError),
364*1b4853f5SAndroid Build Coastguard Worker     #[error("error while receiving frame: {0}")]
365*1b4853f5SAndroid Build Coastguard Worker     ReceiveFrame(#[from] TryReceiveFrameError),
366*1b4853f5SAndroid Build Coastguard Worker     #[error("error while outputing decoded frame: {0}")]
367*1b4853f5SAndroid Build Coastguard Worker     OutputFrame(#[from] TryOutputFrameError),
368*1b4853f5SAndroid Build Coastguard Worker }
369*1b4853f5SAndroid Build Coastguard Worker 
370*1b4853f5SAndroid Build Coastguard Worker impl FfmpegDecoderSession {
371*1b4853f5SAndroid Build Coastguard Worker     /// Try to run the next input job, if any.
372*1b4853f5SAndroid Build Coastguard Worker     ///
373*1b4853f5SAndroid Build Coastguard Worker     /// Returns `true` if the next job has been submitted, `false` if it could not be, either
374*1b4853f5SAndroid Build Coastguard Worker     /// because all pending work has already been queued or because the codec could not accept more
375*1b4853f5SAndroid Build Coastguard Worker     /// input at the moment.
try_send_input_job(&mut self) -> Result<bool, TrySendInputError>376*1b4853f5SAndroid Build Coastguard Worker     fn try_send_input_job(&mut self) -> Result<bool, TrySendInputError> {
377*1b4853f5SAndroid Build Coastguard Worker         let context = self.context.as_mut().ok_or(TrySendInputError::NoContext)?;
378*1b4853f5SAndroid Build Coastguard Worker 
379*1b4853f5SAndroid Build Coastguard Worker         let next_job = match context.jobs.pop_front() {
380*1b4853f5SAndroid Build Coastguard Worker             None => return Ok(false),
381*1b4853f5SAndroid Build Coastguard Worker             Some(job) => job,
382*1b4853f5SAndroid Build Coastguard Worker         };
383*1b4853f5SAndroid Build Coastguard Worker 
384*1b4853f5SAndroid Build Coastguard Worker         match &next_job {
385*1b4853f5SAndroid Build Coastguard Worker             FfmpegDecoderJob::Decode {
386*1b4853f5SAndroid Build Coastguard Worker                 packet,
387*1b4853f5SAndroid Build Coastguard Worker                 input_index,
388*1b4853f5SAndroid Build Coastguard Worker             } => {
389*1b4853f5SAndroid Build Coastguard Worker                 let input_consumed = match context.av_context.try_send_packet(packet) {
390*1b4853f5SAndroid Build Coastguard Worker                     Ok(res) => Ok(res),
391*1b4853f5SAndroid Build Coastguard Worker                     // This could happen if we attempt to submit data while flushing.
392*1b4853f5SAndroid Build Coastguard Worker                     Err(AvError(AVERROR_EOF)) => Ok(false),
393*1b4853f5SAndroid Build Coastguard Worker                     // If we got invalid data, keep going in hope that we will catch a valid state later.
394*1b4853f5SAndroid Build Coastguard Worker                     Err(AvError(AVERROR_INVALIDDATA)) => {
395*1b4853f5SAndroid Build Coastguard Worker                         log::warn!("try_send_input: invalid data in stream, ignoring...");
396*1b4853f5SAndroid Build Coastguard Worker                         Ok(true)
397*1b4853f5SAndroid Build Coastguard Worker                     }
398*1b4853f5SAndroid Build Coastguard Worker                     Err(e) => Err(TrySendInputError::from(e)),
399*1b4853f5SAndroid Build Coastguard Worker                 }?;
400*1b4853f5SAndroid Build Coastguard Worker 
401*1b4853f5SAndroid Build Coastguard Worker                 // If the input job has been rejected, push it back. Otherwise, signal the input buffer can
402*1b4853f5SAndroid Build Coastguard Worker                 // be reused.
403*1b4853f5SAndroid Build Coastguard Worker                 match input_consumed {
404*1b4853f5SAndroid Build Coastguard Worker                     false => context.jobs.push_front(next_job),
405*1b4853f5SAndroid Build Coastguard Worker                     true => self
406*1b4853f5SAndroid Build Coastguard Worker                         .events
407*1b4853f5SAndroid Build Coastguard Worker                         .queue_event(VideoDecoderBackendEvent::InputBufferDone(*input_index))
408*1b4853f5SAndroid Build Coastguard Worker                         .map_err(TrySendInputError::EventQueue)?,
409*1b4853f5SAndroid Build Coastguard Worker                 }
410*1b4853f5SAndroid Build Coastguard Worker 
411*1b4853f5SAndroid Build Coastguard Worker                 Ok(input_consumed)
412*1b4853f5SAndroid Build Coastguard Worker             }
413*1b4853f5SAndroid Build Coastguard Worker             FfmpegDecoderJob::Drain => {
414*1b4853f5SAndroid Build Coastguard Worker                 log::debug!("drain initiated");
415*1b4853f5SAndroid Build Coastguard Worker                 // Just set the state as draining for now. We will send the actual flush command
416*1b4853f5SAndroid Build Coastguard Worker                 // when `try_receive_frame` returns `TryAgain`. This should probably not be
417*1b4853f5SAndroid Build Coastguard Worker                 // necessary but we sometimes miss the last frame if we send the flush command to
418*1b4853f5SAndroid Build Coastguard Worker                 // libavcodec earlier (which looks like a bug with libavcodec but needs to be
419*1b4853f5SAndroid Build Coastguard Worker                 // confirmed).
420*1b4853f5SAndroid Build Coastguard Worker                 context.drain_state = DrainState::Initiated;
421*1b4853f5SAndroid Build Coastguard Worker                 Ok(true)
422*1b4853f5SAndroid Build Coastguard Worker             }
423*1b4853f5SAndroid Build Coastguard Worker         }
424*1b4853f5SAndroid Build Coastguard Worker     }
425*1b4853f5SAndroid Build Coastguard Worker 
426*1b4853f5SAndroid Build Coastguard Worker     /// Try to receive a frame from the context and return it if it worked.
try_receive_frame(&mut self) -> Result<bool, TryReceiveFrameError>427*1b4853f5SAndroid Build Coastguard Worker     fn try_receive_frame(&mut self) -> Result<bool, TryReceiveFrameError> {
428*1b4853f5SAndroid Build Coastguard Worker         let context = self
429*1b4853f5SAndroid Build Coastguard Worker             .context
430*1b4853f5SAndroid Build Coastguard Worker             .as_mut()
431*1b4853f5SAndroid Build Coastguard Worker             .ok_or(TryReceiveFrameError::NoContext)?;
432*1b4853f5SAndroid Build Coastguard Worker         let mut avframe = match context.avframe {
433*1b4853f5SAndroid Build Coastguard Worker             // We already have a frame waiting. Wait until it is sent to process the next one.
434*1b4853f5SAndroid Build Coastguard Worker             Some(_) => return Ok(false),
435*1b4853f5SAndroid Build Coastguard Worker             None => AvFrame::new()?,
436*1b4853f5SAndroid Build Coastguard Worker         };
437*1b4853f5SAndroid Build Coastguard Worker 
438*1b4853f5SAndroid Build Coastguard Worker         match context.av_context.try_receive_frame(&mut avframe) {
439*1b4853f5SAndroid Build Coastguard Worker             Ok(TryReceiveResult::Received) => {
440*1b4853f5SAndroid Build Coastguard Worker                 // Now check whether the resolution of the stream has changed.
441*1b4853f5SAndroid Build Coastguard Worker                 let new_coded_size = (avframe.width as u32, avframe.height as u32);
442*1b4853f5SAndroid Build Coastguard Worker                 // TODO: incorrect! We need to discard these values.
443*1b4853f5SAndroid Build Coastguard Worker                 let new_visible_rect = v4l2r::Rect::new(
444*1b4853f5SAndroid Build Coastguard Worker                     avframe.crop_left as i32,
445*1b4853f5SAndroid Build Coastguard Worker                     avframe.crop_top as i32,
446*1b4853f5SAndroid Build Coastguard Worker                     (avframe.crop_right - avframe.crop_left) as u32,
447*1b4853f5SAndroid Build Coastguard Worker                     (avframe.crop_bottom - avframe.crop_top) as u32,
448*1b4853f5SAndroid Build Coastguard Worker                 );
449*1b4853f5SAndroid Build Coastguard Worker 
450*1b4853f5SAndroid Build Coastguard Worker                 if new_coded_size != self.stream_params.coded_size
451*1b4853f5SAndroid Build Coastguard Worker                     || new_visible_rect != self.stream_params.visible_rect
452*1b4853f5SAndroid Build Coastguard Worker                 {
453*1b4853f5SAndroid Build Coastguard Worker                     log::info!(
454*1b4853f5SAndroid Build Coastguard Worker                         "new resolution detected in stream: {:?} -> {:?}",
455*1b4853f5SAndroid Build Coastguard Worker                         self.stream_params.coded_size,
456*1b4853f5SAndroid Build Coastguard Worker                         new_coded_size
457*1b4853f5SAndroid Build Coastguard Worker                     );
458*1b4853f5SAndroid Build Coastguard Worker                     self.stream_params.coded_size = new_coded_size;
459*1b4853f5SAndroid Build Coastguard Worker                     self.stream_params.visible_rect = new_visible_rect;
460*1b4853f5SAndroid Build Coastguard Worker                     // Reset adjustable coded size if the new stream cannot fit into the current
461*1b4853f5SAndroid Build Coastguard Worker                     // buffers.
462*1b4853f5SAndroid Build Coastguard Worker                     if new_coded_size.0 > self.coded_size.0 || new_coded_size.1 > self.coded_size.1
463*1b4853f5SAndroid Build Coastguard Worker                     {
464*1b4853f5SAndroid Build Coastguard Worker                         self.coded_size = new_coded_size;
465*1b4853f5SAndroid Build Coastguard Worker                     }
466*1b4853f5SAndroid Build Coastguard Worker 
467*1b4853f5SAndroid Build Coastguard Worker                     context.update_converter(self.output_format)?;
468*1b4853f5SAndroid Build Coastguard Worker 
469*1b4853f5SAndroid Build Coastguard Worker                     // TODO: change decoding state to awaiting buffers and reject output buffers
470*1b4853f5SAndroid Build Coastguard Worker                     // until the format has been confirmed somehow? IOW we need the decoder to
471*1b4853f5SAndroid Build Coastguard Worker                     // confirm it has acknowledged our format change before we can accept new
472*1b4853f5SAndroid Build Coastguard Worker                     // buffers.
473*1b4853f5SAndroid Build Coastguard Worker                     //
474*1b4853f5SAndroid Build Coastguard Worker                     // TODO: 07/23: decoder state, check how the crosvm decoder adapter handles
475*1b4853f5SAndroid Build Coastguard Worker                     // resolution change?
476*1b4853f5SAndroid Build Coastguard Worker 
477*1b4853f5SAndroid Build Coastguard Worker                     self.available_output_frames.clear();
478*1b4853f5SAndroid Build Coastguard Worker                     context.accepting_output_buffers = false;
479*1b4853f5SAndroid Build Coastguard Worker 
480*1b4853f5SAndroid Build Coastguard Worker                     self.events
481*1b4853f5SAndroid Build Coastguard Worker                         .queue_event(VideoDecoderBackendEvent::StreamFormatChanged)
482*1b4853f5SAndroid Build Coastguard Worker                         .map_err(TryReceiveFrameError::EventQueue)?;
483*1b4853f5SAndroid Build Coastguard Worker                 }
484*1b4853f5SAndroid Build Coastguard Worker 
485*1b4853f5SAndroid Build Coastguard Worker                 context.avframe = Some(avframe);
486*1b4853f5SAndroid Build Coastguard Worker 
487*1b4853f5SAndroid Build Coastguard Worker                 Ok(true)
488*1b4853f5SAndroid Build Coastguard Worker             }
489*1b4853f5SAndroid Build Coastguard Worker             Ok(TryReceiveResult::TryAgain) => {
490*1b4853f5SAndroid Build Coastguard Worker                 // Start flushing. `try_receive_frame` will return `FlushCompleted` when the
491*1b4853f5SAndroid Build Coastguard Worker                 // flush is completed. `TryAgain` will not be returned again until the flush is
492*1b4853f5SAndroid Build Coastguard Worker                 // completed.
493*1b4853f5SAndroid Build Coastguard Worker                 if context.drain_state == DrainState::Initiated {
494*1b4853f5SAndroid Build Coastguard Worker                     match context.av_context.flush_decoder() {
495*1b4853f5SAndroid Build Coastguard Worker                         // Call ourselves again so we can process the flush.
496*1b4853f5SAndroid Build Coastguard Worker                         Ok(()) => self.try_receive_frame(),
497*1b4853f5SAndroid Build Coastguard Worker                         Err(_) => {
498*1b4853f5SAndroid Build Coastguard Worker                             context.drain_state = DrainState::None;
499*1b4853f5SAndroid Build Coastguard Worker                             Err(TryReceiveFrameError::DrainFailed)
500*1b4853f5SAndroid Build Coastguard Worker                         }
501*1b4853f5SAndroid Build Coastguard Worker                     }
502*1b4853f5SAndroid Build Coastguard Worker                 } else {
503*1b4853f5SAndroid Build Coastguard Worker                     Ok(false)
504*1b4853f5SAndroid Build Coastguard Worker                 }
505*1b4853f5SAndroid Build Coastguard Worker             }
506*1b4853f5SAndroid Build Coastguard Worker             Ok(TryReceiveResult::FlushCompleted) => {
507*1b4853f5SAndroid Build Coastguard Worker                 if context.drain_state == DrainState::Initiated {
508*1b4853f5SAndroid Build Coastguard Worker                     log::debug!(
509*1b4853f5SAndroid Build Coastguard Worker                         "decoder drain completed ; waiting for frame to send with the LAST flag"
510*1b4853f5SAndroid Build Coastguard Worker                     );
511*1b4853f5SAndroid Build Coastguard Worker                     context.drain_state = DrainState::AwaitingFinalFrame;
512*1b4853f5SAndroid Build Coastguard Worker                     Ok(true)
513*1b4853f5SAndroid Build Coastguard Worker                 } else {
514*1b4853f5SAndroid Build Coastguard Worker                     Ok(false)
515*1b4853f5SAndroid Build Coastguard Worker                 }
516*1b4853f5SAndroid Build Coastguard Worker             }
517*1b4853f5SAndroid Build Coastguard Worker             // If we got invalid data, keep going in hope that we will catch a valid state later.
518*1b4853f5SAndroid Build Coastguard Worker             Err(AvError(AVERROR_INVALIDDATA)) => {
519*1b4853f5SAndroid Build Coastguard Worker                 log::warn!("try_receive_frame: invalid data in stream, ignoring...");
520*1b4853f5SAndroid Build Coastguard Worker                 Ok(true)
521*1b4853f5SAndroid Build Coastguard Worker             }
522*1b4853f5SAndroid Build Coastguard Worker             Err(av_err) => Err(TryReceiveFrameError::DecodingError(av_err)),
523*1b4853f5SAndroid Build Coastguard Worker         }
524*1b4853f5SAndroid Build Coastguard Worker     }
525*1b4853f5SAndroid Build Coastguard Worker 
526*1b4853f5SAndroid Build Coastguard Worker     /// Try to output the currently decoded frame in [`DecodingContext::avframe`] into a client's output
527*1b4853f5SAndroid Build Coastguard Worker     /// buffer.
try_output_frame(&mut self) -> Result<bool, TryOutputFrameError>528*1b4853f5SAndroid Build Coastguard Worker     fn try_output_frame(&mut self) -> Result<bool, TryOutputFrameError> {
529*1b4853f5SAndroid Build Coastguard Worker         let context = self
530*1b4853f5SAndroid Build Coastguard Worker             .context
531*1b4853f5SAndroid Build Coastguard Worker             .as_mut()
532*1b4853f5SAndroid Build Coastguard Worker             .ok_or(TryOutputFrameError::NoContext)?;
533*1b4853f5SAndroid Build Coastguard Worker         let mut output_frame = match self.available_output_frames.pop_front() {
534*1b4853f5SAndroid Build Coastguard Worker             Some(output_frame) => output_frame,
535*1b4853f5SAndroid Build Coastguard Worker             None => return Ok(false),
536*1b4853f5SAndroid Build Coastguard Worker         };
537*1b4853f5SAndroid Build Coastguard Worker 
538*1b4853f5SAndroid Build Coastguard Worker         // Special case: if we are at the end of draining, send an empty frame with the LAST flag
539*1b4853f5SAndroid Build Coastguard Worker         // set.
540*1b4853f5SAndroid Build Coastguard Worker         if context.drain_state == DrainState::AwaitingFinalFrame {
541*1b4853f5SAndroid Build Coastguard Worker             // ... but only if all the pending frames have been outputted.
542*1b4853f5SAndroid Build Coastguard Worker             if context.avframe.is_some() {
543*1b4853f5SAndroid Build Coastguard Worker                 self.available_output_frames.push_front(output_frame);
544*1b4853f5SAndroid Build Coastguard Worker                 return Ok(false);
545*1b4853f5SAndroid Build Coastguard Worker             }
546*1b4853f5SAndroid Build Coastguard Worker 
547*1b4853f5SAndroid Build Coastguard Worker             log::debug!("sending frame with LAST flag to signal end of drain");
548*1b4853f5SAndroid Build Coastguard Worker             context.drain_state = DrainState::None;
549*1b4853f5SAndroid Build Coastguard Worker 
550*1b4853f5SAndroid Build Coastguard Worker             self.events
551*1b4853f5SAndroid Build Coastguard Worker                 .queue_event(VideoDecoderBackendEvent::FrameCompleted {
552*1b4853f5SAndroid Build Coastguard Worker                     buffer_id: output_frame.index,
553*1b4853f5SAndroid Build Coastguard Worker                     timestamp: bindings::timeval {
554*1b4853f5SAndroid Build Coastguard Worker                         tv_sec: 0,
555*1b4853f5SAndroid Build Coastguard Worker                         tv_usec: 0,
556*1b4853f5SAndroid Build Coastguard Worker                     },
557*1b4853f5SAndroid Build Coastguard Worker                     bytes_used: vec![],
558*1b4853f5SAndroid Build Coastguard Worker                     is_last: true,
559*1b4853f5SAndroid Build Coastguard Worker                 })
560*1b4853f5SAndroid Build Coastguard Worker                 .map_err(TryOutputFrameError::EventQueue)?;
561*1b4853f5SAndroid Build Coastguard Worker 
562*1b4853f5SAndroid Build Coastguard Worker             return Ok(true);
563*1b4853f5SAndroid Build Coastguard Worker         }
564*1b4853f5SAndroid Build Coastguard Worker 
565*1b4853f5SAndroid Build Coastguard Worker         let avframe = match context.avframe.take() {
566*1b4853f5SAndroid Build Coastguard Worker             Some(avframe) => avframe,
567*1b4853f5SAndroid Build Coastguard Worker             None => {
568*1b4853f5SAndroid Build Coastguard Worker                 self.available_output_frames.push_front(output_frame);
569*1b4853f5SAndroid Build Coastguard Worker                 return Ok(false);
570*1b4853f5SAndroid Build Coastguard Worker             }
571*1b4853f5SAndroid Build Coastguard Worker         };
572*1b4853f5SAndroid Build Coastguard Worker 
573*1b4853f5SAndroid Build Coastguard Worker         let av_format: AvPixelFormat = self.output_format.into();
574*1b4853f5SAndroid Build Coastguard Worker         let bytes_used = av_format.plane_sizes(
575*1b4853f5SAndroid Build Coastguard Worker             // TODO: this works for NV12, but not for other formats...
576*1b4853f5SAndroid Build Coastguard Worker             [self.coded_size.0, self.coded_size.0],
577*1b4853f5SAndroid Build Coastguard Worker             self.coded_size.1,
578*1b4853f5SAndroid Build Coastguard Worker         );
579*1b4853f5SAndroid Build Coastguard Worker         // Build an AvFrame for the output frame.
580*1b4853f5SAndroid Build Coastguard Worker         // TODO: we need to handle stride, and more complex output frame formats.
581*1b4853f5SAndroid Build Coastguard Worker         let mut dst_avframe = {
582*1b4853f5SAndroid Build Coastguard Worker             let mut builder = AvFrame::builder()?;
583*1b4853f5SAndroid Build Coastguard Worker             builder.set_dimensions(Dimensions {
584*1b4853f5SAndroid Build Coastguard Worker                 width: self.coded_size.0,
585*1b4853f5SAndroid Build Coastguard Worker                 height: self.coded_size.1,
586*1b4853f5SAndroid Build Coastguard Worker             })?;
587*1b4853f5SAndroid Build Coastguard Worker             builder.set_format(av_format)?;
588*1b4853f5SAndroid Build Coastguard Worker 
589*1b4853f5SAndroid Build Coastguard Worker             let planes = [
590*1b4853f5SAndroid Build Coastguard Worker                 PlaneDescriptor {
591*1b4853f5SAndroid Build Coastguard Worker                     buffer_index: 0,
592*1b4853f5SAndroid Build Coastguard Worker                     offset: 0,
593*1b4853f5SAndroid Build Coastguard Worker                     stride: av_format.line_size(self.coded_size.0, 0),
594*1b4853f5SAndroid Build Coastguard Worker                 },
595*1b4853f5SAndroid Build Coastguard Worker                 PlaneDescriptor {
596*1b4853f5SAndroid Build Coastguard Worker                     buffer_index: 0,
597*1b4853f5SAndroid Build Coastguard Worker                     offset: bytes_used[0],
598*1b4853f5SAndroid Build Coastguard Worker                     stride: av_format.line_size(self.coded_size.0, 1),
599*1b4853f5SAndroid Build Coastguard Worker                 },
600*1b4853f5SAndroid Build Coastguard Worker             ];
601*1b4853f5SAndroid Build Coastguard Worker 
602*1b4853f5SAndroid Build Coastguard Worker             let av_buffer = AvBuffer::new(output_frame.planes.remove(0))
603*1b4853f5SAndroid Build Coastguard Worker                 .ok_or(TryOutputFrameError::NotEnoughPlanes)?;
604*1b4853f5SAndroid Build Coastguard Worker             builder
605*1b4853f5SAndroid Build Coastguard Worker                 .build_owned([av_buffer], planes)
606*1b4853f5SAndroid Build Coastguard Worker                 .map_err(TryOutputFrameError::CannotBuild)?
607*1b4853f5SAndroid Build Coastguard Worker         };
608*1b4853f5SAndroid Build Coastguard Worker 
609*1b4853f5SAndroid Build Coastguard Worker         context
610*1b4853f5SAndroid Build Coastguard Worker             .converter
611*1b4853f5SAndroid Build Coastguard Worker             .convert(&avframe, &mut dst_avframe)
612*1b4853f5SAndroid Build Coastguard Worker             .map_err(TryOutputFrameError::ConversionError)?;
613*1b4853f5SAndroid Build Coastguard Worker 
614*1b4853f5SAndroid Build Coastguard Worker         let timestamp = bindings::timeval {
615*1b4853f5SAndroid Build Coastguard Worker             tv_sec: avframe.pts / 1_000_000,
616*1b4853f5SAndroid Build Coastguard Worker             tv_usec: avframe.pts % 1_000_000,
617*1b4853f5SAndroid Build Coastguard Worker         };
618*1b4853f5SAndroid Build Coastguard Worker 
619*1b4853f5SAndroid Build Coastguard Worker         self.events
620*1b4853f5SAndroid Build Coastguard Worker             .queue_event(VideoDecoderBackendEvent::FrameCompleted {
621*1b4853f5SAndroid Build Coastguard Worker                 buffer_id: output_frame.index,
622*1b4853f5SAndroid Build Coastguard Worker                 timestamp,
623*1b4853f5SAndroid Build Coastguard Worker                 bytes_used: vec![bytes_used.iter().sum::<usize>() as u32],
624*1b4853f5SAndroid Build Coastguard Worker                 is_last: false,
625*1b4853f5SAndroid Build Coastguard Worker             })
626*1b4853f5SAndroid Build Coastguard Worker             .map_err(TryOutputFrameError::EventQueue)?;
627*1b4853f5SAndroid Build Coastguard Worker 
628*1b4853f5SAndroid Build Coastguard Worker         Ok(true)
629*1b4853f5SAndroid Build Coastguard Worker     }
630*1b4853f5SAndroid Build Coastguard Worker 
631*1b4853f5SAndroid Build Coastguard Worker     /// Try to make progress with decoding.
try_decode(&mut self) -> Result<(), TryDecodeError>632*1b4853f5SAndroid Build Coastguard Worker     fn try_decode(&mut self) -> Result<(), TryDecodeError> {
633*1b4853f5SAndroid Build Coastguard Worker         if self.context.is_none() {
634*1b4853f5SAndroid Build Coastguard Worker             return Ok(());
635*1b4853f5SAndroid Build Coastguard Worker         }
636*1b4853f5SAndroid Build Coastguard Worker 
637*1b4853f5SAndroid Build Coastguard Worker         while self.try_output_frame()? || self.try_receive_frame()? || self.try_send_input_job()? {}
638*1b4853f5SAndroid Build Coastguard Worker 
639*1b4853f5SAndroid Build Coastguard Worker         Ok(())
640*1b4853f5SAndroid Build Coastguard Worker     }
641*1b4853f5SAndroid Build Coastguard Worker }
642*1b4853f5SAndroid Build Coastguard Worker 
643*1b4853f5SAndroid Build Coastguard Worker impl VideoDecoderBackendSession for FfmpegDecoderSession {
644*1b4853f5SAndroid Build Coastguard Worker     type BufferStorage = FfmpegDecoderBuffer;
645*1b4853f5SAndroid Build Coastguard Worker 
decode( &mut self, input: &Self::BufferStorage, index: u32, timestamp: bindings::timeval, bytes_used: u32, ) -> IoctlResult<()>646*1b4853f5SAndroid Build Coastguard Worker     fn decode(
647*1b4853f5SAndroid Build Coastguard Worker         &mut self,
648*1b4853f5SAndroid Build Coastguard Worker         input: &Self::BufferStorage,
649*1b4853f5SAndroid Build Coastguard Worker         index: u32,
650*1b4853f5SAndroid Build Coastguard Worker         timestamp: bindings::timeval,
651*1b4853f5SAndroid Build Coastguard Worker         bytes_used: u32,
652*1b4853f5SAndroid Build Coastguard Worker     ) -> IoctlResult<()> {
653*1b4853f5SAndroid Build Coastguard Worker         // The input format is decided at the time the first input buffer is queued, so this is
654*1b4853f5SAndroid Build Coastguard Worker         // when we create our context.
655*1b4853f5SAndroid Build Coastguard Worker         // Ensure we are in decoding state, and switch to it if we aren't.
656*1b4853f5SAndroid Build Coastguard Worker         let context = match &mut self.context {
657*1b4853f5SAndroid Build Coastguard Worker             Some(context) => context,
658*1b4853f5SAndroid Build Coastguard Worker             None => {
659*1b4853f5SAndroid Build Coastguard Worker                 let codec = self.input_format.1;
660*1b4853f5SAndroid Build Coastguard Worker 
661*1b4853f5SAndroid Build Coastguard Worker                 let context =
662*1b4853f5SAndroid Build Coastguard Worker                     DecodingContext::new(codec, self.output_format, self.stream_params.coded_size)
663*1b4853f5SAndroid Build Coastguard Worker                         .map_err(|_| libc::ENODEV)?;
664*1b4853f5SAndroid Build Coastguard Worker 
665*1b4853f5SAndroid Build Coastguard Worker                 let avcontext = context.av_context.as_ref();
666*1b4853f5SAndroid Build Coastguard Worker                 log::info!(
667*1b4853f5SAndroid Build Coastguard Worker                     "starting decoding {} at resolution {}x{} (AVContext pix_fmt {}) for output format {:?}",
668*1b4853f5SAndroid Build Coastguard Worker                     codec.name(),
669*1b4853f5SAndroid Build Coastguard Worker                     avcontext.width,
670*1b4853f5SAndroid Build Coastguard Worker                     avcontext.height,
671*1b4853f5SAndroid Build Coastguard Worker                     avcontext.pix_fmt,
672*1b4853f5SAndroid Build Coastguard Worker                     self.output_format
673*1b4853f5SAndroid Build Coastguard Worker                 );
674*1b4853f5SAndroid Build Coastguard Worker 
675*1b4853f5SAndroid Build Coastguard Worker                 self.context.get_or_insert(context)
676*1b4853f5SAndroid Build Coastguard Worker             }
677*1b4853f5SAndroid Build Coastguard Worker         };
678*1b4853f5SAndroid Build Coastguard Worker 
679*1b4853f5SAndroid Build Coastguard Worker         #[allow(clippy::unnecessary_cast)]
680*1b4853f5SAndroid Build Coastguard Worker         let timestamp =
681*1b4853f5SAndroid Build Coastguard Worker             (timestamp.tv_sec as i64).wrapping_mul(1_000_000) + (timestamp.tv_usec as i64);
682*1b4853f5SAndroid Build Coastguard Worker 
683*1b4853f5SAndroid Build Coastguard Worker         let mut input_data = vec![0u8; bytes_used as usize];
684*1b4853f5SAndroid Build Coastguard Worker         let mut f = input.fds.first().ok_or(libc::EINVAL)?.as_file();
685*1b4853f5SAndroid Build Coastguard Worker         f.seek(SeekFrom::Start(0)).map_err(|_| libc::EIO)?;
686*1b4853f5SAndroid Build Coastguard Worker         f.read_exact(&mut input_data).map_err(|_| libc::EIO)?;
687*1b4853f5SAndroid Build Coastguard Worker 
688*1b4853f5SAndroid Build Coastguard Worker         let avbuffer = AvBuffer::new(input_data).ok_or(libc::ENOMEM)?;
689*1b4853f5SAndroid Build Coastguard Worker         let avpacket = AvPacket::new_owned(timestamp, avbuffer);
690*1b4853f5SAndroid Build Coastguard Worker 
691*1b4853f5SAndroid Build Coastguard Worker         context.jobs.push_back(FfmpegDecoderJob::Decode {
692*1b4853f5SAndroid Build Coastguard Worker             packet: avpacket,
693*1b4853f5SAndroid Build Coastguard Worker             input_index: index,
694*1b4853f5SAndroid Build Coastguard Worker         });
695*1b4853f5SAndroid Build Coastguard Worker 
696*1b4853f5SAndroid Build Coastguard Worker         self.try_decode().map_err(|e| {
697*1b4853f5SAndroid Build Coastguard Worker             log::warn!("while decoding: {:#}", e);
698*1b4853f5SAndroid Build Coastguard Worker             libc::EINVAL
699*1b4853f5SAndroid Build Coastguard Worker         })
700*1b4853f5SAndroid Build Coastguard Worker     }
701*1b4853f5SAndroid Build Coastguard Worker 
use_as_output(&mut self, index: u32, backing: &mut Self::BufferStorage) -> IoctlResult<()>702*1b4853f5SAndroid Build Coastguard Worker     fn use_as_output(&mut self, index: u32, backing: &mut Self::BufferStorage) -> IoctlResult<()> {
703*1b4853f5SAndroid Build Coastguard Worker         // Silently ignore buffers if we are not ready to accept them yet.
704*1b4853f5SAndroid Build Coastguard Worker         if !self
705*1b4853f5SAndroid Build Coastguard Worker             .context
706*1b4853f5SAndroid Build Coastguard Worker             .as_ref()
707*1b4853f5SAndroid Build Coastguard Worker             .map(|c| c.accepting_output_buffers)
708*1b4853f5SAndroid Build Coastguard Worker             .unwrap_or(true)
709*1b4853f5SAndroid Build Coastguard Worker         {
710*1b4853f5SAndroid Build Coastguard Worker             return Ok(());
711*1b4853f5SAndroid Build Coastguard Worker         }
712*1b4853f5SAndroid Build Coastguard Worker 
713*1b4853f5SAndroid Build Coastguard Worker         let planes = backing
714*1b4853f5SAndroid Build Coastguard Worker             .fds
715*1b4853f5SAndroid Build Coastguard Worker             .iter()
716*1b4853f5SAndroid Build Coastguard Worker             .map(|fd| fd.mmap())
717*1b4853f5SAndroid Build Coastguard Worker             .collect::<Result<_, _>>()
718*1b4853f5SAndroid Build Coastguard Worker             .map_err(|_| libc::ENOMEM)?;
719*1b4853f5SAndroid Build Coastguard Worker 
720*1b4853f5SAndroid Build Coastguard Worker         self.available_output_frames
721*1b4853f5SAndroid Build Coastguard Worker             .push_back(AvailableOutputFrame { index, planes });
722*1b4853f5SAndroid Build Coastguard Worker 
723*1b4853f5SAndroid Build Coastguard Worker         Ok(())
724*1b4853f5SAndroid Build Coastguard Worker     }
725*1b4853f5SAndroid Build Coastguard Worker 
drain(&mut self) -> IoctlResult<()>726*1b4853f5SAndroid Build Coastguard Worker     fn drain(&mut self) -> IoctlResult<()> {
727*1b4853f5SAndroid Build Coastguard Worker         let context = match &mut self.context {
728*1b4853f5SAndroid Build Coastguard Worker             Some(context) => context,
729*1b4853f5SAndroid Build Coastguard Worker             // If the decoder is not ready, the drain command should succeed but no action shall be
730*1b4853f5SAndroid Build Coastguard Worker             // taken.
731*1b4853f5SAndroid Build Coastguard Worker             None => return Ok(()),
732*1b4853f5SAndroid Build Coastguard Worker         };
733*1b4853f5SAndroid Build Coastguard Worker 
734*1b4853f5SAndroid Build Coastguard Worker         log::debug!("enqueuing drain request");
735*1b4853f5SAndroid Build Coastguard Worker         context.jobs.push_back(FfmpegDecoderJob::Drain);
736*1b4853f5SAndroid Build Coastguard Worker         self.try_decode().map_err(|e| {
737*1b4853f5SAndroid Build Coastguard Worker             log::warn!("while draining: {:#}", e);
738*1b4853f5SAndroid Build Coastguard Worker             libc::EINVAL
739*1b4853f5SAndroid Build Coastguard Worker         })
740*1b4853f5SAndroid Build Coastguard Worker     }
741*1b4853f5SAndroid Build Coastguard Worker 
clear_output_buffers(&mut self) -> IoctlResult<()>742*1b4853f5SAndroid Build Coastguard Worker     fn clear_output_buffers(&mut self) -> IoctlResult<()> {
743*1b4853f5SAndroid Build Coastguard Worker         self.available_output_frames.clear();
744*1b4853f5SAndroid Build Coastguard Worker         self.events
745*1b4853f5SAndroid Build Coastguard Worker             .retain(|event| !matches!(event, VideoDecoderBackendEvent::FrameCompleted { .. }));
746*1b4853f5SAndroid Build Coastguard Worker         // We keep `self.context.avframe` as it is likely a DRC frame waiting for its new buffers.
747*1b4853f5SAndroid Build Coastguard Worker 
748*1b4853f5SAndroid Build Coastguard Worker         Ok(())
749*1b4853f5SAndroid Build Coastguard Worker     }
750*1b4853f5SAndroid Build Coastguard Worker 
next_event(&mut self) -> Option<VideoDecoderBackendEvent>751*1b4853f5SAndroid Build Coastguard Worker     fn next_event(&mut self) -> Option<VideoDecoderBackendEvent> {
752*1b4853f5SAndroid Build Coastguard Worker         self.events.dequeue_event()
753*1b4853f5SAndroid Build Coastguard Worker     }
754*1b4853f5SAndroid Build Coastguard Worker 
poll_fd(&self) -> Option<BorrowedFd>755*1b4853f5SAndroid Build Coastguard Worker     fn poll_fd(&self) -> Option<BorrowedFd> {
756*1b4853f5SAndroid Build Coastguard Worker         Some(self.events.as_fd())
757*1b4853f5SAndroid Build Coastguard Worker     }
758*1b4853f5SAndroid Build Coastguard Worker 
current_format(&self, direction: QueueDirection) -> V4l2MplaneFormat759*1b4853f5SAndroid Build Coastguard Worker     fn current_format(&self, direction: QueueDirection) -> V4l2MplaneFormat {
760*1b4853f5SAndroid Build Coastguard Worker         match direction {
761*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Output => {
762*1b4853f5SAndroid Build Coastguard Worker                 let pix_mp = self
763*1b4853f5SAndroid Build Coastguard Worker                     .input_format
764*1b4853f5SAndroid Build Coastguard Worker                     .0
765*1b4853f5SAndroid Build Coastguard Worker                     .into_v4l2_pix_format(self.stream_params.coded_size);
766*1b4853f5SAndroid Build Coastguard Worker 
767*1b4853f5SAndroid Build Coastguard Worker                 V4l2MplaneFormat::from((direction, pix_mp))
768*1b4853f5SAndroid Build Coastguard Worker             }
769*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Capture => {
770*1b4853f5SAndroid Build Coastguard Worker                 let pix_mp = self.output_format.into_v4l2_pix_format(self.coded_size);
771*1b4853f5SAndroid Build Coastguard Worker 
772*1b4853f5SAndroid Build Coastguard Worker                 V4l2MplaneFormat::from((direction, pix_mp))
773*1b4853f5SAndroid Build Coastguard Worker             }
774*1b4853f5SAndroid Build Coastguard Worker         }
775*1b4853f5SAndroid Build Coastguard Worker     }
776*1b4853f5SAndroid Build Coastguard Worker 
stream_params(&self) -> StreamParams777*1b4853f5SAndroid Build Coastguard Worker     fn stream_params(&self) -> StreamParams {
778*1b4853f5SAndroid Build Coastguard Worker         self.stream_params.clone()
779*1b4853f5SAndroid Build Coastguard Worker     }
780*1b4853f5SAndroid Build Coastguard Worker 
streaming_state(&mut self, direction: QueueDirection, streaming: bool)781*1b4853f5SAndroid Build Coastguard Worker     fn streaming_state(&mut self, direction: QueueDirection, streaming: bool) {
782*1b4853f5SAndroid Build Coastguard Worker         if direction == QueueDirection::Capture && streaming {
783*1b4853f5SAndroid Build Coastguard Worker             if let Some(context) = &mut self.context {
784*1b4853f5SAndroid Build Coastguard Worker                 context.accepting_output_buffers = true;
785*1b4853f5SAndroid Build Coastguard Worker             }
786*1b4853f5SAndroid Build Coastguard Worker         }
787*1b4853f5SAndroid Build Coastguard Worker     }
788*1b4853f5SAndroid Build Coastguard Worker }
789*1b4853f5SAndroid Build Coastguard Worker 
790*1b4853f5SAndroid Build Coastguard Worker pub struct FfmpegDecoder {
791*1b4853f5SAndroid Build Coastguard Worker     codecs: BTreeMap<OutputFormat, AvCodec>,
792*1b4853f5SAndroid Build Coastguard Worker }
793*1b4853f5SAndroid Build Coastguard Worker 
794*1b4853f5SAndroid Build Coastguard Worker impl FfmpegDecoder {
795*1b4853f5SAndroid Build Coastguard Worker     /// Create a new ffmpeg decoder backend instance.
796*1b4853f5SAndroid Build Coastguard Worker     #[allow(clippy::new_without_default)]
new() -> Self797*1b4853f5SAndroid Build Coastguard Worker     pub fn new() -> Self {
798*1b4853f5SAndroid Build Coastguard Worker         // Find all the decoders supported by libav and store them.
799*1b4853f5SAndroid Build Coastguard Worker         let codecs = AvCodecIterator::new()
800*1b4853f5SAndroid Build Coastguard Worker             .filter_map(|codec| {
801*1b4853f5SAndroid Build Coastguard Worker                 if !codec.is_decoder() {
802*1b4853f5SAndroid Build Coastguard Worker                     return None;
803*1b4853f5SAndroid Build Coastguard Worker                 }
804*1b4853f5SAndroid Build Coastguard Worker 
805*1b4853f5SAndroid Build Coastguard Worker                 let codec_name = codec.name();
806*1b4853f5SAndroid Build Coastguard Worker 
807*1b4853f5SAndroid Build Coastguard Worker                 // Only keep processing the decoders we are interested in.
808*1b4853f5SAndroid Build Coastguard Worker                 let format = match codec_name {
809*1b4853f5SAndroid Build Coastguard Worker                     "h264" => OutputFormat::H264,
810*1b4853f5SAndroid Build Coastguard Worker                     "hevc" => OutputFormat::HEVC,
811*1b4853f5SAndroid Build Coastguard Worker                     "vp8" => OutputFormat::VP8,
812*1b4853f5SAndroid Build Coastguard Worker                     "vp9" => OutputFormat::VP9,
813*1b4853f5SAndroid Build Coastguard Worker                     _ => return None,
814*1b4853f5SAndroid Build Coastguard Worker                 };
815*1b4853f5SAndroid Build Coastguard Worker 
816*1b4853f5SAndroid Build Coastguard Worker                 // We require custom buffer allocators, so ignore codecs that are not capable of
817*1b4853f5SAndroid Build Coastguard Worker                 // using them.
818*1b4853f5SAndroid Build Coastguard Worker                 if codec.capabilities() & AV_CODEC_CAP_DR1 == 0 {
819*1b4853f5SAndroid Build Coastguard Worker                     log::info!(
820*1b4853f5SAndroid Build Coastguard Worker                         "Skipping codec {} due to lack of DR1 capability.",
821*1b4853f5SAndroid Build Coastguard Worker                         codec_name
822*1b4853f5SAndroid Build Coastguard Worker                     );
823*1b4853f5SAndroid Build Coastguard Worker                     return None;
824*1b4853f5SAndroid Build Coastguard Worker                 }
825*1b4853f5SAndroid Build Coastguard Worker 
826*1b4853f5SAndroid Build Coastguard Worker                 Some((format, codec))
827*1b4853f5SAndroid Build Coastguard Worker             })
828*1b4853f5SAndroid Build Coastguard Worker             .collect();
829*1b4853f5SAndroid Build Coastguard Worker 
830*1b4853f5SAndroid Build Coastguard Worker         Self { codecs }
831*1b4853f5SAndroid Build Coastguard Worker     }
832*1b4853f5SAndroid Build Coastguard Worker }
833*1b4853f5SAndroid Build Coastguard Worker 
834*1b4853f5SAndroid Build Coastguard Worker const SUPPORTED_OUTPUT_FORMATS: [CaptureFormat; 1] = [CaptureFormat::NV12];
835*1b4853f5SAndroid Build Coastguard Worker 
836*1b4853f5SAndroid Build Coastguard Worker /// Returns a format with its invariant fields filled as expected.
format_filler() -> bindings::v4l2_pix_format_mplane837*1b4853f5SAndroid Build Coastguard Worker fn format_filler() -> bindings::v4l2_pix_format_mplane {
838*1b4853f5SAndroid Build Coastguard Worker     bindings::v4l2_pix_format_mplane {
839*1b4853f5SAndroid Build Coastguard Worker         field: bindings::v4l2_field_V4L2_FIELD_NONE,
840*1b4853f5SAndroid Build Coastguard Worker         flags: 0,
841*1b4853f5SAndroid Build Coastguard Worker         colorspace: bindings::v4l2_colorspace_V4L2_COLORSPACE_DEFAULT,
842*1b4853f5SAndroid Build Coastguard Worker         __bindgen_anon_1: bindings::v4l2_pix_format_mplane__bindgen_ty_1 {
843*1b4853f5SAndroid Build Coastguard Worker             ycbcr_enc: bindings::v4l2_ycbcr_encoding_V4L2_YCBCR_ENC_DEFAULT as u8,
844*1b4853f5SAndroid Build Coastguard Worker         },
845*1b4853f5SAndroid Build Coastguard Worker         quantization: bindings::v4l2_quantization_V4L2_QUANTIZATION_DEFAULT as u8,
846*1b4853f5SAndroid Build Coastguard Worker         xfer_func: bindings::v4l2_xfer_func_V4L2_XFER_FUNC_DEFAULT as u8,
847*1b4853f5SAndroid Build Coastguard Worker         ..Default::default()
848*1b4853f5SAndroid Build Coastguard Worker     }
849*1b4853f5SAndroid Build Coastguard Worker }
850*1b4853f5SAndroid Build Coastguard Worker 
851*1b4853f5SAndroid Build Coastguard Worker impl VideoDecoderBackend for FfmpegDecoder {
852*1b4853f5SAndroid Build Coastguard Worker     type Session = FfmpegDecoderSession;
853*1b4853f5SAndroid Build Coastguard Worker 
new_session(&mut self, _id: u32) -> IoctlResult<Self::Session>854*1b4853f5SAndroid Build Coastguard Worker     fn new_session(&mut self, _id: u32) -> IoctlResult<Self::Session> {
855*1b4853f5SAndroid Build Coastguard Worker         const DEFAULT_CODED_SIZE: (u32, u32) = (320, 240);
856*1b4853f5SAndroid Build Coastguard Worker 
857*1b4853f5SAndroid Build Coastguard Worker         let input_format = self
858*1b4853f5SAndroid Build Coastguard Worker             .codecs
859*1b4853f5SAndroid Build Coastguard Worker             .iter()
860*1b4853f5SAndroid Build Coastguard Worker             .map(|(k, v)| (*k, *v))
861*1b4853f5SAndroid Build Coastguard Worker             .next()
862*1b4853f5SAndroid Build Coastguard Worker             .ok_or(libc::ENODEV)?;
863*1b4853f5SAndroid Build Coastguard Worker 
864*1b4853f5SAndroid Build Coastguard Worker         Ok(FfmpegDecoderSession {
865*1b4853f5SAndroid Build Coastguard Worker             input_format,
866*1b4853f5SAndroid Build Coastguard Worker             output_format: SUPPORTED_OUTPUT_FORMATS
867*1b4853f5SAndroid Build Coastguard Worker                 .iter()
868*1b4853f5SAndroid Build Coastguard Worker                 .copied()
869*1b4853f5SAndroid Build Coastguard Worker                 .next()
870*1b4853f5SAndroid Build Coastguard Worker                 .unwrap_or(CaptureFormat::NV12),
871*1b4853f5SAndroid Build Coastguard Worker             context: None,
872*1b4853f5SAndroid Build Coastguard Worker             coded_size: DEFAULT_CODED_SIZE,
873*1b4853f5SAndroid Build Coastguard Worker             stream_params: StreamParams {
874*1b4853f5SAndroid Build Coastguard Worker                 min_output_buffers: 4,
875*1b4853f5SAndroid Build Coastguard Worker                 coded_size: DEFAULT_CODED_SIZE,
876*1b4853f5SAndroid Build Coastguard Worker                 visible_rect: Rect {
877*1b4853f5SAndroid Build Coastguard Worker                     left: 0,
878*1b4853f5SAndroid Build Coastguard Worker                     top: 0,
879*1b4853f5SAndroid Build Coastguard Worker                     width: DEFAULT_CODED_SIZE.0,
880*1b4853f5SAndroid Build Coastguard Worker                     height: DEFAULT_CODED_SIZE.1,
881*1b4853f5SAndroid Build Coastguard Worker                 },
882*1b4853f5SAndroid Build Coastguard Worker             },
883*1b4853f5SAndroid Build Coastguard Worker             available_output_frames: Default::default(),
884*1b4853f5SAndroid Build Coastguard Worker             events: EventQueue::new().map_err(|_| libc::EIO)?,
885*1b4853f5SAndroid Build Coastguard Worker         })
886*1b4853f5SAndroid Build Coastguard Worker     }
887*1b4853f5SAndroid Build Coastguard Worker 
close_session(&mut self, _session: Self::Session)888*1b4853f5SAndroid Build Coastguard Worker     fn close_session(&mut self, _session: Self::Session) {}
889*1b4853f5SAndroid Build Coastguard Worker 
enum_formats( &self, _session: &VideoDecoderSession<Self::Session>, direction: QueueDirection, index: u32, ) -> Option<bindings::v4l2_fmtdesc>890*1b4853f5SAndroid Build Coastguard Worker     fn enum_formats(
891*1b4853f5SAndroid Build Coastguard Worker         &self,
892*1b4853f5SAndroid Build Coastguard Worker         _session: &VideoDecoderSession<Self::Session>,
893*1b4853f5SAndroid Build Coastguard Worker         direction: QueueDirection,
894*1b4853f5SAndroid Build Coastguard Worker         index: u32,
895*1b4853f5SAndroid Build Coastguard Worker     ) -> Option<bindings::v4l2_fmtdesc> {
896*1b4853f5SAndroid Build Coastguard Worker         let pixelformat = match direction {
897*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Output => self.codecs.iter().map(|f| *f.0).nth(index as usize)? as u32,
898*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Capture => SUPPORTED_OUTPUT_FORMATS
899*1b4853f5SAndroid Build Coastguard Worker                 .iter()
900*1b4853f5SAndroid Build Coastguard Worker                 .copied()
901*1b4853f5SAndroid Build Coastguard Worker                 .nth(index as usize)? as u32,
902*1b4853f5SAndroid Build Coastguard Worker         };
903*1b4853f5SAndroid Build Coastguard Worker 
904*1b4853f5SAndroid Build Coastguard Worker         Some(bindings::v4l2_fmtdesc {
905*1b4853f5SAndroid Build Coastguard Worker             index,
906*1b4853f5SAndroid Build Coastguard Worker             type_: QueueType::from_dir_and_class(direction, QueueClass::VideoMplane) as u32,
907*1b4853f5SAndroid Build Coastguard Worker             pixelformat,
908*1b4853f5SAndroid Build Coastguard Worker             ..Default::default()
909*1b4853f5SAndroid Build Coastguard Worker         })
910*1b4853f5SAndroid Build Coastguard Worker     }
911*1b4853f5SAndroid Build Coastguard Worker 
frame_sizes(&self, pixel_format: u32) -> Option<bindings::v4l2_frmsize_stepwise>912*1b4853f5SAndroid Build Coastguard Worker     fn frame_sizes(&self, pixel_format: u32) -> Option<bindings::v4l2_frmsize_stepwise> {
913*1b4853f5SAndroid Build Coastguard Worker         // Only return a value for valid formats.
914*1b4853f5SAndroid Build Coastguard Worker         let _ = CaptureFormat::n(pixel_format)?;
915*1b4853f5SAndroid Build Coastguard Worker 
916*1b4853f5SAndroid Build Coastguard Worker         Some(bindings::v4l2_frmsize_stepwise {
917*1b4853f5SAndroid Build Coastguard Worker             min_width: 32,
918*1b4853f5SAndroid Build Coastguard Worker             max_width: 4096,
919*1b4853f5SAndroid Build Coastguard Worker             step_width: 1,
920*1b4853f5SAndroid Build Coastguard Worker             min_height: 32,
921*1b4853f5SAndroid Build Coastguard Worker             max_height: 4096,
922*1b4853f5SAndroid Build Coastguard Worker             step_height: 1,
923*1b4853f5SAndroid Build Coastguard Worker         })
924*1b4853f5SAndroid Build Coastguard Worker     }
925*1b4853f5SAndroid Build Coastguard Worker 
adjust_format( &self, session: &Self::Session, direction: QueueDirection, format: V4l2MplaneFormat, ) -> V4l2MplaneFormat926*1b4853f5SAndroid Build Coastguard Worker     fn adjust_format(
927*1b4853f5SAndroid Build Coastguard Worker         &self,
928*1b4853f5SAndroid Build Coastguard Worker         session: &Self::Session,
929*1b4853f5SAndroid Build Coastguard Worker         direction: QueueDirection,
930*1b4853f5SAndroid Build Coastguard Worker         format: V4l2MplaneFormat,
931*1b4853f5SAndroid Build Coastguard Worker     ) -> V4l2MplaneFormat {
932*1b4853f5SAndroid Build Coastguard Worker         // Apply the requested pixel format or fall back to the current one.
933*1b4853f5SAndroid Build Coastguard Worker         let pix_mp = match direction {
934*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Output => {
935*1b4853f5SAndroid Build Coastguard Worker                 let pixelformat = OutputFormat::n(format.pixelformat().to_u32())
936*1b4853f5SAndroid Build Coastguard Worker                     .unwrap_or(session.input_format.0);
937*1b4853f5SAndroid Build Coastguard Worker 
938*1b4853f5SAndroid Build Coastguard Worker                 pixelformat.into_v4l2_pix_format(session.stream_params.coded_size)
939*1b4853f5SAndroid Build Coastguard Worker             }
940*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Capture => {
941*1b4853f5SAndroid Build Coastguard Worker                 let pixelformat = CaptureFormat::n(format.pixelformat().to_u32())
942*1b4853f5SAndroid Build Coastguard Worker                     .unwrap_or(session.output_format);
943*1b4853f5SAndroid Build Coastguard Worker 
944*1b4853f5SAndroid Build Coastguard Worker                 pixelformat.into_v4l2_pix_format(session.coded_size)
945*1b4853f5SAndroid Build Coastguard Worker             }
946*1b4853f5SAndroid Build Coastguard Worker         };
947*1b4853f5SAndroid Build Coastguard Worker 
948*1b4853f5SAndroid Build Coastguard Worker         V4l2MplaneFormat::from((direction, pix_mp))
949*1b4853f5SAndroid Build Coastguard Worker     }
950*1b4853f5SAndroid Build Coastguard Worker 
apply_format( &self, session: &mut Self::Session, direction: QueueDirection, format: &V4l2MplaneFormat, )951*1b4853f5SAndroid Build Coastguard Worker     fn apply_format(
952*1b4853f5SAndroid Build Coastguard Worker         &self,
953*1b4853f5SAndroid Build Coastguard Worker         session: &mut Self::Session,
954*1b4853f5SAndroid Build Coastguard Worker         direction: QueueDirection,
955*1b4853f5SAndroid Build Coastguard Worker         format: &V4l2MplaneFormat,
956*1b4853f5SAndroid Build Coastguard Worker     ) {
957*1b4853f5SAndroid Build Coastguard Worker         match direction {
958*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Output => {
959*1b4853f5SAndroid Build Coastguard Worker                 let format = match OutputFormat::n(format.pixelformat().to_u32()) {
960*1b4853f5SAndroid Build Coastguard Worker                     Some(format) => format,
961*1b4853f5SAndroid Build Coastguard Worker                     None => return,
962*1b4853f5SAndroid Build Coastguard Worker                 };
963*1b4853f5SAndroid Build Coastguard Worker                 let avcodec = match self.codecs.get(&format).copied() {
964*1b4853f5SAndroid Build Coastguard Worker                     Some(codec) => codec,
965*1b4853f5SAndroid Build Coastguard Worker                     None => return,
966*1b4853f5SAndroid Build Coastguard Worker                 };
967*1b4853f5SAndroid Build Coastguard Worker 
968*1b4853f5SAndroid Build Coastguard Worker                 session.input_format = (format, avcodec);
969*1b4853f5SAndroid Build Coastguard Worker             }
970*1b4853f5SAndroid Build Coastguard Worker             QueueDirection::Capture => {
971*1b4853f5SAndroid Build Coastguard Worker                 session.output_format = match CaptureFormat::n(format.pixelformat().to_u32()) {
972*1b4853f5SAndroid Build Coastguard Worker                     Some(format) => format,
973*1b4853f5SAndroid Build Coastguard Worker                     None => return,
974*1b4853f5SAndroid Build Coastguard Worker                 }
975*1b4853f5SAndroid Build Coastguard Worker             }
976*1b4853f5SAndroid Build Coastguard Worker         }
977*1b4853f5SAndroid Build Coastguard Worker     }
978*1b4853f5SAndroid Build Coastguard Worker }
979