cros_codecs/decoder/stateless/
vp8.rs1#[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
35pub trait StatelessVp8DecoderBackend:
37 StatelessDecoderBackend + StatelessDecoderBackendPicture<Vp8>
38{
39 fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()>;
41
42 fn new_picture(&mut self, timestamp: u64) -> NewPictureResult<Self::Picture>;
44
45 #[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 parser: Parser,
67
68 last_picture: Option<H>,
70 golden_ref_picture: Option<H>,
72 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
87pub 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 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 => { }
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 => { }
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 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 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 self.decoding_state = DecodingState::Decoding;
238 }
239 }
240
241 match &mut self.decoding_state {
242 DecodingState::AwaitingStreamInfo | DecodingState::Reset => Ok(bitstream.len()),
244 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 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 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 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}