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