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