1use std::convert::TryFrom;
6use std::fmt;
7
8use log::debug;
9
10use crate::bitstream_utils::BitReader;
11use crate::codec::vp8::bool_decoder::BoolDecoder;
12use crate::codec::vp8::bool_decoder::BoolDecoderError;
13use crate::codec::vp8::bool_decoder::BoolDecoderResult;
14use crate::codec::vp8::bool_decoder::BoolDecoderState;
15use crate::codec::vp8::probs::COEFF_DEFAULT_PROBS;
16use crate::codec::vp8::probs::COEFF_UPDATE_PROBS;
17use crate::codec::vp8::probs::KF_UV_MODE_PROBS;
18use crate::codec::vp8::probs::KF_Y_MODE_PROBS;
19use crate::codec::vp8::probs::MV_DEFAULT_PROBS;
20use crate::codec::vp8::probs::MV_UPDATE_PROBS;
21use crate::codec::vp8::probs::NK_UV_MODE_PROBS;
22use crate::codec::vp8::probs::NK_Y_MODE_PROBS;
23
24#[derive(Clone, Debug, Default, PartialEq, Eq)]
26pub struct QuantIndices {
27 pub y_ac_qi: u8,
30 pub y_dc_delta: i8,
33 pub y2_dc_delta: i8,
36 pub y2_ac_delta: i8,
39 pub uv_dc_delta: i8,
42 pub uv_ac_delta: i8,
45}
46
47#[derive(Clone, Debug, Default, PartialEq, Eq)]
48pub struct MbLfAdjustments {
49 pub loop_filter_adj_enable: bool,
52 pub mode_ref_lf_delta_update: bool,
55
56 pub ref_frame_delta: [i8; 4],
60 pub mb_mode_delta: [i8; 4],
63}
64
65#[derive(Clone, Debug, Default, PartialEq, Eq)]
66pub struct Segmentation {
67 pub segmentation_enabled: bool,
69 pub update_mb_segmentation_map: bool,
71 pub update_segment_feature_data: bool,
73
74 pub segment_feature_mode: bool,
78 pub quantizer_update_value: [i8; 4],
80 pub lf_update_value: [i8; 4],
82
83 pub segment_prob: [u8; 3],
86}
87
88#[derive(Clone, Debug, Default, PartialEq, Eq)]
89pub struct ModeProbs {
90 pub intra_16x16_prob: [u8; 4],
93 pub intra_chroma_prob: [u8; 3],
96}
97
98#[derive(Clone, Debug, Default, PartialEq, Eq)]
99pub struct Header {
100 pub key_frame: bool,
102 pub version: u8,
104 pub show_frame: bool,
106 pub data_chunk_size: u8,
108 pub first_part_size: u32,
111
112 pub width: u16,
114 pub height: u16,
116 pub horiz_scale_code: u8,
118 pub vert_scale_code: u8,
120 pub color_space: bool,
122 pub clamping_type: bool,
125 pub filter_type: bool,
127 pub loop_filter_level: u8,
129 pub sharpness_level: u8,
131 log2_nbr_of_dct_partitions: u8,
134
135 pub partition_size: [u32; 8],
136
137 pub quant_indices: QuantIndices,
139
140 pub refresh_entropy_probs: bool,
143 pub refresh_last: bool,
146
147 pub refresh_golden_frame: bool,
149 pub refresh_alternate_frame: bool,
152 pub copy_buffer_to_golden: u8,
154 pub copy_buffer_to_alternate: u8,
156 pub sign_bias_golden: bool,
158 pub sign_bias_alternate: bool,
161
162 pub coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
164 pub mv_prob: [[u8; 19]; 2],
166
167 pub mb_no_coeff_skip: bool,
170 pub prob_skip_false: u8,
173 pub prob_intra: u8,
175 pub prob_last: u8,
178 pub prob_golden: u8,
181 pub mode_probs: ModeProbs,
183
184 pub bd_range: usize,
186 pub bd_value: usize,
188 pub bd_count: isize,
190
191 pub header_size: u32,
194}
195
196#[derive(Debug)]
197pub enum ParseUncompressedChunkError {
198 InvalidStartCode(u32),
199 IoError(String),
200}
201
202impl fmt::Display for ParseUncompressedChunkError {
203 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
204 match self {
205 ParseUncompressedChunkError::InvalidStartCode(x) => {
206 write!(f, "invalid start code {}", x)
207 }
208 ParseUncompressedChunkError::IoError(x) => write!(f, "I/O error: {}", x),
209 }
210 }
211}
212
213#[derive(Debug)]
214pub enum ComputePartitionSizesError {
215 EndOfHeader,
216 PartitionTooLarge,
217}
218
219impl fmt::Display for ComputePartitionSizesError {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 match self {
222 ComputePartitionSizesError::EndOfHeader => write!(f, "unexpected end of header"),
223 ComputePartitionSizesError::PartitionTooLarge => {
224 write!(f, "partition size not fitting in a u32")
225 }
226 }
227 }
228}
229
230impl Header {
231 pub fn num_dct_partitions(&self) -> usize {
234 1 << self.log2_nbr_of_dct_partitions
235 }
236
237 pub fn frame_len(&self) -> usize {
239 std::iter::once(self.data_chunk_size as usize)
241 .chain(std::iter::once(self.first_part_size as usize))
243 .chain(std::iter::once(self.num_dct_partitions().saturating_sub(1) * 3))
245 .chain(self.partition_size.iter().take(self.num_dct_partitions()).map(|s| *s as usize))
247 .sum()
248 }
249
250 fn parse_uncompressed_data_chunk(
252 bitstream: &[u8],
253 ) -> Result<Self, ParseUncompressedChunkError> {
254 debug!("Parsing VP8 uncompressed data chunk.");
255
256 let mut reader = BitReader::new(bitstream, false);
257
258 let frame_tag =
259 reader.read_le::<u32>(3).map_err(|err| ParseUncompressedChunkError::IoError(err))?;
260
261 let mut header = Header {
262 key_frame: (frame_tag & 0x1) == 0,
263 version: ((frame_tag >> 1) & 0x07) as u8,
264 show_frame: ((frame_tag >> 4) & 0x1) != 0,
265 first_part_size: (frame_tag >> 5) & 0x7ffff,
266 ..Default::default()
267 };
268
269 if header.key_frame {
270 let start_code = reader
271 .read_le::<u32>(3)
272 .map_err(|err| ParseUncompressedChunkError::IoError(err))?;
273
274 if start_code != 0x2a019d {
275 return Err(ParseUncompressedChunkError::InvalidStartCode(start_code));
276 }
277
278 let size_code = reader
279 .read_le::<u16>(2)
280 .map_err(|err| ParseUncompressedChunkError::IoError(err))?;
281 header.horiz_scale_code = (size_code >> 14) as u8;
282 header.width = size_code & 0x3fff;
283
284 let size_code = reader
285 .read_le::<u16>(2)
286 .map_err(|err| ParseUncompressedChunkError::IoError(err))?;
287 header.vert_scale_code = (size_code >> 14) as u8;
288 header.height = size_code & 0x3fff;
289 }
290
291 if reader.position() % 8 != 0 {
292 Err(ParseUncompressedChunkError::IoError("Misaligned VP8 header".into()))
293 } else {
294 header.data_chunk_size = (reader.position() / 8) as u8;
295 Ok(header)
296 }
297 }
298
299 fn compute_partition_sizes(&mut self, data: &[u8]) -> Result<(), ComputePartitionSizesError> {
300 let num_partitions = self.num_dct_partitions();
301 let mut part_size_ofs = self.first_part_size as usize;
302 let mut ofs = part_size_ofs + 3 * (num_partitions - 1);
303
304 if ofs > data.len() {
305 return Err(ComputePartitionSizesError::EndOfHeader);
306 }
307
308 for i in 0..num_partitions - 1 {
309 let b0 = u32::from(data[part_size_ofs]);
310 let b1 = u32::from(data[part_size_ofs + 1]) << 8;
311 let b2 = u32::from(data[part_size_ofs + 2]) << 16;
312
313 let part_size = b0 | b1 | b2;
314 part_size_ofs += 3;
315
316 self.partition_size[i] = part_size;
317 ofs += part_size as usize;
318 }
319
320 if ofs > data.len() {
321 return Err(ComputePartitionSizesError::EndOfHeader);
322 }
323
324 self.partition_size[num_partitions - 1] = u32::try_from(data.len() - ofs)
325 .map_err(|_| ComputePartitionSizesError::PartitionTooLarge)?;
326 Ok(())
327 }
328}
329
330pub struct Frame<'a> {
332 bitstream: &'a [u8],
334 frame_len: usize,
336 pub header: Header,
338}
339
340impl<'a> AsRef<[u8]> for Frame<'a> {
341 fn as_ref(&self) -> &[u8] {
342 &self.bitstream[..self.frame_len]
343 }
344}
345
346#[derive(Clone, Debug, PartialEq, Eq)]
348pub struct Parser {
349 segmentation: Segmentation,
351 mb_lf_adjust: MbLfAdjustments,
353 coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
355 mv_prob: [[u8; 19]; 2],
357 mode_probs: ModeProbs,
359}
360
361#[derive(Debug)]
362pub enum ParseFrameError {
363 ParseUncompressedChunk(ParseUncompressedChunkError),
364 InvalidPartitionSize(usize, usize),
365 ParseFrameHeader(BoolDecoderError),
366 ComputePartitionSizes(ComputePartitionSizesError),
367 BitstreamTooShort(usize, usize),
368}
369
370impl fmt::Display for ParseFrameError {
371 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372 match self {
373 ParseFrameError::ParseUncompressedChunk(x) => {
374 write!(f, "error while parsing uncompressed chunk of frame: {}", x)
375 }
376 ParseFrameError::InvalidPartitionSize(x, y) => {
377 write!(f, "partition end {} is bigger than bitstream length {}", x, y)
378 }
379 ParseFrameError::ParseFrameHeader(x) => {
380 write!(f, "error while parsing frame header: {}", x)
381 }
382 ParseFrameError::ComputePartitionSizes(x) => {
383 write!(f, "error while computing frames partitions sizes: {}", x)
384 }
385 ParseFrameError::BitstreamTooShort(x, y) => {
386 write!(f, "bitstream is shorter ({} bytes) than computed length of frame {}", x, y)
387 }
388 }
389 }
390}
391
392impl From<ParseUncompressedChunkError> for ParseFrameError {
393 fn from(err: ParseUncompressedChunkError) -> Self {
394 ParseFrameError::ParseUncompressedChunk(err)
395 }
396}
397
398impl From<BoolDecoderError> for ParseFrameError {
399 fn from(err: BoolDecoderError) -> Self {
400 ParseFrameError::ParseFrameHeader(err)
401 }
402}
403
404impl From<ComputePartitionSizesError> for ParseFrameError {
405 fn from(err: ComputePartitionSizesError) -> Self {
406 ParseFrameError::ComputePartitionSizes(err)
407 }
408}
409
410impl Parser {
411 pub fn segmentation(&self) -> &Segmentation {
412 &self.segmentation
413 }
414
415 pub fn mb_lf_adjust(&self) -> &MbLfAdjustments {
416 &self.mb_lf_adjust
417 }
418
419 fn mode_probs_init_defaults(mode_probs: &mut ModeProbs, key_frame: bool) {
420 if key_frame {
421 mode_probs.intra_16x16_prob = KF_Y_MODE_PROBS;
422 mode_probs.intra_chroma_prob = KF_UV_MODE_PROBS;
423 } else {
424 mode_probs.intra_16x16_prob = NK_Y_MODE_PROBS;
425 mode_probs.intra_chroma_prob = NK_UV_MODE_PROBS;
426 }
427 }
428
429 fn update_segmentation(bd: &mut BoolDecoder, seg: &mut Segmentation) -> BoolDecoderResult<()> {
430 seg.update_mb_segmentation_map = false;
431 seg.update_segment_feature_data = false;
432
433 seg.segmentation_enabled = bd.read_bool()?;
434 if !seg.segmentation_enabled {
435 return Ok(());
436 }
437
438 seg.update_mb_segmentation_map = bd.read_bool()?;
439 seg.update_segment_feature_data = bd.read_bool()?;
440
441 if seg.update_segment_feature_data {
442 seg.segment_feature_mode = bd.read_bool()?;
443
444 for value in seg.quantizer_update_value.iter_mut() {
445 let update = bd.read_bool()?;
446 if update {
447 *value = bd.read_sint(7)?;
448 } else {
449 *value = 0;
452 }
453 }
454
455 for value in seg.lf_update_value.iter_mut() {
456 let update = bd.read_bool()?;
457 if update {
458 *value = bd.read_sint(6)?;
459 } else {
460 *value = 0;
463 }
464 }
465
466 if seg.update_mb_segmentation_map {
467 for value in seg.segment_prob.iter_mut() {
468 let update = bd.read_bool()?;
469 if update {
470 *value = bd.read_uint(8)?;
471 } else {
472 *value = 255;
475 }
476 }
477 }
478 }
479
480 Ok(())
481 }
482
483 fn parse_mb_lf_adjustments(
484 bd: &mut BoolDecoder,
485 adj: &mut MbLfAdjustments,
486 ) -> BoolDecoderResult<()> {
487 adj.mode_ref_lf_delta_update = false;
488
489 adj.loop_filter_adj_enable = bd.read_bool()?;
490 if !adj.loop_filter_adj_enable {
491 return Ok(());
492 }
493
494 adj.mode_ref_lf_delta_update = bd.read_bool()?;
495 if !adj.mode_ref_lf_delta_update {
496 return Ok(());
497 }
498
499 for value in adj.ref_frame_delta.iter_mut() {
500 let update = bd.read_bool()?;
501 if update {
502 *value = bd.read_sint(6)?;
503 }
504 }
505
506 for value in adj.mb_mode_delta.iter_mut() {
507 let update = bd.read_bool()?;
508 if update {
509 *value = bd.read_sint(6)?;
510 }
511 }
512
513 Ok(())
514 }
515
516 fn parse_quant_indices(bd: &mut BoolDecoder, q: &mut QuantIndices) -> BoolDecoderResult<()> {
517 q.y_ac_qi = bd.read_uint(7)?;
518
519 let y_dc_delta_present = bd.read_bool()?;
520
521 if y_dc_delta_present {
522 q.y_dc_delta = bd.read_sint(4)?;
523 } else {
524 q.y_dc_delta = 0;
525 }
526
527 let y2_dc_delta_present = bd.read_bool()?;
528 if y2_dc_delta_present {
529 q.y2_dc_delta = bd.read_sint(4)?;
530 } else {
531 q.y2_dc_delta = 0;
532 }
533
534 let y2_ac_delta_present = bd.read_bool()?;
535 if y2_ac_delta_present {
536 q.y2_ac_delta = bd.read_sint(4)?;
537 } else {
538 q.y2_ac_delta = 0;
539 }
540
541 let uv_dc_delta_present = bd.read_bool()?;
542 if uv_dc_delta_present {
543 q.uv_dc_delta = bd.read_sint(4)?;
544 } else {
545 q.uv_dc_delta = 0;
546 }
547
548 let uv_ac_delta_present = bd.read_bool()?;
549 if uv_ac_delta_present {
550 q.uv_ac_delta = bd.read_sint(4)?;
551 } else {
552 q.uv_ac_delta = 0;
553 }
554
555 Ok(())
556 }
557
558 fn parse_token_prob_update(
559 bd: &mut BoolDecoder,
560 coeff_probs: &mut [[[[u8; 11]; 3]; 8]; 4],
561 ) -> BoolDecoderResult<()> {
562 for (i, vi) in coeff_probs.iter_mut().enumerate() {
563 for (j, vj) in vi.iter_mut().enumerate() {
564 for (k, vk) in vj.iter_mut().enumerate() {
565 for (l, prob) in vk.iter_mut().enumerate() {
566 let update = bd.read_bool_with_prob(COEFF_UPDATE_PROBS[i][j][k][l])?;
567 if update {
568 *prob = bd.read_uint(8)?;
569 }
570 }
571 }
572 }
573 }
574
575 Ok(())
576 }
577
578 fn parse_mv_prob_update(
579 bd: &mut BoolDecoder,
580 mv_probs: &mut [[u8; 19]; 2],
581 ) -> BoolDecoderResult<()> {
582 for (i, vi) in mv_probs.iter_mut().enumerate() {
583 for (j, prob) in vi.iter_mut().enumerate() {
584 let update = bd.read_bool_with_prob(MV_UPDATE_PROBS[i][j])?;
585 if update {
586 let mv_prob_update = bd.read_uint::<u8>(7)?;
587
588 if mv_prob_update > 0 {
589 *prob = mv_prob_update << 1;
590 } else {
591 *prob = 1;
592 }
593 }
594 }
595 }
596
597 Ok(())
598 }
599
600 fn parse_frame_header(&mut self, data: &[u8], frame: &mut Header) -> BoolDecoderResult<()> {
601 debug!("Parsing VP8 frame header.");
602 let mut bd = BoolDecoder::new(data);
603
604 if frame.key_frame {
605 frame.color_space = bd.read_bool()?;
606 frame.clamping_type = bd.read_bool()?;
607 }
608
609 Parser::update_segmentation(&mut bd, &mut self.segmentation)?;
610
611 frame.filter_type = bd.read_bool()?;
612 frame.loop_filter_level = bd.read_uint(6)?;
613 frame.sharpness_level = bd.read_uint(3)?;
614
615 Parser::parse_mb_lf_adjustments(&mut bd, &mut self.mb_lf_adjust)?;
616
617 frame.log2_nbr_of_dct_partitions = bd.read_uint(2)?;
618
619 Parser::parse_quant_indices(&mut bd, &mut frame.quant_indices)?;
620
621 frame.copy_buffer_to_golden = 0;
622 frame.copy_buffer_to_alternate = 0;
623
624 if frame.key_frame {
625 frame.refresh_entropy_probs = bd.read_bool()?;
626
627 frame.refresh_last = true;
628 frame.refresh_golden_frame = true;
629 frame.refresh_alternate_frame = true;
630
631 Parser::mode_probs_init_defaults(&mut frame.mode_probs, true);
632 } else {
633 frame.refresh_golden_frame = bd.read_bool()?;
634 frame.refresh_alternate_frame = bd.read_bool()?;
635
636 if !frame.refresh_golden_frame {
637 frame.copy_buffer_to_golden = bd.read_uint(2)?;
638 }
639
640 if !frame.refresh_alternate_frame {
641 frame.copy_buffer_to_alternate = bd.read_uint(2)?;
642 }
643
644 frame.sign_bias_golden = bd.read_bool()?;
645 frame.sign_bias_alternate = bd.read_bool()?;
646 frame.refresh_entropy_probs = bd.read_bool()?;
647 frame.refresh_last = bd.read_bool()?;
648
649 frame.mode_probs = self.mode_probs.clone();
650 }
651
652 frame.coeff_prob = self.coeff_prob;
653 frame.mv_prob = self.mv_prob;
654
655 Parser::parse_token_prob_update(&mut bd, &mut frame.coeff_prob)?;
656
657 frame.mb_no_coeff_skip = bd.read_bool()?;
658 if frame.mb_no_coeff_skip {
659 frame.prob_skip_false = bd.read_uint(8)?;
660 }
661
662 if !frame.key_frame {
663 frame.prob_intra = bd.read_uint(8)?;
664 frame.prob_last = bd.read_uint(8)?;
665 frame.prob_golden = bd.read_uint(8)?;
666
667 let intra_16x16_prob_update_flag = bd.read_bool()?;
668 if intra_16x16_prob_update_flag {
669 for prob in frame.mode_probs.intra_16x16_prob.iter_mut() {
670 *prob = bd.read_uint(8)?;
671 }
672 }
673
674 let intra_chroma_prob_update_flag = bd.read_bool()?;
675 if intra_chroma_prob_update_flag {
676 for prob in frame.mode_probs.intra_chroma_prob.iter_mut() {
677 *prob = bd.read_uint(8)?;
678 }
679 }
680
681 Parser::parse_mv_prob_update(&mut bd, &mut frame.mv_prob)?;
682 }
683
684 if frame.refresh_entropy_probs {
685 self.coeff_prob = frame.coeff_prob;
686 self.mv_prob = frame.mv_prob;
687
688 if !frame.key_frame {
689 self.mode_probs = frame.mode_probs.clone();
690 }
691 }
692
693 frame.header_size = bd.pos() as u32;
694
695 let state: BoolDecoderState = bd.into();
696 frame.bd_range = state.range;
697 frame.bd_value = state.value;
698 frame.bd_count = state.count;
699
700 Ok(())
701 }
702
703 pub fn parse_frame<'a>(&mut self, bitstream: &'a [u8]) -> Result<Frame<'a>, ParseFrameError> {
705 let mut header = Header::parse_uncompressed_data_chunk(bitstream)?;
706 if header.key_frame {
707 *self = Default::default();
709 }
710
711 let first_part_end = header.data_chunk_size as usize + header.first_part_size as usize;
712
713 if first_part_end > bitstream.len() {
714 return Err(ParseFrameError::InvalidPartitionSize(first_part_end, bitstream.len()));
715 }
716
717 let compressed_area = &bitstream[header.data_chunk_size as usize..];
718
719 self.parse_frame_header(compressed_area, &mut header)?;
720 header.compute_partition_sizes(compressed_area)?;
721
722 let frame_len = header.frame_len();
723 if frame_len > bitstream.as_ref().len() {
724 return Err(ParseFrameError::BitstreamTooShort(bitstream.as_ref().len(), frame_len));
725 }
726
727 Ok(Frame { bitstream, frame_len, header })
728 }
729}
730
731impl Default for Parser {
732 fn default() -> Self {
733 Self {
734 segmentation: Default::default(),
735 mb_lf_adjust: Default::default(),
736 coeff_prob: COEFF_DEFAULT_PROBS,
737 mv_prob: MV_DEFAULT_PROBS,
738 mode_probs: ModeProbs {
739 intra_16x16_prob: NK_Y_MODE_PROBS,
740 intra_chroma_prob: NK_UV_MODE_PROBS,
741 },
742 }
743 }
744}
745
746#[cfg(test)]
747mod tests {
748 use super::Parser;
749
750 const VP8_TEST_0_INTRA: &[u8] = include_bytes!("test_data/vp8-parser-test-0-intra.bin");
753 const VP8_TEST_0_INTER: &[u8] = include_bytes!("test_data/vp8-parser-test-0-inter.bin");
754
755 #[test]
756 fn gst_intra() {
757 let mut parser = Parser::default();
758 let frame = parser.parse_frame(VP8_TEST_0_INTRA).expect("Parsing a intra frame failed");
759
760 assert!(frame.header.key_frame);
761
762 assert_eq!(frame.header.first_part_size, 234);
763 assert_eq!(frame.header.width, 176);
764 assert_eq!(frame.header.height, 144);
765
766 assert!(parser.mb_lf_adjust.loop_filter_adj_enable);
767 assert!(parser.mb_lf_adjust.mode_ref_lf_delta_update);
768
769 assert_eq!(parser.mb_lf_adjust.ref_frame_delta[0], 2);
770 assert_eq!(parser.mb_lf_adjust.ref_frame_delta[1], 0);
771 assert_eq!(parser.mb_lf_adjust.ref_frame_delta[2], -2);
772 assert_eq!(parser.mb_lf_adjust.ref_frame_delta[3], -2);
773
774 assert_eq!(parser.mb_lf_adjust.mb_mode_delta[0], 4);
775 assert_eq!(parser.mb_lf_adjust.mb_mode_delta[1], -2);
776 assert_eq!(parser.mb_lf_adjust.mb_mode_delta[2], 2);
777 assert_eq!(parser.mb_lf_adjust.mb_mode_delta[3], 4);
778
779 assert_eq!(frame.header.quant_indices.y_ac_qi, 4);
780 assert!(frame.header.mb_no_coeff_skip);
781
782 assert_eq!(frame.header.bd_range, 0xe8);
783 assert_eq!(frame.header.bd_value, 0x68);
784 assert_eq!(frame.header.bd_count, 1);
785 }
786
787 #[test]
788 fn gst_inter() {
789 let mut parser = Parser::default();
790 let frame = parser.parse_frame(VP8_TEST_0_INTER).expect("Parsing a inter frame failed");
791
792 assert!(!frame.header.key_frame);
793
794 assert_eq!(frame.header.first_part_size, 98);
795 assert!(parser.mb_lf_adjust.loop_filter_adj_enable);
796 assert_eq!(frame.header.quant_indices.y_ac_qi, 4);
797
798 assert!(frame.header.refresh_entropy_probs);
799 assert!(frame.header.refresh_last);
800 assert!(frame.header.mb_no_coeff_skip);
801
802 assert_eq!(frame.header.prob_skip_false, 131);
803 assert_eq!(frame.header.prob_intra, 224);
804 assert_eq!(frame.header.prob_last, 233);
805 assert_eq!(frame.header.prob_golden, 1);
806
807 assert_eq!(frame.header.bd_range, 0x8e);
808 assert_eq!(frame.header.bd_value, 0x85);
809 assert_eq!(frame.header.bd_count, 5);
810 }
811}