Skip to main content

webp_rust/decoder/
quant.rs

1use std::array::from_fn;
2
3use crate::decoder::vp8::Vp8BoolDecoder;
4use crate::decoder::vp8i::NUM_MB_SEGMENTS;
5use crate::decoder::DecoderError;
6
7use super::vp8::SegmentHeader;
8
9pub const DC_TABLE: [u8; 128] = [
10    4, 5, 6, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 17, 18, 19, 20, 20, 21, 21, 22, 22, 23,
11    23, 24, 25, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 37, 38, 39, 40, 41, 42, 43, 44,
12    45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
13    68, 69, 70, 71, 72, 73, 74, 75, 76, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 91,
14    93, 95, 96, 98, 100, 101, 102, 104, 106, 108, 110, 112, 114, 116, 118, 122, 124, 126, 128, 130,
15    132, 134, 136, 138, 140, 143, 145, 148, 151, 154, 157,
16];
17
18pub const AC_TABLE: [u16; 128] = [
19    4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
20    29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
21    53, 54, 55, 56, 57, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
22    96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 119, 122, 125, 128, 131, 134, 137, 140,
23    143, 146, 149, 152, 155, 158, 161, 164, 167, 170, 173, 177, 181, 185, 189, 193, 197, 201, 205,
24    209, 213, 217, 221, 225, 229, 234, 239, 245, 249, 254, 259, 264, 269, 274, 279, 284,
25];
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct QuantIndices {
29    pub base_q0: i32,
30    pub y1_dc_delta: i32,
31    pub y2_dc_delta: i32,
32    pub y2_ac_delta: i32,
33    pub uv_dc_delta: i32,
34    pub uv_ac_delta: i32,
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct QuantMatrix {
39    pub y1: [u16; 2],
40    pub y2: [u16; 2],
41    pub uv: [u16; 2],
42    pub uv_quant: i32,
43}
44
45impl Default for QuantMatrix {
46    fn default() -> Self {
47        Self {
48            y1: [0; 2],
49            y2: [0; 2],
50            uv: [0; 2],
51            uv_quant: 0,
52        }
53    }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct Quantization {
58    pub indices: QuantIndices,
59    pub matrices: [QuantMatrix; NUM_MB_SEGMENTS],
60}
61
62fn clip(v: i32, max: i32) -> usize {
63    v.clamp(0, max) as usize
64}
65
66pub fn parse_quantization(
67    br: &mut Vp8BoolDecoder<'_>,
68    segment_header: &SegmentHeader,
69) -> Result<Quantization, DecoderError> {
70    let indices = QuantIndices {
71        base_q0: br.get_value(7) as i32,
72        y1_dc_delta: if br.get() == 1 {
73            br.get_signed_value(4)
74        } else {
75            0
76        },
77        y2_dc_delta: if br.get() == 1 {
78            br.get_signed_value(4)
79        } else {
80            0
81        },
82        y2_ac_delta: if br.get() == 1 {
83            br.get_signed_value(4)
84        } else {
85            0
86        },
87        uv_dc_delta: if br.get() == 1 {
88            br.get_signed_value(4)
89        } else {
90            0
91        },
92        uv_ac_delta: if br.get() == 1 {
93            br.get_signed_value(4)
94        } else {
95            0
96        },
97    };
98
99    let matrices = from_fn(|segment| {
100        let q = if segment_header.use_segment {
101            let mut q = segment_header.quantizer[segment] as i32;
102            if !segment_header.absolute_delta {
103                q += indices.base_q0;
104            }
105            q
106        } else {
107            indices.base_q0
108        };
109
110        let mut matrix = QuantMatrix::default();
111        matrix.y1[0] = DC_TABLE[clip(q + indices.y1_dc_delta, 127)] as u16;
112        matrix.y1[1] = AC_TABLE[clip(q, 127)];
113
114        matrix.y2[0] = (DC_TABLE[clip(q + indices.y2_dc_delta, 127)] as u16) * 2;
115        matrix.y2[1] =
116            ((AC_TABLE[clip(q + indices.y2_ac_delta, 127)] as u32 * 101_581) >> 16).max(8) as u16;
117
118        matrix.uv[0] = DC_TABLE[clip(q + indices.uv_dc_delta, 117)] as u16;
119        matrix.uv[1] = AC_TABLE[clip(q + indices.uv_ac_delta, 127)];
120        matrix.uv_quant = q + indices.uv_ac_delta;
121        matrix
122    });
123
124    if br.eof() {
125        return Err(DecoderError::Bitstream("cannot parse quantization"));
126    }
127
128    Ok(Quantization { indices, matrices })
129}