cros_codecs/codec/vp8/
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 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/// Dequantization indices as parsed from the quant_indices() syntax.
25#[derive(Clone, Debug, Default, PartialEq, Eq)]
26pub struct QuantIndices {
27    /// The dequantization table index used for the luma AC coefficients (and
28    /// other coefficient groups if no delta value is present).
29    pub y_ac_qi: u8,
30    /// Indicates the delta value that is added to the baseline index to obtain
31    /// the luma DC coefficient dequantization index.
32    pub y_dc_delta: i8,
33    /// Indicates the delta value that is added to the baseline index to obtain
34    /// the Y2 block DC coefficient dequantization index.
35    pub y2_dc_delta: i8,
36    /// Indicates the delta value that is added to the baseline index to obtain
37    /// the Y2 block AC coefficient dequantization index.
38    pub y2_ac_delta: i8,
39    /// Indicates the delta value that is added to the baseline index to obtain
40    /// the chroma DC coefficient dequantization index.
41    pub uv_dc_delta: i8,
42    /// Indicates the delta value that is added to the baseline index to obtain
43    /// the chroma AC coefficient dequantization index.
44    pub uv_ac_delta: i8,
45}
46
47#[derive(Clone, Debug, Default, PartialEq, Eq)]
48pub struct MbLfAdjustments {
49    /// Indicates if the MB-level loop filter adjustment (based on the used
50    /// reference frame and coding mode) is on for the current frame.
51    pub loop_filter_adj_enable: bool,
52    /// Indicates if the delta values used in adjustment are updated in the
53    /// current frame.
54    pub mode_ref_lf_delta_update: bool,
55
56    //if mode_ref_lf_delta_update == 1
57    /// Indicates the adjustment delta value corresponding to a certain used
58    /// reference frame.
59    pub ref_frame_delta: [i8; 4],
60    /// Indicates the adjustment delta value corresponding to a certain MB
61    /// prediction mode
62    pub mb_mode_delta: [i8; 4],
63}
64
65#[derive(Clone, Debug, Default, PartialEq, Eq)]
66pub struct Segmentation {
67    /// Enables the segmentation feature for the current frame.
68    pub segmentation_enabled: bool,
69    /// Determines if the MB segmentation map is updated in the current frame.
70    pub update_mb_segmentation_map: bool,
71    /// indicates if the segment feature data is updated in the current frame.
72    pub update_segment_feature_data: bool,
73
74    // If update_segment_feature_data == 1
75    /// Indicates the feature data update mode, O for delta and 1 for the
76    /// absolute value.
77    pub segment_feature_mode: bool,
78    /// Indicates if the quantizer value is updated for the izh segment.
79    pub quantizer_update_value: [i8; 4],
80    /// Indicates the update value for the loop filter level.
81    pub lf_update_value: [i8; 4],
82
83    // if update_mb_segmentation_map == 1
84    /// The branch probabilities of the segment id decoding tree.
85    pub segment_prob: [u8; 3],
86}
87
88#[derive(Clone, Debug, Default, PartialEq, Eq)]
89pub struct ModeProbs {
90    /// Branch probabilities of the luma intra prediction mode decoding tree,
91    /// kept live between frames.
92    pub intra_16x16_prob: [u8; 4],
93    /// Branch probabilities of the chroma intra prediction mode decoding tree,
94    /// kept live between frames.
95    pub intra_chroma_prob: [u8; 3],
96}
97
98#[derive(Clone, Debug, Default, PartialEq, Eq)]
99pub struct Header {
100    /// Indicates if the current frame is a key frame or not.
101    pub key_frame: bool,
102    /// Determines the bitstream version.
103    pub version: u8,
104    /// Indicates if the current frame is meant to be displayed or not.
105    pub show_frame: bool,
106    /// The size in bytes of the Uncompressed Data Chunk
107    pub data_chunk_size: u8,
108    /// Determines the size of the first partition (control partition) excluding
109    /// the size of the Uncompressed Data Chunk
110    pub first_part_size: u32,
111
112    /// The frame's width, in pixels.
113    pub width: u16,
114    /// The frame's height, in pixels.
115    pub height: u16,
116    /// Horizontal scale code value.
117    pub horiz_scale_code: u8,
118    /// Vertical scale code value.
119    pub vert_scale_code: u8,
120    /// Defines the YUV color space of the sequence.
121    pub color_space: bool,
122    /// Specifies if the decoder is required to clamp the reconstructed pixel
123    /// values.
124    pub clamping_type: bool,
125    /// Determines whether the normal or the simple loop filter is used.
126    pub filter_type: bool,
127    /// Controls the deblocking filter.
128    pub loop_filter_level: u8,
129    /// Controls the deblocking filter.
130    pub sharpness_level: u8,
131    /// Determines the number of separate partitions containing the DCT
132    /// coefficients of the macroblocks.
133    log2_nbr_of_dct_partitions: u8,
134
135    pub partition_size: [u32; 8],
136
137    /// Dequantizer indices.
138    pub quant_indices: QuantIndices,
139
140    /// Determines whether updated token probabilities are used only for this
141    /// frame or until further update
142    pub refresh_entropy_probs: bool,
143    /// Determines if the current decoded frame refreshes the last frame
144    /// reference buffer
145    pub refresh_last: bool,
146
147    /// Determines if the current decoded frame refreshes the golden frame.
148    pub refresh_golden_frame: bool,
149    /// Determines if the current decoded frame refreshes the alternate
150    /// reference frame.
151    pub refresh_alternate_frame: bool,
152    /// Determines if the golden reference is replaced by another reference.
153    pub copy_buffer_to_golden: u8,
154    /// Determines if the alternate reference is replaced by another reference.
155    pub copy_buffer_to_alternate: u8,
156    /// Controls the sign of motion vectors when the golden frame is referenced.
157    pub sign_bias_golden: bool,
158    /// Controls the sign of motion vectors when the alternate frame is
159    /// referenced.
160    pub sign_bias_alternate: bool,
161
162    /// The new branch probability for the DCT/WHT tree.
163    pub coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
164    /// MV decoding probability.
165    pub mv_prob: [[u8; 19]; 2],
166
167    /// Enables or disables the skipping of macroblocks containing no non-zero
168    /// coefficients.
169    pub mb_no_coeff_skip: bool,
170    /// The probability that the macroblock is not skipped (flag indicating
171    /// skipped macroblock is false).
172    pub prob_skip_false: u8,
173    /// The probability of an intra macroblock.
174    pub prob_intra: u8,
175    /// The probability that the last reference frame is used for inter
176    /// prediction.
177    pub prob_last: u8,
178    /// The probability that the golden reference frame is used for inter
179    /// prediction.
180    pub prob_golden: u8,
181    /// Branch probabilities kept live across frames.
182    pub mode_probs: ModeProbs,
183
184    /// Boolean decoder `range` for this frame.
185    pub bd_range: usize,
186    /// Boolean decoder `value` for this frame.
187    pub bd_value: usize,
188    /// Boolean decoder `count` for this frame.
189    pub bd_count: isize,
190
191    /// The size in bits of the Frame Header, thus excluding any Uncompressed
192    /// Data Chunk bytes.
193    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    /// Returns the number of separate partitions containing the DCT coefficients of the
232    /// macroblocks.
233    pub fn num_dct_partitions(&self) -> usize {
234        1 << self.log2_nbr_of_dct_partitions
235    }
236
237    /// Returns the total size of the encoded frame in bytes, as computed from the header.
238    pub fn frame_len(&self) -> usize {
239        // Uncompressed chunk size.
240        std::iter::once(self.data_chunk_size as usize)
241            // Size of first partition.
242            .chain(std::iter::once(self.first_part_size as usize))
243            // Size of the partitions description area.
244            .chain(std::iter::once(self.num_dct_partitions().saturating_sub(1) * 3))
245            // Size of other DCT partitions.
246            .chain(self.partition_size.iter().take(self.num_dct_partitions()).map(|s| *s as usize))
247            .sum()
248    }
249
250    /// Create a new `Header` by parsing the uncompressed data chunk of a frame.
251    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
330/// A VP8 frame.
331pub struct Frame<'a> {
332    /// The bitstream data for this frame.
333    bitstream: &'a [u8],
334    /// The actual length of the frame data within `bitstream`.
335    frame_len: usize,
336    /// The parsed frame header.
337    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/// A VP8 parser based on GStreamer's vp8parser and Chromium's VP8 parser.
347#[derive(Clone, Debug, PartialEq, Eq)]
348pub struct Parser {
349    /// Segmentation data kept live across frames.
350    segmentation: Segmentation,
351    /// MbLfAdjustments data kept live across frames.
352    mb_lf_adjust: MbLfAdjustments,
353    /// Coeff probabilities data kept live across frames.
354    coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
355    /// Motion vector probabilities data kept live across frames.
356    mv_prob: [[u8; 19]; 2],
357    /// Branch probabilities kept live across frames.
358    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                    // quantizer_update_value defaults to zero if update flag is
450                    // zero (Section 9.3, 4.b)
451                    *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                    // lf_update_value defaults to zero if update flag is
461                    // zero (Section 9.3, 4.b)
462                    *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                        // segment_prob defaults to 255 if update flag is
473                        // zero (Section 9.3, 5)
474                        *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    /// Parse a single frame from the chunk in `data`.
704    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            // Reset on every key frame.
708            *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    // Test and test data extracted from GStreamer
751    // subprojects/gst-plugins-bad/tests/check/libs/vp8parser.c
752    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}