1use crate::bitstream_utils::BitReader;
6use crate::codec::vp9::lookups::AC_QLOOKUP;
7use crate::codec::vp9::lookups::AC_QLOOKUP_10;
8use crate::codec::vp9::lookups::AC_QLOOKUP_12;
9use crate::codec::vp9::lookups::DC_QLOOKUP;
10use crate::codec::vp9::lookups::DC_QLOOKUP_10;
11use crate::codec::vp9::lookups::DC_QLOOKUP_12;
12
13pub const REFS_PER_FRAME: usize = 3;
14
15pub const MAX_REF_LF_DELTAS: usize = 4;
16pub const MAX_MODE_LF_DELTAS: usize = 2;
17
18pub const INTRA_FRAME: usize = 0;
19pub const LAST_FRAME: usize = 1;
20pub const GOLDEN_FRAME: usize = 2;
21pub const ALTREF_FRAME: usize = 3;
22pub const MAX_REF_FRAMES: usize = 4;
23
24pub const MAX_SEGMENTS: usize = 8;
25pub const SEG_TREE_PROBS: usize = MAX_SEGMENTS - 1;
26pub const PREDICTION_PROBS: usize = 3;
27
28#[repr(u8)]
30pub enum SegLvl {
31 AltQ = 0,
32 AltL = 1,
33 RefFrame = 2,
34 LvlSkip = 3,
35}
36pub const SEG_LVL_MAX: usize = 4;
37
38pub const MAX_LOOP_FILTER: u32 = 63;
39
40pub const REF_FRAMES_LOG2: usize = 3;
41pub const REF_FRAMES: usize = 1 << REF_FRAMES_LOG2;
42
43pub const SUPERFRAME_MARKER: u32 = 0x06;
44pub const MAX_FRAMES_IN_SUPERFRAME: usize = 8;
45
46pub const FRAME_MARKER: u32 = 0x02;
47pub const SYNC_CODE: u32 = 0x498342;
48
49pub const MIN_TILE_WIDTH_B64: u32 = 4;
50pub const MAX_TILE_WIDTH_B64: u32 = 64;
51
52pub const NUM_REF_FRAMES: usize = 8;
54
55#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
56pub enum InterpolationFilter {
57 #[default]
58 EightTap = 0,
59 EightTapSmooth = 1,
60 EightTapSharp = 2,
61 Bilinear = 3,
62 Switchable = 4,
63}
64
65impl TryFrom<u32> for InterpolationFilter {
66 type Error = String;
67
68 fn try_from(value: u32) -> Result<Self, Self::Error> {
69 match value {
70 0 => Ok(InterpolationFilter::EightTap),
71 1 => Ok(InterpolationFilter::EightTapSmooth),
72 2 => Ok(InterpolationFilter::EightTapSharp),
73 3 => Ok(InterpolationFilter::Bilinear),
74 4 => Ok(InterpolationFilter::Switchable),
75 _ => Err(format!("Invalid InterpolationFilter {}", value)),
76 }
77 }
78}
79
80#[derive(Copy, Clone, Debug, PartialEq, Eq)]
81pub enum ReferenceFrameType {
82 Intra = 0,
83 Last = 1,
84 Golden = 2,
85 AltRef = 3,
86}
87
88impl TryFrom<u32> for ReferenceFrameType {
89 type Error = String;
90
91 fn try_from(value: u32) -> Result<Self, Self::Error> {
92 match value {
93 0 => Ok(ReferenceFrameType::Intra),
94 1 => Ok(ReferenceFrameType::Last),
95 2 => Ok(ReferenceFrameType::Golden),
96 3 => Ok(ReferenceFrameType::AltRef),
97 _ => Err(format!("Invalid ReferenceFrameType {}", value)),
98 }
99 }
100}
101
102#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
103pub enum FrameType {
104 #[default]
105 KeyFrame = 0,
106 InterFrame = 1,
107}
108
109impl TryFrom<u8> for FrameType {
110 type Error = String;
111
112 fn try_from(value: u8) -> Result<Self, Self::Error> {
113 match value {
114 0 => Ok(FrameType::KeyFrame),
115 1 => Ok(FrameType::InterFrame),
116 _ => Err(format!("Invalid FrameType {}", value)),
117 }
118 }
119}
120
121#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
122pub enum Profile {
123 #[default]
124 Profile0 = 0,
125 Profile1 = 1,
126 Profile2 = 2,
127 Profile3 = 3,
128}
129
130impl TryFrom<u32> for Profile {
131 type Error = String;
132
133 fn try_from(value: u32) -> Result<Self, Self::Error> {
134 match value {
135 0 => Ok(Profile::Profile0),
136 1 => Ok(Profile::Profile1),
137 2 => Ok(Profile::Profile2),
138 3 => Ok(Profile::Profile3),
139 _ => Err(format!("Invalid Profile {}", value)),
140 }
141 }
142}
143
144#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
145pub enum BitDepth {
146 #[default]
147 Depth8 = 8,
148 Depth10 = 10,
149 Depth12 = 12,
150}
151
152impl TryFrom<u32> for BitDepth {
153 type Error = String;
154
155 fn try_from(value: u32) -> Result<Self, Self::Error> {
156 match value {
157 8 => Ok(BitDepth::Depth8),
158 10 => Ok(BitDepth::Depth10),
159 12 => Ok(BitDepth::Depth12),
160 _ => Err(format!("Invalid BitDepth {}", value)),
161 }
162 }
163}
164
165#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
166pub enum ColorSpace {
167 #[default]
168 Unknown = 0,
169 Bt601 = 1,
170 Bt709 = 2,
171 Smpte170 = 3,
172 Smpte240 = 4,
173 Bt2020 = 5,
174 Reserved2 = 6,
175 CsSrgb = 7,
176}
177
178impl TryFrom<u32> for ColorSpace {
179 type Error = String;
180
181 fn try_from(value: u32) -> Result<Self, Self::Error> {
182 match value {
183 0 => Ok(ColorSpace::Unknown),
184 1 => Ok(ColorSpace::Bt601),
185 2 => Ok(ColorSpace::Bt709),
186 3 => Ok(ColorSpace::Smpte170),
187 4 => Ok(ColorSpace::Smpte240),
188 5 => Ok(ColorSpace::Bt2020),
189 6 => Ok(ColorSpace::Reserved2),
190 7 => Ok(ColorSpace::CsSrgb),
191 _ => Err(format!("Invalid ColorSpace {}", value)),
192 }
193 }
194}
195
196#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
197pub enum ColorRange {
198 #[default]
199 StudioSwing = 0,
200 FullSwing = 1,
201}
202
203impl TryFrom<u32> for ColorRange {
204 type Error = String;
205
206 fn try_from(value: u32) -> Result<Self, Self::Error> {
207 match value {
208 0 => Ok(ColorRange::StudioSwing),
209 1 => Ok(ColorRange::FullSwing),
210 _ => Err(format!("Invalid ColorRange {}", value)),
211 }
212 }
213}
214
215#[derive(Clone, Debug, Default, PartialEq, Eq)]
216pub struct LoopFilterParams {
217 pub level: u8,
219 pub sharpness: u8,
223 pub delta_enabled: bool,
227 pub delta_update: bool,
231 pub update_ref_delta: [bool; MAX_REF_LF_DELTAS],
235 pub ref_deltas: [i8; MAX_REF_LF_DELTAS],
239 pub update_mode_delta: [bool; MAX_MODE_LF_DELTAS],
243 pub mode_deltas: [i8; MAX_MODE_LF_DELTAS],
247}
248
249#[derive(Clone, Debug, Default, PartialEq, Eq)]
250pub struct QuantizationParams {
251 pub base_q_idx: u8,
254 pub delta_q_y_dc: i8,
256 pub delta_q_uv_dc: i8,
258 pub delta_q_uv_ac: i8,
260}
261
262#[derive(Clone, Debug, Default, PartialEq, Eq)]
263pub struct SegmentationParams {
264 pub enabled: bool,
267 pub update_map: bool,
271 pub tree_probs: [u8; SEG_TREE_PROBS],
273 pub pred_probs: [u8; PREDICTION_PROBS],
275 pub temporal_update: bool,
280 pub update_data: bool,
284 pub abs_or_delta_update: bool,
288 pub feature_enabled: [[bool; SEG_LVL_MAX]; MAX_SEGMENTS],
292 pub feature_data: [[i16; SEG_LVL_MAX]; MAX_SEGMENTS],
294}
295
296impl SegmentationParams {
297 fn is_feature_enabled(&self, segment_id: u8, feature: SegLvl) -> bool {
299 self.feature_enabled[segment_id as usize][feature as usize]
300 }
301
302 fn is_feature_active(&self, segment_id: u8, feature: SegLvl) -> bool {
304 self.enabled && self.is_feature_enabled(segment_id, feature)
305 }
306
307 fn feature_data(&self, segment_id: u8, feature: SegLvl) -> i16 {
309 self.feature_data[segment_id as usize][feature as usize]
310 }
311}
312
313#[derive(Clone, Debug, Default, PartialEq, Eq)]
314pub struct Segmentation {
315 pub lvl_lookup: [[u8; MAX_MODE_LF_DELTAS]; MAX_REF_FRAMES],
317
318 pub luma_ac_quant_scale: i16,
320 pub luma_dc_quant_scale: i16,
322 pub chroma_ac_quant_scale: i16,
324 pub chroma_dc_quant_scale: i16,
326
327 pub reference_frame_enabled: bool,
329 pub reference_frame: i16,
331 pub reference_skip_enabled: bool,
333}
334
335impl Segmentation {
336 pub fn update_segmentation(segmentation: &mut [Segmentation; MAX_SEGMENTS], hdr: &Header) {
338 let lf = &hdr.lf;
339 let seg = &hdr.seg;
340
341 let n_shift = lf.level >> 5;
342
343 for segment_id in 0..MAX_SEGMENTS as u8 {
344 let luma_dc_quant_scale = hdr.get_dc_quant(segment_id, true);
345 let luma_ac_quant_scale = hdr.get_ac_quant(segment_id, true);
346 let chroma_dc_quant_scale = hdr.get_dc_quant(segment_id, false);
347 let chroma_ac_quant_scale = hdr.get_ac_quant(segment_id, false);
348
349 let mut lvl_lookup: [[u8; MAX_MODE_LF_DELTAS]; MAX_REF_FRAMES];
350
351 if lf.level == 0 {
352 lvl_lookup = Default::default()
353 } else {
354 let mut lvl_seg = i32::from(lf.level);
355
356 if hdr.seg.is_feature_active(segment_id, SegLvl::AltL) {
358 if seg.abs_or_delta_update {
359 lvl_seg = i32::from(seg.feature_data(segment_id, SegLvl::AltL));
360 } else {
361 lvl_seg += i32::from(seg.feature_data(segment_id, SegLvl::AltL));
362 }
363 }
364
365 let lvl_seg = lvl_seg.clamp(0, MAX_LOOP_FILTER as i32) as u8;
366
367 if !lf.delta_enabled {
368 lvl_lookup = [[lvl_seg; MAX_MODE_LF_DELTAS]; MAX_REF_FRAMES]
369 } else {
370 let intra_delta = lf.ref_deltas[INTRA_FRAME] as i32;
371 let mut intra_lvl = lvl_seg as i32 + (intra_delta << n_shift);
372
373 lvl_lookup = segmentation[segment_id as usize].lvl_lookup;
374 lvl_lookup[INTRA_FRAME][0] = intra_lvl.clamp(0, MAX_LOOP_FILTER as i32) as u8;
375
376 #[allow(clippy::needless_range_loop)]
379 for ref_ in LAST_FRAME..MAX_REF_FRAMES {
380 for mode in 0..MAX_MODE_LF_DELTAS {
381 let ref_delta = lf.ref_deltas[ref_] as i32;
382 let mode_delta = lf.mode_deltas[mode] as i32;
383
384 intra_lvl =
385 lvl_seg as i32 + (ref_delta << n_shift) + (mode_delta << n_shift);
386
387 lvl_lookup[ref_][mode] =
388 intra_lvl.clamp(0, MAX_LOOP_FILTER as i32) as u8;
389 }
390 }
391 }
392 }
393
394 segmentation[usize::from(segment_id)] = Segmentation {
395 lvl_lookup,
396 luma_ac_quant_scale,
397 luma_dc_quant_scale,
398 chroma_ac_quant_scale,
399 chroma_dc_quant_scale,
400 reference_frame_enabled: seg.is_feature_enabled(segment_id, SegLvl::RefFrame),
401 reference_frame: seg.feature_data(segment_id, SegLvl::RefFrame),
402 reference_skip_enabled: seg.is_feature_enabled(segment_id, SegLvl::LvlSkip),
403 }
404 }
405 }
406}
407
408#[derive(Clone, Debug, Default, PartialEq, Eq)]
409struct FrameSize {
410 width: u32,
411 height: u32,
412}
413
414pub struct Frame<'a> {
415 bitstream: &'a [u8],
417 pub header: Header,
419 offset: usize,
421 size: usize,
423}
424
425impl<'a> Frame<'a> {
426 pub fn new(bitstream: &'a [u8], header: Header, offset: usize, size: usize) -> Self {
427 Self { bitstream, header, offset, size }
428 }
429}
430
431impl<'a> AsRef<[u8]> for Frame<'a> {
432 fn as_ref(&self) -> &[u8] {
433 let data = self.bitstream;
434 &data[self.offset..self.offset + self.size]
435 }
436}
437
438#[derive(Clone, Debug, Default, PartialEq, Eq)]
440pub struct Header {
441 pub profile: Profile,
443 pub bit_depth: BitDepth,
445 pub subsampling_x: bool,
447 pub subsampling_y: bool,
449 pub color_space: ColorSpace,
451 pub color_range: ColorRange,
454 pub show_existing_frame: bool,
457 pub frame_to_show_map_idx: u8,
460 pub frame_type: FrameType,
462 pub show_frame: bool,
464 pub error_resilient_mode: bool,
466 pub width: u32,
468 pub height: u32,
470 pub render_and_frame_size_different: bool,
474 pub render_width: u32,
476 pub render_height: u32,
478 pub intra_only: bool,
481 pub reset_frame_context: u8,
483 pub refresh_frame_flags: u8,
486 pub ref_frame_idx: [u8; REFS_PER_FRAME],
491 pub ref_frame_sign_bias: [u8; 4],
496 pub allow_high_precision_mv: bool,
500 pub interpolation_filter: InterpolationFilter,
502 pub refresh_frame_context: bool,
507 pub frame_parallel_decoding_mode: bool,
509 pub frame_context_idx: u8,
511 pub lf: LoopFilterParams,
513 pub quant: QuantizationParams,
515 pub seg: SegmentationParams,
517 pub tile_cols_log2: u8,
521 pub tile_rows_log2: u8,
524 pub lossless: bool,
528 pub header_size_in_bytes: u16,
530 pub uncompressed_header_size_in_bytes: u16,
532}
533
534impl Header {
535 fn get_qindex(&self, segment_id: u8) -> u8 {
537 let base_q_idx = self.quant.base_q_idx;
538
539 if self.seg.is_feature_active(segment_id, SegLvl::AltQ) {
540 let mut data = self.seg.feature_data(segment_id, SegLvl::AltQ) as i32;
541
542 if !self.seg.abs_or_delta_update {
543 data += base_q_idx as i32;
544 }
545
546 data.clamp(0, 255) as u8
547 } else {
548 base_q_idx
549 }
550 }
551
552 fn get_dc_quant(&self, segment_id: u8, luma: bool) -> i16 {
554 let delta_q_dc =
555 if luma { self.quant.delta_q_y_dc } else { self.quant.delta_q_uv_dc } as i32;
556 let qindex = self.get_qindex(segment_id);
557 let q_table_idx = (qindex as i32 + delta_q_dc).clamp(0, 255) as u8;
558
559 let table = match self.bit_depth {
560 BitDepth::Depth8 => &DC_QLOOKUP,
561 BitDepth::Depth10 => &DC_QLOOKUP_10,
562 BitDepth::Depth12 => &DC_QLOOKUP_12,
563 };
564
565 table[q_table_idx as usize]
566 }
567
568 fn get_ac_quant(&self, segment_id: u8, luma: bool) -> i16 {
570 let delta_q_ac = if luma { 0 } else { self.quant.delta_q_uv_ac } as i32;
571 let qindex = self.get_qindex(segment_id);
572 let q_table_idx = (qindex as i32 + delta_q_ac).clamp(0, 255) as u8;
573
574 let table = match self.bit_depth {
575 BitDepth::Depth8 => &AC_QLOOKUP,
576 BitDepth::Depth10 => &AC_QLOOKUP_10,
577 BitDepth::Depth12 => &AC_QLOOKUP_12,
578 };
579
580 table[q_table_idx as usize]
581 }
582}
583
584struct SuperframeHeader {
586 frames_in_superframe: u32,
590 frame_sizes: Vec<usize>,
593}
594
595#[derive(Clone, Debug, Default, PartialEq, Eq)]
597pub struct Parser {
598 bit_depth: BitDepth,
599 subsampling_x: bool,
600 subsampling_y: bool,
601 color_space: ColorSpace,
602 color_range: ColorRange,
603
604 mi_cols: u32,
605 mi_rows: u32,
606 sb64_cols: u32,
607 sb64_rows: u32,
608
609 lf: LoopFilterParams,
610 seg: SegmentationParams,
611
612 reference_frame_sz: [FrameSize; REF_FRAMES],
613}
614
615impl Parser {
616 fn parse_superframe_hdr(resource: impl AsRef<[u8]>) -> Result<SuperframeHeader, String> {
617 let bitstream = resource.as_ref();
618
619 let mut reader = BitReader::new(&bitstream[bitstream.len() - 1..], false);
621
622 let marker = reader.read_bits::<u32>(3)?;
624
625 if marker != SUPERFRAME_MARKER {
626 return Ok(SuperframeHeader {
628 frames_in_superframe: 1,
629 frame_sizes: vec![bitstream.len()],
630 });
631 }
632
633 let bytes_per_framesize = reader.read_bits::<u32>(2)? + 1;
634 let frames_in_superframe = reader.read_bits::<u32>(3)? + 1;
635
636 if frames_in_superframe > MAX_FRAMES_IN_SUPERFRAME as u32 {
637 return Err(format!(
638 "Broken stream: too many frames in superframe, expected a maximum of {:?}, found {:?}",
639 MAX_FRAMES_IN_SUPERFRAME,
640 frames_in_superframe
641 ));
642 }
643
644 let sz_index = 2 + frames_in_superframe * bytes_per_framesize;
645
646 let data = resource.as_ref();
647 let index_offset = data.len() - sz_index as usize;
648 let first_byte = data[index_offset];
649 let last_byte = *data.last().ok_or_else(|| String::from("superframe header is empty"))?;
650
651 if first_byte != last_byte {
652 return Ok(SuperframeHeader {
654 frames_in_superframe: 1,
655 frame_sizes: vec![bitstream.len()],
656 });
657 }
658
659 let mut frame_sizes = vec![];
660 let mut reader = BitReader::new(&bitstream[index_offset..], false);
661
662 let _ = reader.read_bits::<u32>(8)?;
664
665 for _ in 0..frames_in_superframe {
666 let mut frame_size = 0;
667
668 for j in 0..bytes_per_framesize {
669 frame_size |= reader.read_bits::<u32>(8)? << (j * 8);
670 }
671
672 frame_sizes.push(frame_size as usize);
673 }
674
675 Ok(SuperframeHeader { frames_in_superframe, frame_sizes })
676 }
677
678 fn read_signed_8(r: &mut BitReader, nbits: u8) -> Result<i8, String> {
679 let value = r.read_bits::<u8>(nbits as usize)?;
680 let negative = r.read_bit()?;
681
682 if negative {
683 Ok(-(value as i8))
684 } else {
685 Ok(value as i8)
686 }
687 }
688
689 fn parse_frame_marker(r: &mut BitReader) -> Result<(), String> {
690 let marker = r.read_bits::<u32>(2)?;
691
692 if marker != FRAME_MARKER {
693 return Err(format!("Broken stream: expected frame marker, found {:?}", marker));
694 }
695
696 Ok(())
697 }
698
699 fn parse_profile(r: &mut BitReader) -> Result<Profile, String> {
700 let low = r.read_bits::<u32>(1)?;
701 let high = r.read_bits::<u32>(1)?;
702
703 let profile = (high << 1) | low;
704
705 if profile == 3 {
706 let _ = r.read_bit()?;
708 }
709
710 Profile::try_from(profile)
711 }
712
713 fn parse_frame_sync_code(r: &mut BitReader) -> Result<(), String> {
714 let sync_code = r.read_bits::<u32>(24)?;
715
716 if sync_code != SYNC_CODE {
717 return Err(format!(
718 "Broken stream: expected sync code == {:?}, found {:?}",
719 SYNC_CODE, sync_code
720 ));
721 }
722
723 Ok(())
724 }
725
726 fn parse_color_config(&mut self, r: &mut BitReader, hdr: &mut Header) -> Result<(), String> {
727 if matches!(hdr.profile, Profile::Profile2 | Profile::Profile3) {
728 let ten_or_twelve_bit = r.read_bit()?;
729 if ten_or_twelve_bit {
730 hdr.bit_depth = BitDepth::Depth12;
731 } else {
732 hdr.bit_depth = BitDepth::Depth10
733 }
734 } else {
735 hdr.bit_depth = BitDepth::Depth8;
736 }
737
738 let color_space = r.read_bits::<u32>(3)?;
739 hdr.color_space = ColorSpace::try_from(color_space)?;
740
741 if !matches!(hdr.color_space, ColorSpace::CsSrgb) {
742 let color_range = r.read_bits::<u32>(1)?;
743
744 hdr.color_range = ColorRange::try_from(color_range)?;
745
746 if matches!(hdr.profile, Profile::Profile1 | Profile::Profile3) {
747 hdr.subsampling_x = r.read_bit()?;
748 hdr.subsampling_y = r.read_bit()?;
749
750 let _ = r.read_bit()?;
752 } else {
753 hdr.subsampling_x = true;
754 hdr.subsampling_y = true;
755 }
756 } else {
757 hdr.color_range = ColorRange::FullSwing;
758 if matches!(hdr.profile, Profile::Profile1 | Profile::Profile3) {
759 hdr.subsampling_x = false;
760 hdr.subsampling_y = false;
761
762 let _ = r.read_bit()?;
764 }
765 }
766
767 self.bit_depth = hdr.bit_depth;
768 self.color_space = hdr.color_space;
769 self.subsampling_x = hdr.subsampling_x;
770 self.subsampling_y = hdr.subsampling_y;
771 self.color_range = hdr.color_range;
772
773 Ok(())
774 }
775
776 fn compute_image_size(&mut self, width: u32, height: u32) {
777 self.mi_cols = (width + 7) >> 3;
778 self.mi_rows = (height + 7) >> 3;
779 self.sb64_cols = (self.mi_cols + 7) >> 3;
780 self.sb64_rows = (self.mi_rows + 7) >> 3;
781 }
782
783 fn parse_frame_size(&mut self, r: &mut BitReader, hdr: &mut Header) -> Result<(), String> {
784 hdr.width = r.read_bits::<u32>(16)? + 1;
785 hdr.height = r.read_bits::<u32>(16)? + 1;
786 self.compute_image_size(hdr.width, hdr.height);
787 Ok(())
788 }
789
790 fn parse_render_size(r: &mut BitReader, hdr: &mut Header) -> Result<(), String> {
791 hdr.render_and_frame_size_different = r.read_bit()?;
792 if hdr.render_and_frame_size_different {
793 hdr.render_width = r.read_bits::<u32>(16)? + 1;
794 hdr.render_height = r.read_bits::<u32>(16)? + 1;
795 } else {
796 hdr.render_width = hdr.width;
797 hdr.render_height = hdr.height;
798 }
799
800 Ok(())
801 }
802
803 fn parse_frame_size_with_refs(
804 &mut self,
805 r: &mut BitReader,
806 hdr: &mut Header,
807 ) -> Result<(), String> {
808 let mut found_ref = false;
809
810 for i in 0..REFS_PER_FRAME {
811 found_ref = r.read_bit()?;
812
813 if found_ref {
814 let idx = hdr.ref_frame_idx[i] as usize;
815 hdr.width = self.reference_frame_sz[idx].width;
816 hdr.height = self.reference_frame_sz[idx].height;
817 break;
818 }
819 }
820
821 if !found_ref {
822 self.parse_frame_size(r, hdr)?;
823 } else {
824 self.compute_image_size(hdr.width, hdr.height)
825 }
826
827 Self::parse_render_size(r, hdr)
828 }
829
830 fn read_interpolation_filter(r: &mut BitReader) -> Result<InterpolationFilter, String> {
831 const LITERAL_TO_TYPE: [InterpolationFilter; 4] = [
832 InterpolationFilter::EightTapSmooth,
833 InterpolationFilter::EightTap,
834 InterpolationFilter::EightTapSharp,
835 InterpolationFilter::Bilinear,
836 ];
837
838 let is_filter_switchable = r.read_bit()?;
839
840 Ok(if is_filter_switchable {
841 InterpolationFilter::Switchable
842 } else {
843 let raw_interpolation_filter = r.read_bits::<u32>(2)?;
844 LITERAL_TO_TYPE[raw_interpolation_filter as usize]
845 })
846 }
847
848 fn setup_past_independence(&mut self, hdr: &mut Header) {
849 self.seg.feature_enabled = Default::default();
850 self.seg.feature_data = Default::default();
851 self.seg.abs_or_delta_update = false;
852
853 self.lf.delta_enabled = true;
854 self.lf.ref_deltas[ReferenceFrameType::Intra as usize] = 1;
855 self.lf.ref_deltas[ReferenceFrameType::Last as usize] = 0;
856 self.lf.ref_deltas[ReferenceFrameType::Golden as usize] = -1;
857 self.lf.ref_deltas[ReferenceFrameType::AltRef as usize] = -1;
858
859 self.lf.mode_deltas = Default::default();
860 hdr.ref_frame_sign_bias = Default::default();
861 }
862
863 fn parse_loop_filter_params(
864 r: &mut BitReader,
865 lf: &mut LoopFilterParams,
866 ) -> Result<(), String> {
867 lf.level = r.read_bits::<u8>(6)?;
868 lf.sharpness = r.read_bits::<u8>(3)?;
869 lf.delta_enabled = r.read_bit()?;
870
871 if lf.delta_enabled {
872 lf.delta_update = r.read_bit()?;
873 if lf.delta_update {
874 for i in 0..MAX_REF_LF_DELTAS {
875 lf.update_ref_delta[i] = r.read_bit()?;
876 if lf.update_ref_delta[i] {
877 lf.ref_deltas[i] = Self::read_signed_8(r, 6)?;
878 }
879 }
880
881 for i in 0..MAX_MODE_LF_DELTAS {
882 lf.update_mode_delta[i] = r.read_bit()?;
883 if lf.update_mode_delta[i] {
884 lf.mode_deltas[i] = Self::read_signed_8(r, 6)?;
885 }
886 }
887 }
888 }
889
890 Ok(())
891 }
892
893 fn read_delta_q(r: &mut BitReader, value: &mut i8) -> Result<(), String> {
894 let delta_coded = r.read_bit()?;
895
896 if delta_coded {
897 *value = Self::read_signed_8(r, 4)?;
898 } else {
899 *value = 0;
900 }
901
902 Ok(())
903 }
904
905 fn parse_quantization_params(r: &mut BitReader, hdr: &mut Header) -> Result<(), String> {
906 let quant = &mut hdr.quant;
907
908 quant.base_q_idx = r.read_bits::<u8>(8)?;
909
910 Self::read_delta_q(r, &mut quant.delta_q_y_dc)?;
911 Self::read_delta_q(r, &mut quant.delta_q_uv_dc)?;
912 Self::read_delta_q(r, &mut quant.delta_q_uv_ac)?;
913
914 hdr.lossless = quant.base_q_idx == 0
915 && quant.delta_q_y_dc == 0
916 && quant.delta_q_uv_dc == 0
917 && quant.delta_q_uv_ac == 0;
918
919 Ok(())
920 }
921
922 fn read_prob(r: &mut BitReader) -> Result<u8, String> {
923 let prob_coded = r.read_bit()?;
924
925 let prob = if prob_coded { r.read_bits::<u8>(8)? } else { 255 };
926
927 Ok(prob)
928 }
929
930 fn parse_segmentation_params(
931 r: &mut BitReader,
932 seg: &mut SegmentationParams,
933 ) -> Result<(), String> {
934 const SEGMENTATION_FEATURE_BITS: [u8; SEG_LVL_MAX] = [8, 6, 2, 0];
935 const SEGMENTATION_FEATURE_SIGNED: [bool; SEG_LVL_MAX] = [true, true, false, false];
936
937 seg.update_map = false;
938 seg.update_data = false;
939
940 seg.enabled = r.read_bit()?;
941
942 if !seg.enabled {
943 return Ok(());
944 }
945
946 seg.update_map = r.read_bit()?;
947
948 if seg.update_map {
949 for i in 0..SEG_TREE_PROBS {
950 seg.tree_probs[i] = Self::read_prob(r)?;
951 }
952
953 seg.temporal_update = r.read_bit()?;
954
955 for i in 0..PREDICTION_PROBS {
956 seg.pred_probs[i] = if seg.temporal_update { Self::read_prob(r)? } else { 255 };
957 }
958 }
959
960 seg.update_data = r.read_bit()?;
961
962 if seg.update_data {
963 seg.abs_or_delta_update = r.read_bit()?;
964 for i in 0..MAX_SEGMENTS {
965 for j in 0..SEG_LVL_MAX {
966 seg.feature_enabled[i][j] = r.read_bit()?;
967 if seg.feature_enabled[i][j] {
968 let bits_to_read = SEGMENTATION_FEATURE_BITS[j];
969 let mut feature_value = r.read_bits_signed::<i16>(bits_to_read as usize)?;
970
971 if SEGMENTATION_FEATURE_SIGNED[j] {
972 let feature_sign = r.read_bit()?;
973
974 if feature_sign {
975 feature_value = -feature_value;
976 }
977 }
978
979 seg.feature_data[i][j] = feature_value;
980 }
981 }
982 }
983 }
984
985 Ok(())
986 }
987
988 fn calc_min_log2_tile_cols(sb64_cols: u32) -> u8 {
989 let mut min_log2 = 0;
990
991 while (MAX_TILE_WIDTH_B64 << min_log2) < sb64_cols {
992 min_log2 += 1;
993 }
994
995 min_log2
996 }
997
998 fn calc_max_log2_tile_cols(sb64_cols: u32) -> u8 {
999 let mut max_log2 = 1;
1000
1001 while (sb64_cols >> max_log2) >= MIN_TILE_WIDTH_B64 {
1002 max_log2 += 1;
1003 }
1004
1005 max_log2 - 1
1006 }
1007
1008 fn parse_tile_info(&self, r: &mut BitReader, hdr: &mut Header) -> Result<(), String> {
1009 let max_log2_tile_cols = Self::calc_max_log2_tile_cols(self.sb64_cols);
1010
1011 hdr.tile_cols_log2 = Self::calc_min_log2_tile_cols(self.sb64_cols);
1012
1013 while hdr.tile_cols_log2 < max_log2_tile_cols {
1014 let increment_tile_cols_log2 = r.read_bit()?;
1015
1016 if increment_tile_cols_log2 {
1017 hdr.tile_cols_log2 += 1;
1018 } else {
1019 break;
1020 }
1021 }
1022
1023 hdr.tile_rows_log2 = r.read_bits::<u8>(1)?;
1024
1025 if hdr.tile_rows_log2 > 0 {
1026 let increment_tile_rows_log2 = r.read_bit()?;
1027 hdr.tile_rows_log2 += increment_tile_rows_log2 as u8;
1028 }
1029
1030 Ok(())
1031 }
1032
1033 fn parse_frame_header(
1034 &mut self,
1035 resource: impl AsRef<[u8]>,
1036 offset: usize,
1037 ) -> Result<Header, String> {
1038 let data = &resource.as_ref()[offset..];
1039 let mut r = BitReader::new(data, false);
1040 let mut hdr = Header::default();
1041
1042 Self::parse_frame_marker(&mut r)?;
1043 hdr.profile = Self::parse_profile(&mut r)?;
1044
1045 hdr.show_existing_frame = r.read_bit()?;
1046
1047 if hdr.show_existing_frame {
1048 hdr.frame_to_show_map_idx = r.read_bits::<u8>(3)?;
1049 return Ok(hdr);
1050 }
1051
1052 hdr.frame_type = FrameType::try_from(r.read_bits::<u8>(1)?)?;
1053
1054 hdr.show_frame = r.read_bit()?;
1055 hdr.error_resilient_mode = r.read_bit()?;
1056
1057 let frame_is_intra;
1058
1059 if matches!(hdr.frame_type, FrameType::KeyFrame) {
1060 Self::parse_frame_sync_code(&mut r)?;
1061 self.parse_color_config(&mut r, &mut hdr)?;
1062 self.parse_frame_size(&mut r, &mut hdr)?;
1063 Self::parse_render_size(&mut r, &mut hdr)?;
1064 hdr.refresh_frame_flags = 0xff;
1065 frame_is_intra = true;
1066 } else {
1067 if !hdr.show_frame {
1068 hdr.intra_only = r.read_bit()?;
1069 }
1070
1071 frame_is_intra = hdr.intra_only;
1072
1073 if !hdr.error_resilient_mode {
1074 hdr.reset_frame_context = r.read_bits::<u8>(2)?;
1075 } else {
1076 hdr.reset_frame_context = 0;
1077 }
1078
1079 if hdr.intra_only {
1080 Self::parse_frame_sync_code(&mut r)?;
1081
1082 if !matches!(hdr.profile, Profile::Profile0) {
1083 self.parse_color_config(&mut r, &mut hdr)?;
1084 } else {
1085 hdr.color_space = ColorSpace::Bt601;
1086 hdr.subsampling_x = true;
1087 hdr.subsampling_y = true;
1088 hdr.bit_depth = BitDepth::Depth8;
1089
1090 self.color_space = hdr.color_space;
1091 self.subsampling_x = hdr.subsampling_x;
1092 self.subsampling_y = hdr.subsampling_y;
1093 self.bit_depth = hdr.bit_depth;
1094 }
1095
1096 hdr.refresh_frame_flags = r.read_bits::<u8>(8)?;
1097 self.parse_frame_size(&mut r, &mut hdr)?;
1098 Self::parse_render_size(&mut r, &mut hdr)?;
1099 } else {
1100 hdr.color_space = self.color_space;
1102 hdr.color_range = self.color_range;
1103 hdr.subsampling_x = self.subsampling_x;
1104 hdr.subsampling_y = self.subsampling_y;
1105 hdr.bit_depth = self.bit_depth;
1106
1107 hdr.refresh_frame_flags = r.read_bits::<u8>(8)?;
1108
1109 for i in 0..REFS_PER_FRAME {
1110 hdr.ref_frame_idx[i] = r.read_bits::<u8>(3)?;
1111 hdr.ref_frame_sign_bias[ReferenceFrameType::Last as usize + i] =
1112 r.read_bits::<u8>(1)?;
1113 }
1114
1115 self.parse_frame_size_with_refs(&mut r, &mut hdr)?;
1116 hdr.allow_high_precision_mv = r.read_bit()?;
1117 hdr.interpolation_filter = Self::read_interpolation_filter(&mut r)?;
1118 }
1119 }
1120
1121 if !hdr.error_resilient_mode {
1122 hdr.refresh_frame_context = r.read_bit()?;
1123 hdr.frame_parallel_decoding_mode = r.read_bit()?;
1124 } else {
1125 hdr.refresh_frame_context = false;
1126 hdr.frame_parallel_decoding_mode = true;
1127 }
1128
1129 hdr.frame_context_idx = r.read_bits::<u8>(2)?;
1130
1131 if frame_is_intra || hdr.error_resilient_mode {
1132 self.setup_past_independence(&mut hdr);
1133 }
1134
1135 Self::parse_loop_filter_params(&mut r, &mut self.lf)?;
1136 Self::parse_quantization_params(&mut r, &mut hdr)?;
1137 Self::parse_segmentation_params(&mut r, &mut self.seg)?;
1138 self.parse_tile_info(&mut r, &mut hdr)?;
1139
1140 hdr.header_size_in_bytes = r.read_bits::<u16>(16)?;
1141
1142 hdr.lf = self.lf.clone();
1143 hdr.seg = self.seg.clone();
1144
1145 for i in 0..REF_FRAMES {
1146 let flag = 1 << i;
1147 if hdr.refresh_frame_flags & flag != 0 {
1148 self.reference_frame_sz[i].width = hdr.width;
1149 self.reference_frame_sz[i].height = hdr.height;
1150 }
1151 }
1152
1153 hdr.uncompressed_header_size_in_bytes = (r.position() as u16 + 7) / 8;
1154
1155 Ok(hdr)
1156 }
1157
1158 pub fn parse_frame<'a>(
1160 &mut self,
1161 bitstream: &'a [u8],
1162 offset: usize,
1163 size: usize,
1164 ) -> Result<Frame<'a>, String> {
1165 let header = self.parse_frame_header(bitstream, offset)?;
1166
1167 Ok(Frame { header, bitstream, offset, size })
1168 }
1169
1170 pub fn parse_chunk<'a>(&mut self, resource: &'a [u8]) -> Result<Vec<Frame<'a>>, String> {
1173 let superframe_hdr = Parser::parse_superframe_hdr(resource)?;
1174 let mut offset = 0;
1175
1176 let mut frames = vec![];
1177
1178 for i in 0..superframe_hdr.frames_in_superframe {
1179 let frame_sz = superframe_hdr.frame_sizes[i as usize];
1180 let frame = self.parse_frame(resource, offset, frame_sz)?;
1181 offset += frame_sz;
1182 frames.push(frame);
1183 }
1184
1185 Ok(frames)
1186 }
1187}
1188
1189#[cfg(test)]
1190mod tests {
1191 use crate::bitstream_utils::IvfIterator;
1192 use crate::codec::vp9::parser::BitDepth;
1193 use crate::codec::vp9::parser::ColorSpace;
1194 use crate::codec::vp9::parser::FrameType;
1195 use crate::codec::vp9::parser::InterpolationFilter;
1196 use crate::codec::vp9::parser::Parser;
1197 use crate::codec::vp9::parser::Profile;
1198 use crate::codec::vp9::parser::MAX_SEGMENTS;
1199 use crate::codec::vp9::parser::SEG_LVL_MAX;
1200
1201 #[test]
1202 fn test_parse_superframe() {
1203 const VP9_TEST_SUPERFRAME: &[u8] = include_bytes!("test_data/vp9-superframe.bin");
1205
1206 let mut parser = Parser::default();
1207 let frames = parser.parse_chunk(VP9_TEST_SUPERFRAME).expect("Parsing a superframe failed");
1208
1209 assert_eq!(frames.len(), 2);
1210 assert_eq!(frames[0].offset, 0);
1211 assert_eq!(frames[0].size, 1333);
1212 assert_eq!(frames[1].offset, 1333);
1213 assert_eq!(frames[1].size, 214);
1214 }
1215
1216 #[test]
1217 fn test_parse_test25fps() {
1218 const TEST_STREAM: &[u8] = include_bytes!("test_data/test-25fps.vp9");
1220
1221 let mut parser = Parser::default();
1222 let ivf_iter = IvfIterator::new(TEST_STREAM);
1223
1224 for (frame_n, packet) in ivf_iter.enumerate() {
1225 let frames = parser.parse_chunk(packet.as_ref()).expect("Parsing a superframe failed");
1226
1227 if frame_n == 0 {
1228 assert_eq!(frames.len(), 1);
1229 let h = &frames[0].header;
1230
1231 assert!(matches!(h.profile, Profile::Profile0));
1232 assert!(matches!(h.bit_depth, BitDepth::Depth8));
1233
1234 assert!(h.subsampling_x);
1235 assert!(h.subsampling_y);
1236
1237 assert!(matches!(h.color_space, ColorSpace::Unknown));
1238 assert!(matches!(
1239 h.color_range,
1240 crate::codec::vp9::parser::ColorRange::StudioSwing
1241 ));
1242
1243 assert!(!h.show_existing_frame);
1244 assert_eq!(h.frame_to_show_map_idx, 0);
1245
1246 assert!(matches!(h.frame_type, FrameType::KeyFrame));
1247 assert!(h.show_frame);
1248 assert!(!h.error_resilient_mode);
1249
1250 assert_eq!(h.width, 320);
1251 assert_eq!(h.height, 240);
1252
1253 assert!(!h.render_and_frame_size_different);
1254
1255 assert_eq!(h.render_width, 320);
1256 assert_eq!(h.render_height, 240);
1257
1258 assert!(!h.intra_only);
1259 assert_eq!(h.reset_frame_context, 0);
1260
1261 assert_eq!(h.refresh_frame_flags, 0xff);
1262 assert_eq!(h.ref_frame_idx, [0, 0, 0]);
1263 assert_eq!(h.ref_frame_sign_bias, [0, 0, 0, 0]);
1264
1265 assert!(!h.allow_high_precision_mv);
1266 assert!(matches!(h.interpolation_filter, InterpolationFilter::EightTap));
1267
1268 assert!(h.refresh_frame_context);
1269 assert!(h.frame_parallel_decoding_mode);
1270 assert_eq!(h.frame_context_idx, 0);
1271
1272 let lf = &h.lf;
1273 assert_eq!(lf.level, 9);
1274 assert_eq!(lf.sharpness, 0);
1275
1276 assert!(lf.delta_enabled);
1277 assert!(lf.delta_update);
1278
1279 assert_eq!(lf.update_ref_delta, [true, false, true, true]);
1280 assert_eq!(lf.ref_deltas, [1, 0, -1, -1]);
1281
1282 assert_eq!(lf.update_mode_delta, [false, false]);
1283
1284 let q = &h.quant;
1285
1286 assert_eq!(q.base_q_idx, 65);
1287 assert_eq!(q.delta_q_y_dc, 0);
1288 assert_eq!(q.delta_q_uv_dc, 0);
1289 assert_eq!(q.delta_q_uv_ac, 0);
1290
1291 let s = &h.seg;
1292
1293 assert!(!s.enabled);
1294 assert!(!s.update_map);
1295 assert_eq!(s.tree_probs, [0, 0, 0, 0, 0, 0, 0]);
1296 assert_eq!(s.pred_probs, [0, 0, 0]);
1297 assert!(!s.temporal_update);
1298 assert!(!s.update_data);
1299 assert!(!s.abs_or_delta_update);
1300 assert_eq!(s.feature_enabled, [[false; SEG_LVL_MAX]; MAX_SEGMENTS]);
1301 assert_eq!(s.feature_data, [[0; SEG_LVL_MAX]; MAX_SEGMENTS]);
1302
1303 assert_eq!(h.tile_cols_log2, 0);
1304 assert_eq!(h.tile_rows_log2, 0);
1305 assert_eq!(h.header_size_in_bytes, 120);
1306
1307 assert!(!h.lossless);
1308 } else if frame_n == 1 {
1309 assert_eq!(frames.len(), 2);
1310
1311 assert_eq!(frames[0].offset, 0);
1312 assert_eq!(frames[0].size, 2390);
1313 assert_eq!(frames[1].offset, 2390);
1314 assert_eq!(frames[1].size, 108);
1315
1316 let h = &frames[0].header;
1317
1318 assert!(matches!(h.profile, Profile::Profile0));
1319 assert!(matches!(h.bit_depth, BitDepth::Depth8));
1320
1321 assert!(h.subsampling_x);
1322 assert!(h.subsampling_y);
1323
1324 assert!(matches!(h.color_space, ColorSpace::Unknown));
1325 assert!(matches!(
1326 h.color_range,
1327 crate::codec::vp9::parser::ColorRange::StudioSwing
1328 ));
1329
1330 assert!(!h.show_existing_frame);
1331 assert_eq!(h.frame_to_show_map_idx, 0);
1332
1333 assert!(matches!(h.frame_type, FrameType::InterFrame));
1334 assert!(!h.show_frame);
1335 assert!(!h.error_resilient_mode);
1336
1337 assert_eq!(h.width, 320);
1338 assert_eq!(h.height, 240);
1339
1340 assert!(!h.render_and_frame_size_different);
1341
1342 assert_eq!(h.render_width, 320);
1343 assert_eq!(h.render_height, 240);
1344
1345 assert!(!h.intra_only);
1346 assert_eq!(h.reset_frame_context, 0);
1347
1348 assert_eq!(h.refresh_frame_flags, 4);
1349 assert_eq!(h.ref_frame_idx, [0, 1, 2]);
1350 assert_eq!(h.ref_frame_sign_bias, [0, 0, 0, 0]);
1351
1352 assert!(h.allow_high_precision_mv);
1353 assert!(matches!(h.interpolation_filter, InterpolationFilter::EightTap));
1354
1355 assert!(h.refresh_frame_context);
1356 assert!(h.frame_parallel_decoding_mode);
1357 assert_eq!(h.frame_context_idx, 1);
1358
1359 let lf = &h.lf;
1360 assert_eq!(lf.level, 15);
1361 assert_eq!(lf.sharpness, 0);
1362
1363 assert!(lf.delta_enabled);
1364 assert!(!lf.delta_update);
1365
1366 assert_eq!(lf.update_ref_delta, [true, false, true, true]);
1367 assert_eq!(lf.ref_deltas, [1, 0, -1, -1]);
1368
1369 assert_eq!(lf.update_mode_delta, [false, false]);
1370
1371 let q = &h.quant;
1372
1373 assert_eq!(q.base_q_idx, 112);
1374 assert_eq!(q.delta_q_y_dc, 0);
1375 assert_eq!(q.delta_q_uv_dc, 0);
1376 assert_eq!(q.delta_q_uv_ac, 0);
1377
1378 let s = &h.seg;
1379
1380 assert!(!s.enabled);
1381 assert!(!s.update_map);
1382 assert_eq!(s.tree_probs, [0, 0, 0, 0, 0, 0, 0]);
1383 assert_eq!(s.pred_probs, [0, 0, 0]);
1384 assert!(!s.temporal_update);
1385 assert!(!s.update_data);
1386 assert!(!s.abs_or_delta_update);
1387 assert_eq!(s.feature_enabled, [[false; SEG_LVL_MAX]; MAX_SEGMENTS]);
1388 assert_eq!(s.feature_data, [[0; SEG_LVL_MAX]; MAX_SEGMENTS]);
1389
1390 assert_eq!(h.tile_cols_log2, 0);
1391 assert_eq!(h.tile_rows_log2, 0);
1392 assert_eq!(h.header_size_in_bytes, 48);
1393
1394 assert!(!h.lossless);
1395
1396 let h = &frames[1].header;
1397
1398 assert!(matches!(h.profile, Profile::Profile0));
1399 assert!(matches!(h.bit_depth, BitDepth::Depth8));
1400
1401 assert!(h.subsampling_x);
1402 assert!(h.subsampling_y);
1403
1404 assert!(matches!(h.color_space, ColorSpace::Unknown));
1405 assert!(matches!(
1406 h.color_range,
1407 crate::codec::vp9::parser::ColorRange::StudioSwing
1408 ));
1409
1410 assert!(!h.show_existing_frame);
1411 assert_eq!(h.frame_to_show_map_idx, 0);
1412
1413 assert!(matches!(h.frame_type, FrameType::InterFrame));
1414 assert!(h.show_frame);
1415 assert!(!h.error_resilient_mode);
1416
1417 assert_eq!(h.width, 320);
1418 assert_eq!(h.height, 240);
1419
1420 assert!(!h.render_and_frame_size_different);
1421
1422 assert_eq!(h.render_width, 320);
1423 assert_eq!(h.render_height, 240);
1424
1425 assert!(!h.intra_only);
1426 assert_eq!(h.reset_frame_context, 0);
1427
1428 assert_eq!(h.refresh_frame_flags, 1);
1429 assert_eq!(h.ref_frame_idx, [0, 1, 2]);
1430 assert_eq!(h.ref_frame_sign_bias, [0, 0, 0, 1]);
1431
1432 assert!(!h.allow_high_precision_mv);
1433 assert!(matches!(h.interpolation_filter, InterpolationFilter::EightTap));
1434
1435 assert!(h.refresh_frame_context);
1436 assert!(h.frame_parallel_decoding_mode);
1437 assert_eq!(h.frame_context_idx, 0);
1438
1439 let lf = &h.lf;
1440 assert_eq!(lf.level, 36);
1441 assert_eq!(lf.sharpness, 0);
1442
1443 assert!(lf.delta_enabled);
1444 assert!(!lf.delta_update);
1445
1446 assert_eq!(lf.update_ref_delta, [true, false, true, true]);
1447 assert_eq!(lf.ref_deltas, [1, 0, -1, -1]);
1448
1449 assert_eq!(lf.update_mode_delta, [false, false]);
1450
1451 let q = &h.quant;
1452
1453 assert_eq!(q.base_q_idx, 216);
1454 assert_eq!(q.delta_q_y_dc, 0);
1455 assert_eq!(q.delta_q_uv_dc, 0);
1456 assert_eq!(q.delta_q_uv_ac, 0);
1457
1458 let s = &h.seg;
1459
1460 assert!(!s.enabled);
1461 assert!(!s.update_map);
1462 assert_eq!(s.tree_probs, [0, 0, 0, 0, 0, 0, 0]);
1463 assert_eq!(s.pred_probs, [0, 0, 0]);
1464 assert!(!s.temporal_update);
1465 assert!(!s.update_data);
1466 assert!(!s.abs_or_delta_update);
1467 assert_eq!(s.feature_enabled, [[false; SEG_LVL_MAX]; MAX_SEGMENTS]);
1468 assert_eq!(s.feature_data, [[0; SEG_LVL_MAX]; MAX_SEGMENTS]);
1469
1470 assert_eq!(h.tile_cols_log2, 0);
1471 assert_eq!(h.tile_rows_log2, 0);
1472 assert_eq!(h.header_size_in_bytes, 9);
1473
1474 assert!(!h.lossless);
1475 }
1476 }
1477 }
1478}