cros_codecs/backend/vaapi/
decoder.rs

1// Copyright 2023 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
5use std::cell::RefCell;
6use std::collections::HashSet;
7use std::rc::Rc;
8
9use anyhow::anyhow;
10use anyhow::Context as AnyhowContext;
11use libva::Config;
12use libva::Context;
13use libva::Display;
14use libva::Image;
15use libva::Picture;
16use libva::PictureEnd;
17use libva::PictureNew;
18use libva::PictureSync;
19use libva::SurfaceMemoryDescriptor;
20use libva::VaError;
21
22use crate::backend::vaapi::p01x_to_i01x;
23use crate::backend::vaapi::surface_pool::PooledVaSurface;
24use crate::backend::vaapi::surface_pool::VaSurfacePool;
25use crate::backend::vaapi::va_rt_format_to_string;
26use crate::backend::vaapi::y21x_to_i21x;
27use crate::backend::vaapi::FormatMap;
28use crate::backend::vaapi::FORMAT_MAP;
29use crate::decoder::stateless::PoolLayer;
30use crate::decoder::stateless::StatelessBackendResult;
31use crate::decoder::stateless::StatelessCodec;
32use crate::decoder::stateless::StatelessDecoderBackend;
33use crate::decoder::stateless::StatelessDecoderBackendPicture;
34use crate::decoder::stateless::TryFormat;
35use crate::decoder::DecodedHandle as DecodedHandleTrait;
36use crate::decoder::DynHandle;
37use crate::decoder::FramePool;
38use crate::decoder::MappableHandle;
39use crate::decoder::StreamInfo;
40use crate::i4xx_copy;
41use crate::nv12_copy;
42use crate::y410_to_i410;
43use crate::DecodedFormat;
44use crate::Fourcc;
45use crate::Resolution;
46
47use super::supported_formats_for_rt_format;
48use super::y412_to_i412;
49
50/// A decoded frame handle.
51pub(crate) type DecodedHandle<M> = Rc<RefCell<VaapiDecodedHandle<M>>>;
52
53/// Gets the VASurfaceID for the given `picture`.
54pub(crate) fn va_surface_id<M: SurfaceMemoryDescriptor>(
55    handle: &Option<DecodedHandle<M>>,
56) -> libva::VASurfaceID {
57    match handle {
58        None => libva::constants::VA_INVALID_SURFACE,
59        Some(handle) => handle.borrow().surface().id(),
60    }
61}
62
63impl<M: SurfaceMemoryDescriptor> DecodedHandleTrait for DecodedHandle<M> {
64    type Descriptor = M;
65
66    fn coded_resolution(&self) -> Resolution {
67        self.borrow().surface().size().into()
68    }
69
70    fn display_resolution(&self) -> Resolution {
71        self.borrow().display_resolution
72    }
73
74    fn timestamp(&self) -> u64 {
75        self.borrow().timestamp()
76    }
77
78    fn dyn_picture<'a>(&'a self) -> Box<dyn DynHandle + 'a> {
79        Box::new(self.borrow())
80    }
81
82    fn is_ready(&self) -> bool {
83        self.borrow().state.is_ready().unwrap_or(true)
84    }
85
86    fn sync(&self) -> anyhow::Result<()> {
87        self.borrow_mut().sync().context("while syncing picture")?;
88
89        Ok(())
90    }
91
92    fn resource(&self) -> std::cell::Ref<M> {
93        std::cell::Ref::map(self.borrow(), |r| match &r.state {
94            PictureState::Ready(p) => p.surface().as_ref(),
95            PictureState::Pending(p) => p.surface().as_ref(),
96            PictureState::Invalid => unreachable!(),
97        })
98    }
99}
100
101/// A trait for providing the basic information needed to setup libva for decoding.
102pub(crate) trait VaStreamInfo {
103    /// Returns the VA profile of the stream.
104    fn va_profile(&self) -> anyhow::Result<i32>;
105    /// Returns the RT format of the stream.
106    fn rt_format(&self) -> anyhow::Result<u32>;
107    /// Returns the minimum number of surfaces required to decode the stream.
108    fn min_num_surfaces(&self) -> usize;
109    /// Returns the coded size of the surfaces required to decode the stream.
110    fn coded_size(&self) -> (u32, u32);
111    /// Returns the visible rectangle within the coded size for the stream.
112    fn visible_rect(&self) -> ((u32, u32), (u32, u32));
113}
114
115pub(crate) struct ParsedStreamMetadata {
116    /// A VAContext from which we can decode from.
117    pub(crate) context: Rc<Context>,
118    /// The VAConfig that created the context. It must kept here so that
119    /// it does not get dropped while it is in use.
120    #[allow(dead_code)]
121    config: Config,
122    /// Information about the current stream, directly extracted from it.
123    stream_info: StreamInfo,
124    /// The image format we will use to map the surfaces. This is usually the
125    /// same as the surface's internal format, but occasionally we can try
126    /// mapping in a different format if requested and if the VA-API driver can
127    /// do it.
128    map_format: Rc<libva::VAImageFormat>,
129    /// The rt_format parsed from the stream.
130    rt_format: u32,
131    /// The profile parsed from the stream.
132    profile: i32,
133}
134
135/// Controls how the decoder should create its surface pool.
136#[derive(Clone, Debug)]
137pub(crate) enum PoolCreationMode {
138    /// Create a single pool and assume a single spatial layer. Used for non-SVC
139    /// content.
140    Highest,
141    /// Create a pool for each spatial layer. Used for SVC content.
142    Layers(Vec<Resolution>),
143}
144
145/// State of the input stream, which can be either unparsed (we don't know the stream properties
146/// yet) or parsed (we know the stream properties and are ready to decode).
147pub(crate) enum StreamMetadataState {
148    /// The metadata for the current stream has not yet been parsed.
149    Unparsed,
150    /// The metadata for the current stream has been parsed and a suitable
151    /// VAContext has been created to accomodate it.
152    Parsed(ParsedStreamMetadata),
153}
154
155type StreamStateWithPool<M> = (StreamMetadataState, Vec<VaSurfacePool<M>>);
156
157impl StreamMetadataState {
158    /// Returns a reference to the parsed metadata state or an error if we haven't reached that
159    /// state yet.
160    pub(crate) fn get_parsed(&self) -> anyhow::Result<&ParsedStreamMetadata> {
161        match self {
162            StreamMetadataState::Unparsed { .. } => Err(anyhow!("Stream metadata not parsed yet")),
163            StreamMetadataState::Parsed(parsed_metadata) => Ok(parsed_metadata),
164        }
165    }
166
167    /// Initializes or reinitializes the codec state.
168    fn open<S: VaStreamInfo, M: SurfaceMemoryDescriptor>(
169        display: &Rc<Display>,
170        hdr: S,
171        format_map: Option<&FormatMap>,
172        old_metadata_state: StreamMetadataState,
173        old_surface_pools: Vec<VaSurfacePool<M>>,
174        supports_context_reuse: bool,
175        pool_creation_mode: PoolCreationMode,
176    ) -> anyhow::Result<StreamStateWithPool<M>> {
177        let va_profile = hdr.va_profile()?;
178        let rt_format = hdr.rt_format()?;
179
180        let coded_resolution =
181            Resolution::from(hdr.coded_size()).round(crate::ResolutionRoundMode::Even);
182
183        let format_map = if let Some(format_map) = format_map {
184            format_map
185        } else {
186            // Pick the first one that fits
187            FORMAT_MAP
188                .iter()
189                .find(|&map| map.rt_format == rt_format)
190                .ok_or(anyhow!(
191                    "format {} is not supported by your hardware or by the implementation for the current codec",
192                    va_rt_format_to_string(rt_format)
193                ))?
194        };
195
196        let map_format = display
197            .query_image_formats()?
198            .iter()
199            .find(|f| f.fourcc == format_map.va_fourcc)
200            .cloned()
201            .ok_or_else(|| {
202                anyhow!(
203                    "fourcc {} is not supported by your hardware or by the implementation for the current codec",
204                    Fourcc::from(format_map.va_fourcc)
205                )
206            })?;
207
208        let min_num_surfaces = hdr.min_num_surfaces();
209
210        let visible_rect = hdr.visible_rect();
211
212        let display_resolution = Resolution {
213            width: visible_rect.1 .0 - visible_rect.0 .0,
214            height: visible_rect.1 .1 - visible_rect.0 .1,
215        };
216
217        let layers = match pool_creation_mode {
218            PoolCreationMode::Highest => vec![coded_resolution],
219            PoolCreationMode::Layers(layers) => layers,
220        };
221
222        let (config, context, mut surface_pools) = match old_metadata_state {
223            // Nothing has changed for VAAPI, reuse current context.
224            //
225            // This can happen as the decoder cannot possibly know whether a
226            // given backend will really need to renegotiate on a given change
227            // of stream parameters.
228            StreamMetadataState::Parsed(old_state)
229                if old_state.stream_info.coded_resolution == coded_resolution
230                    && old_state.rt_format == rt_format
231                    && old_state.profile == va_profile =>
232            {
233                (old_state.config, old_state.context, old_surface_pools)
234            }
235            // The resolution has changed, but we support context reuse. Reuse
236            // current context.
237            StreamMetadataState::Parsed(old_state)
238                if supports_context_reuse
239                    && old_state.rt_format == rt_format
240                    && old_state.profile == va_profile =>
241            {
242                (old_state.config, old_state.context, old_surface_pools)
243            }
244            // Create new context.
245            _ => {
246                let config = display.create_config(
247                    vec![libva::VAConfigAttrib {
248                        type_: libva::VAConfigAttribType::VAConfigAttribRTFormat,
249                        value: rt_format,
250                    }],
251                    va_profile,
252                    libva::VAEntrypoint::VAEntrypointVLD,
253                )?;
254
255                let context = display.create_context::<M>(
256                    &config,
257                    coded_resolution.width,
258                    coded_resolution.height,
259                    None,
260                    true,
261                )?;
262
263                let surface_pools = layers
264                    .iter()
265                    .map(|layer| {
266                        VaSurfacePool::new(
267                            Rc::clone(display),
268                            rt_format,
269                            Some(libva::UsageHint::USAGE_HINT_DECODER),
270                            *layer,
271                        )
272                    })
273                    .collect();
274
275                (config, context, surface_pools)
276            }
277        };
278
279        /* sanity check */
280        assert!(surface_pools.len() == layers.len());
281        for (pool, layer) in surface_pools.iter_mut().zip(layers.iter()) {
282            if !pool.coded_resolution().can_contain(*layer) {
283                /* this will purge the old surfaces by not reclaiming them */
284                pool.set_coded_resolution(*layer);
285            }
286        }
287
288        Ok((
289            StreamMetadataState::Parsed(ParsedStreamMetadata {
290                context,
291                config,
292                stream_info: StreamInfo {
293                    format: match rt_format {
294                        libva::constants::VA_RT_FORMAT_YUV420 => DecodedFormat::I420,
295                        libva::constants::VA_RT_FORMAT_YUV422 => DecodedFormat::I422,
296                        libva::constants::VA_RT_FORMAT_YUV444 => DecodedFormat::I444,
297                        libva::constants::VA_RT_FORMAT_YUV420_10 => DecodedFormat::I010,
298                        libva::constants::VA_RT_FORMAT_YUV420_12 => DecodedFormat::I012,
299                        libva::constants::VA_RT_FORMAT_YUV422_10 => DecodedFormat::I210,
300                        libva::constants::VA_RT_FORMAT_YUV422_12 => DecodedFormat::I212,
301                        libva::constants::VA_RT_FORMAT_YUV444_10 => DecodedFormat::I410,
302                        libva::constants::VA_RT_FORMAT_YUV444_12 => DecodedFormat::I412,
303                        _ => panic!("unrecognized RT format {}", rt_format),
304                    },
305                    coded_resolution,
306                    display_resolution,
307                    min_num_frames: min_num_surfaces,
308                },
309                map_format: Rc::new(map_format),
310                rt_format,
311                profile: va_profile,
312            }),
313            surface_pools,
314        ))
315    }
316}
317
318/// Rendering state of a VA picture.
319enum PictureState<M: SurfaceMemoryDescriptor> {
320    Ready(Picture<PictureSync, PooledVaSurface<M>>),
321    Pending(Picture<PictureEnd, PooledVaSurface<M>>),
322    // Only set in sync when we take ownership of the VA picture.
323    Invalid,
324}
325
326impl<M: SurfaceMemoryDescriptor> PictureState<M> {
327    /// Make sure that all pending operations on the picture have completed.
328    fn sync(&mut self) -> Result<(), VaError> {
329        let res;
330
331        (*self, res) = match std::mem::replace(self, PictureState::Invalid) {
332            state @ PictureState::Ready(_) => (state, Ok(())),
333            PictureState::Pending(picture) => match picture.sync() {
334                Ok(picture) => (PictureState::Ready(picture), Ok(())),
335                Err((e, picture)) => (PictureState::Pending(picture), Err(e)),
336            },
337            PictureState::Invalid => unreachable!(),
338        };
339
340        res
341    }
342
343    fn surface(&self) -> &libva::Surface<M> {
344        match self {
345            PictureState::Ready(picture) => picture.surface(),
346            PictureState::Pending(picture) => picture.surface(),
347            PictureState::Invalid => unreachable!(),
348        }
349    }
350
351    fn timestamp(&self) -> u64 {
352        match self {
353            PictureState::Ready(picture) => picture.timestamp(),
354            PictureState::Pending(picture) => picture.timestamp(),
355            PictureState::Invalid => unreachable!(),
356        }
357    }
358
359    fn is_ready(&self) -> Result<bool, VaError> {
360        match self {
361            PictureState::Ready(_) => Ok(true),
362            PictureState::Pending(picture) => picture
363                .surface()
364                .query_status()
365                .map(|s| s == libva::VASurfaceStatus::VASurfaceReady),
366            PictureState::Invalid => unreachable!(),
367        }
368    }
369
370    fn new_from_same_surface(&self, timestamp: u64) -> Picture<PictureNew, PooledVaSurface<M>> {
371        match &self {
372            PictureState::Ready(picture) => Picture::new_from_same_surface(timestamp, picture),
373            PictureState::Pending(picture) => Picture::new_from_same_surface(timestamp, picture),
374            PictureState::Invalid => unreachable!(),
375        }
376    }
377}
378
379/// VA-API backend handle.
380///
381/// This includes the VA picture which can be pending rendering or complete, as well as useful
382/// meta-information.
383pub struct VaapiDecodedHandle<M: SurfaceMemoryDescriptor> {
384    state: PictureState<M>,
385    /// Actual resolution of the visible rectangle in the decoded buffer.
386    display_resolution: Resolution,
387    /// Image format for this surface, taken from the pool it originates from.
388    map_format: Rc<libva::VAImageFormat>,
389}
390
391impl<M: SurfaceMemoryDescriptor> VaapiDecodedHandle<M> {
392    /// Creates a new pending handle on `surface_id`.
393    fn new(
394        picture: Picture<PictureNew, PooledVaSurface<M>>,
395        metadata: &ParsedStreamMetadata,
396    ) -> anyhow::Result<Self> {
397        let picture = picture.begin()?.render()?.end()?;
398        Ok(Self {
399            state: PictureState::Pending(picture),
400            display_resolution: metadata.stream_info.display_resolution,
401            map_format: Rc::clone(&metadata.map_format),
402        })
403    }
404
405    fn sync(&mut self) -> Result<(), VaError> {
406        self.state.sync()
407    }
408
409    /// Returns a mapped VAImage. this maps the VASurface onto our address space.
410    /// This can be used in place of "DynMappableHandle::map()" if the client
411    /// wants to access the backend mapping directly for any reason.
412    ///
413    /// Note that DynMappableHandle is downcastable.
414    fn image(&self) -> anyhow::Result<Image> {
415        match &self.state {
416            PictureState::Ready(picture) => {
417                // Map the VASurface onto our address space.
418                let image = picture.create_image(
419                    *self.map_format,
420                    self.surface().size(),
421                    self.display_resolution.into(),
422                )?;
423
424                Ok(image)
425            }
426            // Either we are in `Ready` state or we didn't call `sync()`.
427            PictureState::Pending(_) | PictureState::Invalid => {
428                Err(anyhow::anyhow!("picture is not in Ready state"))
429            }
430        }
431    }
432
433    /// Creates a new picture from the surface backing the current one. Useful for interlaced
434    /// decoding.
435    pub(crate) fn new_picture_from_same_surface(
436        &self,
437        timestamp: u64,
438    ) -> Picture<PictureNew, PooledVaSurface<M>> {
439        self.state.new_from_same_surface(timestamp)
440    }
441
442    pub(crate) fn surface(&self) -> &libva::Surface<M> {
443        self.state.surface()
444    }
445
446    /// Returns the timestamp of this handle.
447    fn timestamp(&self) -> u64 {
448        self.state.timestamp()
449    }
450}
451
452impl<'a, M: SurfaceMemoryDescriptor> DynHandle for std::cell::Ref<'a, VaapiDecodedHandle<M>> {
453    fn dyn_mappable_handle<'b>(&'b self) -> anyhow::Result<Box<dyn MappableHandle + 'b>> {
454        self.image().map(|i| Box::new(i) as Box<dyn MappableHandle>)
455    }
456}
457
458impl<'a> MappableHandle for Image<'a> {
459    fn read(&mut self, buffer: &mut [u8]) -> anyhow::Result<()> {
460        let image_size = self.image_size();
461        let image_inner = self.image();
462
463        let display_resolution = self.display_resolution();
464        let width = display_resolution.0 as usize;
465        let height = display_resolution.1 as usize;
466
467        if buffer.len() != image_size {
468            return Err(anyhow!(
469                "buffer size is {} while image size is {}",
470                buffer.len(),
471                image_size
472            ));
473        }
474
475        let pitches = image_inner.pitches.map(|x| x as usize);
476        let offsets = image_inner.offsets.map(|x| x as usize);
477
478        match image_inner.format.fourcc {
479            libva::constants::VA_FOURCC_NV12 => {
480                nv12_copy(self.as_ref(), buffer, width, height, pitches, offsets);
481            }
482            libva::constants::VA_FOURCC_I420 => {
483                i4xx_copy(
484                    self.as_ref(),
485                    buffer,
486                    width,
487                    height,
488                    pitches,
489                    offsets,
490                    (true, true),
491                );
492            }
493            libva::constants::VA_FOURCC_422H => {
494                i4xx_copy(
495                    self.as_ref(),
496                    buffer,
497                    width,
498                    height,
499                    pitches,
500                    offsets,
501                    (true, false),
502                );
503            }
504            libva::constants::VA_FOURCC_444P => {
505                i4xx_copy(
506                    self.as_ref(),
507                    buffer,
508                    width,
509                    height,
510                    pitches,
511                    offsets,
512                    (false, false),
513                );
514            }
515            libva::constants::VA_FOURCC_P010 => {
516                p01x_to_i01x(self.as_ref(), buffer, 10, width, height, pitches, offsets);
517            }
518            libva::constants::VA_FOURCC_P012 => {
519                p01x_to_i01x(self.as_ref(), buffer, 12, width, height, pitches, offsets);
520            }
521            libva::constants::VA_FOURCC_Y210 => {
522                y21x_to_i21x(self.as_ref(), buffer, 10, width, height, pitches, offsets);
523            }
524            libva::constants::VA_FOURCC_Y212 => {
525                y21x_to_i21x(self.as_ref(), buffer, 12, width, height, pitches, offsets);
526            }
527            libva::constants::VA_FOURCC_Y410 => {
528                y410_to_i410(self.as_ref(), buffer, width, height, pitches, offsets);
529            }
530            libva::constants::VA_FOURCC_Y412 => {
531                y412_to_i412(self.as_ref(), buffer, width, height, pitches, offsets);
532            }
533            _ => {
534                return Err(anyhow!(
535                    "unsupported format 0x{:x}",
536                    image_inner.format.fourcc
537                ))
538            }
539        }
540
541        Ok(())
542    }
543
544    fn image_size(&mut self) -> usize {
545        let image = self.image();
546        let display_resolution = self.display_resolution();
547        crate::decoded_frame_size(
548            (&image.format).try_into().unwrap(),
549            display_resolution.0 as usize,
550            display_resolution.1 as usize,
551        )
552    }
553}
554
555pub struct VaapiBackend<M>
556where
557    M: SurfaceMemoryDescriptor,
558{
559    /// VA display in use for this stream.
560    display: Rc<Display>,
561    /// Pools of surfaces. We reuse surfaces as they are expensive to allocate.
562    /// We allow for multiple pools so as to support one spatial layer per pool
563    /// when needed.
564    pub(crate) surface_pools: Vec<VaSurfacePool<M>>,
565    /// The metadata state. Updated whenever the decoder reads new data from the stream.
566    pub(crate) metadata_state: StreamMetadataState,
567    /// Whether the codec supports context reuse on DRC. This is only supported
568    /// by VP9 and AV1.
569    supports_context_reuse: bool,
570    /// Controls the creation of surface pools.
571    pool_creation_mode: PoolCreationMode,
572}
573
574impl<M> VaapiBackend<M>
575where
576    M: SurfaceMemoryDescriptor + 'static,
577{
578    pub(crate) fn new(display: Rc<libva::Display>, supports_context_reuse: bool) -> Self {
579        // Create a pool with reasonable defaults, as we don't know the format of the stream yet.
580        let surface_pools = vec![VaSurfacePool::new(
581            Rc::clone(&display),
582            libva::constants::VA_RT_FORMAT_YUV420,
583            Some(libva::UsageHint::USAGE_HINT_DECODER),
584            Resolution::from((16, 16)),
585        )];
586
587        Self {
588            display,
589            surface_pools,
590            metadata_state: StreamMetadataState::Unparsed,
591            supports_context_reuse,
592            pool_creation_mode: PoolCreationMode::Highest,
593        }
594    }
595
596    pub(crate) fn new_sequence<StreamData>(
597        &mut self,
598        stream_params: &StreamData,
599        pool_creation_mode: PoolCreationMode,
600    ) -> StatelessBackendResult<()>
601    where
602        for<'a> &'a StreamData: VaStreamInfo,
603    {
604        let old_metadata_state =
605            std::mem::replace(&mut self.metadata_state, StreamMetadataState::Unparsed);
606
607        let old_surface_pools = self.surface_pools.drain(..).collect();
608        (self.metadata_state, self.surface_pools) = StreamMetadataState::open(
609            &self.display,
610            stream_params,
611            None,
612            old_metadata_state,
613            old_surface_pools,
614            self.supports_context_reuse,
615            pool_creation_mode.clone(),
616        )?;
617
618        self.pool_creation_mode = pool_creation_mode;
619
620        Ok(())
621    }
622
623    pub(crate) fn process_picture<Codec: StatelessCodec>(
624        &mut self,
625        picture: Picture<PictureNew, PooledVaSurface<M>>,
626    ) -> StatelessBackendResult<<Self as StatelessDecoderBackend>::Handle>
627    where
628        Self: StatelessDecoderBackendPicture<Codec>,
629        for<'a> &'a Codec::FormatInfo: VaStreamInfo,
630    {
631        let metadata = self.metadata_state.get_parsed()?;
632
633        Ok(Rc::new(RefCell::new(VaapiDecodedHandle::new(
634            picture, metadata,
635        )?)))
636    }
637
638    /// Gets a set of supported formats for the particular stream being
639    /// processed. This requires that some buffers be processed before this call
640    /// is made. Only formats that are compatible with the current color space,
641    /// bit depth, and chroma format are returned such that no conversion is
642    /// needed.
643    fn supported_formats_for_stream(&self) -> anyhow::Result<HashSet<DecodedFormat>> {
644        let metadata = self.metadata_state.get_parsed()?;
645        let image_formats = self.display.query_image_formats()?;
646
647        let formats = supported_formats_for_rt_format(
648            &self.display,
649            metadata.rt_format,
650            metadata.profile,
651            libva::VAEntrypoint::VAEntrypointVLD,
652            &image_formats,
653        )?;
654
655        Ok(formats.into_iter().map(|f| f.decoded_format).collect())
656    }
657
658    pub(crate) fn highest_pool(&mut self) -> &mut VaSurfacePool<M> {
659        /* we guarantee that there is at least one pool, at minimum */
660        self.surface_pools
661            .iter_mut()
662            .max_by_key(|p| p.coded_resolution().height)
663            .unwrap()
664    }
665
666    pub(crate) fn pool(&mut self, layer: Resolution) -> Option<&mut VaSurfacePool<M>> {
667        self.surface_pools
668            .iter_mut()
669            .find(|p| p.coded_resolution() == layer)
670    }
671}
672
673/// Shortcut for pictures used for the VAAPI backend.
674pub type VaapiPicture<M> = Picture<PictureNew, PooledVaSurface<M>>;
675
676impl<M> StatelessDecoderBackend for VaapiBackend<M>
677where
678    M: SurfaceMemoryDescriptor,
679{
680    type Handle = DecodedHandle<M>;
681
682    type FramePool = VaSurfacePool<M>;
683
684    fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut Self::FramePool> {
685        if let PoolLayer::Highest = layer {
686            return vec![self
687                .surface_pools
688                .iter_mut()
689                .max_by_key(|other| other.coded_resolution().height)
690                .unwrap()];
691        }
692
693        self.surface_pools
694            .iter_mut()
695            .filter(|pool| {
696                match layer {
697                    PoolLayer::Highest => unreachable!(),
698                    PoolLayer::Layer(resolution) => pool.coded_resolution() == resolution,
699                    PoolLayer::All => {
700                        /* let all through */
701                        true
702                    }
703                }
704            })
705            .collect()
706    }
707
708    fn stream_info(&self) -> Option<&StreamInfo> {
709        self.metadata_state
710            .get_parsed()
711            .ok()
712            .map(|m| &m.stream_info)
713    }
714}
715
716impl<Codec: StatelessCodec, M> TryFormat<Codec> for VaapiBackend<M>
717where
718    //VaapiBackend<M>: StatelessDecoderBackendPicture<Codec>,
719    for<'a> &'a Codec::FormatInfo: VaStreamInfo,
720    M: SurfaceMemoryDescriptor + 'static,
721{
722    fn try_format(
723        &mut self,
724        format_info: &Codec::FormatInfo,
725        format: crate::DecodedFormat,
726    ) -> anyhow::Result<()> {
727        let supported_formats_for_stream = self.supported_formats_for_stream()?;
728
729        if supported_formats_for_stream.contains(&format) {
730            let map_format = FORMAT_MAP
731                .iter()
732                .find(|&map| map.decoded_format == format)
733                .ok_or_else(|| {
734                    anyhow!(
735                        "cannot find corresponding VA format for decoded format {:?}",
736                        format
737                    )
738                })?;
739
740            let old_metadata_state =
741                std::mem::replace(&mut self.metadata_state, StreamMetadataState::Unparsed);
742
743            // TODO: since we have established that it's best to let the VA
744            // driver choose the surface's internal (tiled) format, and map to
745            // the fourcc we want on-the-fly, this call to open() becomes
746            // redundant.
747            //
748            // Let's fix it at a later commit, because it involves other,
749            // non-related, cleanups.
750            //
751            // This does not apply to other (future) backends, like V4L2, which
752            // need to reallocate on format change.
753            let old_surface_pools = self.surface_pools.drain(..).collect();
754            (self.metadata_state, self.surface_pools) = StreamMetadataState::open(
755                &self.display,
756                format_info,
757                Some(map_format),
758                old_metadata_state,
759                old_surface_pools,
760                self.supports_context_reuse,
761                self.pool_creation_mode.clone(),
762            )?;
763
764            Ok(())
765        } else {
766            Err(anyhow!("Format {:?} is unsupported.", format))
767        }
768    }
769}