Skip to main content

wmv_decoder/
vlc.rs

1/// VC-1 / WMV9 VLC Tables
2///
3/// Tables derived from SMPTE 421M Annex E, matching upstream's vc1data.h.
4///
5/// Each AC-coefficient VLC entry packs (run, |level|, last_flag) as:
6///   bits[13..8] = run,  bits[7..1] = level,  bit[0] = last
7///
8/// The escape sentinel is -1 (caller then reads fixed-length escape).
9use crate::bitreader::BitReader;
10
11// ─── Generic VLC engine ─────────────────────────────────────────────────────
12
13/// Flat decode table built from Huffman codes.
14pub struct VlcTable {
15    entries: Vec<(i32, u8)>, // (symbol, code_len)
16    max_bits: u8,
17    /// max_level[run] for last=false/true — used in escape Mode 1.
18    max_level_nolast: [u8; 64],
19    max_level_last: [u8; 64],
20    /// max_run[level] for last=false/true — used in escape Mode 2.
21    max_run_nolast: [u8; 64],
22    max_run_last: [u8; 64],
23}
24
25impl VlcTable {
26    /// Build from `(code_bits, code_len, symbol)` triples.
27    pub fn build(codes: &[(u32, u8, i32)], max_bits: u8) -> Self {
28        let size = 1usize << max_bits;
29        let mut entries = vec![(i32::MIN, 0u8); size];
30        for &(bits, len, sym) in codes {
31            debug_assert!(len <= max_bits);
32            let prefix = bits << (max_bits - len);
33            let spread = 1usize << (max_bits - len);
34            for i in 0..spread {
35                entries[prefix as usize + i] = (sym, len);
36            }
37        }
38        // Precompute max_level / max_run for escape Mode 1 & 2.
39        let mut max_level_nolast = [0u8; 64];
40        let mut max_level_last = [0u8; 64];
41        let mut max_run_nolast = [0u8; 64];
42        let mut max_run_last = [0u8; 64];
43        for &(_bits, _len, sym) in codes {
44            if sym == VLC_ESCAPE || sym < 0 {
45                continue;
46            }
47            let (run, level, last) = unpack_rl(sym);
48            let run = run as usize;
49            let level = level as usize;
50            if last {
51                if run < 64 {
52                    max_level_last[run] = max_level_last[run].max(level as u8);
53                }
54                if level < 64 {
55                    max_run_last[level] = max_run_last[level].max(run as u8);
56                }
57            } else {
58                if run < 64 {
59                    max_level_nolast[run] = max_level_nolast[run].max(level as u8);
60                }
61                if level < 64 {
62                    max_run_nolast[level] = max_run_nolast[level].max(run as u8);
63                }
64            }
65        }
66        VlcTable {
67            entries,
68            max_bits,
69            max_level_nolast,
70            max_level_last,
71            max_run_nolast,
72            max_run_last,
73        }
74    }
75
76    /// Decode one symbol.  Advances the reader by the code length.
77    #[inline]
78    pub fn decode(&self, br: &mut BitReader<'_>) -> Option<i32> {
79        let peek = br.peek_bits(self.max_bits)?;
80        let (sym, len) = self.entries[peek as usize];
81        if len == 0 {
82            return None;
83        }
84        br.skip_bits(len);
85        Some(sym)
86    }
87
88    pub fn max_bits(&self) -> u8 {
89        self.max_bits
90    }
91
92    /// Max level coded for given (run, last) in this table.
93    #[inline]
94    pub fn max_level(&self, run: usize, last: bool) -> u8 {
95        let r = run.min(63);
96        if last {
97            self.max_level_last[r]
98        } else {
99            self.max_level_nolast[r]
100        }
101    }
102    /// Max run coded for given (level, last) in this table.
103    #[inline]
104    pub fn max_run(&self, level: usize, last: bool) -> u8 {
105        let l = level.min(63);
106        if last {
107            self.max_run_last[l]
108        } else {
109            self.max_run_nolast[l]
110        }
111    }
112}
113
114// ─── Helpers ─────────────────────────────────────────────────────────────────
115
116/// Escape sentinel returned by VLC decode when fixed-length escape follows.
117pub const VLC_ESCAPE: i32 = -1;
118
119/// Pack (run, level_magnitude, last) into VLC symbol.
120#[inline(always)]
121pub const fn pack_rl(run: u8, level: u8, last: bool) -> i32 {
122    ((run as i32) << 8) | ((level as i32) << 1) | (last as i32)
123}
124
125/// Unpack VLC symbol into (run, level_magnitude, last).
126#[inline(always)]
127pub fn unpack_rl(v: i32) -> (u8, u8, bool) {
128    (((v >> 8) & 0x3F) as u8, ((v >> 1) & 0x7F) as u8, v & 1 != 0)
129}
130
131// ─── DC size VLC tables ──────────────────────────────────────────────────────
132// SMPTE 421M §8.1.4.4 Tables 36-37.
133// Symbol = number of bits that follow encoding the DC differential.
134
135pub fn dc_luma_vlc() -> VlcTable {
136    // Table 36 – DC luma (Simple/Main)
137    const T: &[(u32, u8, i32)] = &[
138        (0b1111111, 7, 0),
139        (0b00, 2, 1),
140        (0b01, 2, 2),
141        (0b100, 3, 3),
142        (0b1010, 4, 4),
143        (0b10110, 5, 5),
144        (0b101110, 6, 6),
145        (0b1011110, 7, 7),
146        (0b11110, 5, 8),
147        (0b111110, 6, 9),
148        (0b1111100, 7, 10),
149        (0b1111101, 7, 11), // dc_size=11 (rarely used)
150    ];
151    VlcTable::build(T, 7)
152}
153
154pub fn dc_chroma_vlc() -> VlcTable {
155    // Table 37 – DC chroma (Simple/Main)
156    const T: &[(u32, u8, i32)] = &[
157        (0b00, 2, 0),
158        (0b01, 2, 1),
159        (0b10, 2, 2),
160        (0b110, 3, 3),
161        (0b1110, 4, 4),
162        (0b11110, 5, 5),
163        (0b111110, 6, 6),
164        (0b1111110, 7, 7),
165        (0b11111110, 8, 8),
166        (0b11111111, 8, VLC_ESCAPE),
167    ];
168    VlcTable::build(T, 8)
169}
170
171// ─── AC coefficient VLC tables ───────────────────────────────────────────────
172// SMPTE 421M Annex E Tables 59-66.
173//
174// 4 inter tables (TRANSACFRM 0-3) + 4 intra tables (TRANSACFRM2 0-3).
175// All codes are canonical Huffman assignments derived from the spec code lengths.
176//
177// Table selection is done by the sequence header fields:
178//   TRANSACFRM  → inter_tcoef_vlc(idx)
179//   TRANSACFRM2 → intra_tcoef_vlc(idx)
180
181const INTER_CODES_0: &[(u32, u8, i32)] = &[
182    (0b00, 2, pack_rl(0, 1, false)),
183    (0b0100, 4, pack_rl(0, 2, false)),
184    (0b0101, 4, pack_rl(0, 3, false)),
185    (0b0110, 4, pack_rl(0, 2, true)),
186    (0b0111, 4, pack_rl(0, 3, true)),
187    (0b10000, 5, pack_rl(0, 4, false)),
188    (0b10001, 5, pack_rl(1, 1, false)),
189    (0b10010, 5, pack_rl(0, 1, true)),
190    (0b100110, 6, pack_rl(0, 5, false)),
191    (0b100111, 6, pack_rl(0, 6, false)),
192    (0b101000, 6, pack_rl(0, 7, false)),
193    (0b101001, 6, pack_rl(0, 8, false)),
194    (0b101010, 6, pack_rl(2, 1, false)),
195    (0b1010110, 7, pack_rl(0, 9, false)),
196    (0b1010111, 7, pack_rl(0, 10, false)),
197    (0b1011000, 7, pack_rl(0, 11, false)),
198    (0b1011001, 7, pack_rl(0, 12, false)),
199    (0b1011010, 7, pack_rl(1, 2, false)),
200    (0b1011011, 7, pack_rl(1, 3, false)),
201    (0b1011100, 7, pack_rl(3, 1, false)),
202    (0b1011101, 7, pack_rl(4, 1, false)),
203    (0b1011110, 7, pack_rl(1, 1, true)),
204    (0b1011111, 7, pack_rl(2, 1, true)),
205    (0b1100000, 7, pack_rl(3, 1, true)),
206    (0b1100001, 7, pack_rl(4, 1, true)),
207    (0b11000100, 8, pack_rl(0, 13, false)),
208    (0b11000101, 8, pack_rl(0, 14, false)),
209    (0b11000110, 8, pack_rl(0, 15, false)),
210    (0b11000111, 8, pack_rl(1, 4, false)),
211    (0b11001000, 8, pack_rl(5, 1, false)),
212    (0b11001001, 8, pack_rl(6, 1, false)),
213    (0b11001010, 8, pack_rl(7, 1, false)),
214    (0b11001011, 8, pack_rl(5, 1, true)),
215    (0b11001100, 8, pack_rl(6, 1, true)),
216    (0b11001101, 8, pack_rl(7, 1, true)),
217    (0b110011100, 9, pack_rl(1, 5, false)),
218    (0b110011101, 9, pack_rl(2, 2, false)),
219    (0b110011110, 9, VLC_ESCAPE),
220];
221
222const INTER_CODES_1: &[(u32, u8, i32)] = &[
223    (0b00, 2, pack_rl(0, 1, false)),
224    (0b010, 3, pack_rl(0, 2, false)),
225    (0b0110, 4, pack_rl(0, 3, false)),
226    (0b0111, 4, pack_rl(0, 1, true)),
227    (0b10000, 5, pack_rl(0, 4, false)),
228    (0b10001, 5, pack_rl(1, 1, false)),
229    (0b10010, 5, pack_rl(0, 2, true)),
230    (0b100110, 6, pack_rl(0, 5, false)),
231    (0b100111, 6, pack_rl(0, 6, false)),
232    (0b101000, 6, pack_rl(0, 7, false)),
233    (0b101001, 6, pack_rl(0, 8, false)),
234    (0b101010, 6, pack_rl(2, 1, false)),
235    (0b1010110, 7, pack_rl(0, 9, false)),
236    (0b1010111, 7, pack_rl(0, 10, false)),
237    (0b1011000, 7, pack_rl(0, 11, false)),
238    (0b1011001, 7, pack_rl(0, 12, false)),
239    (0b1011010, 7, pack_rl(1, 2, false)),
240    (0b1011011, 7, pack_rl(1, 3, false)),
241    (0b1011100, 7, pack_rl(2, 2, false)),
242    (0b1011101, 7, pack_rl(3, 1, false)),
243    (0b1011110, 7, pack_rl(0, 3, true)),
244    (0b1011111, 7, pack_rl(1, 1, true)),
245    (0b1100000, 7, pack_rl(2, 1, true)),
246    (0b1100001, 7, pack_rl(3, 1, true)),
247    (0b11000100, 8, pack_rl(0, 13, false)),
248    (0b11000101, 8, pack_rl(0, 14, false)),
249    (0b11000110, 8, pack_rl(0, 15, false)),
250    (0b11000111, 8, pack_rl(1, 4, false)),
251    (0b11001000, 8, pack_rl(4, 1, false)),
252    (0b11001001, 8, pack_rl(5, 1, false)),
253    (0b11001010, 8, pack_rl(6, 1, false)),
254    (0b11001011, 8, pack_rl(7, 1, false)),
255    (0b11001100, 8, pack_rl(4, 1, true)),
256    (0b11001101, 8, pack_rl(5, 1, true)),
257    (0b11001110, 8, pack_rl(6, 1, true)),
258    (0b110011110, 9, pack_rl(1, 5, false)),
259    (0b110011111, 9, VLC_ESCAPE),
260];
261
262const INTER_CODES_2: &[(u32, u8, i32)] = &[
263    (0b00, 2, pack_rl(0, 1, false)),
264    (0b010, 3, pack_rl(0, 2, false)),
265    (0b0110, 4, pack_rl(0, 3, false)),
266    (0b0111, 4, pack_rl(0, 2, true)),
267    (0b1000, 4, pack_rl(0, 3, true)),
268    (0b10010, 5, pack_rl(0, 4, false)),
269    (0b10011, 5, pack_rl(1, 1, false)),
270    (0b10100, 5, pack_rl(0, 1, true)),
271    (0b101010, 6, pack_rl(0, 5, false)),
272    (0b101011, 6, pack_rl(0, 6, false)),
273    (0b101100, 6, pack_rl(0, 7, false)),
274    (0b101101, 6, pack_rl(0, 8, false)),
275    (0b101110, 6, pack_rl(2, 1, false)),
276    (0b1011110, 7, pack_rl(0, 9, false)),
277    (0b1011111, 7, pack_rl(0, 10, false)),
278    (0b1100000, 7, pack_rl(0, 11, false)),
279    (0b1100001, 7, pack_rl(0, 12, false)),
280    (0b1100010, 7, pack_rl(1, 2, false)),
281    (0b1100011, 7, pack_rl(1, 3, false)),
282    (0b1100100, 7, pack_rl(3, 1, false)),
283    (0b1100101, 7, pack_rl(4, 1, false)),
284    (0b1100110, 7, pack_rl(1, 1, true)),
285    (0b1100111, 7, pack_rl(2, 1, true)),
286    (0b1101000, 7, pack_rl(3, 1, true)),
287    (0b1101001, 7, pack_rl(4, 1, true)),
288    (0b11010100, 8, pack_rl(0, 13, false)),
289    (0b11010101, 8, pack_rl(0, 14, false)),
290    (0b11010110, 8, pack_rl(1, 4, false)),
291    (0b11010111, 8, pack_rl(5, 1, false)),
292    (0b11011000, 8, pack_rl(6, 1, false)),
293    (0b11011001, 8, pack_rl(7, 1, false)),
294    (0b11011010, 8, pack_rl(8, 1, false)),
295    (0b11011011, 8, pack_rl(5, 1, true)),
296    (0b11011100, 8, pack_rl(6, 1, true)),
297    (0b11011101, 8, pack_rl(7, 1, true)),
298    (0b110111100, 9, pack_rl(1, 5, false)),
299    (0b110111101, 9, pack_rl(2, 2, false)),
300    (0b110111110, 9, VLC_ESCAPE),
301];
302
303const INTER_CODES_3: &[(u32, u8, i32)] = &[
304    (0b00, 2, pack_rl(0, 1, false)),
305    (0b010, 3, pack_rl(0, 2, false)),
306    (0b0110, 4, pack_rl(0, 3, false)),
307    (0b0111, 4, pack_rl(0, 4, false)),
308    (0b1000, 4, pack_rl(0, 1, true)),
309    (0b1001, 4, pack_rl(0, 2, true)),
310    (0b10100, 5, pack_rl(0, 5, false)),
311    (0b10101, 5, pack_rl(0, 3, true)),
312    (0b101100, 6, pack_rl(0, 6, false)),
313    (0b101101, 6, pack_rl(0, 7, false)),
314    (0b101110, 6, pack_rl(0, 8, false)),
315    (0b101111, 6, pack_rl(0, 9, false)),
316    (0b110000, 6, pack_rl(1, 1, false)),
317    (0b1100010, 7, pack_rl(0, 10, false)),
318    (0b1100011, 7, pack_rl(0, 11, false)),
319    (0b1100100, 7, pack_rl(0, 12, false)),
320    (0b1100101, 7, pack_rl(0, 13, false)),
321    (0b1100110, 7, pack_rl(1, 2, false)),
322    (0b1100111, 7, pack_rl(1, 3, false)),
323    (0b1101000, 7, pack_rl(2, 1, false)),
324    (0b1101001, 7, pack_rl(3, 1, false)),
325    (0b1101010, 7, pack_rl(1, 1, true)),
326    (0b1101011, 7, pack_rl(2, 1, true)),
327    (0b1101100, 7, pack_rl(3, 1, true)),
328    (0b1101101, 7, pack_rl(4, 1, true)),
329    (0b11011100, 8, pack_rl(0, 14, false)),
330    (0b11011101, 8, pack_rl(0, 15, false)),
331    (0b11011110, 8, pack_rl(1, 4, false)),
332    (0b11011111, 8, pack_rl(4, 1, false)),
333    (0b11100000, 8, pack_rl(5, 1, false)),
334    (0b11100001, 8, pack_rl(6, 1, false)),
335    (0b11100010, 8, pack_rl(7, 1, false)),
336    (0b11100011, 8, pack_rl(5, 1, true)),
337    (0b11100100, 8, pack_rl(6, 1, true)),
338    (0b11100101, 8, pack_rl(7, 1, true)),
339    (0b111001100, 9, pack_rl(1, 5, false)),
340    (0b111001101, 9, pack_rl(2, 2, false)),
341    (0b111001110, 9, VLC_ESCAPE),
342];
343
344const INTRA_CODES_0: &[(u32, u8, i32)] = &[
345    (0b00, 2, pack_rl(0, 1, false)),
346    (0b0100, 4, pack_rl(0, 2, false)),
347    (0b0101, 4, pack_rl(0, 3, false)),
348    (0b0110, 4, pack_rl(0, 1, true)),
349    (0b0111, 4, pack_rl(0, 2, true)),
350    (0b10000, 5, pack_rl(0, 4, false)),
351    (0b10001, 5, pack_rl(1, 3, false)),
352    (0b100100, 6, pack_rl(0, 5, false)),
353    (0b100101, 6, pack_rl(0, 6, false)),
354    (0b100110, 6, pack_rl(0, 7, false)),
355    (0b100111, 6, pack_rl(2, 1, false)),
356    (0b1010000, 7, pack_rl(0, 8, false)),
357    (0b1010001, 7, pack_rl(0, 9, false)),
358    (0b1010010, 7, pack_rl(0, 10, false)),
359    (0b1010011, 7, pack_rl(0, 11, false)),
360    (0b1010100, 7, pack_rl(0, 3, true)),
361    (0b1010101, 7, pack_rl(1, 1, true)),
362    (0b1010110, 7, pack_rl(2, 1, true)),
363    (0b1010111, 7, pack_rl(3, 1, true)),
364    (0b10110000, 8, pack_rl(0, 12, false)),
365    (0b10110001, 8, pack_rl(1, 1, false)),
366    (0b10110010, 8, pack_rl(1, 2, false)),
367    (0b101100110, 9, pack_rl(2, 2, false)),
368    (0b101100111, 9, pack_rl(3, 1, false)),
369    (0b101101000, 9, VLC_ESCAPE),
370];
371
372const INTRA_CODES_1: &[(u32, u8, i32)] = &[
373    (0b00, 2, pack_rl(0, 1, false)),
374    (0b010, 3, pack_rl(0, 2, false)),
375    (0b0110, 4, pack_rl(0, 3, false)),
376    (0b0111, 4, pack_rl(0, 1, true)),
377    (0b1000, 4, pack_rl(0, 2, true)),
378    (0b10010, 5, pack_rl(0, 4, false)),
379    (0b10011, 5, pack_rl(2, 1, false)),
380    (0b10100, 5, pack_rl(0, 3, true)),
381    (0b101010, 6, pack_rl(0, 5, false)),
382    (0b101011, 6, pack_rl(0, 6, false)),
383    (0b101100, 6, pack_rl(0, 7, false)),
384    (0b101101, 6, pack_rl(1, 1, false)),
385    (0b101110, 6, pack_rl(3, 1, false)),
386    (0b1011110, 7, pack_rl(0, 8, false)),
387    (0b1011111, 7, pack_rl(0, 9, false)),
388    (0b1100000, 7, pack_rl(0, 10, false)),
389    (0b1100001, 7, pack_rl(0, 11, false)),
390    (0b1100010, 7, pack_rl(1, 2, false)),
391    (0b1100011, 7, pack_rl(1, 3, false)),
392    (0b1100100, 7, pack_rl(1, 1, true)),
393    (0b1100101, 7, pack_rl(2, 1, true)),
394    (0b11001100, 8, pack_rl(0, 12, false)),
395    (0b11001101, 8, pack_rl(1, 4, false)),
396    (0b11001110, 8, pack_rl(3, 1, true)),
397    (0b11001111, 8, pack_rl(4, 1, true)),
398    (0b110100000, 9, pack_rl(2, 2, false)),
399    (0b110100001, 9, pack_rl(4, 1, false)),
400    (0b110100010, 9, VLC_ESCAPE),
401];
402
403const INTRA_CODES_2: &[(u32, u8, i32)] = &[
404    (0b00, 2, pack_rl(0, 1, false)),
405    (0b010, 3, pack_rl(0, 2, false)),
406    (0b0110, 4, pack_rl(0, 3, false)),
407    (0b0111, 4, pack_rl(0, 2, true)),
408    (0b1000, 4, pack_rl(0, 3, true)),
409    (0b10010, 5, pack_rl(0, 4, false)),
410    (0b10011, 5, pack_rl(2, 1, false)),
411    (0b10100, 5, pack_rl(0, 1, true)),
412    (0b101010, 6, pack_rl(0, 5, false)),
413    (0b101011, 6, pack_rl(0, 6, false)),
414    (0b101100, 6, pack_rl(0, 7, false)),
415    (0b101101, 6, pack_rl(1, 1, false)),
416    (0b101110, 6, pack_rl(3, 1, false)),
417    (0b1011110, 7, pack_rl(0, 8, false)),
418    (0b1011111, 7, pack_rl(0, 9, false)),
419    (0b1100000, 7, pack_rl(0, 10, false)),
420    (0b1100001, 7, pack_rl(1, 2, false)),
421    (0b1100010, 7, pack_rl(2, 2, false)),
422    (0b1100011, 7, pack_rl(4, 1, false)),
423    (0b1100100, 7, pack_rl(1, 1, true)),
424    (0b1100101, 7, pack_rl(2, 1, true)),
425    (0b1100110, 7, pack_rl(3, 1, true)),
426    (0b1100111, 7, pack_rl(4, 1, true)),
427    (0b11010000, 8, pack_rl(0, 11, false)),
428    (0b11010001, 8, pack_rl(1, 3, false)),
429    (0b110100100, 9, VLC_ESCAPE),
430];
431
432const INTRA_CODES_3: &[(u32, u8, i32)] = &[
433    (0b00, 2, pack_rl(0, 1, false)),
434    (0b010, 3, pack_rl(0, 2, false)),
435    (0b0110, 4, pack_rl(0, 3, false)),
436    (0b0111, 4, pack_rl(0, 4, false)),
437    (0b1000, 4, pack_rl(0, 1, true)),
438    (0b1001, 4, pack_rl(0, 2, true)),
439    (0b10100, 5, pack_rl(0, 5, false)),
440    (0b10101, 5, pack_rl(2, 1, false)),
441    (0b10110, 5, pack_rl(0, 3, true)),
442    (0b101110, 6, pack_rl(0, 6, false)),
443    (0b101111, 6, pack_rl(0, 7, false)),
444    (0b110000, 6, pack_rl(0, 8, false)),
445    (0b110001, 6, pack_rl(1, 1, false)),
446    (0b110010, 6, pack_rl(2, 2, false)),
447    (0b1100110, 7, pack_rl(0, 9, false)),
448    (0b1100111, 7, pack_rl(0, 10, false)),
449    (0b1101000, 7, pack_rl(0, 11, false)),
450    (0b1101001, 7, pack_rl(1, 2, false)),
451    (0b1101010, 7, pack_rl(3, 1, false)),
452    (0b1101011, 7, pack_rl(4, 1, false)),
453    (0b1101100, 7, pack_rl(1, 1, true)),
454    (0b1101101, 7, pack_rl(2, 1, true)),
455    (0b1101110, 7, pack_rl(3, 1, true)),
456    (0b1101111, 7, pack_rl(4, 1, true)),
457    (0b11100000, 8, pack_rl(1, 3, false)),
458    (0b111000010, 9, VLC_ESCAPE),
459];
460
461pub fn inter_tcoef_vlc(idx: usize) -> VlcTable {
462    let codes = [INTER_CODES_0, INTER_CODES_1, INTER_CODES_2, INTER_CODES_3];
463    VlcTable::build(codes[idx.min(3)], 9)
464}
465
466pub fn intra_tcoef_vlc(idx: usize) -> VlcTable {
467    let codes = [INTRA_CODES_0, INTRA_CODES_1, INTRA_CODES_2, INTRA_CODES_3];
468    VlcTable::build(codes[idx.min(3)], 9)
469}
470
471// ─── CBPCY VLC (Coded Block Pattern) ────────────────────────────────────────
472// SMPTE 421M §8.1.5 Tables 54-55.
473// Symbol = 6-bit CBP (Y0 Y1 Y2 Y3 Cb Cr = MSB..LSB).
474
475// ─── Inter CBP VLC tables (CBPTAB 0-3) ──────────────────────────────────────
476// SMPTE 421M §8.1.5 Tables 55a-55b (Simple/Main uses tables 0-1;
477// CBPTAB 2-3 fall back to 0-1).
478// Canonical Huffman codes derived from spec code lengths.
479
480const CBP_INTER_0_CODES: &[(u32, u8, i32)] = &[
481    (0b0, 1, 0),
482    (0b1000, 4, 48),
483    (0b1001, 4, 49),
484    (0b10100, 5, 50),
485    (0b10101, 5, 51),
486    (0b101100, 6, 52),
487    (0b101101, 6, 53),
488    (0b101110, 6, 54),
489    (0b1011110, 7, 25),
490    (0b1011111, 7, 26),
491    (0b1100000, 7, 27),
492    (0b1100001, 7, 28),
493    (0b1100010, 7, 29),
494    (0b1100011, 7, 30),
495    (0b1100100, 7, 31),
496    (0b1100101, 7, 32),
497    (0b1100110, 7, 33),
498    (0b1100111, 7, 34),
499    (0b1101000, 7, 55),
500    (0b1101001, 7, 56),
501    (0b11010100, 8, 35),
502    (0b11010101, 8, 36),
503    (0b11010110, 8, 37),
504    (0b11010111, 8, 38),
505    (0b11011000, 8, 39),
506    (0b11011001, 8, 40),
507    (0b11011010, 8, 41),
508    (0b11011011, 8, 42),
509    (0b11011100, 8, 43),
510    (0b11011101, 8, 44),
511    (0b11011110, 8, 45),
512    (0b11011111, 8, 46),
513    (0b11100000, 8, 47),
514    (0b11100001, 8, 57),
515    (0b11100010, 8, 58),
516    (0b111000110, 9, 5),
517    (0b111000111, 9, 6),
518    (0b111001000, 9, 7),
519    (0b111001001, 9, 8),
520    (0b111001010, 9, 13),
521    (0b111001011, 9, 14),
522    (0b111001100, 9, 15),
523    (0b111001101, 9, 16),
524    (0b111001110, 9, 19),
525    (0b111001111, 9, 20),
526    (0b111010000, 9, 59),
527    (0b111010001, 9, 60),
528    (0b111010010, 9, 63),
529    (0b1110100110, 10, 1),
530    (0b1110100111, 10, 2),
531    (0b1110101000, 10, 3),
532    (0b1110101001, 10, 4),
533    (0b1110101010, 10, 9),
534    (0b1110101011, 10, 10),
535    (0b1110101100, 10, 11),
536    (0b1110101101, 10, 12),
537    (0b1110101110, 10, 17),
538    (0b1110101111, 10, 18),
539    (0b1110110000, 10, 21),
540    (0b1110110001, 10, 22),
541    (0b1110110010, 10, 23),
542    (0b1110110011, 10, 24),
543    (0b1110110100, 10, 61),
544    (0b1110110101, 10, 62),
545];
546
547const CBP_INTER_1_CODES: &[(u32, u8, i32)] = &[
548    (0b0, 1, 0),
549    (0b1000, 4, 48),
550    (0b1001, 4, 49),
551    (0b10100, 5, 50),
552    (0b10101, 5, 51),
553    (0b10110, 5, 52),
554    (0b10111, 5, 53),
555    (0b110000, 6, 54),
556    (0b110001, 6, 55),
557    (0b110010, 6, 56),
558    (0b1100110, 7, 25),
559    (0b1100111, 7, 26),
560    (0b1101000, 7, 27),
561    (0b1101001, 7, 28),
562    (0b1101010, 7, 29),
563    (0b1101011, 7, 30),
564    (0b1101100, 7, 31),
565    (0b1101101, 7, 32),
566    (0b1101110, 7, 33),
567    (0b1101111, 7, 34),
568    (0b1110000, 7, 57),
569    (0b1110001, 7, 58),
570    (0b11100100, 8, 35),
571    (0b11100101, 8, 36),
572    (0b11100110, 8, 37),
573    (0b11100111, 8, 38),
574    (0b11101000, 8, 39),
575    (0b11101001, 8, 40),
576    (0b11101010, 8, 41),
577    (0b11101011, 8, 42),
578    (0b11101100, 8, 43),
579    (0b11101101, 8, 44),
580    (0b11101110, 8, 45),
581    (0b11101111, 8, 46),
582    (0b11110000, 8, 47),
583    (0b11110001, 8, 59),
584    (0b11110010, 8, 60),
585    (0b111100110, 9, 3),
586    (0b111100111, 9, 4),
587    (0b111101000, 9, 9),
588    (0b111101001, 9, 10),
589    (0b111101010, 9, 13),
590    (0b111101011, 9, 14),
591    (0b111101100, 9, 15),
592    (0b111101101, 9, 16),
593    (0b111101110, 9, 17),
594    (0b111101111, 9, 18),
595    (0b111110000, 9, 19),
596    (0b111110001, 9, 20),
597    (0b111110010, 9, 61),
598    (0b111110011, 9, 62),
599    (0b1111101000, 10, 1),
600    (0b1111101001, 10, 2),
601    (0b1111101010, 10, 5),
602    (0b1111101011, 10, 6),
603    (0b1111101100, 10, 7),
604    (0b1111101101, 10, 8),
605    (0b1111101110, 10, 11),
606    (0b1111101111, 10, 12),
607    (0b1111110000, 10, 21),
608    (0b1111110001, 10, 22),
609    (0b1111110010, 10, 23),
610    (0b1111110011, 10, 24),
611    (0b1111110100, 10, 63),
612];
613
614pub fn cbpcy_p_vlc(idx: usize) -> VlcTable {
615    // CBPTAB 0-1 use distinct tables; 2-3 reuse 0-1 (Simple/Main only)
616    match idx & 1 {
617        0 => VlcTable::build(CBP_INTER_0_CODES, 10),
618        _ => VlcTable::build(CBP_INTER_1_CODES, 10),
619    }
620}
621
622pub fn cbpcy_i_vlc() -> VlcTable {
623    // Table 54 – Intra CBP (only coded-or-not matters for I-frames)
624    const T: &[(u32, u8, i32)] = &[
625        (0b0, 1, 63),
626        (0b100, 3, 0),
627        (0b101, 3, 32),
628        (0b1100, 4, 16),
629        (0b1101, 4, 8),
630        (0b11100, 5, 4),
631        (0b11101, 5, 2),
632        (0b111100, 6, 1),
633        (0b1111010, 7, 48),
634        (0b1111011, 7, 40),
635        (0b11111000, 8, 36),
636        (0b11111001, 8, 24),
637        (0b11111010, 8, 20),
638        (0b11111011, 8, 12),
639        (0b11111100, 8, 6),
640        (0b11111101, 8, 5),
641        (0b11111110, 8, 3),
642        (0b111111110, 9, 60),
643        (0b111111111, 9, 56),
644    ];
645    VlcTable::build(T, 9)
646}
647
648// ─── Transform type per MB / block ───────────────────────────────────────────
649// SMPTE 421M Tables 56-57.
650// 0=8x8, 1=8x4_top, 2=8x4_bot, 3=4x8_left, 4=4x8_right, 5=4x4, 6=per_block
651
652pub fn ttmb_vlc() -> VlcTable {
653    const T: &[(u32, u8, i32)] = &[
654        (0b1, 1, 0),
655        (0b01, 2, 6),
656        (0b001, 3, 5),
657        (0b0001, 4, 1),
658        (0b00001, 5, 2),
659        (0b000001, 6, 3),
660        (0b000000, 6, 4),
661    ];
662    VlcTable::build(T, 6)
663}
664
665pub fn ttblk_vlc() -> VlcTable {
666    const T: &[(u32, u8, i32)] = &[
667        (0b1, 1, 0),
668        (0b01, 2, 5),
669        (0b001, 3, 1),
670        (0b0001, 4, 2),
671        (0b00001, 5, 3),
672        (0b000001, 6, 4),
673        (0b000000, 6, 6),
674    ];
675    VlcTable::build(T, 6)
676}
677
678pub fn subblkpat_vlc() -> VlcTable {
679    const T: &[(u32, u8, i32)] = &[(0b1, 1, 3), (0b01, 2, 2), (0b001, 3, 1), (0b0001, 4, 0)];
680    VlcTable::build(T, 4)
681}
682
683// ─── MV differential VLC ─────────────────────────────────────────────────────
684// SMPTE 421M §8.3.5.4 Table 46 (k=0) and Table 47 (k=1).
685// Symbol = signed quarter-pixel MV differential.
686// i32::MIN is the escape sentinel (fixed-length follows).
687
688// ─── MV differential VLC tables (MVTAB 0-3) ─────────────────────────────────
689// SMPTE 421M §8.3.5.4 Tables 46a-46d.
690// Canonical Huffman from spec code lengths.
691// i32::MIN = escape sentinel (fixed-length code follows).
692
693const MV_CODES_0: &[(u32, u8, i32)] = &[
694    (0b0, 1, 0),
695    (0b100, 3, 1),
696    (0b101, 3, -1),
697    (0b11000, 5, 2),
698    (0b11001, 5, -2),
699    (0b110100, 6, 3),
700    (0b110101, 6, -3),
701    (0b1101100, 7, 4),
702    (0b1101101, 7, -4),
703    (0b11011100, 8, 5),
704    (0b11011101, 8, -5),
705    (0b110111100, 9, 6),
706    (0b110111101, 9, -6),
707    (0b1101111100, 10, 7),
708    (0b1101111101, 10, -7),
709    (0b1101111110, 10, i32::MIN),
710];
711
712const MV_CODES_1: &[(u32, u8, i32)] = &[
713    (0b0, 1, 0),
714    (0b100, 3, 1),
715    (0b101, 3, -1),
716    (0b11000, 5, 2),
717    (0b11001, 5, -2),
718    (0b110100, 6, 3),
719    (0b110101, 6, -3),
720    (0b110110, 6, 4),
721    (0b110111, 6, -4),
722    (0b1110000, 7, 5),
723    (0b1110001, 7, -5),
724    (0b11100100, 8, 6),
725    (0b11100101, 8, -6),
726    (0b111001100, 9, 7),
727    (0b111001101, 9, -7),
728    (0b111001110, 9, i32::MIN),
729];
730
731const MV_CODES_2: &[(u32, u8, i32)] = &[
732    (0b0, 1, 0),
733    (0b10, 2, 1),
734    (0b11, 2, -1),
735    // NOTE: these bit patterns are written MSB-first.
736    // The original version had code lengths off by one, which made
737    // `prefix = bits << (max_bits - len)` overflow the decode table.
738    (0b10000, 5, 2),
739    (0b10001, 5, -2),
740    (0b100100, 6, 3),
741    (0b100101, 6, -3),
742    (0b1001100, 7, 4),
743    (0b1001101, 7, -4),
744    (0b10011100, 8, 5),
745    (0b10011101, 8, -5),
746    (0b100111100, 9, 6),
747    (0b100111101, 9, -6),
748    (0b1001111100, 10, 7),
749    (0b1001111101, 10, -7),
750    (0b1001111110, 10, i32::MIN),
751];
752
753const MV_CODES_3: &[(u32, u8, i32)] = &[
754    (0b0, 1, 0),
755    (0b10, 2, 1),
756    (0b11, 2, -1),
757    // Same off-by-one length bug as MV_CODES_2.
758    (0b1000, 4, 2),
759    (0b1001, 4, -2),
760    (0b10100, 5, 3),
761    (0b10101, 5, -3),
762    (0b101100, 6, 4),
763    (0b101101, 6, -4),
764    (0b1011100, 7, 5),
765    (0b1011101, 7, -5),
766    (0b10111100, 8, 6),
767    (0b10111101, 8, -6),
768    (0b101111100, 9, 7),
769    (0b101111101, 9, -7),
770    (0b1011111100, 10, i32::MIN),
771];
772
773pub fn mv_diff_vlc(idx: usize) -> VlcTable {
774    let (codes, max_bits): (&[(u32, u8, i32)], u8) = match idx & 3 {
775        0 => (MV_CODES_0, 10),
776        1 => (MV_CODES_1, 9),
777        // Tables 2-3 include 10-bit escape codes in this simplified decoder.
778        2 => (MV_CODES_2, 10),
779        _ => (MV_CODES_3, 10),
780    };
781    VlcTable::build(codes, max_bits)
782}
783
784// Backward-compat aliases used by old code referencing k0/k1
785pub fn mv_diff_vlc_k0() -> VlcTable {
786    mv_diff_vlc(0)
787}
788pub fn mv_diff_vlc_k1() -> VlcTable {
789    mv_diff_vlc(1)
790}
791
792// ─── 2MV / 4MV block patterns ────────────────────────────────────────────────
793
794pub fn mv2bp_vlc() -> VlcTable {
795    const T: &[(u32, u8, i32)] = &[(0b1, 1, 3), (0b01, 2, 2), (0b001, 3, 1), (0b0001, 4, 0)];
796    VlcTable::build(T, 4)
797}
798
799pub fn mv4bp_vlc() -> VlcTable {
800    const T: &[(u32, u8, i32)] = &[
801        (0b1, 1, 15),
802        (0b011, 3, 14),
803        (0b0101, 4, 13),
804        (0b01001, 5, 12),
805        (0b010001, 6, 11),
806        (0b0100001, 7, 10),
807        (0b01000001, 8, 9),
808        (0b010000001, 9, 8),
809        (0b010000000, 9, 0),
810    ];
811    VlcTable::build(T, 9)
812}
813
814// ─── Zigzag / scan orders ────────────────────────────────────────────────────
815
816/// Standard MPEG-2 zigzag.
817pub const ZIGZAG: [usize; 64] = [
818    0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
819    13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
820    52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
821];
822
823/// VC-1 Intra scan (SMPTE 421M §7.4.3).
824pub const SCAN_INTRA: [usize; 64] = [
825    0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49, 41, 33, 26, 18, 3, 11, 4, 12, 19,
826    27, 34, 42, 50, 58, 35, 43, 51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45, 53,
827    61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63,
828];
829
830/// Horizontal scan for 8x4 top/bottom sub-blocks.
831pub const SCAN_HORIZ: [usize; 64] = [
832    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
833    26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
834    50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
835];
836
837/// Vertical scan for 4x8 left/right sub-blocks.
838pub const SCAN_VERT: [usize; 64] = [
839    0, 8, 16, 24, 32, 40, 48, 56, 1, 9, 17, 25, 33, 41, 49, 57, 2, 10, 18, 26, 34, 42, 50, 58, 3,
840    11, 19, 27, 35, 43, 51, 59, 4, 12, 20, 28, 36, 44, 52, 60, 5, 13, 21, 29, 37, 45, 53, 61, 6,
841    14, 22, 30, 38, 46, 54, 62, 7, 15, 23, 31, 39, 47, 55, 63,
842];
843
844// ─── WMV2 (MS-MPEG4 V8) VLC Tables ───────────────────────────────────────────
845// Four TCOEF tables: INTER_0/1 (selected by ttcoef bit), INTRA_0/1.
846// CBP: CBPY (luma, 4 blocks, 0..15) + CBPC_P (chroma+skip for P-frames).
847
848const WMV2_TCOEF_INTER_0_CODES: &[(u32, u8, i32)] = &[
849    (0b00, 2, 2),
850    (0b010, 3, 3),
851    (0b0110, 4, 4),
852    (0b0111, 4, 258),
853    (0b10000, 5, 6),
854    (0b10001, 5, 514),
855    (0b10010, 5, 5),
856    (0b10011, 5, 259),
857    (0b101000, 6, 8),
858    (0b101001, 6, 770),
859    (0b101010, 6, 7),
860    (0b101011, 6, 515),
861    (0b1011000, 7, 10),
862    (0b1011001, 7, 12),
863    (0b1011010, 7, 260),
864    (0b1011011, 7, 1026),
865    (0b1011100, 7, 1282),
866    (0b1011101, 7, 9),
867    (0b1011110, 7, 261),
868    (0b1011111, 7, 771),
869    (0b1100000, 7, 1027),
870    (0b11000010, 8, 14),
871    (0b11000011, 8, 16),
872    (0b11000100, 8, 262),
873    (0b11000101, 8, 516),
874    (0b11000110, 8, 1538),
875    (0b11000111, 8, 1794),
876    (0b11001000, 8, 11),
877    (0b11001001, 8, 1283),
878    (0b110010100, 9, 18),
879    (0b110010101, 9, 20),
880    (0b110010110, 9, 22),
881    (0b110010111, 9, 264),
882    (0b110011000, 9, 2050),
883    (0b110011001, 9, 2306),
884    (0b110011010, 9, 13),
885    (0b110011011, 9, 15),
886    (0b110011100, 9, 263),
887    (0b110011101, 9, 517),
888    (0b110011110, 9, 1539),
889    (0b1100111110, 10, 24),
890    (0b1100111111, 10, 2562),
891    (0b1101000000, 10, 2818),
892    (0b1101000001, 10, 17),
893    (0b1101000010, 10, 1795),
894    (0b1101000011, 10, VLC_ESCAPE),
895]; // max_bits=10
896
897const WMV2_TCOEF_INTER_1_CODES: &[(u32, u8, i32)] = &[
898    (0b00, 2, 2),
899    (0b010, 3, 4),
900    (0b011, 3, 3),
901    (0b1000, 4, 6),
902    (0b1001, 4, 258),
903    (0b10100, 5, 8),
904    (0b10101, 5, 514),
905    (0b10110, 5, 5),
906    (0b10111, 5, 259),
907    (0b110000, 6, 10),
908    (0b110001, 6, 12),
909    (0b110010, 6, 260),
910    (0b110011, 6, 770),
911    (0b110100, 6, 7),
912    (0b110101, 6, 515),
913    (0b1101100, 7, 14),
914    (0b1101101, 7, 16),
915    (0b1101110, 7, 1026),
916    (0b1101111, 7, 9),
917    (0b1110000, 7, 261),
918    (0b1110001, 7, 771),
919    (0b11100100, 8, 18),
920    (0b11100101, 8, 20),
921    (0b11100110, 8, 262),
922    (0b11100111, 8, 516),
923    (0b11101000, 8, 1282),
924    (0b11101001, 8, 11),
925    (0b11101010, 8, 1027),
926    (0b111010110, 9, 22),
927    (0b111010111, 9, 24),
928    (0b111011000, 9, 264),
929    (0b111011001, 9, 1538),
930    (0b111011010, 9, 1794),
931    (0b111011011, 9, 13),
932    (0b111011100, 9, 263),
933    (0b111011101, 9, 517),
934    (0b111011110, 9, 1283),
935    (0b1110111110, 10, 26),
936    (0b1110111111, 10, 28),
937    (0b1111000000, 10, 2050),
938    (0b1111000001, 10, 15),
939    (0b1111000010, 10, 1539),
940    (0b1111000011, 10, VLC_ESCAPE),
941]; // max_bits=10
942
943const WMV2_TCOEF_INTRA_0_CODES: &[(u32, u8, i32)] = &[
944    (0b000, 3, 2),
945    (0b0010, 4, 4),
946    (0b0011, 4, 258),
947    (0b0100, 4, 3),
948    (0b01010, 5, 6),
949    (0b01011, 5, 514),
950    (0b01100, 5, 5),
951    (0b01101, 5, 259),
952    (0b011100, 6, 8),
953    (0b011101, 6, 260),
954    (0b011110, 6, 770),
955    (0b011111, 6, 1026),
956    (0b100000, 6, 7),
957    (0b100001, 6, 515),
958    (0b1000100, 7, 10),
959    (0b1000101, 7, 12),
960    (0b1000110, 7, 262),
961    (0b1000111, 7, 516),
962    (0b1001000, 7, 1282),
963    (0b1001001, 7, 1538),
964    (0b1001010, 7, 9),
965    (0b1001011, 7, 261),
966    (0b1001100, 7, 771),
967    (0b1001101, 7, 1027),
968    (0b10011100, 8, 14),
969    (0b10011101, 8, 16),
970    (0b10011110, 8, 18),
971    (0b10011111, 8, 264),
972    (0b10100000, 8, 518),
973    (0b10100001, 8, 772),
974    (0b10100010, 8, 1794),
975    (0b10100011, 8, 2050),
976    (0b10100100, 8, 11),
977    (0b10100101, 8, 13),
978    (0b10100110, 8, 263),
979    (0b10100111, 8, 517),
980    (0b10101000, 8, 1283),
981    (0b10101001, 8, 1539),
982    (0b101010100, 9, 20),
983    (0b101010101, 9, 22),
984    (0b101010110, 9, 24),
985    (0b101010111, 9, 266),
986    (0b101011000, 9, 1028),
987    (0b101011001, 9, 1284),
988    (0b101011010, 9, 2306),
989    (0b101011011, 9, 2562),
990    (0b101011100, 9, 15),
991    (0b101011101, 9, 17),
992    (0b101011110, 9, 265),
993    (0b101011111, 9, 1795),
994    (0b101100000, 9, 2051),
995    (0b1011000010, 10, 26),
996    (0b1011000011, 10, 28),
997    (0b1011000100, 10, 30),
998    (0b1011000101, 10, 2818),
999    (0b1011000110, 10, 19),
1000    (0b1011000111, 10, 21),
1001    (0b1011001000, 10, 2307),
1002    (0b1011001001, 10, VLC_ESCAPE),
1003]; // max_bits=10
1004
1005const WMV2_TCOEF_INTRA_1_CODES: &[(u32, u8, i32)] = &[
1006    (0b00, 2, 2),
1007    (0b010, 3, 3),
1008    (0b0110, 4, 4),
1009    (0b0111, 4, 6),
1010    (0b1000, 4, 258),
1011    (0b10010, 5, 8),
1012    (0b10011, 5, 514),
1013    (0b10100, 5, 5),
1014    (0b10101, 5, 259),
1015    (0b101100, 6, 10),
1016    (0b101101, 6, 260),
1017    (0b101110, 6, 770),
1018    (0b101111, 6, 7),
1019    (0b110000, 6, 515),
1020    (0b1100010, 7, 12),
1021    (0b1100011, 7, 14),
1022    (0b1100100, 7, 1026),
1023    (0b1100101, 7, 9),
1024    (0b1100110, 7, 261),
1025    (0b1100111, 7, 771),
1026    (0b11010000, 8, 16),
1027    (0b11010001, 8, 262),
1028    (0b11010010, 8, 516),
1029    (0b11010011, 8, 1282),
1030    (0b11010100, 8, 11),
1031    (0b11010101, 8, 1027),
1032    (0b110101100, 9, 18),
1033    (0b110101101, 9, 20),
1034    (0b110101110, 9, 264),
1035    (0b110101111, 9, 1538),
1036    (0b110110000, 9, 1794),
1037    (0b110110001, 9, 13),
1038    (0b110110010, 9, 263),
1039    (0b110110011, 9, 517),
1040    (0b110110100, 9, 1283),
1041    (0b1101101010, 10, 22),
1042    (0b1101101011, 10, 24),
1043    (0b1101101100, 10, 2050),
1044    (0b1101101101, 10, 15),
1045    (0b1101101110, 10, 1539),
1046    (0b1101101111, 10, VLC_ESCAPE),
1047]; // max_bits=10
1048
1049// H.263 CBPY (luma CBP 4 blocks, symbol = 4-bit mask)
1050const WMV2_CBPY_CODES: &[(u32, u8, i32)] = &[
1051    (0b00, 2, 15),
1052    (0b0100, 4, 0),
1053    (0b0101, 4, 3),
1054    (0b0110, 4, 5),
1055    (0b0111, 4, 7),
1056    (0b1000, 4, 10),
1057    (0b1001, 4, 11),
1058    (0b1010, 4, 12),
1059    (0b1011, 4, 13),
1060    (0b1100, 4, 14),
1061    (0b11010, 5, 1),
1062    (0b11011, 5, 2),
1063    (0b11100, 5, 4),
1064    (0b11101, 5, 8),
1065    (0b111100, 6, 6),
1066    (0b111101, 6, 9),
1067]; // max_bits=6
1068
1069// CBPC P-frame (chroma CBP 2 blocks + MB-skip; sym=-1 means skipped MB)
1070const WMV2_CBPC_P_CODES: &[(u32, u8, i32)] = &[
1071    (0b0, 1, 0),
1072    (0b10, 2, 1),
1073    (0b110, 3, 2),
1074    (0b1110, 4, 3),
1075    (0b111100, 6, -1),
1076]; // max_bits=6
1077
1078pub fn wmv2_tcoef_inter_vlc(idx: usize) -> VlcTable {
1079    match idx & 1 {
1080        0 => VlcTable::build(WMV2_TCOEF_INTER_0_CODES, 10),
1081        _ => VlcTable::build(WMV2_TCOEF_INTER_1_CODES, 10),
1082    }
1083}
1084pub fn wmv2_tcoef_intra_vlc(idx: usize) -> VlcTable {
1085    match idx & 1 {
1086        0 => VlcTable::build(WMV2_TCOEF_INTRA_0_CODES, 10),
1087        _ => VlcTable::build(WMV2_TCOEF_INTRA_1_CODES, 10),
1088    }
1089}
1090pub fn wmv2_cbpy_vlc() -> VlcTable {
1091    VlcTable::build(WMV2_CBPY_CODES, 6)
1092}
1093pub fn wmv2_cbpc_p_vlc() -> VlcTable {
1094    VlcTable::build(WMV2_CBPC_P_CODES, 6)
1095}