nx_h264_cabac.nx source
↩ module page · 100 lines · 5984 B
1// nx_h264_cabac.nx -- H.264 CABAC arithmetic decoding ENGINE (ITU-T H.264 clause 9.3), STEP 1 core.
2// The arithmetic core (DecodeDecision/DecodeBypass/DecodeTerminate + renormalization) is IDENTICAL
3// to HEVC's and is copied VERBATIM from the gated nx_hevc_cabac engine, including the normative
4// rangeTabLps[64x4]/transIdxLps[64]/transIdxMps[64] tables. The H.264-specific delta lives in
5// context-variable init from the (m,n) init tables (clause 9.3.1.1) -> cab_ctx_init_mn.
6//
7// This is the ENGINE only. The I-slice syntax-element context tables + binarizations
8// (mb_type, coded_block_pattern, coded_block_flag, significant_coeff_flag,
9// last_significant_coeff_flag, coeff_abs_level_minus1, mb_qp_delta, prev_intra4x4_pred_mode,
10// intra_chroma_pred_mode, transform_size_8x8_flag, end_of_slice) are the NEXT rung and plug
11// their (m,n) rows into cab_ctx_init_mn + drive cab_decision with the derived ctxIdx.
12//
13// LIB (no main); gated by nx_h264_cabac_gate. license_tier: ORIGINAL
14// genealogy_id: itu_t_h264_sec9_3_cabac lineage_id: hevc_arith_engine_reuse + h264_mn_ctxinit
15import "nx_syscalls.nx"
16
17// fill an i64 array from a space-separated number string; returns count
18func cab_parse_nums(s: *u8, out: *i64) -> i64 {
19 var n: i64 = 0
20 var i: i64 = 0
21 var cur: i64 = 0
22 var has: i64 = 0
23 while s[i] != (0 as u8) {
24 let c: i64 = s[i] as i64
25 if c >= 48 { if c <= 57 { cur = cur * 10 + (c - 48); has = 1 } else { if has == 1 { out[n] = cur; n = n + 1; cur = 0; has = 0 } } } else { if has == 1 { out[n] = cur; n = n + 1; cur = 0; has = 0 } }
26 i = i + 1
27 }
28 if has == 1 { out[n] = cur; n = n + 1 }
29 return n
30}
31
32func cab_clip3(lo: i64, hi: i64, v: i64) -> i64 { if v < lo { return lo } if v > hi { return hi } return v }
33
34// Load the normative arithmetic tables. rlps[256] (=rangeTabLps 64x4 flat), tlps[64], tmps[64].
35// Returns 1 iff all three parsed to their canonical lengths (256/64/64), else 0 (fail-closed).
36func cab_load_tables(rlps: *i64, tlps: *i64, tmps: *i64) -> i64 {
37 let nr: i64 = cab_parse_nums("128 176 208 240 128 167 197 227 128 158 187 216 123 150 178 205 116 142 169 195 111 135 160 185 105 128 152 175 100 122 144 166 95 116 137 158 90 110 130 150 85 104 123 142 81 99 117 135 77 94 111 128 73 89 105 122 69 85 100 116 66 80 95 110 62 76 90 104 59 72 86 99 56 69 81 94 53 65 77 89 51 62 73 85 48 59 69 80 46 56 66 76 43 53 63 72 41 50 59 69 39 48 56 65 37 45 54 62 35 43 51 59 33 41 48 56 32 39 46 53 30 37 43 50 28 35 41 47 27 33 39 45 26 31 37 43 24 30 35 41 23 28 33 39 22 27 32 37 21 26 30 35 20 24 29 33 19 23 27 31 18 22 26 30 17 21 25 28 16 20 23 27 15 19 22 25 14 18 21 24 14 17 20 23 13 16 19 22 12 15 18 21 12 14 17 20 11 14 16 19 11 13 15 18 10 12 15 17 10 12 14 16 9 11 13 15 9 11 12 14 8 10 12 14 8 9 11 13 7 9 11 12 7 9 10 12 7 8 10 11 6 8 9 11 6 7 9 10 6 7 8 9 2 2 2 2\x00" as *u8, rlps)
38 let nl: i64 = cab_parse_nums("0 0 1 2 2 4 4 5 6 7 8 9 9 11 11 12 13 13 15 15 16 16 18 18 19 19 21 21 23 22 23 24 24 25 26 26 27 27 28 29 29 30 30 30 31 32 32 33 33 33 34 34 35 35 35 36 36 36 37 37 37 38 38 63\x00" as *u8, tlps)
39 let nm: i64 = cab_parse_nums("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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 62 63\x00" as *u8, tmps)
40 if nr != 256 { return 0 }
41 if nl != 64 { return 0 }
42 if nm != 64 { return 0 }
43 return 1
44}
45
46// --- arithmetic engine. cab[0]=ivlCurrRange cab[1]=ivlOffset cab[2]=data ptr cab[3]=bitpos cab[4]=len*8 ---
47func cab_bit(cab: *i64) -> i64 {
48 let bp: i64 = cab[3]
49 if bp >= cab[4] { cab[3] = bp + 1; return 0 }
50 let p: *u8 = cab[2] as *u8
51 let byte: i64 = p[bp >> 3] as i64
52 cab[3] = bp + 1
53 return (byte >> (7 - (bp & 7))) & 1
54}
55func cab_init(cab: *i64, data: *u8, bitstart: i64, bytelen: i64) -> i64 {
56 cab[2] = data as i64; cab[3] = bitstart; cab[4] = bytelen * 8
57 cab[0] = 510
58 var off: i64 = 0
59 var k: i64 = 0
60 while k < 9 { off = (off << 1) | cab_bit(cab); k = k + 1 }
61 cab[1] = off
62 return 0
63}
64func cab_renorm(cab: *i64) -> i64 { while cab[0] < 256 { cab[0] = cab[0] << 1; cab[1] = (cab[1] << 1) | cab_bit(cab) } return 0 }
65// DecodeDecision on context k. ctx[2k]=pStateIdx ctx[2k+1]=valMps.
66func cab_decision(cab: *i64, ctx: *i64, k: i64, rlps: *i64, tlps: *i64, tmps: *i64) -> i64 {
67 let ps: i64 = ctx[2*k]
68 let mps: i64 = ctx[2*k+1]
69 let qIdx: i64 = (cab[0] >> 6) & 3
70 let lps: i64 = rlps[ps*4 + qIdx]
71 cab[0] = cab[0] - lps
72 var bin: i64 = 0
73 if cab[1] >= cab[0] {
74 bin = 1 - mps; cab[1] = cab[1] - cab[0]; cab[0] = lps
75 if ps == 0 { ctx[2*k+1] = 1 - mps }
76 ctx[2*k] = tlps[ps]
77 } else {
78 bin = mps; ctx[2*k] = tmps[ps]
79 }
80 cab_renorm(cab)
81 return bin
82}
83func cab_bypass(cab: *i64) -> i64 { cab[1] = (cab[1] << 1) | cab_bit(cab); if cab[1] >= cab[0] { cab[1] = cab[1] - cab[0]; return 1 } return 0 }
84func cab_terminate(cab: *i64) -> i64 { cab[0] = cab[0] - 2; if cab[1] >= cab[0] { return 1 } cab_renorm(cab); return 0 }
85
86// HEVC-style init from a PACKED initValue byte (kept for the KAT cross-check vs nx_hevc_cabac).
87func cab_ctx_init_iv(ctx: *i64, k: i64, initValue: i64, sliceQpY: i64) -> i64 {
88 let slope: i64 = (initValue >> 4) * 5 - 45
89 let offs: i64 = ((initValue & 15) << 3) - 16
90 let pre: i64 = cab_clip3(1, 126, ((slope * cab_clip3(0, 51, sliceQpY)) >> 4) + offs)
91 if pre <= 63 { ctx[2*k] = 63 - pre; ctx[2*k+1] = 0 } else { ctx[2*k] = pre - 64; ctx[2*k+1] = 1 }
92 return 0
93}
94// H.264 init from the SEPARATE (m,n) init tables (clause 9.3.1.1):
95// preCtxState = Clip3(1,126, (m*Clip3(0,51,SliceQPY) >> 4) + n)
96func cab_ctx_init_mn(ctx: *i64, k: i64, m: i64, n: i64, sliceQpY: i64) -> i64 {
97 let pre: i64 = cab_clip3(1, 126, ((m * cab_clip3(0, 51, sliceQpY)) >> 4) + n)
98 if pre <= 63 { ctx[2*k] = 63 - pre; ctx[2*k+1] = 0 } else { ctx[2*k] = pre - 64; ctx[2*k+1] = 1 }
99 return 0
100}