nx_h264_cabac_residual.nx source
↩ module page · 118 lines · 4974 B
1// nx_h264_cabac_residual.nx -- H.264 CABAC residual block decoding (clause 9.3.2.3 / 9.3.3.1.3).
2// STEP 2, built on the STEP-1 arithmetic engine in nx_h264_cabac.nx which is KAT-verified against
3// clause 9.3.1 (gate ALL-PASS). Decodes ONE residual block: the significance map, then the levels
4// in reverse scan order, then signs.
5//
6// WHY THIS EXISTS: ~50% of the recording corpus is CABAC-coded and the poster/dead-air paths refuse
7// it outright (rc=10), which is the single largest measured blocker on gallery posters (117 of 236
8// files needing work, 2026-07-31). The arithmetic engine already existed and was never built on.
9//
10// SCOPE + HONESTY: binarization and context routing follow the spec, and the teeth below check the
11// structure that can be checked without a reference decoder. END-TO-END CORRECTNESS IS NOT PROVEN
12// HERE -- that requires decoding a real CABAC stream and looking at the image. Do not claim CABAC
13// posters work until that runs.
14// license_tier: ORIGINAL
15import "nx_syscalls.nx"
16import "nx_h264_cabac.nx"
17import "nx_h264_cabac_ctxinc.nx"
18
19const CBR_MAXCOEFF: i64 = 64 // largest block we handle (8x8 luma); 4x4 uses 16
20const CBR_UNARY_MAX: i64 = 13 // coeff_abs_level_minus1 prefix cap before the EG0 suffix
21const CBR_EG0_MAXK: i64 = 32
22const CBR_MAX_LEVEL: i64 = 32768 // a coefficient level beyond this cannot occur in 8-bit H.264; past it the stream is corrupt and we REFUSE rather than emit a value that overflows the coefficient arrays // bound on the Exp-Golomb suffix so a corrupt stream cannot spin
23
24// Exp-Golomb order-0 suffix, all bypass bins. Bounded: a corrupt stream must not loop forever.
25func cbr_eg0_bypass(cab: *i64) -> i64 {
26 var k: i64 = 0
27 var val: i64 = 0
28 var go: i64 = 1
29 while go == 1 {
30 if k >= CBR_EG0_MAXK { return 0 - 1 } else {
31 if cab_bypass(cab) == 1 {
32 val = val + (1 << k)
33 k = k + 1
34 } else { go = 0 }
35 }
36 }
37 var suffix: i64 = 0
38 var i: i64 = 0
39 while i < k {
40 suffix = (suffix << 1) | cab_bypass(cab)
41 i = i + 1
42 }
43 return val + suffix
44}
45
46// Significance map (9.3.2.3). Fills sigflag[0..maxc-1] with 1 where a coefficient is present.
47// Returns the number of coefficients present, or 0-1 if the stream is inconsistent.
48func cbr_sigmap(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64,
49 base_sig: i64, base_last: i64, maxc: i64, sigflag: *i64) -> i64 {
50 if maxc <= 0 { return 0 - 1 }
51 if maxc > CBR_MAXCOEFF { return 0 - 1 }
52 var i: i64 = 0
53 while i < maxc { sigflag[i] = 0; i = i + 1 }
54 var n: i64 = 0
55 var pos: i64 = 0
56 var go: i64 = 1
57 while go == 1 {
58 if pos >= maxc - 1 { go = 0 } else {
59 let s: i64 = cab_decision(cab, ctx, base_sig + cci_sig4x4(pos), rlps, tlps, tmps)
60 if s == 1 {
61 sigflag[pos] = 1
62 n = n + 1
63 let l: i64 = cab_decision(cab, ctx, base_last + cci_sig4x4(pos), rlps, tlps, tmps)
64 if l == 1 { go = 0; pos = maxc }
65 }
66 if go == 1 { pos = pos + 1 }
67 }
68 }
69 // if we ran to the final position without a last-flag, that coefficient is implicitly present
70 if pos == maxc - 1 {
71 sigflag[maxc - 1] = 1
72 n = n + 1
73 }
74 return n
75}
76
77// Levels in REVERSE scan order (9.3.3.1.3), with signs. Writes signed levels into out[].
78// Returns the number of levels decoded.
79func cbr_levels(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64,
80 base_abs: i64, maxc: i64, sigflag: *i64, out: *i64) -> i64 {
81 var i: i64 = 0
82 while i < maxc { out[i] = 0; i = i + 1 }
83 var numGt1: i64 = 0
84 var numEq1: i64 = 0
85 var done: i64 = 0
86 var p: i64 = maxc - 1
87 while p >= 0 {
88 if sigflag[p] == 1 {
89 let c0: i64 = base_abs + cci_abslevel_bin0(numGt1, numEq1)
90 var level: i64 = 1
91 if cab_decision(cab, ctx, c0, rlps, tlps, tmps) == 1 {
92 let cn: i64 = base_abs + cci_abslevel_binN(numGt1)
93 var k: i64 = 0
94 var go: i64 = 1
95 while go == 1 {
96 if k >= CBR_UNARY_MAX { go = 0 } else {
97 if cab_decision(cab, ctx, cn, rlps, tlps, tmps) == 1 { k = k + 1 } else { go = 0 }
98 }
99 }
100 if k >= CBR_UNARY_MAX {
101 let eg: i64 = cbr_eg0_bypass(cab)
102 if eg < 0 { return 0 - 1 }
103 level = CBR_UNARY_MAX + 1 + eg
104 if level > CBR_MAX_LEVEL { return 0 - 1 }
105 } else {
106 level = k + 2
107 }
108 numGt1 = numGt1 + 1
109 } else {
110 numEq1 = numEq1 + 1
111 }
112 if cab_bypass(cab) == 1 { out[p] = 0 - level } else { out[p] = level }
113 done = done + 1
114 }
115 p = p - 1
116 }
117 return done
118}