nx_h264_cabac_mb.nx source
↩ module page · 158 lines · 7973 B
1// nx_h264_cabac_mb.nx -- H.264 CABAC I-slice macroblock syntax (clauses 9.3.2.5, 9.3.3.1.1, Table 9-36).
2// STEP 3, on the KAT-verified engine (nx_h264_cabac.nx, clause 9.3.1) and the residual layer
3// (nx_h264_cabac_residual.nx, gate 8/8). I-slices only: an I-frame poster needs no motion vectors
4// and no inter prediction, which removes most of full CABAC from scope.
5//
6// All ctxIdxOffsets are NAMED (rule 11) and carry their spec table reference, so a wrong constant is
7// reviewable against the standard instead of being a bare number.
8// license_tier: ORIGINAL
9import "nx_syscalls.nx"
10import "nx_h264_cabac.nx"
11import "nx_h264_cabac_ctxinc.nx"
12
13const CMB_OFF_MBTYPE_I: i64 = 3 // Table 9-34: mb_type, I slices
14const CMB_CTX_TERMINATE: i64 = 276 // clause 9.3.3.2.2.3: the end-of-slice / I_PCM terminate context
15const CMB_OFF_CHROMA_PRED: i64 = 64 // Table 9-34: intra_chroma_pred_mode
16const CMB_OFF_PREV_I4: i64 = 68 // Table 9-34: prev_intra4x4_pred_mode_flag
17const CMB_OFF_REM_I4: i64 = 69 // Table 9-34: rem_intra4x4_pred_mode
18const CMB_OFF_CBP_LUMA: i64 = 73 // Table 9-34: coded_block_pattern, luma prefix
19const CMB_OFF_CBP_CHROMA: i64 = 77 // Table 9-34: coded_block_pattern, chroma suffix
20const CMB_MBTYPE_I_NXN: i64 = 0
21const CMB_MBTYPE_I_PCM: i64 = 25
22const CMB_REM_I4_BITS: i64 = 3 // FL binarization, cMax=7
23
24// mb_type for an I slice (Table 9-36 binarization + Table 9-39 ctxIdxInc).
25// condA/condB are condTermFlagA/B: 1 when that neighbour exists and is NOT I_NxN.
26// Returns 0 for I_NxN, 25 for I_PCM, else 1..24 encoding predMode/cbpChroma/cbpLuma.
27func cmb_mbtype_i(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64, condA: i64, condB: i64) -> i64 {
28 let b0: i64 = cab_decision(cab, ctx, CMB_OFF_MBTYPE_I + condA + condB, rlps, tlps, tmps)
29 if b0 == 0 { return CMB_MBTYPE_I_NXN }
30 if cab_terminate(cab) == 1 { return CMB_MBTYPE_I_PCM }
31 let cbpLuma: i64 = cab_decision(cab, ctx, CMB_OFF_MBTYPE_I + 3, rlps, tlps, tmps)
32 let b3: i64 = cab_decision(cab, ctx, CMB_OFF_MBTYPE_I + 4, rlps, tlps, tmps)
33 var cbpChroma: i64 = 0
34 if b3 != 0 {
35 // second chroma bin uses ctxIdxInc 5 ONLY on this branch (Table 9-39 "5,6")
36 let b4: i64 = cab_decision(cab, ctx, CMB_OFF_MBTYPE_I + 5, rlps, tlps, tmps)
37 cbpChroma = 1 + b4
38 }
39 let p0: i64 = cab_decision(cab, ctx, CMB_OFF_MBTYPE_I + 6, rlps, tlps, tmps)
40 let p1: i64 = cab_decision(cab, ctx, CMB_OFF_MBTYPE_I + 7, rlps, tlps, tmps)
41 let predMode: i64 = 2 * p0 + p1
42 return 1 + predMode + 4 * cbpChroma + 12 * cbpLuma
43}
44
45// Does this mb_type mean Intra_16x16? (1..24 are the I_16x16 family)
46func cmb_is_i16x16(mbt: i64) -> i64 {
47 if mbt < 1 { return 0 }
48 if mbt > 24 { return 0 }
49 return 1
50}
51// Decompose an I_16x16 mb_type back into its three fields.
52func cmb_i16_predmode(mbt: i64) -> i64 { if cmb_is_i16x16(mbt) == 0 { return 0 - 1 } return (mbt - 1) % 4 }
53func cmb_i16_cbpchroma(mbt: i64) -> i64 { if cmb_is_i16x16(mbt) == 0 { return 0 - 1 } return ((mbt - 1) / 4) % 3 }
54func cmb_i16_cbpluma(mbt: i64) -> i64 {
55 if cmb_is_i16x16(mbt) == 0 { return 0 - 1 }
56 if (mbt - 1) >= 12 { return 15 }
57 return 0
58}
59
60// prev_intra4x4_pred_mode_flag (single bin, ctxIdxInc 0)
61func cmb_prev_i4(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64) -> i64 {
62 return cab_decision(cab, ctx, CMB_OFF_PREV_I4, rlps, tlps, tmps)
63}
64// rem_intra4x4_pred_mode: FL binarization, 3 bins, all ctxIdxInc 0, LSB first (9.3.2.5)
65func cmb_rem_i4(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64) -> i64 {
66 var v: i64 = 0
67 var i: i64 = 0
68 while i < CMB_REM_I4_BITS {
69 let b: i64 = cab_decision(cab, ctx, CMB_OFF_REM_I4, rlps, tlps, tmps)
70 v = v | (b << i)
71 i = i + 1
72 }
73 return v
74}
75// intra_chroma_pred_mode: TU cMax=3. bin0 ctxIdxInc = condA+condB, bins 1..2 ctxIdxInc = 3.
76func cmb_chroma_pred(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64, condA: i64, condB: i64) -> i64 {
77 if cab_decision(cab, ctx, CMB_OFF_CHROMA_PRED + condA + condB, rlps, tlps, tmps) == 0 { return 0 }
78 if cab_decision(cab, ctx, CMB_OFF_CHROMA_PRED + 3, rlps, tlps, tmps) == 0 { return 1 }
79 if cab_decision(cab, ctx, CMB_OFF_CHROMA_PRED + 3, rlps, tlps, tmps) == 0 { return 2 }
80 return 3
81}
82// coded_block_pattern luma: 4 bins, ctxIdxInc from the two neighbouring cbp bits (9.3.3.1.1.4).
83// condA[i]/condB[i] are 1 when that neighbouring 8x8 has NO coefficients.
84func cmb_cbp_luma(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64, condA: *i64, condB: *i64) -> i64 {
85 var cbp: i64 = 0
86 var i: i64 = 0
87 while i < 4 {
88 let inc: i64 = condA[i] + 2 * condB[i]
89 let b: i64 = cab_decision(cab, ctx, CMB_OFF_CBP_LUMA + inc, rlps, tlps, tmps)
90 cbp = cbp | (b << i)
91 i = i + 1
92 }
93 return cbp
94}
95// coded_block_pattern chroma: bin0 inc = condA+2*condB; if set, bin1 inc = 4 + condA2+2*condB2.
96func cmb_cbp_chroma(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64,
97 condA0: i64, condB0: i64, condA1: i64, condB1: i64) -> i64 {
98 if cab_decision(cab, ctx, CMB_OFF_CBP_CHROMA + condA0 + 2 * condB0, rlps, tlps, tmps) == 0 { return 0 }
99 if cab_decision(cab, ctx, CMB_OFF_CBP_CHROMA + 4 + condA1 + 2 * condB1, rlps, tlps, tmps) == 0 { return 1 }
100 return 2
101}
102
103// ---- ctxBlockCat plumbing (Table 9-34 offsets + clause 9.3.3.1.1.9) -------------------------
104// These are the BASES the residual layer takes as parameters, so the whole CABAC decoder-side
105// contract lives here and integration is only "call these from the macroblock loop".
106const CMB_OFF_CBF: i64 = 85 // Table 9-34: coded_block_flag base
107const CMB_OFF_SIG: i64 = 105 // significant_coeff_flag base (frame-coded)
108const CMB_OFF_LAST: i64 = 166 // last_significant_coeff_flag base (frame-coded)
109const CMB_OFF_ABS: i64 = 227 // coeff_abs_level_minus1 base
110const CMB_CAT_MAX: i64 = 4 // ctxBlockCat 0..4 for non-8x8 I-slice residual
111
112// ctxBlockCat -> per-category offsets. Cat 0=Intra16x16DC 1=Intra16x16AC 2=Luma4x4 3=ChromaDC 4=ChromaAC
113func cmb_cbf_catoff(cat: i64) -> i64 {
114 if cat < 0 { return 0 - 1 }
115 if cat > CMB_CAT_MAX { return 0 - 1 }
116 return cat * 4
117}
118func cmb_sig_catoff(cat: i64) -> i64 {
119 if cat < 0 { return 0 - 1 }
120 if cat == 0 { return 0 }
121 if cat == 1 { return 15 }
122 if cat == 2 { return 29 }
123 if cat == 3 { return 44 }
124 if cat == 4 { return 47 }
125 return 0 - 1
126}
127func cmb_abs_catoff(cat: i64) -> i64 {
128 if cat < 0 { return 0 - 1 }
129 if cat == 0 { return 0 }
130 if cat == 1 { return 10 }
131 if cat == 2 { return 20 }
132 if cat == 3 { return 30 }
133 if cat == 4 { return 39 }
134 return 0 - 1
135}
136// number of coefficients carried by each category
137func cmb_cat_maxcoeff(cat: i64) -> i64 {
138 if cat == 0 { return 16 }
139 if cat == 1 { return 15 }
140 if cat == 2 { return 16 }
141 if cat == 3 { return 4 }
142 if cat == 4 { return 15 }
143 return 0 - 1
144}
145// absolute context bases to hand to the residual layer
146func cmb_sig_base(cat: i64) -> i64 { let o: i64 = cmb_sig_catoff(cat); if o < 0 { return 0 - 1 } return CMB_OFF_SIG + o }
147func cmb_last_base(cat: i64) -> i64 { let o: i64 = cmb_sig_catoff(cat); if o < 0 { return 0 - 1 } return CMB_OFF_LAST + o }
148func cmb_abs_base(cat: i64) -> i64 { let o: i64 = cmb_abs_catoff(cat); if o < 0 { return 0 - 1 } return CMB_OFF_ABS + o }
149
150// coded_block_flag (9.3.3.1.1.9). condA/condB are 1 when that neighbour block has coefficients;
151// an UNAVAILABLE neighbour contributes 0 for an intra block, which is why the first macroblock of
152// a frame is decodable with condA=condB=0.
153func cmb_coded_block_flag(cab: *i64, ctx: *i64, rlps: *i64, tlps: *i64, tmps: *i64,
154 cat: i64, condA: i64, condB: i64) -> i64 {
155 let o: i64 = cmb_cbf_catoff(cat)
156 if o < 0 { return 0 - 1 }
157 return cab_decision(cab, ctx, CMB_OFF_CBF + o + cci_cbf(condA, condB), rlps, tlps, tmps)
158}