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