• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::cell::RefCell;
6 use std::collections::HashSet;
7 use std::collections::VecDeque;
8 use std::fmt::Debug;
9 use std::rc::Rc;
10 
11 use anyhow::anyhow;
12 use anyhow::Result;
13 use libva::Config;
14 use libva::Context;
15 use libva::Display;
16 use libva::Image;
17 use libva::PictureEnd;
18 use libva::PictureNew;
19 use libva::PictureSync;
20 use libva::Surface;
21 use libva::VAConfigAttrib;
22 use libva::VAConfigAttribType;
23 
24 use crate::decoders::BlockingMode;
25 use crate::decoders::DecodedHandle as DecodedHandleTrait;
26 use crate::decoders::DynHandle;
27 use crate::decoders::Error as VideoDecoderError;
28 use crate::decoders::MappableHandle;
29 use crate::decoders::Result as VideoDecoderResult;
30 use crate::decoders::StatelessBackendError;
31 use crate::decoders::StatelessBackendResult;
32 use crate::decoders::VideoDecoderBackend;
33 use crate::i420_copy;
34 use crate::nv12_copy;
35 use crate::DecodedFormat;
36 use crate::Resolution;
37 
38 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
39 pub struct FormatMap {
40     pub rt_format: u32,
41     pub va_fourcc: u32,
42     pub decoded_format: DecodedFormat,
43 }
44 
45 /// Maps a given VA_RT_FORMAT to a compatible decoded format in an arbitrary
46 /// preferred order.
47 pub const FORMAT_MAP: [FormatMap; 2] = [
48     FormatMap {
49         rt_format: libva::constants::VA_RT_FORMAT_YUV420,
50         va_fourcc: libva::constants::VA_FOURCC_NV12,
51         decoded_format: DecodedFormat::NV12,
52     },
53     FormatMap {
54         rt_format: libva::constants::VA_RT_FORMAT_YUV420,
55         va_fourcc: libva::constants::VA_FOURCC_I420,
56         decoded_format: DecodedFormat::I420,
57     },
58 ];
59 
60 /// Returns a set of supported decoded formats given `rt_format`
supported_formats_for_rt_format( display: Rc<Display>, rt_format: u32, profile: i32, entrypoint: u32, image_formats: &[libva::VAImageFormat], ) -> Result<HashSet<FormatMap>>61 fn supported_formats_for_rt_format(
62     display: Rc<Display>,
63     rt_format: u32,
64     profile: i32,
65     entrypoint: u32,
66     image_formats: &[libva::VAImageFormat],
67 ) -> Result<HashSet<FormatMap>> {
68     let mut attrs = vec![VAConfigAttrib {
69         type_: VAConfigAttribType::VAConfigAttribRTFormat,
70         value: 0,
71     }];
72 
73     display.get_config_attributes(profile, entrypoint, &mut attrs)?;
74 
75     // See whether this RT_FORMAT is supported by the given VAProfile and
76     // VAEntrypoint pair.
77     if attrs[0].value == libva::constants::VA_ATTRIB_NOT_SUPPORTED
78         || attrs[0].value & rt_format == 0
79     {
80         return Err(anyhow!(
81             "rt_format {:?} not supported for profile {:?} and entrypoint {:?}",
82             rt_format,
83             profile,
84             entrypoint
85         ));
86     }
87 
88     let mut supported_formats = HashSet::new();
89 
90     for format in FORMAT_MAP {
91         if format.rt_format == rt_format {
92             supported_formats.insert(format);
93         }
94     }
95 
96     // Only retain those that the hardware can actually map into.
97     supported_formats.retain(|&entry| {
98         image_formats
99             .iter()
100             .any(|fmt| fmt.fourcc == entry.va_fourcc)
101     });
102 
103     Ok(supported_formats)
104 }
105 
106 impl TryInto<Option<Surface>> for PictureState {
107     type Error = anyhow::Error;
108 
try_into(self) -> Result<Option<Surface>, Self::Error>109     fn try_into(self) -> Result<Option<Surface>, Self::Error> {
110         match self {
111             PictureState::Ready { picture, .. } => picture.take_surface().map(Some),
112             PictureState::Pending { surface_id, .. } => Err(anyhow!(
113                 "Attempting to retrieve a surface (id: {:?}) that might have operations pending.",
114                 surface_id
115             )),
116             PictureState::Invalid => unreachable!(),
117         }
118     }
119 }
120 
121 /// A decoded frame handle.
122 pub struct DecodedHandle {
123     /// The actual object backing the handle.
124     inner: Rc<RefCell<GenericBackendHandle>>,
125     /// The timestamp of the input buffer that produced this frame.
126     timestamp: u64,
127     /// A monotonically increasing counter that denotes the display order of
128     /// this handle in comparison with other handles.
129     pub display_order: Option<u64>,
130 }
131 
132 impl Clone for DecodedHandle {
133     // See https://stegosaurusdormant.com/understanding-derive-clone/ on why
134     // this cannot be derived. Note that T probably doesn't implement Clone, but
135     // it's not a problem, since Rc is Clone.
clone(&self) -> Self136     fn clone(&self) -> Self {
137         DecodedHandle {
138             inner: self.inner.clone(),
139             timestamp: self.timestamp,
140             display_order: self.display_order,
141         }
142     }
143 }
144 
145 impl DecodedHandle {
146     /// Creates a new handle
new(inner: Rc<RefCell<GenericBackendHandle>>, timestamp: u64) -> Self147     pub fn new(inner: Rc<RefCell<GenericBackendHandle>>, timestamp: u64) -> Self {
148         Self {
149             inner,
150             timestamp,
151             display_order: None,
152         }
153     }
154 }
155 
156 impl DecodedHandleTrait for DecodedHandle {
157     type BackendHandle = GenericBackendHandle;
158 
handle_rc(&self) -> &Rc<RefCell<Self::BackendHandle>>159     fn handle_rc(&self) -> &Rc<RefCell<Self::BackendHandle>> {
160         &self.inner
161     }
162 
display_order(&self) -> Option<u64>163     fn display_order(&self) -> Option<u64> {
164         self.display_order
165     }
166 
set_display_order(&mut self, display_order: u64)167     fn set_display_order(&mut self, display_order: u64) {
168         self.display_order = Some(display_order)
169     }
170 
display_resolution(&self) -> Resolution171     fn display_resolution(&self) -> Resolution {
172         self.handle().resolution
173     }
174 
timestamp(&self) -> u64175     fn timestamp(&self) -> u64 {
176         self.timestamp
177     }
178 }
179 
180 /// A surface pool handle to reduce the number of costly Surface allocations.
181 #[derive(Clone)]
182 pub struct SurfacePoolHandle {
183     surfaces: Rc<RefCell<VecDeque<Surface>>>,
184     coded_resolution: Resolution,
185 }
186 
187 impl SurfacePoolHandle {
188     /// Creates a new pool
new(surfaces: Vec<Surface>, resolution: Resolution) -> Self189     pub fn new(surfaces: Vec<Surface>, resolution: Resolution) -> Self {
190         Self {
191             surfaces: Rc::new(RefCell::new(VecDeque::from(surfaces))),
192             coded_resolution: resolution,
193         }
194     }
195 
196     /// Retrieve the current coded resolution of the pool
coded_resolution(&self) -> Resolution197     pub fn coded_resolution(&self) -> Resolution {
198         self.coded_resolution
199     }
200 
201     /// Adds a new surface to the pool
add_surface(&mut self, surface: Surface)202     pub fn add_surface(&mut self, surface: Surface) {
203         self.surfaces.borrow_mut().push_back(surface)
204     }
205 
206     /// Gets a free surface from the pool
get_surface(&mut self) -> Option<Surface>207     pub fn get_surface(&mut self) -> Option<Surface> {
208         let mut vec = self.surfaces.borrow_mut();
209         vec.pop_front()
210     }
211 
212     /// Returns new number of surfaces left.
num_surfaces_left(&self) -> usize213     pub fn num_surfaces_left(&self) -> usize {
214         self.surfaces.borrow().len()
215     }
216 }
217 
218 /// A trait for providing the basic information needed to setup libva for decoding.
219 pub(crate) trait StreamInfo {
220     /// Returns the VA profile of the stream.
va_profile(&self) -> anyhow::Result<i32>221     fn va_profile(&self) -> anyhow::Result<i32>;
222     /// Returns the RT format of the stream.
rt_format(&self) -> anyhow::Result<u32>223     fn rt_format(&self) -> anyhow::Result<u32>;
224     /// Returns the minimum number of surfaces required to decode the stream.
min_num_surfaces(&self) -> usize225     fn min_num_surfaces(&self) -> usize;
226     /// Returns the coded size of the surfaces required to decode the stream.
coded_size(&self) -> (u32, u32)227     fn coded_size(&self) -> (u32, u32);
228     /// Returns the visible rectangle within the coded size for the stream.
visible_rect(&self) -> ((u32, u32), (u32, u32))229     fn visible_rect(&self) -> ((u32, u32), (u32, u32));
230 }
231 
232 pub(crate) struct ParsedStreamMetadata {
233     /// A VAContext from which we can decode from.
234     pub(crate) context: Rc<Context>,
235     /// The VAConfig that created the context. It must kept here so that
236     /// it does not get dropped while it is in use.
237     #[allow(dead_code)]
238     config: Config,
239     /// A pool of surfaces. We reuse surfaces as they are expensive to allocate.
240     pub(crate) surface_pool: SurfacePoolHandle,
241     /// The number of surfaces required to parse the stream.
242     pub(crate) min_num_surfaces: usize,
243     /// The decoder current display resolution.
244     pub(crate) display_resolution: Resolution,
245     /// The image format we will use to map the surfaces. This is usually the
246     /// same as the surface's internal format, but occasionally we can try
247     /// mapping in a different format if requested and if the VA-API driver can
248     /// do it.
249     pub(crate) map_format: Rc<libva::VAImageFormat>,
250     /// The rt_format parsed from the stream.
251     pub(crate) rt_format: u32,
252     /// The profile parsed from the stream.
253     pub(crate) profile: i32,
254 }
255 
256 /// State of the input stream, which can be either unparsed (we don't know the stream properties
257 /// yet) or parsed (we know the stream properties and are ready to decode).
258 pub(crate) enum StreamMetadataState {
259     /// The metadata for the current stream has not yet been parsed.
260     Unparsed { display: Rc<Display> },
261     /// The metadata for the current stream has been parsed and a suitable
262     /// VAContext has been created to accomodate it.
263     Parsed(ParsedStreamMetadata),
264 }
265 
266 impl StreamMetadataState {
display(&self) -> Rc<libva::Display>267     pub(crate) fn display(&self) -> Rc<libva::Display> {
268         match self {
269             StreamMetadataState::Unparsed { display } => Rc::clone(display),
270             StreamMetadataState::Parsed(ParsedStreamMetadata { context, .. }) => context.display(),
271         }
272     }
273 
274     /// Returns a reference to the parsed metadata state or an error if we haven't reached that
275     /// state yet.
get_parsed(&self) -> Result<&ParsedStreamMetadata>276     pub(crate) fn get_parsed(&self) -> Result<&ParsedStreamMetadata> {
277         match self {
278             StreamMetadataState::Unparsed { .. } => Err(anyhow!("Stream metadata not parsed yet")),
279             StreamMetadataState::Parsed(parsed_metadata) => Ok(parsed_metadata),
280         }
281     }
282 
283     /// Returns a mutable reference to the parsed metadata state or an error if we haven't reached
284     /// that state yet.
get_parsed_mut(&mut self) -> Result<&mut ParsedStreamMetadata>285     pub(crate) fn get_parsed_mut(&mut self) -> Result<&mut ParsedStreamMetadata> {
286         match self {
287             StreamMetadataState::Unparsed { .. } => Err(anyhow!("Stream metadata not parsed yet")),
288             StreamMetadataState::Parsed(parsed_metadata) => Ok(parsed_metadata),
289         }
290     }
291 
292     /// Gets a set of supported formats for the particular stream being
293     /// processed. This requires that some buffers be processed before this call
294     /// is made. Only formats that are compatible with the current color space,
295     /// bit depth, and chroma format are returned such that no conversion is
296     /// needed.
supported_formats_for_stream(&self) -> Result<HashSet<DecodedFormat>>297     pub(crate) fn supported_formats_for_stream(&self) -> Result<HashSet<DecodedFormat>> {
298         let metadata = self.get_parsed()?;
299         let display = self.display();
300 
301         let image_formats = display.query_image_formats()?;
302 
303         let formats = supported_formats_for_rt_format(
304             display,
305             metadata.rt_format,
306             metadata.profile,
307             libva::VAEntrypoint::VAEntrypointVLD,
308             &image_formats,
309         )?;
310 
311         Ok(formats.into_iter().map(|f| f.decoded_format).collect())
312     }
313 
314     /// Initializes or reinitializes the codec state.
open<S: StreamInfo>( &mut self, hdr: S, format_map: Option<&FormatMap>, ) -> Result<()>315     pub(crate) fn open<S: StreamInfo>(
316         &mut self,
317         hdr: S,
318         format_map: Option<&FormatMap>,
319     ) -> Result<()> {
320         let display = self.display();
321         let va_profile = hdr.va_profile()?;
322         let rt_format = hdr.rt_format()?;
323         let (frame_w, frame_h) = hdr.coded_size();
324 
325         let attrs = vec![libva::VAConfigAttrib {
326             type_: libva::VAConfigAttribType::VAConfigAttribRTFormat,
327             value: rt_format,
328         }];
329 
330         let config =
331             display.create_config(attrs, va_profile, libva::VAEntrypoint::VAEntrypointVLD)?;
332 
333         let format_map = if let Some(format_map) = format_map {
334             format_map
335         } else {
336             // Pick the first one that fits
337             FORMAT_MAP
338                 .iter()
339                 .find(|&map| map.rt_format == rt_format)
340                 .ok_or(anyhow!("Unsupported format {}", rt_format))?
341         };
342 
343         let map_format = display
344             .query_image_formats()?
345             .iter()
346             .find(|f| f.fourcc == format_map.va_fourcc)
347             .cloned()
348             .unwrap();
349 
350         let min_num_surfaces = hdr.min_num_surfaces();
351 
352         let surfaces = display.create_surfaces(
353             rt_format,
354             Some(map_format.fourcc),
355             frame_w,
356             frame_h,
357             Some(libva::UsageHint::USAGE_HINT_DECODER),
358             min_num_surfaces as u32,
359         )?;
360 
361         let context = display.create_context(
362             &config,
363             i32::try_from(frame_w)?,
364             i32::try_from(frame_h)?,
365             Some(&surfaces),
366             true,
367         )?;
368 
369         let coded_resolution = Resolution {
370             width: frame_w,
371             height: frame_h,
372         };
373 
374         let visible_rect = hdr.visible_rect();
375 
376         let display_resolution = Resolution {
377             width: visible_rect.1 .0 - visible_rect.0 .0,
378             height: visible_rect.1 .1 - visible_rect.0 .1,
379         };
380 
381         let surface_pool = SurfacePoolHandle::new(surfaces, coded_resolution);
382 
383         *self = StreamMetadataState::Parsed(ParsedStreamMetadata {
384             context,
385             config,
386             surface_pool,
387             min_num_surfaces,
388             display_resolution,
389             map_format: Rc::new(map_format),
390             rt_format,
391             profile: va_profile,
392         });
393 
394         Ok(())
395     }
396 }
397 
398 /// VA-API backend handle.
399 ///
400 /// This includes the VA picture which can be pending rendering or complete, as well as useful
401 /// meta-information.
402 pub struct GenericBackendHandle {
403     state: PictureState,
404     /// The decoder resolution when this frame was processed. Not all codecs
405     /// send resolution data in every frame header.
406     resolution: Resolution,
407     /// A handle to the surface pool from which the backing surface originates.
408     surface_pool: SurfacePoolHandle,
409 }
410 
411 impl Drop for GenericBackendHandle {
drop(&mut self)412     fn drop(&mut self) {
413         // Take ownership of the internal state.
414         let state = std::mem::replace(&mut self.state, PictureState::Invalid);
415         if self.surface_pool.coded_resolution() == self.resolution {
416             if let Ok(Some(surface)) = state.try_into() {
417                 self.surface_pool.add_surface(surface);
418             }
419         }
420     }
421 }
422 
423 impl GenericBackendHandle {
424     /// Creates a new pending handle on `surface_id`.
new_pending( picture: libva::Picture<PictureNew>, surface_pool: SurfacePoolHandle, ) -> Result<Self>425     pub(crate) fn new_pending(
426         picture: libva::Picture<PictureNew>,
427         surface_pool: SurfacePoolHandle,
428     ) -> Result<Self> {
429         let surface_id = picture.surface().id();
430         let picture = picture.begin()?.render()?.end()?;
431         Ok(Self {
432             state: PictureState::Pending {
433                 picture,
434                 surface_id,
435             },
436             resolution: surface_pool.coded_resolution(),
437             surface_pool,
438         })
439     }
440 
sync(&mut self, metadata: &ParsedStreamMetadata) -> Result<()>441     pub(crate) fn sync(&mut self, metadata: &ParsedStreamMetadata) -> Result<()> {
442         match std::mem::replace(&mut self.state, PictureState::Invalid) {
443             state @ PictureState::Ready { .. } => self.state = state,
444             PictureState::Pending { picture, .. } => {
445                 let picture = picture.sync()?;
446                 self.state = PictureState::Ready {
447                     map_format: Rc::clone(&metadata.map_format),
448                     picture,
449                     display_resolution: metadata.display_resolution,
450                 };
451             }
452             PictureState::Invalid => unreachable!(),
453         }
454 
455         Ok(())
456     }
457 
458     /// Returns a mapped VAImage. this maps the VASurface onto our address space.
459     /// This can be used in place of "DynMappableHandle::map()" if the client
460     /// wants to access the backend mapping directly for any reason.
461     ///
462     /// Note that DynMappableHandle is downcastable.
image(&mut self) -> Result<Image>463     pub fn image(&mut self) -> Result<Image> {
464         match &mut self.state {
465             PictureState::Ready {
466                 map_format,
467                 picture,
468                 display_resolution,
469                 ..
470             } => {
471                 // Get the associated VAImage, which will map the
472                 // VASurface onto our address space.
473                 let image = libva::Image::new(
474                     picture,
475                     *map_format.clone(),
476                     display_resolution.width,
477                     display_resolution.height,
478                     false,
479                 )?;
480 
481                 Ok(image)
482             }
483             PictureState::Pending { .. } => Err(anyhow!("Mapping failed")),
484             PictureState::Invalid => unreachable!(),
485         }
486     }
487 
488     /// Returns the picture of this handle.
picture(&self) -> Option<&libva::Picture<PictureSync>>489     pub fn picture(&self) -> Option<&libva::Picture<PictureSync>> {
490         match &self.state {
491             PictureState::Ready { picture, .. } => Some(picture),
492             PictureState::Pending { .. } => None,
493             PictureState::Invalid => unreachable!(),
494         }
495     }
496 
497     /// Returns the id of the VA surface backing this handle.
surface_id(&self) -> libva::VASurfaceID498     pub fn surface_id(&self) -> libva::VASurfaceID {
499         match &self.state {
500             PictureState::Ready { picture, .. } => picture.surface().id(),
501             PictureState::Pending { surface_id, .. } => *surface_id,
502             PictureState::Invalid => unreachable!(),
503         }
504     }
505 
506     /// Returns `true` if this handle is ready.
is_ready(&self) -> bool507     pub fn is_ready(&self) -> bool {
508         matches!(self.state, PictureState::Ready { .. })
509     }
510 
is_va_ready(&self) -> Result<bool>511     pub fn is_va_ready(&self) -> Result<bool> {
512         match &self.state {
513             PictureState::Ready { .. } => Ok(true),
514             PictureState::Pending { picture, .. } => picture
515                 .query_status()
516                 .map(|s| s == libva::VASurfaceStatus::VASurfaceReady),
517             PictureState::Invalid => unreachable!(),
518         }
519     }
520 }
521 
522 /// Rendering state of a VA picture.
523 enum PictureState {
524     Ready {
525         map_format: Rc<libva::VAImageFormat>,
526         picture: libva::Picture<PictureSync>,
527         display_resolution: Resolution,
528     },
529     Pending {
530         /// Submitted VA picture pending completion.
531         picture: libva::Picture<PictureEnd>,
532         /// VA surface ID for `picture`.
533         surface_id: u32,
534     },
535     // Only set in the destructor when we take ownership of the VA picture.
536     Invalid,
537 }
538 
539 impl<'a> MappableHandle for Image<'a> {
read(&mut self, buffer: &mut [u8]) -> VideoDecoderResult<()>540     fn read(&mut self, buffer: &mut [u8]) -> VideoDecoderResult<()> {
541         let image_size = self.image_size();
542         let image_inner = self.image();
543 
544         let width = image_inner.width as u32;
545         let height = image_inner.height as u32;
546 
547         if buffer.len() != image_size {
548             return Err(VideoDecoderError::StatelessBackendError(
549                 StatelessBackendError::Other(anyhow!(
550                     "buffer size is {} while image size is {}",
551                     buffer.len(),
552                     image_size
553                 )),
554             ));
555         }
556 
557         match image_inner.format.fourcc {
558             libva::constants::VA_FOURCC_NV12 => {
559                 nv12_copy(
560                     self.as_ref(),
561                     buffer,
562                     width,
563                     height,
564                     image_inner.pitches,
565                     image_inner.offsets,
566                 );
567             }
568             libva::constants::VA_FOURCC_I420 => {
569                 i420_copy(
570                     self.as_ref(),
571                     buffer,
572                     width,
573                     height,
574                     image_inner.pitches,
575                     image_inner.offsets,
576                 );
577             }
578             _ => {
579                 return Err(crate::decoders::Error::StatelessBackendError(
580                     StatelessBackendError::UnsupportedFormat,
581                 ))
582             }
583         }
584 
585         Ok(())
586     }
587 
image_size(&mut self) -> usize588     fn image_size(&mut self) -> usize {
589         let image = self.image();
590 
591         crate::decoded_frame_size(
592             (&image.format).try_into().unwrap(),
593             image.width,
594             image.height,
595         )
596     }
597 }
598 
599 impl DynHandle for GenericBackendHandle {
dyn_mappable_handle_mut<'a>(&'a mut self) -> Box<dyn MappableHandle + 'a>600     fn dyn_mappable_handle_mut<'a>(&'a mut self) -> Box<dyn MappableHandle + 'a> {
601         Box::new(self.image().unwrap())
602     }
603 }
604 
605 impl TryFrom<&libva::VAImageFormat> for DecodedFormat {
606     type Error = anyhow::Error;
607 
try_from(value: &libva::VAImageFormat) -> Result<Self, Self::Error>608     fn try_from(value: &libva::VAImageFormat) -> Result<Self, Self::Error> {
609         match value.fourcc {
610             libva::constants::VA_FOURCC_NV12 => Ok(DecodedFormat::NV12),
611             libva::constants::VA_FOURCC_I420 => Ok(DecodedFormat::I420),
612             _ => Err(anyhow!("Unsupported format")),
613         }
614     }
615 }
616 
617 /// Keeps track of where the backend is in the negotiation process.
618 ///
619 /// The generic parameter is the data that the decoder wishes to pass from the `Possible` to the
620 /// `Negotiated` state - typically, the properties of the stream like its resolution as they have
621 /// been parsed.
622 #[derive(Clone, Default)]
623 pub(crate) enum NegotiationStatus<T> {
624     /// No property about the stream has been parsed yet.
625     #[default]
626     NonNegotiated,
627     /// Properties of the stream have been parsed and the client may query and change them.
628     Possible(T),
629     /// Stream is actively decoding and its properties cannot be changed by the client.
630     Negotiated,
631 }
632 
633 impl<T> Debug for NegotiationStatus<T> {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result634     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
635         match self {
636             NegotiationStatus::NonNegotiated => write!(f, "NonNegotiated"),
637             NegotiationStatus::Possible(_) => write!(f, "Possible"),
638             NegotiationStatus::Negotiated => write!(f, "Negotiated"),
639         }
640     }
641 }
642 
643 pub(crate) struct VaapiBackend<StreamData>
644 where
645     for<'a> &'a StreamData: StreamInfo,
646 {
647     /// The metadata state. Updated whenever the decoder reads new data from the stream.
648     pub(crate) metadata_state: StreamMetadataState,
649     /// The negotiation status
650     pub(crate) negotiation_status: NegotiationStatus<Box<StreamData>>,
651     /// The FIFO for all pending pictures, in the order they were submitted.
652     pub(crate) pending_jobs: VecDeque<Rc<RefCell<GenericBackendHandle>>>,
653 }
654 
655 impl<StreamData> VaapiBackend<StreamData>
656 where
657     for<'a> &'a StreamData: StreamInfo,
658 {
new(display: Rc<libva::Display>) -> Self659     pub(crate) fn new(display: Rc<libva::Display>) -> Self {
660         Self {
661             metadata_state: StreamMetadataState::Unparsed { display },
662             pending_jobs: Default::default(),
663             negotiation_status: NegotiationStatus::NonNegotiated,
664         }
665     }
666 
process_picture( &mut self, picture: libva::Picture<PictureNew>, block: BlockingMode, ) -> StatelessBackendResult<<Self as VideoDecoderBackend>::Handle>667     pub(crate) fn process_picture(
668         &mut self,
669         picture: libva::Picture<PictureNew>,
670         block: BlockingMode,
671     ) -> StatelessBackendResult<<Self as VideoDecoderBackend>::Handle> {
672         let metadata = self.metadata_state.get_parsed()?;
673         let timestamp = picture.timestamp();
674 
675         let handle = Rc::new(RefCell::new(GenericBackendHandle::new_pending(
676             picture,
677             metadata.surface_pool.clone(),
678         )?));
679 
680         match block {
681             BlockingMode::Blocking => handle.borrow_mut().sync(metadata)?,
682             BlockingMode::NonBlocking => self.pending_jobs.push_back(Rc::clone(&handle)),
683         }
684 
685         Ok(self.build_va_decoded_handle(handle, timestamp))
686     }
687 
build_va_decoded_handle( &self, picture: Rc<RefCell<GenericBackendHandle>>, timestamp: u64, ) -> <Self as VideoDecoderBackend>::Handle688     fn build_va_decoded_handle(
689         &self,
690         picture: Rc<RefCell<GenericBackendHandle>>,
691         timestamp: u64,
692     ) -> <Self as VideoDecoderBackend>::Handle {
693         DecodedHandle::new(picture, timestamp)
694     }
695 }
696 
697 impl<StreamData> VideoDecoderBackend for VaapiBackend<StreamData>
698 where
699     for<'a> &'a StreamData: StreamInfo,
700 {
701     type Handle = DecodedHandle;
702 
coded_resolution(&self) -> Option<Resolution>703     fn coded_resolution(&self) -> Option<Resolution> {
704         self.metadata_state
705             .get_parsed()
706             .map(|m| m.surface_pool.coded_resolution)
707             .ok()
708     }
709 
display_resolution(&self) -> Option<Resolution>710     fn display_resolution(&self) -> Option<Resolution> {
711         self.metadata_state
712             .get_parsed()
713             .map(|m| m.display_resolution)
714             .ok()
715     }
716 
num_resources_total(&self) -> usize717     fn num_resources_total(&self) -> usize {
718         self.metadata_state
719             .get_parsed()
720             .map(|m| m.min_num_surfaces)
721             .unwrap_or(0)
722     }
723 
num_resources_left(&self) -> usize724     fn num_resources_left(&self) -> usize {
725         self.metadata_state
726             .get_parsed()
727             .map(|m| m.surface_pool.num_surfaces_left())
728             .unwrap_or(0)
729     }
730 
format(&self) -> Option<crate::DecodedFormat>731     fn format(&self) -> Option<crate::DecodedFormat> {
732         let map_format = self
733             .metadata_state
734             .get_parsed()
735             .map(|m| &m.map_format)
736             .ok()?;
737         DecodedFormat::try_from(map_format.as_ref()).ok()
738     }
739 
try_format(&mut self, format: crate::DecodedFormat) -> VideoDecoderResult<()>740     fn try_format(&mut self, format: crate::DecodedFormat) -> VideoDecoderResult<()> {
741         let header = match &self.negotiation_status {
742             NegotiationStatus::Possible(header) => header,
743             _ => {
744                 return Err(VideoDecoderError::StatelessBackendError(
745                     StatelessBackendError::NegotiationFailed(anyhow!(
746                         "Negotiation is not possible at this stage {:?}",
747                         self.negotiation_status
748                     )),
749                 ))
750             }
751         };
752 
753         let supported_formats_for_stream = self.metadata_state.supported_formats_for_stream()?;
754 
755         if supported_formats_for_stream.contains(&format) {
756             let map_format = FORMAT_MAP
757                 .iter()
758                 .find(|&map| map.decoded_format == format)
759                 .unwrap();
760 
761             self.metadata_state
762                 .open(header.as_ref(), Some(map_format))?;
763 
764             Ok(())
765         } else {
766             Err(VideoDecoderError::StatelessBackendError(
767                 StatelessBackendError::NegotiationFailed(anyhow!(
768                     "Format {:?} is unsupported.",
769                     format
770                 )),
771             ))
772         }
773     }
774 
poll(&mut self, blocking_mode: BlockingMode) -> VideoDecoderResult<VecDeque<Self::Handle>>775     fn poll(&mut self, blocking_mode: BlockingMode) -> VideoDecoderResult<VecDeque<Self::Handle>> {
776         let mut completed = VecDeque::new();
777         let candidates = self.pending_jobs.drain(..).collect::<VecDeque<_>>();
778 
779         for job in candidates {
780             if matches!(blocking_mode, BlockingMode::NonBlocking) {
781                 if !job.borrow().is_va_ready()? {
782                     self.pending_jobs.push_back(job);
783                     continue;
784                 }
785             }
786 
787             let metadata = self.metadata_state.get_parsed()?;
788 
789             job.borrow_mut().sync(metadata)?;
790             completed.push_back(job);
791         }
792 
793         let completed = completed.into_iter().map(|picture| {
794             // Safe because the backend handle has been turned into a ready one.
795             let timestamp = picture.borrow().picture().unwrap().timestamp();
796             Ok(self.build_va_decoded_handle(picture, timestamp))
797         });
798 
799         completed.collect::<Result<VecDeque<_>, _>>()
800     }
801 
handle_is_ready(&self, handle: &Self::Handle) -> bool802     fn handle_is_ready(&self, handle: &Self::Handle) -> bool {
803         handle.handle().is_ready()
804     }
805 
block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()>806     fn block_on_handle(&mut self, handle: &Self::Handle) -> StatelessBackendResult<()> {
807         for i in 0..self.pending_jobs.len() {
808             // Remove from the queue in order.
809             let job = &self.pending_jobs[i];
810 
811             if Rc::ptr_eq(job, handle.handle_rc()) {
812                 let job = self.pending_jobs.remove(i).unwrap();
813                 let metadata = self.metadata_state.get_parsed()?;
814 
815                 job.borrow_mut().sync(metadata)?;
816                 return Ok(());
817             }
818         }
819 
820         Err(StatelessBackendError::Other(anyhow!(
821             "Asked to block on a pending job that doesn't exist"
822         )))
823     }
824 }
825