code wiki / _hdl_build / nx_vcodec_subpel_gate.nx
nx_vcodec_subpel_gate.nx source
↩ module page · 74 lines · 4095 B
1// nx_vcodec_subpel_gate.nx -- proves the half-pel wiring is REALIZED inside the transmittable codec: a frame shifted
2// by exactly 0.5px is encoded inter, the decoder reconstructs it BIT-EXACT, and the half-pel predictor slashes the
3// residual the codec must code (vs what integer-only prediction would leave) -- the in-codec sub-pixel q/bit win.
4import "nx_syscalls.nx"
5import "nx_gate_emit_lib.nx"
6import "nx_vcodec.nx"
7
8func g_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
9func frame_equal(a: *u8, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if a[i]!=b[i] { return 0 } i=i+1 } return 1 }
10func frame_maxerr(a: *u8, b: *u8, n: i64) -> i64 { var m: i64=0; var i: i64=0; while i<n { let e: i64=g_abs((a[i] as i64)-(b[i] as i64)); if e>m { m=e } i=i+1 } return m }
11
12func main() -> i64 {
13 g_puts("nx_vcodec sub-pixel gate (half-pel realized IN the codec, BIT-EXACT + q/bit)\n" as *u8)
14 var pass: i64 = 0; var total: i64 = 0
15 let W: i64 = 48; let H: i64 = 32; let N: i64 = W*H
16 let QP: i64 = 12; let SAD_THRESH: i64 = 64
17
18 let f0: *u8 = sys_mmap(N) as *u8
19 let f1: *u8 = sys_mmap(N) as *u8
20 let recon0: *u8 = sys_mmap(N) as *u8
21 let enc1: *u8 = sys_mmap(N) as *u8
22 let dec1: *u8 = sys_mmap(N) as *u8
23 let stream: *u8 = sys_mmap(8192) as *u8
24 let blk: *i64 = sys_mmap(16*8) as *i64
25 let mv: *i64 = sys_mmap(2*8) as *i64
26
27 // textured reference (neighbours differ so sub-pixel motion is real), f1 = f0 shifted +0.5px in x
28 var y: i64 = 0
29 while y < H { var x: i64 = 0
30 while x < W { f0[y*W+x] = (40 + ((x*11 + y*7) % 120)) as u8; x = x + 1 } y = y + 1 }
31 y = 0
32 while y < H { var x: i64 = 0
33 while x < W - 1 { f1[y*W+x] = (((f0[y*W+x] as i64) + (f0[y*W+(x+1)] as i64) + 1) / 2) as u8; x = x + 1 }
34 f1[y*W + (W-1)] = f0[y*W + (W-1)]; y = y + 1 }
35
36 // keyframe f0 -> shared reference recon0 (encoder + decoder agree)
37 vc_enc_frame_packed(f0, recon0, recon0, W, H, QP, 1, SAD_THRESH, stream, blk, mv)
38 vc_dec_frame_packed(recon0, recon0, W, H, QP, stream, blk, mv) // recon0 now = the reference both sides hold
39
40 // encode the 0.5px-shifted frame INTER, then decode independently
41 let bits: i64 = vc_enc_frame_packed(f1, recon0, enc1, W, H, QP, 0, SAD_THRESH, stream, blk, mv)
42 let bytes: i64 = (bits + 7) / 8
43 vc_dec_frame_packed(recon0, dec1, W, H, QP, stream, blk, mv)
44
45 let eq: i64 = frame_equal(enc1, dec1, N)
46 let q: i64 = frame_maxerr(enc1, f1, N)
47
48 // evidence: residual the codec would face WITHOUT half-pel (integer prediction) vs WITH (half-pel), over an interior MB
49 let cx: i64 = 0; let cy: i64 = 0
50 var int_sad: i64 = 0
51 var half_sad: i64 = 0
52 var ry: i64 = 0
53 while ry < 16 {
54 var rx: i64 = 0
55 while rx < 16 {
56 let cur: i64 = f1[(cy+ry)*W + (cx+rx)] as i64
57 int_sad = int_sad + g_abs(cur - hp_pixel(recon0, W, cx+rx, cy+ry, 0, 0))
58 half_sad = half_sad + g_abs(cur - hp_pixel(recon0, W, cx+rx, cy+ry, 1, 0))
59 rx = rx + 1
60 }
61 ry = ry + 1
62 }
63
64 g_puts(" [measure] 0.5px-shift inter stream=" as *u8); g_pn(bytes); g_puts(" B recon max-err vs original=" as *u8); g_pn(q); g_puts("\n" as *u8)
65 g_puts(" [measure] one MB residual SAD: integer-pred=" as *u8); g_pn(int_sad); g_puts(" half-pel-pred=" as *u8); g_pn(half_sad); g_puts(" (the bits half-pel saves)\n" as *u8)
66
67 pass = pass + g_check("0.5px-shift frame round-trips BIT-EXACT through the codec (decoder == encoder)" as *u8, eq); total=total+1
68 pass = pass + g_check("reconstruction faithful (max-err <= 16, normal QP=12 lossy on a real residual)" as *u8, q <= 16); total=total+1
69 pass = pass + g_check("codec's half-pel slashes the residual integer-pred would leave (>= 4x smaller)" as *u8, half_sad * 4 < int_sad); total=total+1
70
71 g_puts("---- vcodec sub-pixel gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
72 if pass == total { g_puts("verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
73 g_puts("verdict=RED\n" as *u8); sys_exit(1); return 1
74}