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