code wiki / _hdl_build / nx_vcodec_subpel_ceiling.nx

nx_vcodec_subpel_ceiling.nx source

↩ module page · 177 lines · 8659 B

1// nx_vcodec_subpel_ceiling.nx -- RE-AUDIT the self-judged "6-tap sub-pel = 0" verdict (task #17) against a MEASURED 2// residual ceiling, decoder-transparent. The codec's sub-pel is BILINEAR (qp_pixel: a 4-neighbour weighted blend that 3// BLURS the reference). H.264 uses a SHARP 6-tap FIR (1,-5,20,20,-5,1)/32 that preserves high-frequency detail -> a 4// tighter prediction -> smaller residual -> fewer bits at identical quality. This probe isolates FILTER SHARPNESS: 5// for each interior 16x16 P-block, integer-search the clean prev (+/-16), then refine to HALF-pel with (a) the existing 6// bilinear filter and (b) a proper 6-tap filter, and sum the best SAD each way over several P-frames. If 6-tap's total 7// residual is materially lower, the "0" verdict was a short-bench lie (like RD-skip and wide-ME were) and the real 8// enc+dec+wasm build is justified. Pure measurement on CLEAN originals => no bitstream, no parity risk. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_vsubpel.nx" 11import "nx_vmotion.nx" 12const K_MAGIC_2147483647: i64 = 2147483647 13const K_MAGIC_2026: i64 = 2026 14 15const NW: i64 = 576 16const NH: i64 = 1024 17 18func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 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 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 } 24func clp(v: i64) -> i64 { if v<0 { return 0 } if v>255 { return 255 } return v } 25 26// 6-tap horizontal half-pel PRE-SHIFT value sampled at (x+0.5, y): taps prev[y, x-2 .. x+3] 27func s6h(prev: *u8, W: i64, x: i64, y: i64) -> i64 { 28 let e: i64 = prev[y*W + x-2] as i64 29 let f: i64 = prev[y*W + x-1] as i64 30 let g: i64 = prev[y*W + x] as i64 31 let h: i64 = prev[y*W + x+1] as i64 32 let i: i64 = prev[y*W + x+2] as i64 33 let j: i64 = prev[y*W + x+3] as i64 34 return e - 5*f + 20*g + 20*h - 5*i + j 35} 36// 6-tap vertical half-pel PRE-SHIFT value sampled at (x, y+0.5): taps prev[y-2 .. y+3, x] 37func s6v(prev: *u8, W: i64, x: i64, y: i64) -> i64 { 38 let e: i64 = prev[(y-2)*W + x] as i64 39 let f: i64 = prev[(y-1)*W + x] as i64 40 let g: i64 = prev[y*W + x] as i64 41 let h: i64 = prev[(y+1)*W + x] as i64 42 let i: i64 = prev[(y+2)*W + x] as i64 43 let j: i64 = prev[(y+3)*W + x] as i64 44 return e - 5*f + 20*g + 20*h - 5*i + j 45} 46// 6-tap CENTER (j) PRE-SHIFT^2 value at (x+0.5, y+0.5): 6-tap vertical over 6 horizontal-half values at rows y-2..y+3 47func s6c(prev: *u8, W: i64, x: i64, y: i64) -> i64 { 48 let e: i64 = s6h(prev, W, x, y-2) 49 let f: i64 = s6h(prev, W, x, y-1) 50 let g: i64 = s6h(prev, W, x, y) 51 let h: i64 = s6h(prev, W, x, y+1) 52 let i: i64 = s6h(prev, W, x, y+2) 53 let j: i64 = s6h(prev, W, x, y+3) 54 return e - 5*f + 20*g + 20*h - 5*i + j 55} 56// one 6-tap half-pel sample at reference (x,y) with half offsets hx,hy in {0,1} 57func s6_pixel(prev: *u8, W: i64, x: i64, y: i64, hx: i64, hy: i64) -> i64 { 58 if hx == 0 { 59 if hy == 0 { return prev[y*W + x] as i64 } 60 return clp((s6v(prev, W, x, y) + 16) >> 5) 61 } 62 if hy == 0 { return clp((s6h(prev, W, x, y) + 16) >> 5) } 63 return clp((s6c(prev, W, x, y) + 512) >> 10) 64} 65// best 6-tap HALF-pel SAD for the TxT block at (cx,cy), integer base (px,py): test the 4 (hx,hy) 66func s6_refine(cur: *u8, prev: *u8, W: i64, cx: i64, cy: i64, px: i64, py: i64, T: i64) -> i64 { 67 var best: i64 = K_MAGIC_2147483647 68 var hy: i64 = 0 69 while hy <= 1 { 70 var hx: i64 = 0 71 while hx <= 1 { 72 var sad: i64 = 0 73 var ry: i64 = 0 74 while ry < T { 75 var rx: i64 = 0 76 while rx < T { 77 let d: i64 = (cur[(cy+ry)*W + (cx+rx)] as i64) - s6_pixel(prev, W, px+rx, py+ry, hx, hy) 78 if d < 0 { sad = sad - d } else { sad = sad + d } 79 rx = rx + 1 80 } 81 ry = ry + 1 82 } 83 if sad < best { best = sad } 84 hx = hx + 1 85 } 86 hy = hy + 1 87 } 88 return best 89} 90// best BILINEAR half-pel SAD (the codec's current filter), same 4 (hx,hy), via hp_pixel 91func bl_refine(cur: *u8, prev: *u8, W: i64, cx: i64, cy: i64, px: i64, py: i64, T: i64) -> i64 { 92 var best: i64 = K_MAGIC_2147483647 93 var hy: i64 = 0 94 while hy <= 1 { 95 var hx: i64 = 0 96 while hx <= 1 { 97 var sad: i64 = 0 98 var ry: i64 = 0 99 while ry < T { 100 var rx: i64 = 0 101 while rx < T { 102 let d: i64 = (cur[(cy+ry)*W + (cx+rx)] as i64) - hp_pixel(prev, W, px+rx, py+ry, hx, hy) 103 if d < 0 { sad = sad - d } else { sad = sad + d } 104 rx = rx + 1 105 } 106 ry = ry + 1 107 } 108 if sad < best { best = sad } 109 hx = hx + 1 110 } 111 hy = hy + 1 112 } 113 return best 114} 115 116func main() -> i64 { 117 let vmscr3: *i64 = sys_mmap(32) as *i64 // vm_search scratch (K_MAGIC_2026-07-29: hoisted ONE alloc; the per-call sys_mmap inside vm_search was the wasm 0-stub + native map-leak class) 118 gw("=== nx_vcodec_subpel_ceiling: 6-tap vs bilinear half-pel residual (re-audit the 'sub-pel=0' verdict) ===\n" as *u8) 119 let box: *i64 = sys_mmap(16) as *i64 120 let yuv: *u8 = sys_read_file("/mnt/c/Users/elder/nishi-core/nxc2/knowledge/staging/media/bframe_test_decoded.yuv" as *u8, box) 121 if (yuv as i64) == 0 { gw("cannot read yuv -> RED\n" as *u8); return 1 } 122 let N: i64 = NW*NH 123 let FB: i64 = N + N/2 124 if box[0] < 12 * FB { gw("file too small -> RED\n" as *u8); return 1 } 125 let mv: *i64 = sys_mmap(64) as *i64 126 let T: i64 = 16 127 128 var totInt: i64 = 0; var totBil: i64 = 0; var tot6: i64 = 0; var nblk: i64 = 0 129 // predict P-frames 6,7,8 from their clean previous originals (decoder-transparent ceiling) 130 var fp: i64 = 6 131 while fp <= 8 { 132 let cur: *u8 = ((yuv as i64) + fp*FB) as *u8 133 let prev: *u8 = ((yuv as i64) + (fp-1)*FB) as *u8 134 var cy: i64 = 32 135 while cy <= NH-48 { 136 var cx: i64 = 32 137 while cx <= NW-48 { 138 let isad: i64 = vm_search(cur, prev, NW, NH, cx/16, cy/16, T, 16, mv, vmscr3) 139 let px: i64 = cx + mv[0]; let py: i64 = cy + mv[1] 140 // 6-tap needs a 2px margin beyond the block on every side; skip blocks whose MV lands near the edge 141 var ok: i64 = 1 142 if px < 2 { ok = 0 } 143 if py < 2 { ok = 0 } 144 if px + T + 3 >= NW { ok = 0 } 145 if py + T + 3 >= NH { ok = 0 } 146 if ok == 1 { 147 let sb: i64 = bl_refine(cur, prev, NW, cx, cy, px, py, T) 148 let s6: i64 = s6_refine(cur, prev, NW, cx, cy, px, py, T) 149 totInt = totInt + isad 150 totBil = totBil + sb 151 tot6 = tot6 + s6 152 nblk = nblk + 1 153 } 154 cx = cx + 16 155 } 156 cy = cy + 16 157 } 158 fp = fp + 1 159 } 160 gw("blocks measured=" as *u8); gn(nblk); gw(" (interior 16x16, 3 P-frames)\n" as *u8) 161 gw(" integer-pel total SAD = " as *u8); gn(totInt); gw("\n" as *u8) 162 gw(" bilinear-half total SAD = " as *u8); gn(totBil) 163 let bilGainInt: i64 = (totInt-totBil)*1000/totInt 164 gw(" (-" as *u8); gn(bilGainInt); gw("permille vs integer)\n" as *u8) 165 gw(" 6-tap-half total SAD = " as *u8); gn(tot6) 166 let sixGainInt: i64 = (totInt-tot6)*1000/totInt 167 gw(" (-" as *u8); gn(sixGainInt); gw("permille vs integer)\n" as *u8) 168 // the decisive number: 6-tap residual vs bilinear residual at the SAME half-pel granularity (isolates sharpness) 169 let sixVsBil: i64 = (totBil-tot6)*1000/totBil 170 gw(" === 6-tap vs bilinear residual = " as *u8) 171 if tot6 < totBil { gw("-" as *u8); gn(sixVsBil); gw("permille (6-tap TIGHTER -> BUILD IT) ===\n" as *u8) } 172 else { gw("+" as *u8); gn((tot6-totBil)*1000/totBil); gw("permille (6-tap WORSE -> verdict holds, dead) ===\n" as *u8) } 173 // liar-killer: 6-tap must at least beat integer (a sharper sub-pel can't be worse than no sub-pel on real motion) 174 if tot6 < totInt { gw("LIAR-KILLER PASS: 6-tap beats integer-pel (sub-pel is doing real work)\n" as *u8) } 175 else { gw("LIAR-KILLER WARN: 6-tap did NOT beat integer -- content near-static or a bug\n" as *u8) } 176 return 0 177}