• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 avframe_ref = avframe.as_ref();
391         let picture_ready_event = DecoderEvent::PictureReady {
392             picture_buffer_id: picture_buffer_id as i32,
393             timestamp: avframe_ref.pts as u64,
394             visible_rect: Rect {
395                 left: 0,
396                 top: 0,
397                 right: avframe_ref.width,
398                 bottom: avframe_ref.height,
399             },
400         };
401 
402         // Convert the frame into the target buffer and emit the picture ready event.
403         format_converter.convert(
404             &avframe,
405             &mut target_buffer.try_as_av_frame(MemoryMappingAvBufferSource::from)?,
406         )?;
407         self.event_queue.queue_event(picture_ready_event)?;
408 
409         Ok(true)
410     }
411 
412     /// Try to progress as much as possible with decoding.
413     ///
414     /// Our pipeline has three stages: send encoded input to libavcodec, receive decoded frames from
415     /// libavcodec, and copy decoded frames into output buffers sent to the client. This method
416     /// calls these three stages in a loop for as long as at least one makes progress.
try_decode(&mut self) -> Result<(), TryDecodeError>417     fn try_decode(&mut self) -> Result<(), TryDecodeError> {
418         // Try to make the pipeline progress as long as one of the stages can move forward
419         while self.try_send_frame()? || self.try_receive_frame()? || self.try_send_input_job()? {}
420 
421         Ok(())
422     }
423 }
424 
425 impl DecoderSession for FfmpegDecoderSession {
set_output_parameters(&mut self, buffer_count: usize, format: Format) -> VideoResult<()>426     fn set_output_parameters(&mut self, buffer_count: usize, format: Format) -> VideoResult<()> {
427         match self.state {
428             // It is valid to set an output format before the the initial DRC, but we won't do
429             // anything with it.
430             SessionState::AwaitingInitialResolution => Ok(()),
431             SessionState::AwaitingBufferCount | SessionState::Drc => {
432                 let avcontext = self.context.as_ref();
433 
434                 let dst_pix_format: AvPixelFormat =
435                     format.try_into().map_err(|_| VideoError::InvalidFormat)?;
436 
437                 self.state = SessionState::Decoding {
438                     output_queue: OutputQueue::new(buffer_count),
439                     format_converter: SwConverter::new(
440                         avcontext.width as usize,
441                         avcontext.height as usize,
442                         avcontext.pix_fmt,
443                         dst_pix_format.pix_fmt(),
444                     )
445                     .context("while setting output parameters")
446                     .map_err(VideoError::BackendFailure)?,
447                 };
448                 Ok(())
449             }
450             _ => Err(VideoError::BackendFailure(anyhow!(
451                 "invalid state while calling set_output_parameters"
452             ))),
453         }
454     }
455 
decode( &mut self, resource_id: u32, timestamp: u64, resource: GuestResourceHandle, offset: u32, bytes_used: u32, ) -> VideoResult<()>456     fn decode(
457         &mut self,
458         resource_id: u32,
459         timestamp: u64,
460         resource: GuestResourceHandle,
461         offset: u32,
462         bytes_used: u32,
463     ) -> VideoResult<()> {
464         let input_buffer = InputBuffer {
465             mapping: resource
466                 .get_mapping(offset as usize, bytes_used as usize)
467                 .context("while mapping input buffer")
468                 .map_err(VideoError::BackendFailure)?,
469             resource_id,
470             event_queue: Arc::downgrade(&self.event_queue),
471         };
472 
473         let avbuffer = AvBuffer::new(input_buffer)
474             .context("while creating AvPacket")
475             .map_err(VideoError::BackendFailure)?;
476 
477         let avpacket = AvPacket::new_owned(timestamp as i64, avbuffer);
478 
479         self.codec_jobs.push_back(CodecJob::Packet(avpacket));
480 
481         self.try_decode()
482             .context("while decoding")
483             .map_err(VideoError::BackendFailure)
484     }
485 
flush(&mut self) -> VideoResult<()>486     fn flush(&mut self) -> VideoResult<()> {
487         if self.is_flushing {
488             Err(VideoError::BackendFailure(anyhow!(
489                 "flush is already in progress"
490             )))
491         } else {
492             self.codec_jobs.push_back(CodecJob::Flush);
493             self.try_decode()
494                 .context("while flushing")
495                 .map_err(VideoError::BackendFailure)
496         }
497     }
498 
reset(&mut self) -> VideoResult<()>499     fn reset(&mut self) -> VideoResult<()> {
500         // Reset the codec.
501         self.context.reset();
502 
503         // Drop all currently pending jobs.
504         self.codec_jobs.clear();
505 
506         // Drop the queued output buffers.
507         self.clear_output_buffers()?;
508 
509         self.queue_event(DecoderEvent::ResetCompleted(Ok(())))
510             .context("while resetting")
511             .map_err(VideoError::BackendFailure)
512     }
513 
clear_output_buffers(&mut self) -> VideoResult<()>514     fn clear_output_buffers(&mut self) -> VideoResult<()> {
515         // Cancel any ongoing flush.
516         self.is_flushing = false;
517 
518         // Drop all output buffers we currently hold.
519         if let SessionState::Decoding { output_queue, .. } = &mut self.state {
520             output_queue.clear_ready_buffers();
521         }
522 
523         // Drop the currently decoded frame.
524         self.avframe = None;
525 
526         // Drop all decoded frames signaled as ready and cancel any reported flush.
527         self.event_queue.retain(|event| {
528             !matches!(
529                 event,
530                 DecoderEvent::PictureReady { .. } | DecoderEvent::FlushCompleted(_)
531             )
532         });
533 
534         Ok(())
535     }
536 
event_pipe(&self) -> &dyn AsRawDescriptor537     fn event_pipe(&self) -> &dyn AsRawDescriptor {
538         self.event_queue.as_ref()
539     }
540 
use_output_buffer( &mut self, picture_buffer_id: i32, resource: GuestResource, ) -> VideoResult<()>541     fn use_output_buffer(
542         &mut self,
543         picture_buffer_id: i32,
544         resource: GuestResource,
545     ) -> VideoResult<()> {
546         let output_queue = match &mut self.state {
547             // It is valid to receive buffers before the the initial DRC, but we won't decode
548             // anything into them.
549             SessionState::AwaitingInitialResolution => return Ok(()),
550             SessionState::Decoding { output_queue, .. } => output_queue,
551             // Receiving buffers during DRC is valid, but we won't use them and can just drop them.
552             SessionState::Drc => return Ok(()),
553             _ => {
554                 error!("use_output_buffer: invalid state");
555                 return Ok(());
556             }
557         };
558 
559         output_queue
560             .import_buffer(picture_buffer_id as u32, resource)
561             .context("while importing output buffer")
562             .map_err(VideoError::BackendFailure)?;
563         self.try_decode()
564             .context("while importing output buffer")
565             .map_err(VideoError::BackendFailure)
566     }
567 
reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()>568     fn reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()> {
569         let output_queue = match &mut self.state {
570             // It is valid to receive buffers before the the initial DRC, but we won't decode
571             // anything into them.
572             SessionState::AwaitingInitialResolution => return Ok(()),
573             SessionState::Decoding { output_queue, .. } => output_queue,
574             // Reusing buffers during DRC is valid, but we won't use them and can just drop them.
575             SessionState::Drc => return Ok(()),
576             _ => {
577                 return Err(VideoError::BackendFailure(anyhow!(
578                     "invalid state while calling reuse_output_buffer"
579                 )))
580             }
581         };
582 
583         output_queue
584             .reuse_buffer(picture_buffer_id as u32)
585             .context("while reusing output buffer")
586             .map_err(VideoError::BackendFailure)?;
587         self.try_decode()
588             .context("while reusing output buffer")
589             .map_err(VideoError::BackendFailure)
590     }
591 
read_event(&mut self) -> VideoResult<DecoderEvent>592     fn read_event(&mut self) -> VideoResult<DecoderEvent> {
593         self.event_queue
594             .dequeue_event()
595             .context("while reading decoder event")
596             .map_err(VideoError::BackendFailure)
597     }
598 }
599 
600 pub struct FfmpegDecoder {
601     codecs: BTreeMap<Format, AvCodec>,
602 }
603 
604 impl FfmpegDecoder {
605     /// Create a new ffmpeg decoder backend instance.
new() -> Self606     pub fn new() -> Self {
607         // Find all the decoders supported by libav and store them.
608         let codecs = AvCodecIterator::new()
609             .filter_map(|codec| {
610                 if !codec.is_decoder() {
611                     return None;
612                 }
613 
614                 let codec_name = codec.name();
615 
616                 // Only keep processing the decoders we are interested in. These are all software
617                 // decoders, but nothing prevents us from supporting hardware-accelerated ones
618                 // (e.g. *_qsv for VAAPI-based acceleration) in the future!
619                 let format = match codec_name {
620                     "h264" => Format::H264,
621                     "vp8" => Format::VP8,
622                     "vp9" => Format::VP9,
623                     "hevc" => Format::Hevc,
624                     _ => return None,
625                 };
626 
627                 // We require custom buffer allocators, so ignore codecs that are not capable of
628                 // using them.
629                 if codec.capabilities() & AV_CODEC_CAP_DR1 == 0 {
630                     warn!(
631                         "Skipping codec {} due to lack of DR1 capability.",
632                         codec_name
633                     );
634                     return None;
635                 }
636 
637                 Some((format, codec))
638             })
639             .collect();
640 
641         Self { codecs }
642     }
643 }
644 
645 impl DecoderBackend for FfmpegDecoder {
646     type Session = FfmpegDecoderSession;
647 
get_capabilities(&self) -> Capability648     fn get_capabilities(&self) -> Capability {
649         // The virtio device only supports NV12 for now it seems...
650         const SUPPORTED_OUTPUT_FORMATS: [Format; 1] = [Format::NV12];
651 
652         let mut in_formats = vec![];
653         let mut profiles_map: BTreeMap<Format, Vec<Profile>> = Default::default();
654         let mut levels: BTreeMap<Format, Vec<Level>> = Default::default();
655         for (&format, codec) in &self.codecs {
656             let profile_iter = codec.profile_iter();
657             let profiles = match format {
658                 Format::H264 => {
659                     // We only support Level 1.0 for H.264.
660                     // TODO Do we? Why?
661                     levels.insert(format, vec![Level::H264_1_0]);
662 
663                     profile_iter
664                         .filter_map(|p| {
665                             match p.profile() {
666                                 FF_PROFILE_H264_BASELINE => Some(Profile::H264Baseline),
667                                 FF_PROFILE_H264_MAIN => Some(Profile::H264Main),
668                                 FF_PROFILE_H264_EXTENDED => Some(Profile::H264Extended),
669                                 FF_PROFILE_H264_HIGH => Some(Profile::H264High),
670                                 FF_PROFILE_H264_HIGH_10 => Some(Profile::H264High10),
671                                 FF_PROFILE_H264_HIGH_422 => Some(Profile::H264High422),
672                                 FF_PROFILE_H264_HIGH_444_PREDICTIVE => {
673                                     Some(Profile::H264High444PredictiveProfile)
674                                 }
675                                 FF_PROFILE_H264_STEREO_HIGH => Some(Profile::H264StereoHigh),
676                                 FF_PROFILE_H264_MULTIVIEW_HIGH => Some(Profile::H264MultiviewHigh),
677                                 // TODO H264ScalableBaseline and H264ScalableHigh have no libav
678                                 // equivalents?
679                                 _ => None,
680                             }
681                         })
682                         .collect()
683                 }
684                 Format::VP8 => {
685                     // FFmpeg has no VP8 profiles, for some reason...
686                     vec![
687                         Profile::VP8Profile0,
688                         Profile::VP8Profile1,
689                         Profile::VP8Profile2,
690                         Profile::VP8Profile3,
691                     ]
692                 }
693                 Format::VP9 => profile_iter
694                     .filter_map(|p| match p.profile() {
695                         FF_PROFILE_VP9_0 => Some(Profile::VP9Profile0),
696                         FF_PROFILE_VP9_1 => Some(Profile::VP9Profile1),
697                         FF_PROFILE_VP9_2 => Some(Profile::VP9Profile2),
698                         FF_PROFILE_VP9_3 => Some(Profile::VP9Profile3),
699                         _ => None,
700                     })
701                     .collect(),
702                 Format::Hevc => profile_iter
703                     .filter_map(|p| match p.profile() {
704                         FF_PROFILE_HEVC_MAIN => Some(Profile::HevcMain),
705                         FF_PROFILE_HEVC_MAIN_10 => Some(Profile::HevcMain10),
706                         FF_PROFILE_HEVC_MAIN_STILL_PICTURE => Some(Profile::HevcMainStillPicture),
707                         _ => None,
708                     })
709                     .collect(),
710                 _ => unreachable!("Unhandled format {:?}", format),
711             };
712 
713             profiles_map.insert(format, profiles);
714 
715             in_formats.push(FormatDesc {
716                 mask: !(u64::MAX << SUPPORTED_OUTPUT_FORMATS.len()),
717                 format,
718                 frame_formats: vec![FrameFormat {
719                     // These frame sizes are arbitrary, but avcodec does not seem to have any
720                     // specific restriction in that regard (or any way to query the supported
721                     // resolutions).
722                     width: FormatRange {
723                         min: 64,
724                         max: 16384,
725                         step: 1,
726                     },
727                     height: FormatRange {
728                         min: 64,
729                         max: 16384,
730                         step: 1,
731                     },
732                     bitrates: Default::default(),
733                 }],
734                 plane_align: max_buffer_alignment() as u32,
735             });
736         }
737 
738         // We support all output formats through the use of swscale().
739         let out_formats = SUPPORTED_OUTPUT_FORMATS
740             .iter()
741             .map(|&format| FormatDesc {
742                 mask: !(u64::MAX << in_formats.len()),
743                 format,
744                 frame_formats: vec![FrameFormat {
745                     // These frame sizes are arbitrary, but avcodec does not seem to have any
746                     // specific restriction in that regard (or any way to query the supported
747                     // resolutions).
748                     width: FormatRange {
749                         min: 64,
750                         max: 16384,
751                         step: 1,
752                     },
753                     height: FormatRange {
754                         min: 64,
755                         max: 16384,
756                         step: 1,
757                     },
758                     bitrates: Default::default(),
759                 }],
760                 plane_align: max_buffer_alignment() as u32,
761             })
762             .collect::<Vec<_>>();
763 
764         Capability::new(in_formats, out_formats, profiles_map, levels)
765     }
766 
new_session(&mut self, format: Format) -> VideoResult<Self::Session>767     fn new_session(&mut self, format: Format) -> VideoResult<Self::Session> {
768         let codec = self.codecs.get(&format).ok_or(VideoError::InvalidFormat)?;
769         let context = codec
770             // TODO we should use a custom `get_buffer` function that renders directly into the
771             // target buffer if the output format is directly supported by libavcodec. Right now
772             // libavcodec is allocating its own frame buffers, which forces us to perform a copy.
773             .build_decoder()
774             .and_then(|b| b.build())
775             .context("while creating new session")
776             .map_err(VideoError::BackendFailure)?;
777         Ok(FfmpegDecoderSession {
778             codec_jobs: Default::default(),
779             is_flushing: false,
780             state: SessionState::AwaitingInitialResolution,
781             event_queue: Arc::new(
782                 EventQueue::new()
783                     .context("while creating decoder session")
784                     .map_err(VideoError::BackendFailure)?
785                     .into(),
786             ),
787             context,
788             current_visible_res: (0, 0),
789             avframe: None,
790         })
791     }
792 }
793 
794 #[cfg(test)]
795 mod tests {
796     use super::super::tests::*;
797     use super::*;
798 
799     #[test]
test_get_capabilities()800     fn test_get_capabilities() {
801         let decoder = FfmpegDecoder::new();
802         let caps = decoder.get_capabilities();
803         assert!(!caps.input_formats().is_empty());
804         assert!(!caps.output_formats().is_empty());
805     }
806 
807     #[test]
test_decode_h264_guestmem_to_guestmem()808     fn test_decode_h264_guestmem_to_guestmem() {
809         decode_h264_generic(
810             &mut FfmpegDecoder::new(),
811             build_guest_mem_handle,
812             build_guest_mem_handle,
813         );
814     }
815 
816     // Decode using guest memory input and virtio object output buffers.
817     #[test]
test_decode_h264_guestmem_to_object()818     fn test_decode_h264_guestmem_to_object() {
819         decode_h264_generic(
820             &mut FfmpegDecoder::new(),
821             build_guest_mem_handle,
822             build_object_handle,
823         );
824     }
825 
826     // Decode using virtio object input and guest memory output buffers.
827     #[test]
test_decode_h264_object_to_guestmem()828     fn test_decode_h264_object_to_guestmem() {
829         decode_h264_generic(
830             &mut FfmpegDecoder::new(),
831             build_object_handle,
832             build_guest_mem_handle,
833         );
834     }
835 
836     // Decode using virtio object input and output buffers.
837     #[test]
test_decode_h264_object_to_object()838     fn test_decode_h264_object_to_object() {
839         decode_h264_generic(
840             &mut FfmpegDecoder::new(),
841             build_object_handle,
842             build_object_handle,
843         );
844     }
845 }
846