cros_codecs/decoder/stateless/
vp8.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(any(test, fuzzing))]
6mod dummy;
7#[cfg(feature = "vaapi")]
8mod vaapi;
9
10use std::os::fd::AsFd;
11use std::os::fd::BorrowedFd;
12
13use crate::codec::vp8::parser::Frame;
14use crate::codec::vp8::parser::Header;
15use crate::codec::vp8::parser::MbLfAdjustments;
16use crate::codec::vp8::parser::Parser;
17use crate::codec::vp8::parser::Segmentation;
18use crate::decoder::stateless::DecodeError;
19use crate::decoder::stateless::DecodingState;
20use crate::decoder::stateless::NewPictureResult;
21use crate::decoder::stateless::PoolLayer;
22use crate::decoder::stateless::StatelessBackendResult;
23use crate::decoder::stateless::StatelessCodec;
24use crate::decoder::stateless::StatelessDecoder;
25use crate::decoder::stateless::StatelessDecoderBackend;
26use crate::decoder::stateless::StatelessDecoderBackendPicture;
27use crate::decoder::stateless::StatelessVideoDecoder;
28use crate::decoder::stateless::TryFormat;
29use crate::decoder::BlockingMode;
30use crate::decoder::DecodedHandle;
31use crate::decoder::DecoderEvent;
32use crate::decoder::StreamInfo;
33use crate::Resolution;
34
35/// Stateless backend methods specific to VP8.
36pub trait StatelessVp8DecoderBackend:
37    StatelessDecoderBackend + StatelessDecoderBackendPicture<Vp8>
38{
39    /// Called when new stream parameters are found.
40    fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()>;
41
42    /// Called when the decoder determines that a frame or field was found.
43    fn new_picture(&mut self, timestamp: u64) -> NewPictureResult<Self::Picture>;
44
45    /// Called when the decoder wants the backend to finish the decoding
46    /// operations for `picture`.
47    ///
48    /// This call will assign the ownership of the BackendHandle to the Picture
49    /// and then assign the ownership of the Picture to the Handle.
50    #[allow(clippy::too_many_arguments)]
51    fn submit_picture(
52        &mut self,
53        picture: Self::Picture,
54        hdr: &Header,
55        last_ref: &Option<Self::Handle>,
56        golden_ref: &Option<Self::Handle>,
57        alt_ref: &Option<Self::Handle>,
58        bitstream: &[u8],
59        segmentation: &Segmentation,
60        mb_lf_adjust: &MbLfAdjustments,
61    ) -> StatelessBackendResult<Self::Handle>;
62}
63
64pub struct Vp8DecoderState<H: DecodedHandle> {
65    /// VP8 bitstream parser.
66    parser: Parser,
67
68    /// The picture used as the last reference picture.
69    last_picture: Option<H>,
70    /// The picture used as the golden reference picture.
71    golden_ref_picture: Option<H>,
72    /// The picture used as the alternate reference picture.
73    alt_ref_picture: Option<H>,
74}
75
76impl<H: DecodedHandle> Default for Vp8DecoderState<H> {
77    fn default() -> Self {
78        Self {
79            parser: Default::default(),
80            last_picture: Default::default(),
81            golden_ref_picture: Default::default(),
82            alt_ref_picture: Default::default(),
83        }
84    }
85}
86
87/// [`StatelessCodec`] structure to use in order to create a VP8 stateless decoder.
88///
89/// # Accepted input
90///
91/// A decoder using this codec processes exactly one encoded frame per call to
92/// [`StatelessDecoder::decode`], and returns the number of bytes actually taken by the frame data.
93/// If the frame was properly encapsulated in its container, the returned value should be equal to
94/// the length of the submitted input.
95pub struct Vp8;
96
97impl StatelessCodec for Vp8 {
98    type FormatInfo = Header;
99    type DecoderState<H: DecodedHandle, P> = Vp8DecoderState<H>;
100}
101
102impl<H> Vp8DecoderState<H>
103where
104    H: DecodedHandle + Clone,
105{
106    /// Replace a reference frame with `handle`.
107    fn replace_reference(reference: &mut Option<H>, handle: &H) {
108        *reference = Some(handle.clone());
109    }
110
111    pub(crate) fn update_references(
112        &mut self,
113        header: &Header,
114        decoded_handle: &H,
115    ) -> anyhow::Result<()> {
116        if header.key_frame {
117            Self::replace_reference(&mut self.last_picture, decoded_handle);
118            Self::replace_reference(&mut self.golden_ref_picture, decoded_handle);
119            Self::replace_reference(&mut self.alt_ref_picture, decoded_handle);
120        } else {
121            if header.refresh_alternate_frame {
122                Self::replace_reference(&mut self.alt_ref_picture, decoded_handle);
123            } else {
124                match header.copy_buffer_to_alternate {
125                    0 => { /* do nothing */ }
126
127                    1 => {
128                        if let Some(last_picture) = &self.last_picture {
129                            Self::replace_reference(&mut self.alt_ref_picture, last_picture);
130                        }
131                    }
132
133                    2 => {
134                        if let Some(golden_ref) = &self.golden_ref_picture {
135                            Self::replace_reference(&mut self.alt_ref_picture, golden_ref);
136                        }
137                    }
138
139                    other => anyhow::bail!("invalid copy_buffer_to_alternate value: {}", other),
140                }
141            }
142
143            if header.refresh_golden_frame {
144                Self::replace_reference(&mut self.golden_ref_picture, decoded_handle);
145            } else {
146                match header.copy_buffer_to_golden {
147                    0 => { /* do nothing */ }
148
149                    1 => {
150                        if let Some(last_picture) = &self.last_picture {
151                            Self::replace_reference(&mut self.golden_ref_picture, last_picture);
152                        }
153                    }
154
155                    2 => {
156                        if let Some(alt_ref) = &self.alt_ref_picture {
157                            Self::replace_reference(&mut self.golden_ref_picture, alt_ref);
158                        }
159                    }
160
161                    other => anyhow::bail!("invalid copy_buffer_to_golden value: {}", other),
162                }
163            }
164
165            if header.refresh_last {
166                Self::replace_reference(&mut self.last_picture, decoded_handle);
167            }
168        }
169
170        Ok(())
171    }
172}
173
174impl<B> StatelessDecoder<Vp8, B>
175where
176    B: StatelessVp8DecoderBackend,
177    B::Handle: Clone,
178{
179    /// Handle a single frame.
180    fn handle_frame(&mut self, frame: Frame, timestamp: u64) -> Result<(), DecodeError> {
181        let show_frame = frame.header.show_frame;
182
183        let picture = self.backend.new_picture(timestamp)?;
184        let decoded_handle = self.backend.submit_picture(
185            picture,
186            &frame.header,
187            &self.codec.last_picture,
188            &self.codec.golden_ref_picture,
189            &self.codec.alt_ref_picture,
190            frame.as_ref(),
191            self.codec.parser.segmentation(),
192            self.codec.parser.mb_lf_adjust(),
193        )?;
194
195        if self.blocking_mode == BlockingMode::Blocking {
196            decoded_handle.sync()?;
197        }
198
199        // Do DPB management
200        self.codec
201            .update_references(&frame.header, &decoded_handle)?;
202
203        if show_frame {
204            self.ready_queue.push(decoded_handle);
205        }
206
207        Ok(())
208    }
209
210    fn negotiation_possible(&self, frame: &Frame) -> bool {
211        let coded_resolution = self.coded_resolution;
212        let hdr = &frame.header;
213        let width = u32::from(hdr.width);
214        let height = u32::from(hdr.height);
215
216        width != coded_resolution.width || height != coded_resolution.height
217    }
218}
219
220impl<B> StatelessVideoDecoder for StatelessDecoder<Vp8, B>
221where
222    B: StatelessVp8DecoderBackend + TryFormat<Vp8>,
223    B::Handle: Clone + 'static,
224{
225    type Handle = B::Handle;
226    type FramePool = B::FramePool;
227
228    fn decode(&mut self, timestamp: u64, bitstream: &[u8]) -> Result<usize, DecodeError> {
229        let frame = self.codec.parser.parse_frame(bitstream)?;
230
231        if frame.header.key_frame {
232            if self.negotiation_possible(&frame) {
233                self.backend.new_sequence(&frame.header)?;
234                self.await_format_change(frame.header.clone());
235            } else if matches!(self.decoding_state, DecodingState::Reset) {
236                // We can resume decoding since the decoding parameters have not changed.
237                self.decoding_state = DecodingState::Decoding;
238            }
239        }
240
241        match &mut self.decoding_state {
242            // Skip input until we get information from the stream.
243            DecodingState::AwaitingStreamInfo | DecodingState::Reset => Ok(bitstream.len()),
244            // Ask the client to confirm the format before we can process this.
245            DecodingState::AwaitingFormat(_) => Err(DecodeError::CheckEvents),
246            DecodingState::Decoding => {
247                let len = frame.header.frame_len();
248                self.handle_frame(frame, timestamp)?;
249                Ok(len)
250            }
251        }
252    }
253
254    fn flush(&mut self) -> Result<(), DecodeError> {
255        // Note: all the submitted frames are already in the ready queue.
256        self.codec.last_picture = Default::default();
257        self.codec.golden_ref_picture = Default::default();
258        self.codec.alt_ref_picture = Default::default();
259        self.decoding_state = DecodingState::Reset;
260
261        Ok(())
262    }
263
264    fn next_event(&mut self) -> Option<DecoderEvent<B::Handle>> {
265        self.query_next_event(|decoder, hdr| {
266            decoder.coded_resolution = Resolution {
267                width: hdr.width as u32,
268                height: hdr.height as u32,
269            };
270        })
271    }
272
273    fn frame_pool(&mut self, layer: PoolLayer) -> Vec<&mut B::FramePool> {
274        self.backend.frame_pool(layer)
275    }
276
277    fn stream_info(&self) -> Option<&StreamInfo> {
278        self.backend.stream_info()
279    }
280
281    fn poll_fd(&self) -> BorrowedFd {
282        self.epoll_fd.0.as_fd()
283    }
284}
285
286#[cfg(test)]
287pub mod tests {
288    use crate::decoder::stateless::tests::test_decode_stream;
289    use crate::decoder::stateless::tests::TestStream;
290    use crate::decoder::stateless::vp8::Vp8;
291    use crate::decoder::stateless::StatelessDecoder;
292    use crate::decoder::BlockingMode;
293    use crate::utils::simple_playback_loop;
294    use crate::utils::simple_playback_loop_owned_frames;
295    use crate::utils::IvfIterator;
296    use crate::DecodedFormat;
297
298    /// Run `test` using the dummy decoder, in both blocking and non-blocking modes.
299    fn test_decoder_dummy(test: &TestStream, blocking_mode: BlockingMode) {
300        let decoder = StatelessDecoder::<Vp8, _>::new_dummy(blocking_mode).unwrap();
301
302        test_decode_stream(
303            |d, s, c| {
304                simple_playback_loop(
305                    d,
306                    IvfIterator::new(s),
307                    c,
308                    &mut simple_playback_loop_owned_frames,
309                    DecodedFormat::NV12,
310                    blocking_mode,
311                )
312            },
313            decoder,
314            test,
315            false,
316            false,
317        );
318    }
319
320    /// Same as Chromium's test-25fps.vp8
321    pub const DECODE_TEST_25FPS: TestStream = TestStream {
322        stream: include_bytes!("../../codec/vp8/test_data/test-25fps.vp8"),
323        crcs: include_str!("../../codec/vp8/test_data/test-25fps.vp8.crc"),
324    };
325
326    #[test]
327    fn test_25fps_block() {
328        test_decoder_dummy(&DECODE_TEST_25FPS, BlockingMode::Blocking);
329    }
330
331    #[test]
332    fn test_25fps_nonblock() {
333        test_decoder_dummy(&DECODE_TEST_25FPS, BlockingMode::NonBlocking);
334    }
335}