cros_codecs/codec/vp9/
parser.rs

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
5use anyhow::anyhow;
6use anyhow::Context;
7use bitreader::BitReader;
8use enumn::N;
9
10use crate::codec::vp9::lookups::AC_QLOOKUP;
11use crate::codec::vp9::lookups::AC_QLOOKUP_10;
12use crate::codec::vp9::lookups::AC_QLOOKUP_12;
13use crate::codec::vp9::lookups::DC_QLOOKUP;
14use crate::codec::vp9::lookups::DC_QLOOKUP_10;
15use crate::codec::vp9::lookups::DC_QLOOKUP_12;
16
17pub const REFS_PER_FRAME: usize = 3;
18
19pub const MAX_REF_LF_DELTAS: usize = 4;
20pub const MAX_MODE_LF_DELTAS: usize = 2;
21
22pub const INTRA_FRAME: usize = 0;
23pub const LAST_FRAME: usize = 1;
24pub const GOLDEN_FRAME: usize = 2;
25pub const ALTREF_FRAME: usize = 3;
26pub const MAX_REF_FRAMES: usize = 4;
27
28pub const MAX_SEGMENTS: usize = 8;
29pub const SEG_TREE_PROBS: usize = MAX_SEGMENTS - 1;
30pub const PREDICTION_PROBS: usize = 3;
31
32/// Valid segment features values.
33#[repr(u8)]
34pub enum SegLvl {
35    AltQ = 0,
36    AltL = 1,
37    RefFrame = 2,
38    LvlSkip = 3,
39}
40pub const SEG_LVL_MAX: usize = 4;
41
42pub const MAX_LOOP_FILTER: u32 = 63;
43
44pub const REF_FRAMES_LOG2: usize = 3;
45pub const REF_FRAMES: usize = 1 << REF_FRAMES_LOG2;
46
47pub const SUPERFRAME_MARKER: u32 = 0x06;
48pub const MAX_FRAMES_IN_SUPERFRAME: usize = 8;
49
50pub const FRAME_MARKER: u32 = 0x02;
51pub const SYNC_CODE: u32 = 0x498342;
52
53pub const MIN_TILE_WIDTH_B64: u32 = 4;
54pub const MAX_TILE_WIDTH_B64: u32 = 64;
55
56/// The number of pictures in the DPB
57pub const NUM_REF_FRAMES: usize = 8;
58
59#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, N)]
60pub enum InterpolationFilter {
61    #[default]
62    EightTap = 0,
63    EightTapSmooth = 1,
64    EightTapSharp = 2,
65    Bilinear = 3,
66    Switchable = 4,
67}
68
69#[derive(Copy, Clone, Debug, PartialEq, Eq, N)]
70pub enum ReferenceFrameType {
71    Intra = 0,
72    Last = 1,
73    Golden = 2,
74    AltRef = 3,
75}
76
77#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, N)]
78
79pub enum FrameType {
80    #[default]
81    KeyFrame = 0,
82    InterFrame = 1,
83}
84
85#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, N)]
86pub enum Profile {
87    #[default]
88    Profile0 = 0,
89    Profile1 = 1,
90    Profile2 = 2,
91    Profile3 = 3,
92}
93
94#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, N)]
95pub enum BitDepth {
96    #[default]
97    Depth8 = 8,
98    Depth10 = 10,
99    Depth12 = 12,
100}
101
102#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, N)]
103pub enum ColorSpace {
104    #[default]
105    Unknown = 0,
106    Bt601 = 1,
107    Bt709 = 2,
108    Smpte170 = 3,
109    Smpte240 = 4,
110    Bt2020 = 5,
111    Reserved2 = 6,
112    CsSrgb = 7,
113}
114
115#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, N)]
116pub enum ColorRange {
117    #[default]
118    StudioSwing = 0,
119    FullSwing = 1,
120}
121
122#[derive(Clone, Debug, Default, PartialEq, Eq)]
123pub struct LoopFilterParams {
124    /// Indicates the loop filter strength.
125    pub level: u8,
126    /// Indicates the sharpness level. The loop filter level and loop
127    /// filter_sharpness together determine when a block edge is filtered, and
128    /// by how much the filtering can change the sample values.
129    pub sharpness: u8,
130    /// If set, means that the filter level depends on the mode and reference
131    /// frame used to predict a block. If unset, means that the filter level
132    /// does not depend on the mode and reference frame.
133    pub delta_enabled: bool,
134    /// If set, means that the bitstream contains additional syntax elements
135    /// that specify which mode and reference frame deltas are to be updated. If
136    /// unset, means that these syntax elements are not present.
137    pub delta_update: bool,
138    /// If set, means that the bitstream contains additional syntax elements
139    /// that specify which mode and reference frame deltas are to be updated. If
140    /// unset, means that these syntax elements are not present.
141    pub update_ref_delta: [bool; MAX_REF_LF_DELTAS],
142    /// Contains the adjustment needed for the filter level based on the chosen
143    /// reference frame. If this syntax element is not present in the bitstream,
144    /// it maintains its previous value.
145    pub ref_deltas: [i8; MAX_REF_LF_DELTAS],
146    ///  If set, means that the bitstream contains the syntax element
147    ///  loop_filter_mode_deltas. If unset, means that the bitstream does not
148    ///  contain this syntax element.
149    pub update_mode_delta: [bool; MAX_MODE_LF_DELTAS],
150    /// Contains the adjustment needed for the filter level based on the chosen
151    /// mode. If this syntax element is not present in the bitstream, it
152    /// maintains its previous value.
153    pub mode_deltas: [i8; MAX_MODE_LF_DELTAS],
154}
155
156#[derive(Clone, Debug, Default, PartialEq, Eq)]
157pub struct QuantizationParams {
158    /// Indicates the base frame qindex. This is used for Y AC coefficients and
159    /// as the base value for the other quantizers.
160    pub base_q_idx: u8,
161    /// Indicates the Y DC quantizer relative to base_q_idx.
162    pub delta_q_y_dc: i8,
163    /// Indicates the UV DC quantizer relative to base_q_idx.
164    pub delta_q_uv_dc: i8,
165    /// Indicates the UV AC quantizer relative to base_q_idx.
166    pub delta_q_uv_ac: i8,
167}
168
169#[derive(Clone, Debug, Default, PartialEq, Eq)]
170pub struct SegmentationParams {
171    ///  If set, indicates that this frame makes use of the segmentation tool.
172    ///  If unset, indicates that the frame does not use segmentation.
173    pub enabled: bool,
174    /// If set, indicates that the segmentation map should be updated during
175    /// the decoding of this frame. If unset, means that the segmentation map
176    /// from the previous frame is used.
177    pub update_map: bool,
178    /// Specify the probability values to be used when decoding segment_id.
179    pub tree_probs: [u8; SEG_TREE_PROBS],
180    /// Specify the probability values to be used when decoding seg_id_predicted.
181    pub pred_probs: [u8; PREDICTION_PROBS],
182    /// If set, indicates that the updates to the segmentation map are coded
183    /// relative to the existing segmentation map. If unset,
184    /// indicates that the new segmentation map is coded without
185    /// reference to the existing segmentation map.
186    pub temporal_update: bool,
187    /// If set, indicates that new parameters are about to be specified for each
188    /// segment. If unset, indicates that the segmentation parameters should
189    /// keep their existing values.
190    pub update_data: bool,
191    /// If unset, indicates that the segmentation parameters represent
192    /// adjustments relative to the standard values. If set, indicates that the
193    /// segmentation parameters represent the actual values to be used.
194    pub abs_or_delta_update: bool,
195    /// If unset, indicates that the corresponding feature is unused and has
196    /// value equal to 0. if set, indicates that the feature value is coded in
197    /// the bitstream.
198    feature_enabled: [[bool; SEG_LVL_MAX]; MAX_SEGMENTS],
199    /// Specifies the magnitude of the feature data for a segment feature.
200    feature_data: [[i16; SEG_LVL_MAX]; MAX_SEGMENTS],
201}
202
203impl SegmentationParams {
204    /// Returns whether `feature` is enabled for `segment_id`.
205    fn is_feature_enabled(&self, segment_id: u8, feature: SegLvl) -> bool {
206        self.feature_enabled[segment_id as usize][feature as usize]
207    }
208
209    /// An implementation of seg_feature_active as per "6.4.9 Segmentation feature active syntax"
210    fn is_feature_active(&self, segment_id: u8, feature: SegLvl) -> bool {
211        self.enabled && self.is_feature_enabled(segment_id, feature)
212    }
213
214    /// Returns the data for `feature` on `segment_id`.
215    fn feature_data(&self, segment_id: u8, feature: SegLvl) -> i16 {
216        self.feature_data[segment_id as usize][feature as usize]
217    }
218}
219
220#[derive(Clone, Debug, Default, PartialEq, Eq)]
221pub struct Segmentation {
222    /// Loop filter level
223    pub lvl_lookup: [[u8; MAX_MODE_LF_DELTAS]; MAX_REF_FRAMES],
224
225    /// AC quant scale for luma component
226    pub luma_ac_quant_scale: i16,
227    /// DC quant scale for luma component
228    pub luma_dc_quant_scale: i16,
229    /// AC quant scale for chroma component
230    pub chroma_ac_quant_scale: i16,
231    /// DC quant scale for chroma component
232    pub chroma_dc_quant_scale: i16,
233
234    /// Whether the alternate reference frame segment feature is enabled (SEG_LVL_REF_FRAME)
235    pub reference_frame_enabled: bool,
236    /// The feature data for the reference frame featire
237    pub reference_frame: i16,
238    /// Whether the skip segment feature is enabled (SEG_LVL_SKIP)
239    pub reference_skip_enabled: bool,
240}
241
242impl Segmentation {
243    /// Update the state of the segmentation parameters after seeing a frame
244    pub fn update_segmentation(segmentation: &mut [Segmentation; MAX_SEGMENTS], hdr: &Header) {
245        let lf = &hdr.lf;
246        let seg = &hdr.seg;
247
248        let n_shift = lf.level >> 5;
249
250        for segment_id in 0..MAX_SEGMENTS as u8 {
251            let luma_dc_quant_scale = hdr.get_dc_quant(segment_id, true);
252            let luma_ac_quant_scale = hdr.get_ac_quant(segment_id, true);
253            let chroma_dc_quant_scale = hdr.get_dc_quant(segment_id, false);
254            let chroma_ac_quant_scale = hdr.get_ac_quant(segment_id, false);
255
256            let mut lvl_lookup: [[u8; MAX_MODE_LF_DELTAS]; MAX_REF_FRAMES];
257
258            if lf.level == 0 {
259                lvl_lookup = Default::default()
260            } else {
261                let mut lvl_seg = i32::from(lf.level);
262
263                // 8.8.1 Loop filter frame init process
264                if hdr.seg.is_feature_active(segment_id, SegLvl::AltL) {
265                    if seg.abs_or_delta_update {
266                        lvl_seg = i32::from(seg.feature_data(segment_id, SegLvl::AltL));
267                    } else {
268                        lvl_seg += i32::from(seg.feature_data(segment_id, SegLvl::AltL));
269                    }
270                }
271
272                let lvl_seg = lvl_seg.clamp(0, MAX_LOOP_FILTER as i32) as u8;
273
274                if !lf.delta_enabled {
275                    lvl_lookup = [[lvl_seg; MAX_MODE_LF_DELTAS]; MAX_REF_FRAMES]
276                } else {
277                    let intra_delta = lf.ref_deltas[INTRA_FRAME] as i32;
278                    let mut intra_lvl = lvl_seg as i32 + (intra_delta << n_shift);
279
280                    lvl_lookup = segmentation[segment_id as usize].lvl_lookup;
281                    lvl_lookup[INTRA_FRAME][0] = intra_lvl.clamp(0, MAX_LOOP_FILTER as i32) as u8;
282
283                    // Note, this array has the [0] element unspecified/unused in
284                    // VP9. Confusing, but we do start to index from 1.
285                    #[allow(clippy::needless_range_loop)]
286                    for ref_ in LAST_FRAME..MAX_REF_FRAMES {
287                        for mode in 0..MAX_MODE_LF_DELTAS {
288                            let ref_delta = lf.ref_deltas[ref_] as i32;
289                            let mode_delta = lf.mode_deltas[mode] as i32;
290
291                            intra_lvl =
292                                lvl_seg as i32 + (ref_delta << n_shift) + (mode_delta << n_shift);
293
294                            lvl_lookup[ref_][mode] =
295                                intra_lvl.clamp(0, MAX_LOOP_FILTER as i32) as u8;
296                        }
297                    }
298                }
299            }
300
301            segmentation[usize::from(segment_id)] = Segmentation {
302                lvl_lookup,
303                luma_ac_quant_scale,
304                luma_dc_quant_scale,
305                chroma_ac_quant_scale,
306                chroma_dc_quant_scale,
307                reference_frame_enabled: seg.is_feature_enabled(segment_id, SegLvl::RefFrame),
308                reference_frame: seg.feature_data(segment_id, SegLvl::RefFrame),
309                reference_skip_enabled: seg.is_feature_enabled(segment_id, SegLvl::LvlSkip),
310            }
311        }
312    }
313}
314
315#[derive(Clone, Debug, Default, PartialEq, Eq)]
316struct FrameSize {
317    width: u32,
318    height: u32,
319}
320
321pub struct Frame<'a> {
322    /// The bitstream data for this frame.
323    bitstream: &'a [u8],
324    /// The frame header.
325    pub header: Header,
326    /// The offset into T
327    offset: usize,
328    /// The size of the data in T
329    size: usize,
330}
331
332impl<'a> Frame<'a> {
333    pub fn new(bitstream: &'a [u8], header: Header, offset: usize, size: usize) -> Self {
334        Self {
335            bitstream,
336            header,
337            offset,
338            size,
339        }
340    }
341}
342
343impl<'a> AsRef<[u8]> for Frame<'a> {
344    fn as_ref(&self) -> &[u8] {
345        let data = self.bitstream;
346        &data[self.offset..self.offset + self.size]
347    }
348}
349
350/// A VP9 frame header.
351#[derive(Clone, Debug, Default, PartialEq, Eq)]
352pub struct Header {
353    /// A subset of syntax, semantics and algorithms defined in a part.
354    pub profile: Profile,
355    /// The bit depth of the frame.
356    pub bit_depth: BitDepth,
357    /// Specifies the chroma subsampling format.
358    pub subsampling_x: bool,
359    /// Specifies the chroma subsampling format.
360    pub subsampling_y: bool,
361    /// Specifies the color space of the stream.
362    pub color_space: ColorSpace,
363    /// Specifies the black level and range of the luma and chroma signals as
364    /// specified in Rec. ITU-R BT.709-6 and Rec. ITU-R BT.2020-2
365    pub color_range: ColorRange,
366    /// Indicates the frame indexed by frame_to_show_map_idx is to be displayed.
367    /// If unset, indicates that further processing is required.
368    pub show_existing_frame: bool,
369    /// Specifies the frame to be displayed. It is only available if
370    /// show_existing_frame is set.
371    pub frame_to_show_map_idx: u8,
372    /// Indicates whether a frame is a key frame.
373    pub frame_type: FrameType,
374    /// Whether this frame should be displayed.
375    pub show_frame: bool,
376    /// Whether error resilient mode is enabled.
377    pub error_resilient_mode: bool,
378    /// The width of the frame in pixels.
379    pub width: u32,
380    /// The height of the frame in pixels.
381    pub height: u32,
382    /// If unset, means that the render width and height are inferred from the
383    /// frame width and height. If set, means that the render width and height
384    /// are explicitly coded in the bitstream.
385    pub render_and_frame_size_different: bool,
386    /// The render width of the frame in pixels.
387    pub render_width: u32,
388    /// The render height of the frame in pixels.
389    pub render_height: u32,
390    /// If set, indicates that this frame is an intra-only frame. If unset,
391    /// indicates that this frame is a inter frame.
392    pub intra_only: bool,
393    /// Specifies whether the frame context should be reset to default values.
394    pub reset_frame_context: u8,
395    /// Contains a bitmask that specifies which reference frame slots will be
396    /// updated with the current frame after it is decoded.
397    pub refresh_frame_flags: u8,
398    /// Specifies which reference frames are used by inter frames. It is a
399    /// requirement of bitstream conformance that the selected reference frames
400    /// match the current frame in bit depth, profile, chroma subsampling, and
401    /// color space.
402    pub ref_frame_idx: [u8; REFS_PER_FRAME],
403    /// Specifies the intended direction of the motion vector in time for each
404    /// reference frame. A sign bias equal to 0 indicates that the reference
405    /// frame is a backwards reference; a sign bias equal to 1 indicates that
406    /// the reference frame is a forwards reference
407    pub ref_frame_sign_bias: [u8; 4],
408    /// If unset, specifies that motion vectors are specified to quarter pel
409    /// precision. If set, specifies that motion vectors are specified to eighth
410    /// pel precision.
411    pub allow_high_precision_mv: bool,
412    /// The interpolation filter parameters.
413    pub interpolation_filter: InterpolationFilter,
414    /// If set, indicates that the probabilities computed for this frame (after
415    /// adapting to the observed frequencies if adaption is enabled) should be
416    /// stored for reference by future frames. If unset, indicates that the
417    /// probabilities should be discarded at the end of the frame.
418    pub refresh_frame_context: bool,
419    /// Whether parallel decoding mode is enabled.
420    pub frame_parallel_decoding_mode: bool,
421    /// Indicates the frame context to use.
422    pub frame_context_idx: u8,
423    /// The loop filter parameters
424    pub lf: LoopFilterParams,
425    /// The quantization parameters.
426    pub quant: QuantizationParams,
427    /// The segmentation parameters
428    pub seg: SegmentationParams,
429    /// Specifies the base 2 logarithm of the width of each tile (where the
430    /// width is measured in units of 8x8 blocks). It is a requirement of
431    /// bitstream conformance that tile_cols_log2 is less than or equal to 6.
432    pub tile_cols_log2: u8,
433    /// Specifies the base 2 logarithm of the height of each tile (where the
434    /// height is measured in units of 8x8 blocks).
435    pub tile_rows_log2: u8,
436    /// Computed from the syntax elements. If set, indicates that the frame is
437    /// coded using a special 4x4 transform designed for encoding frames that
438    /// are bit-identical with the original frames.
439    pub lossless: bool,
440    /// Indicates the size of the compressed header in bytes.
441    pub header_size_in_bytes: u16,
442    /// Indicates the size of the uncompressed header in bytes.
443    pub uncompressed_header_size_in_bytes: u16,
444}
445
446impl Header {
447    /// An implementation of get_qindex as per "8.6.1 Dequantization functions"
448    fn get_qindex(&self, segment_id: u8) -> u8 {
449        let base_q_idx = self.quant.base_q_idx;
450
451        if self.seg.is_feature_active(segment_id, SegLvl::AltQ) {
452            let mut data = self.seg.feature_data(segment_id, SegLvl::AltQ) as i32;
453
454            if !self.seg.abs_or_delta_update {
455                data += base_q_idx as i32;
456            }
457
458            data.clamp(0, 255) as u8
459        } else {
460            base_q_idx
461        }
462    }
463
464    /// An implementation of get_dc_quant as per "8.6.1 Dequantization functions"
465    fn get_dc_quant(&self, segment_id: u8, luma: bool) -> i16 {
466        let delta_q_dc = if luma {
467            self.quant.delta_q_y_dc
468        } else {
469            self.quant.delta_q_uv_dc
470        } as i32;
471        let qindex = self.get_qindex(segment_id);
472        let q_table_idx = (qindex as i32 + delta_q_dc).clamp(0, 255) as u8;
473
474        let table = match self.bit_depth {
475            BitDepth::Depth8 => &DC_QLOOKUP,
476            BitDepth::Depth10 => &DC_QLOOKUP_10,
477            BitDepth::Depth12 => &DC_QLOOKUP_12,
478        };
479
480        table[q_table_idx as usize]
481    }
482
483    /// An implementation of get_ac_quant as per "8.6.1 Dequantization functions"
484    fn get_ac_quant(&self, segment_id: u8, luma: bool) -> i16 {
485        let delta_q_ac = if luma { 0 } else { self.quant.delta_q_uv_ac } as i32;
486        let qindex = self.get_qindex(segment_id);
487        let q_table_idx = (qindex as i32 + delta_q_ac).clamp(0, 255) as u8;
488
489        let table = match self.bit_depth {
490            BitDepth::Depth8 => &AC_QLOOKUP,
491            BitDepth::Depth10 => &AC_QLOOKUP_10,
492            BitDepth::Depth12 => &AC_QLOOKUP_12,
493        };
494
495        table[q_table_idx as usize]
496    }
497}
498
499/// The VP9 superframe header as per Annex B, B.2.1, B.2.2
500struct SuperframeHeader {
501    /// Indicates the number of frames within this superframe. NOTE - It is
502    /// legal for a superframe to contain just a single frame and have NumFrames
503    /// equal to 1.
504    frames_in_superframe: u32,
505    /// Specifies the size in bytes of frame number i (zero indexed) within this
506    /// superframe.
507    frame_sizes: Vec<usize>,
508}
509
510/// A VP9 bitstream parser.
511#[derive(Clone, Debug, Default, PartialEq, Eq)]
512pub struct Parser {
513    bit_depth: BitDepth,
514    subsampling_x: bool,
515    subsampling_y: bool,
516    color_space: ColorSpace,
517    color_range: ColorRange,
518
519    mi_cols: u32,
520    mi_rows: u32,
521    sb64_cols: u32,
522    sb64_rows: u32,
523
524    lf: LoopFilterParams,
525    seg: SegmentationParams,
526
527    reference_frame_sz: [FrameSize; REF_FRAMES],
528}
529
530impl Parser {
531    fn parse_superframe_hdr(resource: impl AsRef<[u8]>) -> anyhow::Result<SuperframeHeader> {
532        let bitstream = resource.as_ref();
533
534        // Skip to the end of the chunk.
535        let mut reader = BitReader::new(&bitstream[bitstream.len() - 1..]);
536
537        // Try reading a superframe marker.
538        let marker = reader.read_u32(3)?;
539
540        if marker != SUPERFRAME_MARKER {
541            // Not a superframe
542            return Ok(SuperframeHeader {
543                frames_in_superframe: 1,
544                frame_sizes: vec![bitstream.len()],
545            });
546        }
547
548        let bytes_per_framesize = reader.read_u32(2)? + 1;
549        let frames_in_superframe = reader.read_u32(3)? + 1;
550
551        if frames_in_superframe > MAX_FRAMES_IN_SUPERFRAME as u32 {
552            return Err(anyhow!(
553                "Broken stream: too many frames in superframe, expected a maximum of {:?}, found {:?}",
554                MAX_FRAMES_IN_SUPERFRAME,
555                frames_in_superframe
556            ));
557        }
558
559        let sz_index = 2 + frames_in_superframe * bytes_per_framesize;
560
561        let data = resource.as_ref();
562        let index_offset = data.len() - sz_index as usize;
563        let first_byte = data[index_offset];
564        let last_byte = *data
565            .last()
566            .ok_or_else(|| anyhow!("superframe header is empty"))?;
567
568        if first_byte != last_byte {
569            // Also not a superframe, we must pass both tests as per the specification.
570            return Ok(SuperframeHeader {
571                frames_in_superframe: 1,
572                frame_sizes: vec![bitstream.len()],
573            });
574        }
575
576        let mut frame_sizes = vec![];
577        let mut reader = BitReader::new(&bitstream[index_offset..]);
578
579        // Skip the superframe header.
580        let _ = reader.read_u32(8)?;
581
582        for _ in 0..frames_in_superframe {
583            let mut frame_size = 0;
584
585            for j in 0..bytes_per_framesize {
586                frame_size |= reader.read_u32(8)? << (j * 8);
587            }
588
589            frame_sizes.push(frame_size as usize);
590        }
591
592        Ok(SuperframeHeader {
593            frames_in_superframe,
594            frame_sizes,
595        })
596    }
597
598    fn read_signed_8(r: &mut BitReader, nbits: u8) -> bitreader::Result<i8> {
599        let value = r.read_u8(nbits)?;
600        let negative = r.read_bool()?;
601
602        if negative {
603            Ok(-(value as i8))
604        } else {
605            Ok(value as i8)
606        }
607    }
608
609    fn parse_frame_marker(r: &mut BitReader) -> anyhow::Result<()> {
610        let marker = r.read_u32(2)?;
611
612        if marker != FRAME_MARKER {
613            return Err(anyhow!(
614                "Broken stream: expected frame marker, found {:?}",
615                marker
616            ));
617        }
618
619        Ok(())
620    }
621
622    fn parse_profile(r: &mut BitReader) -> anyhow::Result<Profile> {
623        let low = r.read_u32(1)?;
624        let high = r.read_u32(1)?;
625
626        let profile = (high << 1) | low;
627
628        if profile == 3 {
629            // Skip the reserved bit
630            let _ = r.read_bool()?;
631        }
632
633        Profile::n(profile).with_context(|| format!("Broken stream: invalid profile {:?}", profile))
634    }
635
636    fn parse_frame_sync_code(r: &mut BitReader) -> anyhow::Result<()> {
637        let sync_code = r.read_u32(24)?;
638
639        if sync_code != SYNC_CODE {
640            return Err(anyhow!(
641                "Broken stream: expected sync code == {:?}, found {:?}",
642                SYNC_CODE,
643                sync_code
644            ));
645        }
646
647        Ok(())
648    }
649
650    fn parse_color_config(&mut self, r: &mut BitReader, hdr: &mut Header) -> anyhow::Result<()> {
651        if matches!(hdr.profile, Profile::Profile2 | Profile::Profile3) {
652            let ten_or_twelve_bit = r.read_bool()?;
653            if ten_or_twelve_bit {
654                hdr.bit_depth = BitDepth::Depth12;
655            } else {
656                hdr.bit_depth = BitDepth::Depth10
657            }
658        } else {
659            hdr.bit_depth = BitDepth::Depth8;
660        }
661
662        let color_space = r.read_u32(3)?;
663        hdr.color_space = ColorSpace::n(color_space)
664            .with_context(|| format!("Broken stream: invalid color space: {:?}", color_space))?;
665
666        if !matches!(hdr.color_space, ColorSpace::CsSrgb) {
667            let color_range = r.read_u32(1)?;
668
669            hdr.color_range = ColorRange::n(color_range).with_context(|| {
670                format!("Broken stream: invalid color range: {:?}", color_range)
671            })?;
672
673            if matches!(hdr.profile, Profile::Profile1 | Profile::Profile3) {
674                hdr.subsampling_x = r.read_bool()?;
675                hdr.subsampling_y = r.read_bool()?;
676
677                // Skip the reserved bit
678                let _ = r.read_bool()?;
679            } else {
680                hdr.subsampling_x = true;
681                hdr.subsampling_y = true;
682            }
683        } else {
684            hdr.color_range = ColorRange::FullSwing;
685            if matches!(hdr.profile, Profile::Profile1 | Profile::Profile3) {
686                hdr.subsampling_x = false;
687                hdr.subsampling_y = false;
688
689                // Skip the reserved bit
690                let _ = r.read_bool()?;
691            }
692        }
693
694        self.bit_depth = hdr.bit_depth;
695        self.color_space = hdr.color_space;
696        self.subsampling_x = hdr.subsampling_x;
697        self.subsampling_y = hdr.subsampling_y;
698        self.color_range = hdr.color_range;
699
700        Ok(())
701    }
702
703    fn compute_image_size(&mut self, width: u32, height: u32) {
704        self.mi_cols = (width + 7) >> 3;
705        self.mi_rows = (height + 7) >> 3;
706        self.sb64_cols = (self.mi_cols + 7) >> 3;
707        self.sb64_rows = (self.mi_rows + 7) >> 3;
708    }
709
710    fn parse_frame_size(&mut self, r: &mut BitReader, hdr: &mut Header) -> bitreader::Result<()> {
711        hdr.width = r.read_u32(16)? + 1;
712        hdr.height = r.read_u32(16)? + 1;
713        self.compute_image_size(hdr.width, hdr.height);
714        Ok(())
715    }
716
717    fn parse_render_size(r: &mut BitReader, hdr: &mut Header) -> bitreader::Result<()> {
718        hdr.render_and_frame_size_different = r.read_bool()?;
719        if hdr.render_and_frame_size_different {
720            hdr.render_width = r.read_u32(16)? + 1;
721            hdr.render_height = r.read_u32(16)? + 1;
722        } else {
723            hdr.render_width = hdr.width;
724            hdr.render_height = hdr.height;
725        }
726
727        Ok(())
728    }
729
730    fn parse_frame_size_with_refs(
731        &mut self,
732        r: &mut BitReader,
733        hdr: &mut Header,
734    ) -> bitreader::Result<()> {
735        let mut found_ref = false;
736
737        for i in 0..REFS_PER_FRAME {
738            found_ref = r.read_bool()?;
739
740            if found_ref {
741                let idx = hdr.ref_frame_idx[i] as usize;
742                hdr.width = self.reference_frame_sz[idx].width;
743                hdr.height = self.reference_frame_sz[idx].height;
744                break;
745            }
746        }
747
748        if !found_ref {
749            self.parse_frame_size(r, hdr)?;
750        } else {
751            self.compute_image_size(hdr.width, hdr.height)
752        }
753
754        Self::parse_render_size(r, hdr)
755    }
756
757    fn read_interpolation_filter(r: &mut BitReader) -> bitreader::Result<InterpolationFilter> {
758        const LITERAL_TO_TYPE: [InterpolationFilter; 4] = [
759            InterpolationFilter::EightTapSmooth,
760            InterpolationFilter::EightTap,
761            InterpolationFilter::EightTapSharp,
762            InterpolationFilter::Bilinear,
763        ];
764
765        let is_filter_switchable = r.read_bool()?;
766
767        Ok(if is_filter_switchable {
768            InterpolationFilter::Switchable
769        } else {
770            let raw_interpolation_filter = r.read_u32(2)?;
771            LITERAL_TO_TYPE[raw_interpolation_filter as usize]
772        })
773    }
774
775    fn setup_past_independence(&mut self, hdr: &mut Header) {
776        self.seg.feature_enabled = Default::default();
777        self.seg.feature_data = Default::default();
778        self.seg.abs_or_delta_update = false;
779
780        self.lf.delta_enabled = true;
781        self.lf.ref_deltas[ReferenceFrameType::Intra as usize] = 1;
782        self.lf.ref_deltas[ReferenceFrameType::Last as usize] = 0;
783        self.lf.ref_deltas[ReferenceFrameType::Golden as usize] = -1;
784        self.lf.ref_deltas[ReferenceFrameType::AltRef as usize] = -1;
785
786        self.lf.mode_deltas = Default::default();
787        hdr.ref_frame_sign_bias = Default::default();
788    }
789
790    fn parse_loop_filter_params(
791        r: &mut BitReader,
792        lf: &mut LoopFilterParams,
793    ) -> bitreader::Result<()> {
794        lf.level = r.read_u8(6)?;
795        lf.sharpness = r.read_u8(3)?;
796        lf.delta_enabled = r.read_bool()?;
797
798        if lf.delta_enabled {
799            lf.delta_update = r.read_bool()?;
800            if lf.delta_update {
801                for i in 0..MAX_REF_LF_DELTAS {
802                    lf.update_ref_delta[i] = r.read_bool()?;
803                    if lf.update_ref_delta[i] {
804                        lf.ref_deltas[i] = Self::read_signed_8(r, 6)?;
805                    }
806                }
807
808                for i in 0..MAX_MODE_LF_DELTAS {
809                    lf.update_mode_delta[i] = r.read_bool()?;
810                    if lf.update_mode_delta[i] {
811                        lf.mode_deltas[i] = Self::read_signed_8(r, 6)?;
812                    }
813                }
814            }
815        }
816
817        Ok(())
818    }
819
820    fn read_delta_q(r: &mut BitReader, value: &mut i8) -> bitreader::Result<()> {
821        let delta_coded = r.read_bool()?;
822
823        if delta_coded {
824            *value = Self::read_signed_8(r, 4)?;
825        } else {
826            *value = 0;
827        }
828
829        Ok(())
830    }
831
832    fn parse_quantization_params(r: &mut BitReader, hdr: &mut Header) -> bitreader::Result<()> {
833        let quant = &mut hdr.quant;
834
835        quant.base_q_idx = r.read_u8(8)?;
836
837        Self::read_delta_q(r, &mut quant.delta_q_y_dc)?;
838        Self::read_delta_q(r, &mut quant.delta_q_uv_dc)?;
839        Self::read_delta_q(r, &mut quant.delta_q_uv_ac)?;
840
841        hdr.lossless = quant.base_q_idx == 0
842            && quant.delta_q_y_dc == 0
843            && quant.delta_q_uv_dc == 0
844            && quant.delta_q_uv_ac == 0;
845
846        Ok(())
847    }
848
849    fn read_prob(r: &mut BitReader) -> bitreader::Result<u8> {
850        let prob_coded = r.read_bool()?;
851
852        let prob = if prob_coded { r.read_u8(8)? } else { 255 };
853
854        Ok(prob)
855    }
856
857    fn parse_segmentation_params(
858        r: &mut BitReader,
859        seg: &mut SegmentationParams,
860    ) -> bitreader::Result<()> {
861        const SEGMENTATION_FEATURE_BITS: [u8; SEG_LVL_MAX] = [8, 6, 2, 0];
862        const SEGMENTATION_FEATURE_SIGNED: [bool; SEG_LVL_MAX] = [true, true, false, false];
863
864        seg.update_map = false;
865        seg.update_data = false;
866
867        seg.enabled = r.read_bool()?;
868
869        if !seg.enabled {
870            return Ok(());
871        }
872
873        seg.update_map = r.read_bool()?;
874
875        if seg.update_map {
876            for i in 0..SEG_TREE_PROBS {
877                seg.tree_probs[i] = Self::read_prob(r)?;
878            }
879
880            seg.temporal_update = r.read_bool()?;
881
882            for i in 0..PREDICTION_PROBS {
883                seg.pred_probs[i] = if seg.temporal_update {
884                    Self::read_prob(r)?
885                } else {
886                    255
887                };
888            }
889        }
890
891        seg.update_data = r.read_bool()?;
892
893        if seg.update_data {
894            seg.abs_or_delta_update = r.read_bool()?;
895            for i in 0..MAX_SEGMENTS {
896                for j in 0..SEG_LVL_MAX {
897                    seg.feature_enabled[i][j] = r.read_bool()?;
898                    if seg.feature_enabled[i][j] {
899                        let bits_to_read = SEGMENTATION_FEATURE_BITS[j];
900                        let mut feature_value = r.read_i16(bits_to_read)?;
901
902                        if SEGMENTATION_FEATURE_SIGNED[j] {
903                            let feature_sign = r.read_bool()?;
904
905                            if feature_sign {
906                                feature_value = -feature_value;
907                            }
908                        }
909
910                        seg.feature_data[i][j] = feature_value;
911                    }
912                }
913            }
914        }
915
916        Ok(())
917    }
918
919    fn calc_min_log2_tile_cols(sb64_cols: u32) -> u8 {
920        let mut min_log2 = 0;
921
922        while (MAX_TILE_WIDTH_B64 << min_log2) < sb64_cols {
923            min_log2 += 1;
924        }
925
926        min_log2
927    }
928
929    fn calc_max_log2_tile_cols(sb64_cols: u32) -> u8 {
930        let mut max_log2 = 1;
931
932        while (sb64_cols >> max_log2) >= MIN_TILE_WIDTH_B64 {
933            max_log2 += 1;
934        }
935
936        max_log2 - 1
937    }
938
939    fn parse_tile_info(&self, r: &mut BitReader, hdr: &mut Header) -> bitreader::Result<()> {
940        let max_log2_tile_cols = Self::calc_max_log2_tile_cols(self.sb64_cols);
941
942        hdr.tile_cols_log2 = Self::calc_min_log2_tile_cols(self.sb64_cols);
943
944        while hdr.tile_cols_log2 < max_log2_tile_cols {
945            let increment_tile_cols_log2 = r.read_bool()?;
946
947            if increment_tile_cols_log2 {
948                hdr.tile_cols_log2 += 1;
949            } else {
950                break;
951            }
952        }
953
954        hdr.tile_rows_log2 = r.read_u8(1)?;
955
956        if hdr.tile_rows_log2 > 0 {
957            let increment_tile_rows_log2 = r.read_bool()?;
958            hdr.tile_rows_log2 += increment_tile_rows_log2 as u8;
959        }
960
961        Ok(())
962    }
963
964    fn parse_frame_header(
965        &mut self,
966        resource: impl AsRef<[u8]>,
967        offset: usize,
968    ) -> anyhow::Result<Header> {
969        let data = &resource.as_ref()[offset..];
970        let mut r = BitReader::new(data);
971        let mut hdr = Header::default();
972
973        Self::parse_frame_marker(&mut r)?;
974        hdr.profile = Self::parse_profile(&mut r)?;
975
976        hdr.show_existing_frame = r.read_bool()?;
977
978        if hdr.show_existing_frame {
979            hdr.frame_to_show_map_idx = r.read_u8(3)?;
980            return Ok(hdr);
981        }
982
983        hdr.frame_type =
984            FrameType::n(r.read_u8(1)?).ok_or(anyhow!("Broken data: invalid frame type"))?;
985
986        hdr.show_frame = r.read_bool()?;
987        hdr.error_resilient_mode = r.read_bool()?;
988
989        let frame_is_intra;
990
991        if matches!(hdr.frame_type, FrameType::KeyFrame) {
992            Self::parse_frame_sync_code(&mut r)?;
993            self.parse_color_config(&mut r, &mut hdr)?;
994            self.parse_frame_size(&mut r, &mut hdr)?;
995            Self::parse_render_size(&mut r, &mut hdr)?;
996            hdr.refresh_frame_flags = 0xff;
997            frame_is_intra = true;
998        } else {
999            if !hdr.show_frame {
1000                hdr.intra_only = r.read_bool()?;
1001            }
1002
1003            frame_is_intra = hdr.intra_only;
1004
1005            if !hdr.error_resilient_mode {
1006                hdr.reset_frame_context = r.read_u8(2)?;
1007            } else {
1008                hdr.reset_frame_context = 0;
1009            }
1010
1011            if hdr.intra_only {
1012                Self::parse_frame_sync_code(&mut r)?;
1013
1014                if !matches!(hdr.profile, Profile::Profile0) {
1015                    self.parse_color_config(&mut r, &mut hdr)?;
1016                } else {
1017                    hdr.color_space = ColorSpace::Bt601;
1018                    hdr.subsampling_x = true;
1019                    hdr.subsampling_y = true;
1020                    hdr.bit_depth = BitDepth::Depth8;
1021
1022                    self.color_space = hdr.color_space;
1023                    self.subsampling_x = hdr.subsampling_x;
1024                    self.subsampling_y = hdr.subsampling_y;
1025                    self.bit_depth = hdr.bit_depth;
1026                }
1027
1028                hdr.refresh_frame_flags = r.read_u8(8)?;
1029                self.parse_frame_size(&mut r, &mut hdr)?;
1030                Self::parse_render_size(&mut r, &mut hdr)?;
1031            } else {
1032                // Copy from our cached version
1033                hdr.color_space = self.color_space;
1034                hdr.color_range = self.color_range;
1035                hdr.subsampling_x = self.subsampling_x;
1036                hdr.subsampling_y = self.subsampling_y;
1037                hdr.bit_depth = self.bit_depth;
1038
1039                hdr.refresh_frame_flags = r.read_u8(8)?;
1040
1041                for i in 0..REFS_PER_FRAME {
1042                    hdr.ref_frame_idx[i] = r.read_u8(3)?;
1043                    hdr.ref_frame_sign_bias[ReferenceFrameType::Last as usize + i] =
1044                        r.read_u8(1)?;
1045                }
1046
1047                self.parse_frame_size_with_refs(&mut r, &mut hdr)?;
1048                hdr.allow_high_precision_mv = r.read_bool()?;
1049                hdr.interpolation_filter = Self::read_interpolation_filter(&mut r)?;
1050            }
1051        }
1052
1053        if !hdr.error_resilient_mode {
1054            hdr.refresh_frame_context = r.read_bool()?;
1055            hdr.frame_parallel_decoding_mode = r.read_bool()?;
1056        } else {
1057            hdr.refresh_frame_context = false;
1058            hdr.frame_parallel_decoding_mode = true;
1059        }
1060
1061        hdr.frame_context_idx = r.read_u8(2)?;
1062
1063        if frame_is_intra || hdr.error_resilient_mode {
1064            self.setup_past_independence(&mut hdr);
1065        }
1066
1067        Self::parse_loop_filter_params(&mut r, &mut self.lf)?;
1068        Self::parse_quantization_params(&mut r, &mut hdr)?;
1069        Self::parse_segmentation_params(&mut r, &mut self.seg)?;
1070        self.parse_tile_info(&mut r, &mut hdr)?;
1071
1072        hdr.header_size_in_bytes = r.read_u16(16)?;
1073
1074        hdr.lf = self.lf.clone();
1075        hdr.seg = self.seg.clone();
1076
1077        for i in 0..REF_FRAMES {
1078            let flag = 1 << i;
1079            if hdr.refresh_frame_flags & flag != 0 {
1080                self.reference_frame_sz[i].width = hdr.width;
1081                self.reference_frame_sz[i].height = hdr.height;
1082            }
1083        }
1084
1085        hdr.uncompressed_header_size_in_bytes = (r.position() as u16 + 7) / 8;
1086
1087        Ok(hdr)
1088    }
1089
1090    /// Parse a single VP9 frame.
1091    pub fn parse_frame<'a>(
1092        &mut self,
1093        bitstream: &'a [u8],
1094        offset: usize,
1095        size: usize,
1096    ) -> anyhow::Result<Frame<'a>> {
1097        let header = self.parse_frame_header(bitstream, offset)?;
1098
1099        Ok(Frame {
1100            header,
1101            bitstream,
1102            offset,
1103            size,
1104        })
1105    }
1106
1107    /// Parses VP9 frames from the data in `resource`. This can result in more than one frame if the
1108    /// data passed in contains a VP9 superframe.
1109    pub fn parse_chunk<'a>(&mut self, resource: &'a [u8]) -> anyhow::Result<Vec<Frame<'a>>> {
1110        let superframe_hdr = Parser::parse_superframe_hdr(resource)?;
1111        let mut offset = 0;
1112
1113        let mut frames = vec![];
1114
1115        for i in 0..superframe_hdr.frames_in_superframe {
1116            let frame_sz = superframe_hdr.frame_sizes[i as usize];
1117            let frame = self.parse_frame(resource, offset, frame_sz)?;
1118            offset += frame_sz;
1119            frames.push(frame);
1120        }
1121
1122        Ok(frames)
1123    }
1124}
1125
1126#[cfg(test)]
1127mod tests {
1128    use crate::codec::vp9::parser::BitDepth;
1129    use crate::codec::vp9::parser::ColorSpace;
1130    use crate::codec::vp9::parser::FrameType;
1131    use crate::codec::vp9::parser::InterpolationFilter;
1132    use crate::codec::vp9::parser::Parser;
1133    use crate::codec::vp9::parser::Profile;
1134    use crate::codec::vp9::parser::MAX_SEGMENTS;
1135    use crate::codec::vp9::parser::SEG_LVL_MAX;
1136    use crate::utils::IvfIterator;
1137
1138    #[test]
1139    fn test_parse_superframe() {
1140        // Demuxed, raw vp9 superframe
1141        const VP9_TEST_SUPERFRAME: &[u8] = include_bytes!("test_data/vp9-superframe.bin");
1142
1143        let mut parser = Parser::default();
1144        let frames = parser
1145            .parse_chunk(VP9_TEST_SUPERFRAME)
1146            .expect("Parsing a superframe failed");
1147
1148        assert_eq!(frames.len(), 2);
1149        assert_eq!(frames[0].offset, 0);
1150        assert_eq!(frames[0].size, 1333);
1151        assert_eq!(frames[1].offset, 1333);
1152        assert_eq!(frames[1].size, 214);
1153    }
1154
1155    #[test]
1156    fn test_parse_test25fps() {
1157        // Muxed as IVF
1158        const TEST_STREAM: &[u8] = include_bytes!("test_data/test-25fps.vp9");
1159
1160        let mut parser = Parser::default();
1161        let ivf_iter = IvfIterator::new(TEST_STREAM);
1162
1163        for (frame_n, packet) in ivf_iter.enumerate() {
1164            let frames = parser
1165                .parse_chunk(packet.as_ref())
1166                .expect("Parsing a superframe failed");
1167
1168            if frame_n == 0 {
1169                assert_eq!(frames.len(), 1);
1170                let h = &frames[0].header;
1171
1172                assert!(matches!(h.profile, Profile::Profile0));
1173                assert!(matches!(h.bit_depth, BitDepth::Depth8));
1174
1175                assert!(h.subsampling_x);
1176                assert!(h.subsampling_y);
1177
1178                assert!(matches!(h.color_space, ColorSpace::Unknown));
1179                assert!(matches!(
1180                    h.color_range,
1181                    crate::codec::vp9::parser::ColorRange::StudioSwing
1182                ));
1183
1184                assert!(!h.show_existing_frame);
1185                assert_eq!(h.frame_to_show_map_idx, 0);
1186
1187                assert!(matches!(h.frame_type, FrameType::KeyFrame));
1188                assert!(h.show_frame);
1189                assert!(!h.error_resilient_mode);
1190
1191                assert_eq!(h.width, 320);
1192                assert_eq!(h.height, 240);
1193
1194                assert!(!h.render_and_frame_size_different);
1195
1196                assert_eq!(h.render_width, 320);
1197                assert_eq!(h.render_height, 240);
1198
1199                assert!(!h.intra_only);
1200                assert_eq!(h.reset_frame_context, 0);
1201
1202                assert_eq!(h.refresh_frame_flags, 0xff);
1203                assert_eq!(h.ref_frame_idx, [0, 0, 0]);
1204                assert_eq!(h.ref_frame_sign_bias, [0, 0, 0, 0]);
1205
1206                assert!(!h.allow_high_precision_mv);
1207                assert!(matches!(
1208                    h.interpolation_filter,
1209                    InterpolationFilter::EightTap
1210                ));
1211
1212                assert!(h.refresh_frame_context);
1213                assert!(h.frame_parallel_decoding_mode);
1214                assert_eq!(h.frame_context_idx, 0);
1215
1216                let lf = &h.lf;
1217                assert_eq!(lf.level, 9);
1218                assert_eq!(lf.sharpness, 0);
1219
1220                assert!(lf.delta_enabled);
1221                assert!(lf.delta_update);
1222
1223                assert_eq!(lf.update_ref_delta, [true, false, true, true]);
1224                assert_eq!(lf.ref_deltas, [1, 0, -1, -1]);
1225
1226                assert_eq!(lf.update_mode_delta, [false, false]);
1227
1228                let q = &h.quant;
1229
1230                assert_eq!(q.base_q_idx, 65);
1231                assert_eq!(q.delta_q_y_dc, 0);
1232                assert_eq!(q.delta_q_uv_dc, 0);
1233                assert_eq!(q.delta_q_uv_ac, 0);
1234
1235                let s = &h.seg;
1236
1237                assert!(!s.enabled);
1238                assert!(!s.update_map);
1239                assert_eq!(s.tree_probs, [0, 0, 0, 0, 0, 0, 0]);
1240                assert_eq!(s.pred_probs, [0, 0, 0]);
1241                assert!(!s.temporal_update);
1242                assert!(!s.update_data);
1243                assert!(!s.abs_or_delta_update);
1244                assert_eq!(s.feature_enabled, [[false; SEG_LVL_MAX]; MAX_SEGMENTS]);
1245                assert_eq!(s.feature_data, [[0; SEG_LVL_MAX]; MAX_SEGMENTS]);
1246
1247                assert_eq!(h.tile_cols_log2, 0);
1248                assert_eq!(h.tile_rows_log2, 0);
1249                assert_eq!(h.header_size_in_bytes, 120);
1250
1251                assert!(!h.lossless);
1252            } else if frame_n == 1 {
1253                assert_eq!(frames.len(), 2);
1254
1255                assert_eq!(frames[0].offset, 0);
1256                assert_eq!(frames[0].size, 2390);
1257                assert_eq!(frames[1].offset, 2390);
1258                assert_eq!(frames[1].size, 108);
1259
1260                let h = &frames[0].header;
1261
1262                assert!(matches!(h.profile, Profile::Profile0));
1263                assert!(matches!(h.bit_depth, BitDepth::Depth8));
1264
1265                assert!(h.subsampling_x);
1266                assert!(h.subsampling_y);
1267
1268                assert!(matches!(h.color_space, ColorSpace::Unknown));
1269                assert!(matches!(
1270                    h.color_range,
1271                    crate::codec::vp9::parser::ColorRange::StudioSwing
1272                ));
1273
1274                assert!(!h.show_existing_frame);
1275                assert_eq!(h.frame_to_show_map_idx, 0);
1276
1277                assert!(matches!(h.frame_type, FrameType::InterFrame));
1278                assert!(!h.show_frame);
1279                assert!(!h.error_resilient_mode);
1280
1281                assert_eq!(h.width, 320);
1282                assert_eq!(h.height, 240);
1283
1284                assert!(!h.render_and_frame_size_different);
1285
1286                assert_eq!(h.render_width, 320);
1287                assert_eq!(h.render_height, 240);
1288
1289                assert!(!h.intra_only);
1290                assert_eq!(h.reset_frame_context, 0);
1291
1292                assert_eq!(h.refresh_frame_flags, 4);
1293                assert_eq!(h.ref_frame_idx, [0, 1, 2]);
1294                assert_eq!(h.ref_frame_sign_bias, [0, 0, 0, 0]);
1295
1296                assert!(h.allow_high_precision_mv);
1297                assert!(matches!(
1298                    h.interpolation_filter,
1299                    InterpolationFilter::EightTap
1300                ));
1301
1302                assert!(h.refresh_frame_context);
1303                assert!(h.frame_parallel_decoding_mode);
1304                assert_eq!(h.frame_context_idx, 1);
1305
1306                let lf = &h.lf;
1307                assert_eq!(lf.level, 15);
1308                assert_eq!(lf.sharpness, 0);
1309
1310                assert!(lf.delta_enabled);
1311                assert!(!lf.delta_update);
1312
1313                assert_eq!(lf.update_ref_delta, [true, false, true, true]);
1314                assert_eq!(lf.ref_deltas, [1, 0, -1, -1]);
1315
1316                assert_eq!(lf.update_mode_delta, [false, false]);
1317
1318                let q = &h.quant;
1319
1320                assert_eq!(q.base_q_idx, 112);
1321                assert_eq!(q.delta_q_y_dc, 0);
1322                assert_eq!(q.delta_q_uv_dc, 0);
1323                assert_eq!(q.delta_q_uv_ac, 0);
1324
1325                let s = &h.seg;
1326
1327                assert!(!s.enabled);
1328                assert!(!s.update_map);
1329                assert_eq!(s.tree_probs, [0, 0, 0, 0, 0, 0, 0]);
1330                assert_eq!(s.pred_probs, [0, 0, 0]);
1331                assert!(!s.temporal_update);
1332                assert!(!s.update_data);
1333                assert!(!s.abs_or_delta_update);
1334                assert_eq!(s.feature_enabled, [[false; SEG_LVL_MAX]; MAX_SEGMENTS]);
1335                assert_eq!(s.feature_data, [[0; SEG_LVL_MAX]; MAX_SEGMENTS]);
1336
1337                assert_eq!(h.tile_cols_log2, 0);
1338                assert_eq!(h.tile_rows_log2, 0);
1339                assert_eq!(h.header_size_in_bytes, 48);
1340
1341                assert!(!h.lossless);
1342
1343                let h = &frames[1].header;
1344
1345                assert!(matches!(h.profile, Profile::Profile0));
1346                assert!(matches!(h.bit_depth, BitDepth::Depth8));
1347
1348                assert!(h.subsampling_x);
1349                assert!(h.subsampling_y);
1350
1351                assert!(matches!(h.color_space, ColorSpace::Unknown));
1352                assert!(matches!(
1353                    h.color_range,
1354                    crate::codec::vp9::parser::ColorRange::StudioSwing
1355                ));
1356
1357                assert!(!h.show_existing_frame);
1358                assert_eq!(h.frame_to_show_map_idx, 0);
1359
1360                assert!(matches!(h.frame_type, FrameType::InterFrame));
1361                assert!(h.show_frame);
1362                assert!(!h.error_resilient_mode);
1363
1364                assert_eq!(h.width, 320);
1365                assert_eq!(h.height, 240);
1366
1367                assert!(!h.render_and_frame_size_different);
1368
1369                assert_eq!(h.render_width, 320);
1370                assert_eq!(h.render_height, 240);
1371
1372                assert!(!h.intra_only);
1373                assert_eq!(h.reset_frame_context, 0);
1374
1375                assert_eq!(h.refresh_frame_flags, 1);
1376                assert_eq!(h.ref_frame_idx, [0, 1, 2]);
1377                assert_eq!(h.ref_frame_sign_bias, [0, 0, 0, 1]);
1378
1379                assert!(!h.allow_high_precision_mv);
1380                assert!(matches!(
1381                    h.interpolation_filter,
1382                    InterpolationFilter::EightTap
1383                ));
1384
1385                assert!(h.refresh_frame_context);
1386                assert!(h.frame_parallel_decoding_mode);
1387                assert_eq!(h.frame_context_idx, 0);
1388
1389                let lf = &h.lf;
1390                assert_eq!(lf.level, 36);
1391                assert_eq!(lf.sharpness, 0);
1392
1393                assert!(lf.delta_enabled);
1394                assert!(!lf.delta_update);
1395
1396                assert_eq!(lf.update_ref_delta, [true, false, true, true]);
1397                assert_eq!(lf.ref_deltas, [1, 0, -1, -1]);
1398
1399                assert_eq!(lf.update_mode_delta, [false, false]);
1400
1401                let q = &h.quant;
1402
1403                assert_eq!(q.base_q_idx, 216);
1404                assert_eq!(q.delta_q_y_dc, 0);
1405                assert_eq!(q.delta_q_uv_dc, 0);
1406                assert_eq!(q.delta_q_uv_ac, 0);
1407
1408                let s = &h.seg;
1409
1410                assert!(!s.enabled);
1411                assert!(!s.update_map);
1412                assert_eq!(s.tree_probs, [0, 0, 0, 0, 0, 0, 0]);
1413                assert_eq!(s.pred_probs, [0, 0, 0]);
1414                assert!(!s.temporal_update);
1415                assert!(!s.update_data);
1416                assert!(!s.abs_or_delta_update);
1417                assert_eq!(s.feature_enabled, [[false; SEG_LVL_MAX]; MAX_SEGMENTS]);
1418                assert_eq!(s.feature_data, [[0; SEG_LVL_MAX]; MAX_SEGMENTS]);
1419
1420                assert_eq!(h.tile_cols_log2, 0);
1421                assert_eq!(h.tile_rows_log2, 0);
1422                assert_eq!(h.header_size_in_bytes, 9);
1423
1424                assert!(!h.lossless);
1425            }
1426        }
1427    }
1428}