code wiki / _hdl_build / nx_vmvpred_gate.nx

nx_vmvpred_gate.nx source

↩ module page · 82 lines · 4378 B

1// nx_vmvpred_gate.nx -- proves + MEASURES MV prediction (nx_vmvpred): on a realistic motion field (a camera pan with a 2// couple of differently-moving object blocks), coding MVs as residuals from the median neighbour predictor costs far 3// fewer bits than coding them absolutely. Uses the codec's real varint MV cost (ve_zze/ve_blen). 4import "nx_syscalls.nx" 5import "nx_gate_emit_lib.nx" 6import "nx_vmvpred.nx" 7import "nx_ventropy.nx" 8import "nx_gate_verdict.nx" 9 10func vbits(v: i64) -> i64 { return 5 + ve_blen(ve_zze(v)) } // bits one varint MV component costs (codec's coder) 11 12func main() -> i64 { 13 g_puts("nx_vmvpred gate (median MV prediction cuts MV bits on a pan, MEASURED)\n" as *u8) 14 var pass: i64 = 0; var total: i64 = 0 15 let BW: i64 = 6; let BH: i64 = 4; let NB: i64 = BW*BH // 6x4 = 24 macroblocks 16 17 // realistic motion field: a (3,1) camera pan everywhere, EXCEPT a 2x2 "object" at (bx 2..3, by 1..2) moving (3,5), 18 // and one fast block at (5,0) moving (8,-2). Stored as mvx[NB], mvy[NB] in raster order. 19 let mvx: *i64 = sys_mmap(NB*8) as *i64 20 let mvy: *i64 = sys_mmap(NB*8) as *i64 21 var by: i64 = 0 22 while by < BH { 23 var bx: i64 = 0 24 while bx < BW { 25 let i: i64 = by*BW + bx 26 var dx: i64 = 3; var dy: i64 = 1 // the pan 27 if bx >= 2 { if bx <= 3 { if by >= 1 { if by <= 2 { dx = 3; dy = 5 } } } } // object 28 if bx == 5 { if by == 0 { dx = 8; dy = 0 - 2 } } // fast block 29 mvx[i] = dx; mvy[i] = dy 30 bx = bx + 1 31 } 32 by = by + 1 33 } 34 35 let L: *i64 = sys_mmap(2*8) as *i64 36 let T: *i64 = sys_mmap(2*8) as *i64 37 let TR: *i64 = sys_mmap(2*8) as *i64 38 let pred: *i64 = sys_mmap(2*8) as *i64 39 40 var abs_bits: i64 = 0 41 var diff_bits: i64 = 0 42 by = 0 43 while by < BH { 44 var bx: i64 = 0 45 while bx < BW { 46 let i: i64 = by*BW + bx 47 // neighbours (0 if off-grid): L=left, T=top, TR=top-right 48 L[0]=0; L[1]=0; T[0]=0; T[1]=0; TR[0]=0; TR[1]=0 49 if bx > 0 { L[0]=mvx[i-1]; L[1]=mvy[i-1] } 50 if by > 0 { T[0]=mvx[i-BW]; T[1]=mvy[i-BW] } 51 if by > 0 { if bx < BW-1 { TR[0]=mvx[i-BW+1]; TR[1]=mvy[i-BW+1] } } 52 mvp_predict(L, T, TR, pred) 53 abs_bits = abs_bits + vbits(mvx[i]) + vbits(mvy[i]) 54 diff_bits = diff_bits + vbits(mvx[i]-pred[0]) + vbits(mvy[i]-pred[1]) 55 bx = bx + 1 56 } 57 by = by + 1 58 } 59 60 // separate the varint's fixed 5-bit length prefix (per component, unavoidable) from the magnitude bits MVP targets 61 let prefix: i64 = 5 * 2 * NB 62 let abs_mag: i64 = abs_bits - prefix 63 let pred_mag: i64 = diff_bits - prefix 64 65 g_puts(" [measure] MV coding over " as *u8); g_pn(NB); g_puts(" blocks: absolute=" as *u8); g_pn(abs_bits); g_puts(" bits predicted=" as *u8); g_pn(diff_bits); g_puts(" bits (total saving " as *u8); g_pn((abs_bits - diff_bits) * 100 / abs_bits); g_puts("%)\n" as *u8) 66 g_puts(" [measure] MV MAGNITUDE bits (ex the fixed 5-bit prefix): absolute=" as *u8); g_pn(abs_mag); g_puts(" predicted=" as *u8); g_pn(pred_mag); g_puts(" (saving " as *u8); g_pn((abs_mag - pred_mag) * 100 / abs_mag); g_puts("%)\n" as *u8) 67 68 pass = pass + g_check("predicted MV coding costs fewer bits than absolute" as *u8, diff_bits < abs_bits); total=total+1 69 pass = pass + g_check("MVP cuts MV MAGNITUDE bits >= 50% (its real effect; the fixed 5-bit prefix masks it in the total)" as *u8, pred_mag * 2 <= abs_mag); total=total+1 70 pass = pass + g_check("total MV-bit saving >= 20% even with the prefix overhead" as *u8, diff_bits * 5 <= abs_bits * 4); total=total+1 71 72 g_puts("---- vmvpred gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 73 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 74 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 75 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 76 let ctr__dry: *i64 = gv_ctr() 77 ctr__dry[0] = pass 78 ctr__dry[1] = total 79 let rc__dry: i64 = gv_verdict("VMVPRED-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 80 sys_exit(rc__dry) 81 return rc__dry 82}