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