@invintusmedia/tomp4 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,292 +0,0 @@
1
- /**
2
- * H.264 Intra Prediction
3
- *
4
- * Implements Intra 4x4, Intra 8x8, and Intra 16x16 prediction modes
5
- * for luma and chroma. Used during macroblock decoding to reconstruct
6
- * the predicted block from neighboring samples.
7
- *
8
- * Reference: ITU-T H.264, Section 8.3
9
- *
10
- * @module codecs/h264-intra
11
- */
12
-
13
- import { clip255 } from './h264-transform.js';
14
-
15
- // ══════════════════════════════════════════════════════════
16
- // Intra 4x4 Prediction (Section 8.3.1.2)
17
- // 9 modes for each 4x4 luma block
18
- // ══════════════════════════════════════════════════════════
19
-
20
- /**
21
- * Perform Intra 4x4 prediction.
22
- * @param {number} mode - Prediction mode (0-8)
23
- * @param {Int32Array|null} above - 8 samples above (indices 0-3 = directly above, 4-7 = above-right)
24
- * @param {Int32Array|null} left - 4 samples to the left
25
- * @param {number} aboveLeft - Above-left corner sample
26
- * @param {boolean} hasAbove - Whether above samples are available
27
- * @param {boolean} hasLeft - Whether left samples are available
28
- * @param {boolean} hasAboveRight - Whether above-right samples are available
29
- * @returns {Int32Array} 16-element predicted block in raster order
30
- */
31
- export function intra4x4Predict(mode, above, left, aboveLeft, hasAbove, hasLeft, hasAboveRight) {
32
- const pred = new Int32Array(16);
33
-
34
- // Extend above samples: if above-right not available, repeat the last above sample
35
- const p = new Int32Array(13); // p[-1..7] mapped to p[0..12] (index offset: +1)
36
- // p[0] = above-left, p[1..4] = above[0..3], p[5..8] = above-right[0..3]
37
- if (hasAbove) {
38
- for (let i = 0; i < 4; i++) p[i + 1] = above[i];
39
- if (hasAboveRight) {
40
- for (let i = 0; i < 4; i++) p[i + 5] = above[i + 4];
41
- } else {
42
- for (let i = 0; i < 4; i++) p[i + 5] = above[3];
43
- }
44
- }
45
- p[0] = hasAbove && hasLeft ? aboveLeft : hasAbove ? above[0] : hasLeft ? left[0] : 128;
46
-
47
- const l = left || new Int32Array(4); // left[0..3]
48
-
49
- switch (mode) {
50
- case 0: // Vertical
51
- for (let y = 0; y < 4; y++)
52
- for (let x = 0; x < 4; x++)
53
- pred[y * 4 + x] = p[x + 1];
54
- break;
55
-
56
- case 1: // Horizontal
57
- for (let y = 0; y < 4; y++)
58
- for (let x = 0; x < 4; x++)
59
- pred[y * 4 + x] = l[y];
60
- break;
61
-
62
- case 2: { // DC
63
- let sum = 0, count = 0;
64
- if (hasAbove) { for (let i = 0; i < 4; i++) sum += p[i + 1]; count += 4; }
65
- if (hasLeft) { for (let i = 0; i < 4; i++) sum += l[i]; count += 4; }
66
- const dc = count > 0 ? (sum + (count >> 1)) / count | 0 : 128;
67
- pred.fill(dc);
68
- break;
69
- }
70
-
71
- case 3: // Diagonal Down-Left
72
- for (let y = 0; y < 4; y++)
73
- for (let x = 0; x < 4; x++) {
74
- if (x === 3 && y === 3)
75
- pred[y * 4 + x] = (p[6] + 3 * p[7] + 2) >> 2;
76
- else
77
- pred[y * 4 + x] = (p[x + y + 1] + 2 * p[x + y + 2] + p[x + y + 3] + 2) >> 2;
78
- }
79
- break;
80
-
81
- case 4: // Diagonal Down-Right
82
- for (let y = 0; y < 4; y++)
83
- for (let x = 0; x < 4; x++) {
84
- if (x > y)
85
- pred[y * 4 + x] = (p[x - y] + 2 * p[x - y + 1] + p[x - y + 2] + 2) >> 2;
86
- else if (x < y)
87
- pred[y * 4 + x] = (l[y - x - 1] + 2 * (x === 0 && y - 1 >= 0 ? l[y - 1] : l[y - x - 1]) + (y - x >= 2 ? l[y - x - 2] : p[0]) + 2) >> 2;
88
- else // x === y
89
- pred[y * 4 + x] = (p[1] + 2 * p[0] + l[0] + 2) >> 2;
90
- }
91
- break;
92
-
93
- // Modes 5-8 are less common; implement with the standard filter formulas
94
- case 5: // Vertical-Right
95
- for (let y = 0; y < 4; y++)
96
- for (let x = 0; x < 4; x++) {
97
- const zVR = 2 * x - y;
98
- if (zVR >= 0 && (zVR & 1) === 0)
99
- pred[y * 4 + x] = (p[(zVR >> 1)] + p[(zVR >> 1) + 1] + 1) >> 1;
100
- else if (zVR >= 0)
101
- pred[y * 4 + x] = (p[(zVR >> 1)] + 2 * p[(zVR >> 1) + 1] + p[(zVR >> 1) + 2] + 2) >> 2;
102
- else if (zVR === -1)
103
- pred[y * 4 + x] = (l[0] + 2 * p[0] + p[1] + 2) >> 2;
104
- else // zVR < -1
105
- pred[y * 4 + x] = (l[y - 1] + 2 * l[y - 2] + l[y - 3 >= 0 ? y - 3 : 0] + 2) >> 2;
106
- }
107
- break;
108
-
109
- case 6: // Horizontal-Down
110
- for (let y = 0; y < 4; y++)
111
- for (let x = 0; x < 4; x++) {
112
- const zHD = 2 * y - x;
113
- if (zHD >= 0 && (zHD & 1) === 0)
114
- pred[y * 4 + x] = zHD === 0
115
- ? (p[0] + l[0] + 1) >> 1
116
- : (l[(zHD >> 1) - 1] + l[zHD >> 1] + 1) >> 1;
117
- else if (zHD >= 0)
118
- pred[y * 4 + x] = zHD === 1
119
- ? (l[0] + 2 * p[0] + p[1] + 2) >> 2
120
- : (l[(zHD >> 1) - 1] + 2 * l[zHD >> 1] + l[(zHD >> 1) + 1 < 4 ? (zHD >> 1) + 1 : 3] + 2) >> 2;
121
- else if (zHD === -1)
122
- pred[y * 4 + x] = (p[0] + 2 * p[1] + p[2] + 2) >> 2;
123
- else
124
- pred[y * 4 + x] = (p[x - 1] + 2 * p[x] + p[x + 1] + 2) >> 2;
125
- }
126
- break;
127
-
128
- case 7: // Vertical-Left
129
- for (let y = 0; y < 4; y++)
130
- for (let x = 0; x < 4; x++) {
131
- if ((y & 1) === 0)
132
- pred[y * 4 + x] = (p[x + (y >> 1) + 1] + p[x + (y >> 1) + 2] + 1) >> 1;
133
- else
134
- pred[y * 4 + x] = (p[x + (y >> 1) + 1] + 2 * p[x + (y >> 1) + 2] + p[x + (y >> 1) + 3] + 2) >> 2;
135
- }
136
- break;
137
-
138
- case 8: // Horizontal-Up
139
- for (let y = 0; y < 4; y++)
140
- for (let x = 0; x < 4; x++) {
141
- const zHU = x + 2 * y;
142
- if (zHU < 5 && (zHU & 1) === 0)
143
- pred[y * 4 + x] = (l[zHU >> 1] + l[(zHU >> 1) + 1] + 1) >> 1;
144
- else if (zHU < 5)
145
- pred[y * 4 + x] = (l[zHU >> 1] + 2 * l[(zHU >> 1) + 1] + l[Math.min((zHU >> 1) + 2, 3)] + 2) >> 2;
146
- else if (zHU === 5)
147
- pred[y * 4 + x] = (l[2] + 3 * l[3] + 2) >> 2;
148
- else
149
- pred[y * 4 + x] = l[3];
150
- }
151
- break;
152
- }
153
-
154
- return pred;
155
- }
156
-
157
- // ══════════════════════════════════════════════════════════
158
- // Intra 16x16 Prediction (Section 8.3.3)
159
- // 4 modes for the full 16x16 luma block
160
- // ══════════════════════════════════════════════════════════
161
-
162
- /**
163
- * Perform Intra 16x16 prediction.
164
- * @param {number} mode - Prediction mode (0-3)
165
- * @param {Uint8Array} above - 16 samples above the macroblock
166
- * @param {Uint8Array} left - 16 samples to the left
167
- * @param {number} aboveLeft - Above-left corner sample
168
- * @param {boolean} hasAbove
169
- * @param {boolean} hasLeft
170
- * @returns {Int32Array} 256-element predicted block (16x16 raster)
171
- */
172
- export function intra16x16Predict(mode, above, left, aboveLeft, hasAbove, hasLeft) {
173
- const pred = new Int32Array(256);
174
-
175
- switch (mode) {
176
- case 0: // Vertical
177
- for (let y = 0; y < 16; y++)
178
- for (let x = 0; x < 16; x++)
179
- pred[y * 16 + x] = above[x];
180
- break;
181
-
182
- case 1: // Horizontal
183
- for (let y = 0; y < 16; y++)
184
- for (let x = 0; x < 16; x++)
185
- pred[y * 16 + x] = left[y];
186
- break;
187
-
188
- case 2: { // DC
189
- let sum = 0, count = 0;
190
- if (hasAbove) { for (let i = 0; i < 16; i++) sum += above[i]; count += 16; }
191
- if (hasLeft) { for (let i = 0; i < 16; i++) sum += left[i]; count += 16; }
192
- const dc = count > 0 ? (sum + (count >> 1)) / count | 0 : 128;
193
- pred.fill(dc);
194
- break;
195
- }
196
-
197
- case 3: { // Plane
198
- let H = 0, V = 0;
199
- for (let i = 0; i < 8; i++) {
200
- H += (i + 1) * (above[8 + i] - above[6 - i]);
201
- V += (i + 1) * (left[8 + i] - left[6 - i]);
202
- }
203
- const a = 16 * (above[15] + left[15]);
204
- const b = (5 * H + 32) >> 6;
205
- const c = (5 * V + 32) >> 6;
206
-
207
- for (let y = 0; y < 16; y++)
208
- for (let x = 0; x < 16; x++)
209
- pred[y * 16 + x] = clip255((a + b * (x - 7) + c * (y - 7) + 16) >> 5);
210
- break;
211
- }
212
- }
213
-
214
- return pred;
215
- }
216
-
217
- // ══════════════════════════════════════════════════════════
218
- // Intra Chroma Prediction (Section 8.3.4)
219
- // 4 modes for each 8x8 chroma block (4:2:0)
220
- // ══════════════════════════════════════════════════════════
221
-
222
- /**
223
- * Perform Intra chroma prediction (8x8 for 4:2:0).
224
- * @param {number} mode - 0=DC, 1=Horizontal, 2=Vertical, 3=Plane
225
- * @param {Uint8Array} above - 8 samples above
226
- * @param {Uint8Array} left - 8 samples to the left
227
- * @param {number} aboveLeft - Corner sample
228
- * @param {boolean} hasAbove
229
- * @param {boolean} hasLeft
230
- * @returns {Int32Array} 64-element predicted block (8x8 raster)
231
- */
232
- export function intraChromaPredict(mode, above, left, aboveLeft, hasAbove, hasLeft) {
233
- const pred = new Int32Array(64);
234
-
235
- switch (mode) {
236
- case 0: { // DC (per 4x4 sub-block)
237
- for (let blkY = 0; blkY < 2; blkY++) {
238
- for (let blkX = 0; blkX < 2; blkX++) {
239
- let sum = 0, count = 0;
240
- const topAvail = hasAbove;
241
- const leftAvail = hasLeft;
242
-
243
- if (topAvail) {
244
- for (let i = 0; i < 4; i++) sum += above[blkX * 4 + i];
245
- count += 4;
246
- }
247
- if (leftAvail) {
248
- for (let i = 0; i < 4; i++) sum += left[blkY * 4 + i];
249
- count += 4;
250
- }
251
-
252
- const dc = count > 0 ? (sum + (count >> 1)) / count | 0 : 128;
253
-
254
- for (let y = 0; y < 4; y++)
255
- for (let x = 0; x < 4; x++)
256
- pred[(blkY * 4 + y) * 8 + blkX * 4 + x] = dc;
257
- }
258
- }
259
- break;
260
- }
261
-
262
- case 1: // Horizontal
263
- for (let y = 0; y < 8; y++)
264
- for (let x = 0; x < 8; x++)
265
- pred[y * 8 + x] = left[y];
266
- break;
267
-
268
- case 2: // Vertical
269
- for (let y = 0; y < 8; y++)
270
- for (let x = 0; x < 8; x++)
271
- pred[y * 8 + x] = above[x];
272
- break;
273
-
274
- case 3: { // Plane
275
- let H = 0, V = 0;
276
- for (let i = 0; i < 4; i++) {
277
- H += (i + 1) * (above[4 + i] - above[2 - i]);
278
- V += (i + 1) * (left[4 + i] - left[2 - i]);
279
- }
280
- const a = 16 * (above[7] + left[7]);
281
- const b = (17 * H + 16) >> 5;
282
- const c = (17 * V + 16) >> 5;
283
-
284
- for (let y = 0; y < 8; y++)
285
- for (let x = 0; x < 8; x++)
286
- pred[y * 8 + x] = clip255((a + b * (x - 3) + c * (y - 3) + 16) >> 5);
287
- break;
288
- }
289
- }
290
-
291
- return pred;
292
- }