Skip to main content

h264_reader/nal/slice/
cavlc.rs

1//! CAVLC (Context-Adaptive Variable-Length Coding) entropy decoding for H.264
2//! residual blocks, as specified in ITU-T H.264 section 9.2.
3
4use std::fmt;
5
6use crate::rbsp::{BitRead, BitReaderError};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum CavlcContext {
10    NC(u8),
11    ChromaDC,
12}
13
14#[derive(Debug)]
15pub enum CavlcError {
16    IoError(BitReaderError),
17    InvalidCode(&'static str),
18    OutOfRange { field: &'static str, value: i64 },
19}
20
21impl fmt::Display for CavlcError {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        match self {
24            CavlcError::IoError(e) => write!(f, "bitstream I/O: {e:?}"),
25            CavlcError::InvalidCode(ctx) => write!(f, "invalid VLC code: {ctx}"),
26            CavlcError::OutOfRange { field, value } => {
27                write!(f, "{field} out of range: {value}")
28            }
29        }
30    }
31}
32
33impl std::error::Error for CavlcError {}
34
35impl From<BitReaderError> for CavlcError {
36    fn from(e: BitReaderError) -> Self {
37        CavlcError::IoError(e)
38    }
39}
40
41type CoeffTokenTable = &'static [(u8, u16, u8, u8)];
42
43fn read_coeff_token_vlc<R: BitRead>(
44    r: &mut R,
45    table: CoeffTokenTable,
46    name: &'static str,
47) -> Result<(u8, u8), CavlcError> {
48    let mut accum: u16 = 0;
49    let mut bits_read: u8 = 0;
50    let mut table_idx = 0;
51
52    loop {
53        let bit = r.read_bit(name)?;
54        accum = (accum << 1) | (bit as u16);
55        bits_read += 1;
56
57        while table_idx < table.len() && table[table_idx].0 == bits_read {
58            let (_, code_val, tc, to) = table[table_idx];
59            if code_val == accum {
60                return Ok((tc, to));
61            }
62            table_idx += 1;
63        }
64
65        if table_idx >= table.len() || bits_read > 16 {
66            return Err(CavlcError::InvalidCode(name));
67        }
68    }
69}
70
71type ValueVlcTable = &'static [(u8, u16, u8)];
72
73fn read_value_vlc<R: BitRead>(
74    r: &mut R,
75    table: ValueVlcTable,
76    name: &'static str,
77) -> Result<u8, CavlcError> {
78    let mut accum: u16 = 0;
79    let mut bits_read: u8 = 0;
80    let mut table_idx = 0;
81
82    loop {
83        let bit = r.read_bit(name)?;
84        accum = (accum << 1) | (bit as u16);
85        bits_read += 1;
86
87        while table_idx < table.len() && table[table_idx].0 == bits_read {
88            let (_, code_val, val) = table[table_idx];
89            if code_val == accum {
90                return Ok(val);
91            }
92            table_idx += 1;
93        }
94
95        if table_idx >= table.len() || bits_read > 16 {
96            return Err(CavlcError::InvalidCode(name));
97        }
98    }
99}
100
101fn read_coeff_token<R: BitRead>(r: &mut R, nc: CavlcContext) -> Result<(u8, u8), CavlcError> {
102    match nc {
103        CavlcContext::NC(n) if n >= 8 => read_coeff_token_fixed6(r),
104        CavlcContext::NC(4..=7) => read_coeff_token_vlc(r, COEFF_TOKEN_4, "coeff_token (4<=nC<8)"),
105        CavlcContext::NC(2..=3) => read_coeff_token_vlc(r, COEFF_TOKEN_2, "coeff_token (2<=nC<4)"),
106        CavlcContext::NC(_) => read_coeff_token_vlc(r, COEFF_TOKEN_0, "coeff_token (nC<2)"),
107        CavlcContext::ChromaDC => {
108            read_coeff_token_vlc(r, COEFF_TOKEN_CHROMA_DC, "coeff_token (ChromaDC)")
109        }
110    }
111}
112
113fn read_coeff_token_fixed6<R: BitRead>(r: &mut R) -> Result<(u8, u8), CavlcError> {
114    let code: u8 = r.read::<6, u8>("coeff_token")?;
115    if code == 3 {
116        return Ok((0, 0));
117    }
118    let total_coeff = (code >> 2) + 1;
119    let trailing_ones = code & 3;
120    if trailing_ones > core::cmp::min(3, total_coeff) {
121        return Err(CavlcError::InvalidCode(
122            "coeff_token nC>=8: trailing_ones > total_coeff",
123        ));
124    }
125    Ok((total_coeff, trailing_ones))
126}
127
128// Table 9-5(a): 0 <= nC < 2
129#[rustfmt::skip]
130static COEFF_TOKEN_0: CoeffTokenTable = &[
131    // len, code, TC, TO
132    ( 1, 0b1,                    0, 0),
133    ( 2, 0b01,                   1, 1),
134    ( 3, 0b001,                  2, 2),
135    ( 5, 0b00011,                3, 3),
136    ( 6, 0b000101,               1, 0),
137    ( 6, 0b000100,               2, 1),
138    ( 6, 0b000011,               4, 3),
139    ( 7, 0b0000101,              3, 2),
140    ( 7, 0b0000100,              5, 3),
141    ( 8, 0b00000111,             2, 0),
142    ( 8, 0b00000110,             3, 1),
143    ( 8, 0b00000101,             4, 2),
144    ( 8, 0b00000100,             6, 3),
145    ( 9, 0b000000111,            3, 0),
146    ( 9, 0b000000110,            4, 1),
147    ( 9, 0b000000101,            5, 2),
148    ( 9, 0b000000100,            7, 3),
149    (10, 0b0000000111,           4, 0),
150    (10, 0b0000000110,           5, 1),
151    (10, 0b0000000101,           6, 2),
152    (10, 0b0000000100,           8, 3),
153    (11, 0b00000000111,          5, 0),
154    (11, 0b00000000110,          6, 1),
155    (11, 0b00000000101,          7, 2),
156    (11, 0b00000000100,          9, 3),
157    (13, 0b0000000001111,        6, 0),
158    (13, 0b0000000001110,        7, 1),
159    (13, 0b0000000001101,        8, 2),
160    (13, 0b0000000001100,       10, 3),
161    (13, 0b0000000001011,        7, 0),
162    (13, 0b0000000001010,        8, 1),
163    (13, 0b0000000001001,        9, 2),
164    (13, 0b0000000001000,        8, 0),
165    (14, 0b00000000001111,       9, 0),
166    (14, 0b00000000001110,       9, 1),
167    (14, 0b00000000001101,      10, 2),
168    (14, 0b00000000001100,      11, 3),
169    (14, 0b00000000001011,      10, 0),
170    (14, 0b00000000001010,      10, 1),
171    (14, 0b00000000001001,      11, 2),
172    (14, 0b00000000001000,      12, 3),
173    (15, 0b000000000001111,     11, 0),
174    (15, 0b000000000001110,     11, 1),
175    (15, 0b000000000001101,     12, 2),
176    (15, 0b000000000001100,     13, 3),
177    (15, 0b000000000001011,     12, 0),
178    (15, 0b000000000001010,     12, 1),
179    (15, 0b000000000001001,     13, 2),
180    (15, 0b000000000001000,     14, 3),
181    (15, 0b000000000000001,     13, 1),
182    (16, 0b0000000000001111,    13, 0),
183    (16, 0b0000000000001110,    14, 1),
184    (16, 0b0000000000001101,    14, 2),
185    (16, 0b0000000000001100,    15, 3),
186    (16, 0b0000000000001011,    14, 0),
187    (16, 0b0000000000001010,    15, 1),
188    (16, 0b0000000000001001,    15, 2),
189    (16, 0b0000000000001000,    16, 3),
190    (16, 0b0000000000000111,    15, 0),
191    (16, 0b0000000000000110,    16, 1),
192    (16, 0b0000000000000101,    16, 2),
193    (16, 0b0000000000000100,    16, 0),
194];
195
196// Table 9-5(b): 2 <= nC < 4
197#[rustfmt::skip]
198static COEFF_TOKEN_2: CoeffTokenTable = &[
199    ( 2, 0b11,                   0, 0),
200    ( 2, 0b10,                   1, 1),
201    ( 3, 0b011,                  2, 2),
202    ( 4, 0b0101,                 3, 3),
203    ( 4, 0b0100,                 4, 3),
204    ( 5, 0b00111,                2, 1),
205    ( 5, 0b00110,                5, 3),
206    ( 6, 0b001011,               1, 0),
207    ( 6, 0b001010,               3, 1),
208    ( 6, 0b001001,               3, 2),
209    ( 6, 0b001000,               6, 3),
210    ( 6, 0b000111,               2, 0),
211    ( 6, 0b000110,               4, 1),
212    ( 6, 0b000101,               4, 2),
213    ( 6, 0b000100,               7, 3),
214    ( 7, 0b0000111,              3, 0),
215    ( 7, 0b0000110,              5, 1),
216    ( 7, 0b0000101,              5, 2),
217    ( 7, 0b0000100,              8, 3),
218    ( 8, 0b00000111,             4, 0),
219    ( 8, 0b00000110,             6, 1),
220    ( 8, 0b00000101,             6, 2),
221    ( 8, 0b00000100,             5, 0),
222    ( 9, 0b000000111,            6, 0),
223    ( 9, 0b000000110,            7, 1),
224    ( 9, 0b000000101,            7, 2),
225    ( 9, 0b000000100,            9, 3),
226    (11, 0b00000001111,          7, 0),
227    (11, 0b00000001110,          8, 1),
228    (11, 0b00000001101,          8, 2),
229    (11, 0b00000001100,         10, 3),
230    (11, 0b00000001011,          8, 0),
231    (11, 0b00000001010,          9, 1),
232    (11, 0b00000001001,          9, 2),
233    (11, 0b00000001000,         11, 3),
234    (12, 0b000000001111,         9, 0),
235    (12, 0b000000001110,        10, 1),
236    (12, 0b000000001101,        10, 2),
237    (12, 0b000000001100,        12, 3),
238    (12, 0b000000001011,        10, 0),
239    (12, 0b000000001010,        11, 1),
240    (12, 0b000000001001,        11, 2),
241    (12, 0b000000001000,        11, 0),
242    (13, 0b0000000001111,       12, 0),
243    (13, 0b0000000001110,       12, 1),
244    (13, 0b0000000001101,       12, 2),
245    (13, 0b0000000001100,       13, 3),
246    (13, 0b0000000001011,       13, 0),
247    (13, 0b0000000001010,       13, 1),
248    (13, 0b0000000001001,       13, 2),
249    (13, 0b0000000001000,       14, 3),
250    (13, 0b0000000000111,       14, 0),
251    (13, 0b0000000000110,       14, 2),
252    (13, 0b0000000000001,       15, 3),
253    (14, 0b00000000001011,      14, 1),
254    (14, 0b00000000001010,      15, 2),
255    (14, 0b00000000001001,      15, 0),
256    (14, 0b00000000001000,      15, 1),
257    (14, 0b00000000000111,      16, 0),
258    (14, 0b00000000000110,      16, 1),
259    (14, 0b00000000000101,      16, 2),
260    (14, 0b00000000000100,      16, 3),
261];
262
263// Table 9-5(c): 4 <= nC < 8
264#[rustfmt::skip]
265static COEFF_TOKEN_4: CoeffTokenTable = &[
266    ( 4, 0b1111,                 0, 0),
267    ( 4, 0b1110,                 1, 1),
268    ( 4, 0b1101,                 2, 2),
269    ( 4, 0b1100,                 3, 3),
270    ( 4, 0b1011,                 4, 3),
271    ( 4, 0b1010,                 5, 3),
272    ( 4, 0b1001,                 6, 3),
273    ( 4, 0b1000,                 7, 3),
274    ( 5, 0b01111,                2, 1),
275    ( 5, 0b01110,                3, 2),
276    ( 5, 0b01101,                8, 3),
277    ( 5, 0b01100,                3, 1),
278    ( 5, 0b01011,                4, 2),
279    ( 5, 0b01010,                4, 1),
280    ( 5, 0b01001,                5, 2),
281    ( 5, 0b01000,                5, 1),
282    ( 6, 0b001111,               1, 0),
283    ( 6, 0b001110,               6, 1),
284    ( 6, 0b001101,               6, 2),
285    ( 6, 0b001100,               9, 3),
286    ( 6, 0b001011,               2, 0),
287    ( 6, 0b001010,               7, 1),
288    ( 6, 0b001001,               7, 2),
289    ( 6, 0b001000,               3, 0),
290    ( 7, 0b0001111,              4, 0),
291    ( 7, 0b0001110,              8, 1),
292    ( 7, 0b0001101,              8, 2),
293    ( 7, 0b0001100,             10, 3),
294    ( 7, 0b0001011,              5, 0),
295    ( 7, 0b0001010,              9, 2),
296    ( 7, 0b0001001,              6, 0),
297    ( 7, 0b0001000,              7, 0),
298    ( 8, 0b00001111,             8, 0),
299    ( 8, 0b00001110,             9, 1),
300    ( 8, 0b00001101,            10, 2),
301    ( 8, 0b00001100,            11, 3),
302    ( 8, 0b00001011,             9, 0),
303    ( 8, 0b00001010,            10, 1),
304    ( 8, 0b00001001,            11, 2),
305    ( 8, 0b00001000,            12, 3),
306    ( 9, 0b000001111,           10, 0),
307    ( 9, 0b000001110,           11, 1),
308    ( 9, 0b000001101,           12, 2),
309    ( 9, 0b000001100,           13, 3),
310    ( 9, 0b000001011,           11, 0),
311    ( 9, 0b000001010,           12, 1),
312    ( 9, 0b000001001,           13, 2),
313    ( 9, 0b000001000,           12, 0),
314    ( 9, 0b000000111,           13, 1),
315    (10, 0b0000001101,          13, 0),
316    (10, 0b0000001100,          14, 1),
317    (10, 0b0000001011,          14, 2),
318    (10, 0b0000001010,          14, 3),
319    (10, 0b0000001001,          14, 0),
320    (10, 0b0000001000,          15, 1),
321    (10, 0b0000000111,          15, 2),
322    (10, 0b0000000110,          15, 3),
323    (10, 0b0000000101,          15, 0),
324    (10, 0b0000000100,          16, 1),
325    (10, 0b0000000011,          16, 2),
326    (10, 0b0000000010,          16, 3),
327    (10, 0b0000000001,          16, 0),
328];
329
330// ChromaDC table for nC == -1 (4:2:0, max 4 coeffs)
331#[rustfmt::skip]
332static COEFF_TOKEN_CHROMA_DC: CoeffTokenTable = &[
333    ( 1, 0b1,         1, 1),
334    ( 2, 0b01,        0, 0),
335    ( 3, 0b001,       2, 2),
336    ( 6, 0b000111,    1, 0),
337    ( 6, 0b000110,    2, 1),
338    ( 6, 0b000101,    3, 3),
339    ( 6, 0b000100,    2, 0),
340    ( 6, 0b000011,    3, 0),
341    ( 6, 0b000010,    4, 0),
342    ( 7, 0b0000011,   3, 1),
343    ( 7, 0b0000010,   3, 2),
344    ( 7, 0b0000000,   4, 3),
345    ( 8, 0b00000011,  4, 1),
346    ( 8, 0b00000010,  4, 2),
347];
348
349fn read_level_prefix<R: BitRead>(r: &mut R) -> Result<u32, CavlcError> {
350    let mut prefix = 0u32;
351    loop {
352        if r.read_bit("level_prefix")? {
353            return Ok(prefix);
354        }
355        prefix += 1;
356        if prefix > 32 {
357            return Err(CavlcError::InvalidCode("level_prefix exceeds 32"));
358        }
359    }
360}
361
362fn read_level<R: BitRead>(r: &mut R, suffix_length: u32) -> Result<i32, CavlcError> {
363    let level_prefix = read_level_prefix(r)?;
364
365    let level_suffix_size = if level_prefix == 14 && suffix_length == 0 {
366        4
367    } else if level_prefix >= 15 {
368        level_prefix - 3
369    } else {
370        suffix_length
371    };
372
373    let level_suffix: u32 = if level_suffix_size > 0 {
374        r.read_var(level_suffix_size, "level_suffix")?
375    } else {
376        0
377    };
378
379    let level_code = {
380        let prefix_part = core::cmp::min(15, level_prefix) << suffix_length;
381        let mut code = prefix_part + level_suffix;
382        if level_prefix >= 15 && suffix_length == 0 {
383            code += 15;
384        }
385        if level_prefix >= 16 {
386            code += (1u32 << (level_prefix - 3)) - 4096;
387        }
388        code
389    };
390
391    let level_val = if level_code & 1 == 0 {
392        (level_code as i32 >> 1) + 1
393    } else {
394        -(level_code as i32 >> 1) - 1
395    };
396
397    Ok(level_val)
398}
399
400fn update_suffix_length(suffix_length: &mut u32, level_val: i32) {
401    let abs_level = level_val.unsigned_abs();
402    if *suffix_length == 0 {
403        *suffix_length = 1;
404    }
405    if abs_level > (3u32 << (*suffix_length - 1)) && *suffix_length < 6 {
406        *suffix_length += 1;
407    }
408}
409
410#[rustfmt::skip]
411static TOTAL_ZEROS_1: ValueVlcTable = &[
412    (1, 0b1,          0),
413    (3, 0b011,        1),
414    (3, 0b010,        2),
415    (4, 0b0011,       3),
416    (4, 0b0010,       4),
417    (5, 0b00011,      5),
418    (5, 0b00010,      6),
419    (6, 0b000011,     7),
420    (6, 0b000010,     8),
421    (7, 0b0000011,    9),
422    (7, 0b0000010,   10),
423    (8, 0b00000011,  11),
424    (8, 0b00000010,  12),
425    (9, 0b000000011, 13),
426    (9, 0b000000010, 14),
427    (9, 0b000000001, 15),
428];
429
430#[rustfmt::skip]
431static TOTAL_ZEROS_2: ValueVlcTable = &[
432    (3, 0b111, 0),
433    (3, 0b110, 1),
434    (3, 0b101, 2),
435    (3, 0b100, 3),
436    (3, 0b011, 4),
437    (4, 0b0101, 5),
438    (4, 0b0100, 6),
439    (4, 0b0011, 7),
440    (4, 0b0010, 8),
441    (5, 0b00011, 9),
442    (5, 0b00010, 10),
443    (6, 0b000011, 11),
444    (6, 0b000010, 12),
445    (6, 0b000001, 13),
446    (6, 0b000000, 14),
447];
448
449#[rustfmt::skip]
450static TOTAL_ZEROS_3: ValueVlcTable = &[
451    (3, 0b111,  1),
452    (3, 0b110,  2),
453    (3, 0b101,  3),
454    (3, 0b100,  6),
455    (3, 0b011,  7),
456    (4, 0b0101,  0),
457    (4, 0b0100,  4),
458    (4, 0b0011,  5),
459    (4, 0b0010,  8),
460    (5, 0b00011,  9),
461    (5, 0b00010, 10),
462    (5, 0b00001, 12),
463    (6, 0b000001, 11),
464    (6, 0b000000, 13),
465];
466
467#[rustfmt::skip]
468static TOTAL_ZEROS_4: ValueVlcTable = &[
469    (3, 0b111,  1),
470    (3, 0b110,  4),
471    (3, 0b101,  5),
472    (3, 0b100,  6),
473    (3, 0b011,  8),
474    (4, 0b0101,  2),
475    (4, 0b0100,  3),
476    (4, 0b0011,  7),
477    (4, 0b0010,  9),
478    (5, 0b00011,  0),
479    (5, 0b00010, 10),
480    (5, 0b00001, 11),
481    (5, 0b00000, 12),
482];
483
484#[rustfmt::skip]
485static TOTAL_ZEROS_5: ValueVlcTable = &[
486    (3, 0b111,  3),
487    (3, 0b110,  4),
488    (3, 0b101,  5),
489    (3, 0b100,  6),
490    (3, 0b011,  7),
491    (4, 0b0101,  0),
492    (4, 0b0100,  1),
493    (4, 0b0011,  2),
494    (4, 0b0010,  8),
495    (4, 0b0001, 10),
496    (5, 0b00001,  9),
497    (5, 0b00000, 11),
498];
499
500#[rustfmt::skip]
501static TOTAL_ZEROS_6: ValueVlcTable = &[
502    (3, 0b111,  2),
503    (3, 0b110,  3),
504    (3, 0b101,  4),
505    (3, 0b100,  5),
506    (3, 0b011,  6),
507    (3, 0b010,  7),
508    (3, 0b001,  9),
509    (4, 0b0001,  8),
510    (5, 0b00001,  1),
511    (6, 0b000001,  0),
512    (6, 0b000000, 10),
513];
514
515#[rustfmt::skip]
516static TOTAL_ZEROS_7: ValueVlcTable = &[
517    (2, 0b11,  5),
518    (3, 0b101,  2),
519    (3, 0b100,  3),
520    (3, 0b011,  4),
521    (3, 0b010,  6),
522    (3, 0b001,  8),
523    (4, 0b0001,  7),
524    (5, 0b00001,  1),
525    (6, 0b000001,  0),
526    (6, 0b000000,  9),
527];
528
529#[rustfmt::skip]
530static TOTAL_ZEROS_8: ValueVlcTable = &[
531    (2, 0b11,  4),
532    (2, 0b10,  5),
533    (3, 0b011,  3),
534    (3, 0b010,  6),
535    (3, 0b001,  7),
536    (4, 0b0001,  1),
537    (5, 0b00001,  2),
538    (6, 0b000001,  0),
539    (6, 0b000000,  8),
540];
541
542#[rustfmt::skip]
543static TOTAL_ZEROS_9: ValueVlcTable = &[
544    (2, 0b11,  3),
545    (2, 0b10,  4),
546    (2, 0b01,  6),
547    (3, 0b001,  5),
548    (4, 0b0001,  2),
549    (5, 0b00001,  7),
550    (6, 0b000001,  0),
551    (6, 0b000000,  1),
552];
553
554#[rustfmt::skip]
555static TOTAL_ZEROS_10: ValueVlcTable = &[
556    (2, 0b11,  3),
557    (2, 0b10,  4),
558    (2, 0b01,  5),
559    (3, 0b001,  2),
560    (4, 0b0001,  6),
561    (5, 0b00001,  0),
562    (5, 0b00000,  1),
563];
564
565#[rustfmt::skip]
566static TOTAL_ZEROS_11: ValueVlcTable = &[
567    (1, 0b1,  4),
568    (3, 0b011,  5),
569    (3, 0b010,  3),
570    (3, 0b001,  2),
571    (4, 0b0001,  1),
572    (4, 0b0000,  0),
573];
574
575#[rustfmt::skip]
576static TOTAL_ZEROS_12: ValueVlcTable = &[
577    (1, 0b1,  3),
578    (2, 0b01,  2),
579    (3, 0b001,  4),
580    (4, 0b0001,  1),
581    (4, 0b0000,  0),
582];
583
584#[rustfmt::skip]
585static TOTAL_ZEROS_13: ValueVlcTable = &[
586    (1, 0b1,  2),
587    (2, 0b01,  3),
588    (3, 0b001,  1),
589    (3, 0b000,  0),
590];
591
592#[rustfmt::skip]
593static TOTAL_ZEROS_14: ValueVlcTable = &[
594    (1, 0b1,  2),
595    (2, 0b01,  1),
596    (2, 0b00,  0),
597];
598
599#[rustfmt::skip]
600static TOTAL_ZEROS_15: ValueVlcTable = &[
601    (1, 0b1,  1),
602    (1, 0b0,  0),
603];
604
605fn total_zeros_table_16(total_coeff: u8) -> Result<ValueVlcTable, CavlcError> {
606    match total_coeff {
607        1 => Ok(TOTAL_ZEROS_1),
608        2 => Ok(TOTAL_ZEROS_2),
609        3 => Ok(TOTAL_ZEROS_3),
610        4 => Ok(TOTAL_ZEROS_4),
611        5 => Ok(TOTAL_ZEROS_5),
612        6 => Ok(TOTAL_ZEROS_6),
613        7 => Ok(TOTAL_ZEROS_7),
614        8 => Ok(TOTAL_ZEROS_8),
615        9 => Ok(TOTAL_ZEROS_9),
616        10 => Ok(TOTAL_ZEROS_10),
617        11 => Ok(TOTAL_ZEROS_11),
618        12 => Ok(TOTAL_ZEROS_12),
619        13 => Ok(TOTAL_ZEROS_13),
620        14 => Ok(TOTAL_ZEROS_14),
621        15 => Ok(TOTAL_ZEROS_15),
622        _ => Err(CavlcError::OutOfRange {
623            field: "total_coeff for total_zeros",
624            value: total_coeff as i64,
625        }),
626    }
627}
628
629// Table 9-9(a): total_zeros for maxNumCoeff=4 (Chroma DC 4:2:0)
630
631#[rustfmt::skip]
632static TOTAL_ZEROS_CHROMA_DC_1: ValueVlcTable = &[
633    (1, 0b1,   0),
634    (2, 0b01,  1),
635    (3, 0b001, 2),
636    (3, 0b000, 3),
637];
638
639#[rustfmt::skip]
640static TOTAL_ZEROS_CHROMA_DC_2: ValueVlcTable = &[
641    (1, 0b1,  0),
642    (2, 0b01, 1),
643    (2, 0b00, 2),
644];
645
646#[rustfmt::skip]
647static TOTAL_ZEROS_CHROMA_DC_3: ValueVlcTable = &[
648    (1, 0b1, 0),
649    (1, 0b0, 1),
650];
651
652fn total_zeros_table_4(total_coeff: u8) -> Result<ValueVlcTable, CavlcError> {
653    match total_coeff {
654        1 => Ok(TOTAL_ZEROS_CHROMA_DC_1),
655        2 => Ok(TOTAL_ZEROS_CHROMA_DC_2),
656        3 => Ok(TOTAL_ZEROS_CHROMA_DC_3),
657        _ => Err(CavlcError::OutOfRange {
658            field: "total_coeff for chroma_dc total_zeros",
659            value: total_coeff as i64,
660        }),
661    }
662}
663
664fn read_total_zeros<R: BitRead>(
665    r: &mut R,
666    total_coeff: u8,
667    max_num_coeff: usize,
668) -> Result<u8, CavlcError> {
669    let table = if max_num_coeff == 4 {
670        total_zeros_table_4(total_coeff)?
671    } else {
672        total_zeros_table_16(total_coeff)?
673    };
674    read_value_vlc(r, table, "total_zeros")
675}
676
677// Table 9-10
678
679#[rustfmt::skip]
680static RUN_BEFORE_1: ValueVlcTable = &[
681    (1, 0b1, 0),
682    (1, 0b0, 1),
683];
684
685#[rustfmt::skip]
686static RUN_BEFORE_2: ValueVlcTable = &[
687    (1, 0b1, 0),
688    (2, 0b01, 1),
689    (2, 0b00, 2),
690];
691
692#[rustfmt::skip]
693static RUN_BEFORE_3: ValueVlcTable = &[
694    (2, 0b11, 0),
695    (2, 0b10, 1),
696    (2, 0b01, 2),
697    (2, 0b00, 3),
698];
699
700#[rustfmt::skip]
701static RUN_BEFORE_4: ValueVlcTable = &[
702    (2, 0b11, 0),
703    (2, 0b10, 1),
704    (2, 0b01, 2),
705    (3, 0b001, 3),
706    (3, 0b000, 4),
707];
708
709#[rustfmt::skip]
710static RUN_BEFORE_5: ValueVlcTable = &[
711    (2, 0b11, 0),
712    (2, 0b10, 1),
713    (3, 0b011, 2),
714    (3, 0b010, 3),
715    (3, 0b001, 4),
716    (3, 0b000, 5),
717];
718
719// Table 9-10, zerosLeft=6
720#[rustfmt::skip]
721static RUN_BEFORE_6: ValueVlcTable = &[
722    (2, 0b11,  0),
723    (3, 0b101,  5),
724    (3, 0b100,  6),
725    (3, 0b011,  3),
726    (3, 0b010,  4),
727    (3, 0b001,  2),
728    (3, 0b000,  1),
729];
730
731// Table 9-10, zerosLeft > 6
732#[rustfmt::skip]
733static RUN_BEFORE_GT6: ValueVlcTable = &[
734    (3, 0b111,  0),
735    (3, 0b110,  1),
736    (3, 0b101,  2),
737    (3, 0b100,  3),
738    (3, 0b011,  4),
739    (3, 0b010,  5),
740    (3, 0b001,  6),
741    (4, 0b0001,  7),
742    (5, 0b00001,  8),
743    (6, 0b000001,  9),
744    (7, 0b0000001, 10),
745    (8, 0b00000001, 11),
746    (9, 0b000000001, 12),
747    (10, 0b0000000001, 13),
748    (11, 0b00000000001, 14),
749];
750
751fn read_run_before<R: BitRead>(r: &mut R, zeros_left: u8) -> Result<u8, CavlcError> {
752    if zeros_left == 0 {
753        return Ok(0);
754    }
755
756    let table: ValueVlcTable = match zeros_left {
757        1 => RUN_BEFORE_1,
758        2 => RUN_BEFORE_2,
759        3 => RUN_BEFORE_3,
760        4 => RUN_BEFORE_4,
761        5 => RUN_BEFORE_5,
762        6 => RUN_BEFORE_6,
763        _ => RUN_BEFORE_GT6,
764    };
765    read_value_vlc(r, table, "run_before")
766}
767
768pub(crate) fn residual_block_cavlc<R: BitRead>(
769    r: &mut R,
770    coeff_level: &mut [i32],
771    start_idx: usize,
772    end_idx: usize,
773    max_num_coeff: usize,
774    nc: CavlcContext,
775) -> Result<u8, CavlcError> {
776    // Zero the output range.
777    for c in coeff_level[start_idx..=end_idx].iter_mut() {
778        *c = 0;
779    }
780
781    let (total_coeff, trailing_ones) = read_coeff_token(r, nc)?;
782
783    if total_coeff == 0 {
784        return Ok(0);
785    }
786
787    if total_coeff as usize > max_num_coeff {
788        return Err(CavlcError::OutOfRange {
789            field: "TotalCoeff",
790            value: total_coeff as i64,
791        });
792    }
793
794    // coefficients in reverse scan order (highest frequency first)
795    let mut levels = [0i32; 16];
796
797    for item in levels.iter_mut().take(trailing_ones as usize) {
798        let negative = r.read_bit("trailing_ones_sign_flag")?;
799        *item = if negative { -1 } else { 1 };
800    }
801
802    let remaining = total_coeff as usize - trailing_ones as usize;
803
804    let mut suffix_length: u32 = if total_coeff > 10 && trailing_ones < 3 {
805        1
806    } else {
807        0
808    };
809
810    let level_start = trailing_ones as usize;
811    for i in 0..remaining {
812        let mut level_val = read_level(r, suffix_length)?;
813
814        if i == 0 && trailing_ones < 3 {
815            if level_val > 0 {
816                level_val += 1;
817            } else {
818                level_val -= 1;
819            }
820        }
821
822        levels[level_start + i] = level_val;
823
824        update_suffix_length(&mut suffix_length, level_val);
825    }
826
827    let total_zeros = if (total_coeff as usize) < max_num_coeff {
828        read_total_zeros(r, total_coeff, max_num_coeff)?
829    } else {
830        0
831    };
832    if (total_coeff as usize) + (total_zeros as usize) > max_num_coeff {
833        return Err(CavlcError::OutOfRange {
834            field: "total_coeff + total_zeros exceeds max_num_coeff",
835            value: (total_coeff as i64) + (total_zeros as i64),
836        });
837    }
838
839    let mut runs = [0u8; 16];
840    let mut zeros_left = total_zeros;
841
842    for item in runs.iter_mut().take(total_coeff as usize - 1) {
843        if zeros_left > 0 {
844            *item = read_run_before(r, zeros_left)?;
845            zeros_left = zeros_left
846                .checked_sub(*item)
847                .ok_or(CavlcError::OutOfRange {
848                    field: "zeros_left underflow in run_before",
849                    value: -(*item as i64),
850                })?;
851        }
852    }
853    // last coefficient absorbs any remaining zeros
854    runs[total_coeff as usize - 1] = zeros_left;
855
856    let mut coeff_idx = (total_coeff as usize + total_zeros as usize)
857        .checked_sub(1)
858        .ok_or(CavlcError::OutOfRange {
859            field: "coefficient position",
860            value: 0,
861        })?;
862
863    for i in 0..total_coeff as usize {
864        let pos = start_idx + coeff_idx;
865        if pos > end_idx {
866            return Err(CavlcError::OutOfRange {
867                field: "coefficient position exceeds end_idx",
868                value: pos as i64,
869            });
870        }
871        coeff_level[pos] = levels[i];
872
873        if i < total_coeff as usize - 1 {
874            coeff_idx =
875                coeff_idx
876                    .checked_sub(1 + runs[i] as usize)
877                    .ok_or(CavlcError::OutOfRange {
878                        field: "coeff_idx underflow",
879                        value: -(1i64),
880                    })?;
881        }
882    }
883    Ok(total_coeff)
884}
885
886#[cfg(test)]
887mod tests {
888    use super::*;
889
890    fn check_prefix_free_coeff_token(table: CoeffTokenTable, name: &str) {
891        for i in 0..table.len() {
892            for j in (i + 1)..table.len() {
893                let (len_a, bits_a, tc_a, to_a) = table[i];
894                let (len_b, bits_b, tc_b, to_b) = table[j];
895                if len_a == len_b {
896                    // Same length: just check they differ in bits (no duplicate codes)
897                    assert_ne!(
898                        bits_a, bits_b,
899                        "{name}: duplicate code at entries {i} (TC={tc_a},TO={to_a}) and {j} (TC={tc_b},TO={to_b}), len={len_a} bits={bits_a:#b}"
900                    );
901                } else {
902                    // Different length: check neither is a prefix of the other
903                    let (short_len, short_bits, long_len, long_bits) = if len_a < len_b {
904                        (len_a, bits_a, len_b, bits_b)
905                    } else {
906                        (len_b, bits_b, len_a, bits_a)
907                    };
908                    let shifted = long_bits >> (long_len - short_len);
909                    assert_ne!(
910                        shifted, short_bits,
911                        "{name}: prefix collision between entry {i} (len={len_a},bits={bits_a:#b},TC={tc_a},TO={to_a}) and entry {j} (len={len_b},bits={bits_b:#b},TC={tc_b},TO={to_b})"
912                    );
913                }
914            }
915        }
916    }
917
918    fn check_coeff_token_coverage(table: CoeffTokenTable, max_num_coeff: u8, name: &str) {
919        let mut seen_pairs = std::collections::HashSet::new();
920        let mut seen_codes = std::collections::HashSet::new();
921        for (idx, &(len, bits, tc, to)) in table.iter().enumerate() {
922            assert!(len > 0, "{}[{}]: zero-length code", name, idx);
923            assert!(
924                (bits as u32) < (1u32 << len),
925                "{}[{}]: bits {:#b} don't fit in {} bits",
926                name,
927                idx,
928                bits,
929                len
930            );
931            assert!(
932                to <= tc.min(3),
933                "{}[{}]: TO={} > min(3, TC={})",
934                name,
935                idx,
936                to,
937                tc
938            );
939            assert!(
940                tc <= max_num_coeff,
941                "{}[{}]: TC={} > max={}",
942                name,
943                idx,
944                tc,
945                max_num_coeff
946            );
947            assert!(
948                seen_pairs.insert((tc, to)),
949                "{}[{}]: duplicate (TC={}, TO={})",
950                name,
951                idx,
952                tc,
953                to
954            );
955            assert!(
956                seen_codes.insert((len, bits)),
957                "{}[{}]: duplicate code (len={}, bits={:#b})",
958                name,
959                idx,
960                len,
961                bits
962            );
963        }
964        // Check all valid (TC, TO) pairs are present
965        for tc in 0..=max_num_coeff {
966            for to in 0..=tc.min(3) {
967                assert!(
968                    seen_pairs.contains(&(tc, to)),
969                    "{}: missing (TC={}, TO={})",
970                    name,
971                    tc,
972                    to
973                );
974            }
975        }
976    }
977
978    #[test]
979    fn coeff_token_tables_are_prefix_free() {
980        check_prefix_free_coeff_token(COEFF_TOKEN_0, "COEFF_TOKEN_0");
981        check_prefix_free_coeff_token(COEFF_TOKEN_2, "COEFF_TOKEN_2");
982        check_prefix_free_coeff_token(COEFF_TOKEN_4, "COEFF_TOKEN_4");
983        check_prefix_free_coeff_token(COEFF_TOKEN_CHROMA_DC, "COEFF_TOKEN_CHROMA_DC");
984    }
985
986    #[test]
987    fn coeff_token_0_complete_coverage() {
988        check_coeff_token_coverage(COEFF_TOKEN_0, 16, "COEFF_TOKEN_0");
989    }
990
991    #[test]
992    fn coeff_token_2_complete_coverage() {
993        check_coeff_token_coverage(COEFF_TOKEN_2, 16, "COEFF_TOKEN_2");
994    }
995
996    #[test]
997    fn coeff_token_4_complete_coverage() {
998        check_coeff_token_coverage(COEFF_TOKEN_4, 16, "COEFF_TOKEN_4");
999    }
1000
1001    #[test]
1002    fn coeff_token_chroma_dc_complete_coverage() {
1003        check_coeff_token_coverage(COEFF_TOKEN_CHROMA_DC, 4, "COEFF_TOKEN_CHROMA_DC");
1004    }
1005
1006    fn check_prefix_free_value_vlc(table: ValueVlcTable, name: &str) {
1007        for i in 0..table.len() {
1008            for j in (i + 1)..table.len() {
1009                let (len_a, bits_a, val_a) = table[i];
1010                let (len_b, bits_b, val_b) = table[j];
1011                if len_a == len_b {
1012                    assert_ne!(
1013                        bits_a, bits_b,
1014                        "{name}: duplicate code at entries {i} (val={val_a}) and {j} (val={val_b}), len={len_a} bits={bits_a:#b}"
1015                    );
1016                } else {
1017                    let (short_len, short_bits, long_len, long_bits) = if len_a < len_b {
1018                        (len_a, bits_a, len_b, bits_b)
1019                    } else {
1020                        (len_b, bits_b, len_a, bits_a)
1021                    };
1022                    let shifted = long_bits >> (long_len - short_len);
1023                    assert_ne!(
1024                        shifted, short_bits,
1025                        "{name}: prefix collision between entry {i} (len={len_a},bits={bits_a:#b},val={val_a}) and entry {j} (len={len_b},bits={bits_b:#b},val={val_b})"
1026                    );
1027                }
1028            }
1029        }
1030    }
1031
1032    fn check_value_vlc_coverage(table: ValueVlcTable, max_val: u8, name: &str) {
1033        let mut seen_vals = std::collections::HashSet::new();
1034        let mut seen_codes = std::collections::HashSet::new();
1035        for (idx, &(len, bits, val)) in table.iter().enumerate() {
1036            assert!(len > 0, "{}[{}]: zero-length code", name, idx);
1037            assert!(
1038                (bits as u32) < (1u32 << len),
1039                "{}[{}]: bits {:#b} don't fit in {} bits",
1040                name,
1041                idx,
1042                bits,
1043                len
1044            );
1045            assert!(
1046                val <= max_val,
1047                "{}[{}]: val={} > max={}",
1048                name,
1049                idx,
1050                val,
1051                max_val
1052            );
1053            assert!(
1054                seen_vals.insert(val),
1055                "{}[{}]: duplicate value {}",
1056                name,
1057                idx,
1058                val
1059            );
1060            assert!(
1061                seen_codes.insert((len, bits)),
1062                "{}[{}]: duplicate code (len={}, bits={:#b})",
1063                name,
1064                idx,
1065                len,
1066                bits
1067            );
1068        }
1069        for v in 0..=max_val {
1070            assert!(seen_vals.contains(&v), "{}: missing value {}", name, v);
1071        }
1072    }
1073
1074    #[test]
1075    fn total_zeros_luma_tables_complete_and_prefix_free() {
1076        let tables: &[(ValueVlcTable, u8, &str)] = &[
1077            (TOTAL_ZEROS_1, 15, "TOTAL_ZEROS_1"),
1078            (TOTAL_ZEROS_2, 14, "TOTAL_ZEROS_2"),
1079            (TOTAL_ZEROS_3, 13, "TOTAL_ZEROS_3"),
1080            (TOTAL_ZEROS_4, 12, "TOTAL_ZEROS_4"),
1081            (TOTAL_ZEROS_5, 11, "TOTAL_ZEROS_5"),
1082            (TOTAL_ZEROS_6, 10, "TOTAL_ZEROS_6"),
1083            (TOTAL_ZEROS_7, 9, "TOTAL_ZEROS_7"),
1084            (TOTAL_ZEROS_8, 8, "TOTAL_ZEROS_8"),
1085            (TOTAL_ZEROS_9, 7, "TOTAL_ZEROS_9"),
1086            (TOTAL_ZEROS_10, 6, "TOTAL_ZEROS_10"),
1087            (TOTAL_ZEROS_11, 5, "TOTAL_ZEROS_11"),
1088            (TOTAL_ZEROS_12, 4, "TOTAL_ZEROS_12"),
1089            (TOTAL_ZEROS_13, 3, "TOTAL_ZEROS_13"),
1090            (TOTAL_ZEROS_14, 2, "TOTAL_ZEROS_14"),
1091            (TOTAL_ZEROS_15, 1, "TOTAL_ZEROS_15"),
1092        ];
1093        for &(table, max_val, name) in tables {
1094            check_prefix_free_value_vlc(table, name);
1095            check_value_vlc_coverage(table, max_val, name);
1096        }
1097    }
1098
1099    #[test]
1100    fn total_zeros_chroma_dc_tables_complete_and_prefix_free() {
1101        let tables: &[(ValueVlcTable, u8, &str)] = &[
1102            (TOTAL_ZEROS_CHROMA_DC_1, 3, "TOTAL_ZEROS_CHROMA_DC_1"),
1103            (TOTAL_ZEROS_CHROMA_DC_2, 2, "TOTAL_ZEROS_CHROMA_DC_2"),
1104            (TOTAL_ZEROS_CHROMA_DC_3, 1, "TOTAL_ZEROS_CHROMA_DC_3"),
1105        ];
1106        for &(table, max_val, name) in tables {
1107            check_prefix_free_value_vlc(table, name);
1108            check_value_vlc_coverage(table, max_val, name);
1109        }
1110    }
1111
1112    #[test]
1113    fn run_before_tables_complete_and_prefix_free() {
1114        let tables: &[(ValueVlcTable, u8, &str)] = &[
1115            (RUN_BEFORE_1, 1, "RUN_BEFORE_1"),
1116            (RUN_BEFORE_2, 2, "RUN_BEFORE_2"),
1117            (RUN_BEFORE_3, 3, "RUN_BEFORE_3"),
1118            (RUN_BEFORE_4, 4, "RUN_BEFORE_4"),
1119            (RUN_BEFORE_5, 5, "RUN_BEFORE_5"),
1120            (RUN_BEFORE_6, 6, "RUN_BEFORE_6"),
1121            (RUN_BEFORE_GT6, 14, "RUN_BEFORE_GT6"),
1122        ];
1123        for &(table, max_val, name) in tables {
1124            check_prefix_free_value_vlc(table, name);
1125            check_value_vlc_coverage(table, max_val, name);
1126        }
1127    }
1128
1129    #[test]
1130    fn coeff_token_tables_sorted_by_length() {
1131        for (table, name) in [
1132            (COEFF_TOKEN_0, "COEFF_TOKEN_0"),
1133            (COEFF_TOKEN_2, "COEFF_TOKEN_2"),
1134            (COEFF_TOKEN_4, "COEFF_TOKEN_4"),
1135            (COEFF_TOKEN_CHROMA_DC, "COEFF_TOKEN_CHROMA_DC"),
1136        ] {
1137            for i in 1..table.len() {
1138                assert!(
1139                    table[i].0 >= table[i - 1].0,
1140                    "{name}: not sorted by length at index {i}: {} < {}",
1141                    table[i].0,
1142                    table[i - 1].0
1143                );
1144            }
1145        }
1146    }
1147
1148    #[test]
1149    fn value_vlc_tables_sorted_by_length() {
1150        let tables: &[(ValueVlcTable, &str)] = &[
1151            (TOTAL_ZEROS_1, "TOTAL_ZEROS_1"),
1152            (TOTAL_ZEROS_2, "TOTAL_ZEROS_2"),
1153            (TOTAL_ZEROS_3, "TOTAL_ZEROS_3"),
1154            (TOTAL_ZEROS_4, "TOTAL_ZEROS_4"),
1155            (TOTAL_ZEROS_5, "TOTAL_ZEROS_5"),
1156            (TOTAL_ZEROS_6, "TOTAL_ZEROS_6"),
1157            (TOTAL_ZEROS_7, "TOTAL_ZEROS_7"),
1158            (TOTAL_ZEROS_8, "TOTAL_ZEROS_8"),
1159            (TOTAL_ZEROS_9, "TOTAL_ZEROS_9"),
1160            (TOTAL_ZEROS_10, "TOTAL_ZEROS_10"),
1161            (TOTAL_ZEROS_11, "TOTAL_ZEROS_11"),
1162            (TOTAL_ZEROS_12, "TOTAL_ZEROS_12"),
1163            (TOTAL_ZEROS_13, "TOTAL_ZEROS_13"),
1164            (TOTAL_ZEROS_14, "TOTAL_ZEROS_14"),
1165            (TOTAL_ZEROS_15, "TOTAL_ZEROS_15"),
1166            (TOTAL_ZEROS_CHROMA_DC_1, "TOTAL_ZEROS_CHROMA_DC_1"),
1167            (TOTAL_ZEROS_CHROMA_DC_2, "TOTAL_ZEROS_CHROMA_DC_2"),
1168            (TOTAL_ZEROS_CHROMA_DC_3, "TOTAL_ZEROS_CHROMA_DC_3"),
1169            (RUN_BEFORE_1, "RUN_BEFORE_1"),
1170            (RUN_BEFORE_2, "RUN_BEFORE_2"),
1171            (RUN_BEFORE_3, "RUN_BEFORE_3"),
1172            (RUN_BEFORE_4, "RUN_BEFORE_4"),
1173            (RUN_BEFORE_5, "RUN_BEFORE_5"),
1174            (RUN_BEFORE_6, "RUN_BEFORE_6"),
1175            (RUN_BEFORE_GT6, "RUN_BEFORE_GT6"),
1176        ];
1177        for &(table, name) in tables {
1178            for i in 1..table.len() {
1179                assert!(
1180                    table[i].0 >= table[i - 1].0,
1181                    "{name}: not sorted by length at index {i}: {} < {}",
1182                    table[i].0,
1183                    table[i - 1].0
1184                );
1185            }
1186        }
1187    }
1188}