xref: /aosp_15_r20/external/crosvm/devices/src/virtio/video/decoder/backend/vaapi.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #![deny(missing_docs)]
6 
7 use std::collections::btree_map::Entry;
8 use std::collections::BTreeMap;
9 use std::collections::VecDeque;
10 use std::os::fd::FromRawFd;
11 use std::os::fd::OwnedFd;
12 use std::rc::Rc;
13 
14 use anyhow::anyhow;
15 use anyhow::Result;
16 use base::IntoRawDescriptor;
17 use base::MappedRegion;
18 use base::MemoryMappingArena;
19 use cros_codecs::decoder::stateless::h264::H264;
20 use cros_codecs::decoder::stateless::h265::H265;
21 use cros_codecs::decoder::stateless::vp8::Vp8;
22 use cros_codecs::decoder::stateless::vp9::Vp9;
23 use cros_codecs::decoder::stateless::DecodeError;
24 use cros_codecs::decoder::stateless::StatelessVideoDecoder;
25 use cros_codecs::decoder::DecodedHandle;
26 use cros_codecs::libva;
27 use cros_codecs::libva::Display;
28 use cros_codecs::multiple_desc_type;
29 use cros_codecs::utils::DmabufFrame;
30 use cros_codecs::DecodedFormat;
31 use cros_codecs::FrameLayout;
32 use cros_codecs::PlaneLayout;
33 
34 use crate::virtio::video::decoder::Capability;
35 use crate::virtio::video::decoder::DecoderBackend;
36 use crate::virtio::video::decoder::DecoderEvent;
37 use crate::virtio::video::decoder::DecoderSession;
38 use crate::virtio::video::error::VideoError;
39 use crate::virtio::video::error::VideoResult;
40 use crate::virtio::video::format::Format;
41 use crate::virtio::video::format::FormatDesc;
42 use crate::virtio::video::format::FormatRange;
43 use crate::virtio::video::format::FrameFormat;
44 use crate::virtio::video::format::Level;
45 use crate::virtio::video::format::Profile;
46 use crate::virtio::video::format::Rect;
47 use crate::virtio::video::resource::BufferHandle;
48 use crate::virtio::video::resource::GuestMemHandle;
49 use crate::virtio::video::resource::GuestResource;
50 use crate::virtio::video::resource::GuestResourceHandle;
51 use crate::virtio::video::utils::EventQueue;
52 
53 /// A guest memory descriptor that uses a managed buffer as a shadow that will be copied into the
54 /// guest memory once decoding is over.
55 struct GuestMemDescriptor(GuestMemHandle);
56 
57 impl libva::SurfaceMemoryDescriptor for GuestMemDescriptor {
add_attrs( &mut self, attrs: &mut Vec<libva::VASurfaceAttrib>, ) -> Option<Box<dyn std::any::Any>>58     fn add_attrs(
59         &mut self,
60         attrs: &mut Vec<libva::VASurfaceAttrib>,
61     ) -> Option<Box<dyn std::any::Any>> {
62         // Decode into a managed buffer.
63         ().add_attrs(attrs)
64     }
65 }
66 
67 multiple_desc_type! {
68     enum BufferDescriptor {
69         GuestMem(GuestMemDescriptor),
70         Dmabuf(DmabufFrame),
71     }
72 }
73 
74 struct BufferDescWithPicId {
75     desc: BufferDescriptor,
76     picture_buffer_id: i32,
77 }
78 
79 impl libva::SurfaceMemoryDescriptor for BufferDescWithPicId {
add_attrs( &mut self, attrs: &mut Vec<libva::VASurfaceAttrib>, ) -> Option<Box<dyn std::any::Any>>80     fn add_attrs(
81         &mut self,
82         attrs: &mut Vec<libva::VASurfaceAttrib>,
83     ) -> Option<Box<dyn std::any::Any>> {
84         self.desc.add_attrs(attrs)
85     }
86 }
87 
88 /// Represents a buffer we have not yet sent to the accelerator.
89 struct PendingJob {
90     resource_id: u32,
91     timestamp: u64,
92     resource: GuestResourceHandle,
93     offset: usize,
94     bytes_used: usize,
95     remaining: usize,
96 }
97 
98 impl TryFrom<DecodedFormat> for Format {
99     type Error = anyhow::Error;
100 
try_from(value: DecodedFormat) -> Result<Self, Self::Error>101     fn try_from(value: DecodedFormat) -> Result<Self, Self::Error> {
102         match value {
103             DecodedFormat::NV12 => Ok(Format::NV12),
104             _ => Err(anyhow!("Unsupported format")),
105         }
106     }
107 }
108 
109 impl TryFrom<Format> for DecodedFormat {
110     type Error = anyhow::Error;
111 
try_from(value: Format) -> Result<Self, Self::Error>112     fn try_from(value: Format) -> Result<Self, Self::Error> {
113         match value {
114             Format::NV12 => Ok(DecodedFormat::NV12),
115             _ => Err(anyhow!("Unsupported format")),
116         }
117     }
118 }
119 
120 impl TryFrom<libva::VAProfile::Type> for Profile {
121     type Error = anyhow::Error;
122 
try_from(value: libva::VAProfile::Type) -> Result<Self, Self::Error>123     fn try_from(value: libva::VAProfile::Type) -> Result<Self, Self::Error> {
124         match value {
125             libva::VAProfile::VAProfileH264Baseline => Ok(Self::H264Baseline),
126             libva::VAProfile::VAProfileH264Main => Ok(Self::H264Main),
127             libva::VAProfile::VAProfileH264High => Ok(Self::H264High),
128             libva::VAProfile::VAProfileH264StereoHigh => Ok(Self::H264StereoHigh),
129             libva::VAProfile::VAProfileH264MultiviewHigh => Ok(Self::H264MultiviewHigh),
130             libva::VAProfile::VAProfileHEVCMain => Ok(Self::HevcMain),
131             libva::VAProfile::VAProfileHEVCMain10 => Ok(Self::HevcMain10),
132             libva::VAProfile::VAProfileVP8Version0_3 => Ok(Self::VP8Profile0),
133             libva::VAProfile::VAProfileVP9Profile0 => Ok(Self::VP9Profile0),
134             libva::VAProfile::VAProfileVP9Profile1 => Ok(Self::VP9Profile1),
135             libva::VAProfile::VAProfileVP9Profile2 => Ok(Self::VP9Profile2),
136             libva::VAProfile::VAProfileVP9Profile3 => Ok(Self::VP9Profile3),
137             _ => Err(anyhow!(
138                 "Conversion failed for unexpected VAProfile: {}",
139                 value
140             )),
141         }
142     }
143 }
144 
145 /// The state for the output queue containing the buffers that will receive the
146 /// decoded data.
147 enum OutputQueueState {
148     /// Waiting for the client to call `set_output_buffer_count`.
149     AwaitingBufferCount,
150     /// Codec is capable of decoding frames.
151     Decoding,
152     /// Dynamic Resolution Change - we can still accept buffers in the old
153     /// format, but are waiting for new parameters before doing any decoding.
154     Drc,
155 }
156 
157 ///A safe decoder abstraction over libva for a single vaContext
158 pub struct VaapiDecoder {
159     /// The capabilities for the decoder
160     caps: Capability,
161 }
162 
163 // The VA capabilities for the coded side
164 struct CodedCap {
165     profile: libva::VAProfile::Type,
166     max_width: u32,
167     max_height: u32,
168 }
169 
170 // The VA capabilities for the raw side
171 struct RawCap {
172     fourcc: u32,
173     min_width: u32,
174     min_height: u32,
175     max_width: u32,
176     max_height: u32,
177 }
178 
179 impl VaapiDecoder {
180     // Query the capabilities for the coded format
get_coded_cap( display: &libva::Display, profile: libva::VAProfile::Type, ) -> Result<CodedCap>181     fn get_coded_cap(
182         display: &libva::Display,
183         profile: libva::VAProfile::Type,
184     ) -> Result<CodedCap> {
185         let mut attrs = vec![
186             libva::VAConfigAttrib {
187                 type_: libva::VAConfigAttribType::VAConfigAttribMaxPictureWidth,
188                 value: 0,
189             },
190             libva::VAConfigAttrib {
191                 type_: libva::VAConfigAttribType::VAConfigAttribMaxPictureHeight,
192                 value: 0,
193             },
194         ];
195 
196         display.get_config_attributes(profile, libva::VAEntrypoint::VAEntrypointVLD, &mut attrs)?;
197 
198         let mut max_width = 1u32;
199         let mut max_height = 1u32;
200 
201         for attr in &attrs {
202             if attr.value == libva::constants::VA_ATTRIB_NOT_SUPPORTED {
203                 continue;
204             }
205 
206             match attr.type_ {
207                 libva::VAConfigAttribType::VAConfigAttribMaxPictureWidth => max_width = attr.value,
208                 libva::VAConfigAttribType::VAConfigAttribMaxPictureHeight => {
209                     max_height = attr.value
210                 }
211 
212                 _ => panic!("Unexpected VAConfigAttribType {}", attr.type_),
213             }
214         }
215 
216         Ok(CodedCap {
217             profile,
218             max_width,
219             max_height,
220         })
221     }
222 
223     // Query the capabilities for the raw format
get_raw_caps(display: Rc<libva::Display>, coded_cap: &CodedCap) -> Result<Vec<RawCap>>224     fn get_raw_caps(display: Rc<libva::Display>, coded_cap: &CodedCap) -> Result<Vec<RawCap>> {
225         let mut raw_caps = Vec::new();
226 
227         let mut config = display.create_config(
228             vec![],
229             coded_cap.profile,
230             libva::VAEntrypoint::VAEntrypointVLD,
231         )?;
232 
233         let fourccs = config.query_surface_attributes_by_type(
234             libva::VASurfaceAttribType::VASurfaceAttribPixelFormat,
235         )?;
236 
237         for fourcc in fourccs {
238             let fourcc = match fourcc {
239                 libva::GenericValue::Integer(i) => i as u32,
240                 other => panic!("Unexpected VAGenericValue {:?}", other),
241             };
242 
243             let min_width = config.query_surface_attributes_by_type(
244                 libva::VASurfaceAttribType::VASurfaceAttribMinWidth,
245             )?;
246 
247             let min_width = match min_width.first() {
248                 Some(libva::GenericValue::Integer(i)) => *i as u32,
249                 Some(other) => panic!("Unexpected VAGenericValue {:?}", other),
250                 None => 1,
251             };
252 
253             let min_height = config.query_surface_attributes_by_type(
254                 libva::VASurfaceAttribType::VASurfaceAttribMinHeight,
255             )?;
256             let min_height = match min_height.first() {
257                 Some(libva::GenericValue::Integer(i)) => *i as u32,
258                 Some(other) => panic!("Unexpected VAGenericValue {:?}", other),
259                 None => 1,
260             };
261 
262             let max_width = config.query_surface_attributes_by_type(
263                 libva::VASurfaceAttribType::VASurfaceAttribMaxWidth,
264             )?;
265             let max_width = match max_width.first() {
266                 Some(libva::GenericValue::Integer(i)) => *i as u32,
267                 Some(other) => panic!("Unexpected VAGenericValue {:?}", other),
268                 None => coded_cap.max_width,
269             };
270 
271             let max_height = config.query_surface_attributes_by_type(
272                 libva::VASurfaceAttribType::VASurfaceAttribMaxHeight,
273             )?;
274             let max_height = match max_height.first() {
275                 Some(libva::GenericValue::Integer(i)) => *i as u32,
276                 Some(other) => panic!("Unexpected VAGenericValue {:?}", other),
277                 None => coded_cap.max_height,
278             };
279 
280             raw_caps.push(RawCap {
281                 fourcc,
282                 min_width,
283                 min_height,
284                 max_width,
285                 max_height,
286             });
287         }
288 
289         Ok(raw_caps)
290     }
291 
292     /// Creates a new instance of the Vaapi decoder.
new() -> Result<Self>293     pub fn new() -> Result<Self> {
294         let display = libva::Display::open().ok_or_else(|| anyhow!("failed to open VA display"))?;
295 
296         let va_profiles = display.query_config_profiles()?;
297 
298         let mut in_fmts = Vec::new();
299         let mut out_fmts = Vec::new();
300         let mut profiles_map: BTreeMap<Format, Vec<Profile>> = Default::default();
301 
302         // VA has no API for querying the levels supported by the driver.
303         // vaQueryProcessingRate is close, but not quite a solution here
304         // for all codecs.
305         let levels: BTreeMap<Format, Vec<Level>> = Default::default();
306 
307         for va_profile in va_profiles {
308             let mut profiles = Vec::new();
309 
310             let entrypoints = display.query_config_entrypoints(va_profile)?;
311             if !entrypoints
312                 .iter()
313                 .any(|e| *e == libva::VAEntrypoint::VAEntrypointVLD)
314             {
315                 // All formats we are aiming to support require
316                 // VAEntrypointVLD.
317                 continue;
318             }
319 
320             let profile = match Profile::try_from(va_profile) {
321                 Ok(p) => p,
322                 // Skip if we cannot convert to a valid virtio format
323                 Err(_) => continue,
324             };
325 
326             // Manually push all VP8 profiles, since VA exposes only a single
327             // VP8 profile for all of these
328             if va_profile == libva::VAProfile::VAProfileVP8Version0_3 {
329                 profiles.push(Profile::VP8Profile0);
330                 profiles.push(Profile::VP8Profile1);
331                 profiles.push(Profile::VP8Profile2);
332                 profiles.push(Profile::VP8Profile3);
333             } else {
334                 profiles.push(profile);
335             }
336 
337             let coded_cap = VaapiDecoder::get_coded_cap(display.as_ref(), va_profile)?;
338             let raw_caps = VaapiDecoder::get_raw_caps(Rc::clone(&display), &coded_cap)?;
339 
340             let coded_frame_fmt = FrameFormat {
341                 width: FormatRange {
342                     min: 1,
343                     max: coded_cap.max_width,
344                     step: 1,
345                 },
346 
347                 height: FormatRange {
348                     min: 1,
349                     max: coded_cap.max_height,
350                     step: 1,
351                 },
352 
353                 bitrates: Default::default(),
354             };
355 
356             let coded_format = profile.to_format();
357             match profiles_map.entry(coded_format) {
358                 Entry::Vacant(e) => {
359                     e.insert(profiles);
360                 }
361                 Entry::Occupied(mut ps) => {
362                     ps.get_mut().push(profile);
363                 }
364             }
365 
366             let mut n_out = 0;
367             for raw_cap in raw_caps {
368                 if raw_cap.fourcc != libva::constants::VA_FOURCC_NV12 {
369                     // Apparently only NV12 is currently supported by virtio video
370                     continue;
371                 }
372 
373                 let raw_frame_fmt = FrameFormat {
374                     width: FormatRange {
375                         min: raw_cap.min_width,
376                         max: raw_cap.max_width,
377                         step: 1,
378                     },
379 
380                     height: FormatRange {
381                         min: raw_cap.min_height,
382                         max: raw_cap.max_height,
383                         step: 1,
384                     },
385 
386                     bitrates: Default::default(),
387                 };
388 
389                 out_fmts.push(FormatDesc {
390                     mask: 0,
391                     format: Format::NV12,
392                     frame_formats: vec![raw_frame_fmt],
393                     plane_align: 1,
394                 });
395 
396                 n_out += 1;
397             }
398 
399             let mask = !(u64::MAX << n_out) << (out_fmts.len() - n_out);
400 
401             if mask != 0 {
402                 in_fmts.push(FormatDesc {
403                     mask,
404                     format: coded_format,
405                     frame_formats: vec![coded_frame_fmt],
406                     plane_align: 1,
407                 });
408             }
409         }
410 
411         Ok(Self {
412             caps: Capability::new(in_fmts, out_fmts, profiles_map, levels),
413         })
414     }
415 }
416 
417 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
418 pub struct Resolution {
419     width: u32,
420     height: u32,
421 }
422 
423 trait AsBufferHandle {
424     type BufferHandle: BufferHandle;
as_buffer_handle(&self) -> &Self::BufferHandle425     fn as_buffer_handle(&self) -> &Self::BufferHandle;
426 }
427 
428 impl AsBufferHandle for GuestResource {
429     type BufferHandle = GuestResourceHandle;
430 
as_buffer_handle(&self) -> &Self::BufferHandle431     fn as_buffer_handle(&self) -> &Self::BufferHandle {
432         &self.handle
433     }
434 }
435 
436 impl AsBufferHandle for GuestMemHandle {
437     type BufferHandle = Self;
438 
as_buffer_handle(&self) -> &Self::BufferHandle439     fn as_buffer_handle(&self) -> &Self::BufferHandle {
440         self
441     }
442 }
443 
444 impl AsBufferHandle for GuestResourceHandle {
445     type BufferHandle = Self;
446 
as_buffer_handle(&self) -> &Self::BufferHandle447     fn as_buffer_handle(&self) -> &Self::BufferHandle {
448         self
449     }
450 }
451 
452 /// A convenience type implementing persistent slice access for BufferHandles.
453 struct BufferMapping<'a, T: AsBufferHandle> {
454     #[allow(dead_code)]
455     /// The underlying resource. Must be kept so as not to drop the BufferHandle
456     resource: &'a T,
457     /// The mapping that backs the underlying slices returned by AsRef and AsMut
458     mapping: MemoryMappingArena,
459 }
460 
461 impl<'a, T: AsBufferHandle> BufferMapping<'a, T> {
462     /// Creates a new BufferMap
new(resource: &'a T, offset: usize, size: usize) -> Result<Self>463     pub fn new(resource: &'a T, offset: usize, size: usize) -> Result<Self> {
464         let mapping = resource.as_buffer_handle().get_mapping(offset, size)?;
465 
466         Ok(Self { resource, mapping })
467     }
468 }
469 
470 impl<'a, T: AsBufferHandle> AsRef<[u8]> for BufferMapping<'a, T> {
as_ref(&self) -> &[u8]471     fn as_ref(&self) -> &[u8] {
472         let mapping = &self.mapping;
473         // SAFETY:
474         // Safe because the mapping is linear and we own it, so it will not be unmapped during
475         // the lifetime of this slice.
476         unsafe { std::slice::from_raw_parts(mapping.as_ptr(), mapping.size()) }
477     }
478 }
479 
480 impl<'a, T: AsBufferHandle> AsMut<[u8]> for BufferMapping<'a, T> {
as_mut(&mut self) -> &mut [u8]481     fn as_mut(&mut self) -> &mut [u8] {
482         let mapping = &self.mapping;
483         // SAFETY:
484         // Safe because the mapping is linear and we own it, so it will not be unmapped during
485         // the lifetime of this slice.
486         unsafe { std::slice::from_raw_parts_mut(mapping.as_ptr(), mapping.size()) }
487     }
488 }
489 
490 /// A frame that is currently not available for being decoded into, either because it has been
491 /// decoded and is waiting for us to release it (`Decoded`), or because we temporarily removed it
492 /// from the decoder pool after a reset and are waiting for the client to tell us we can use it
493 /// (`Held`).
494 #[allow(dead_code)] // TODO: b/344974550
495 enum BorrowedFrame {
496     Decoded(Box<dyn DecodedHandle<Descriptor = BufferDescWithPicId>>),
497     Held(Box<dyn AsRef<BufferDescWithPicId>>),
498 }
499 
500 /// A decoder session for the libva backend
501 pub struct VaapiDecoderSession {
502     /// The implementation for the codec specific logic.
503     codec: Box<dyn StatelessVideoDecoder<BufferDescWithPicId>>,
504     /// The state for the output queue. Updated when `set_output_buffer_count`
505     /// is called or when we detect a dynamic resolution change.
506     output_queue_state: OutputQueueState,
507     /// Frames currently held by us, indexed by `picture_buffer_id`.
508     held_frames: BTreeMap<i32, BorrowedFrame>,
509     /// Queue containing the buffers we have not yet submitted to the codec.
510     submit_queue: VecDeque<PendingJob>,
511     /// The event queue we can use to signal new events.
512     event_queue: EventQueue<DecoderEvent>,
513     /// Whether the decoder is currently flushing.
514     flushing: bool,
515 }
516 
517 impl VaapiDecoderSession {
518     /// Copy raw decoded data from `image` into the output buffer
output_picture( decoded_frame: &dyn DecodedHandle<Descriptor = BufferDescWithPicId>, event_queue: &mut EventQueue<DecoderEvent>, ) -> Result<()>519     fn output_picture(
520         decoded_frame: &dyn DecodedHandle<Descriptor = BufferDescWithPicId>,
521         event_queue: &mut EventQueue<DecoderEvent>,
522     ) -> Result<()> {
523         let timestamp = decoded_frame.timestamp();
524 
525         let buffer_desc = decoded_frame.resource();
526         let picture_buffer_id = buffer_desc.picture_buffer_id;
527 
528         // Sync the frame if it is in guest memory, as we are going to map and read it.
529         // This statement is in its own block so we can drop the `buffer_desc` reference
530         // before calling `sync`, which does a mutable borrow.
531         if let BufferDescriptor::GuestMem(_) = &buffer_desc.desc {
532             drop(buffer_desc);
533             decoded_frame.sync()?;
534         }
535 
536         // Copy guest memory buffers into their destination.
537         if let BufferDescriptor::GuestMem(handle) = &decoded_frame.resource().desc {
538             let picture = decoded_frame.dyn_picture();
539             let mut backend_handle = picture.dyn_mappable_handle()?;
540             let buffer_size = backend_handle.image_size();
541 
542             // Get a mapping from the start of the buffer to the size of the
543             // underlying decoded data in the Image.
544             let mut output_map = BufferMapping::new(&handle.0, 0, buffer_size)?;
545             let output_bytes = output_map.as_mut();
546 
547             backend_handle.read(output_bytes)?;
548         }
549 
550         // Say that we are done decoding this picture.
551         event_queue
552             .queue_event(DecoderEvent::PictureReady {
553                 picture_buffer_id,
554                 timestamp,
555             })
556             .map_err(|e| {
557                 VideoError::BackendFailure(anyhow!("Can't queue the PictureReady event {}", e))
558             })?;
559 
560         Ok(())
561     }
562 
try_emit_flush_completed(&mut self) -> Result<()>563     fn try_emit_flush_completed(&mut self) -> Result<()> {
564         if self.submit_queue.is_empty() {
565             self.flushing = false;
566 
567             let event_queue = &mut self.event_queue;
568 
569             event_queue
570                 .queue_event(DecoderEvent::FlushCompleted(Ok(())))
571                 .map_err(|e| anyhow!("Can't queue the PictureReady event {}", e))
572         } else {
573             Ok(())
574         }
575     }
576 
drain_submit_queue(&mut self) -> VideoResult<()>577     fn drain_submit_queue(&mut self) -> VideoResult<()> {
578         while let Some(job) = self.submit_queue.front_mut() {
579             let bitstream_map = BufferMapping::new(&job.resource, job.offset, job.bytes_used)
580                 .map_err(VideoError::BackendFailure)?;
581 
582             let slice_start = job.bytes_used - job.remaining;
583             match self
584                 .codec
585                 .decode(job.timestamp, &bitstream_map.as_ref()[slice_start..])
586             {
587                 Ok(processed) => {
588                     job.remaining = job.remaining.saturating_sub(processed);
589                     // We have completed the buffer.
590                     if job.remaining == 0 {
591                         // We are always done with the input buffer after decode returns.
592                         self.event_queue
593                             .queue_event(DecoderEvent::NotifyEndOfBitstreamBuffer(job.resource_id))
594                             .map_err(|e| {
595                                 VideoError::BackendFailure(anyhow!(
596                                     "Can't queue the NotifyEndOfBitstream event {}",
597                                     e
598                                 ))
599                             })?;
600                         self.submit_queue.pop_front();
601                     }
602                 }
603                 Err(DecodeError::CheckEvents) => {
604                     self.process_decoder_events()?;
605                     break;
606                 }
607                 // We will succeed once buffers are returned by the client. This could be optimized
608                 // to only retry decoding once buffers are effectively returned.
609                 Err(DecodeError::NotEnoughOutputBuffers(_)) => break,
610                 // TODO add an InvalidInput error to cros-codecs so we can detect these cases and
611                 // just throw a warning instead of a fatal error?
612                 Err(e) => {
613                     self.event_queue
614                         .queue_event(DecoderEvent::NotifyError(VideoError::BackendFailure(
615                             anyhow!("Decoding buffer {} failed", job.resource_id),
616                         )))
617                         .map_err(|e| {
618                             VideoError::BackendFailure(anyhow!(
619                                 "Can't queue the NotifyError event {}",
620                                 e
621                             ))
622                         })?;
623                     return Err(VideoError::BackendFailure(e.into()));
624                 }
625             }
626         }
627 
628         Ok(())
629     }
630 
process_decoder_events(&mut self) -> VideoResult<()>631     fn process_decoder_events(&mut self) -> VideoResult<()> {
632         while let Some(event) = self.codec.next_event() {
633             match event {
634                 cros_codecs::decoder::DecoderEvent::FrameReady(frame) => {
635                     Self::output_picture(frame.as_ref(), &mut self.event_queue)
636                         .map_err(VideoError::BackendFailure)?;
637                     let picture_id = frame.resource().picture_buffer_id;
638                     self.held_frames
639                         .insert(picture_id, BorrowedFrame::Decoded(frame));
640                 }
641                 cros_codecs::decoder::DecoderEvent::FormatChanged(mut format) => {
642                     let coded_resolution = format.stream_info().coded_resolution;
643                     let display_resolution = format.stream_info().display_resolution;
644 
645                     // Ask the client for new buffers.
646                     self.event_queue
647                         .queue_event(DecoderEvent::ProvidePictureBuffers {
648                             min_num_buffers: format.stream_info().min_num_frames as u32,
649                             width: coded_resolution.width as i32,
650                             height: coded_resolution.height as i32,
651                             visible_rect: Rect {
652                                 left: 0,
653                                 top: 0,
654                                 right: display_resolution.width as i32,
655                                 bottom: display_resolution.height as i32,
656                             },
657                         })
658                         .map_err(|e| VideoError::BackendFailure(e.into()))?;
659 
660                     format.frame_pool().clear();
661 
662                     // Drop our output queue and wait for the new number of output buffers.
663                     self.output_queue_state = match &self.output_queue_state {
664                         // If this is part of the initialization step, then do not switch states.
665                         OutputQueueState::AwaitingBufferCount => {
666                             OutputQueueState::AwaitingBufferCount
667                         }
668                         OutputQueueState::Decoding => OutputQueueState::Drc,
669                         OutputQueueState::Drc => {
670                             return Err(VideoError::BackendFailure(anyhow!(
671                                 "Invalid state during DRC."
672                             )))
673                         }
674                     };
675                 }
676             }
677         }
678 
679         Ok(())
680     }
681 
try_make_progress(&mut self) -> VideoResult<()>682     fn try_make_progress(&mut self) -> VideoResult<()> {
683         self.process_decoder_events()?;
684         self.drain_submit_queue()?;
685 
686         Ok(())
687     }
688 }
689 
690 impl DecoderSession for VaapiDecoderSession {
set_output_parameters(&mut self, _: usize, _: Format) -> VideoResult<()>691     fn set_output_parameters(&mut self, _: usize, _: Format) -> VideoResult<()> {
692         let output_queue_state = &mut self.output_queue_state;
693 
694         // This logic can still be improved, in particular it needs better
695         // support at the virtio-video protocol level.
696         //
697         // We must ensure that set_output_parameters is only called after we are
698         // sure that we have processed some stream metadata, which currently is
699         // not the case. In particular, the {SET|GET}_PARAMS logic currently
700         // takes place *before* we had a chance to parse any stream metadata at
701         // all.
702         //
703         // This can lead to a situation where we accept a format (say, NV12),
704         // but then discover we are unable to decode it after processing some
705         // buffers (because the stream indicates that the bit depth is 10, for
706         // example). Note that there is no way to reject said stream as of right
707         // now unless we hardcode NV12 in cros-codecs itself.
708         //
709         // Nevertheless, the support is already in place in cros-codecs: the
710         // decoders will queue buffers until they read some metadata. At this
711         // point, it will allow for the negotiation of the decoded format until
712         // a new call to decode() is made. At the crosvm level, we can use this
713         // window of time to try different decoded formats with .try_format().
714         //
715         // For now, we accept the default format chosen by cros-codecs instead.
716         // In practice, this means NV12 if it the stream can be decoded into
717         // NV12 and if the hardware can do so.
718 
719         match output_queue_state {
720             OutputQueueState::AwaitingBufferCount | OutputQueueState::Drc => {
721                 // Accept the default format chosen by cros-codecs instead.
722                 //
723                 // if let Some(backend_format) = self.backend.backend().format() {
724                 //     let backend_format = Format::try_from(backend_format);
725 
726                 //     let format_matches = match backend_format {
727                 //         Ok(backend_format) => backend_format != format,
728                 //         Err(_) => false,
729                 //     };
730 
731                 //     if !format_matches {
732                 //         let format =
733                 //             DecodedFormat::try_from(format).map_err(VideoError::BackendFailure)?;
734 
735                 //         self.backend.backend().try_format(format).map_err(|e| {
736                 //             VideoError::BackendFailure(anyhow!(
737                 //                 "Failed to set the codec backend format: {}",
738                 //                 e
739                 //             ))
740                 //         })?;
741                 //     }
742                 // }
743 
744                 *output_queue_state = OutputQueueState::Decoding;
745 
746                 Ok(())
747             }
748             OutputQueueState::Decoding => {
749                 // Covers the slightly awkward ffmpeg v4l2 stateful
750                 // implementation for the capture queue setup.
751                 //
752                 // ffmpeg will queue a single OUTPUT buffer and immediately
753                 // follow up with a VIDIOC_G_FMT call on the CAPTURE queue.
754                 // This leads to a race condition, because it takes some
755                 // appreciable time for the real resolution to propagate back to
756                 // the guest as the virtio machinery processes and delivers the
757                 // event.
758                 //
759                 // In the event that VIDIOC_G_FMT(capture) returns the default
760                 // format, ffmpeg allocates buffers of the default resolution
761                 // (640x480) only to immediately reallocate as soon as it
762                 // processes the SRC_CH v4l2 event. Otherwise (if the resolution
763                 // has propagated in time), this path will not be taken during
764                 // the initialization.
765                 //
766                 // This leads to the following workflow in the virtio video
767                 // worker:
768                 // RESOURCE_QUEUE -> QUEUE_CLEAR -> RESOURCE_QUEUE
769                 //
770                 // Failing to accept this (as we previously did), leaves us
771                 // with bad state and completely breaks the decoding process. We
772                 // should replace the queue even if this is not 100% according
773                 // to spec.
774                 //
775                 // On the other hand, this branch still exists to highlight the
776                 // fact that we should assert that we have emitted a buffer with
777                 // the LAST flag when support for buffer flags is implemented in
778                 // a future CL. If a buffer with the LAST flag hasn't been
779                 // emitted, it's technically a mistake to be here because we
780                 // still have buffers of the old resolution to deliver.
781                 *output_queue_state = OutputQueueState::Decoding;
782 
783                 // TODO: check whether we have emitted a buffer with the LAST
784                 // flag before returning.
785                 Ok(())
786             }
787         }
788     }
789 
decode( &mut self, resource_id: u32, timestamp: u64, resource: GuestResourceHandle, offset: u32, bytes_used: u32, ) -> VideoResult<()>790     fn decode(
791         &mut self,
792         resource_id: u32,
793         timestamp: u64,
794         resource: GuestResourceHandle,
795         offset: u32,
796         bytes_used: u32,
797     ) -> VideoResult<()> {
798         let job = PendingJob {
799             resource_id,
800             timestamp,
801             resource,
802             offset: offset as usize,
803             bytes_used: bytes_used as usize,
804             remaining: bytes_used as usize,
805         };
806 
807         self.submit_queue.push_back(job);
808         self.try_make_progress()?;
809 
810         Ok(())
811     }
812 
flush(&mut self) -> VideoResult<()>813     fn flush(&mut self) -> VideoResult<()> {
814         self.flushing = true;
815 
816         self.try_make_progress()?;
817 
818         if !self.submit_queue.is_empty() {
819             return Ok(());
820         }
821 
822         // Retrieve ready frames from the codec, if any.
823         self.codec
824             .flush()
825             .map_err(|e| VideoError::BackendFailure(e.into()))?;
826         self.process_decoder_events()?;
827 
828         self.try_emit_flush_completed()
829             .map_err(VideoError::BackendFailure)
830     }
831 
reset(&mut self) -> VideoResult<()>832     fn reset(&mut self) -> VideoResult<()> {
833         self.submit_queue.clear();
834 
835         // Make sure the codec is not active.
836         self.codec
837             .flush()
838             .map_err(|e| VideoError::BackendFailure(e.into()))?;
839 
840         self.process_decoder_events()?;
841 
842         // Drop the queued output buffers.
843         self.clear_output_buffers()?;
844 
845         self.event_queue
846             .queue_event(DecoderEvent::ResetCompleted(Ok(())))
847             .map_err(|e| {
848                 VideoError::BackendFailure(anyhow!("Can't queue the ResetCompleted event {}", e))
849             })?;
850 
851         Ok(())
852     }
853 
clear_output_buffers(&mut self) -> VideoResult<()>854     fn clear_output_buffers(&mut self) -> VideoResult<()> {
855         // Cancel any ongoing flush.
856         self.flushing = false;
857 
858         // Drop all decoded frames signaled as ready and cancel any reported flush.
859         self.event_queue.retain(|event| {
860             !matches!(
861                 event,
862                 DecoderEvent::PictureReady { .. } | DecoderEvent::FlushCompleted(_)
863             )
864         });
865 
866         // Now hold all the imported frames until reuse_output_buffer is called on them.
867         let frame_pool = self.codec.frame_pool();
868         while let Some(frame) = frame_pool.take_free_frame() {
869             let picture_id = (*frame).as_ref().picture_buffer_id;
870             self.held_frames
871                 .insert(picture_id, BorrowedFrame::Held(frame));
872         }
873 
874         Ok(())
875     }
876 
event_pipe(&self) -> &dyn base::AsRawDescriptor877     fn event_pipe(&self) -> &dyn base::AsRawDescriptor {
878         &self.event_queue
879     }
880 
use_output_buffer( &mut self, picture_buffer_id: i32, resource: GuestResource, ) -> VideoResult<()>881     fn use_output_buffer(
882         &mut self,
883         picture_buffer_id: i32,
884         resource: GuestResource,
885     ) -> VideoResult<()> {
886         let output_queue_state = &mut self.output_queue_state;
887         if let OutputQueueState::Drc = output_queue_state {
888             // Reusing buffers during DRC is valid, but we won't use them and can just drop them.
889             return Ok(());
890         }
891 
892         let desc = match resource.handle {
893             GuestResourceHandle::GuestPages(handle) => {
894                 BufferDescriptor::GuestMem(GuestMemDescriptor(handle))
895             }
896             GuestResourceHandle::VirtioObject(handle) => {
897                 // SAFETY: descriptor is expected to be valid
898                 let fd = unsafe { OwnedFd::from_raw_fd(handle.desc.into_raw_descriptor()) };
899                 let modifier = handle.modifier;
900 
901                 let frame = DmabufFrame {
902                     fds: vec![fd],
903                     layout: FrameLayout {
904                         format: (cros_codecs::Fourcc::from(b"NV12"), modifier),
905                         size: cros_codecs::Resolution::from((resource.width, resource.height)),
906                         planes: resource
907                             .planes
908                             .iter()
909                             .map(|p| PlaneLayout {
910                                 buffer_index: 0,
911                                 offset: p.offset,
912                                 stride: p.stride,
913                             })
914                             .collect(),
915                     },
916                 };
917 
918                 BufferDescriptor::Dmabuf(frame)
919             }
920         };
921 
922         let desc_with_pic_id = BufferDescWithPicId {
923             desc,
924             picture_buffer_id,
925         };
926 
927         self.codec
928             .frame_pool()
929             .add_frames(vec![desc_with_pic_id])
930             .map_err(VideoError::BackendFailure)?;
931 
932         self.try_make_progress()
933     }
934 
reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()>935     fn reuse_output_buffer(&mut self, picture_buffer_id: i32) -> VideoResult<()> {
936         let output_queue_state = &mut self.output_queue_state;
937         if let OutputQueueState::Drc = output_queue_state {
938             // Reusing buffers during DRC is valid, but we won't use them and can just drop them.
939             return Ok(());
940         }
941 
942         self.held_frames.remove(&picture_buffer_id);
943 
944         self.try_make_progress()?;
945 
946         if self.flushing {
947             // Try flushing again now that we have a new buffer. This might let
948             // us progress further in the flush operation.
949             self.flush()?;
950         }
951         Ok(())
952     }
953 
read_event(&mut self) -> VideoResult<DecoderEvent>954     fn read_event(&mut self) -> VideoResult<DecoderEvent> {
955         self.event_queue
956             .dequeue_event()
957             .map_err(|e| VideoError::BackendFailure(anyhow!("Can't read event {}", e)))
958     }
959 }
960 
961 impl DecoderBackend for VaapiDecoder {
962     type Session = VaapiDecoderSession;
963 
get_capabilities(&self) -> Capability964     fn get_capabilities(&self) -> Capability {
965         self.caps.clone()
966     }
967 
new_session(&mut self, format: Format) -> VideoResult<Self::Session>968     fn new_session(&mut self, format: Format) -> VideoResult<Self::Session> {
969         let display = Display::open()
970             .ok_or_else(|| VideoError::BackendFailure(anyhow!("failed to open VA display")))?;
971 
972         let codec: Box<dyn StatelessVideoDecoder<BufferDescWithPicId>> = match format {
973             Format::VP8 => Box::new(
974                 cros_codecs::decoder::stateless::StatelessDecoder::<Vp8, _>::new_vaapi(
975                     display,
976                     cros_codecs::decoder::BlockingMode::NonBlocking,
977                 ),
978             ),
979             Format::VP9 => Box::new(
980                 cros_codecs::decoder::stateless::StatelessDecoder::<Vp9, _>::new_vaapi(
981                     display,
982                     cros_codecs::decoder::BlockingMode::NonBlocking,
983                 ),
984             ),
985             Format::H264 => Box::new(
986                 cros_codecs::decoder::stateless::StatelessDecoder::<H264, _>::new_vaapi(
987                     display,
988                     cros_codecs::decoder::BlockingMode::NonBlocking,
989                 ),
990             ),
991             Format::Hevc => Box::new(
992                 cros_codecs::decoder::stateless::StatelessDecoder::<H265, _>::new_vaapi(
993                     display,
994                     cros_codecs::decoder::BlockingMode::NonBlocking,
995                 ),
996             ),
997             _ => return Err(VideoError::InvalidFormat),
998         };
999 
1000         Ok(VaapiDecoderSession {
1001             codec,
1002             output_queue_state: OutputQueueState::AwaitingBufferCount,
1003             held_frames: Default::default(),
1004             submit_queue: Default::default(),
1005             event_queue: EventQueue::new().map_err(|e| VideoError::BackendFailure(anyhow!(e)))?,
1006             flushing: Default::default(),
1007         })
1008     }
1009 }
1010 
1011 #[cfg(test)]
1012 mod tests {
1013     use super::super::tests::*;
1014     use super::*;
1015 
1016     #[test]
1017     // Ignore this test by default as it requires libva-compatible hardware.
1018     #[ignore]
test_get_capabilities()1019     fn test_get_capabilities() {
1020         let decoder = VaapiDecoder::new().unwrap();
1021         let caps = decoder.get_capabilities();
1022         assert!(!caps.input_formats().is_empty());
1023         assert!(!caps.output_formats().is_empty());
1024     }
1025 
1026     // Decode using guest memory input and output buffers.
1027     #[test]
1028     // Ignore this test by default as it requires libva-compatible hardware.
1029     #[ignore]
test_decode_h264_guestmem_to_guestmem()1030     fn test_decode_h264_guestmem_to_guestmem() {
1031         decode_h264_generic(
1032             &mut VaapiDecoder::new().unwrap(),
1033             build_guest_mem_handle,
1034             build_guest_mem_handle,
1035         );
1036     }
1037 }
1038