nx_h264_fdct.nx source
↩ module page · 97 lines · 4347 B
1// nx_h264_fdct.nx -- H.264 FORWARD 4x4 integer transform + forward quantization (the ENCODE counterpart of
2// the existing decode-side nx_h264_idct + nx_h264_dequant). This is the core rung of the sovereign H.264
3// ENCODER (R6, for HEVC->H.264 transcode): residual -> coefficients -> quantized levels, validated by
4// round-tripping back through the proven inverse pieces. The core transform Cf (rows then cols):
5// [1 1 1 1; 2 1 -1 -2; 1 -1 -1 1; 1 -2 2 -1], in butterfly form (no floats). Forward quant uses the
6// standard MF[qp%6][posClass] multiplier matrix + dead-zone f, matching the inverse normAdjust/V table so the
7// pair round-trips. Reuses nx_dq_posclass for the position class (DRY, identical to the dequant). ITU-T H.264
8// transform is public -> patent-clean for the integer math. license_tier: ORIGINAL
9import "nx_syscalls.nx"
10import "nx_h264_dequant.nx" // reuse nx_dq_posclass (position class 0/1/2)
11const K_MAGIC_13107: i64 = 13107
12const K_MAGIC_5243: i64 = 5243
13const K_MAGIC_8066: i64 = 8066
14const K_MAGIC_11916: i64 = 11916
15const K_MAGIC_4660: i64 = 4660
16const K_MAGIC_7490: i64 = 7490
17const K_MAGIC_10082: i64 = 10082
18const K_MAGIC_4194: i64 = 4194
19const K_MAGIC_6554: i64 = 6554
20const K_MAGIC_9362: i64 = 9362
21const K_MAGIC_3647: i64 = 3647
22const K_MAGIC_5825: i64 = 5825
23const K_MAGIC_8192: i64 = 8192
24const K_MAGIC_3355: i64 = 3355
25const K_MAGIC_7282: i64 = 7282
26const K_MAGIC_2893: i64 = 2893
27const K_MAGIC_4559: i64 = 4559
28
29// In-place forward core 4x4 transform on d[16] (raster order). Y = Cf * X * Cf^T.
30func nx_h264_fdct4x4(d: *i64) -> i64 {
31 let t: *i64 = sys_mmap(16 * 8) as *i64
32 var i: i64 = 0
33 while i < 4 {
34 let a: i64 = d[i*4+0]; let b: i64 = d[i*4+1]; let c: i64 = d[i*4+2]; let e: i64 = d[i*4+3]
35 let s0: i64 = a + e; let s1: i64 = b + c; let s2: i64 = b - c; let s3: i64 = a - e
36 t[i*4+0] = s0 + s1; t[i*4+1] = 2*s3 + s2; t[i*4+2] = s0 - s1; t[i*4+3] = s3 - 2*s2
37 i = i + 1
38 }
39 var j: i64 = 0
40 while j < 4 {
41 let a: i64 = t[0*4+j]; let b: i64 = t[1*4+j]; let c: i64 = t[2*4+j]; let e: i64 = t[3*4+j]
42 let s0: i64 = a + e; let s1: i64 = b + c; let s2: i64 = b - c; let s3: i64 = a - e
43 d[0*4+j] = s0 + s1; d[1*4+j] = 2*s3 + s2; d[2*4+j] = s0 - s1; d[3*4+j] = s3 - 2*s2
44 j = j + 1
45 }
46 return 0
47}
48
49// forward quant multiplier MF[m][posClass] (m = qp % 6), the spec's standard matrix.
50func nx_h264_fq_mf(m: i64, pc: i64) -> i64 {
51 let tab: *i64 = sys_mmap(18 * 8) as *i64
52 tab[0]=K_MAGIC_13107; tab[1]=K_MAGIC_5243; tab[2]=K_MAGIC_8066
53 tab[3]=K_MAGIC_11916; tab[4]=K_MAGIC_4660; tab[5]=K_MAGIC_7490
54 tab[6]=K_MAGIC_10082; tab[7]=K_MAGIC_4194; tab[8]=K_MAGIC_6554
55 tab[9]=K_MAGIC_9362; tab[10]=K_MAGIC_3647; tab[11]=K_MAGIC_5825
56 tab[12]=K_MAGIC_8192; tab[13]=K_MAGIC_3355; tab[14]=K_MAGIC_5243
57 tab[15]=K_MAGIC_7282; tab[16]=K_MAGIC_2893; tab[17]=K_MAGIC_4559
58 return tab[m * 3 + pc]
59}
60
61// Forward quantize the 16 core-transformed coeffs c[] at qp into out[] (levels). Dead-zone f = (1<<qbits)/3
62// (intra). |Z| = (|W|*MF + f) >> qbits ; qbits = 15 + qp/6. Sign preserved.
63func nx_h264_fquant4x4(c: *i64, qp: i64, out: *i64) -> i64 {
64 let m: i64 = qp % 6
65 let qbits: i64 = 15 + qp / 6
66 let f: i64 = (1 << qbits) / 3
67 var i: i64 = 0
68 while i < 4 {
69 var j: i64 = 0
70 while j < 4 {
71 let pc: i64 = nx_dq_posclass(i, j)
72 let mf: i64 = nx_h264_fq_mf(m, pc)
73 let idx: i64 = i * 4 + j
74 let w: i64 = c[idx]
75 var a: i64 = w; if a < 0 { a = 0 - a }
76 var z: i64 = (a * mf + f) >> qbits
77 if w < 0 { z = 0 - z }
78 out[idx] = z
79 j = j + 1
80 }
81 i = i + 1
82 }
83 return 0
84}
85
86// Forward 4x4 zig-zag scan: scan[i] = raster[ZZ[i]] (raster -> CAVLC scan order; the inverse permutation of
87// nx_h264_inv_zigzag4x4, ZZ = spec Table 8-12). The encoder feeds these scan-order levels to the CAVLC encoder.
88func nx_h264_fwd_zigzag4x4(raster: *i64, scan: *i64) -> i64 {
89 let zz: *i64 = sys_mmap(16 * 8) as *i64
90 zz[0]=0; zz[1]=1; zz[2]=4; zz[3]=8
91 zz[4]=5; zz[5]=2; zz[6]=3; zz[7]=6
92 zz[8]=9; zz[9]=12; zz[10]=13; zz[11]=10
93 zz[12]=7; zz[13]=11; zz[14]=14; zz[15]=15
94 var i: i64 = 0
95 while i < 16 { scan[i] = raster[zz[i]]; i = i + 1 }
96 return 0
97}