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