code wiki / (root) / nx_yuvgen.nx

nx_yuvgen.nx source

↩ module page · 134 lines · 5909 B

1// nx_yuvgen.nx -- synthesise a YUV420p test clip so the videocodec gates can RUN on the NAS. 2// 3// WHY THIS EXISTS. 17 videocodec gates all open 4// /mnt/c/Users/elder/nishi-core/nxc2/knowledge/staging/media/bframe_test_decoded.yuv 5// a HARDCODED LAPTOP PATH. Execution moved laptop->NAS and the asset did not follow, so all 17 return 6// "cannot read yuv -> RED" with pass=0/0 -- ZERO teeth run. That is a gate that never executed, not a 7// gate that failed, and it is currently what blocks EVERY deploy in the ecosystem through the 8// nx_deploy_ready evidence-honesty check. The file is absent from the LAPTOP too, so the evidence has 9// been unreproducible for some time and the RED is honest. 10// 11// WHY SYNTHETIC IS THE RIGHT ANSWER, NOT A COMPROMISE. These benches measure codec BEHAVIOUR -- B-frame 12// vs P-chain at matched PSNR, decode parity, motion-vector cost. That needs real MOTION, not a real 13// movie. A generated clip with KNOWN, CONTROLLED motion is a better instrument than an arbitrary 14// video: the ground truth is exact, it is hermetic, it costs no 10MB asset transfer, and it cannot 15// silently change under you. Same reasoning that made nx_q4k_dot_simd runnable with synthesised Q4_K 16// blocks instead of a 1.1GB model. 17// 18// CONTENT (deliberately non-degenerate -- a flat or static clip would make the comparison meaningless): 19// - a fixed diagonal gradient background, so intra prediction has real structure to model; 20// - a bright block TRANSLATING a few pixels per frame, so motion estimation has a true displacement 21// to find and B-frames have something to interpolate that P-chains must code; 22// - a slow luma pedestal drift, so rate control sees frame-to-frame change. 23// U/V carry a mild spatial ramp plus a per-frame tint so chroma is exercised rather than constant. 24// 25// argv: <outpath> [W] [H] [frames] defaults 576x1024x16 (the gates need >=12). 26// Writes plain YUV420p: Y plane W*H, then U and V each (W/2)*(H/2), per frame, no header. 27// license_tier: ORIGINAL No hw writes (Rule 26). 28import "nx_syscalls.nx" 29import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 30 31const YG_DEF_W: i64 = 576 32const YG_DEF_H: i64 = 1024 33const YG_DEF_F: i64 = 16 34const YG_MODE: i64 = 420 35 36func yg_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 37func yg_p(s: *u8) -> i64 { sys_write(1, s, yg_len(s)); return 0 } 38// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 39// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 40// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 41// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 42func yg_n(v: i64) -> i64 { nxi_out(v); return 0 } 43func yg_atoi(s: *u8) -> i64 { 44 var v: i64 = 0 45 var i: i64 = 0 46 while s[i] != (0 as u8) { 47 let c: i64 = s[i] as i64 48 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 49 i = i + 1 50 } 51 return v 52} 53func yg_clamp(v: i64) -> i64 { 54 if v < 16 { return 16 } 55 if v > 235 { return 235 } 56 return v 57} 58 59func main(argc: i64, argv: *i64) -> i64 { 60 if argc < 2 { 61 yg_p("usage: nx_yuvgen <outpath> [W] [H] [frames] (YUV420p, default 576x1024x16)\n" as *u8) 62 return 2 63 } 64 let path: *u8 = argv[1] as *u8 65 var W: i64 = YG_DEF_W 66 var H: i64 = YG_DEF_H 67 var F: i64 = YG_DEF_F 68 if argc >= 3 { W = yg_atoi(argv[2] as *u8) } 69 if argc >= 4 { H = yg_atoi(argv[3] as *u8) } 70 if argc >= 5 { F = yg_atoi(argv[4] as *u8) } 71 if W <= 0 { return 3 } 72 if H <= 0 { return 3 } 73 if F <= 0 { return 3 } 74 75 let cw: i64 = W / 2 76 let ch: i64 = H / 2 77 let ysz: i64 = W * H 78 let csz: i64 = cw * ch 79 let yb: *u8 = sys_mmap(ysz + 64) 80 let ub: *u8 = sys_mmap(csz + 64) 81 let vb: *u8 = sys_mmap(csz + 64) 82 83 let fd: i64 = sys_openat_wr(path, 420) 84 if fd < 0 { yg_p("REFUSED reason=outfile-unwritable path=" as *u8); yg_p(path); yg_p("\n" as *u8); return 4 } 85 86 var total: i64 = 0 87 var f: i64 = 0 88 while f < F { 89 // moving block: translates diagonally, wrapping, so every frame has a true displacement 90 let bx: i64 = (f * 11) % (W - 64) 91 let by: i64 = (f * 7) % (H - 64) 92 let ped: i64 = (f * 3) % 24 93 var y: i64 = 0 94 while y < H { 95 var x: i64 = 0 96 let row: i64 = y * W 97 while x < W { 98 var lum: i64 = 40 + ((x + y) % 160) + ped 99 if x >= bx { if x < bx + 64 { if y >= by { if y < by + 64 { lum = 210 } } } } 100 yb[row + x] = yg_clamp(lum) as u8 101 x = x + 1 102 } 103 y = y + 1 104 } 105 var cy: i64 = 0 106 while cy < ch { 107 var cx: i64 = 0 108 let crow: i64 = cy * cw 109 while cx < cw { 110 ub[crow + cx] = yg_clamp(110 + (cx % 40) + (f % 12)) as u8 111 vb[crow + cx] = yg_clamp(130 + (cy % 40) - (f % 12)) as u8 112 cx = cx + 1 113 } 114 cy = cy + 1 115 } 116 var w1: i64 = 0 117 while w1 < ysz { let r: i64 = sys_write(fd, ((yb as i64) + w1) as *u8, ysz - w1); if r <= 0 { w1 = ysz } else { w1 = w1 + r } } 118 var w2: i64 = 0 119 while w2 < csz { let r: i64 = sys_write(fd, ((ub as i64) + w2) as *u8, csz - w2); if r <= 0 { w2 = csz } else { w2 = w2 + r } } 120 var w3: i64 = 0 121 while w3 < csz { let r: i64 = sys_write(fd, ((vb as i64) + w3) as *u8, csz - w3); if r <= 0 { w3 = csz } else { w3 = w3 + r } } 122 total = total + ysz + csz + csz 123 f = f + 1 124 } 125 sys_close(fd) 126 yg_p("NX-YUVGEN OK path=" as *u8); yg_p(path) 127 yg_p(" mode=" as *u8); yg_n(YG_MODE) 128 yg_p(" w=" as *u8); yg_n(W) 129 yg_p(" h=" as *u8); yg_n(H) 130 yg_p(" frames=" as *u8); yg_n(F) 131 yg_p(" bytes=" as *u8); yg_n(total) 132 yg_p("\n" as *u8) 133 return 0 134}