xref: /aosp_15_r20/external/crosvm/devices/src/virtio/video/decoder/backend/ffmpeg.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! A ffmpeg-based software decoder backend for crosvm. Since it does not require any particular
6 //! harware, it can provide fake hardware acceleration decoding to any guest and is mostly useful in
7 //! order to work on the virtio-video specification, or to implement guest decoder code from the
8 //! comfort of a workstation.
9 //!
10 //! This backend is supposed to serve as the reference implementation for decoding backends in
11 //! crosvm. As such it is fairly complete and exposes all the features and memory types that crosvm
12 //! support.
13 //!
14 //! The code in this main module provides the actual implementation and is free of unsafe code. Safe
15 //! abstractions over the ffmpeg libraries are provided in sub-modules, one per ffmpeg library we
16 //! want to support.
17 
18 use std::collections::BTreeMap;
19 use std::collections::VecDeque;
20 use std::sync::Arc;
21 use std::sync::Weak;
22 
23 use ::ffmpeg::avcodec::*;
24 use ::ffmpeg::swscale::*;
25 use ::ffmpeg::*;
26 use anyhow::anyhow;
27 use anyhow::Context;
28 use base::error;
29 use base::info;
30 use base::warn;
31 use base::MappedRegion;
32 use base::MemoryMappingArena;
33 use thiserror::Error as ThisError;
34 
35 use crate::virtio::video::decoder::backend::*;
36 use crate::virtio::video::ffmpeg::GuestResourceToAvFrameError;
37 use crate::virtio::video::ffmpeg::MemoryMappingAvBufferSource;
38 use crate::virtio::video::ffmpeg::TryAsAvFrameExt;
39 use crate::virtio::video::format::FormatDesc;
40 use crate::virtio::video::format::FormatRange;
41 use crate::virtio::video::format::FrameFormat;
42 use crate::virtio::video::format::Level;
43 use crate::virtio::video::format::Profile;
44 use crate::virtio::video::resource::BufferHandle;
45 use crate::virtio::video::resource::GuestResource;
46 use crate::virtio::video::resource::GuestResourceHandle;
47 use crate::virtio::video::utils::EventQueue;
48 use crate::virtio::video::utils::OutputQueue;
49 use crate::virtio::video::utils::SyncEventQueue;
50 
51 /// Structure maintaining a mapping for an encoded input buffer that can be used as a libavcodec
52 /// buffer source. It also sends a `NotifyEndOfBitstreamBuffer` event when dropped.
53 struct InputBuffer {
54     /// Memory mapping to the encoded input data.
55     mapping: MemoryMappingArena,
56     /// Resource ID that we will signal using `NotifyEndOfBitstreamBuffer` upon destruction.
57     resource_id: u32,
58     /// Pointer to the event queue to send the `NotifyEndOfBitstreamBuffer` event to. The event
59     /// will not be sent if the pointer becomes invalid.
60     event_queue: Weak<SyncEventQueue<DecoderEvent>>,
61 }
62 
63 impl Drop for InputBuffer {
drop(&mut self)64     fn drop(&mut self) {
65         match self.event_queue.upgrade() {
66             None => (),
67             // If the event queue is still valid, send the event signaling we can be reused.
68             Some(event_queue) => event_queue
69                 .queue_event(DecoderEvent::NotifyEndOfBitstreamBuffer(self.resource_id))
70                 .unwrap_or_else(|e| {
71                     error!("cannot send end of input buffer notification: {:#}", e)
72                 }),
73         }
74     }
75 }
76 
77 impl AvBufferSource for InputBuffer {
as_ptr(&self) -> *const u878     fn as_ptr(&self) -> *const u8 {
79         self.mapping.as_ptr()
80     }
81 
len(&self) -> usize82     fn len(&self) -> usize {
83         self.mapping.size()
84     }
85 
is_empty(&self) -> bool86     fn is_empty(&self) -> bool {
87         self.len() == 0
88     }
89 }
90 
91 /// Types of input job we can receive from the crosvm decoder code.
92 enum CodecJob {
93     Packet(AvPacket<'static>),
94     Flush,
95 }
96 
97 /// A crosvm decoder needs to go through a number if setup stages before being able to decode, and
98 /// can require some setup to be redone when a dynamic resolution change occurs. This enum ensures
99 /// that the data associated with a given state only exists when we actually are in this state.
100 enum SessionState {
101     /// Waiting for libavcodec to tell us the resolution of the stream.
102     AwaitingInitialResolution,
103     /// Waiting for the client to call `set_output_buffer_count`.
104     AwaitingBufferCount,
105     /// Decoding and producing frames.
106     Decoding {
107         output_queue: OutputQueue,
108         format_converter: SwConverter,
109     },
110     /// Dynamic Resolution Change - we can still accept buffers in the old
111     /// format, but are waiting for new parameters before doing any decoding.
112     Drc,
113 }
114 
115 /// A decoder session for the ffmpeg backend.
116 pub struct FfmpegDecoderSession {
117     /// Queue of events waiting to be read by the client.
118     event_queue: Arc<SyncEventQueue<DecoderEvent>>,
119 
120     /// FIFO of jobs submitted by the client and waiting to be performed.
121     codec_jobs: VecDeque<CodecJob>,
122     /// Whether we are currently flushing.
123     is_flushing: bool,
124 
125     /// Current state of the session.
126     state: SessionState,
127     /// Visible size of the decoded frames (width, height).
128     current_visible_res: (usize, usize),
129 
130     /// The libav context for this session.
131     context: AvCodecContext,
132     /// The last frame to have been decoded, waiting to be copied into an output buffer and sent
133     /// to the client.
134     avframe: Option<AvFrame>,
135 }
136 
137 #[derive(Debug, ThisError)]
138 enum TrySendFrameError {
139     #[error("error while converting frame: {0}")]
140     CannotConvertFrame(#[from] ConversionError),
141     #[error("error while constructing AvFrame: {0}")]
142     IntoAvFrame(#[from] GuestResourceToAvFrameError),
143     #[error("error while sending picture ready event: {0}")]
144     BrokenPipe(#[from] base::Error),
145 }
146 
147 #[derive(Debug, ThisError)]
148 enum TryReceiveFrameError {
149     #[error("error creating AvFrame: {0}")]
150     CreateAvFrame(#[from] AvFrameError),
151     #[error("error queueing flush completed event: {0}")]
152     CannotQueueFlushEvent(#[from] base::Error),
153     #[error("error while changing resolution: {0}")]
154     ChangeResolutionError(#[from] ChangeResolutionError),
155 }
156 
157 #[derive(Debug, ThisError)]
158 enum TrySendPacketError {
159     #[error("error while sending input packet to libavcodec: {0}")]
160     AvError(#[from] AvError),
161 }
162 
163 #[derive(Debug, ThisError)]
164 enum TryDecodeError {
165     #[error("error while sending packet: {0}")]
166     SendPacket(#[from] TrySendPacketError),
167     #[error("error while trying to send decoded frame: {0}")]
168     SendFrameError(#[from] TrySendFrameError),
169     #[error("error while receiving frame: {0}")]
170     ReceiveFrame(#[from] TryReceiveFrameError),
171 }
172 
173 #[derive(Debug, ThisError)]
174 enum ChangeResolutionError {
175     #[error("error queueing event: {0}")]
176     QueueEventFailed(#[from] base::Error),
177     #[error("unexpected state during resolution change")]
178     UnexpectedState,
179 }
180 
181 impl FfmpegDecoderSession {
182     /// Queue an event for the client to receive.
queue_event(&mut self, event: DecoderEvent) -> base::Result<()>183     fn queue_event(&mut self, event: DecoderEvent) -> base::Result<()> {
184         self.event_queue.queue_event(event)
185     }
186 
187     /// Start the resolution change process, buffers will now be of size `new_visible_res`.
change_resolution( &mut self, new_visible_res: (usize, usize), ) -> Result<(), ChangeResolutionError>188     fn change_resolution(
189         &mut self,
190         new_visible_res: (usize, usize),
191     ) -> Result<(), ChangeResolutionError> {
192         info!("resolution changed to {:?}", new_visible_res);
193 
194         // Ask the client for new buffers.
195         self.queue_event(DecoderEvent::ProvidePictureBuffers {
196             min_num_buffers: std::cmp::max(self.context.as_ref().refs, 0) as u32 + 1,
197             width: new_visible_res.0 as i32,
198             height: new_visible_res.1 as i32,
199             visible_rect: Rect {
200                 left: 0,
201                 top: 0,
202                 right: new_visible_res.0 as i32,
203                 bottom: new_visible_res.1 as i32,
204             },
205         })?;
206 
207         self.current_visible_res = new_visible_res;
208 
209         // Drop our output queue and wait for the new number of output buffers.
210         self.state = match self.state {
211             SessionState::AwaitingInitialResolution => SessionState::AwaitingBufferCount,
212             SessionState::Decoding { .. } => SessionState::Drc,
213             _ => return Err(ChangeResolutionError::UnexpectedState),
214         };
215 
216         Ok(())
217     }
218 
219     /// Try to send one input packet to the codec.
220     ///
221     /// Returns `true` if a packet has successfully been queued, `false` if it could not be, either
222     /// because all pending work has already been queued or because the codec could not accept more
223     /// input at the moment.
try_send_packet( &mut self, input_packet: &AvPacket<'static>, ) -> Result<bool, TrySendPacketError>224     fn try_send_packet(
225         &mut self,
226         input_packet: &AvPacket<'static>,
227     ) -> Result<bool, TrySendPacketError> {
228         match self.context.try_send_packet(input_packet) {
229             Ok(true) => Ok(true),
230             // The codec cannot take more input at the moment, we'll try again after we receive some
231             // frames.
232             Ok(false) => Ok(false),
233             // This should happen only if we attempt to submit data while flushing.
234             Err(AvError(AVERROR_EOF)) => Ok(false),
235             // If we got invalid data, keep going in hope that we will catch a valid state later.
236             Err(AvError(AVERROR_INVALIDDATA)) => {
237                 warn!("Invalid data in stream, ignoring...");
238                 Ok(true)
239             }
240             Err(e) => Err(e.into()),
241         }
242     }
243 
244     /// Try to run the next input job, if any.
245     ///
246     /// Returns `true` if the next job has been submitted, `false` if it could not be, either
247     /// because all pending work has already been queued or because the codec could not accept more
248     /// input at the moment.
try_send_input_job(&mut self) -> Result<bool, TrySendPacketError>249     fn try_send_input_job(&mut self) -> Result<bool, TrySendPacketError> {
250         // Do not process any more input while we are flushing.
251         if self.is_flushing {
252             return Ok(false);
253         }
254 
255         let mut next_job = match self.codec_jobs.pop_front() {
256             // No work to do at the moment.
257             None => return Ok(false),
258             Some(job) => job,
259         };
260 
261         match &mut next_job {
262             CodecJob::Packet(input_packet) => {
263                 let res = self.try_send_packet(input_packet)?;
264                 match res {
265                     // The input buffer has been processed so we can drop it.
266                     true => drop(next_job),
267                     // The codec cannot accept new input for now, put the job back into the queue.
268                     false => self.codec_jobs.push_front(next_job),
269                 }
270 
271                 Ok(res)
272             }
273             CodecJob::Flush => {
274                 // Just set the is_flushing flag for now. We will send the actual flush command when
275                 // `try_receive_frame` returns `TryAgain`. This should probably not be necessary but
276                 // we sometimes miss the last frame if we send the flush command to libavcodec
277                 // earlier (which looks like a bug with libavcodec but needs to be confirmed).
278                 self.is_flushing = true;
279 
280                 Ok(true)
281             }
282         }
283     }
284 
285     /// Try to receive a frame from the codec and store it until we emit the corresponding
286     /// `PictureReady` decoder event.
287     ///
288     /// Returns `true` if a frame was successfully retrieved, or false if no frame was available at
289     /// the time, a decoded frame is already waiting to be returned to the client, or the decoder
290     /// needs more input data to proceed further.
try_receive_frame(&mut self) -> Result<bool, TryReceiveFrameError>291     fn try_receive_frame(&mut self) -> Result<bool, TryReceiveFrameError> {
292         let mut avframe = match self.avframe {
293             // We already have a frame waiting. Wait until it is sent to process the next one.
294             Some(_) => return Ok(false),
295             None => AvFrame::new()?,
296         };
297 
298         match self.context.try_receive_frame(&mut avframe) {
299             Ok(TryReceiveResult::Received) => {
300                 // Now check whether the resolution of the stream has changed.
301                 let new_visible_res = (avframe.width as usize, avframe.height as usize);
302                 if new_visible_res != self.current_visible_res {
303                     self.change_resolution(new_visible_res)?;
304                 }
305 
306                 self.avframe = Some(avframe);
307 
308                 Ok(true)
309             }
310             Ok(TryReceiveResult::TryAgain) => {
311                 if self.is_flushing {
312                     // Start flushing. `try_receive_frame` will return `FlushCompleted` when the
313                     // flush is completed. `TryAgain` will not be returned again until the flush is
314                     // completed.
315                     match self.context.flush_decoder() {
316                         // Call ourselves again so we can process the flush.
317                         Ok(()) => self.try_receive_frame(),
318                         Err(err) => {
319                             self.is_flushing = false;
320                             self.queue_event(DecoderEvent::FlushCompleted(Err(
321                                 VideoError::BackendFailure(err.into()),
322                             )))?;
323                             Ok(false)
324                         }
325                     }
326                 } else {
327                     // The codec is not ready to output a frame yet.
328                     Ok(false)
329                 }
330             }
331             Ok(TryReceiveResult::FlushCompleted) => {
332                 self.is_flushing = false;
333                 self.queue_event(DecoderEvent::FlushCompleted(Ok(())))?;
334                 self.context.reset();
335                 Ok(false)
336             }
337             // If we got invalid data, keep going in hope that we will catch a valid state later.
338             Err(AvError(AVERROR_INVALIDDATA)) => {
339                 warn!("Invalid data in stream, ignoring...");
340                 Ok(false)
341             }
342             Err(av_err) => {
343                 // This is a decoding error, so signal it using a `NotifyError` event to reflect the
344                 // same asynchronous flow as a hardware decoder would.
345                 if let Err(e) = self.event_queue.queue_event(DecoderEvent::NotifyError(
346                     VideoError::BackendFailure(av_err.into()),
347                 )) {
348                     error!("failed to notify error: {}", e);
349                 }
350                 Ok(false)
351             }
352         }
353     }
354 
355     /// Try to send a pending decoded frame to the client by copying its content into an output
356     /// buffer.
357     ///
358     /// This can only be done if `self.avframe` contains a decoded frame, and an output buffer is
359     /// ready to be written into.
360     ///
361     /// Returns `true` if a frame has been emitted, `false` if the conditions were not met for it to
362     /// happen yet.
try_send_frame(&mut self) -> Result<bool, TrySendFrameError>363     fn try_send_frame(&mut self) -> Result<bool, TrySendFrameError> {
364         let (output_queue, format_converter) = match &mut self.state {
365             SessionState::Decoding {
366                 output_queue,
367                 format_converter,
368             } => (output_queue, format_converter),
369             // Frames can only be emitted if we are actively decoding.
370             _ => return Ok(false),
371         };
372 
373         let avframe = match self.avframe.take() {
374             // No decoded frame available at the moment.
375             None => return Ok(false),
376             Some(avframe) => avframe,
377         };
378 
379         let (picture_buffer_id, target_buffer) = match output_queue.try_get_ready_buffer() {
380             None => {
381                 // Keep the decoded frame since we don't have a destination buffer to process it.
382                 self.avframe = Some(avframe);
383                 return Ok(false);
384             }
385             Some(buffer) => buffer,
386         };
387 
388         // Prepare the picture ready event that we will emit once the frame is written into the
389         // target buffer.
390         let picture_ready_event = DecoderEvent::PictureReady {
391             picture_buffer_id: picture_buffer_id as i32,
392             timestamp: avframe.pts as u64,
393         };
394 
395         // Convert the frame into the target buffer and emit the picture ready event.
396         format_converter.convert(
397             &avframe,
398             &mut target_buffer.try_as_av_frame(MemoryMappingAvBufferSource::from)?,
399         )?;
400         self.event_queue.queue_event(picture_ready_event)?;
401 
402         Ok(true)
403     }
404 
405     /// Try to progress as much as possible with decoding.
406     ///
407     /// Our pipeline has three stages: send encoded input to libavcodec, receive decoded frames from
408     /// libavcodec, and copy decoded frames into output buffers sent to the client. This method
409     /// calls these three stages in a loop for as long as at least one makes progress.
try_decode(&mut self) -> Result<(), TryDecodeError>410     fn try_decode(&mut self) -> Result<(), TryDecodeError> {
411         // Try to make the pipeline progress as long as one of the stages can move forward
412         while self.try_send_frame()? || self.try_receive_frame()? || self.try_send_input_job()? {}
413 
414         Ok(())
415     }
416 }
417 
418 impl DecoderSession for FfmpegDecoderSession {
set_output_parameters(&mut self, buffer_count: usize, format: Format) -> VideoResult<()>419     fn set_output_parameters(&mut self, buffer_count: usize, format: Format) -> VideoResult<()> {
420         match self.state {
421             // It is valid to set an output format before the the initial DRC, but we won't do
422             // anything with it.
423             SessionState::AwaitingInitialResolution => Ok(()),
424             SessionState::AwaitingBufferCount | SessionState::Drc => {
425                 let avcontext = self.context.as_ref();
426 
427                 let dst_pix_format: AvPixelFormat =
428                     format.try_into().map_err(|_| VideoError::InvalidFormat)?;
429 
430                 self.state = SessionState::Decoding {
431                     output_queue: OutputQueue::new(buffer_count),
432                     format_converter: SwConverter::new(
433                         avcontext.width as usize,
434                         avcontext.height as usize,
435                         avcontext.pix_fmt,
436                         dst_pix_format.pix_fmt(),
437                     )
438                     .context("while setting output parameters")
439                     .map_err(VideoError::BackendFailure)?,
440                 };
441                 Ok(())
442             }
443             _ => Err(VideoError::BackendFailure(anyhow!(
444                 "invalid state while calling set_output_parameters"
445             ))),
446         }
447     }
448 
decode( &mut self, resource_id: u32, timestamp: u64, resource: GuestResourceHandle, offset: u32, bytes_used: u32, ) -> VideoResult<()>449     fn decode(
450         &mut self,
451         resource_id: u32,
452         timestamp: u64,
453         resource: GuestResourceHandle,
454         offset: u32,
455         bytes_used: u32,
456     ) -> VideoResult<()> {
457         let input_buffer = InputBuffer {
458             mapping: resource
459                 .get_mapping(offset as usize, bytes_used as usize)
460                 .context("while mapping input buffer")
461                 .map_err(VideoError::BackendFailure)?,
462             resource_id,
463             event_queue: Arc::downgrade(&self.event_queue),
464         };
465 
466         let avbuffer = AvBuffer::new(input_buffer)
467             .context("while creating AvPacket")
468             .map_err(VideoError::BackendFailure)?;
469 
470         let avpacket = AvPacket::new_owned(timestamp as i64, avbuffer);
471 
472         self.codec_jobs.push_back(CodecJob::Packet(avpacket));
473 
474         self.try_decode()
475             .context("while decoding")
476             .map_err(VideoError::BackendFailure)
477     }
478 
flush(&mut self) -> VideoResult<()>479     fn flush(&mut self) -> VideoResult<()> {
480         if self.is_flushing {
481             Err(VideoError::BackendFailure(anyhow!(
482                 "flush is already in progress"
483             )))
484         } else {
485             self.codec_jobs.push_back(CodecJob::Flush);
486             self.try_decode()
487                 .context("while flushing")
488                 .map_err(VideoError::BackendFailure)
489         }
490     }
491 
reset(&mut self) -> VideoResult<()>492     fn reset(&mut self) -> VideoResult<()> {
493         // Reset the codec.
494         self.context.reset();
495 
496         // Drop all currently pending jobs.
497         self.codec_jobs.clear();
498 
499         // Drop the queued output buffers.
500         self.clear_output_buffers()?;
501 
502         self.queue_event(DecoderEvent::ResetCompleted(Ok(())))
503             .context("while resetting")
504             .map_err(VideoError::BackendFailure)
505     }
506 
clear_output_buffers(&mut self) -> VideoResult<()>507     fn clear_output_buffers(&mut self) -> VideoResult<()> {
508         // Cancel any ongoing flush.
509         self.is_flushing = false;
510 
511         // Drop all output buffers we currently hold.
512         if let SessionState::Decoding { output_queue, .. } = &mut self.state {
513             output_queue.clear_ready_buffers();
514         }
515 
516         // Drop the currently decoded frame.
517         self.avframe = None;
518 
519         // Drop all decoded frames signaled as ready and cancel any reported flush.
520         self.event_queue.retain(|event| {
521             !matches!(
522                 event,
523                 DecoderEvent::PictureReady { .. } | DecoderEvent::FlushCompleted(_)
524             )
525         });
526 
527         Ok(())
528     }
529 
event_pipe(&self) -> &dyn AsRawDescriptor530     fn event_pipe(&self) -> &dyn AsRawDescriptor {
531         self.event_queue.as_ref()
532     }
533 
use_output_buffer( &mut self, picture_buffer_id: i32, resource: GuestResource, ) -> VideoResult<()>534     fn use_output_buffer(
535         &mut self,
536         picture_buffer_id: i32,
537         resource: GuestResource,
538     ) -> VideoResult<()> {
539         let output_queue = match &mut self.state {
540             // It is valid to receive buffers before the the initial DRC, but we won't decode
541             // anything into them.
542             SessionState::AwaitingInitialResolution => return Ok(()),
543             SessionState::Decoding { output_queue, .. } => output_queue,
544             // Receiving buffers during DRC is valid, but we won't use them and can just drop them.
545             SessionState::Drc => return Ok(()),
546             _ => {
547                 error!("use_output_buffer: invalid state");
548                 return Ok(());
549             }
550         };
551 
552         output_queue
553             .import_buffer(picture_buffer_id as u32, resource)
554             .context("while importing output buffer")
555             .map_err(VideoError::BackendFailure)?;
556         self.try_decode()
557             .context("while decoding output buffer")
558             .map_err(VideoError::BackendFailure)
559     }
560 
reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()>561     fn reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()> {
562         let output_queue = match &mut self.state {
563             // It is valid to receive buffers before the the initial DRC, but we won't decode
564             // anything into them.
565             SessionState::AwaitingInitialResolution => return Ok(()),
566             SessionState::Decoding { output_queue, .. } => output_queue,
567             // Reusing buffers during DRC is valid, but we won't use them and can just drop them.
568             SessionState::Drc => return Ok(()),
569             _ => {
570                 return Err(VideoError::BackendFailure(anyhow!(
571                     "invalid state while calling reuse_output_buffer"
572                 )))
573             }
574         };
575 
576         output_queue
577             .reuse_buffer(picture_buffer_id as u32)
578             .context("while reusing output buffer")
579             .map_err(VideoError::BackendFailure)?;
580         self.try_decode()
581             .context("while reusing output buffer")
582             .map_err(VideoError::BackendFailure)
583     }
584 
read_event(&mut self) -> VideoResult<DecoderEvent>585     fn read_event(&mut self) -> VideoResult<DecoderEvent> {
586         self.event_queue
587             .dequeue_event()
588             .context("while reading decoder event")
589             .map_err(VideoError::BackendFailure)
590     }
591 }
592 
593 pub struct FfmpegDecoder {
594     codecs: BTreeMap<Format, AvCodec>,
595 }
596 
597 impl FfmpegDecoder {
598     /// Create a new ffmpeg decoder backend instance.
new() -> Self599     pub fn new() -> Self {
600         // Find all the decoders supported by libav and store them.
601         let codecs = AvCodecIterator::new()
602             .filter_map(|codec| {
603                 if !codec.is_decoder() {
604                     return None;
605                 }
606 
607                 let codec_name = codec.name();
608 
609                 // Only keep processing the decoders we are interested in. These are all software
610                 // decoders, but nothing prevents us from supporting hardware-accelerated ones
611                 // (e.g. *_qsv for VAAPI-based acceleration) in the future!
612                 let format = match codec_name {
613                     "h264" => Format::H264,
614                     "vp8" => Format::VP8,
615                     "vp9" => Format::VP9,
616                     "hevc" => Format::Hevc,
617                     _ => return None,
618                 };
619 
620                 // We require custom buffer allocators, so ignore codecs that are not capable of
621                 // using them.
622                 if codec.capabilities() & AV_CODEC_CAP_DR1 == 0 {
623                     warn!(
624                         "Skipping codec {} due to lack of DR1 capability.",
625                         codec_name
626                     );
627                     return None;
628                 }
629 
630                 Some((format, codec))
631             })
632             .collect();
633 
634         Self { codecs }
635     }
636 }
637 
638 impl DecoderBackend for FfmpegDecoder {
639     type Session = FfmpegDecoderSession;
640 
get_capabilities(&self) -> Capability641     fn get_capabilities(&self) -> Capability {
642         // The virtio device only supports NV12 for now it seems...
643         const SUPPORTED_OUTPUT_FORMATS: [Format; 1] = [Format::NV12];
644 
645         let mut in_formats = vec![];
646         let mut profiles_map: BTreeMap<Format, Vec<Profile>> = Default::default();
647         let mut levels: BTreeMap<Format, Vec<Level>> = Default::default();
648         for (&format, codec) in &self.codecs {
649             let profile_iter = codec.profile_iter();
650             let profiles = match format {
651                 Format::H264 => {
652                     // We only support Level 1.0 for H.264.
653                     // TODO Do we? Why?
654                     levels.insert(format, vec![Level::H264_1_0]);
655 
656                     profile_iter
657                         .filter_map(|p| {
658                             match p.profile() {
659                                 FF_PROFILE_H264_BASELINE => Some(Profile::H264Baseline),
660                                 FF_PROFILE_H264_MAIN => Some(Profile::H264Main),
661                                 FF_PROFILE_H264_EXTENDED => Some(Profile::H264Extended),
662                                 FF_PROFILE_H264_HIGH => Some(Profile::H264High),
663                                 FF_PROFILE_H264_HIGH_10 => Some(Profile::H264High10),
664                                 FF_PROFILE_H264_HIGH_422 => Some(Profile::H264High422),
665                                 FF_PROFILE_H264_HIGH_444_PREDICTIVE => {
666                                     Some(Profile::H264High444PredictiveProfile)
667                                 }
668                                 FF_PROFILE_H264_STEREO_HIGH => Some(Profile::H264StereoHigh),
669                                 FF_PROFILE_H264_MULTIVIEW_HIGH => Some(Profile::H264MultiviewHigh),
670                                 // TODO H264ScalableBaseline and H264ScalableHigh have no libav
671                                 // equivalents?
672                                 _ => None,
673                             }
674                         })
675                         .collect()
676                 }
677                 Format::VP8 => {
678                     // FFmpeg has no VP8 profiles, for some reason...
679                     vec![
680                         Profile::VP8Profile0,
681                         Profile::VP8Profile1,
682                         Profile::VP8Profile2,
683                         Profile::VP8Profile3,
684                     ]
685                 }
686                 Format::VP9 => profile_iter
687                     .filter_map(|p| match p.profile() {
688                         FF_PROFILE_VP9_0 => Some(Profile::VP9Profile0),
689                         FF_PROFILE_VP9_1 => Some(Profile::VP9Profile1),
690                         FF_PROFILE_VP9_2 => Some(Profile::VP9Profile2),
691                         FF_PROFILE_VP9_3 => Some(Profile::VP9Profile3),
692                         _ => None,
693                     })
694                     .collect(),
695                 Format::Hevc => profile_iter
696                     .filter_map(|p| match p.profile() {
697                         FF_PROFILE_HEVC_MAIN => Some(Profile::HevcMain),
698                         FF_PROFILE_HEVC_MAIN_10 => Some(Profile::HevcMain10),
699                         FF_PROFILE_HEVC_MAIN_STILL_PICTURE => Some(Profile::HevcMainStillPicture),
700                         _ => None,
701                     })
702                     .collect(),
703                 _ => unreachable!("Unhandled format {:?}", format),
704             };
705 
706             profiles_map.insert(format, profiles);
707 
708             in_formats.push(FormatDesc {
709                 mask: !(u64::MAX << SUPPORTED_OUTPUT_FORMATS.len()),
710                 format,
711                 frame_formats: vec![FrameFormat {
712                     // These frame sizes are arbitrary, but avcodec does not seem to have any
713                     // specific restriction in that regard (or any way to query the supported
714                     // resolutions).
715                     width: FormatRange {
716                         min: 64,
717                         max: 16384,
718                         step: 1,
719                     },
720                     height: FormatRange {
721                         min: 64,
722                         max: 16384,
723                         step: 1,
724                     },
725                     bitrates: Default::default(),
726                 }],
727                 plane_align: max_buffer_alignment() as u32,
728             });
729         }
730 
731         // We support all output formats through the use of swscale().
732         let out_formats = SUPPORTED_OUTPUT_FORMATS
733             .iter()
734             .map(|&format| FormatDesc {
735                 mask: !(u64::MAX << in_formats.len()),
736                 format,
737                 frame_formats: vec![FrameFormat {
738                     // These frame sizes are arbitrary, but avcodec does not seem to have any
739                     // specific restriction in that regard (or any way to query the supported
740                     // resolutions).
741                     width: FormatRange {
742                         min: 64,
743                         max: 16384,
744                         step: 1,
745                     },
746                     height: FormatRange {
747                         min: 64,
748                         max: 16384,
749                         step: 1,
750                     },
751                     bitrates: Default::default(),
752                 }],
753                 plane_align: max_buffer_alignment() as u32,
754             })
755             .collect::<Vec<_>>();
756 
757         Capability::new(in_formats, out_formats, profiles_map, levels)
758     }
759 
new_session(&mut self, format: Format) -> VideoResult<Self::Session>760     fn new_session(&mut self, format: Format) -> VideoResult<Self::Session> {
761         let codec = self.codecs.get(&format).ok_or(VideoError::InvalidFormat)?;
762         let context = codec
763             // TODO we should use a custom `get_buffer` function that renders directly into the
764             // target buffer if the output format is directly supported by libavcodec. Right now
765             // libavcodec is allocating its own frame buffers, which forces us to perform a copy.
766             .build_decoder()
767             .and_then(|b| b.build())
768             .context("while creating new session")
769             .map_err(VideoError::BackendFailure)?;
770         Ok(FfmpegDecoderSession {
771             codec_jobs: Default::default(),
772             is_flushing: false,
773             state: SessionState::AwaitingInitialResolution,
774             event_queue: Arc::new(
775                 EventQueue::new()
776                     .context("while creating decoder session")
777                     .map_err(VideoError::BackendFailure)?
778                     .into(),
779             ),
780             context,
781             current_visible_res: (0, 0),
782             avframe: None,
783         })
784     }
785 }
786 
787 #[cfg(test)]
788 mod tests {
789     use super::super::tests::*;
790     use super::*;
791 
792     #[test]
test_get_capabilities()793     fn test_get_capabilities() {
794         let decoder = FfmpegDecoder::new();
795         let caps = decoder.get_capabilities();
796         assert!(!caps.input_formats().is_empty());
797         assert!(!caps.output_formats().is_empty());
798     }
799 
800     #[test]
test_decode_h264_guestmem_to_guestmem()801     fn test_decode_h264_guestmem_to_guestmem() {
802         decode_h264_generic(
803             &mut FfmpegDecoder::new(),
804             build_guest_mem_handle,
805             build_guest_mem_handle,
806         );
807     }
808 
809     // Decode using guest memory input and virtio object output buffers.
810     #[test]
test_decode_h264_guestmem_to_object()811     fn test_decode_h264_guestmem_to_object() {
812         decode_h264_generic(
813             &mut FfmpegDecoder::new(),
814             build_guest_mem_handle,
815             build_object_handle,
816         );
817     }
818 
819     // Decode using virtio object input and guest memory output buffers.
820     #[test]
test_decode_h264_object_to_guestmem()821     fn test_decode_h264_object_to_guestmem() {
822         decode_h264_generic(
823             &mut FfmpegDecoder::new(),
824             build_object_handle,
825             build_guest_mem_handle,
826         );
827     }
828 
829     // Decode using virtio object input and output buffers.
830     #[test]
test_decode_h264_object_to_object()831     fn test_decode_h264_object_to_object() {
832         decode_h264_generic(
833             &mut FfmpegDecoder::new(),
834             build_object_handle,
835             build_object_handle,
836         );
837     }
838 }
839