devices/virtio/video/decoder/backend/
ffmpeg.rs

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
18use std::collections::BTreeMap;
19use std::collections::VecDeque;
20use std::sync::Arc;
21use std::sync::Weak;
22
23use ::ffmpeg::avcodec::*;
24use ::ffmpeg::swscale::*;
25use ::ffmpeg::*;
26use anyhow::anyhow;
27use anyhow::Context;
28use base::error;
29use base::info;
30use base::warn;
31use base::MappedRegion;
32use base::MemoryMappingArena;
33use thiserror::Error as ThisError;
34
35use crate::virtio::video::decoder::backend::*;
36use crate::virtio::video::ffmpeg::GuestResourceToAvFrameError;
37use crate::virtio::video::ffmpeg::MemoryMappingAvBufferSource;
38use crate::virtio::video::ffmpeg::TryAsAvFrameExt;
39use crate::virtio::video::format::FormatDesc;
40use crate::virtio::video::format::FormatRange;
41use crate::virtio::video::format::FrameFormat;
42use crate::virtio::video::format::Level;
43use crate::virtio::video::format::Profile;
44use crate::virtio::video::resource::BufferHandle;
45use crate::virtio::video::resource::GuestResource;
46use crate::virtio::video::resource::GuestResourceHandle;
47use crate::virtio::video::utils::EventQueue;
48use crate::virtio::video::utils::OutputQueue;
49use 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.
53struct 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
63impl Drop for InputBuffer {
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
77impl AvBufferSource for InputBuffer {
78    fn as_ptr(&self) -> *const u8 {
79        self.mapping.as_ptr()
80    }
81
82    fn len(&self) -> usize {
83        self.mapping.size()
84    }
85
86    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.
92enum 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.
100enum 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.
116pub 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)]
138enum 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)]
148enum 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)]
158enum TrySendPacketError {
159    #[error("error while sending input packet to libavcodec: {0}")]
160    AvError(#[from] AvError),
161}
162
163#[derive(Debug, ThisError)]
164enum 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)]
174enum ChangeResolutionError {
175    #[error("error queueing event: {0}")]
176    QueueEventFailed(#[from] base::Error),
177    #[error("unexpected state during resolution change")]
178    UnexpectedState,
179}
180
181impl FfmpegDecoderSession {
182    /// Queue an event for the client to receive.
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`.
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.
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.
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.
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.
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.
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
418impl DecoderSession for FfmpegDecoderSession {
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
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
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
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
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
530    fn event_pipe(&self) -> &dyn AsRawDescriptor {
531        self.event_queue.as_ref()
532    }
533
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
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
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
593pub struct FfmpegDecoder {
594    codecs: BTreeMap<Format, AvCodec>,
595}
596
597impl FfmpegDecoder {
598    /// Create a new ffmpeg decoder backend instance.
599    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
638impl DecoderBackend for FfmpegDecoder {
639    type Session = FfmpegDecoderSession;
640
641    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
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)]
788mod tests {
789    use super::super::tests::*;
790    use super::*;
791
792    #[test]
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]
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]
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]
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]
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}