code wiki / _hdl_build / nx_vcodec_skiprate_gate.nx
nx_vcodec_skiprate_gate.nx source
↩ module page · 104 lines · 6241 B
1import "nx_gate_base.nx"
2// nx_vcodec_skiprate_gate.nx -- MEASURE the P-frame skip rate on standard akiyo (the 73%-of-stream leak).
3// The encoder skips an MB when vm_sad_zero(cur, prev_recon) < qp*188 (and MV==(0,0)). This gate replicates
4// that EXACT decision against the real reconstructed reference each frame (so zsad matches the encoder bit-for-
5// bit), and reports: skip rate at the shipping threshold, at 2x/4x/8x, and a zsad/threshold histogram so we can
6// see whether non-skipped MBs are genuine motion (high SAD) or just quant-noise blocks sitting a hair above the
7// gate. Also sums the added distortion (SSE) of the would-skip-if-2x blocks so we know if raising is SAFE.
8// Decides the highest-leverage P-frame fix WITHOUT guessing. license: ORIGINAL
9import "nx_syscalls.nx"
10import "nx_video_codec_wasm.nx"
11import "nx_vmotion.nx"
12
13const SW: i64 = 352
14const SH: i64 = 288
15const NF: i64 = 48
16
17func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
18" as *u8); return ok }
19func gn(v: i64) -> i64 {
20 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m}
21 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}
22 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
23func cpb(d: *u8, s: *u8, n: i64) -> i64 { var i: i64=0; while i<n { d[i]=s[i]; i=i+1 } return 0 }
24
25// SSE of luma MB (bx,by) cur vs prev co-located (what a true-skip would reconstruct as error)
26func mb_sse(cur: *u8, prev: *u8, W: i64, bx: i64, by: i64) -> i64 {
27 let cx: i64=bx*16; let cy: i64=by*16; var s: i64=0; var j: i64=0
28 while j<16 { var i: i64=0
29 while i<16 { let d: i64=(cur[(cy+j)*W+(cx+i)]&0xff) - (prev[(cy+j)*W+(cx+i)]&0xff); s=s+d*d; i=i+1 } j=j+1 }
30 return s }
31
32func run(yuv: *u8, hi: i64, total: i64, qp: i64) -> i64 {
33 let N: i64=SW*SH; let C2: i64=(SW/2)*(SH/2); let fdata: i64=N+2*C2; let sz: i64=fdata
34 let fp: *i64 = sys_mmap(128*8) as *i64
35 var nf: i64=0; var p: i64=hi
36 while nf < NF { if p>=total { break }
37 var q: i64=p; while q<total { if (yuv[q]&0xff)==10 { break } q=q+1 } q=q+1
38 if q+fdata>total { break } fp[nf]=(yuv as i64)+q; nf=nf+1; p=q+fdata }
39 if nf < NF { gw("too few frames\n" as *u8); return 1 }
40 let prevE: *u8=sys_mmap(sz+64); let reconE: *u8=sys_mmap(sz+64)
41 let wire: *u8=sys_mmap(2097152); let blk: *i64=sys_mmap(512) as *i64; let mv: *i64=sys_mmap(128) as *i64
42 let est: *i64=sys_mmap(64) as *i64; let probs: *i64=sys_mmap(32*8) as *i64; let rcbuf: *u8=sys_mmap(2097152)
43 let t8c: *i64=sys_mmap(5120) as *i64; let rctx: *i64=sys_mmap(64) as *i64
44 vc_t8_init(t8c)
45 var z: i64=0; while z<sz { prevE[z]=0 as u8; z=z+1 }
46 rctx[0]=1; rctx[1]=est as i64; rctx[2]=probs as i64; rctx[3]=rcbuf as i64; rctx[4]=t8c as i64; rctx[5]=0; rctx[6]=0; rctx[7]=0
47 let mbx: i64=SW/16; let mby: i64=SH/16; let nmb: i64=mbx*mby
48 let thr: i64=qp*188
49 var tot_mb: i64=0; var sk1: i64=0; var sk2: i64=0; var sk4: i64=0; var sk8: i64=0
50 var h_lt1: i64=0; var h12: i64=0; var h24: i64=0; var h48: i64=0; var h8p: i64=0
51 var extra_sse_2x: i64=0; var extra_mb_2x: i64=0
52 var f: i64=0
53 while f < NF {
54 let cur: *u8=fp[f] as *u8
55 var key: i64=0; if f==0 { key=1 }
56 // BEFORE encoding this frame, prevE = recon of prior frame = EXACTLY what the encoder's skip decision sees.
57 if key==0 {
58 var by: i64=0
59 while by<mby { var bx: i64=0
60 while bx<mbx {
61 let zsad: i64=vm_sad_zero(cur, prevE, SW, bx, by, 16)
62 tot_mb=tot_mb+1
63 if zsad < thr { sk1=sk1+1 }
64 if zsad < thr*2 { sk2=sk2+1 } else { }
65 if zsad < thr*4 { sk4=sk4+1 }
66 if zsad < thr*8 { sk8=sk8+1 }
67 // histogram of zsad/thr
68 if zsad < thr { h_lt1=h_lt1+1 }
69 if zsad>=thr { if zsad<thr*2 { h12=h12+1 } }
70 if zsad>=thr*2 { if zsad<thr*4 { h24=h24+1 } }
71 if zsad>=thr*4 { if zsad<thr*8 { h48=h48+1 } }
72 if zsad>=thr*8 { h8p=h8p+1 }
73 // added distortion if we RAISED to 2x (blocks in [thr,2thr) that would newly skip)
74 if zsad>=thr { if zsad<thr*2 { extra_sse_2x=extra_sse_2x+mb_sse(cur,prevE,SW,bx,by); extra_mb_2x=extra_mb_2x+1 } }
75 bx=bx+1 } by=by+1 }
76 }
77 rctx[0]=1
78 let nb: i64 = vv_enc_rct8(cur, prevE, reconE, SW, SH, qp, key, thr, wire, 2097152, blk, mv, rctx)
79 if nb<=0 { gw("enc fail\n" as *u8); return 1 }
80 cpb(prevE, reconE, sz)
81 f=f+1
82 }
83 gw(" qp=" as *u8); gn(qp); gw(" thr=qp*188=" as *u8); gn(thr); gw(" MBs/P-frame=" as *u8); gn(nmb); gw("\n" as *u8)
84 gw(" SKIP RATE @1x(shipping)=" as *u8); gn(sk1*100/tot_mb); gw("% @2x=" as *u8); gn(sk2*100/tot_mb)
85 gw("% @4x=" as *u8); gn(sk4*100/tot_mb); gw("% @8x=" as *u8); gn(sk8*100/tot_mb); gw("%\n" as *u8)
86 gw(" zsad/thr HISTO [<1 skip]=" as *u8); gn(h_lt1); gw(" [1-2)=" as *u8); gn(h12)
87 gw(" [2-4)=" as *u8); gn(h24); gw(" [4-8)=" as *u8); gn(h48); gw(" [8+]=" as *u8); gn(h8p); gw("\n" as *u8)
88 // avg per-MB SSE of the [1,2) band -> is raising to 2x SAFE? (small SSE = yes)
89 var avg_extra: i64=0; if extra_mb_2x>0 { avg_extra=extra_sse_2x/extra_mb_2x }
90 gw(" RAISE-TO-2x would newly-skip " as *u8); gn(extra_mb_2x); gw(" MBs, avg added SSE/MB=" as *u8); gn(avg_extra)
91 gw(" (256px*small = safe; large = real motion)\n" as *u8)
92 return 0 }
93
94func main() -> i64 {
95 gw("=== nx_vcodec_skiprate_gate: P-frame SKIP RATE on akiyo (is the 73% leak skip-starvation?) ===\n" as *u8)
96 let box: *i64 = sys_mmap(16) as *i64
97 let yuv: *u8 = sys_read_file("/tmp/akiyo_cif.y4m" as *u8, box)
98 if (yuv as i64)==0 { gw("cannot read /tmp/akiyo_cif.y4m -> RED\n" as *u8); return 1 }
99 let total: i64=box[0]
100 var hi: i64=0; while hi<total { if (yuv[hi]&0xff)==10 { break } hi=hi+1 } hi=hi+1
101 run(yuv, hi, total, 8)
102 run(yuv, hi, total, 4)
103 gw("SKIPRATE: DONE (diagnostic -- skip rate + headroom)\n" as *u8)
104 return 0 }