Skip to main content

pito_codecs/vp9/
tables.rs

1pub use crate::vp9::spec_tables::*;
2
3pub const BLOCK_8X8: u8 = 3;
4pub const BLOCK_16X16: u8 = 6;
5pub const BLOCK_64X64: u8 = 12;
6pub const BLOCK_INVALID: u8 = 14;
7
8pub const TX_4X4: u8 = 0;
9pub const TX_8X8: u8 = 1;
10pub const TX_16X16: u8 = 2;
11pub const TX_32X32: u8 = 3;
12pub const TX_MODE_SELECT: u8 = 4;
13
14pub const DC_PRED: u8 = 0;
15pub const V_PRED: u8 = 1;
16pub const H_PRED: u8 = 2;
17pub const D45_PRED: u8 = 3;
18pub const D135_PRED: u8 = 4;
19pub const D117_PRED: u8 = 5;
20pub const D153_PRED: u8 = 6;
21pub const D207_PRED: u8 = 7;
22pub const D63_PRED: u8 = 8;
23pub const TM_PRED: u8 = 9;
24pub const NEARESTMV: u8 = 10;
25pub const NEARMV: u8 = 11;
26pub const ZEROMV: u8 = 12;
27pub const NEWMV: u8 = 13;
28
29pub const NONE: i8 = -1;
30pub const INTRA_FRAME: i8 = 0;
31pub const LAST_FRAME: i8 = 1;
32pub const GOLDEN_FRAME: i8 = 2;
33pub const ALTREF_FRAME: i8 = 3;
34
35pub const DCT_DCT: u8 = 0;
36pub const ADST_DCT: u8 = 1;
37pub const DCT_ADST: u8 = 2;
38pub const ADST_ADST: u8 = 3;
39
40pub const SWITCHABLE: u8 = 4;
41
42pub const SEG_LVL_ALT_Q: usize = 0;
43pub const SEG_LVL_ALT_L: usize = 1;
44pub const SEG_LVL_REF_FRAME: usize = 2;
45pub const SEG_LVL_SKIP: usize = 3;
46pub const MAX_SEGMENTS: usize = 8;
47
48pub const MAX_LOOP_FILTER: i32 = 63;
49pub const MIN_TILE_WIDTH_B64: u32 = 4;
50pub const MAX_TILE_WIDTH_B64: u32 = 64;
51pub const COMPANDED_MVREF_THRESH: i32 = 8;
52pub const MV_BORDER: i32 = 128;
53pub const INTERP_EXTEND: i32 = 4;
54pub const BORDERINPIXELS: i32 = 160;
55pub const COUNT_SAT: u32 = 20;
56pub const MAX_UPDATE_FACTOR: u32 = 128;
57
58pub const B_WIDTH_LOG2: [u8; 13] = [0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4];
59pub const B_HEIGHT_LOG2: [u8; 13] = [0, 1, 0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4];
60pub const NUM_4X4_WIDE: [u8; 13] = [1, 1, 2, 2, 2, 4, 4, 4, 8, 8, 8, 16, 16];
61pub const NUM_4X4_HIGH: [u8; 13] = [1, 2, 1, 2, 4, 2, 4, 8, 4, 8, 16, 8, 16];
62pub const MI_WIDTH_LOG2: [u8; 13] = [0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3];
63pub const NUM_8X8_WIDE: [u8; 13] = [1, 1, 1, 1, 1, 2, 2, 2, 4, 4, 4, 8, 8];
64pub const NUM_8X8_HIGH: [u8; 13] = [1, 1, 1, 1, 2, 1, 2, 4, 2, 4, 8, 4, 8];
65pub const SIZE_GROUP: [u8; 13] = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3];
66pub const MAX_TXSIZE: [u8; 13] = [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3];
67pub const TX_MODE_TO_BIGGEST_TX_SIZE: [u8; 5] = [0, 1, 2, 3, 3];
68
69pub const SUBSIZE_LOOKUP: [[u8; 13]; 4] = [
70    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
71    [14, 14, 14, 2, 14, 14, 5, 14, 14, 8, 14, 14, 11],
72    [14, 14, 14, 1, 14, 14, 4, 14, 14, 7, 14, 14, 10],
73    [14, 14, 14, 0, 14, 14, 3, 14, 14, 6, 14, 14, 9],
74];
75
76pub const SS_SIZE_LOOKUP: [[[u8; 2]; 2]; 13] = [
77    [[0, 14], [14, 14]],
78    [[1, 0], [14, 14]],
79    [[2, 14], [0, 14]],
80    [[3, 2], [1, 0]],
81    [[4, 3], [14, 1]],
82    [[5, 14], [3, 2]],
83    [[6, 5], [4, 3]],
84    [[7, 6], [14, 4]],
85    [[8, 14], [6, 5]],
86    [[9, 8], [7, 6]],
87    [[10, 9], [14, 7]],
88    [[11, 14], [9, 8]],
89    [[12, 11], [10, 9]],
90];
91
92pub const MODE2TXFM: [u8; 14] = [
93    DCT_DCT, ADST_DCT, DCT_ADST, DCT_DCT, ADST_ADST, ADST_DCT, DCT_ADST, DCT_ADST, ADST_DCT,
94    ADST_ADST, DCT_DCT, DCT_DCT, DCT_DCT, DCT_DCT,
95];
96
97pub const COUNTER_TO_CONTEXT: [u8; 19] = [2, 3, 4, 1, 3, 9, 0, 9, 9, 5, 5, 9, 5, 9, 9, 9, 9, 9, 6];
98
99pub const IDX_N_COLUMN_TO_SUBBLOCK: [[u8; 2]; 4] = [[1, 2], [1, 3], [3, 2], [3, 3]];
100
101pub const LITERAL_TO_TYPE: [u8; 4] = [1, 0, 2, 3];
102
103pub const SEGMENTATION_FEATURE_BITS: [u32; 4] = [8, 6, 2, 0];
104pub const SEGMENTATION_FEATURE_SIGNED: [bool; 4] = [true, true, false, false];
105
106pub const EXTRA_BITS: [(u8, u8, u16); 11] = [
107    (0, 0, 0),
108    (0, 0, 1),
109    (0, 0, 2),
110    (0, 0, 3),
111    (0, 0, 4),
112    (1, 1, 5),
113    (2, 2, 7),
114    (3, 3, 11),
115    (4, 4, 19),
116    (5, 5, 35),
117    (6, 14, 67),
118];
119
120pub const CAT_PROBS: [&[u8]; 7] = [
121    &[],
122    &[159],
123    &[165, 145],
124    &[173, 148, 140],
125    &[176, 155, 140, 135],
126    &[180, 157, 141, 134, 130],
127    &[
128        254, 254, 254, 252, 249, 243, 230, 196, 177, 153, 140, 133, 130, 129,
129    ],
130];
131
132pub const PARTITION_TREE: [i8; 6] = [0, 2, -1, 4, -2, -3];
133pub const INTRA_MODE_TREE: [i8; 18] = [
134    -(DC_PRED as i8),
135    2,
136    -(TM_PRED as i8),
137    4,
138    -(V_PRED as i8),
139    6,
140    8,
141    12,
142    -(H_PRED as i8),
143    10,
144    -(D135_PRED as i8),
145    -(D117_PRED as i8),
146    -(D45_PRED as i8),
147    14,
148    -(D63_PRED as i8),
149    16,
150    -(D153_PRED as i8),
151    -(D207_PRED as i8),
152];
153pub const SEGMENT_TREE: [i8; 14] = [2, 4, 6, 8, 10, 12, 0, -1, -2, -3, -4, -5, -6, -7];
154pub const TX_SIZE_32_TREE: [i8; 6] = [0, 2, -1, 4, -2, -3];
155pub const TX_SIZE_16_TREE: [i8; 4] = [0, 2, -1, -2];
156pub const TX_SIZE_8_TREE: [i8; 2] = [0, -1];
157pub const INTER_MODE_TREE: [i8; 6] = [-2, 2, 0, 4, -1, -3];
158pub const INTERP_FILTER_TREE: [i8; 4] = [0, 2, -1, -2];
159pub const MV_JOINT_TREE: [i8; 6] = [0, 2, -1, 4, -2, -3];
160pub const MV_CLASS_TREE: [i8; 20] = [
161    0, 2, -1, 4, 6, 8, -2, -3, 10, 12, -4, -5, -6, 14, 16, 18, -7, -8, -9, -10,
162];
163pub const MV_FR_TREE: [i8; 6] = [0, 2, -1, 4, -2, -3];
164pub const SMALL_TOKEN_TREE: [i8; 6] = [0, 0, 0, 4, -1, -2];
165pub const BINARY_TREE: [i8; 2] = [0, -1];
166
167pub fn pareto_full() -> &'static [[u8; 8]; 255] {
168    use std::sync::OnceLock;
169    static T: OnceLock<[[u8; 8]; 255]> = OnceLock::new();
170    T.get_or_init(|| {
171        let mut t = [[0u8; 8]; 255];
172        for p in 1..=255usize {
173            let x = (p - 1) / 2;
174            for n in 0..8 {
175                t[p - 1][n] = if p & 1 == 1 {
176                    PARETO_TABLE[x * 8 + n]
177                } else {
178                    ((PARETO_TABLE[x * 8 + n] as u32 + PARETO_TABLE[(x + 1) * 8 + n] as u32) >> 1)
179                        as u8
180                };
181            }
182        }
183        t
184    })
185}
186
187pub fn scan(tx_size: u8, tx_type: u8) -> &'static [u16] {
188    match (tx_size, tx_type) {
189        (0, ADST_DCT) => &ROW_SCAN_4X4,
190        (0, DCT_ADST) => &COL_SCAN_4X4,
191        (0, _) => &DEFAULT_SCAN_4X4,
192        (1, ADST_DCT) => &ROW_SCAN_8X8,
193        (1, DCT_ADST) => &COL_SCAN_8X8,
194        (1, _) => &DEFAULT_SCAN_8X8,
195        (2, ADST_DCT) => &ROW_SCAN_16X16,
196        (2, DCT_ADST) => &COL_SCAN_16X16,
197        (2, _) => &DEFAULT_SCAN_16X16,
198        _ => &DEFAULT_SCAN_32X32,
199    }
200}
201
202pub fn neighbors(tx_size: u8, tx_type: u8) -> &'static [(u16, u16)] {
203    use std::sync::OnceLock;
204    static T: OnceLock<Vec<Vec<(u16, u16)>>> = OnceLock::new();
205    let all = T.get_or_init(|| {
206        let mut v = Vec::new();
207        for tx in 0..4u8 {
208            for ty in 0..4u8 {
209                let sc = scan(tx, ty);
210                let n = 4usize << tx;
211                let mut nb = vec![(0u16, 0u16); sc.len()];
212                for (c, &pos) in sc.iter().enumerate().skip(1) {
213                    let pos = pos as usize;
214                    let (i, j) = (pos / n, pos % n);
215                    nb[c] = if i > 0 && j > 0 {
216                        let a = ((i - 1) * n + j) as u16;
217                        let a2 = (i * n + j - 1) as u16;
218                        let ty = if tx == 3 { DCT_DCT } else { ty };
219                        match ty {
220                            DCT_ADST => (a, a),
221                            ADST_DCT => (a2, a2),
222                            _ => (a, a2),
223                        }
224                    } else if i > 0 {
225                        let a = ((i - 1) * n + j) as u16;
226                        (a, a)
227                    } else {
228                        let a = (i * n + j - 1) as u16;
229                        (a, a)
230                    };
231                }
232                v.push(nb);
233            }
234        }
235        v
236    });
237    &all[(tx_size * 4 + tx_type) as usize]
238}
239
240#[cfg(test)]
241mod tests {
242    use super::*;
243
244    #[test]
245    fn trees_are_consistent() {
246        fn leaves(t: &[i8]) -> Vec<i8> {
247            let mut v: Vec<i8> = t
248                .iter()
249                .enumerate()
250                .filter(|(i, x)| **x <= 0 && !(*i == 0 && t.len() > 2 && t[0] == 0 && t[1] == 0))
251                .map(|(_, x)| -x)
252                .collect();
253            v.sort();
254            v
255        }
256        assert_eq!(leaves(&INTRA_MODE_TREE), (0..10).collect::<Vec<i8>>());
257        assert_eq!(leaves(&MV_CLASS_TREE), (0..11).collect::<Vec<i8>>());
258        assert_eq!(leaves(&PARTITION_TREE), (0..4).collect::<Vec<i8>>());
259        assert_eq!(leaves(&INTER_MODE_TREE), (0..4).collect::<Vec<i8>>());
260    }
261
262    #[test]
263    fn pareto_rows() {
264        let p = pareto_full();
265        assert_eq!(p[0], [3, 86, 128, 6, 86, 23, 88, 29]);
266        assert_eq!(p[254][..], PARETO_TABLE[127 * 8..128 * 8]);
267    }
268
269    #[test]
270    fn default_coef_probs_unused_are_zero() {
271        for (k, chunk) in DEFAULT_COEF_PROBS.chunks(3 * 6).enumerate() {
272            let band = k % 6;
273            for (ctx, p) in chunk.chunks(3).enumerate() {
274                if band == 0 && ctx >= 3 {
275                    assert_eq!(p, [0, 0, 0]);
276                } else {
277                    assert!(p.iter().all(|&x| x > 0), "band {band} ctx {ctx}");
278                }
279            }
280        }
281    }
282}