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::io::Cursor;
7
8use byteorder::ReadBytesExt;
9use byteorder::LE;
10use log::debug;
11use thiserror::Error;
12
13use crate::codec::vp8::bool_decoder::BoolDecoder;
14use crate::codec::vp8::bool_decoder::BoolDecoderError;
15use crate::codec::vp8::bool_decoder::BoolDecoderResult;
16use crate::codec::vp8::bool_decoder::BoolDecoderState;
17use crate::codec::vp8::probs::COEFF_DEFAULT_PROBS;
18use crate::codec::vp8::probs::COEFF_UPDATE_PROBS;
19use crate::codec::vp8::probs::KF_UV_MODE_PROBS;
20use crate::codec::vp8::probs::KF_Y_MODE_PROBS;
21use crate::codec::vp8::probs::MV_DEFAULT_PROBS;
22use crate::codec::vp8::probs::MV_UPDATE_PROBS;
23use crate::codec::vp8::probs::NK_UV_MODE_PROBS;
24use crate::codec::vp8::probs::NK_Y_MODE_PROBS;
25
26/// Dequantization indices as parsed from the quant_indices() syntax.
27#[derive(Clone, Debug, Default, PartialEq, Eq)]
28pub struct QuantIndices {
29    /// The dequantization table index used for the luma AC coefficients (and
30    /// other coefficient groups if no delta value is present).
31    pub y_ac_qi: u8,
32    /// Indicates the delta value that is added to the baseline index to obtain
33    /// the luma DC coefficient dequantization index.
34    pub y_dc_delta: i8,
35    /// Indicates the delta value that is added to the baseline index to obtain
36    /// the Y2 block DC coefficient dequantization index.
37    pub y2_dc_delta: i8,
38    /// Indicates the delta value that is added to the baseline index to obtain
39    /// the Y2 block AC coefficient dequantization index.
40    pub y2_ac_delta: i8,
41    /// Indicates the delta value that is added to the baseline index to obtain
42    /// the chroma DC coefficient dequantization index.
43    pub uv_dc_delta: i8,
44    /// Indicates the delta value that is added to the baseline index to obtain
45    /// the chroma AC coefficient dequantization index.
46    pub uv_ac_delta: i8,
47}
48
49#[derive(Clone, Debug, Default, PartialEq, Eq)]
50pub struct MbLfAdjustments {
51    /// Indicates if the MB-level loop filter adjustment (based on the used
52    /// reference frame and coding mode) is on for the current frame.
53    pub loop_filter_adj_enable: bool,
54    /// Indicates if the delta values used in adjustment are updated in the
55    /// current frame.
56    pub mode_ref_lf_delta_update: bool,
57
58    //if mode_ref_lf_delta_update == 1
59    /// Indicates the adjustment delta value corresponding to a certain used
60    /// reference frame.
61    pub ref_frame_delta: [i8; 4],
62    /// Indicates the adjustment delta value corresponding to a certain MB
63    /// prediction mode
64    pub mb_mode_delta: [i8; 4],
65}
66
67#[derive(Clone, Debug, Default, PartialEq, Eq)]
68pub struct Segmentation {
69    /// Enables the segmentation feature for the current frame.
70    pub segmentation_enabled: bool,
71    /// Determines if the MB segmentation map is updated in the current frame.
72    pub update_mb_segmentation_map: bool,
73    /// indicates if the segment feature data is updated in the current frame.
74    pub update_segment_feature_data: bool,
75
76    // If update_segment_feature_data == 1
77    /// Indicates the feature data update mode, O for delta and 1 for the
78    /// absolute value.
79    pub segment_feature_mode: bool,
80    /// Indicates if the quantizer value is updated for the izh segment.
81    pub quantizer_update_value: [i8; 4],
82    /// Indicates the update value for the loop filter level.
83    pub lf_update_value: [i8; 4],
84
85    // if update_mb_segmentation_map == 1
86    /// The branch probabilities of the segment id decoding tree.
87    pub segment_prob: [u8; 3],
88}
89
90#[derive(Clone, Debug, Default, PartialEq, Eq)]
91pub struct ModeProbs {
92    /// Branch probabilities of the luma intra prediction mode decoding tree,
93    /// kept live between frames.
94    pub intra_16x16_prob: [u8; 4],
95    /// Branch probabilities of the chroma intra prediction mode decoding tree,
96    /// kept live between frames.
97    pub intra_chroma_prob: [u8; 3],
98}
99
100#[derive(Clone, Debug, Default, PartialEq, Eq)]
101pub struct Header {
102    /// Indicates if the current frame is a key frame or not.
103    pub key_frame: bool,
104    /// Determines the bitstream version.
105    pub version: u8,
106    /// Indicates if the current frame is meant to be displayed or not.
107    pub show_frame: bool,
108    /// The size in bytes of the Uncompressed Data Chunk
109    pub data_chunk_size: u8,
110    /// Determines the size of the first partition (control partition) excluding
111    /// the size of the Uncompressed Data Chunk
112    pub first_part_size: u32,
113
114    /// The frame's width, in pixels.
115    pub width: u16,
116    /// The frame's height, in pixels.
117    pub height: u16,
118    /// Horizontal scale code value.
119    pub horiz_scale_code: u8,
120    /// Vertical scale code value.
121    pub vert_scale_code: u8,
122    /// Defines the YUV color space of the sequence.
123    pub color_space: bool,
124    /// Specifies if the decoder is required to clamp the reconstructed pixel
125    /// values.
126    pub clamping_type: bool,
127    /// Determines whether the normal or the simple loop filter is used.
128    pub filter_type: bool,
129    /// Controls the deblocking filter.
130    pub loop_filter_level: u8,
131    /// Controls the deblocking filter.
132    pub sharpness_level: u8,
133    /// Determines the number of separate partitions containing the DCT
134    /// coefficients of the macroblocks.
135    log2_nbr_of_dct_partitions: u8,
136
137    pub partition_size: [u32; 8],
138
139    /// Dequantizer indices.
140    pub quant_indices: QuantIndices,
141
142    /// Determines whether updated token probabilities are used only for this
143    /// frame or until further update
144    pub refresh_entropy_probs: bool,
145    /// Determines if the current decoded frame refreshes the last frame
146    /// reference buffer
147    pub refresh_last: bool,
148
149    /// Determines if the current decoded frame refreshes the golden frame.
150    pub refresh_golden_frame: bool,
151    /// Determines if the current decoded frame refreshes the alternate
152    /// reference frame.
153    pub refresh_alternate_frame: bool,
154    /// Determines if the golden reference is replaced by another reference.
155    pub copy_buffer_to_golden: u8,
156    /// Determines if the alternate reference is replaced by another reference.
157    pub copy_buffer_to_alternate: u8,
158    /// Controls the sign of motion vectors when the golden frame is referenced.
159    pub sign_bias_golden: bool,
160    /// Controls the sign of motion vectors when the alternate frame is
161    /// referenced.
162    pub sign_bias_alternate: bool,
163
164    /// The new branch probability for the DCT/WHT tree.
165    pub coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
166    /// MV decoding probability.
167    pub mv_prob: [[u8; 19]; 2],
168
169    /// Enables or disables the skipping of macroblocks containing no non-zero
170    /// coefficients.
171    pub mb_no_coeff_skip: bool,
172    /// The probability that the macroblock is not skipped (flag indicating
173    /// skipped macroblock is false).
174    pub prob_skip_false: u8,
175    /// The probability of an intra macroblock.
176    pub prob_intra: u8,
177    /// The probability that the last reference frame is used for inter
178    /// prediction.
179    pub prob_last: u8,
180    /// The probability that the golden reference frame is used for inter
181    /// prediction.
182    pub prob_golden: u8,
183    /// Branch probabilities kept live across frames.
184    pub mode_probs: ModeProbs,
185
186    /// Boolean decoder `range` for this frame.
187    pub bd_range: usize,
188    /// Boolean decoder `value` for this frame.
189    pub bd_value: usize,
190    /// Boolean decoder `count` for this frame.
191    pub bd_count: isize,
192
193    /// The size in bits of the Frame Header, thus excluding any Uncompressed
194    /// Data Chunk bytes.
195    pub header_size: u32,
196}
197
198#[derive(Debug, Error)]
199pub enum ParseUncompressedChunkError {
200    #[error("invalid start code {0}")]
201    InvalidStartCode(u32),
202    #[error("I/O error: {0}")]
203    IoError(#[from] std::io::Error),
204}
205
206#[derive(Debug, Error)]
207pub enum ComputePartitionSizesError {
208    #[error("unexpected end of header")]
209    EndOfHeader,
210    #[error("partition size not fitting in a u32")]
211    PartitionTooLarge,
212}
213
214impl Header {
215    /// Returns the number of separate partitions containing the DCT coefficients of the
216    /// macroblocks.
217    pub fn num_dct_partitions(&self) -> usize {
218        1 << self.log2_nbr_of_dct_partitions
219    }
220
221    /// Returns the total size of the encoded frame in bytes, as computed from the header.
222    pub fn frame_len(&self) -> usize {
223        // Uncompressed chunk size.
224        std::iter::once(self.data_chunk_size as usize)
225            // Size of first partition.
226            .chain(std::iter::once(self.first_part_size as usize))
227            // Size of the partitions description area.
228            .chain(std::iter::once(
229                self.num_dct_partitions().saturating_sub(1) * 3,
230            ))
231            // Size of other DCT partitions.
232            .chain(
233                self.partition_size
234                    .iter()
235                    .take(self.num_dct_partitions())
236                    .map(|s| *s as usize),
237            )
238            .sum()
239    }
240
241    /// Create a new `Header` by parsing the uncompressed data chunk of a frame.
242    fn parse_uncompressed_data_chunk(
243        bitstream: &[u8],
244    ) -> Result<Self, ParseUncompressedChunkError> {
245        debug!("Parsing VP8 uncompressed data chunk.");
246
247        let mut reader = Cursor::new(bitstream);
248
249        let frame_tag = reader.read_u24::<LE>()?;
250
251        let mut header = Header {
252            key_frame: (frame_tag & 0x1) == 0,
253            version: ((frame_tag >> 1) & 0x07) as u8,
254            show_frame: ((frame_tag >> 4) & 0x1) != 0,
255            first_part_size: (frame_tag >> 5) & 0x7ffff,
256            ..Default::default()
257        };
258
259        if header.key_frame {
260            let start_code = reader.read_u24::<LE>()?;
261
262            if start_code != 0x2a019d {
263                return Err(ParseUncompressedChunkError::InvalidStartCode(start_code));
264            }
265
266            let size_code = reader.read_u16::<LE>()?;
267            header.horiz_scale_code = (size_code >> 14) as u8;
268            header.width = size_code & 0x3fff;
269
270            let size_code = reader.read_u16::<LE>()?;
271            header.vert_scale_code = (size_code >> 14) as u8;
272            header.height = size_code & 0x3fff;
273        }
274
275        header.data_chunk_size = reader.position() as u8;
276
277        Ok(header)
278    }
279
280    fn compute_partition_sizes(&mut self, data: &[u8]) -> Result<(), ComputePartitionSizesError> {
281        let num_partitions = self.num_dct_partitions();
282        let mut part_size_ofs = self.first_part_size as usize;
283        let mut ofs = part_size_ofs + 3 * (num_partitions - 1);
284
285        if ofs > data.len() {
286            return Err(ComputePartitionSizesError::EndOfHeader);
287        }
288
289        for i in 0..num_partitions - 1 {
290            let b0 = u32::from(data[part_size_ofs]);
291            let b1 = u32::from(data[part_size_ofs + 1]) << 8;
292            let b2 = u32::from(data[part_size_ofs + 2]) << 16;
293
294            let part_size = b0 | b1 | b2;
295            part_size_ofs += 3;
296
297            self.partition_size[i] = part_size;
298            ofs += part_size as usize;
299        }
300
301        if ofs > data.len() {
302            return Err(ComputePartitionSizesError::EndOfHeader);
303        }
304
305        self.partition_size[num_partitions - 1] = u32::try_from(data.len() - ofs)
306            .map_err(|_| ComputePartitionSizesError::PartitionTooLarge)?;
307        Ok(())
308    }
309}
310
311/// A VP8 frame.
312pub struct Frame<'a> {
313    /// The bitstream data for this frame.
314    bitstream: &'a [u8],
315    /// The actual length of the frame data within `bitstream`.
316    frame_len: usize,
317    /// The parsed frame header.
318    pub header: Header,
319}
320
321impl<'a> AsRef<[u8]> for Frame<'a> {
322    fn as_ref(&self) -> &[u8] {
323        &self.bitstream[..self.frame_len]
324    }
325}
326
327/// A VP8 parser based on GStreamer's vp8parser and Chromium's VP8 parser.
328#[derive(Clone, Debug, PartialEq, Eq)]
329pub struct Parser {
330    /// Segmentation data kept live across frames.
331    segmentation: Segmentation,
332    /// MbLfAdjustments data kept live across frames.
333    mb_lf_adjust: MbLfAdjustments,
334    /// Coeff probabilities data kept live across frames.
335    coeff_prob: [[[[u8; 11]; 3]; 8]; 4],
336    /// Motion vector probabilities data kept live across frames.
337    mv_prob: [[u8; 19]; 2],
338    /// Branch probabilities kept live across frames.
339    mode_probs: ModeProbs,
340}
341
342#[derive(Debug, Error)]
343pub enum ParseFrameError {
344    #[error("error while parsing uncompressed chunk of frame: {0}")]
345    ParseUncompressedChunk(#[from] ParseUncompressedChunkError),
346    #[error("partition end {0} is bigger than bitstream length {1}")]
347    InvalidPartitionSize(usize, usize),
348    #[error("error while parsing frame header: {0}")]
349    ParseFrameHeader(#[from] BoolDecoderError),
350    #[error("error while computing frames partitions sizes: {0}")]
351    ComputePartitionSizes(#[from] ComputePartitionSizesError),
352    #[error("bitstream is shorter ({0} bytes) than computed length of frame {1}")]
353    BitstreamTooShort(usize, usize),
354}
355
356impl Parser {
357    pub fn segmentation(&self) -> &Segmentation {
358        &self.segmentation
359    }
360
361    pub fn mb_lf_adjust(&self) -> &MbLfAdjustments {
362        &self.mb_lf_adjust
363    }
364
365    fn mode_probs_init_defaults(mode_probs: &mut ModeProbs, key_frame: bool) {
366        if key_frame {
367            mode_probs.intra_16x16_prob = KF_Y_MODE_PROBS;
368            mode_probs.intra_chroma_prob = KF_UV_MODE_PROBS;
369        } else {
370            mode_probs.intra_16x16_prob = NK_Y_MODE_PROBS;
371            mode_probs.intra_chroma_prob = NK_UV_MODE_PROBS;
372        }
373    }
374
375    fn update_segmentation<T: AsRef<[u8]>>(
376        bd: &mut BoolDecoder<T>,
377        seg: &mut Segmentation,
378    ) -> BoolDecoderResult<()> {
379        seg.update_mb_segmentation_map = false;
380        seg.update_segment_feature_data = false;
381
382        seg.segmentation_enabled = bd.read_bool()?;
383        if !seg.segmentation_enabled {
384            return Ok(());
385        }
386
387        seg.update_mb_segmentation_map = bd.read_bool()?;
388        seg.update_segment_feature_data = bd.read_bool()?;
389
390        if seg.update_segment_feature_data {
391            seg.segment_feature_mode = bd.read_bool()?;
392
393            for value in seg.quantizer_update_value.iter_mut() {
394                let update = bd.read_bool()?;
395                if update {
396                    *value = bd.read_sint(7)?;
397                } else {
398                    // quantizer_update_value defaults to zero if update flag is
399                    // zero (Section 9.3, 4.b)
400                    *value = 0;
401                }
402            }
403
404            for value in seg.lf_update_value.iter_mut() {
405                let update = bd.read_bool()?;
406                if update {
407                    *value = bd.read_sint(6)?;
408                } else {
409                    // lf_update_value defaults to zero if update flag is
410                    // zero (Section 9.3, 4.b)
411                    *value = 0;
412                }
413            }
414
415            if seg.update_mb_segmentation_map {
416                for value in seg.segment_prob.iter_mut() {
417                    let update = bd.read_bool()?;
418                    if update {
419                        *value = bd.read_uint(8)?;
420                    } else {
421                        // segment_prob defaults to 255 if update flag is
422                        // zero (Section 9.3, 5)
423                        *value = 255;
424                    }
425                }
426            }
427        }
428
429        Ok(())
430    }
431
432    fn parse_mb_lf_adjustments<T: AsRef<[u8]>>(
433        bd: &mut BoolDecoder<T>,
434        adj: &mut MbLfAdjustments,
435    ) -> BoolDecoderResult<()> {
436        adj.mode_ref_lf_delta_update = false;
437
438        adj.loop_filter_adj_enable = bd.read_bool()?;
439        if !adj.loop_filter_adj_enable {
440            return Ok(());
441        }
442
443        adj.mode_ref_lf_delta_update = bd.read_bool()?;
444        if !adj.mode_ref_lf_delta_update {
445            return Ok(());
446        }
447
448        for value in adj.ref_frame_delta.iter_mut() {
449            let update = bd.read_bool()?;
450            if update {
451                *value = bd.read_sint(6)?;
452            }
453        }
454
455        for value in adj.mb_mode_delta.iter_mut() {
456            let update = bd.read_bool()?;
457            if update {
458                *value = bd.read_sint(6)?;
459            }
460        }
461
462        Ok(())
463    }
464
465    fn parse_quant_indices<T: AsRef<[u8]>>(
466        bd: &mut BoolDecoder<T>,
467        q: &mut QuantIndices,
468    ) -> BoolDecoderResult<()> {
469        q.y_ac_qi = bd.read_uint(7)?;
470
471        let y_dc_delta_present = bd.read_bool()?;
472
473        if y_dc_delta_present {
474            q.y_dc_delta = bd.read_sint(4)?;
475        } else {
476            q.y_dc_delta = 0;
477        }
478
479        let y2_dc_delta_present = bd.read_bool()?;
480        if y2_dc_delta_present {
481            q.y2_dc_delta = bd.read_sint(4)?;
482        } else {
483            q.y2_dc_delta = 0;
484        }
485
486        let y2_ac_delta_present = bd.read_bool()?;
487        if y2_ac_delta_present {
488            q.y2_ac_delta = bd.read_sint(4)?;
489        } else {
490            q.y2_ac_delta = 0;
491        }
492
493        let uv_dc_delta_present = bd.read_bool()?;
494        if uv_dc_delta_present {
495            q.uv_dc_delta = bd.read_sint(4)?;
496        } else {
497            q.uv_dc_delta = 0;
498        }
499
500        let uv_ac_delta_present = bd.read_bool()?;
501        if uv_ac_delta_present {
502            q.uv_ac_delta = bd.read_sint(4)?;
503        } else {
504            q.uv_ac_delta = 0;
505        }
506
507        Ok(())
508    }
509
510    fn parse_token_prob_update<T: AsRef<[u8]>>(
511        bd: &mut BoolDecoder<T>,
512        coeff_probs: &mut [[[[u8; 11]; 3]; 8]; 4],
513    ) -> BoolDecoderResult<()> {
514        for (i, vi) in coeff_probs.iter_mut().enumerate() {
515            for (j, vj) in vi.iter_mut().enumerate() {
516                for (k, vk) in vj.iter_mut().enumerate() {
517                    for (l, prob) in vk.iter_mut().enumerate() {
518                        let update = bd.read_bool_with_prob(COEFF_UPDATE_PROBS[i][j][k][l])?;
519                        if update {
520                            *prob = bd.read_uint(8)?;
521                        }
522                    }
523                }
524            }
525        }
526
527        Ok(())
528    }
529
530    fn parse_mv_prob_update<T: AsRef<[u8]>>(
531        bd: &mut BoolDecoder<T>,
532        mv_probs: &mut [[u8; 19]; 2],
533    ) -> BoolDecoderResult<()> {
534        for (i, vi) in mv_probs.iter_mut().enumerate() {
535            for (j, prob) in vi.iter_mut().enumerate() {
536                let update = bd.read_bool_with_prob(MV_UPDATE_PROBS[i][j])?;
537                if update {
538                    let mv_prob_update = bd.read_uint::<u8>(7)?;
539
540                    if mv_prob_update > 0 {
541                        *prob = mv_prob_update << 1;
542                    } else {
543                        *prob = 1;
544                    }
545                }
546            }
547        }
548
549        Ok(())
550    }
551
552    fn parse_frame_header(&mut self, data: &[u8], frame: &mut Header) -> BoolDecoderResult<()> {
553        debug!("Parsing VP8 frame header.");
554        let mut bd = BoolDecoder::new(data);
555
556        if frame.key_frame {
557            frame.color_space = bd.read_bool()?;
558            frame.clamping_type = bd.read_bool()?;
559        }
560
561        Parser::update_segmentation(&mut bd, &mut self.segmentation)?;
562
563        frame.filter_type = bd.read_bool()?;
564        frame.loop_filter_level = bd.read_uint(6)?;
565        frame.sharpness_level = bd.read_uint(3)?;
566
567        Parser::parse_mb_lf_adjustments(&mut bd, &mut self.mb_lf_adjust)?;
568
569        frame.log2_nbr_of_dct_partitions = bd.read_uint(2)?;
570
571        Parser::parse_quant_indices(&mut bd, &mut frame.quant_indices)?;
572
573        frame.copy_buffer_to_golden = 0;
574        frame.copy_buffer_to_alternate = 0;
575
576        if frame.key_frame {
577            frame.refresh_entropy_probs = bd.read_bool()?;
578
579            frame.refresh_last = true;
580            frame.refresh_golden_frame = true;
581            frame.refresh_alternate_frame = true;
582
583            Parser::mode_probs_init_defaults(&mut frame.mode_probs, true);
584        } else {
585            frame.refresh_golden_frame = bd.read_bool()?;
586            frame.refresh_alternate_frame = bd.read_bool()?;
587
588            if !frame.refresh_golden_frame {
589                frame.copy_buffer_to_golden = bd.read_uint(2)?;
590            }
591
592            if !frame.refresh_alternate_frame {
593                frame.copy_buffer_to_alternate = bd.read_uint(2)?;
594            }
595
596            frame.sign_bias_golden = bd.read_bool()?;
597            frame.sign_bias_alternate = bd.read_bool()?;
598            frame.refresh_entropy_probs = bd.read_bool()?;
599            frame.refresh_last = bd.read_bool()?;
600
601            frame.mode_probs = self.mode_probs.clone();
602        }
603
604        frame.coeff_prob = self.coeff_prob;
605        frame.mv_prob = self.mv_prob;
606
607        Parser::parse_token_prob_update(&mut bd, &mut frame.coeff_prob)?;
608
609        frame.mb_no_coeff_skip = bd.read_bool()?;
610        if frame.mb_no_coeff_skip {
611            frame.prob_skip_false = bd.read_uint(8)?;
612        }
613
614        if !frame.key_frame {
615            frame.prob_intra = bd.read_uint(8)?;
616            frame.prob_last = bd.read_uint(8)?;
617            frame.prob_golden = bd.read_uint(8)?;
618
619            let intra_16x16_prob_update_flag = bd.read_bool()?;
620            if intra_16x16_prob_update_flag {
621                for prob in frame.mode_probs.intra_16x16_prob.iter_mut() {
622                    *prob = bd.read_uint(8)?;
623                }
624            }
625
626            let intra_chroma_prob_update_flag = bd.read_bool()?;
627            if intra_chroma_prob_update_flag {
628                for prob in frame.mode_probs.intra_chroma_prob.iter_mut() {
629                    *prob = bd.read_uint(8)?;
630                }
631            }
632
633            Parser::parse_mv_prob_update(&mut bd, &mut frame.mv_prob)?;
634        }
635
636        if frame.refresh_entropy_probs {
637            self.coeff_prob = frame.coeff_prob;
638            self.mv_prob = frame.mv_prob;
639
640            if !frame.key_frame {
641                self.mode_probs = frame.mode_probs.clone();
642            }
643        }
644
645        frame.header_size = bd.pos() as u32;
646
647        let state: BoolDecoderState = bd.into();
648        frame.bd_range = state.range;
649        frame.bd_value = state.value;
650        frame.bd_count = state.count;
651
652        Ok(())
653    }
654
655    /// Parse a single frame from the chunk in `data`.
656    pub fn parse_frame<'a>(&mut self, bitstream: &'a [u8]) -> Result<Frame<'a>, ParseFrameError> {
657        let mut header = Header::parse_uncompressed_data_chunk(bitstream)?;
658        if header.key_frame {
659            // Reset on every key frame.
660            *self = Default::default();
661        }
662
663        let first_part_end = header.data_chunk_size as usize + header.first_part_size as usize;
664
665        if first_part_end > bitstream.len() {
666            return Err(ParseFrameError::InvalidPartitionSize(
667                first_part_end,
668                bitstream.len(),
669            ));
670        }
671
672        let compressed_area = &bitstream[header.data_chunk_size as usize..];
673
674        self.parse_frame_header(compressed_area, &mut header)?;
675        header.compute_partition_sizes(compressed_area)?;
676
677        let frame_len = header.frame_len();
678        if frame_len > bitstream.as_ref().len() {
679            return Err(ParseFrameError::BitstreamTooShort(
680                bitstream.as_ref().len(),
681                frame_len,
682            ));
683        }
684
685        Ok(Frame {
686            bitstream,
687            frame_len,
688            header,
689        })
690    }
691}
692
693impl Default for Parser {
694    fn default() -> Self {
695        Self {
696            segmentation: Default::default(),
697            mb_lf_adjust: Default::default(),
698            coeff_prob: COEFF_DEFAULT_PROBS,
699            mv_prob: MV_DEFAULT_PROBS,
700            mode_probs: ModeProbs {
701                intra_16x16_prob: NK_Y_MODE_PROBS,
702                intra_chroma_prob: NK_UV_MODE_PROBS,
703            },
704        }
705    }
706}
707
708#[cfg(test)]
709mod tests {
710    use super::Parser;
711
712    // Test and test data extracted from GStreamer
713    // subprojects/gst-plugins-bad/tests/check/libs/vp8parser.c
714    const VP8_TEST_0_INTRA: &[u8] = include_bytes!("test_data/vp8-parser-test-0-intra.bin");
715    const VP8_TEST_0_INTER: &[u8] = include_bytes!("test_data/vp8-parser-test-0-inter.bin");
716
717    #[test]
718    fn gst_intra() {
719        let mut parser = Parser::default();
720        let frame = parser
721            .parse_frame(VP8_TEST_0_INTRA)
722            .expect("Parsing a intra frame failed");
723
724        assert!(frame.header.key_frame);
725
726        assert_eq!(frame.header.first_part_size, 234);
727        assert_eq!(frame.header.width, 176);
728        assert_eq!(frame.header.height, 144);
729
730        assert!(parser.mb_lf_adjust.loop_filter_adj_enable);
731        assert!(parser.mb_lf_adjust.mode_ref_lf_delta_update);
732
733        assert_eq!(parser.mb_lf_adjust.ref_frame_delta[0], 2);
734        assert_eq!(parser.mb_lf_adjust.ref_frame_delta[1], 0);
735        assert_eq!(parser.mb_lf_adjust.ref_frame_delta[2], -2);
736        assert_eq!(parser.mb_lf_adjust.ref_frame_delta[3], -2);
737
738        assert_eq!(parser.mb_lf_adjust.mb_mode_delta[0], 4);
739        assert_eq!(parser.mb_lf_adjust.mb_mode_delta[1], -2);
740        assert_eq!(parser.mb_lf_adjust.mb_mode_delta[2], 2);
741        assert_eq!(parser.mb_lf_adjust.mb_mode_delta[3], 4);
742
743        assert_eq!(frame.header.quant_indices.y_ac_qi, 4);
744        assert!(frame.header.mb_no_coeff_skip);
745
746        assert_eq!(frame.header.bd_range, 0xe8);
747        assert_eq!(frame.header.bd_value, 0x68);
748        assert_eq!(frame.header.bd_count, 1);
749    }
750
751    #[test]
752    fn gst_inter() {
753        let mut parser = Parser::default();
754        let frame = parser
755            .parse_frame(VP8_TEST_0_INTER)
756            .expect("Parsing a inter frame failed");
757
758        assert!(!frame.header.key_frame);
759
760        assert_eq!(frame.header.first_part_size, 98);
761        assert!(parser.mb_lf_adjust.loop_filter_adj_enable);
762        assert_eq!(frame.header.quant_indices.y_ac_qi, 4);
763
764        assert!(frame.header.refresh_entropy_probs);
765        assert!(frame.header.refresh_last);
766        assert!(frame.header.mb_no_coeff_skip);
767
768        assert_eq!(frame.header.prob_skip_false, 131);
769        assert_eq!(frame.header.prob_intra, 224);
770        assert_eq!(frame.header.prob_last, 233);
771        assert_eq!(frame.header.prob_golden, 1);
772
773        assert_eq!(frame.header.bd_range, 0x8e);
774        assert_eq!(frame.header.bd_value, 0x85);
775        assert_eq!(frame.header.bd_count, 5);
776    }
777}