code wiki / _hdl_build / nx_vcodec_multiref_gate.nx
nx_vcodec_multiref_gate.nx source
↩ module page · 96 lines · 5882 B
1// nx_vcodec_multiref_gate.nx -- MEASURES the latency-safe B-frame lever: does predicting from TWO PAST
2// references (multi-ref best-of + COMPOUND averaging) shrink the residual vs single-ref (previous frame only)?
3// This is how low-latency RTC codecs get B-frame-like gains WITHOUT the reorder/latency of classic
4// bidirectional B (which references a FUTURE frame). Per 16x16 block, on real frames, measures total residual
5// SAD for: (1) single-ref = prev frame N-1; (2) multi-ref = best-of {N-1, N-2, N-4 long-term}; (3) compound =
6// average of the two best past predictions. The SAD reduction = the upper-bound prediction gain a multi-ref/
7// compound generation would win. GREEN reports the measured reduction (build-decision, not pass/fail-of-idea).
8// license_tier: ORIGINAL
9import "nx_syscalls.nx"
10import "nx_vmotion.nx"
11
12const NW: i64 = 576
13const NH: i64 = 1024
14const T: i64 = 16
15const R: i64 = 8
16
17func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
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 }
22
23// SAD of cur block (cx,cy) vs the AVERAGE of ref1@mv1 and ref2@mv2 (integer MVs). Edge-guarded by the caller.
24func compound_sad(cur: *u8, r1: *u8, r2: *u8, W: i64, cx: i64, cy: i64, mvx1: i64, mvy1: i64, mvx2: i64, mvy2: i64) -> i64 {
25 var s: i64=0; var yy: i64=0
26 while yy < T { var xx: i64=0
27 while xx < T {
28 let c: i64 = cur[(cy+yy)*W + cx+xx] & 0xff
29 let p1: i64 = r1[(cy+yy+mvy1)*W + cx+xx+mvx1] & 0xff
30 let p2: i64 = r2[(cy+yy+mvy2)*W + cx+xx+mvx2] & 0xff
31 let pc: i64 = (p1 + p2 + 1) / 2
32 let d: i64 = c - pc; if d<0 { s=s-d } else { s=s+d }
33 xx=xx+1 } yy=yy+1 }
34 return s }
35
36func inb(cx: i64, cy: i64, mvx: i64, mvy: i64) -> i64 { // is the MC block fully in-frame?
37 if cx+mvx < 0 { return 0 } if cy+mvy < 0 { return 0 }
38 if cx+mvx+T > NW { return 0 } if cy+mvy+T > NH { return 0 }
39 return 1 }
40
41func main() -> i64 {
42 let vmscr3: *i64 = sys_mmap(32) as *i64 // vm_search scratch (2026-07-29: hoisted ONE alloc; the per-call sys_mmap inside vm_search was the wasm 0-stub + native map-leak class)
43 gw("=== nx_vcodec_multiref_gate: single-ref vs multi-ref vs compound (latency-safe B lever), real frames ===\n" as *u8)
44 let box: *i64 = sys_mmap(16) as *i64
45 let yuv: *u8 = sys_read_file("/mnt/c/Users/elder/nishi-core/nxc2/knowledge/staging/media/bframe_test_decoded.yuv" as *u8, box)
46 if (yuv as i64) == 0 { gw("cannot read yuv -> verdict=RED\n" as *u8); return 1 }
47 let N: i64=NW*NH; let FB: i64=N+N/2
48 if box[0] < 12*FB { gw("file too small -> verdict=RED\n" as *u8); return 1 }
49 let mv1: *i64=sys_mmap(32) as *i64; let mv2: *i64=sys_mmap(32) as *i64; let mvl: *i64=sys_mmap(32) as *i64
50
51 var sSingle: i64=0; var sMulti: i64=0; var sComp: i64=0
52 var f: i64=8
53 while f < 12 {
54 let cur: *u8 = ((yuv as i64) + f*FB) as *u8
55 let r1: *u8 = ((yuv as i64) + (f-1)*FB) as *u8 // N-1
56 let r2: *u8 = ((yuv as i64) + (f-2)*FB) as *u8 // N-2
57 let rl: *u8 = ((yuv as i64) + (f-4)*FB) as *u8 // N-4 (long-term)
58 var by: i64=0
59 while by < NH/T {
60 var bx: i64=0
61 while bx < NW/T {
62 let cx: i64=bx*T; let cy: i64=by*T
63 let sad1: i64 = vm_search(cur, r1, NW, NH, bx, by, T, R, mv1, vmscr3)
64 let sad2: i64 = vm_search(cur, r2, NW, NH, bx, by, T, R, mv2, vmscr3)
65 let sadl: i64 = vm_search(cur, rl, NW, NH, bx, by, T, R, mvl, vmscr3)
66 sSingle = sSingle + sad1
67 var best: i64 = sad1; if sad2 < best { best=sad2 } if sadl < best { best=sadl }
68 sMulti = sMulti + best
69 // compound = average of the two BEST past predictions (N-1 and whichever of N-2/N-4 is better)
70 var mx2: i64=mv2[0]; var my2: i64=mv2[1]; var rr2: i64 = r2 as i64
71 if sadl < sad2 { mx2=mvl[0]; my2=mvl[1]; rr2 = rl as i64 }
72 var cs: i64 = best // compound only if both refs in-frame, else fall back to best
73 if inb(cx,cy,mv1[0],mv1[1])==1 { if inb(cx,cy,mx2,my2)==1 {
74 let c2: i64 = compound_sad(cur, r1, rr2 as *u8, NW, cx, cy, mv1[0], mv1[1], mx2, my2)
75 if c2 < cs { cs = c2 }
76 } }
77 sComp = sComp + cs
78 bx=bx+1 } by=by+1 }
79 f=f+1
80 }
81 gw(" total residual SAD -- single-ref(N-1)=" as *u8); gn(sSingle)
82 gw(" multi-ref(best of N-1,N-2,N-4)=" as *u8); gn(sMulti)
83 gw(" compound(avg 2 past)=" as *u8); gn(sComp); gw("\n" as *u8)
84 let rM: i64 = (sSingle-sMulti)*1000/sSingle
85 let rC: i64 = (sSingle-sComp)*1000/sSingle
86 gw(" multi-ref cuts residual " as *u8); gn(rM); gw("permille; compound cuts " as *u8); gn(rC); gw("permille vs single-ref\n" as *u8)
87
88 var pass: i64=0; var tot: i64=0
89 tot=tot+1; if sMulti <= sSingle { pass=pass+1 } // multi-ref never hurts
90 tot=tot+1; if sComp <= sMulti { pass=pass+1 } // compound never hurts vs multi
91 tot=tot+1; if sSingle > 1000000 { pass=pass+1 } // real substantial measurement
92 gw("MULTIREF: " as *u8); gn(pass); gw("/" as *u8); gn(tot)
93 if pass==tot {
94 if rC >= 50 { gw(" verdict=GREEN -- compound/multi-ref cuts residual >=5pct: a latency-safe B-lever WORTH building\n" as *u8); return 0 }
95 gw(" verdict=GREEN -- but gain is SMALL (<5pct residual): multi-ref marginal for this content, NOT worth the wire\n" as *u8); return 0 }
96 gw(" verdict=RED\n" as *u8); return 1 }