code wiki / (root) / nx_h264_idct.nx

nx_h264_idct.nx source

↩ module page · 77 lines · 2939 B

1// nx_h264_idct.nx -- H.264 4x4 inverse integer transform (rung 5-core, built 2// bottom-up). THE deterministic DSP kernel at the base of pixel reconstruction: 3// dequantized transform coefficients -> residual samples. Spec ITU-T H.264 4// section 8.5.12.2 (residual 4x4): two butterfly passes (rows then columns) then 5// r = (h + 32) >> 6. Reusable regardless of the entropy layer above. 6// 7// Arithmetic right shift (floor, sign-preserving) is REQUIRED on negatives. We 8// implement asr() to shift only non-negative magnitudes, so correctness does NOT 9// depend on whether the language '>>' is arithmetic or logical -- the gate's 10// negative outputs (e.g. -1) prove it. 11// 12// genealogy_id: itu_t_h264_sec8_5_residual_transform + malvar_2003_low_complexity_transform 13// lineage_id: integer_butterfly_2pass + round_shift6 14// license_tier: ORIGINAL 15import "nx_syscalls.nx" 16 17// arithmetic shift right by n (floor toward -inf), shift-semantics-independent 18func asr(x: i64, n: i64) -> i64 { 19 if x >= 0 { return x >> n } 20 let p: i64 = 0 - x 21 return 0 - ((p + ((1 << n) - 1)) >> n) 22} 23 24// in-place inverse transform of a 16-element row-major 4x4 coefficient block 25// LEAK FIX 2026-08-01: this mmapped a 16-word scratch PER CALL and runs once per 26// 4x4 block (~196,000 calls per 1080p frame) with page-granular mmap and no free. 27// The _s variant takes caller-provided scratch; the old wrapper is kept so the 10 28// cold callers (gates/tests) need no change. 29func nx_idct4x4(d: *i64) -> i64 { let f: *i64 = sys_mmap(16 * 8) as *i64; return nx_idct4x4_s(d, f) } 30func nx_idct4x4_s(d: *i64, f: *i64) -> i64 { 31 var i: i64 = 0 32 while i < 4 { 33 let z0: i64 = d[i * 4 + 0] 34 let z1: i64 = d[i * 4 + 1] 35 let z2: i64 = d[i * 4 + 2] 36 let z3: i64 = d[i * 4 + 3] 37 let e0: i64 = z0 + z2 38 let e1: i64 = z0 - z2 39 let e2: i64 = asr(z1, 1) - z3 40 let e3: i64 = z1 + asr(z3, 1) 41 f[i * 4 + 0] = e0 + e3 42 f[i * 4 + 1] = e1 + e2 43 f[i * 4 + 2] = e1 - e2 44 f[i * 4 + 3] = e0 - e3 45 i = i + 1 46 } 47 var j: i64 = 0 48 while j < 4 { 49 let z0: i64 = f[0 * 4 + j] 50 let z1: i64 = f[1 * 4 + j] 51 let z2: i64 = f[2 * 4 + j] 52 let z3: i64 = f[3 * 4 + j] 53 let g0: i64 = z0 + z2 54 let g1: i64 = z0 - z2 55 let g2: i64 = asr(z1, 1) - z3 56 let g3: i64 = z1 + asr(z3, 1) 57 d[0 * 4 + j] = asr(g0 + g3 + 32, 6) 58 d[1 * 4 + j] = asr(g1 + g2 + 32, 6) 59 d[2 * 4 + j] = asr(g1 - g2 + 32, 6) 60 d[3 * 4 + j] = asr(g0 - g3 + 32, 6) 61 j = j + 1 62 } 63 return 0 64} 65 66// reconstruct: out[i] = clip(pred[i] + residual[i], 0, 255) 67func nx_idct_add_clip(pred: *u8, res: *i64, out: *u8, n: i64) -> i64 { 68 var i: i64 = 0 69 while i < n { 70 var v: i64 = (pred[i] as i64) + res[i] 71 if v < 0 { v = 0 } 72 if v > 255 { v = 255 } 73 out[i] = v as u8 74 i = i + 1 75 } 76 return 0 77}