code wiki / (root) / nx_vtransform.nx

nx_vtransform.nx source

↩ module page · 53 lines · 2662 B

1// nx_vtransform.nx -- sovereign 4x4 integer TRANSFORM + QUANTIZE for the motion-comp residual (V-R2). After 2// motion compensation the residual block is small + smooth; a separable 4x4 Walsh-Hadamard transform compacts 3// its energy into a few coefficients (mostly DC), then quantization zeros the small ones -> very few nonzero 4// values to entropy-code. This is the transform+quant stage VP8/H.264 use (they use an integer DCT; WHT is the 5// integer, EXACTLY-invertible first rung -- integer-DCT is a later refinement). Pure integer ops, no FPU/syscalls. 6// Block = 16 i64 row-major (a 4x4 residual). license_tier: ORIGINAL 7 8// 1D 4-point Walsh-Hadamard butterfly on the 4 elements at base, base+st, base+2st, base+3st (in place). 9func vt_wht4(b: *i64, base: i64, st: i64) -> i64 { 10 let s0: i64 = b[base] 11 let s1: i64 = b[base + st] 12 let s2: i64 = b[base + 2*st] 13 let s3: i64 = b[base + 3*st] 14 let a: i64 = s0 + s1 15 let d0: i64 = s0 - s1 16 let c: i64 = s2 + s3 17 let d1: i64 = s2 - s3 18 b[base] = a + c 19 b[base + st] = d0 + d1 20 b[base + 2*st] = a - c 21 b[base + 3*st] = d0 - d1 22 return 0 23} 24// 2D forward transform: WHT on the 4 rows, then the 4 columns. 25func vt_fwd(blk: *i64) -> i64 { 26 var r: i64 = 0; while r < 4 { vt_wht4(blk, r*4, 1); r = r + 1 } 27 var c: i64 = 0; while c < 4 { vt_wht4(blk, c, 4); c = c + 1 } 28 return 0 29} 30// 2D inverse: the WHT is its own inverse up to scale 16 (4 per 1D x 2 passes) -> apply forward then /16. Exact. 31func vt_inv(blk: *i64) -> i64 { 32 var r: i64 = 0; while r < 4 { vt_wht4(blk, r*4, 1); r = r + 1 } 33 var c: i64 = 0; while c < 4 { vt_wht4(blk, c, 4); c = c + 1 } 34 var i: i64 = 0; while i < 16 { blk[i] = blk[i] / 16; i = i + 1 } 35 return 0 36} 37// quantize coefficients by step q with a DEADZONE (truncate toward zero, like H.264/VP8): any coefficient with 38// magnitude < q becomes 0, so the small (high-freq) coeffs vanish -> real compaction. returns the NONZERO count. 39func vt_quant(blk: *i64, q: i64) -> i64 { 40 var nz: i64 = 0 41 var i: i64 = 0 42 while i < 16 { 43 let v: i64 = blk[i] / q // NishiLang integer divide truncates toward zero = deadzone 44 blk[i] = v 45 if v != 0 { nz = nz + 1 } 46 i = i + 1 47 } 48 return nz 49} 50// dequantize (scale back by q) before the inverse transform. 51func vt_dequant(blk: *i64, q: i64) -> i64 { var i: i64 = 0; while i < 16 { blk[i] = blk[i] * q; i = i + 1 } return 0 } 52// count nonzero entries of a block (the entropy-coding cost proxy). 53func vt_nonzero(blk: *i64) -> i64 { var nz: i64 = 0; var i: i64 = 0; while i < 16 { if blk[i] != 0 { nz = nz + 1 } i = i + 1 } return nz }