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}