code wiki / _hdl_build / nx_vcodec_rdoq2_gate.nx
nx_vcodec_rdoq2_gate.nx source
↩ module page · 91 lines · 5517 B
1import "nx_gate_base.nx"
2// nx_vcodec_rdoq2_gate.nx -- FAST clean A/B of RDOQ (decoder-transparent quant) on real 4x4 DCT-II blocks.
3// Small crop (128x128, 4 frames) so it runs in seconds. Both arms range-code the same transformed residuals;
4// arm A = plain deadzone quant, arm B = RDOQ (vt2_quant_rdoq). Reports total bytes + recon SSE->PSNR for each.
5// RDOQ ships (encoder-only, NO vcv bump) iff it is RD-POSITIVE: saves bytes at same/better quality, or saves
6// bytes-per-dB better than the codec's rate slope (~8866 bytes/dB from the RD curve). Eats the RDOQ debt:
7// measure -> ship or remove. license_tier: ORIGINAL
8import "nx_syscalls.nx"
9import "nx_vcodec.nx" // vt2_quant + vt2_quant_rdoq + rc_* + RC_NCTX8 (transitive)
10
11const NW: i64 = 576
12const NH: i64 = 1024
13const CW: i64 = 256
14const CH: i64 = 192
15const CX0: i64 = 128
16const CY0: i64 = 384 // the visual harness's proven motion-rich region (a 200/420 crop hit STATIC background -> mse~1, empty blocks, useless A/B)
17
18func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
19" as *u8); return ok }
20func gn(v: i64) -> i64 {
21 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m}
22 let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}
23 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
24func g2(v: i64) -> i64 { gn(v/100); gw("." as *u8); let f: i64=v%100; if f<10{gw("0" as *u8)} gn(f); return 0 }
25// integer PSNR cdb from SSE over n pixels: 10*log10(65025/mse), via a small log10 approx (bit-length based)
26func psnr_cdb(sse: i64, n: i64) -> i64 {
27 if sse <= 0 { return 9900 }
28 let mse: i64 = sse/n; if mse<=0 { return 9900 }
29 // 10*log10(65025/mse). log10(x) ~ (bitlen-based) -- use: log10 = log2/3.3219. compute log2 in cdb.
30 var num: i64 = 65025; var q: i64 = 0; var x: i64 = num/mse; if x<1 {x=1}
31 // log2(x)*100 via bit position + linear frac
32 var bl: i64=0; var xx: i64=x; while xx>1 { bl=bl+1; xx=xx>>1 }
33 let frac: i64 = ((x - (1<<bl)) * 100) / (1<<bl) // fractional part 0..99
34 let log2_c: i64 = bl*100 + frac // ~log2(x)*100
35 return (log2_c * 1000) / 332 // PSNR_cdb = 1000*log10(x) = (100*log2(x))*1000/332.2
36}
37
38func enc_arm(yuv: *u8, f: i64, qp: i64, rdoq: i64, est: *i64, probs: *i64, rcbuf: *u8, blk: *i64, sse_out: *i64) -> i64 {
39 let N: i64=NW*NH; let FB: i64=N+N/2
40 let cur: *u8=((yuv as i64)+f*FB) as *u8; let prv: *u8=((yuv as i64)+(f-1)*FB) as *u8
41 rc_enc_init(est); var ci: i64=0; while ci<RC_NCTX8 { probs[ci]=2048; ci=ci+1 }
42 var sse: i64=0
43 let tru: *i64 = ((blk as i64)+64*8) as *i64
44 var by: i64=0
45 while by < CH/4 { var bx: i64=0
46 while bx < CW/4 {
47 var yy: i64=0
48 while yy<4 { var xx: i64=0
49 while xx<4 { let p: i64=(CY0+by*4+yy)*NW+(CX0+bx*4+xx); let d: i64=(cur[p]&0xff)-(prv[p]&0xff); blk[yy*4+xx]=d; tru[yy*4+xx]=d; xx=xx+1 } yy=yy+1 }
50 vt2_fwd(blk)
51 if rdoq==1 { vt2_quant_rdoq(blk, qp) } else { vt2_quant(blk, qp) }
52 rc_block_encode(blk, est, rcbuf, probs)
53 vt2_dequant(blk, qp); vt2_inv(blk)
54 var e: i64=0; while e<16 { let df: i64=tru[e]-blk[e]; sse=sse+df*df; e=e+1 } e=0
55 bx=bx+1 } by=by+1 }
56 sse_out[0]=sse
57 return rc_enc_flush(est, rcbuf) }
58
59func main() -> i64 {
60 gw("=== nx_vcodec_rdoq2_gate: RDOQ vs plain quant, decoder-transparent, fast A/B ===\n" as *u8)
61 let box: *i64=sys_mmap(16) as *i64
62 let yuv: *u8=sys_read_file("/mnt/c/Users/elder/nishi-core/nxc2/knowledge/staging/media/bframe_test_decoded.yuv" as *u8, box)
63 if (yuv as i64)==0 { gw("cannot read yuv -> RED\n" as *u8); return 1 }
64 if box[0] < 12*(NW*NH+NW*NH/2) { gw("file too small -> RED\n" as *u8); return 1 }
65 let est: *i64=sys_mmap(64) as *i64; let probs: *i64=sys_mmap(32*8) as *i64; let rcbuf: *u8=sys_mmap(1048576)
66 let blk: *i64=sys_mmap(128*8) as *i64
67 let sA: *i64=sys_mmap(16) as *i64; let sB: *i64=sys_mmap(16) as *i64
68 let npix: i64=(CW*CH)*4
69 var pass: i64=0; var tot: i64=0; var anypos: i64=0
70 let qs: *i64=sys_mmap(32) as *i64; qs[0]=22; qs[1]=28; qs[2]=34
71 var qi: i64=0
72 while qi<3 {
73 let qp: i64=qs[qi]
74 var bA: i64=0; var bB: i64=0; var ssA: i64=0; var ssB: i64=0
75 var f: i64=8
76 while f<12 { bA=bA+enc_arm(yuv,f,qp,0,est,probs,rcbuf,blk,sA); ssA=ssA+sA[0]
77 bB=bB+enc_arm(yuv,f,qp,1,est,probs,rcbuf,blk,sB); ssB=ssB+sB[0]; f=f+1 }
78 let pA: i64=psnr_cdb(ssA,npix); let pB: i64=psnr_cdb(ssB,npix)
79 gw(" qp=" as *u8); gn(qp); gw(" PLAIN " as *u8); gn(bA); gw("B/" as *u8); g2(pA)
80 gw("dB RDOQ " as *u8); gn(bB); gw("B/" as *u8); g2(pB); gw("dB" as *u8)
81 let dB: i64=bA-bB; let ddb: i64=pA-pB
82 gw(" saved=" as *u8); gn(dB); gw("B for " as *u8); gn(ddb); gw("cdB" as *u8)
83 var rdpos: i64=0
84 if ddb<=0 { if dB>0 { rdpos=1 } } else { if dB*100 > ddb*8866 { rdpos=1 } }
85 gw(" RD+=" as *u8); gn(rdpos); gw("\n" as *u8)
86 if rdpos==1 { anypos=1 }
87 qi=qi+1 }
88 tot=tot+1; if anypos==1 { pass=pass+1 }
89 gw("RDOQ2: " as *u8); gn(pass); gw("/" as *u8); gn(tot)
90 if pass==tot { gw(" GREEN -- RDOQ is RD-POSITIVE (ship it, encoder-only no vcv bump)\n" as *u8); return 0 }
91 gw(" RED -- RDOQ not RD-positive (remove the dead code, debt eaten)\n" as *u8); return 1 }