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