Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/video/decoder/backend/ffmpeg.rs
5394 views
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 {
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 {
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.
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.
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
418
impl 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
593
pub struct FfmpegDecoder {
594
codecs: BTreeMap<Format, AvCodec>,
595
}
596
597
impl 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
638
impl 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
AV_PROFILE_H264_BASELINE => Some(Profile::H264Baseline),
660
AV_PROFILE_H264_MAIN => Some(Profile::H264Main),
661
AV_PROFILE_H264_EXTENDED => Some(Profile::H264Extended),
662
AV_PROFILE_H264_HIGH => Some(Profile::H264High),
663
AV_PROFILE_H264_HIGH_10 => Some(Profile::H264High10),
664
AV_PROFILE_H264_HIGH_422 => Some(Profile::H264High422),
665
AV_PROFILE_H264_HIGH_444_PREDICTIVE => {
666
Some(Profile::H264High444PredictiveProfile)
667
}
668
AV_PROFILE_H264_STEREO_HIGH => Some(Profile::H264StereoHigh),
669
AV_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
AV_PROFILE_VP9_0 => Some(Profile::VP9Profile0),
689
AV_PROFILE_VP9_1 => Some(Profile::VP9Profile1),
690
AV_PROFILE_VP9_2 => Some(Profile::VP9Profile2),
691
AV_PROFILE_VP9_3 => Some(Profile::VP9Profile3),
692
_ => None,
693
})
694
.collect(),
695
Format::Hevc => profile_iter
696
.filter_map(|p| match p.profile() {
697
AV_PROFILE_HEVC_MAIN => Some(Profile::HevcMain),
698
AV_PROFILE_HEVC_MAIN_10 => Some(Profile::HevcMain10),
699
AV_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)]
788
mod 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
}
839
840