code wiki / _hdl_build / nx_vcodec_drift_diag.nx
nx_vcodec_drift_diag.nx source
↩ module page · 75 lines · 4097 B
1import "nx_gate_base.nx"
2// nx_vcodec_drift_diag.nx -- WHY are our P-frames ~10 dB below the keyframe at the same qp (MSU: intra 1.75x but
3// overall 8x behind x264 => the P-frames are the catastrophe)? Encodes /tmp/seq.y4m at a given qp (live emode 169)
4// and prints EVERY frame's luma SSE, so the shell can plot per-frame PSNR: a monotonic climb = temporal DRIFT
5// (error accumulates through the GOP); a flat-high plateau = P-frames systematically coded worse than intra. That
6// distinction picks the fix (drift -> prediction/quant loop; flat -> P residual fidelity). CIF only. license: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_video_codec_wasm.nx"
9const K_MAGIC_4194304: i64 = 4194304
10const K_MAGIC_5120: i64 = 5120
11
12const SW: i64 = 352
13const SH: i64 = 288
14const NF: i64 = 48
15
16func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
17" as *u8); return ok }
18func gn(v: i64) -> i64 {
19 let b: *u8=sys_mmap(28); var m: i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m}
20 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}
21 var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
22func cpb(d: *u8, s: *u8, n: i64) -> i64 { var i: i64=0; while i<n { d[i]=s[i]; i=i+1 } return 0 }
23
24func frames(yuv: *u8, hi: i64, total: i64, fp: *i64, fdata: i64) -> i64 {
25 var nf: i64=0; var p: i64=hi
26 while nf < NF { if p>=total { break }
27 var q: i64=p; while q<total { if (yuv[q]&0xff)==10 { break } q=q+1 } q=q+1
28 if q+fdata>total { break } fp[nf]=(yuv as i64)+q; nf=nf+1; p=q+fdata }
29 return nf }
30
31func run(fp: *i64, qp: i64, emode: i64, sz: i64, skipmul: i64) -> i64 {
32 let prevE: *u8=sys_mmap(sz+64); let reconE: *u8=sys_mmap(sz+64)
33 let wire: *u8=sys_mmap(K_MAGIC_4194304); let blk: *i64=sys_mmap(512) as *i64; let mv: *i64=sys_mmap(128) as *i64
34 let est: *i64=sys_mmap(64) as *i64; let probs: *i64=sys_mmap(32*8) as *i64; let rcbuf: *u8=sys_mmap(K_MAGIC_4194304)
35 let t8c: *i64=sys_mmap(K_MAGIC_5120) as *i64; let rctx: *i64=sys_mmap(64) as *i64
36 vc_t8_init(t8c)
37 var z: i64=0; while z<sz { prevE[z]=0 as u8; z=z+1 }
38 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
39 let NL: i64=SW*SH
40 var totB: i64=0; var keySSE: i64=0; var lastSSE: i64=0; var pSSEsum: i64=0
41 var f: i64=0
42 while f < NF {
43 let cur: *u8=fp[f] as *u8
44 var key: i64=0; if f==0 { key=1 }
45 rctx[0]=emode
46 let nb: i64 = vv_enc_rct8(cur, prevE, reconE, SW, SH, qp, key, qp*skipmul, wire, K_MAGIC_4194304, blk, mv, rctx)
47 if nb<=0 { gw("enc fail\n" as *u8); return 1 }
48 var pxi: i64=0; var fsse: i64=0
49 while pxi<NL { let d: i64=(reconE[pxi]&0xff)-(cur[pxi]&0xff); fsse=fsse+d*d; pxi=pxi+1 }
50 totB=totB+nb; if f==0 { keySSE=fsse } else { pSSEsum=pSSEsum+fsse; lastSSE=fsse }
51 cpb(prevE, reconE, sz)
52 f=f+1
53 }
54 // report keyframe sseY, P-avg sseY, P-last sseY (shell -> PSNR), total bytes
55 gw("SKIPMUL="); gn(skipmul); gw(" totB="); gn(totB); gw(" keySSE="); gn(keySSE)
56 gw(" pAvgSSE="); gn(pSSEsum/(NF-1)); gw(" pLastSSE="); gn(lastSSE); gw("\n" as *u8)
57 return 0 }
58
59func main() -> i64 {
60 let box: *i64 = sys_mmap(16) as *i64
61 let yuv: *u8 = sys_read_file("/tmp/seq.y4m" as *u8, box)
62 if (yuv as i64)==0 { gw("cannot read /tmp/seq.y4m -> RED\n" as *u8); return 1 }
63 let total: i64=box[0]
64 var hi: i64=0; while hi<total { if (yuv[hi]&0xff)==10 { break } hi=hi+1 } hi=hi+1
65 let C2: i64=(SW/2)*(SH/2); let fdata: i64=SW*SH+2*C2; let sz: i64=fdata
66 let fp: *i64=sys_mmap(128*8) as *i64
67 let nf: i64=frames(yuv, hi, total, fp, fdata)
68 if nf < NF { gw("too few frames -> RED\n" as *u8); return 1 }
69 // sweep the skip threshold: 188=baseline, lower=less skip (code more MBs). Does less skip fix the drift?
70 run(fp, 8, 169, sz, 188)
71 run(fp, 8, 169, sz, 60)
72 run(fp, 8, 169, sz, 20)
73 run(fp, 8, 169, sz, 4)
74 gw("DRIFT: DONE\n" as *u8)
75 return 0 }