nx_hevc_cabac.nx source
↩ module page · 79 lines · 6373 B
1// nx_hevc_cabac.nx -- SOVEREIGN HEVC CABAC entropy decoder, RUNG 2 of the HEVC decoder.
2// The arithmetic decoding engine (ITU-T H.265 clause 9.3): DecodeDecision / DecodeBypass / DecodeTerminate +
3// renormalization + context-variable init from initValue + SliceQpY. Normative tables (rangeTabLps 64x4,
4// transIdxLps, transIdxMps) embedded as data. The syntax-element contexts (rung 3) plug their initValues into
5// cab_ctx_init(). Self-test: init on a buffer + decode bypass/decision bins, confirm range/offset stay valid.
6// No third party. license_tier: ORIGINAL
7import "nx_syscalls.nx"
8
9func pe(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return sys_write(1,s,n) }
10func pn(v: i64) -> i64 { var m: i64=v; if m<0{m=0-m} let b: *u8=sys_mmap(32); var i: i64=32; if m==0{i=i-1;b[i]=(48 as u8)} while m>0{let q: i64=m/10; i=i-1; b[i]=((48+(m-q*10)) as u8); m=q} if v<0 {i=i-1; b[i]=(45 as u8)} return sys_write(1,((b as i64)+i) as *u8,32-i) }
11// fill an i64 array from a space-separated number string; returns count
12func parse_nums(s: *u8, out: *i64) -> i64 { var n: i64=0; var i: i64=0; var cur: i64=0; var has: i64=0; while s[i]!=(0 as u8){ let c: i64=s[i] as i64; 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} } i=i+1 } if has==1 {out[n]=cur; n=n+1} return n }
13func clip3(lo: i64, hi: i64, v: i64) -> i64 { if v<lo {return lo} if v>hi {return hi} return v }
14
15// ---- bit reader for the CABAC byte stream (cab[2]=ptr cab[3]=bitpos cab[4]=len*8) ----
16func cab_bit(cab: *i64) -> i64 { let bp: i64=cab[3]; if bp>=cab[4] { cab[3]=bp+1; return 0 } let p: *u8=cab[2] as *u8; let byte: i64=p[bp>>3] as i64; cab[3]=bp+1; return (byte>>(7-(bp&7)))&1 }
17
18// ---- engine. cab[0]=ivlCurrRange cab[1]=ivlOffset ----
19func cab_init(cab: *i64, data: *u8, bitstart: i64, bytelen: i64) -> i64 {
20 cab[2]=data as i64; cab[3]=bitstart; cab[4]=bytelen*8
21 cab[0]=510
22 var off: i64=0; var k: i64=0; while k<9 { off=(off<<1)|cab_bit(cab); k=k+1 } cab[1]=off
23 return 0
24}
25func cab_renorm(cab: *i64) -> i64 { while cab[0]<256 { cab[0]=cab[0]<<1; cab[1]=(cab[1]<<1)|cab_bit(cab) } return 0 }
26// ctx[2k]=pStateIdx ctx[2k+1]=valMps. rlps = rangeTabLps flat[64*4], tlps/tmps = transIdx[64].
27func cab_decision(cab: *i64, ctx: *i64, k: i64, rlps: *i64, tlps: *i64, tmps: *i64) -> i64 {
28 let ps: i64=ctx[2*k]; let mps: i64=ctx[2*k+1]
29 let qIdx: i64=(cab[0]>>6)&3
30 let lps: i64=rlps[ps*4+qIdx]
31 cab[0]=cab[0]-lps
32 var bin: i64=0
33 if cab[1]>=cab[0] {
34 bin=1-mps; cab[1]=cab[1]-cab[0]; cab[0]=lps
35 if ps==0 { ctx[2*k+1]=1-mps }
36 ctx[2*k]=tlps[ps]
37 } else {
38 bin=mps; ctx[2*k]=tmps[ps]
39 }
40 cab_renorm(cab)
41 return bin
42}
43func 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 }
44func cab_terminate(cab: *i64) -> i64 { cab[0]=cab[0]-2; if cab[1]>=cab[0] { return 1 } cab_renorm(cab); return 0 }
45// init one context variable from its initValue + SliceQpY (clause 9.3.2.2)
46func cab_ctx_init(ctx: *i64, k: i64, initValue: i64, sliceQpY: i64) -> i64 {
47 let slope: i64=(initValue>>4)*5-45
48 let offs: i64=((initValue&15)<<3)-16
49 let pre: i64=clip3(1,126, ((slope*clip3(0,51,sliceQpY))>>4)+offs)
50 if pre<=63 { ctx[2*k]=63-pre; ctx[2*k+1]=0 } else { ctx[2*k]=pre-64; ctx[2*k+1]=1 }
51 return 0
52}
53
54func main(argc: i64, argv: *i64) -> i64 {
55 // load normative tables
56 let rlps: *i64=sys_mmap(8*300) as *i64
57 let tlps: *i64=sys_mmap(8*80) as *i64
58 let tmps: *i64=sys_mmap(8*80) as *i64
59 let nr: i64=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" as *u8, rlps)
60 let nl: i64=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" as *u8, tlps)
61 let nm: i64=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" as *u8, tmps)
62 pe("CABAC tables: rangeTabLps=" as *u8); pn(nr); pe(" transIdxLps=" as *u8); pn(nl); pe(" transIdxMps=" as *u8); pn(nm); pe("\n" as *u8)
63 if nr!=256 { pe("BAD rangeTabLps count\n" as *u8); return 1 }
64 if nl!=64 { pe("BAD transIdxLps count\n" as *u8); return 1 }
65 if nm!=64 { pe("BAD transIdxMps count\n" as *u8); return 1 }
66 // self-test: init on a fixed buffer, decode some bypass bins + decision bins with a test context
67 let buf: *u8=sys_mmap(64); var bi: i64=0; while bi<64 { buf[bi]=((bi*37+11)&0xff) as u8; bi=bi+1 }
68 let cab: *i64=sys_mmap(8*8) as *i64
69 cab_init(cab, buf, 0, 64)
70 pe("init range=" as *u8); pn(cab[0]); pe(" offset=" as *u8); pn(cab[1]); pe("\n" as *u8)
71 let ctx: *i64=sys_mmap(8*4) as *i64
72 cab_ctx_init(ctx, 0, 154, 26) // a mid initValue at QP26
73 pe("ctx0 pState=" as *u8); pn(ctx[0]); pe(" mps=" as *u8); pn(ctx[1]); pe("\n" as *u8)
74 pe("bypass bins:" as *u8); var t: i64=0; while t<16 { pe(" " as *u8); pn(cab_bypass(cab)); t=t+1 } pe("\n" as *u8)
75 pe("decision bins:" as *u8); t=0; var ok: i64=1; while t<16 { let bn: i64=cab_decision(cab, ctx, 0, rlps, tlps, tmps); pe(" " as *u8); pn(bn); if cab[0]<256 {ok=0} if cab[0]>510 {ok=0} t=t+1 } pe("\n" as *u8)
76 pe("terminate bin=" as *u8); pn(cab_terminate(cab)); pe("\n" as *u8)
77 if ok==1 { pe("ENGINE OK (range stayed in [256,510] post-renorm)\n" as *u8) } else { pe("ENGINE BAD (range out of range)\n" as *u8) }
78 return 0
79}