• 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 use std::convert::TryFrom;
6 use std::rc::Rc;
7 
8 use anyhow::anyhow;
9 use anyhow::Context;
10 use libva::BufferType;
11 use libva::Display;
12 use libva::IQMatrix;
13 use libva::IQMatrixBufferVP8;
14 use libva::ProbabilityDataBufferVP8;
15 
16 use crate::backend::vaapi::decoder::va_surface_id;
17 use crate::backend::vaapi::decoder::VaStreamInfo;
18 use crate::backend::vaapi::decoder::VaapiBackend;
19 use crate::backend::vaapi::decoder::VaapiPicture;
20 use crate::codec::vp8::parser::Header;
21 use crate::codec::vp8::parser::MbLfAdjustments;
22 use crate::codec::vp8::parser::Segmentation;
23 use crate::decoder::stateless::vp8::StatelessVp8DecoderBackend;
24 use crate::decoder::stateless::vp8::Vp8;
25 use crate::decoder::stateless::NewPictureError;
26 use crate::decoder::stateless::NewPictureResult;
27 use crate::decoder::stateless::NewStatelessDecoderError;
28 use crate::decoder::stateless::StatelessBackendResult;
29 use crate::decoder::stateless::StatelessDecoder;
30 use crate::decoder::stateless::StatelessDecoderBackend;
31 use crate::decoder::stateless::StatelessDecoderBackendPicture;
32 use crate::decoder::BlockingMode;
33 use crate::decoder::DecodedHandle;
34 use crate::video_frame::VideoFrame;
35 use crate::Rect;
36 use crate::Resolution;
37 
38 /// The number of surfaces to allocate for this codec. Same as GStreamer's vavp8dec.
39 const NUM_SURFACES: usize = 7;
40 
41 impl VaStreamInfo for &Header {
va_profile(&self) -> anyhow::Result<i32>42     fn va_profile(&self) -> anyhow::Result<i32> {
43         Ok(libva::VAProfile::VAProfileVP8Version0_3)
44     }
45 
rt_format(&self) -> anyhow::Result<u32>46     fn rt_format(&self) -> anyhow::Result<u32> {
47         Ok(libva::VA_RT_FORMAT_YUV420)
48     }
49 
min_num_surfaces(&self) -> usize50     fn min_num_surfaces(&self) -> usize {
51         NUM_SURFACES
52     }
53 
coded_size(&self) -> Resolution54     fn coded_size(&self) -> Resolution {
55         Resolution::from((self.width as u32, self.height as u32))
56     }
57 
visible_rect(&self) -> Rect58     fn visible_rect(&self) -> Rect {
59         Rect { x: 0, y: 0, width: self.coded_size().width, height: self.coded_size().height }
60     }
61 }
62 
63 /// A clamp such that min <= x <= max
clamp<T: PartialOrd>(x: T, low: T, high: T) -> T64 fn clamp<T: PartialOrd>(x: T, low: T, high: T) -> T {
65     if x > high {
66         high
67     } else if x < low {
68         low
69     } else {
70         x
71     }
72 }
73 
build_iq_matrix( frame_hdr: &Header, segmentation: &Segmentation, ) -> anyhow::Result<libva::BufferType>74 fn build_iq_matrix(
75     frame_hdr: &Header,
76     segmentation: &Segmentation,
77 ) -> anyhow::Result<libva::BufferType> {
78     let mut quantization_index: [[u16; 6]; 4] = Default::default();
79 
80     for (i, quantization_index) in quantization_index.iter_mut().enumerate() {
81         let mut qi_base: i16;
82 
83         if segmentation.segmentation_enabled {
84             qi_base = i16::from(segmentation.quantizer_update_value[i]);
85             if !segmentation.segment_feature_mode {
86                 qi_base += i16::from(frame_hdr.quant_indices.y_ac_qi);
87             }
88         } else {
89             qi_base = i16::from(frame_hdr.quant_indices.y_ac_qi);
90         }
91 
92         let mut qi = qi_base;
93         quantization_index[0] = u16::try_from(clamp(qi, 0, 127))?;
94         qi = qi_base + i16::from(frame_hdr.quant_indices.y_dc_delta);
95         quantization_index[1] = u16::try_from(clamp(qi, 0, 127))?;
96         qi = qi_base + i16::from(frame_hdr.quant_indices.y2_dc_delta);
97         quantization_index[2] = u16::try_from(clamp(qi, 0, 127))?;
98         qi = qi_base + i16::from(frame_hdr.quant_indices.y2_ac_delta);
99         quantization_index[3] = u16::try_from(clamp(qi, 0, 127))?;
100         qi = qi_base + i16::from(frame_hdr.quant_indices.uv_dc_delta);
101         quantization_index[4] = u16::try_from(clamp(qi, 0, 127))?;
102         qi = qi_base + i16::from(frame_hdr.quant_indices.uv_ac_delta);
103         quantization_index[5] = u16::try_from(clamp(qi, 0, 127))?;
104     }
105 
106     Ok(BufferType::IQMatrix(IQMatrix::VP8(IQMatrixBufferVP8::new(quantization_index))))
107 }
108 
build_probability_table(frame_hdr: &Header) -> libva::BufferType109 fn build_probability_table(frame_hdr: &Header) -> libva::BufferType {
110     BufferType::Probability(ProbabilityDataBufferVP8::new(frame_hdr.coeff_prob))
111 }
112 
build_pic_param( frame_hdr: &Header, resolution: &Resolution, seg: &Segmentation, adj: &MbLfAdjustments, last: u32, golden: u32, alt: u32, ) -> anyhow::Result<libva::BufferType>113 fn build_pic_param(
114     frame_hdr: &Header,
115     resolution: &Resolution,
116     seg: &Segmentation,
117     adj: &MbLfAdjustments,
118     last: u32,
119     golden: u32,
120     alt: u32,
121 ) -> anyhow::Result<libva::BufferType> {
122     let mut loop_filter_level: [u8; 4] = Default::default();
123     let mut loop_filter_deltas_ref_frame: [i8; 4] = Default::default();
124     let mut loop_filter_deltas_mode: [i8; 4] = Default::default();
125 
126     for i in 0..4 {
127         let mut level;
128         if seg.segmentation_enabled {
129             level = seg.lf_update_value[i];
130             if !seg.segment_feature_mode {
131                 level += i8::try_from(frame_hdr.loop_filter_level)?;
132             }
133         } else {
134             level = i8::try_from(frame_hdr.loop_filter_level)?;
135         }
136 
137         loop_filter_level[i] = clamp(u8::try_from(level)?, 0, 63);
138         loop_filter_deltas_ref_frame[i] = adj.ref_frame_delta[i];
139         loop_filter_deltas_mode[i] = adj.mb_mode_delta[i];
140     }
141 
142     let pic_fields = libva::VP8PicFields::new(
143         u32::from(!frame_hdr.key_frame),
144         u32::from(frame_hdr.version),
145         u32::from(seg.segmentation_enabled),
146         u32::from(seg.update_mb_segmentation_map),
147         u32::from(seg.update_segment_feature_data),
148         u32::from(frame_hdr.filter_type),
149         u32::from(frame_hdr.sharpness_level),
150         u32::from(adj.loop_filter_adj_enable),
151         u32::from(adj.mode_ref_lf_delta_update),
152         u32::from(frame_hdr.sign_bias_golden),
153         u32::from(frame_hdr.sign_bias_alternate),
154         u32::from(frame_hdr.mb_no_coeff_skip),
155         u32::from(frame_hdr.loop_filter_level == 0),
156     );
157 
158     let bool_coder_ctx = libva::BoolCoderContextVPX::new(
159         u8::try_from(frame_hdr.bd_range)?,
160         u8::try_from(frame_hdr.bd_value)?,
161         u8::try_from(frame_hdr.bd_count)?,
162     );
163 
164     let pic_param = libva::PictureParameterBufferVP8::new(
165         resolution.width,
166         resolution.height,
167         last,
168         golden,
169         alt,
170         &pic_fields,
171         seg.segment_prob,
172         loop_filter_level,
173         loop_filter_deltas_ref_frame,
174         loop_filter_deltas_mode,
175         frame_hdr.prob_skip_false,
176         frame_hdr.prob_intra,
177         frame_hdr.prob_last,
178         frame_hdr.prob_golden,
179         frame_hdr.mode_probs.intra_16x16_prob,
180         frame_hdr.mode_probs.intra_chroma_prob,
181         frame_hdr.mv_prob,
182         &bool_coder_ctx,
183     );
184 
185     Ok(libva::BufferType::PictureParameter(libva::PictureParameter::VP8(pic_param)))
186 }
187 
build_slice_param(frame_hdr: &Header, slice_size: usize) -> anyhow::Result<libva::BufferType>188 fn build_slice_param(frame_hdr: &Header, slice_size: usize) -> anyhow::Result<libva::BufferType> {
189     let mut partition_size: [u32; 9] = Default::default();
190     let num_of_partitions = frame_hdr.num_dct_partitions() + 1;
191 
192     partition_size[0] = frame_hdr.first_part_size - ((frame_hdr.header_size + 7) >> 3);
193 
194     partition_size[1..num_of_partitions]
195         .clone_from_slice(&frame_hdr.partition_size[..(num_of_partitions - 1)]);
196 
197     Ok(libva::BufferType::SliceParameter(libva::SliceParameter::VP8(
198         libva::SliceParameterBufferVP8::new(
199             u32::try_from(slice_size)?,
200             u32::from(frame_hdr.data_chunk_size),
201             0,
202             frame_hdr.header_size,
203             u8::try_from(num_of_partitions)?,
204             partition_size,
205         ),
206     )))
207 }
208 
209 impl<V: VideoFrame> StatelessDecoderBackendPicture<Vp8> for VaapiBackend<V> {
210     type Picture = VaapiPicture<V>;
211 }
212 
213 impl<V: VideoFrame> StatelessVp8DecoderBackend for VaapiBackend<V> {
new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()>214     fn new_sequence(&mut self, header: &Header) -> StatelessBackendResult<()> {
215         self.new_sequence(header)
216     }
217 
new_picture( &mut self, timestamp: u64, alloc_cb: &mut dyn FnMut() -> Option< <<Self as StatelessDecoderBackend>::Handle as DecodedHandle>::Frame, >, ) -> NewPictureResult<Self::Picture>218     fn new_picture(
219         &mut self,
220         timestamp: u64,
221         alloc_cb: &mut dyn FnMut() -> Option<
222             <<Self as StatelessDecoderBackend>::Handle as DecodedHandle>::Frame,
223         >,
224     ) -> NewPictureResult<Self::Picture> {
225         Ok(VaapiPicture::new(
226             timestamp,
227             Rc::clone(&self.context),
228             alloc_cb().ok_or(NewPictureError::OutOfOutputBuffers)?,
229         ))
230     }
231 
submit_picture( &mut self, mut 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>232     fn submit_picture(
233         &mut self,
234         mut picture: Self::Picture,
235         hdr: &Header,
236         last_ref: &Option<Self::Handle>,
237         golden_ref: &Option<Self::Handle>,
238         alt_ref: &Option<Self::Handle>,
239         bitstream: &[u8],
240         segmentation: &Segmentation,
241         mb_lf_adjust: &MbLfAdjustments,
242     ) -> StatelessBackendResult<Self::Handle> {
243         let last_ref = va_surface_id(last_ref);
244         let golden_ref = va_surface_id(golden_ref);
245         let alt_ref = va_surface_id(alt_ref);
246 
247         let coded_resolution =
248             &self.stream_info().ok_or(anyhow!("No stream info found!"))?.coded_resolution;
249         let context = &self.context;
250 
251         let iq_buffer = context
252             .create_buffer(build_iq_matrix(hdr, segmentation)?)
253             .context("while creating IQ matrix buffer")?;
254 
255         let probs = context
256             .create_buffer(build_probability_table(hdr))
257             .context("while creating probability table buffer")?;
258 
259         let pic_param = context
260             .create_buffer(build_pic_param(
261                 hdr,
262                 &coded_resolution,
263                 segmentation,
264                 mb_lf_adjust,
265                 last_ref,
266                 golden_ref,
267                 alt_ref,
268             )?)
269             .context("while creating pic params buffer")?;
270 
271         let slice_param = context
272             .create_buffer(build_slice_param(hdr, bitstream.len())?)
273             .context("while creating slice params buffer")?;
274 
275         let slice_data = context
276             .create_buffer(libva::BufferType::SliceData(Vec::from(bitstream)))
277             .context("while creating slice data buffer")?;
278 
279         // Add buffers with the parsed data.
280         picture.add_buffer(iq_buffer);
281         picture.add_buffer(probs);
282         picture.add_buffer(pic_param);
283         picture.add_buffer(slice_param);
284         picture.add_buffer(slice_data);
285 
286         self.process_picture::<Vp8>(picture)
287     }
288 }
289 
290 impl<V: VideoFrame> StatelessDecoder<Vp8, VaapiBackend<V>> {
291     // Creates a new instance of the decoder using the VAAPI backend.
new_vaapi( display: Rc<Display>, blocking_mode: BlockingMode, ) -> Result<Self, NewStatelessDecoderError>292     pub fn new_vaapi(
293         display: Rc<Display>,
294         blocking_mode: BlockingMode,
295     ) -> Result<Self, NewStatelessDecoderError> {
296         Self::new(VaapiBackend::new(display, false), blocking_mode)
297     }
298 }
299 
300 #[cfg(test)]
301 mod tests {
302     use libva::BufferType;
303     use libva::Display;
304     use libva::IQMatrix;
305     use libva::PictureParameter;
306     use libva::SliceParameter;
307 
308     use crate::bitstream_utils::IvfIterator;
309     use crate::codec::vp8::parser::Parser;
310     use crate::decoder::stateless::tests::test_decode_stream;
311     use crate::decoder::stateless::tests::TestStream;
312     use crate::decoder::stateless::StatelessDecoder;
313     use crate::decoder::BlockingMode;
314     use crate::utils::simple_playback_loop;
315     use crate::utils::simple_playback_loop_owned_frames;
316     use crate::DecodedFormat;
317     use crate::Resolution;
318 
319     use super::*;
320 
321     /// Run `test` using the vaapi decoder, in both blocking and non-blocking modes.
test_decoder_vaapi( test: &TestStream, output_format: DecodedFormat, blocking_mode: BlockingMode, )322     fn test_decoder_vaapi(
323         test: &TestStream,
324         output_format: DecodedFormat,
325         blocking_mode: BlockingMode,
326     ) {
327         let display = Display::open().unwrap();
328         let decoder = StatelessDecoder::<Vp8, _>::new_vaapi::<()>(display, blocking_mode).unwrap();
329 
330         test_decode_stream(
331             |d, s, c| {
332                 simple_playback_loop(
333                     d,
334                     IvfIterator::new(s),
335                     c,
336                     &mut simple_playback_loop_owned_frames,
337                     output_format,
338                     blocking_mode,
339                 )
340             },
341             decoder,
342             test,
343             true,
344             false,
345         );
346     }
347 
348     #[test]
349     // Ignore this test by default as it requires libva-compatible hardware.
350     #[ignore]
test_25fps_block()351     fn test_25fps_block() {
352         use crate::decoder::stateless::vp8::tests::DECODE_TEST_25FPS;
353         test_decoder_vaapi(&DECODE_TEST_25FPS, DecodedFormat::NV12, BlockingMode::Blocking);
354     }
355 
356     #[test]
357     // Ignore this test by default as it requires libva-compatible hardware.
358     #[ignore]
test_25fps_nonblock()359     fn test_25fps_nonblock() {
360         use crate::decoder::stateless::vp8::tests::DECODE_TEST_25FPS;
361         test_decoder_vaapi(&DECODE_TEST_25FPS, DecodedFormat::NV12, BlockingMode::NonBlocking);
362     }
363 
364     #[test]
365     /// Check that we are able to build the VA picture parameters from the stream properly.
build_pic_params()366     fn build_pic_params() {
367         const TEST_STREAM: &[u8] = include_bytes!("../../../codec/vp8/test_data/test-25fps.vp8");
368         const TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_0: &[u8] =
369             include_bytes!("../../../codec/vp8/test_data/test-25fps-vp8-probability-table-0.bin");
370         const TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_1: &[u8] =
371             include_bytes!("../../../codec/vp8/test_data/test-25fps-vp8-probability-table-1.bin");
372         const TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_2: &[u8] =
373             include_bytes!("../../../codec/vp8/test_data/test-25fps-vp8-probability-table-2.bin");
374 
375         let mut parser: Parser = Default::default();
376         let mut ivf_iter = IvfIterator::new(TEST_STREAM);
377 
378         // FRAME 0
379 
380         let packet = ivf_iter.next().unwrap();
381         assert_eq!(packet.len(), 14788);
382 
383         let frame = parser.parse_frame(packet).unwrap();
384 
385         let resolution =
386             Resolution { width: frame.header.width as u32, height: frame.header.height as u32 };
387 
388         let pic_param = build_pic_param(
389             &frame.header,
390             &resolution,
391             parser.segmentation(),
392             parser.mb_lf_adjust(),
393             libva::VA_INVALID_SURFACE,
394             libva::VA_INVALID_SURFACE,
395             libva::VA_INVALID_SURFACE,
396         )
397         .unwrap();
398         let pic_param = match pic_param {
399             BufferType::PictureParameter(PictureParameter::VP8(pic_param)) => pic_param,
400             _ => panic!(),
401         };
402 
403         let iq_matrix = build_iq_matrix(&frame.header, parser.segmentation()).unwrap();
404         let iq_matrix = match iq_matrix {
405             BufferType::IQMatrix(IQMatrix::VP8(iq_matrix)) => iq_matrix,
406             _ => panic!(),
407         };
408 
409         let prob_table = build_probability_table(&frame.header);
410         let prob_table = match prob_table {
411             BufferType::Probability(prob_table) => prob_table,
412             _ => panic!(),
413         };
414 
415         let slice_param = build_slice_param(&frame.header, packet.len()).unwrap();
416         let slice_param = match slice_param {
417             BufferType::SliceParameter(SliceParameter::VP8(slice_param)) => slice_param,
418             _ => panic!(),
419         };
420 
421         assert_eq!(iq_matrix.inner().quantization_index, [[4; 6]; 4]);
422         for i in 0..4 {
423             for j in 0..8 {
424                 for k in 0..3 {
425                     for l in 0..11 {
426                         const OFF_I: usize = 8 * 3 * 11;
427                         const OFF_J: usize = 3 * 11;
428                         const OFF_K: usize = 11;
429                         // maybe std::transmute?
430                         assert_eq!(
431                             prob_table.inner().dct_coeff_probs[i][j][k][l],
432                             TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_0
433                                 [(i * OFF_I) + (j * OFF_J) + (k * OFF_K) + l]
434                         );
435                     }
436                 }
437             }
438         }
439 
440         assert_eq!(pic_param.inner().frame_width, 320);
441         assert_eq!(pic_param.inner().frame_height, 240);
442         assert_eq!(pic_param.inner().last_ref_frame, libva::VA_INVALID_SURFACE);
443         assert_eq!(pic_param.inner().golden_ref_frame, libva::VA_INVALID_SURFACE);
444         assert_eq!(pic_param.inner().alt_ref_frame, libva::VA_INVALID_SURFACE);
445         assert_eq!(pic_param.inner().out_of_loop_frame, libva::VA_INVALID_SURFACE);
446 
447         // Safe because this bitfield is initialized by the decoder.
448         assert_eq!(unsafe { pic_param.inner().pic_fields.value }, unsafe {
449             libva::VP8PicFields::new(0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1).inner().value
450         });
451 
452         assert_eq!(pic_param.inner().mb_segment_tree_probs, [0; 3]);
453         assert_eq!(pic_param.inner().loop_filter_level, [0; 4]);
454         assert_eq!(pic_param.inner().loop_filter_deltas_ref_frame, [2, 0, -2, -2]);
455         assert_eq!(pic_param.inner().loop_filter_deltas_mode, [4, -2, 2, 4]);
456         assert_eq!(pic_param.inner().prob_skip_false, 0xbe);
457         assert_eq!(pic_param.inner().prob_intra, 0);
458         assert_eq!(pic_param.inner().prob_last, 0);
459         assert_eq!(pic_param.inner().prob_gf, 0);
460 
461         assert_eq!(pic_param.inner().y_mode_probs, [0x91, 0x9c, 0xa3, 0x80]);
462         assert_eq!(pic_param.inner().uv_mode_probs, [0x8e, 0x72, 0xb7]);
463         assert_eq!(
464             pic_param.inner().mv_probs[0],
465             [
466                 0xa2, 0x80, 0xe1, 0x92, 0xac, 0x93, 0xd6, 0x27, 0x9c, 0x80, 0x81, 0x84, 0x4b, 0x91,
467                 0xb2, 0xce, 0xef, 0xfe, 0xfe
468             ]
469         );
470         assert_eq!(
471             pic_param.inner().mv_probs[1],
472             [
473                 0xa4, 0x80, 0xcc, 0xaa, 0x77, 0xeb, 0x8c, 0xe6, 0xe4, 0x80, 0x82, 0x82, 0x4a, 0x94,
474                 0xb4, 0xcb, 0xec, 0xfe, 0xfe,
475             ]
476         );
477 
478         assert_eq!(pic_param.inner().bool_coder_ctx.range, 0xfc);
479         assert_eq!(pic_param.inner().bool_coder_ctx.value, 0x39);
480         assert_eq!(pic_param.inner().bool_coder_ctx.count, 0x0);
481 
482         assert_eq!(
483             slice_param.inner(),
484             libva::SliceParameterBufferVP8::new(
485                 14788,
486                 10,
487                 0,
488                 3040,
489                 2,
490                 [926, 13472, 0, 0, 0, 0, 0, 0, 0],
491             )
492             .inner(),
493         );
494 
495         // FRAME 1
496 
497         let packet = ivf_iter.next().unwrap();
498         assert_eq!(packet.len(), 257);
499 
500         let frame = parser.parse_frame(packet).unwrap();
501 
502         let pic_param = build_pic_param(
503             &frame.header,
504             &resolution,
505             parser.segmentation(),
506             parser.mb_lf_adjust(),
507             0,
508             0,
509             0,
510         )
511         .unwrap();
512         let pic_param = match pic_param {
513             BufferType::PictureParameter(PictureParameter::VP8(pic_param)) => pic_param,
514             _ => panic!(),
515         };
516 
517         let iq_matrix = build_iq_matrix(&frame.header, parser.segmentation()).unwrap();
518         let iq_matrix = match iq_matrix {
519             BufferType::IQMatrix(IQMatrix::VP8(iq_matrix)) => iq_matrix,
520             _ => panic!(),
521         };
522 
523         let prob_table = build_probability_table(&frame.header);
524         let prob_table = match prob_table {
525             BufferType::Probability(prob_table) => prob_table,
526             _ => panic!(),
527         };
528 
529         let slice_param = build_slice_param(&frame.header, packet.len()).unwrap();
530         let slice_param = match slice_param {
531             BufferType::SliceParameter(SliceParameter::VP8(slice_param)) => slice_param,
532             _ => panic!(),
533         };
534 
535         assert_eq!(iq_matrix.inner().quantization_index, [[0x7f; 6]; 4]);
536         for i in 0..4 {
537             for j in 0..8 {
538                 for k in 0..3 {
539                     for l in 0..11 {
540                         const OFF_I: usize = 8 * 3 * 11;
541                         const OFF_J: usize = 3 * 11;
542                         const OFF_K: usize = 11;
543                         // maybe std::transmute?
544                         assert_eq!(
545                             prob_table.inner().dct_coeff_probs[i][j][k][l],
546                             TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_1
547                                 [(i * OFF_I) + (j * OFF_J) + (k * OFF_K) + l]
548                         );
549                     }
550                 }
551             }
552         }
553         assert_eq!(pic_param.inner().frame_width, 320);
554         assert_eq!(pic_param.inner().frame_height, 240);
555         assert_eq!(pic_param.inner().last_ref_frame, 0);
556         assert_eq!(pic_param.inner().golden_ref_frame, 0);
557         assert_eq!(pic_param.inner().alt_ref_frame, 0);
558         assert_eq!(pic_param.inner().out_of_loop_frame, libva::VA_INVALID_SURFACE);
559 
560         // Safe because this bitfield is initialized by the decoder.
561         assert_eq!(unsafe { pic_param.inner().pic_fields.value }, unsafe {
562             libva::VP8PicFields::new(1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0).inner().value
563         });
564 
565         assert_eq!(pic_param.inner().mb_segment_tree_probs, [0; 3]);
566         assert_eq!(pic_param.inner().loop_filter_level, [44; 4]);
567         assert_eq!(pic_param.inner().loop_filter_deltas_ref_frame, [2, 0, -2, -2]);
568         assert_eq!(pic_param.inner().loop_filter_deltas_mode, [4, -2, 2, 4]);
569         assert_eq!(pic_param.inner().prob_skip_false, 0x11);
570         assert_eq!(pic_param.inner().prob_intra, 0x2a);
571         assert_eq!(pic_param.inner().prob_last, 0xff);
572         assert_eq!(pic_param.inner().prob_gf, 0x80);
573 
574         assert_eq!(pic_param.inner().y_mode_probs, [0x70, 0x56, 0x8c, 0x25]);
575         assert_eq!(pic_param.inner().uv_mode_probs, [0xa2, 0x65, 0xcc]);
576         assert_eq!(
577             pic_param.inner().mv_probs[0],
578             [
579                 0xa2, 0x80, 0xe1, 0x92, 0xac, 0x93, 0xd6, 0x27, 0x9c, 0x80, 0x81, 0x84, 0x4b, 0x91,
580                 0xb2, 0xce, 0xef, 0xfe, 0xfe,
581             ]
582         );
583         assert_eq!(
584             pic_param.inner().mv_probs[1],
585             [
586                 0xa4, 0x80, 0xcc, 0xaa, 0x77, 0xeb, 0x8c, 0xe6, 0xe4, 0x80, 0x82, 0x82, 0x4a, 0x94,
587                 0xb4, 0xcb, 0xec, 0xfe, 0xfe,
588             ]
589         );
590 
591         assert_eq!(pic_param.inner().bool_coder_ctx.range, 0xde);
592         assert_eq!(pic_param.inner().bool_coder_ctx.value, 0x39);
593         assert_eq!(pic_param.inner().bool_coder_ctx.count, 0x7);
594 
595         assert_eq!(
596             slice_param.inner(),
597             libva::SliceParameterBufferVP8::new(257, 3, 0, 129, 2, [143, 94, 0, 0, 0, 0, 0, 0, 0],)
598                 .inner()
599         );
600 
601         // FRAME 2
602 
603         let packet = ivf_iter.next().unwrap();
604         assert_eq!(packet.len(), 131);
605 
606         let frame = parser.parse_frame(packet).unwrap();
607 
608         let pic_param = build_pic_param(
609             &frame.header,
610             &resolution,
611             parser.segmentation(),
612             parser.mb_lf_adjust(),
613             1,
614             0,
615             0,
616         )
617         .unwrap();
618         let pic_param = match pic_param {
619             BufferType::PictureParameter(PictureParameter::VP8(pic_param)) => pic_param,
620             _ => panic!(),
621         };
622 
623         let iq_matrix = build_iq_matrix(&frame.header, parser.segmentation()).unwrap();
624         let iq_matrix = match iq_matrix {
625             BufferType::IQMatrix(IQMatrix::VP8(iq_matrix)) => iq_matrix,
626             _ => panic!(),
627         };
628 
629         let prob_table = build_probability_table(&frame.header);
630         let prob_table = match prob_table {
631             BufferType::Probability(prob_table) => prob_table,
632             _ => panic!(),
633         };
634 
635         let slice_param = build_slice_param(&frame.header, packet.len()).unwrap();
636         let slice_param = match slice_param {
637             BufferType::SliceParameter(SliceParameter::VP8(slice_param)) => slice_param,
638             _ => panic!(),
639         };
640 
641         assert_eq!(iq_matrix.inner().quantization_index, [[0x7f; 6]; 4]);
642         for i in 0..4 {
643             for j in 0..8 {
644                 for k in 0..3 {
645                     for l in 0..11 {
646                         const OFF_I: usize = 8 * 3 * 11;
647                         const OFF_J: usize = 3 * 11;
648                         const OFF_K: usize = 11;
649                         // maybe std::transmute?
650                         assert_eq!(
651                             prob_table.inner().dct_coeff_probs[i][j][k][l],
652                             TEST_25_FPS_VP8_STREAM_PROBABILITY_TABLE_2
653                                 [(i * OFF_I) + (j * OFF_J) + (k * OFF_K) + l]
654                         );
655                     }
656                 }
657             }
658         }
659         assert_eq!(pic_param.inner().frame_width, 320);
660         assert_eq!(pic_param.inner().frame_height, 240);
661         assert_eq!(pic_param.inner().last_ref_frame, 1);
662         assert_eq!(pic_param.inner().golden_ref_frame, 0);
663         assert_eq!(pic_param.inner().alt_ref_frame, 0);
664         assert_eq!(pic_param.inner().out_of_loop_frame, libva::VA_INVALID_SURFACE);
665 
666         // Safe because this bitfield is initialized by the decoder.
667         assert_eq!(unsafe { pic_param.inner().pic_fields.value }, unsafe {
668             libva::VP8PicFields::new(1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0).inner().value
669         });
670 
671         assert_eq!(pic_param.inner().mb_segment_tree_probs, [0; 3]);
672         assert_eq!(pic_param.inner().loop_filter_level, [28; 4]);
673         assert_eq!(pic_param.inner().loop_filter_deltas_ref_frame, [2, 0, -2, -2]);
674         assert_eq!(pic_param.inner().loop_filter_deltas_mode, [4, -2, 2, 4]);
675         assert_eq!(pic_param.inner().prob_skip_false, 0x6);
676         assert_eq!(pic_param.inner().prob_intra, 0x1);
677         assert_eq!(pic_param.inner().prob_last, 0xf8);
678         assert_eq!(pic_param.inner().prob_gf, 0xff);
679 
680         assert_eq!(pic_param.inner().y_mode_probs, [0x70, 0x56, 0x8c, 0x25]);
681         assert_eq!(pic_param.inner().uv_mode_probs, [0xa2, 0x65, 0xcc]);
682         assert_eq!(
683             pic_param.inner().mv_probs[0],
684             [
685                 0xa2, 0x80, 0xe1, 0x92, 0xac, 0x93, 0xd6, 0x27, 0x9c, 0x80, 0x81, 0x84, 0x4b, 0x91,
686                 0xb2, 0xce, 0xef, 0xfe, 0xfe,
687             ]
688         );
689         assert_eq!(
690             pic_param.inner().mv_probs[1],
691             [
692                 0xa4, 0x80, 0xcc, 0xaa, 0x77, 0xeb, 0x8c, 0xe6, 0xe4, 0x80, 0x82, 0x82, 0x4a, 0x94,
693                 0xb4, 0xcb, 0xec, 0xfe, 0xfe,
694             ]
695         );
696 
697         assert_eq!(pic_param.inner().bool_coder_ctx.range, 0xb1);
698         assert_eq!(pic_param.inner().bool_coder_ctx.value, 0xd);
699         assert_eq!(pic_param.inner().bool_coder_ctx.count, 0x2);
700 
701         assert_eq!(
702             slice_param.inner(),
703             libva::SliceParameterBufferVP8::new(131, 3, 0, 86, 2, [66, 51, 0, 0, 0, 0, 0, 0, 0],)
704                 .inner()
705         );
706     }
707 }
708