• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Eyevinn / hi264 / 22355512869

24 Feb 2026 02:37PM UTC coverage: 87.965% (+0.4%) from 87.558%
22355512869

push

github

tobbee
feat: 8x8 block granularity, double-res text glyphs, and PlaneGrid

Add 8x8 block resolution for the encoder. Each grid character maps to
an 8x8 block (4 per macroblock) with proper AC residual encoding at
quadrant boundaries using a forward 4x4 integer DCT.

Introduce PlaneGrid type for direct Y/Cb/Cr value planes with no
character-count limit, supporting both 16x16 and 8x8 block granularity.
All CLI output paths now use PlaneGrid as intermediate representation.

Add 6x10 double-resolution font (Glyph2x) for 8x8 block mode, giving
4x the glyph detail of the 3x5 font at the same pixel footprint.
Even text scales (2, 4, 6...) in 16x16 mode auto-select the 2x font
for sharper glyphs without requiring -8x8.

Text character set aligned across both fonts: A-Z 0-9 and
! # % + - . / : = ? [ ] _ ( ) plus space. Lowercase a-z and
rarely-used punctuation removed; lowercase input auto-uppercased.

Bug fixes:
- CAVLC level VLC encoding overflow for large coefficients (QP=0)
- Encoder reconstruction order (inverse Hadamard before dequant)
- SMPTE bars distributed at block-column granularity in -8x8 mode
- CLI -8x8 flag takes priority over .gridimg default block size

1068 of 1182 new or added lines in 11 files covered. (90.36%)

5 existing lines in 3 files now uncovered.

7236 of 8226 relevant lines covered (87.96%)

1.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.21
/pkg/encode/forward.go
1
package encode
2

3
import "github.com/Eyevinn/hi264/internal/transform"
4

5
// ForwardHadamard4x4 performs the forward 4x4 Hadamard transform for luma DC.
6
// The Hadamard transform is self-inverse (up to scaling), so we use the same
7
// butterfly structure as the inverse.
8
func ForwardHadamard4x4(dc [16]int32) [16]int32 {
1✔
9
        var temp [16]int32
1✔
10

1✔
11
        // 1D Hadamard on rows
1✔
12
        for i := range 4 {
2✔
13
                s0 := dc[i*4+0]
1✔
14
                s1 := dc[i*4+1]
1✔
15
                s2 := dc[i*4+2]
1✔
16
                s3 := dc[i*4+3]
1✔
17

1✔
18
                temp[i*4+0] = s0 + s1 + s2 + s3
1✔
19
                temp[i*4+1] = s0 + s1 - s2 - s3
1✔
20
                temp[i*4+2] = s0 - s1 - s2 + s3
1✔
21
                temp[i*4+3] = s0 - s1 + s2 - s3
1✔
22
        }
1✔
23

24
        // 1D Hadamard on columns, with /2 normalization
25
        var result [16]int32
1✔
26
        for j := range 4 {
2✔
27
                f0 := temp[0*4+j]
1✔
28
                f1 := temp[1*4+j]
1✔
29
                f2 := temp[2*4+j]
1✔
30
                f3 := temp[3*4+j]
1✔
31

1✔
32
                result[0*4+j] = (f0 + f1 + f2 + f3) / 2
1✔
33
                result[1*4+j] = (f0 + f1 - f2 - f3) / 2
1✔
34
                result[2*4+j] = (f0 - f1 - f2 + f3) / 2
1✔
35
                result[3*4+j] = (f0 - f1 + f2 - f3) / 2
1✔
36
        }
1✔
37

38
        return result
1✔
39
}
40

41
// ForwardHadamard2x2 performs the forward 2x2 Hadamard transform for chroma DC.
42
// Self-inverse (up to scaling).
43
func ForwardHadamard2x2(dc [4]int32) [4]int32 {
1✔
44
        return [4]int32{
1✔
45
                dc[0] + dc[1] + dc[2] + dc[3],
1✔
46
                dc[0] - dc[1] + dc[2] - dc[3],
1✔
47
                dc[0] + dc[1] - dc[2] - dc[3],
1✔
48
                dc[0] - dc[1] - dc[2] + dc[3],
1✔
49
        }
1✔
50
}
1✔
51

52
// MF4x4 is the forward quantization multiplication factor table.
53
// Indexed by QP%6 and position category (same as dequant LevelScale).
54
// These are the standard forward quantization factors from JM reference.
55
var MF4x4 = [6][3]int32{
56
        {13107, 8066, 5243},
57
        {11916, 7490, 4660},
58
        {10082, 6554, 4194},
59
        {9362, 5825, 3647},
60
        {8192, 5243, 3355},
61
        {7282, 4559, 2893},
62
}
63

64
// Quantize4x4 performs forward quantization on a 4x4 block.
65
// Returns quantized coefficients (levels).
66
func Quantize4x4(coeffs [16]int32, qp int) [16]int32 {
1✔
67
        var result [16]int32
1✔
68

1✔
69
        qpPer := qp / 6
1✔
70
        qpRem := qp % 6
1✔
71
        qBits := 15 + qpPer
1✔
72
        add := int32(1) << uint(qBits) / 3 // rounding for intra
1✔
73

1✔
74
        for i := range 16 {
2✔
75
                row := i / 4
1✔
76
                col := i % 4
1✔
77
                v := levelScaleIdx(row, col)
1✔
78
                mf := MF4x4[qpRem][v]
1✔
79

1✔
80
                sign := int32(1)
1✔
81
                c := coeffs[i]
1✔
82
                if c < 0 {
2✔
83
                        sign = -1
1✔
84
                        c = -c
1✔
85
                }
1✔
86
                result[i] = sign * ((c*mf + add) >> uint(qBits))
1✔
87
        }
88
        return result
1✔
89
}
90

91
// QuantizeDC4x4 performs forward quantization on 16x16 luma DC coefficients.
92
// wsDC is the scaling list DC value (typically 16 for flat default).
93
func QuantizeDC4x4(coeffs [16]int32, qp int, wsDC int32) [16]int32 {
1✔
94
        var result [16]int32
1✔
95

1✔
96
        qpPer := qp / 6
1✔
97
        qpRem := qp % 6
1✔
98
        mf := MF4x4[qpRem][0]
1✔
99
        // Adjust mf for scaling list: mf = mf * 16 / wsDC
1✔
100
        if wsDC != 16 {
1✔
101
                mf = mf * 16 / wsDC
×
102
        }
×
103
        qBits := 15 + qpPer + 1 // extra +1 for DC after Hadamard normalization
1✔
104
        add := int32(1) << uint(qBits) / 3
1✔
105

1✔
106
        for i := range 16 {
2✔
107
                sign := int32(1)
1✔
108
                c := coeffs[i]
1✔
109
                if c < 0 {
2✔
110
                        sign = -1
1✔
111
                        c = -c
1✔
112
                }
1✔
113
                result[i] = sign * ((c*mf + add) >> uint(qBits))
1✔
114
        }
115
        return result
1✔
116
}
117

118
// QuantizeChromaDC2x2 performs forward quantization on chroma DC coefficients (4:2:0).
119
func QuantizeChromaDC2x2(coeffs [4]int32, qpc int) [4]int32 {
1✔
120
        var result [4]int32
1✔
121

1✔
122
        qpPer := qpc / 6
1✔
123
        qpRem := qpc % 6
1✔
124
        mf := MF4x4[qpRem][0]
1✔
125
        qBits := 15 + qpPer + 1
1✔
126
        add := int32(1) << uint(qBits) / 3
1✔
127

1✔
128
        for i := range 4 {
2✔
129
                sign := int32(1)
1✔
130
                c := coeffs[i]
1✔
131
                if c < 0 {
2✔
132
                        sign = -1
1✔
133
                        c = -c
1✔
134
                }
1✔
135
                result[i] = sign * ((c*mf + add) >> uint(qBits))
1✔
136
        }
137
        return result
1✔
138
}
139

140
// levelScaleIdx maps (row, col) to LevelScale/MF index.
141
func levelScaleIdx(row, col int) int {
1✔
142
        r := row % 2
1✔
143
        c := col % 2
1✔
144
        if r == 0 && c == 0 {
2✔
145
                return 0
1✔
146
        }
1✔
147
        if r == 1 && c == 1 {
2✔
148
                return 2
1✔
149
        }
1✔
150
        return 1
1✔
151
}
152

153
// ChromaQP maps luma QP to chroma QP (Table 8-15).
154
func ChromaQP(qpY int) int {
1✔
155
        if qpY < 0 {
1✔
156
                qpY = 0
×
157
        }
×
158
        if qpY < 30 {
2✔
159
                return qpY
1✔
160
        }
1✔
161
        if qpY > 51 {
×
162
                return 51
×
163
        }
×
164
        qpcTable := []int{
×
165
                29, 30, 31, 32, 32, 33, 34, 34,
×
166
                35, 35, 36, 36, 37, 37, 37, 38,
×
167
                38, 38, 39, 39, 39, 39,
×
168
        }
×
169
        return qpcTable[qpY-30]
×
170
}
171

172
// ForwardTransformDC4x4Const computes the DC coefficient of a 4x4 block
173
// from a constant residual value. For a constant block with value R:
174
// DC = 16*R (forward 4x4 DCT: row sum 4R, column sum 4*4R = 16R).
NEW
175
func ForwardTransformDC4x4Const(residual int32) int32 {
×
UNCOV
176
        return 16 * residual
×
UNCOV
177
}
×
178

179
// ForwardTransformDC4x4 is an alias for ForwardTransformDC4x4Const for backward compatibility.
NEW
180
func ForwardTransformDC4x4(residual int32) int32 {
×
NEW
181
        return ForwardTransformDC4x4Const(residual)
×
NEW
182
}
×
183

184
// ForwardTransform4x4 performs the forward 4x4 integer DCT.
185
// Input: 16 residual samples in raster order (row*4+col).
186
// Output: 16 transform coefficients in raster order.
187
// This is the inverse of InverseTransform4x4 in internal/transform.
188
func ForwardTransform4x4(block [16]int32) [16]int32 {
1✔
189
        var temp [16]int32
1✔
190

1✔
191
        // 1D transform on rows
1✔
192
        for i := range 4 {
2✔
193
                s0 := block[i*4+0]
1✔
194
                s1 := block[i*4+1]
1✔
195
                s2 := block[i*4+2]
1✔
196
                s3 := block[i*4+3]
1✔
197

1✔
198
                p0 := s0 + s3
1✔
199
                p1 := s1 + s2
1✔
200
                p2 := s1 - s2
1✔
201
                p3 := s0 - s3
1✔
202

1✔
203
                temp[i*4+0] = p0 + p1
1✔
204
                temp[i*4+1] = p2 + (p3 << 1)
1✔
205
                temp[i*4+2] = p0 - p1
1✔
206
                temp[i*4+3] = p3 - (p2 << 1)
1✔
207
        }
1✔
208

209
        // 1D transform on columns
210
        var result [16]int32
1✔
211
        for j := range 4 {
2✔
212
                s0 := temp[0*4+j]
1✔
213
                s1 := temp[1*4+j]
1✔
214
                s2 := temp[2*4+j]
1✔
215
                s3 := temp[3*4+j]
1✔
216

1✔
217
                p0 := s0 + s3
1✔
218
                p1 := s1 + s2
1✔
219
                p2 := s1 - s2
1✔
220
                p3 := s0 - s3
1✔
221

1✔
222
                result[0*4+j] = p0 + p1
1✔
223
                result[1*4+j] = p2 + (p3 << 1)
1✔
224
                result[2*4+j] = p0 - p1
1✔
225
                result[3*4+j] = p3 - (p2 << 1)
1✔
226
        }
1✔
227

228
        return result
1✔
229
}
230

231
// ForwardTransformDC4x4Block computes the full 4x4 DCT coefficients for a block
232
// made of at most 4 constant-value quadrants. The block is composed of:
233
//
234
//        vals[0] vals[1]   (top-left 2x2, top-right 2x2)
235
//        vals[2] vals[3]   (bottom-left 2x2, bottom-right 2x2)
236
//
237
// This avoids building a 16-element pixel array by computing the transform
238
// analytically from the 4 quadrant values.
239
func ForwardTransformDC4x4Block(vals [4]int32) [16]int32 {
1✔
240
        // Build the 4x4 residual block from the quadrant values
1✔
241
        var block [16]int32
1✔
242
        for r := range 4 {
2✔
243
                for c := range 4 {
2✔
244
                        qr := r / 2 // 0 for rows 0-1, 1 for rows 2-3
1✔
245
                        qc := c / 2 // 0 for cols 0-1, 1 for cols 2-3
1✔
246
                        block[r*4+c] = vals[qr*2+qc]
1✔
247
                }
1✔
248
        }
249
        return ForwardTransform4x4(block)
1✔
250
}
251

252
// ForwardDequantRoundTrip verifies that forward quant + dequant of a DC value
253
// round-trips correctly. Used only for testing.
254
func ForwardDequantRoundTrip(dc int32, qp int) (quantized, dequantized int32) {
1✔
255
        // Forward Hadamard of 16 identical DC values
1✔
256
        var dcMatrix [16]int32
1✔
257
        for i := range dcMatrix {
2✔
258
                dcMatrix[i] = dc
1✔
259
        }
1✔
260
        hadamard := ForwardHadamard4x4(dcMatrix)
1✔
261

1✔
262
        // Forward quantize
1✔
263
        quantizedMatrix := QuantizeDC4x4(hadamard, qp, 16)
1✔
264

1✔
265
        // Inverse: dequant then inverse Hadamard
1✔
266
        dequantMatrix := transform.DequantDC4x4(quantizedMatrix, qp, 16)
1✔
267
        invHadamard := transform.InverseHadamard4x4(dequantMatrix)
1✔
268

1✔
269
        return quantizedMatrix[0], invHadamard[0]
1✔
270
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc