cros_codecs/decoder/stateless/
vp9.rs

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#[cfg(test)]
6mod dummy;
7#[cfg(feature = "vaapi")]
8mod vaapi;
9
10use std::os::fd::AsFd;
11use std::os::fd::BorrowedFd;
12
13use log::debug;
14
15use crate::codec::vp9::parser::BitDepth;
16use crate::codec::vp9::parser::Frame;
17use crate::codec::vp9::parser::Header;
18use crate::codec::vp9::parser::Parser;
19use crate::codec::vp9::parser::Profile;
20use crate::codec::vp9::parser::Segmentation;
21use crate::codec::vp9::parser::MAX_SEGMENTS;
22use crate::codec::vp9::parser::NUM_REF_FRAMES;
23use crate::decoder::stateless::DecodeError;
24use crate::decoder::stateless::DecodingState;
25use crate::decoder::stateless::NewPictureError;
26use crate::decoder::stateless::NewPictureResult;
27use crate::decoder::stateless::PoolLayer;
28use crate::decoder::stateless::StatelessBackendResult;
29use crate::decoder::stateless::StatelessCodec;
30use crate::decoder::stateless::StatelessDecoder;
31use crate::decoder::stateless::StatelessDecoderBackend;
32use crate::decoder::stateless::StatelessDecoderBackendPicture;
33use crate::decoder::stateless::StatelessVideoDecoder;
34use crate::decoder::stateless::TryFormat;
35use crate::decoder::BlockingMode;
36use crate::decoder::DecodedHandle;
37use crate::decoder::DecoderEvent;
38use crate::decoder::StreamInfo;
39use crate::Resolution;
40
41/// Stateless backend methods specific to VP9.
42pub trait StatelessVp9DecoderBackend:
43    StatelessDecoderBackend + StatelessDecoderBackendPicture<Vp9>
44{
45    /// Called when new stream parameters are found.
46    fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()>;
47
48    /// Allocate all resources required to process a new picture.
49    fn new_picture(&mut self, timestamp: u64) -> NewPictureResult<Self::Picture>;
50
51    /// Called when the decoder wants the backend to finish the decoding
52    /// operations for `picture`.
53    ///
54    /// This call will assign the ownership of the BackendHandle to the Picture
55    /// and then assign the ownership of the Picture to the Handle.
56    fn submit_picture(
57        &mut self,
58        picture: Self::Picture,
59        hdr: &Header,
60        reference_frames: &[Option<Self::Handle>; NUM_REF_FRAMES],
61        bitstream: &[u8],
62        segmentation: &[Segmentation; MAX_SEGMENTS],
63    ) -> StatelessBackendResult<Self::Handle>;
64}
65
66pub struct Vp9DecoderState<H: DecodedHandle> {
67    /// VP9 bitstream parser.
68    parser: Parser,
69
70    /// The reference frames in use.
71    reference_frames: [Option<H>; NUM_REF_FRAMES],
72
73    /// Per-segment data.
74    segmentation: [Segmentation; MAX_SEGMENTS],
75
76    /// Keeps track of the last values seen for negotiation purposes.
77    negotiation_info: NegotiationInfo,
78}
79
80impl<H> Default for Vp9DecoderState<H>
81where
82    H: DecodedHandle,
83{
84    fn default() -> Self {
85        Self {
86            parser: Default::default(),
87            reference_frames: Default::default(),
88            segmentation: Default::default(),
89            negotiation_info: Default::default(),
90        }
91    }
92}
93
94/// Keeps track of the last values seen for negotiation purposes.
95#[derive(Clone, Debug, Default, PartialEq, Eq)]
96struct NegotiationInfo {
97    /// The current coded resolution
98    coded_resolution: Resolution,
99    /// Cached value for bit depth
100    bit_depth: BitDepth,
101    /// Cached value for profile
102    profile: Profile,
103}
104
105impl From<&Header> for NegotiationInfo {
106    fn from(hdr: &Header) -> Self {
107        NegotiationInfo {
108            coded_resolution: Resolution {
109                width: hdr.width,
110                height: hdr.height,
111            },
112            bit_depth: hdr.bit_depth,
113            profile: hdr.profile,
114        }
115    }
116}
117
118/// [`StatelessCodec`] structure to use in order to create a VP9 stateless decoder.
119///
120/// # Accepted input
121///
122/// the VP9 specification requires the last byte of the chunk to contain the superframe marker.
123/// Thus, a decoder using this codec processes exactly one encoded chunk per call to
124/// [`StatelessDecoder::decode`], and always returns the size of the passed input if successful.
125pub struct Vp9;
126
127impl StatelessCodec for Vp9 {
128    type FormatInfo = Header;
129    type DecoderState<H: DecodedHandle, P> = Vp9DecoderState<H>;
130}
131
132impl<B> StatelessDecoder<Vp9, B>
133where
134    B: StatelessVp9DecoderBackend,
135    B::Handle: Clone,
136{
137    fn update_references(
138        reference_frames: &mut [Option<B::Handle>; NUM_REF_FRAMES],
139        picture: &B::Handle,
140        mut refresh_frame_flags: u8,
141    ) -> anyhow::Result<()> {
142        #[allow(clippy::needless_range_loop)]
143        for i in 0..NUM_REF_FRAMES {
144            if (refresh_frame_flags & 1) == 1 {
145                debug!("Replacing reference frame {}", i);
146                reference_frames[i] = Some(picture.clone());
147            }
148
149            refresh_frame_flags >>= 1;
150        }
151
152        Ok(())
153    }
154
155    /// Handle a frame which `show_existing_frame` flag is `true`.
156    fn handle_show_existing_frame(&mut self, frame_to_show_map_idx: u8) -> Result<(), DecodeError> {
157        // Frame to be shown. Because the spec mandates that frame_to_show_map_idx references a
158        // valid entry in the DPB, an non-existing index means that the stream is invalid.
159        let idx = usize::from(frame_to_show_map_idx);
160        let ref_frame = self
161            .codec
162            .reference_frames
163            .get(idx)
164            .ok_or_else(|| anyhow::anyhow!("invalid reference frame index in header"))?
165            .as_ref()
166            .ok_or_else(|| anyhow::anyhow!("empty reference frame referenced in frame header"))?;
167
168        // We are done, no further processing needed.
169        let decoded_handle = ref_frame.clone();
170
171        self.ready_queue.push(decoded_handle);
172
173        Ok(())
174    }
175
176    /// Decode a single frame.
177    fn handle_frame(&mut self, frame: &Frame, picture: B::Picture) -> Result<(), DecodeError> {
178        let refresh_frame_flags = frame.header.refresh_frame_flags;
179
180        Segmentation::update_segmentation(&mut self.codec.segmentation, &frame.header);
181
182        let decoded_handle = self.backend.submit_picture(
183            picture,
184            &frame.header,
185            &self.codec.reference_frames,
186            frame.as_ref(),
187            &self.codec.segmentation,
188        )?;
189
190        if self.blocking_mode == BlockingMode::Blocking {
191            decoded_handle.sync()?;
192        }
193
194        // Do DPB management
195        Self::update_references(
196            &mut self.codec.reference_frames,
197            &decoded_handle,
198            refresh_frame_flags,
199        )?;
200
201        if frame.header.show_frame {
202            self.ready_queue.push(decoded_handle);
203        }
204
205        Ok(())
206    }
207
208    fn negotiation_possible(&self, hdr: &Header, old_negotiation_info: &NegotiationInfo) -> bool {
209        let negotiation_info = NegotiationInfo::from(hdr);
210
211        if negotiation_info.coded_resolution.width == 0
212            || negotiation_info.coded_resolution.height == 0
213        {
214            false
215        } else {
216            *old_negotiation_info != negotiation_info
217        }
218    }
219}
220
221impl<B> StatelessVideoDecoder for StatelessDecoder<Vp9, B>
222where
223    B: StatelessVp9DecoderBackend + TryFormat<Vp9>,
224    B::Handle: Clone + 'static,
225{
226    type Handle = B::Handle;
227    type FramePool = B::FramePool;
228
229    fn decode(&mut self, timestamp: u64, bitstream: &[u8]) -> Result<usize, DecodeError> {
230        let frames = self.codec.parser.parse_chunk(bitstream)?;
231
232        // With SVC, the first frame will usually be a key-frame, with
233        // inter-frames carrying the other layers.
234        //
235        // We do not want each of those to be considered as a separate DRC
236        // event. Not only that, allowing them to be will cause an infinite
237        // loop.
238        //
239        // Instead, negotiate based on the largest spatial layer. That will be
240        // enough to house the other layers in between.
241        let largest_in_superframe = frames.iter().max_by(|&a, &b| {
242            let a_res = Resolution::from((a.header.width, a.header.height));
243            let b_res = Resolution::from((b.header.width, b.header.height));
244            if a_res == b_res {
245                std::cmp::Ordering::Equal
246            } else if a_res.can_contain(b_res) {
247                std::cmp::Ordering::Greater
248            } else {
249                std::cmp::Ordering::Less
250            }
251        });
252
253        if let Some(frame) = largest_in_superframe {
254            if self.negotiation_possible(&frame.header, &self.codec.negotiation_info) {
255                self.backend.new_sequence(&frame.header)?;
256                self.await_format_change(frame.header.clone());
257            } else if matches!(self.decoding_state, DecodingState::Reset) {
258                // We can resume decoding since the decoding parameters have not changed.
259                self.decoding_state = DecodingState::Decoding;
260            }
261        }
262
263        match &mut self.decoding_state {
264            // Skip input until we get information from the stream.
265            DecodingState::AwaitingStreamInfo | DecodingState::Reset => (),
266            // Ask the client to confirm the format before we can process this.
267            DecodingState::AwaitingFormat(_) => return Err(DecodeError::CheckEvents),
268            DecodingState::Decoding => {
269                // First allocate all the pictures we need for this superframe.
270                let num_required_pictures = frames
271                    .iter()
272                    .filter(|f| !f.header.show_existing_frame)
273                    .count();
274                let frames_with_pictures = frames
275                    .into_iter()
276                    .enumerate()
277                    .map(|(i, frame)| {
278                        if frame.header.show_existing_frame {
279                            Ok((frame, None))
280                        } else {
281                            self.backend
282                                .new_picture(timestamp)
283                                .map_err(|e| match e {
284                                    NewPictureError::OutOfOutputBuffers => {
285                                        DecodeError::NotEnoughOutputBuffers(
286                                            num_required_pictures - i,
287                                        )
288                                    }
289                                    e => DecodeError::from(e),
290                                })
291                                .map(|picture| (frame, Some(picture)))
292                        }
293                    })
294                    .collect::<Result<Vec<_>, _>>()?;
295
296                // Then process each frame.
297                for (frame, picture) in frames_with_pictures {
298                    match picture {
299                        None => {
300                            self.handle_show_existing_frame(frame.header.frame_to_show_map_idx)?
301                        }
302                        Some(picture) => self.handle_frame(&frame, picture)?,
303                    }
304                }
305            }
306        }
307
308        Ok(bitstream.len())
309    }
310
311    fn flush(&mut self) -> Result<(), DecodeError> {
312        // Note: all the submitted frames are already in the ready queue.
313        self.codec.reference_frames = Default::default();
314        self.decoding_state = DecodingState::Reset;
315
316        Ok(())
317    }
318
319    fn next_event(&mut self) -> Option<DecoderEvent<B::Handle>> {
320        self.query_next_event(|decoder, hdr| {
321            decoder.codec.negotiation_info = hdr.into();
322        })
323    }
324
325    fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut B::FramePool> {
326        self.backend.frame_pool(layer)
327    }
328
329    fn stream_info(&self) -> Option<&StreamInfo> {
330        self.backend.stream_info()
331    }
332
333    fn poll_fd(&self) -> BorrowedFd {
334        self.epoll_fd.0.as_fd()
335    }
336}
337
338#[cfg(test)]
339pub mod tests {
340    use crate::decoder::stateless::tests::test_decode_stream;
341    use crate::decoder::stateless::tests::TestStream;
342    use crate::decoder::stateless::vp9::Vp9;
343    use crate::decoder::stateless::StatelessDecoder;
344    use crate::decoder::BlockingMode;
345    use crate::utils::simple_playback_loop;
346    use crate::utils::simple_playback_loop_owned_frames;
347    use crate::utils::IvfIterator;
348    use crate::DecodedFormat;
349
350    /// Run `test` using the dummy decoder, in both blocking and non-blocking modes.
351    fn test_decoder_dummy(test: &TestStream, blocking_mode: BlockingMode) {
352        let decoder = StatelessDecoder::<Vp9, _>::new_dummy(blocking_mode).unwrap();
353
354        test_decode_stream(
355            |d, s, c| {
356                simple_playback_loop(
357                    d,
358                    IvfIterator::new(s),
359                    c,
360                    &mut simple_playback_loop_owned_frames,
361                    DecodedFormat::NV12,
362                    blocking_mode,
363                )
364            },
365            decoder,
366            test,
367            false,
368            false,
369        );
370    }
371
372    /// Same as Chromium's test-25fps.vp8
373    pub const DECODE_TEST_25FPS: TestStream = TestStream {
374        stream: include_bytes!("../../codec/vp9/test_data/test-25fps.vp9"),
375        crcs: include_str!("../../codec/vp9/test_data/test-25fps.vp9.crc"),
376    };
377
378    #[test]
379    fn test_25fps_block() {
380        test_decoder_dummy(&DECODE_TEST_25FPS, BlockingMode::Blocking);
381    }
382
383    #[test]
384    fn test_25fps_nonblock() {
385        test_decoder_dummy(&DECODE_TEST_25FPS, BlockingMode::NonBlocking);
386    }
387
388    // Remuxed from the original matroska source in libvpx using ffmpeg:
389    // ffmpeg -i vp90-2-10-show-existing-frame.webm/vp90-2-10-show-existing-frame.webm -c:v copy /tmp/vp90-2-10-show-existing-frame.vp9.ivf
390    pub const DECODE_TEST_25FPS_SHOW_EXISTING_FRAME: TestStream = TestStream {
391        stream: include_bytes!("../../codec/vp9/test_data/vp90-2-10-show-existing-frame.vp9.ivf"),
392        crcs: include_str!("../../codec/vp9/test_data/vp90-2-10-show-existing-frame.vp9.ivf.crc"),
393    };
394
395    #[test]
396    fn show_existing_frame_block() {
397        test_decoder_dummy(
398            &DECODE_TEST_25FPS_SHOW_EXISTING_FRAME,
399            BlockingMode::Blocking,
400        );
401    }
402
403    #[test]
404    fn show_existing_frame_nonblock() {
405        test_decoder_dummy(
406            &DECODE_TEST_25FPS_SHOW_EXISTING_FRAME,
407            BlockingMode::NonBlocking,
408        );
409    }
410
411    pub const DECODE_TEST_25FPS_SHOW_EXISTING_FRAME2: TestStream = TestStream {
412        stream: include_bytes!("../../codec/vp9/test_data/vp90-2-10-show-existing-frame2.vp9.ivf"),
413        crcs: include_str!("../../codec/vp9/test_data/vp90-2-10-show-existing-frame2.vp9.ivf.crc"),
414    };
415
416    #[test]
417    fn show_existing_frame2_block() {
418        test_decoder_dummy(
419            &DECODE_TEST_25FPS_SHOW_EXISTING_FRAME2,
420            BlockingMode::Blocking,
421        );
422    }
423
424    #[test]
425    fn show_existing_frame2_nonblock() {
426        test_decoder_dummy(
427            &DECODE_TEST_25FPS_SHOW_EXISTING_FRAME2,
428            BlockingMode::NonBlocking,
429        );
430    }
431
432    // Remuxed from the original matroska source in libvpx using ffmpeg:
433    // ffmpeg -i vp90-2-10-show-existing-frame.webm/vp90-2-10-show-existing-frame.webm -c:v copy /tmp/vp90-2-10-show-existing-frame.vp9.ivf
434    // There are some weird padding issues introduced by GStreamer for
435    // resolutions that are not multiple of 4, so we're ignoring CRCs for
436    // this one.
437    pub const DECODE_RESOLUTION_CHANGE_500FRAMES: TestStream = TestStream {
438        stream: include_bytes!("../../codec/vp9/test_data/resolution_change_500frames-vp9.ivf"),
439        crcs: include_str!("../../codec/vp9/test_data/resolution_change_500frames-vp9.ivf.crc"),
440    };
441
442    #[test]
443    fn test_resolution_change_500frames_block() {
444        test_decoder_dummy(&DECODE_RESOLUTION_CHANGE_500FRAMES, BlockingMode::Blocking);
445    }
446
447    #[test]
448    fn test_resolution_change_500frames_nonblock() {
449        test_decoder_dummy(&DECODE_RESOLUTION_CHANGE_500FRAMES, BlockingMode::Blocking);
450    }
451}