Skip to main content

webp_rust/decoder/
vp8.rs

1use crate::decoder::quant::{parse_quantization, Quantization};
2use crate::decoder::tree::{
3    parse_intra_mode_row, parse_probability_tables, parse_probability_updates, MacroBlockHeader,
4    ProbabilityTables, ProbabilityUpdateSummary,
5};
6use crate::decoder::vp8i::{
7    B_DC_PRED, MAX_NUM_PARTITIONS, MB_FEATURE_TREE_PROBS, NUM_MB_SEGMENTS, NUM_MODE_LF_DELTAS,
8    NUM_REF_LF_DELTAS, VP8L_FRAME_HEADER_SIZE, VP8_FRAME_HEADER_SIZE,
9};
10use crate::decoder::DecoderError;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct Vp8FrameHeader {
14    pub key_frame: bool,
15    pub profile: u8,
16    pub show: bool,
17    pub partition_length: usize,
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct Vp8PictureHeader {
22    pub width: u16,
23    pub height: u16,
24    pub xscale: u8,
25    pub yscale: u8,
26    pub colorspace: u8,
27    pub clamp_type: u8,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
31pub struct SegmentHeader {
32    pub use_segment: bool,
33    pub update_map: bool,
34    pub absolute_delta: bool,
35    pub quantizer: [i8; NUM_MB_SEGMENTS],
36    pub filter_strength: [i8; NUM_MB_SEGMENTS],
37    pub segment_probs: [u8; MB_FEATURE_TREE_PROBS],
38}
39
40impl Default for SegmentHeader {
41    fn default() -> Self {
42        Self {
43            use_segment: false,
44            update_map: false,
45            absolute_delta: true,
46            quantizer: [0; NUM_MB_SEGMENTS],
47            filter_strength: [0; NUM_MB_SEGMENTS],
48            segment_probs: [255; MB_FEATURE_TREE_PROBS],
49        }
50    }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub enum FilterType {
55    Off,
56    Simple,
57    Complex,
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct FilterHeader {
62    pub simple: bool,
63    pub level: u8,
64    pub sharpness: u8,
65    pub use_lf_delta: bool,
66    pub ref_lf_delta: [i8; NUM_REF_LF_DELTAS],
67    pub mode_lf_delta: [i8; NUM_MODE_LF_DELTAS],
68    pub filter_type: FilterType,
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub struct LosslessInfo {
73    pub width: usize,
74    pub height: usize,
75    pub has_alpha: bool,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct LossyHeader {
80    pub frame: Vp8FrameHeader,
81    pub picture: Vp8PictureHeader,
82    pub macroblock_width: usize,
83    pub macroblock_height: usize,
84    pub segment: SegmentHeader,
85    pub filter: FilterHeader,
86    pub token_partition_sizes: Vec<usize>,
87    pub quantization: Quantization,
88    pub probabilities: ProbabilityUpdateSummary,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq)]
92pub struct MacroBlockHeaders {
93    pub frame: LossyHeader,
94    pub macroblocks: Vec<MacroBlockHeader>,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq)]
98pub struct MacroBlockData {
99    pub header: MacroBlockHeader,
100    pub coeffs: [i16; 384],
101    pub non_zero_y: u32,
102    pub non_zero_uv: u32,
103}
104
105#[derive(Debug, Clone, PartialEq, Eq)]
106pub struct MacroBlockDataFrame {
107    pub frame: LossyHeader,
108    pub macroblocks: Vec<MacroBlockData>,
109}
110
111#[derive(Debug, Clone, Copy, Default)]
112struct NonZeroContext {
113    nz: u8,
114    nz_dc: u8,
115}
116
117#[derive(Debug, Clone)]
118pub struct Vp8BoolDecoder<'a> {
119    data: &'a [u8],
120    position: usize,
121    value: u64,
122    range: u32,
123    bits: i32,
124    eof: bool,
125}
126
127impl<'a> Vp8BoolDecoder<'a> {
128    pub fn new(data: &'a [u8]) -> Self {
129        let mut reader = Self {
130            data,
131            position: 0,
132            value: 0,
133            range: 255 - 1,
134            bits: -8,
135            eof: false,
136        };
137        reader.load_new_bytes();
138        reader
139    }
140
141    pub fn eof(&self) -> bool {
142        self.eof
143    }
144
145    fn load_new_bytes(&mut self) {
146        while self.bits < 0 {
147            if self.position < self.data.len() {
148                self.bits += 8;
149                self.value = (self.value << 8) | self.data[self.position] as u64;
150                self.position += 1;
151            } else if !self.eof {
152                self.value <<= 8;
153                self.bits += 8;
154                self.eof = true;
155            } else {
156                self.bits = 0;
157            }
158        }
159    }
160
161    pub fn get(&mut self) -> u32 {
162        self.get_bit(0x80)
163    }
164
165    pub fn get_value(&mut self, num_bits: usize) -> u32 {
166        let mut value = 0u32;
167        for bit_index in (0..num_bits).rev() {
168            value |= self.get() << bit_index;
169        }
170        value
171    }
172
173    pub fn get_signed_value(&mut self, num_bits: usize) -> i32 {
174        let value = self.get_value(num_bits) as i32;
175        if self.get() == 1 {
176            -value
177        } else {
178            value
179        }
180    }
181
182    pub fn get_signed(&mut self, value: i32) -> i32 {
183        if self.get() == 1 {
184            -value
185        } else {
186            value
187        }
188    }
189
190    pub fn get_bit(&mut self, prob: u8) -> u32 {
191        if self.bits < 0 {
192            self.load_new_bytes();
193        }
194
195        let pos = self.bits as u32;
196        let mut range = self.range;
197        let split = (range * prob as u32) >> 8;
198        let value = (self.value >> pos) as u32;
199        let bit = (value > split) as u32;
200        if bit == 1 {
201            range -= split;
202            self.value -= ((split + 1) as u64) << pos;
203        } else {
204            range = split + 1;
205        }
206
207        let shift = 7 ^ (31 - range.leading_zeros()) as i32;
208        range <<= shift as u32;
209        self.bits -= shift;
210        self.range = range - 1;
211        bit
212    }
213}
214
215pub fn check_lossy_signature(data: &[u8]) -> bool {
216    data.len() >= 3 && data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a
217}
218
219pub fn get_info(data: &[u8], chunk_size: usize) -> Result<(usize, usize), DecoderError> {
220    if data.len() < VP8_FRAME_HEADER_SIZE {
221        return Err(DecoderError::NotEnoughData("VP8 frame header"));
222    }
223    if !check_lossy_signature(&data[3..]) {
224        return Err(DecoderError::Bitstream("bad VP8 signature"));
225    }
226
227    let bits = data[0] as u32 | ((data[1] as u32) << 8) | ((data[2] as u32) << 16);
228    let key_frame = (bits & 1) == 0;
229    let profile = ((bits >> 1) & 0x07) as u8;
230    let show = ((bits >> 4) & 1) == 1;
231    let partition_length = (bits >> 5) as usize;
232    let width = ((((data[7] as u16) << 8) | data[6] as u16) & 0x3fff) as usize;
233    let height = ((((data[9] as u16) << 8) | data[8] as u16) & 0x3fff) as usize;
234
235    if !key_frame {
236        return Err(DecoderError::Unsupported("interframes are not supported"));
237    }
238    if profile > 3 {
239        return Err(DecoderError::Bitstream("unknown VP8 profile"));
240    }
241    if !show {
242        return Err(DecoderError::Unsupported("invisible VP8 frame"));
243    }
244    if partition_length >= chunk_size {
245        return Err(DecoderError::Bitstream("bad VP8 partition length"));
246    }
247    if width == 0 || height == 0 {
248        return Err(DecoderError::Bitstream("invalid VP8 dimensions"));
249    }
250
251    Ok((width, height))
252}
253
254pub fn check_lossless_signature(data: &[u8]) -> bool {
255    data.len() >= VP8L_FRAME_HEADER_SIZE && data[0] == 0x2f && (data[4] >> 5) == 0
256}
257
258pub fn get_lossless_info(data: &[u8]) -> Result<LosslessInfo, DecoderError> {
259    if data.len() < VP8L_FRAME_HEADER_SIZE {
260        return Err(DecoderError::NotEnoughData("VP8L frame header"));
261    }
262    if !check_lossless_signature(data) {
263        return Err(DecoderError::Bitstream("bad VP8L signature"));
264    }
265
266    let bits = u32::from_le_bytes([data[1], data[2], data[3], data[4]]);
267    let width = ((bits & 0x3fff) + 1) as usize;
268    let height = (((bits >> 14) & 0x3fff) + 1) as usize;
269    let has_alpha = ((bits >> 28) & 1) == 1;
270    let version = (bits >> 29) & 0x07;
271
272    if version != 0 {
273        return Err(DecoderError::Bitstream("unsupported VP8L version"));
274    }
275
276    Ok(LosslessInfo {
277        width,
278        height,
279        has_alpha,
280    })
281}
282
283fn parse_segment_header(br: &mut Vp8BoolDecoder<'_>) -> Result<SegmentHeader, DecoderError> {
284    let mut header = SegmentHeader {
285        use_segment: br.get() == 1,
286        ..SegmentHeader::default()
287    };
288    if header.use_segment {
289        header.update_map = br.get() == 1;
290        if br.get() == 1 {
291            header.absolute_delta = br.get() == 1;
292            for value in &mut header.quantizer {
293                *value = if br.get() == 1 {
294                    br.get_signed_value(7) as i8
295                } else {
296                    0
297                };
298            }
299            for value in &mut header.filter_strength {
300                *value = if br.get() == 1 {
301                    br.get_signed_value(6) as i8
302                } else {
303                    0
304                };
305            }
306        }
307        if header.update_map {
308            for value in &mut header.segment_probs {
309                *value = if br.get() == 1 {
310                    br.get_value(8) as u8
311                } else {
312                    255
313                };
314            }
315        }
316    }
317
318    if br.eof() {
319        return Err(DecoderError::Bitstream("cannot parse segment header"));
320    }
321
322    Ok(header)
323}
324
325fn parse_filter_header(br: &mut Vp8BoolDecoder<'_>) -> Result<FilterHeader, DecoderError> {
326    let simple = br.get() == 1;
327    let level = br.get_value(6) as u8;
328    let sharpness = br.get_value(3) as u8;
329    let use_lf_delta = br.get() == 1;
330    let mut header = FilterHeader {
331        simple,
332        level,
333        sharpness,
334        use_lf_delta,
335        ref_lf_delta: [0; NUM_REF_LF_DELTAS],
336        mode_lf_delta: [0; NUM_MODE_LF_DELTAS],
337        filter_type: FilterType::Off,
338    };
339
340    if use_lf_delta && br.get() == 1 {
341        for value in &mut header.ref_lf_delta {
342            if br.get() == 1 {
343                *value = br.get_signed_value(6) as i8;
344            }
345        }
346        for value in &mut header.mode_lf_delta {
347            if br.get() == 1 {
348                *value = br.get_signed_value(6) as i8;
349            }
350        }
351    }
352
353    header.filter_type = if level == 0 {
354        FilterType::Off
355    } else if simple {
356        FilterType::Simple
357    } else {
358        FilterType::Complex
359    };
360
361    if br.eof() {
362        return Err(DecoderError::Bitstream("cannot parse filter header"));
363    }
364
365    Ok(header)
366}
367
368fn parse_token_partitions(
369    br: &mut Vp8BoolDecoder<'_>,
370    data: &[u8],
371) -> Result<Vec<usize>, DecoderError> {
372    let num_parts_minus_one = (1usize << br.get_value(2)) - 1;
373    if num_parts_minus_one >= MAX_NUM_PARTITIONS {
374        return Err(DecoderError::Bitstream("too many VP8 token partitions"));
375    }
376
377    let size_bytes = num_parts_minus_one * 3;
378    if data.len() < size_bytes {
379        return Err(DecoderError::NotEnoughData("VP8 token partition sizes"));
380    }
381
382    let mut partitions = Vec::with_capacity(num_parts_minus_one + 1);
383    let mut size_left = data.len() - size_bytes;
384    for chunk in data[..size_bytes].chunks_exact(3) {
385        let stored = chunk[0] as usize | ((chunk[1] as usize) << 8) | ((chunk[2] as usize) << 16);
386        let actual = stored.min(size_left);
387        partitions.push(actual);
388        size_left -= actual;
389    }
390    partitions.push(size_left);
391
392    if data.len() == size_bytes {
393        return Err(DecoderError::NotEnoughData("VP8 token partitions"));
394    }
395
396    Ok(partitions)
397}
398
399const CAT3: [u8; 4] = [173, 148, 140, 0];
400const CAT4: [u8; 5] = [176, 155, 140, 135, 0];
401const CAT5: [u8; 6] = [180, 157, 141, 134, 130, 0];
402const CAT6: [u8; 12] = [254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0];
403const ZIGZAG: [usize; 16] = [0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15];
404
405fn transform_wht(input: &[i16; 16]) -> [i16; 16] {
406    let mut tmp = [0i32; 16];
407    for i in 0..4 {
408        let a0 = input[i] as i32 + input[12 + i] as i32;
409        let a1 = input[4 + i] as i32 + input[8 + i] as i32;
410        let a2 = input[4 + i] as i32 - input[8 + i] as i32;
411        let a3 = input[i] as i32 - input[12 + i] as i32;
412        tmp[i] = a0 + a1;
413        tmp[8 + i] = a0 - a1;
414        tmp[4 + i] = a3 + a2;
415        tmp[12 + i] = a3 - a2;
416    }
417
418    let mut out = [0i16; 16];
419    for i in 0..4 {
420        let base = i * 4;
421        let dc = tmp[base] + 3;
422        let a0 = dc + tmp[base + 3];
423        let a1 = tmp[base + 1] + tmp[base + 2];
424        let a2 = tmp[base + 1] - tmp[base + 2];
425        let a3 = dc - tmp[base + 3];
426        out[base] = ((a0 + a1) >> 3) as i16;
427        out[base + 1] = ((a3 + a2) >> 3) as i16;
428        out[base + 2] = ((a0 - a1) >> 3) as i16;
429        out[base + 3] = ((a3 - a2) >> 3) as i16;
430    }
431    out
432}
433
434fn get_large_value(br: &mut Vp8BoolDecoder<'_>, p: &[u8; 11]) -> i32 {
435    if br.get_bit(p[3]) == 0 {
436        if br.get_bit(p[4]) == 0 {
437            2
438        } else {
439            3 + br.get_bit(p[5]) as i32
440        }
441    } else if br.get_bit(p[6]) == 0 {
442        if br.get_bit(p[7]) == 0 {
443            5 + br.get_bit(159) as i32
444        } else {
445            7 + 2 * br.get_bit(165) as i32 + br.get_bit(145) as i32
446        }
447    } else {
448        let (cat, table): (usize, &[u8]) = if br.get_bit(p[8]) == 0 {
449            if br.get_bit(p[9]) == 0 {
450                (0, &CAT3)
451            } else {
452                (1, &CAT4)
453            }
454        } else if br.get_bit(p[10]) == 0 {
455            (2, &CAT5)
456        } else {
457            (3, &CAT6)
458        };
459        let mut value = 0i32;
460        for &prob in table {
461            if prob == 0 {
462                break;
463            }
464            value = value + value + br.get_bit(prob) as i32;
465        }
466        value + 3 + (8 << cat) as i32
467    }
468}
469
470fn get_coeffs(
471    br: &mut Vp8BoolDecoder<'_>,
472    probabilities: &ProbabilityTables,
473    coeff_type: usize,
474    ctx: usize,
475    dq: [u16; 2],
476    start: usize,
477    out: &mut [i16],
478) -> usize {
479    let mut n = start;
480    let mut p = probabilities.coeff_probs(coeff_type, n, ctx);
481    while n < 16 {
482        if br.get_bit(p[0]) == 0 {
483            return n;
484        }
485        while br.get_bit(p[1]) == 0 {
486            n += 1;
487            if n == 16 {
488                return 16;
489            }
490            p = probabilities.coeff_probs(coeff_type, n, 0);
491        }
492
493        let next_ctx;
494        let value = if br.get_bit(p[2]) == 0 {
495            next_ctx = 1;
496            1
497        } else {
498            next_ctx = 2;
499            get_large_value(br, p)
500        };
501        let dequant = if n > 0 { dq[1] } else { dq[0] } as i32;
502        out[ZIGZAG[n]] = (br.get_signed(value) * dequant) as i16;
503        n += 1;
504        p = probabilities.coeff_probs(coeff_type, n, next_ctx);
505    }
506    16
507}
508
509fn nz_code_bits(nz_coeffs: u32, nz: usize, dc_nz: bool) -> u32 {
510    (nz_coeffs << 2)
511        | if nz > 3 {
512            3
513        } else if nz > 1 {
514            2
515        } else if dc_nz {
516            1
517        } else {
518            0
519        }
520}
521
522fn parse_residuals(
523    header: MacroBlockHeader,
524    top: &mut NonZeroContext,
525    left: &mut NonZeroContext,
526    token_br: &mut Vp8BoolDecoder<'_>,
527    quantization: &Quantization,
528    probabilities: &ProbabilityTables,
529) -> MacroBlockData {
530    let mut coeffs = [0i16; 384];
531    if header.skip {
532        top.nz = 0;
533        left.nz = 0;
534        if !header.is_i4x4 {
535            top.nz_dc = 0;
536            left.nz_dc = 0;
537        }
538        return MacroBlockData {
539            header,
540            coeffs,
541            non_zero_y: 0,
542            non_zero_uv: 0,
543        };
544    }
545
546    let q = &quantization.matrices[header.segment as usize];
547    let mut offset = 0usize;
548    let first;
549    let coeff_type;
550    if !header.is_i4x4 {
551        let mut dc = [0i16; 16];
552        let ctx = (top.nz_dc + left.nz_dc) as usize;
553        let nz = get_coeffs(token_br, probabilities, 1, ctx, q.y2, 0, &mut dc);
554        let has_dc = nz > 0;
555        top.nz_dc = has_dc as u8;
556        left.nz_dc = has_dc as u8;
557        if nz > 1 {
558            let transformed = transform_wht(&dc);
559            for (block, value) in transformed.into_iter().enumerate() {
560                coeffs[block * 16] = value;
561            }
562        } else {
563            let dc0 = ((dc[0] as i32 + 3) >> 3) as i16;
564            for block in 0..16 {
565                coeffs[block * 16] = dc0;
566            }
567        }
568        first = 1;
569        coeff_type = 0;
570    } else {
571        first = 0;
572        coeff_type = 3;
573    }
574
575    let mut non_zero_y = 0u32;
576    let mut tnz = top.nz & 0x0f;
577    let mut lnz = left.nz & 0x0f;
578    for _y in 0..4 {
579        let mut l = lnz & 1;
580        let mut nz_coeffs = 0u32;
581        for _x in 0..4 {
582            let ctx = (l + (tnz & 1)) as usize;
583            let nz = get_coeffs(
584                token_br,
585                probabilities,
586                coeff_type,
587                ctx,
588                q.y1,
589                first,
590                &mut coeffs[offset..offset + 16],
591            );
592            l = (nz > first) as u8;
593            tnz = (tnz >> 1) | (l << 7);
594            nz_coeffs = nz_code_bits(nz_coeffs, nz, coeffs[offset] != 0);
595            offset += 16;
596        }
597        tnz >>= 4;
598        lnz = (lnz >> 1) | (l << 7);
599        non_zero_y = (non_zero_y << 8) | nz_coeffs;
600    }
601
602    let mut out_t_nz = tnz;
603    let mut out_l_nz = lnz >> 4;
604    let mut non_zero_uv = 0u32;
605    for ch in [0usize, 2usize] {
606        let mut nz_coeffs = 0u32;
607        let mut tnz = top.nz >> (4 + ch);
608        let mut lnz = left.nz >> (4 + ch);
609        for _y in 0..2 {
610            let mut l = lnz & 1;
611            for _x in 0..2 {
612                let ctx = (l + (tnz & 1)) as usize;
613                let nz = get_coeffs(
614                    token_br,
615                    probabilities,
616                    2,
617                    ctx,
618                    q.uv,
619                    0,
620                    &mut coeffs[offset..offset + 16],
621                );
622                l = (nz > 0) as u8;
623                tnz = (tnz >> 1) | (l << 3);
624                nz_coeffs = nz_code_bits(nz_coeffs, nz, coeffs[offset] != 0);
625                offset += 16;
626            }
627            tnz >>= 2;
628            lnz = (lnz >> 1) | (l << 5);
629        }
630        non_zero_uv |= nz_coeffs << (4 * ch);
631        out_t_nz |= (tnz << 4) << ch;
632        out_l_nz |= (lnz & 0xf0) << ch;
633    }
634    top.nz = out_t_nz;
635    left.nz = out_l_nz;
636
637    MacroBlockData {
638        header,
639        coeffs,
640        non_zero_y,
641        non_zero_uv,
642    }
643}
644
645pub fn parse_lossy_headers(data: &[u8]) -> Result<LossyHeader, DecoderError> {
646    if data.len() < VP8_FRAME_HEADER_SIZE {
647        return Err(DecoderError::NotEnoughData("VP8 frame header"));
648    }
649
650    let frame_bits = data[0] as u32 | ((data[1] as u32) << 8) | ((data[2] as u32) << 16);
651    let frame = Vp8FrameHeader {
652        key_frame: (frame_bits & 1) == 0,
653        profile: ((frame_bits >> 1) & 0x07) as u8,
654        show: ((frame_bits >> 4) & 1) == 1,
655        partition_length: (frame_bits >> 5) as usize,
656    };
657    if !frame.key_frame {
658        return Err(DecoderError::Unsupported("interframes are not supported"));
659    }
660    if frame.profile > 3 {
661        return Err(DecoderError::Bitstream("unknown VP8 profile"));
662    }
663    if !frame.show {
664        return Err(DecoderError::Unsupported("invisible VP8 frame"));
665    }
666    if !check_lossy_signature(&data[3..]) {
667        return Err(DecoderError::Bitstream("bad VP8 signature"));
668    }
669
670    let picture = Vp8PictureHeader {
671        width: (((data[7] as u16) << 8) | data[6] as u16) & 0x3fff,
672        height: (((data[9] as u16) << 8) | data[8] as u16) & 0x3fff,
673        xscale: data[7] >> 6,
674        yscale: data[9] >> 6,
675        colorspace: 0,
676        clamp_type: 0,
677    };
678    if picture.width == 0 || picture.height == 0 {
679        return Err(DecoderError::Bitstream("invalid VP8 dimensions"));
680    }
681
682    let partition0_offset = VP8_FRAME_HEADER_SIZE;
683    let partition0_end = partition0_offset + frame.partition_length;
684    if partition0_end > data.len() {
685        return Err(DecoderError::NotEnoughData("VP8 partition 0"));
686    }
687
688    let mut br = Vp8BoolDecoder::new(&data[partition0_offset..partition0_end]);
689    let mut picture = picture;
690    picture.colorspace = br.get() as u8;
691    picture.clamp_type = br.get() as u8;
692
693    let segment = parse_segment_header(&mut br)?;
694    let filter = parse_filter_header(&mut br)?;
695    let token_partition_sizes = parse_token_partitions(&mut br, &data[partition0_end..])?;
696    let quantization = parse_quantization(&mut br, &segment)?;
697    let _ = br.get();
698    let probabilities = parse_probability_updates(&mut br)?;
699
700    Ok(LossyHeader {
701        frame,
702        picture,
703        macroblock_width: (picture.width as usize + 15) >> 4,
704        macroblock_height: (picture.height as usize + 15) >> 4,
705        segment,
706        filter,
707        token_partition_sizes,
708        quantization,
709        probabilities,
710    })
711}
712
713pub fn parse_macroblock_headers(data: &[u8]) -> Result<MacroBlockHeaders, DecoderError> {
714    let frame = parse_lossy_headers(data)?;
715
716    let partition0_offset = VP8_FRAME_HEADER_SIZE;
717    let partition0_end = partition0_offset + frame.frame.partition_length;
718    let mut br = Vp8BoolDecoder::new(&data[partition0_offset..partition0_end]);
719
720    let _ = br.get();
721    let _ = br.get();
722    let segment = parse_segment_header(&mut br)?;
723    let _ = parse_filter_header(&mut br)?;
724    let _ = parse_token_partitions(&mut br, &data[partition0_end..])?;
725    let _ = parse_quantization(&mut br, &segment)?;
726    let _ = br.get();
727    let probabilities = parse_probability_updates(&mut br)?;
728
729    let mut top_modes = vec![B_DC_PRED; frame.macroblock_width * 4];
730    let mut macroblocks = Vec::with_capacity(frame.macroblock_width * frame.macroblock_height);
731    for _mb_y in 0..frame.macroblock_height {
732        let mut left_modes = [B_DC_PRED; 4];
733        let row = parse_intra_mode_row(
734            &mut br,
735            frame.macroblock_width,
736            segment.update_map,
737            &segment.segment_probs,
738            probabilities.use_skip_probability,
739            probabilities.skip_probability.unwrap_or(0),
740            &mut top_modes,
741            &mut left_modes,
742        )?;
743        macroblocks.extend(row);
744    }
745
746    Ok(MacroBlockHeaders { frame, macroblocks })
747}
748
749pub fn parse_macroblock_data(data: &[u8]) -> Result<MacroBlockDataFrame, DecoderError> {
750    let frame = parse_lossy_headers(data)?;
751    let partition0_offset = VP8_FRAME_HEADER_SIZE;
752    let partition0_end = partition0_offset + frame.frame.partition_length;
753    let mut br = Vp8BoolDecoder::new(&data[partition0_offset..partition0_end]);
754
755    let _ = br.get();
756    let _ = br.get();
757    let segment = parse_segment_header(&mut br)?;
758    let _ = parse_filter_header(&mut br)?;
759    let token_partition_sizes = parse_token_partitions(&mut br, &data[partition0_end..])?;
760    let quantization = parse_quantization(&mut br, &segment)?;
761    let _ = br.get();
762    let probabilities = parse_probability_tables(&mut br)?;
763
764    let partition_size_bytes = (token_partition_sizes.len() - 1) * 3;
765    let mut token_offset = partition0_end + partition_size_bytes;
766    let mut token_readers = Vec::with_capacity(token_partition_sizes.len());
767    for size in &token_partition_sizes {
768        let end = token_offset + *size;
769        token_readers.push(Vp8BoolDecoder::new(&data[token_offset..end]));
770        token_offset = end;
771    }
772
773    let mut top_modes = vec![B_DC_PRED; frame.macroblock_width * 4];
774    let mut top_contexts = vec![NonZeroContext::default(); frame.macroblock_width];
775    let part_mask = token_readers.len() - 1;
776    let mut macroblocks = Vec::with_capacity(frame.macroblock_width * frame.macroblock_height);
777
778    for mb_y in 0..frame.macroblock_height {
779        let mut left_modes = [B_DC_PRED; 4];
780        let row = parse_intra_mode_row(
781            &mut br,
782            frame.macroblock_width,
783            segment.update_map,
784            &segment.segment_probs,
785            probabilities.summary.use_skip_probability,
786            probabilities.summary.skip_probability.unwrap_or(0),
787            &mut top_modes,
788            &mut left_modes,
789        )?;
790
791        let token_br = &mut token_readers[mb_y & part_mask];
792        let mut left_context = NonZeroContext::default();
793        for (mb_x, header) in row.into_iter().enumerate() {
794            let mb = parse_residuals(
795                header,
796                &mut top_contexts[mb_x],
797                &mut left_context,
798                token_br,
799                &quantization,
800                &probabilities,
801            );
802            macroblocks.push(mb);
803        }
804    }
805
806    Ok(MacroBlockDataFrame { frame, macroblocks })
807}