code wiki / (root) / nx_vtransform_dct2.nx

nx_vtransform_dct2.nx source

↩ module page · 98 lines · 4688 B

1// nx_vtransform_dct2.nx -- ROYALTY-FREE integer DCT-II (4x4) for the sovereign video codec. 2// PATENT-CLEAN BY PROVENANCE: the literal Ahmed-Natarajan-Rao 1974 DCT-II basis cos((2n+1)*k*pi/8), evaluated 3// at scale 64 and rounded to integers -> matrix M, with UNIFORM scalar quantization. This is NOT H.264/AVC's 4// specific integer core ([1,1,1,1; 2,1,-1,-2; 1,-1,-1,1; 1,-2,2,-1]) and NOT its position-dependent Mf/Vi quant 5// tables (those are the AVC patent-pool technique), and NOT HEVC's 32x32-derived matrices. The DCT *itself* is 6// 1974 prior art -- CITED to the sovereign-fetched source knowledge/fetched/dct_provenance.raw ("Nasir Ahmed 7// ... in 1972 ... Natarajan ... Rao ... 1974"). Better energy compaction than Walsh-Hadamard on natural images 8// -> recovers the DCT RD win cleanly. Shape-compatible with nx_vtransform: vt2_fwd / vt2_inv / vt2_quant / 9// vt2_dequant operate on a 4x4 i64 block (row-major, 16 elements). 10// license_tier: ORIGINAL 11import "nx_syscalls.nx" 12 13// M = round( orthonormal DCT-II(N=4) * 64 ): 14// row0 [ 32, 32, 32, 32] (DC) 15// row1 [ 42, 17,-17,-42] (cos(pi/8)*sqrt(1/2)*64=41.8->42 ; cos(3pi/8)*sqrt(1/2)*64=17.3->17) 16// row2 [ 32,-32,-32, 32] 17// row3 [ 17,-42, 42,-17] 18// M*M^T ~= 4096*I (DC 4096, AC 4106 -> 0.24% gain imbalance, negligible for lossy). 2D round-trip ~= 4096^2 = 2^24. 19 20const DCT2_QSHIFT: i64 = 10 // q<<10: aligns the quant step with the WHT path's raw scale (DCT 2D fwd 21 // scale 16384 vs WHT 16 -> ratio 1024 = 2^10) so a given QP means ~the same 22 // bitrate on both transforms -> the RD comparison is fair. 23const DCT2_ISHIFT: i64 = 24 // inverse final descale (2D round-trip ~= 4096^2 = 2^24) 24const DCT2_IROUND: i64 = 8388608 // 1<<23, symmetric rounding for the inverse descale 25 26// 1D forward along (base, stride): Y[k] = sum_n M[k][n]*x[n] 27func vt2_1d_fwd(b: *i64, base: i64, st: i64) -> i64 { 28 let x0: i64 = b[base] 29 let x1: i64 = b[base+st] 30 let x2: i64 = b[base+2*st] 31 let x3: i64 = b[base+3*st] 32 b[base] = 32*(x0+x1+x2+x3) 33 b[base+st] = 42*x0 + 17*x1 - 17*x2 - 42*x3 34 b[base+2*st] = 32*(x0 - x1 - x2 + x3) 35 b[base+3*st] = 17*x0 - 42*x1 + 42*x2 - 17*x3 36 return 0 37} 38// 1D inverse along (base, stride): x[n] = sum_k M[k][n]*Y[k] (apply M^T) 39func vt2_1d_inv(b: *i64, base: i64, st: i64) -> i64 { 40 let y0: i64 = b[base] 41 let y1: i64 = b[base+st] 42 let y2: i64 = b[base+2*st] 43 let y3: i64 = b[base+3*st] 44 b[base] = 32*y0 + 42*y1 + 32*y2 + 17*y3 45 b[base+st] = 32*y0 + 17*y1 - 32*y2 - 42*y3 46 b[base+2*st] = 32*y0 - 17*y1 - 32*y2 + 42*y3 47 b[base+3*st] = 32*y0 - 42*y1 + 32*y2 - 17*y3 48 return 0 49} 50func vt2_fwd(blk: *i64) -> i64 { 51 var i: i64 = 0 52 while i < 4 { vt2_1d_fwd(blk, i*4, 1); i = i + 1 } // transform rows 53 i = 0 54 while i < 4 { vt2_1d_fwd(blk, i, 4); i = i + 1 } // transform columns 55 return 0 56} 57func vt2_inv(blk: *i64) -> i64 { 58 var i: i64 = 0 59 while i < 4 { vt2_1d_inv(blk, i, 4); i = i + 1 } // inverse columns 60 i = 0 61 while i < 4 { vt2_1d_inv(blk, i*4, 1); i = i + 1 } // inverse rows 62 i = 0 63 while i < 16 { // final descale (>>24) with symmetric rounding 64 let v: i64 = blk[i] 65 if v >= 0 { blk[i] = (v + DCT2_IROUND) >> DCT2_ISHIFT } 66 else { blk[i] = 0 - ((0 - v + DCT2_IROUND) >> DCT2_ISHIFT) } 67 i = i + 1 68 } 69 return 0 70} 71// QUANT ROUNDING OFFSET in 24ths of the step (rule-11; F1116 sweep 2026-07-28). 0 = the historical 72// floor-quant = WIDEST deadzone with dequant at the bin's LOWER EDGE (every nonzero systematically 73// under-reconstructed by ~d/2 mean). H.264 practice: f=d/6 (inter) .. d/3 (intra) narrows the deadzone 74// so reconstruction error centers. ENCODER-ONLY: dequant (and thus every decoder) is untouched; the 75// encoder reconstructs from the same levels, so enc==dec parity holds by construction at ANY value. 76const VC_QOFF_24: i64 = 10 77// deadzone scalar quant: blk[i] /= (q<<10), truncation toward zero (sign-explicit). returns nonzero count. 78func vt2_quant(blk: *i64, q: i64) -> i64 { 79 let d: i64 = q << DCT2_QSHIFT 80 let f0: i64 = (d * VC_QOFF_24) / 24 81 var nz: i64 = 0 82 var i: i64 = 0 83 while i < 16 { 84 let v: i64 = blk[i] 85 var r: i64 = 0 86 if v >= 0 { r = (v + f0) / d } else { r = 0 - ((0 - v + f0) / d) } 87 blk[i] = r 88 if r != 0 { nz = nz + 1 } 89 i = i + 1 90 } 91 return nz 92} 93func vt2_dequant(blk: *i64, q: i64) -> i64 { 94 let d: i64 = q << DCT2_QSHIFT 95 var i: i64 = 0 96 while i < 16 { blk[i] = blk[i] * d; i = i + 1 } 97 return 0 98}