FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/h274.c
Date: 2025-08-19 23:55:23
Exec Total Coverage
Lines: 3 222 1.4%
Functions: 1 16 6.2%
Branches: 1 140 0.7%

Line Branch Exec Source
1 /*
2 * H.274 film grain synthesis
3 * Copyright (c) 2021 Niklas Haas <ffmpeg@haasn.xyz>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /**
23 * @file
24 * H.274 film grain synthesis.
25 * @author Niklas Haas <ffmpeg@haasn.xyz>
26 */
27
28 #include "libavutil/avassert.h"
29 #include "libavutil/bswap.h"
30 #include "libavcodec/bswapdsp.h"
31 #include "libavutil/crc.h"
32 #include "libavutil/imgutils.h"
33 #include "libavutil/md5.h"
34 #include "libavutil/mem.h"
35
36 #include "h274.h"
37
38 static const int8_t Gaussian_LUT[2048+4];
39 static const uint32_t Seed_LUT[256];
40 static const int8_t R64T[64][64];
41
42 static void prng_shift(uint32_t *state)
43 {
44 // Primitive polynomial x^31 + x^3 + 1 (modulo 2)
45 uint32_t x = *state;
46 uint8_t feedback = 1u ^ (x >> 2) ^ (x >> 30);
47 *state = (x << 1) | (feedback & 1u);
48 }
49
50 static void init_slice_c(int8_t out[64][64], uint8_t h, uint8_t v,
51 int16_t tmp[64][64])
52 {
53 static const uint8_t deblock_factors[13] = {
54 64, 71, 77, 84, 90, 96, 103, 109, 116, 122, 128, 128, 128
55 };
56
57 const uint8_t deblock_coeff = deblock_factors[v];
58 const uint8_t freq_h = ((h + 3) << 2) - 1;
59 const uint8_t freq_v = ((v + 3) << 2) - 1;
60 uint32_t seed = Seed_LUT[h + v * 13];
61
62 // Initialize with random gaussian values, using the output array as a
63 // temporary buffer for these intermediate values.
64 //
65 // Note: To make the subsequent matrix multiplication cache friendlier, we
66 // store each *column* of the starting image in a *row* of `out`
67 for (int l = 0; l <= freq_v; l++) {
68 for (int k = 0; k <= freq_h; k += 4) {
69 uint16_t offset = seed % 2048;
70 out[l][k + 0] = Gaussian_LUT[offset + 0];
71 out[l][k + 1] = Gaussian_LUT[offset + 1];
72 out[l][k + 2] = Gaussian_LUT[offset + 2];
73 out[l][k + 3] = Gaussian_LUT[offset + 3];
74 prng_shift(&seed);
75 }
76 }
77
78 out[0][0] = 0;
79
80 // 64x64 inverse integer transform
81 for (int y = 0; y < 64; y++) {
82 for (int x = 0; x <= freq_v; x++) {
83 int32_t sum = 0;
84 for (int p = 0; p <= freq_h; p++)
85 sum += R64T[y][p] * out[x][p];
86 tmp[y][x] = (sum + 128) >> 8;
87 }
88 }
89
90 for (int y = 0; y < 64; y++) {
91 for (int x = 0; x < 64; x++) {
92 int32_t sum = 0;
93 for (int p = 0; p <= freq_v; p++)
94 sum += tmp[x][p] * R64T[y][p]; // R64T^T = R64
95 // Renormalize and clip to [-127, 127]
96 out[y][x] = av_clip((sum + 128) >> 8, -127, 127);
97 }
98 }
99
100 // Deblock horizontal edges by simple attenuation of values
101 for (int y = 0; y < 64; y += 8) {
102 for (int x = 0; x < 64; x++) {
103 out[y + 0][x] = (out[y + 0][x] * deblock_coeff) >> 7;
104 out[y + 7][x] = (out[y + 7][x] * deblock_coeff) >> 7;
105 }
106 }
107 }
108
109 static void init_slice(H274FilmGrainDatabase *database, uint8_t h, uint8_t v)
110 {
111 if (database->residency[h] & (1 << v))
112 return;
113
114 database->residency[h] |= (1 << v);
115 init_slice_c(database->db[h][v], h, v, database->slice_tmp);
116 }
117
118 // Computes the average of an 8x8 block
119 static uint16_t avg_8x8_c(const uint8_t *in, int in_stride)
120 {
121 uint16_t avg[8] = {0}; // summing over an array vectorizes better
122
123 for (int y = 0; y < 8; y++) {
124 for (int x = 0; x < 8; x++)
125 avg[x] += in[x];
126 in += in_stride;
127 }
128
129 return (avg[0] + avg[1] + avg[2] + avg[3] +
130 avg[4] + avg[5] + avg[6] + avg[7]) >> 6;
131 }
132
133 // Synthesize an 8x8 block of film grain by copying the pattern from `db`
134 static void synth_grain_8x8_c(int8_t *out, const int out_stride,
135 const int16_t scale, const uint8_t shift,
136 const int8_t *db)
137 {
138 for (int y = 0; y < 8; y++) {
139 for (int x = 0; x < 8; x++)
140 out[x] = (scale * db[x]) >> shift;
141
142 out += out_stride;
143 db += 64;
144 }
145 }
146
147 // Deblock vertical edges of an 8x8 block, mixing with the previous block
148 static void deblock_8x8_c(int8_t *out, const int out_stride)
149 {
150 for (int y = 0; y < 8; y++) {
151 const int8_t l1 = out[-2], l0 = out[-1];
152 const int8_t r0 = out[0], r1 = out[1];
153 out[0] = (l0 + r0 * 2 + r1) >> 2;
154 out[-1] = (r0 + l0 * 2 + l1) >> 2;
155 out += out_stride;
156 }
157 }
158
159 // Generates a single 8x8 block of grain, optionally also applying the
160 // deblocking step (note that this implies writing to the previous block).
161 static av_always_inline void generate(int8_t *out, int out_stride,
162 const uint8_t *in, int in_stride,
163 H274FilmGrainDatabase *database,
164 const AVFilmGrainH274Params *h274,
165 int c, int invert, int deblock,
166 int y_offset, int x_offset)
167 {
168 const uint8_t shift = h274->log2_scale_factor + 6;
169 const uint16_t avg = avg_8x8_c(in, in_stride);
170 int16_t scale;
171 uint8_t h, v;
172 int8_t s = -1;
173
174 // FIXME: This logic only generates grain with a single
175 // intensity interval. Strictly speaking, the H.274 specification allows
176 // for overlapping intensity intervals, however SMPTE RDD 5-2006 (which
177 // concerns the implementation of H.274 for H.264) forbids this as it
178 // requires a nontrivial grain synthesis process (FFT).
179 //
180 // In principle, we should detect this possibility ahead of time and warn
181 // the user that the output is unlikely to be correct, or alternatively
182 // return an AVERROR_PATCHWELCOME.
183 for (int i = 0; i < h274->num_intensity_intervals[c]; i++) {
184 if (avg >= h274->intensity_interval_lower_bound[c][i] &&
185 avg <= h274->intensity_interval_upper_bound[c][i])
186 {
187 s = i;
188 break;
189 }
190 }
191
192 if (s < 0) {
193 // No matching intensity interval, synthesize blank film grain
194 for (int y = 0; y < 8; y++)
195 memset(out + y * out_stride, 0, sizeof(int8_t[8]));
196 return;
197 }
198
199 h = av_clip(h274->comp_model_value[c][s][1], 2, 14) - 2;
200 v = av_clip(h274->comp_model_value[c][s][2], 2, 14) - 2;
201 init_slice(database, h, v);
202
203 scale = h274->comp_model_value[c][s][0];
204 if (invert)
205 scale = -scale;
206
207 synth_grain_8x8_c(out, out_stride, scale, shift,
208 &database->db[h][v][y_offset][x_offset]);
209
210 if (deblock)
211 deblock_8x8_c(out, out_stride);
212 }
213
214 // Saturating 8-bit sum of a+b
215 static void add_8x8_clip_c(uint8_t *out, const uint8_t *a, const int8_t *b,
216 int n)
217 {
218 for (int i = 0; i < n; i++)
219 out[i] = av_clip_uint8(a[i] + b[i]);
220 }
221
222 int ff_h274_apply_film_grain(AVFrame *out_frame, const AVFrame *in_frame,
223 H274FilmGrainDatabase *database,
224 const AVFilmGrainParams *params)
225 {
226 AVFilmGrainH274Params h274 = params->codec.h274;
227 av_assert1(params->type == AV_FILM_GRAIN_PARAMS_H274);
228 if (h274.model_id != 0)
229 return AVERROR_PATCHWELCOME;
230
231 av_assert1(out_frame->format == in_frame->format);
232 if (in_frame->format != AV_PIX_FMT_YUV420P)
233 return AVERROR_PATCHWELCOME;
234
235 for (int c = 0; c < 3; c++) {
236 static const uint8_t color_offset[3] = { 0, 85, 170 };
237 uint32_t seed = Seed_LUT[(params->seed + color_offset[c]) % 256];
238 const int width = c > 0 ? AV_CEIL_RSHIFT(out_frame->width, 1) : out_frame->width;
239 const int height = c > 0 ? AV_CEIL_RSHIFT(out_frame->height, 1) : out_frame->height;
240
241 uint8_t * const out = out_frame->data[c];
242 const int out_stride = out_frame->linesize[c];
243 int8_t * const grain = out_frame->data[c]; // reuse output buffer for grain
244 const int grain_stride = out_stride;
245 const uint8_t * const in = in_frame->data[c];
246 const int in_stride = in_frame->linesize[c];
247
248 if (!h274.component_model_present[c]) {
249 av_image_copy_plane(out, out_stride, in, in_stride,
250 width * sizeof(uint8_t), height);
251 continue;
252 }
253
254 if (c > 0) {
255 // Adaptation for 4:2:0 chroma subsampling
256 for (int i = 0; i < h274.num_intensity_intervals[c]; i++) {
257 h274.comp_model_value[c][i][0] >>= 1;
258 h274.comp_model_value[c][i][1] *= 2;
259 h274.comp_model_value[c][i][2] *= 2;
260 }
261 }
262
263 // Film grain synthesis is done in 8x8 blocks, but the PRNG state is
264 // only advanced in 16x16 blocks, so use a nested loop
265 for (int y = 0; y < height; y += 16) {
266 for (int x = 0; x < width; x += 16) {
267 uint16_t x_offset = (seed >> 16) % 52;
268 uint16_t y_offset = (seed & 0xFFFF) % 56;
269 const int invert = (seed & 0x1);
270 x_offset &= 0xFFFC;
271 y_offset &= 0xFFF8;
272 prng_shift(&seed);
273
274 for (int yy = 0; yy < 16 && y+yy < height; yy += 8) {
275 for (int xx = 0; xx < 16 && x+xx < width; xx += 8) {
276 generate(grain + (y+yy) * grain_stride + (x+xx), grain_stride,
277 in + (y+yy) * in_stride + (x+xx), in_stride,
278 database, &h274, c, invert, (x+xx) > 0,
279 y_offset + yy, x_offset + xx);
280 }
281 }
282 }
283 }
284
285 // Final output blend pass, done after grain synthesis is complete
286 // because deblocking depends on previous grain values
287 for (int y = 0; y < height; y++) {
288 add_8x8_clip_c(out + y * out_stride, in + y * in_stride,
289 grain + y * grain_stride, width);
290 }
291 }
292
293 return 0;
294 }
295
296 // These tables are all taken from the SMPTE RDD 5-2006 specification
297 static const int8_t Gaussian_LUT[2048+4] = {
298 -11, 12, 103, -11, 42, -35, 12, 59, 77, 98, -87, 3, 65, -78, 45, 56, -51, 21,
299 13, -11, -20, -19, 33, -127, 17, -6, -105, 18, 19, 71, 48, -10, -38, 42,
300 -2, 75, -67, 52, -90, 33, -47, 21, -3, -56, 49, 1, -57, -42, -1, 120, -127,
301 -108, -49, 9, 14, 127, 122, 109, 52, 127, 2, 7, 114, 19, 30, 12, 77, 112,
302 82, -61, -127, 111, -52, -29, 2, -49, -24, 58, -29, -73, 12, 112, 67, 79,
303 -3, -114, -87, -6, -5, 40, 58, -81, 49, -27, -31, -34, -105, 50, 16, -24,
304 -35, -14, -15, -127, -55, -22, -55, -127, -112, 5, -26, -72, 127, 127, -2,
305 41, 87, -65, -16, 55, 19, 91, -81, -65, -64, 35, -7, -54, 99, -7, 88, 125,
306 -26, 91, 0, 63, 60, -14, -23, 113, -33, 116, 14, 26, 51, -16, 107, -8, 53,
307 38, -34, 17, -7, 4, -91, 6, 63, 63, -15, 39, -36, 19, 55, 17, -51, 40, 33,
308 -37, 126, -39, -118, 17, -30, 0, 19, 98, 60, 101, -12, -73, -17, -52, 98,
309 3, 3, 60, 33, -3, -2, 10, -42, -106, -38, 14, 127, 16, -127, -31, -86, -39,
310 -56, 46, -41, 75, 23, -19, -22, -70, 74, -54, -2, 32, -45, 17, -92, 59,
311 -64, -67, 56, -102, -29, -87, -34, -92, 68, 5, -74, -61, 93, -43, 14, -26,
312 -38, -126, -17, 16, -127, 64, 34, 31, 93, 17, -51, -59, 71, 77, 81, 127,
313 127, 61, 33, -106, -93, 0, 0, 75, -69, 71, 127, -19, -111, 30, 23, 15, 2,
314 39, 92, 5, 42, 2, -6, 38, 15, 114, -30, -37, 50, 44, 106, 27, 119, 7, -80,
315 25, -68, -21, 92, -11, -1, 18, 41, -50, 79, -127, -43, 127, 18, 11, -21,
316 32, -52, 27, -88, -90, -39, -19, -10, 24, -118, 72, -24, -44, 2, 12, 86,
317 -107, 39, -33, -127, 47, 51, -24, -22, 46, 0, 15, -35, -69, -2, -74, 24,
318 -6, 0, 29, -3, 45, 32, -32, 117, -45, 79, -24, -17, -109, -10, -70, 88,
319 -48, 24, -91, 120, -37, 50, -127, 58, 32, -82, -10, -17, -7, 46, -127, -15,
320 89, 127, 17, 98, -39, -33, 37, 42, -40, -32, -21, 105, -19, 19, 19, -59,
321 -9, 30, 0, -127, 34, 127, -84, 75, 24, -40, -49, -127, -107, -14, 45, -75,
322 1, 30, -20, 41, -68, -40, 12, 127, -3, 5, 20, -73, -59, -127, -3, -3, -53,
323 -6, -119, 93, 120, -80, -50, 0, 20, -46, 67, 78, -12, -22, -127, 36, -41,
324 56, 119, -5, -116, -22, 68, -14, -90, 24, -82, -44, -127, 107, -25, -37,
325 40, -7, -7, -82, 5, -87, 44, -34, 9, -127, 39, 70, 49, -63, 74, -49, 109,
326 -27, -89, -47, -39, 44, 49, -4, 60, -42, 80, 9, -127, -9, -56, -49, 125,
327 -66, 47, 36, 117, 15, -11, -96, 109, 94, -17, -56, 70, 8, -14, -5, 50, 37,
328 -45, 120, -30, -76, 40, -46, 6, 3, 69, 17, -78, 1, -79, 6, 127, 43, 26,
329 127, -127, 28, -55, -26, 55, 112, 48, 107, -1, -77, -1, 53, -9, -22, -43,
330 123, 108, 127, 102, 68, 46, 5, 1, 123, -13, -55, -34, -49, 89, 65, -105,
331 -5, 94, -53, 62, 45, 30, 46, 18, -35, 15, 41, 47, -98, -24, 94, -75, 127,
332 -114, 127, -68, 1, -17, 51, -95, 47, 12, 34, -45, -75, 89, -107, -9, -58,
333 -29, -109, -24, 127, -61, -13, 77, -45, 17, 19, 83, -24, 9, 127, -66, 54,
334 4, 26, 13, 111, 43, -113, -22, 10, -24, 83, 67, -14, 75, -123, 59, 127,
335 -12, 99, -19, 64, -38, 54, 9, 7, 61, -56, 3, -57, 113, -104, -59, 3, -9,
336 -47, 74, 85, -55, -34, 12, 118, 28, 93, -72, 13, -99, -72, -20, 30, 72,
337 -94, 19, -54, 64, -12, -63, -25, 65, 72, -10, 127, 0, -127, 103, -20, -73,
338 -112, -103, -6, 28, -42, -21, -59, -29, -26, 19, -4, -51, 94, -58, -95,
339 -37, 35, 20, -69, 127, -19, -127, -22, -120, -53, 37, 74, -127, -1, -12,
340 -119, -53, -28, 38, 69, 17, 16, -114, 89, 62, 24, 37, -23, 49, -101, -32,
341 -9, -95, -53, 5, 93, -23, -49, -8, 51, 3, -75, -90, -10, -39, 127, -86,
342 -22, 20, 20, 113, 75, 52, -31, 92, -63, 7, -12, 46, 36, 101, -43, -17, -53,
343 -7, -38, -76, -31, -21, 62, 31, 62, 20, -127, 31, 64, 36, 102, -85, -10,
344 77, 80, 58, -79, -8, 35, 8, 80, -24, -9, 3, -17, 72, 127, 83, -87, 55, 18,
345 -119, -123, 36, 10, 127, 56, -55, 113, 13, 26, 32, -13, -48, 22, -13, 5,
346 58, 27, 24, 26, -11, -36, 37, -92, 78, 81, 9, 51, 14, 67, -13, 0, 32, 45,
347 -76, 32, -39, -22, -49, -127, -27, 31, -9, 36, 14, 71, 13, 57, 12, -53,
348 -86, 53, -44, -35, 2, 127, 12, -66, -44, 46, -115, 3, 10, 56, -35, 119,
349 -19, -61, 52, -59, -127, -49, -23, 4, -5, 17, -82, -6, 127, 25, 79, 67, 64,
350 -25, 14, -64, -37, -127, -28, 21, -63, 66, -53, -41, 109, -62, 15, -22, 13,
351 29, -63, 20, 27, 95, -44, -59, -116, -10, 79, -49, 22, -43, -16, 46, -47,
352 -120, -36, -29, -52, -44, 29, 127, -13, 49, -9, -127, 75, -28, -23, 88, 59,
353 11, -95, 81, -59, 58, 60, -26, 40, -92, -3, -22, -58, -45, -59, -22, -53,
354 71, -29, 66, -32, -23, 14, -17, -66, -24, -28, -62, 47, 38, 17, 16, -37,
355 -24, -11, 8, -27, -19, 59, 45, -49, -47, -4, -22, -81, 30, -67, -127, 74,
356 102, 5, -18, 98, 34, -66, 42, -52, 7, -59, 24, -58, -19, -24, -118, -73,
357 91, 15, -16, 79, -32, -79, -127, -36, 41, 77, -83, 2, 56, 22, -75, 127,
358 -16, -21, 12, 31, 56, -113, -127, 90, 55, 61, 12, 55, -14, -113, -14, 32,
359 49, -67, -17, 91, -10, 1, 21, 69, -70, 99, -19, -112, 66, -90, -10, -9,
360 -71, 127, 50, -81, -49, 24, 61, -61, -111, 7, -41, 127, 88, -66, 108, -127,
361 -6, 36, -14, 41, -50, 14, 14, 73, -101, -28, 77, 127, -8, -100, 88, 38,
362 121, 88, -125, -60, 13, -94, -115, 20, -67, -87, -94, -119, 44, -28, -30,
363 18, 5, -53, -61, 20, -43, 11, -77, -60, 13, 29, 3, 6, -72, 38, -60, -11,
364 108, -53, 41, 66, -12, -127, -127, -49, 24, 29, 46, 36, 91, 34, -33, 116,
365 -51, -34, -52, 91, 7, -83, 73, -26, -103, 24, -10, 76, 84, 5, 68, -80, -13,
366 -17, -32, -48, 20, 50, 26, 10, 63, -104, -14, 37, 127, 114, 97, 35, 1, -33,
367 -55, 127, -124, -33, 61, -7, 119, -32, -127, -53, -42, 63, 3, -5, -26, 70,
368 -58, -33, -44, -43, 34, -56, -127, 127, 25, -35, -11, 16, -81, 29, -58, 40,
369 -127, -127, 20, -47, -11, -36, -63, -52, -32, -82, 78, -76, -73, 8, 27,
370 -72, -9, -74, -85, -86, -57, 25, 78, -10, -97, 35, -65, 8, -59, 14, 1, -42,
371 32, -88, -44, 17, -3, -9, 59, 40, 12, -108, -40, 24, 34, 18, -28, 2, 51,
372 -110, -4, 100, 1, 65, 22, 0, 127, 61, 45, 25, -31, 6, 9, -7, -48, 99, 16,
373 44, -2, -40, 32, -39, -52, 10, -110, -19, 56, -127, 69, 26, 51, 92, 40, 61,
374 -52, 45, -38, 13, 85, 122, 27, 66, 45, -111, -83, -3, 31, 37, 19, -36, 58,
375 71, 39, -78, -47, 58, -78, 8, -62, -36, -14, 61, 42, -127, 71, -4, 24, -54,
376 52, -127, 67, -4, -42, 30, -63, 59, -3, -1, -18, -46, -92, -81, -96, -14,
377 -53, -10, -11, -77, 13, 1, 8, -67, -127, 127, -28, 26, -14, 18, -13, -26,
378 2, 10, -46, -32, -15, 27, -31, -59, 59, 77, -121, 28, 40, -54, -62, -31,
379 -21, -37, -32, -6, -127, -25, -60, 70, -127, 112, -127, 127, 88, -7, 116,
380 110, 53, 87, -127, 3, 16, 23, 74, -106, -51, 3, 74, -82, -112, -74, 65, 81,
381 25, 53, 127, -45, -50, -103, -41, -65, -29, 79, -67, 64, -33, -30, -8, 127,
382 0, -13, -51, 67, -14, 5, -92, 29, -35, -8, -90, -57, -3, 36, 43, 44, -31,
383 -69, -7, 36, 39, -51, 43, -81, 58, 6, 127, 12, 57, 66, 46, 59, -43, -42,
384 41, -15, -120, 24, 3, -11, 19, -13, 51, 28, 3, 55, -48, -12, -1, 2, 97,
385 -19, 29, 42, 13, 43, 78, -44, 56, -108, -43, -19, 127, 15, -11, -18, -81,
386 83, -37, 77, -109, 15, 65, -50, 43, 12, 13, 27, 28, 61, 57, 30, 26, 106,
387 -18, 56, 13, 97, 4, -8, -62, -103, 94, 108, -44, 52, 27, -47, -9, 105, -53,
388 46, 89, 103, -33, 38, -34, 55, 51, 70, -94, -35, -87, -107, -19, -31, 9,
389 -19, 79, -14, 77, 5, -19, -107, 85, 21, -45, -39, -42, 9, -29, 74, 47, -75,
390 60, -127, 120, -112, -57, -32, 41, 7, 79, 76, 66, 57, 41, -25, 31, 37, -47,
391 -36, 43, -73, -37, 63, 127, -69, -52, 90, -33, -61, 60, -55, 44, 15, 4,
392 -67, 13, -92, 64, 29, -39, -3, 83, -2, -38, -85, -86, 58, 35, -69, -61, 29,
393 -37, -95, -78, 4, 30, -4, -32, -80, -22, -9, -77, 46, 7, -93, -71, 65, 9,
394 -50, 127, -70, 26, -12, -39, -114, 63, -127, -100, 4, -32, 111, 22, -60,
395 65, -101, 26, -42, 21, -59, -27, -74, 2, -94, 6, 126, 5, 76, -88, -9, -43,
396 -101, 127, 1, 125, 92, -63, 52, 56, 4, 81, -127, 127, 80, 127, -29, 30,
397 116, -74, -17, -57, 105, 48, 45, 25, -72, 48, -38, -108, 31, -34, 4, -11,
398 41, -127, 52, -104, -43, -37, 52, 2, 47, 87, -9, 77, 27, -41, -25, 90, 86,
399 -56, 75, 10, 33, 78, 58, 127, 127, -7, -73, 49, -33, -106, -35, 38, 57, 53,
400 -17, -4, 83, 52, -108, 54, -125, 28, 23, 56, -43, -88, -17, -6, 47, 23, -9,
401 0, -13, 111, 75, 27, -52, -38, -34, 39, 30, 66, 39, 38, -64, 38, 3, 21,
402 -32, -51, -28, 54, -38, -87, 20, 52, 115, 18, -81, -70, 0, -14, -46, -46,
403 -3, 125, 16, -14, 23, -82, -84, -69, -20, -65, -127, 9, 81, -49, 61, 7,
404 -36, -45, -42, 57, -26, 47, 20, -85, 46, -13, 41, -37, -75, -60, 86, -78,
405 -127, 12, 50, 2, -3, 13, 47, 5, 19, -78, -55, -27, 65, -71, 12, -108, 20,
406 -16, 11, -31, 63, -55, 37, 75, -17, 127, -73, -33, -28, -120, 105, 68, 106,
407 -103, -106, 71, 61, 2, 23, -3, 33, -5, -15, -67, -15, -23, -54, 15, -63,
408 76, 58, -110, 1, 83, -27, 22, 75, -39, -17, -11, 64, -17, -127, -54, -66,
409 31, 96, 116, 3, -114, -7, -108, -63, 97, 9, 50, 8, 75, -28, 72, 112, -36,
410 -112, 95, -50, 23, -13, -19, 55, 21, 23, 92, 91, 22, -49, 16, -75, 23, 9,
411 -49, -97, -37, 49, -36, 36, -127, -86, 43, 127, -24, -24, 84, 83, -35, -34,
412 -12, 109, 102, -38, 51, -68, 34, 19, -22, 49, -32, 127, 40, 24, -93, -4,
413 -3, 105, 3, -58, -18, 8, 127, -18, 125, 68, 69, -62, 30, -36, 54, -57, -24,
414 17, 43, -36, -27, -57, -67, -21, -10, -49, 68, 12, 65, 4, 48, 55, 127, -75,
415 44, 89, -66, -13, -78, -82, -91, 22, 30, 33, -40, -87, -34, 96, -91, 39,
416 10, -64, -3, -12, 127, -50, -37, -56, 23, -35, -36, -54, 90, -91, 2, 50,
417 77, -6, -127, 16, 46, -5, -73, 0, -56, -18, -72, 28, 93, 60, 49, 20, 18,
418 111, -111, 32, -83, 47, 47, -10, 35, -88, 43, 57, -98, 127, -17, 0, 1, -39,
419 -127, -2, 0, 63, 93, 0, 36, -66, -61, -19, 39, -127, 58, 50, -17, 127, 88,
420 -43, -108, -51, -16, 7, -36, 68, 46, -14, 107, 40, 57, 7, 19, 8, 3, 88,
421 -90, -92, -18, -21, -24, 13, 7, -4, -78, -91, -4, 8, -35, -5, 19, 2, -111,
422 4, -66, -81, 122, -20, -34, -37, -84, 127, 68, 46, 17, 47,
423
424 // Repeat the beginning of the array to allow wrapping reads
425 -11, 12, 103, -11,
426 };
427
428 static const uint32_t Seed_LUT[256] = {
429 747538460, 1088979410, 1744950180, 1767011913, 1403382928,
430 521866116, 1060417601, 2110622736, 1557184770, 105289385, 585624216,
431 1827676546, 1191843873, 1018104344, 1123590530, 663361569, 2023850500,
432 76561770, 1226763489, 80325252, 1992581442, 502705249, 740409860,
433 516219202, 557974537, 1883843076, 720112066, 1640137737, 1820967556,
434 40667586, 155354121, 1820967557, 1115949072, 1631803309, 98284748,
435 287433856, 2119719977, 988742797, 1827432592, 579378475, 1017745956,
436 1309377032, 1316535465, 2074315269, 1923385360, 209722667, 1546228260,
437 168102420, 135274561, 355958469, 248291472, 2127839491, 146920100,
438 585982612, 1611702337, 696506029, 1386498192, 1258072451, 1212240548,
439 1043171860, 1217404993, 1090770605, 1386498193, 169093201, 541098240,
440 1468005469, 456510673, 1578687785, 1838217424, 2010752065, 2089828354,
441 1362717428, 970073673, 854129835, 714793201, 1266069081, 1047060864,
442 1991471829, 1098097741, 913883585, 1669598224, 1337918685, 1219264706,
443 1799741108, 1834116681, 683417731, 1120274457, 1073098457, 1648396544,
444 176642749, 31171789, 718317889, 1266977808, 1400892508, 549749008,
445 1808010512, 67112961, 1005669825, 903663673, 1771104465, 1277749632,
446 1229754427, 950632997, 1979371465, 2074373264, 305357524, 1049387408,
447 1171033360, 1686114305, 2147468765, 1941195985, 117709841, 809550080,
448 991480851, 1816248997, 1561503561, 329575568, 780651196, 1659144592,
449 1910793616, 604016641, 1665084765, 1530186961, 1870928913, 809550081,
450 2079346113, 71307521, 876663040, 1073807360, 832356664, 1573927377,
451 204073344, 2026918147, 1702476788, 2043881033, 57949587, 2001393952,
452 1197426649, 1186508931, 332056865, 950043140, 890043474, 349099312,
453 148914948, 236204097, 2022643605, 1441981517, 498130129, 1443421481,
454 924216797, 1817491777, 1913146664, 1411989632, 929068432, 495735097,
455 1684636033, 1284520017, 432816184, 1344884865, 210843729, 676364544,
456 234449232, 12112337, 1350619139, 1753272996, 2037118872, 1408560528,
457 533334916, 1043640385, 357326099, 201376421, 110375493, 541106497,
458 416159637, 242512193, 777294080, 1614872576, 1535546636, 870600145,
459 910810409, 1821440209, 1605432464, 1145147393, 951695441, 1758494976,
460 1506656568, 1557150160, 608221521, 1073840384, 217672017, 684818688,
461 1750138880, 16777217, 677990609, 953274371, 1770050213, 1359128393,
462 1797602707, 1984616737, 1865815816, 2120835200, 2051677060, 1772234061,
463 1579794881, 1652821009, 1742099468, 1887260865, 46468113, 1011925248,
464 1134107920, 881643832, 1354774993, 472508800, 1892499769, 1752793472,
465 1962502272, 687898625, 883538000, 1354355153, 1761673473, 944820481,
466 2020102353, 22020353, 961597696, 1342242816, 964808962, 1355809701,
467 17016649, 1386540177, 647682692, 1849012289, 751668241, 1557184768,
468 127374604, 1927564752, 1045744913, 1614921984, 43588881, 1016185088,
469 1544617984, 1090519041, 136122424, 215038417, 1563027841, 2026918145,
470 1688778833, 701530369, 1372639488, 1342242817, 2036945104, 953274369,
471 1750192384, 16842753, 964808960, 1359020032, 1358954497
472 };
473
474 // Note: This is pre-transposed, i.e. stored column-major order
475 static const int8_t R64T[64][64] = {
476 {
477 32, 45, 45, 45, 45, 45, 45, 45, 44, 44, 44, 44, 43, 43, 43, 42,
478 42, 41, 41, 40, 40, 39, 39, 38, 38, 37, 36, 36, 35, 34, 34, 33,
479 32, 31, 30, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
480 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 4, 3, 2, 1,
481 }, {
482 32, 45, 45, 44, 43, 42, 41, 39, 38, 36, 34, 31, 29, 26, 23, 20,
483 17, 14, 11, 8, 4, 1, -2, -6, -9, -12, -15, -18, -21, -24, -27, -30,
484 -32, -34, -36, -38, -40, -41, -43, -44, -44, -45, -45, -45, -45, -45, -44, -43,
485 -42, -40, -39, -37, -35, -33, -30, -28, -25, -22, -19, -16, -13, -10, -7, -3,
486 }, {
487 32, 45, 44, 42, 40, 37, 34, 30, 25, 20, 15, 10, 4, -1, -7, -12,
488 -17, -22, -27, -31, -35, -38, -41, -43, -44, -45, -45, -45, -43, -41, -39, -36,
489 -32, -28, -23, -18, -13, -8, -2, 3, 9, 14, 19, 24, 29, 33, 36, 39,
490 42, 44, 45, 45, 45, 44, 43, 40, 38, 34, 30, 26, 21, 16, 11, 6,
491 }, {
492 32, 45, 43, 39, 35, 30, 23, 16, 9, 1, -7, -14, -21, -28, -34, -38,
493 -42, -44, -45, -45, -43, -40, -36, -31, -25, -18, -11, -3, 4, 12, 19, 26,
494 32, 37, 41, 44, 45, 45, 44, 41, 38, 33, 27, 20, 13, 6, -2, -10,
495 -17, -24, -30, -36, -40, -43, -45, -45, -44, -42, -39, -34, -29, -22, -15, -8,
496 }, {
497 32, 44, 41, 36, 29, 20, 11, 1, -9, -18, -27, -34, -40, -44, -45, -45,
498 -42, -37, -30, -22, -13, -3, 7, 16, 25, 33, 39, 43, 45, 45, 43, 38,
499 32, 24, 15, 6, -4, -14, -23, -31, -38, -42, -45, -45, -43, -39, -34, -26,
500 -17, -8, 2, 12, 21, 30, 36, 41, 44, 45, 44, 40, 35, 28, 19, 10,
501 }, {
502 32, 44, 39, 31, 21, 10, -2, -14, -25, -34, -41, -45, -45, -42, -36, -28,
503 -17, -6, 7, 18, 29, 37, 43, 45, 44, 40, 34, 24, 13, 1, -11, -22,
504 -32, -39, -44, -45, -43, -38, -30, -20, -9, 3, 15, 26, 35, 41, 45, 45,
505 42, 36, 27, 16, 4, -8, -19, -30, -38, -43, -45, -44, -40, -33, -23, -12,
506 }, {
507 32, 43, 36, 26, 13, -1, -15, -28, -38, -44, -45, -42, -35, -24, -11, 3,
508 17, 30, 39, 44, 45, 41, 34, 22, 9, -6, -19, -31, -40, -45, -45, -40,
509 -32, -20, -7, 8, 21, 33, 41, 45, 44, 39, 30, 18, 4, -10, -23, -34,
510 -42, -45, -44, -38, -29, -16, -2, 12, 25, 36, 43, 45, 43, 37, 27, 14,
511 }, {
512 32, 42, 34, 20, 4, -12, -27, -38, -44, -45, -39, -28, -13, 3, 19, 33,
513 42, 45, 43, 34, 21, 6, -11, -26, -38, -44, -45, -39, -29, -14, 2, 18,
514 32, 41, 45, 43, 35, 22, 7, -10, -25, -37, -44, -45, -40, -30, -15, 1,
515 17, 31, 41, 45, 43, 36, 23, 8, -9, -24, -36, -44, -45, -40, -30, -16,
516 }, {
517 32, 41, 30, 14, -4, -22, -36, -44, -44, -37, -23, -6, 13, 30, 41, 45,
518 42, 31, 15, -3, -21, -36, -44, -45, -38, -24, -7, 12, 29, 40, 45, 42,
519 32, 16, -2, -20, -35, -44, -45, -38, -25, -8, 11, 28, 40, 45, 43, 33,
520 17, -1, -19, -34, -43, -45, -39, -26, -9, 10, 27, 39, 45, 43, 34, 18,
521 }, {
522 32, 40, 27, 8, -13, -31, -43, -45, -38, -22, -2, 18, 35, 44, 44, 34,
523 17, -3, -23, -38, -45, -42, -30, -12, 9, 28, 41, 45, 40, 26, 7, -14,
524 -32, -43, -45, -37, -21, -1, 19, 36, 44, 44, 34, 16, -4, -24, -39, -45,
525 -42, -30, -11, 10, 29, 41, 45, 39, 25, 6, -15, -33, -43, -45, -36, -20,
526 }, {
527 32, 39, 23, 1, -21, -38, -45, -40, -25, -3, 19, 37, 45, 41, 27, 6,
528 -17, -36, -45, -42, -29, -8, 15, 34, 44, 43, 30, 10, -13, -33, -44, -44,
529 -32, -12, 11, 31, 43, 44, 34, 14, -9, -30, -43, -45, -35, -16, 7, 28,
530 42, 45, 36, 18, -4, -26, -41, -45, -38, -20, 2, 24, 40, 45, 39, 22,
531 }, {
532 32, 38, 19, -6, -29, -43, -44, -31, -9, 16, 36, 45, 40, 22, -2, -26,
533 -42, -45, -34, -12, 13, 34, 45, 41, 25, 1, -23, -40, -45, -36, -15, 10,
534 32, 44, 43, 28, 4, -20, -39, -45, -38, -18, 7, 30, 43, 44, 30, 8,
535 -17, -37, -45, -39, -21, 3, 27, 42, 44, 33, 11, -14, -35, -45, -41, -24,
536 }, {
537 32, 37, 15, -12, -35, -45, -39, -18, 9, 33, 45, 40, 21, -6, -30, -44,
538 -42, -24, 2, 28, 43, 43, 27, 1, -25, -42, -44, -30, -4, 22, 41, 45,
539 32, 8, -19, -39, -45, -34, -11, 16, 38, 45, 36, 14, -13, -36, -45, -38,
540 -17, 10, 34, 45, 40, 20, -7, -31, -44, -41, -23, 3, 29, 44, 43, 26,
541 }, {
542 32, 36, 11, -18, -40, -45, -30, -3, 25, 43, 43, 24, -4, -31, -45, -39,
543 -17, 12, 36, 45, 35, 10, -19, -40, -44, -30, -2, 26, 43, 42, 23, -6,
544 -32, -45, -39, -16, 13, 37, 45, 34, 9, -20, -41, -44, -29, -1, 27, 44,
545 42, 22, -7, -33, -45, -38, -15, 14, 38, 45, 34, 8, -21, -41, -44, -28,
546 }, {
547 32, 34, 7, -24, -43, -41, -19, 12, 38, 45, 30, 1, -29, -45, -39, -14,
548 17, 40, 44, 26, -4, -33, -45, -36, -9, 22, 43, 42, 21, -10, -36, -45,
549 -32, -3, 27, 44, 40, 16, -15, -39, -44, -28, 2, 31, 45, 37, 11, -20,
550 -42, -43, -23, 8, 35, 45, 34, 6, -25, -44, -41, -18, 13, 38, 45, 30,
551 }, {
552 32, 33, 2, -30, -45, -36, -7, 26, 44, 38, 11, -22, -43, -40, -15, 18,
553 42, 42, 19, -14, -40, -44, -23, 10, 38, 45, 27, -6, -35, -45, -30, 1,
554 32, 45, 34, 3, -29, -45, -36, -8, 25, 44, 39, 12, -21, -43, -41, -16,
555 17, 41, 43, 20, -13, -39, -44, -24, 9, 37, 45, 28, -4, -34, -45, -31,
556 }, {
557 32, 31, -2, -34, -45, -28, 7, 37, 44, 24, -11, -39, -43, -20, 15, 41,
558 42, 16, -19, -43, -40, -12, 23, 44, 38, 8, -27, -45, -35, -3, 30, 45,
559 32, -1, -34, -45, -29, 6, 36, 45, 25, -10, -39, -44, -21, 14, 41, 42,
560 17, -18, -43, -40, -13, 22, 44, 38, 9, -26, -45, -36, -4, 30, 45, 33,
561 }, {
562 32, 30, -7, -38, -43, -18, 19, 44, 38, 6, -30, -45, -29, 8, 39, 43,
563 17, -20, -44, -37, -4, 31, 45, 28, -9, -39, -43, -16, 21, 44, 36, 3,
564 -32, -45, -27, 10, 40, 42, 15, -22, -44, -36, -2, 33, 45, 26, -11, -40,
565 -42, -14, 23, 45, 35, 1, -34, -45, -25, 12, 41, 41, 13, -24, -45, -34,
566 }, {
567 32, 28, -11, -41, -40, -8, 30, 45, 25, -14, -43, -38, -4, 33, 45, 22,
568 -17, -44, -36, -1, 35, 44, 19, -20, -44, -34, 2, 37, 43, 16, -23, -45,
569 -32, 6, 39, 42, 13, -26, -45, -30, 9, 40, 41, 10, -29, -45, -27, 12,
570 42, 39, 7, -31, -45, -24, 15, 43, 38, 3, -34, -45, -21, 18, 44, 36,
571 }, {
572 32, 26, -15, -44, -35, 3, 39, 41, 9, -31, -45, -20, 21, 45, 30, -10,
573 -42, -38, -2, 36, 43, 14, -27, -45, -25, 16, 44, 34, -4, -39, -41, -8,
574 32, 45, 19, -22, -45, -30, 11, 42, 38, 1, -36, -43, -13, 28, 45, 24,
575 -17, -44, -34, 6, 40, 40, 7, -33, -44, -18, 23, 45, 29, -12, -43, -37,
576 }, {
577 32, 24, -19, -45, -29, 14, 44, 33, -9, -42, -36, 3, 40, 39, 2, -37,
578 -42, -8, 34, 44, 13, -30, -45, -18, 25, 45, 23, -20, -45, -28, 15, 44,
579 32, -10, -43, -36, 4, 40, 39, 1, -38, -41, -7, 34, 43, 12, -30, -45,
580 -17, 26, 45, 22, -21, -45, -27, 16, 44, 31, -11, -43, -35, 6, 41, 38,
581 }, {
582 32, 22, -23, -45, -21, 24, 45, 20, -25, -45, -19, 26, 45, 18, -27, -45,
583 -17, 28, 45, 16, -29, -45, -15, 30, 44, 14, -30, -44, -13, 31, 44, 12,
584 -32, -44, -11, 33, 43, 10, -34, -43, -9, 34, 43, 8, -35, -42, -7, 36,
585 42, 6, -36, -41, -4, 37, 41, 3, -38, -40, -2, 38, 40, 1, -39, -39,
586 }, {
587 32, 20, -27, -45, -13, 33, 43, 6, -38, -39, 2, 41, 35, -10, -44, -30,
588 17, 45, 23, -24, -45, -16, 30, 44, 9, -36, -41, -1, 40, 37, -7, -43,
589 -32, 14, 45, 26, -21, -45, -19, 28, 44, 12, -34, -42, -4, 38, 39, -3,
590 -42, -34, 11, 44, 29, -18, -45, -22, 25, 45, 15, -31, -43, -8, 36, 40,
591 }, {
592 32, 18, -30, -43, -4, 39, 36, -10, -44, -26, 23, 45, 13, -34, -41, 1,
593 42, 33, -15, -45, -21, 28, 44, 8, -38, -38, 7, 44, 29, -20, -45, -16,
594 32, 42, 2, -40, -35, 12, 45, 24, -25, -45, -11, 36, 40, -3, -43, -31,
595 17, 45, 19, -30, -43, -6, 39, 37, -9, -44, -27, 22, 45, 14, -34, -41,
596 }, {
597 32, 16, -34, -40, 4, 44, 27, -24, -44, -8, 39, 36, -13, -45, -19, 31,
598 42, -1, -43, -30, 21, 45, 11, -37, -38, 10, 45, 22, -29, -43, -2, 41,
599 32, -18, -45, -14, 35, 39, -7, -44, -25, 26, 44, 6, -40, -34, 15, 45,
600 17, -33, -41, 3, 43, 28, -23, -45, -9, 38, 36, -12, -45, -20, 30, 42,
601 }, {
602 32, 14, -36, -37, 13, 45, 15, -36, -38, 12, 45, 16, -35, -38, 11, 45,
603 17, -34, -39, 10, 45, 18, -34, -39, 9, 45, 19, -33, -40, 8, 45, 20,
604 -32, -40, 7, 45, 21, -31, -41, 6, 44, 22, -30, -41, 4, 44, 23, -30,
605 -42, 3, 44, 24, -29, -42, 2, 44, 25, -28, -43, 1, 43, 26, -27, -43,
606 }, {
607 32, 12, -39, -33, 21, 44, 2, -43, -25, 30, 41, -8, -45, -16, 36, 36,
608 -17, -45, -7, 41, 29, -26, -43, 3, 44, 20, -34, -38, 13, 45, 11, -39,
609 -32, 22, 44, 1, -43, -24, 30, 40, -9, -45, -15, 37, 35, -18, -45, -6,
610 42, 28, -27, -42, 4, 45, 19, -34, -38, 14, 45, 10, -40, -31, 23, 44,
611 }, {
612 32, 10, -41, -28, 29, 40, -11, -45, -9, 41, 27, -30, -40, 12, 45, 8,
613 -42, -26, 30, 39, -13, -45, -7, 42, 25, -31, -39, 14, 45, 6, -43, -24,
614 32, 38, -15, -45, -4, 43, 23, -33, -38, 16, 45, 3, -43, -22, 34, 37,
615 -17, -45, -2, 44, 21, -34, -36, 18, 44, 1, -44, -20, 35, 36, -19, -44,
616 }, {
617 32, 8, -43, -22, 35, 34, -23, -42, 9, 45, 7, -43, -21, 36, 34, -24,
618 -42, 10, 45, 6, -43, -20, 36, 33, -25, -41, 11, 45, 4, -44, -19, 37,
619 32, -26, -41, 12, 45, 3, -44, -18, 38, 31, -27, -40, 13, 45, 2, -44,
620 -17, 38, 30, -28, -40, 14, 45, 1, -44, -16, 39, 30, -29, -39, 15, 45,
621 }, {
622 32, 6, -44, -16, 40, 26, -34, -34, 25, 40, -15, -44, 4, 45, 7, -44,
623 -17, 39, 27, -33, -35, 24, 41, -14, -44, 3, 45, 8, -43, -18, 39, 28,
624 -32, -36, 23, 41, -13, -45, 2, 45, 9, -43, -19, 38, 29, -31, -36, 22,
625 42, -12, -45, 1, 45, 10, -43, -20, 38, 30, -30, -37, 21, 42, -11, -45,
626 }, {
627 32, 3, -45, -10, 43, 16, -41, -22, 38, 28, -34, -33, 29, 37, -23, -40,
628 17, 43, -11, -45, 4, 45, 2, -45, -9, 44, 15, -41, -21, 38, 27, -34,
629 -32, 30, 36, -24, -40, 18, 43, -12, -44, 6, 45, 1, -45, -8, 44, 14,
630 -42, -20, 39, 26, -35, -31, 30, 36, -25, -39, 19, 42, -13, -44, 7, 45,
631 }, {
632 32, 1, -45, -3, 45, 6, -45, -8, 44, 10, -44, -12, 43, 14, -43, -16,
633 42, 18, -41, -20, 40, 22, -39, -24, 38, 26, -36, -28, 35, 30, -34, -31,
634 32, 33, -30, -34, 29, 36, -27, -37, 25, 38, -23, -39, 21, 40, -19, -41,
635 17, 42, -15, -43, 13, 44, -11, -44, 9, 45, -7, -45, 4, 45, -2, -45,
636 }, {
637 32, -1, -45, 3, 45, -6, -45, 8, 44, -10, -44, 12, 43, -14, -43, 16,
638 42, -18, -41, 20, 40, -22, -39, 24, 38, -26, -36, 28, 35, -30, -34, 31,
639 32, -33, -30, 34, 29, -36, -27, 37, 25, -38, -23, 39, 21, -40, -19, 41,
640 17, -42, -15, 43, 13, -44, -11, 44, 9, -45, -7, 45, 4, -45, -2, 45,
641 }, {
642 32, -3, -45, 10, 43, -16, -41, 22, 38, -28, -34, 33, 29, -37, -23, 40,
643 17, -43, -11, 45, 4, -45, 2, 45, -9, -44, 15, 41, -21, -38, 27, 34,
644 -32, -30, 36, 24, -40, -18, 43, 12, -44, -6, 45, -1, -45, 8, 44, -14,
645 -42, 20, 39, -26, -35, 31, 30, -36, -25, 39, 19, -42, -13, 44, 7, -45,
646 }, {
647 32, -6, -44, 16, 40, -26, -34, 34, 25, -40, -15, 44, 4, -45, 7, 44,
648 -17, -39, 27, 33, -35, -24, 41, 14, -44, -3, 45, -8, -43, 18, 39, -28,
649 -32, 36, 23, -41, -13, 45, 2, -45, 9, 43, -19, -38, 29, 31, -36, -22,
650 42, 12, -45, -1, 45, -10, -43, 20, 38, -30, -30, 37, 21, -42, -11, 45,
651 }, {
652 32, -8, -43, 22, 35, -34, -23, 42, 9, -45, 7, 43, -21, -36, 34, 24,
653 -42, -10, 45, -6, -43, 20, 36, -33, -25, 41, 11, -45, 4, 44, -19, -37,
654 32, 26, -41, -12, 45, -3, -44, 18, 38, -31, -27, 40, 13, -45, 2, 44,
655 -17, -38, 30, 28, -40, -14, 45, -1, -44, 16, 39, -30, -29, 39, 15, -45,
656 }, {
657 32, -10, -41, 28, 29, -40, -11, 45, -9, -41, 27, 30, -40, -12, 45, -8,
658 -42, 26, 30, -39, -13, 45, -7, -42, 25, 31, -39, -14, 45, -6, -43, 24,
659 32, -38, -15, 45, -4, -43, 23, 33, -38, -16, 45, -3, -43, 22, 34, -37,
660 -17, 45, -2, -44, 21, 34, -36, -18, 44, -1, -44, 20, 35, -36, -19, 44,
661 }, {
662 32, -12, -39, 33, 21, -44, 2, 43, -25, -30, 41, 8, -45, 16, 36, -36,
663 -17, 45, -7, -41, 29, 26, -43, -3, 44, -20, -34, 38, 13, -45, 11, 39,
664 -32, -22, 44, -1, -43, 24, 30, -40, -9, 45, -15, -37, 35, 18, -45, 6,
665 42, -28, -27, 42, 4, -45, 19, 34, -38, -14, 45, -10, -40, 31, 23, -44,
666 }, {
667 32, -14, -36, 37, 13, -45, 15, 36, -38, -12, 45, -16, -35, 38, 11, -45,
668 17, 34, -39, -10, 45, -18, -34, 39, 9, -45, 19, 33, -40, -8, 45, -20,
669 -32, 40, 7, -45, 21, 31, -41, -6, 44, -22, -30, 41, 4, -44, 23, 30,
670 -42, -3, 44, -24, -29, 42, 2, -44, 25, 28, -43, -1, 43, -26, -27, 43,
671 }, {
672 32, -16, -34, 40, 4, -44, 27, 24, -44, 8, 39, -36, -13, 45, -19, -31,
673 42, 1, -43, 30, 21, -45, 11, 37, -38, -10, 45, -22, -29, 43, -2, -41,
674 32, 18, -45, 14, 35, -39, -7, 44, -25, -26, 44, -6, -40, 34, 15, -45,
675 17, 33, -41, -3, 43, -28, -23, 45, -9, -38, 36, 12, -45, 20, 30, -42,
676 }, {
677 32, -18, -30, 43, -4, -39, 36, 10, -44, 26, 23, -45, 13, 34, -41, -1,
678 42, -33, -15, 45, -21, -28, 44, -8, -38, 38, 7, -44, 29, 20, -45, 16,
679 32, -42, 2, 40, -35, -12, 45, -24, -25, 45, -11, -36, 40, 3, -43, 31,
680 17, -45, 19, 30, -43, 6, 39, -37, -9, 44, -27, -22, 45, -14, -34, 41,
681 }, {
682 32, -20, -27, 45, -13, -33, 43, -6, -38, 39, 2, -41, 35, 10, -44, 30,
683 17, -45, 23, 24, -45, 16, 30, -44, 9, 36, -41, 1, 40, -37, -7, 43,
684 -32, -14, 45, -26, -21, 45, -19, -28, 44, -12, -34, 42, -4, -38, 39, 3,
685 -42, 34, 11, -44, 29, 18, -45, 22, 25, -45, 15, 31, -43, 8, 36, -40,
686 }, {
687 32, -22, -23, 45, -21, -24, 45, -20, -25, 45, -19, -26, 45, -18, -27, 45,
688 -17, -28, 45, -16, -29, 45, -15, -30, 44, -14, -30, 44, -13, -31, 44, -12,
689 -32, 44, -11, -33, 43, -10, -34, 43, -9, -34, 43, -8, -35, 42, -7, -36,
690 42, -6, -36, 41, -4, -37, 41, -3, -38, 40, -2, -38, 40, -1, -39, 39,
691 }, {
692 32, -24, -19, 45, -29, -14, 44, -33, -9, 42, -36, -3, 40, -39, 2, 37,
693 -42, 8, 34, -44, 13, 30, -45, 18, 25, -45, 23, 20, -45, 28, 15, -44,
694 32, 10, -43, 36, 4, -40, 39, -1, -38, 41, -7, -34, 43, -12, -30, 45,
695 -17, -26, 45, -22, -21, 45, -27, -16, 44, -31, -11, 43, -35, -6, 41, -38,
696 }, {
697 32, -26, -15, 44, -35, -3, 39, -41, 9, 31, -45, 20, 21, -45, 30, 10,
698 -42, 38, -2, -36, 43, -14, -27, 45, -25, -16, 44, -34, -4, 39, -41, 8,
699 32, -45, 19, 22, -45, 30, 11, -42, 38, -1, -36, 43, -13, -28, 45, -24,
700 -17, 44, -34, -6, 40, -40, 7, 33, -44, 18, 23, -45, 29, 12, -43, 37,
701 }, {
702 32, -28, -11, 41, -40, 8, 30, -45, 25, 14, -43, 38, -4, -33, 45, -22,
703 -17, 44, -36, 1, 35, -44, 19, 20, -44, 34, 2, -37, 43, -16, -23, 45,
704 -32, -6, 39, -42, 13, 26, -45, 30, 9, -40, 41, -10, -29, 45, -27, -12,
705 42, -39, 7, 31, -45, 24, 15, -43, 38, -3, -34, 45, -21, -18, 44, -36,
706 }, {
707 32, -30, -7, 38, -43, 18, 19, -44, 38, -6, -30, 45, -29, -8, 39, -43,
708 17, 20, -44, 37, -4, -31, 45, -28, -9, 39, -43, 16, 21, -44, 36, -3,
709 -32, 45, -27, -10, 40, -42, 15, 22, -44, 36, -2, -33, 45, -26, -11, 40,
710 -42, 14, 23, -45, 35, -1, -34, 45, -25, -12, 41, -41, 13, 24, -45, 34,
711 }, {
712 32, -31, -2, 34, -45, 28, 7, -37, 44, -24, -11, 39, -43, 20, 15, -41,
713 42, -16, -19, 43, -40, 12, 23, -44, 38, -8, -27, 45, -35, 3, 30, -45,
714 32, 1, -34, 45, -29, -6, 36, -45, 25, 10, -39, 44, -21, -14, 41, -42,
715 17, 18, -43, 40, -13, -22, 44, -38, 9, 26, -45, 36, -4, -30, 45, -33,
716 }, {
717 32, -33, 2, 30, -45, 36, -7, -26, 44, -38, 11, 22, -43, 40, -15, -18,
718 42, -42, 19, 14, -40, 44, -23, -10, 38, -45, 27, 6, -35, 45, -30, -1,
719 32, -45, 34, -3, -29, 45, -36, 8, 25, -44, 39, -12, -21, 43, -41, 16,
720 17, -41, 43, -20, -13, 39, -44, 24, 9, -37, 45, -28, -4, 34, -45, 31,
721 }, {
722 32, -34, 7, 24, -43, 41, -19, -12, 38, -45, 30, -1, -29, 45, -39, 14,
723 17, -40, 44, -26, -4, 33, -45, 36, -9, -22, 43, -42, 21, 10, -36, 45,
724 -32, 3, 27, -44, 40, -16, -15, 39, -44, 28, 2, -31, 45, -37, 11, 20,
725 -42, 43, -23, -8, 35, -45, 34, -6, -25, 44, -41, 18, 13, -38, 45, -30,
726 }, {
727 32, -36, 11, 18, -40, 45, -30, 3, 25, -43, 43, -24, -4, 31, -45, 39,
728 -17, -12, 36, -45, 35, -10, -19, 40, -44, 30, -2, -26, 43, -42, 23, 6,
729 -32, 45, -39, 16, 13, -37, 45, -34, 9, 20, -41, 44, -29, 1, 27, -44,
730 42, -22, -7, 33, -45, 38, -15, -14, 38, -45, 34, -8, -21, 41, -44, 28,
731 }, {
732 32, -37, 15, 12, -35, 45, -39, 18, 9, -33, 45, -40, 21, 6, -30, 44,
733 -42, 24, 2, -28, 43, -43, 27, -1, -25, 42, -44, 30, -4, -22, 41, -45,
734 32, -8, -19, 39, -45, 34, -11, -16, 38, -45, 36, -14, -13, 36, -45, 38,
735 -17, -10, 34, -45, 40, -20, -7, 31, -44, 41, -23, -3, 29, -44, 43, -26,
736 }, {
737 32, -38, 19, 6, -29, 43, -44, 31, -9, -16, 36, -45, 40, -22, -2, 26,
738 -42, 45, -34, 12, 13, -34, 45, -41, 25, -1, -23, 40, -45, 36, -15, -10,
739 32, -44, 43, -28, 4, 20, -39, 45, -38, 18, 7, -30, 43, -44, 30, -8,
740 -17, 37, -45, 39, -21, -3, 27, -42, 44, -33, 11, 14, -35, 45, -41, 24,
741 }, {
742 32, -39, 23, -1, -21, 38, -45, 40, -25, 3, 19, -37, 45, -41, 27, -6,
743 -17, 36, -45, 42, -29, 8, 15, -34, 44, -43, 30, -10, -13, 33, -44, 44,
744 -32, 12, 11, -31, 43, -44, 34, -14, -9, 30, -43, 45, -35, 16, 7, -28,
745 42, -45, 36, -18, -4, 26, -41, 45, -38, 20, 2, -24, 40, -45, 39, -22,
746 }, {
747 32, -40, 27, -8, -13, 31, -43, 45, -38, 22, -2, -18, 35, -44, 44, -34,
748 17, 3, -23, 38, -45, 42, -30, 12, 9, -28, 41, -45, 40, -26, 7, 14,
749 -32, 43, -45, 37, -21, 1, 19, -36, 44, -44, 34, -16, -4, 24, -39, 45,
750 -42, 30, -11, -10, 29, -41, 45, -39, 25, -6, -15, 33, -43, 45, -36, 20,
751 }, {
752 32, -41, 30, -14, -4, 22, -36, 44, -44, 37, -23, 6, 13, -30, 41, -45,
753 42, -31, 15, 3, -21, 36, -44, 45, -38, 24, -7, -12, 29, -40, 45, -42,
754 32, -16, -2, 20, -35, 44, -45, 38, -25, 8, 11, -28, 40, -45, 43, -33,
755 17, 1, -19, 34, -43, 45, -39, 26, -9, -10, 27, -39, 45, -43, 34, -18,
756 }, {
757 32, -42, 34, -20, 4, 12, -27, 38, -44, 45, -39, 28, -13, -3, 19, -33,
758 42, -45, 43, -34, 21, -6, -11, 26, -38, 44, -45, 39, -29, 14, 2, -18,
759 32, -41, 45, -43, 35, -22, 7, 10, -25, 37, -44, 45, -40, 30, -15, -1,
760 17, -31, 41, -45, 43, -36, 23, -8, -9, 24, -36, 44, -45, 40, -30, 16,
761 }, {
762 32, -43, 36, -26, 13, 1, -15, 28, -38, 44, -45, 42, -35, 24, -11, -3,
763 17, -30, 39, -44, 45, -41, 34, -22, 9, 6, -19, 31, -40, 45, -45, 40,
764 -32, 20, -7, -8, 21, -33, 41, -45, 44, -39, 30, -18, 4, 10, -23, 34,
765 -42, 45, -44, 38, -29, 16, -2, -12, 25, -36, 43, -45, 43, -37, 27, -14,
766 }, {
767 32, -44, 39, -31, 21, -10, -2, 14, -25, 34, -41, 45, -45, 42, -36, 28,
768 -17, 6, 7, -18, 29, -37, 43, -45, 44, -40, 34, -24, 13, -1, -11, 22,
769 -32, 39, -44, 45, -43, 38, -30, 20, -9, -3, 15, -26, 35, -41, 45, -45,
770 42, -36, 27, -16, 4, 8, -19, 30, -38, 43, -45, 44, -40, 33, -23, 12,
771 }, {
772 32, -44, 41, -36, 29, -20, 11, -1, -9, 18, -27, 34, -40, 44, -45, 45,
773 -42, 37, -30, 22, -13, 3, 7, -16, 25, -33, 39, -43, 45, -45, 43, -38,
774 32, -24, 15, -6, -4, 14, -23, 31, -38, 42, -45, 45, -43, 39, -34, 26,
775 -17, 8, 2, -12, 21, -30, 36, -41, 44, -45, 44, -40, 35, -28, 19, -10,
776 }, {
777 32, -45, 43, -39, 35, -30, 23, -16, 9, -1, -7, 14, -21, 28, -34, 38,
778 -42, 44, -45, 45, -43, 40, -36, 31, -25, 18, -11, 3, 4, -12, 19, -26,
779 32, -37, 41, -44, 45, -45, 44, -41, 38, -33, 27, -20, 13, -6, -2, 10,
780 -17, 24, -30, 36, -40, 43, -45, 45, -44, 42, -39, 34, -29, 22, -15, 8,
781 }, {
782 32, -45, 44, -42, 40, -37, 34, -30, 25, -20, 15, -10, 4, 1, -7, 12,
783 -17, 22, -27, 31, -35, 38, -41, 43, -44, 45, -45, 45, -43, 41, -39, 36,
784 -32, 28, -23, 18, -13, 8, -2, -3, 9, -14, 19, -24, 29, -33, 36, -39,
785 42, -44, 45, -45, 45, -44, 43, -40, 38, -34, 30, -26, 21, -16, 11, -6,
786 }, {
787 32, -45, 45, -44, 43, -42, 41, -39, 38, -36, 34, -31, 29, -26, 23, -20,
788 17, -14, 11, -8, 4, -1, -2, 6, -9, 12, -15, 18, -21, 24, -27, 30,
789 -32, 34, -36, 38, -40, 41, -43, 44, -44, 45, -45, 45, -45, 45, -44, 43,
790 -42, 40, -39, 37, -35, 33, -30, 28, -25, 22, -19, 16, -13, 10, -7, 3,
791 }, {
792 32, -45, 45, -45, 45, -45, 45, -45, 44, -44, 44, -44, 43, -43, 43, -42,
793 42, -41, 41, -40, 40, -39, 39, -38, 38, -37, 36, -36, 35, -34, 34, -33,
794 32, -31, 30, -30, 29, -28, 27, -26, 25, -24, 23, -22, 21, -20, 19, -18,
795 17, -16, 15, -14, 13, -12, 11, -10, 9, -8, 7, -6, 4, -3, 2, -1,
796 }
797 };
798
799 struct H274HashContext {
800 int type;
801 struct AVMD5 *ctx;
802
803 #if HAVE_BIGENDIAN
804 BswapDSPContext bdsp;
805 uint8_t *buf;
806 int buf_size;
807 #endif
808 };
809
810 static av_always_inline void bswap16_buf_if_be(H274HashContext *s, const int ps, const uint8_t **src, const int w)
811 {
812 #if HAVE_BIGENDIAN
813 if (ps) {
814 s->bdsp.bswap16_buf((uint16_t *)s->buf,
815 (const uint16_t *)*src, w);
816 *src = s->buf;
817 }
818 #endif
819 }
820
821 static int verify_plane_md5(H274HashContext *s,
822 const uint8_t *_src, const int w, const int h, const int stride,
823 const int ps, const uint8_t *expected)
824 {
825 #define MD5_SIZE 16
826 struct AVMD5 *ctx = s->ctx;
827 uint8_t md5[MD5_SIZE];
828
829 av_md5_init(ctx);
830 for (int j = 0; j < h; j++) {
831 const uint8_t *src = &_src[j * stride];
832 bswap16_buf_if_be(s, ps, &src, w);
833 av_md5_update(ctx, src, w << ps);
834 src += stride;
835 }
836 av_md5_final(ctx, md5);
837
838 if (memcmp(md5, expected, MD5_SIZE))
839 return AVERROR_INVALIDDATA;
840
841 return 0;
842 }
843
844 static int verify_plane_crc(H274HashContext *s, const uint8_t *_src, const int w, const int h, const int stride,
845 const int ps, uint16_t expected)
846 {
847 uint32_t crc = 0x0F1D; // CRC-16-CCITT-AUG
848 const AVCRC *ctx = av_crc_get_table(AV_CRC_16_CCITT);
849
850 for (int j = 0; j < h; j++) {
851 const uint8_t *src = &_src[j * stride];
852 bswap16_buf_if_be(s, ps, &src, w);
853 crc = av_crc(ctx, crc, src, w << ps);
854 src += stride;
855 }
856 crc = av_bswap16(crc);
857
858 if (crc != expected)
859 return AVERROR_INVALIDDATA;
860
861 return 0;
862 }
863
864 #define CAL_CHECKSUM(pixel) ((pixel) ^ xor_mask)
865 static int verify_plane_checksum(const uint8_t *src, const int w, const int h, const int stride, const int ps,
866 uint32_t expected)
867 {
868 uint32_t checksum = 0;
869 expected = av_le2ne32(expected);
870
871 for (int y = 0; y < h; y++) {
872 for (int x = 0; x < w; x++) {
873 const int xor_mask = (x & 0xFF) ^ (y & 0xFF) ^ (x >> 8) ^ (y >> 8);
874 checksum += CAL_CHECKSUM(src[x << ps]);
875 if (ps)
876 checksum += CAL_CHECKSUM(src[(x << ps) + 1]);
877 }
878 src += stride;
879 }
880
881 if (checksum != expected)
882 return AVERROR_INVALIDDATA;
883
884 return 0;
885 }
886
887 enum {
888 HASH_MD5SUM,
889 HASH_CRC,
890 HASH_CHECKSUM,
891 HASH_LAST = HASH_CHECKSUM,
892 };
893
894 94 void ff_h274_hash_freep(H274HashContext **ctx)
895 {
896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 if (*ctx) {
897 H274HashContext *c = *ctx;
898 if (c->ctx)
899 av_free(c->ctx);
900 av_freep(ctx);
901 #if HAVE_BIGENDIAN
902 av_freep(&c->buf);
903 #endif
904 }
905 94 }
906
907 int ff_h274_hash_init(H274HashContext **ctx, const int type)
908 {
909 H274HashContext *c;
910
911 if (type > HASH_LAST || !ctx)
912 return AVERROR(EINVAL);
913
914 c = *ctx;
915 if (c) {
916 if (c->type != type) {
917 if (c->type == HASH_MD5SUM)
918 av_freep(&c->ctx);
919 c->type = type;
920 }
921 } else {
922 c = av_mallocz(sizeof(H274HashContext));
923 if (!c)
924 return AVERROR(ENOMEM);
925 c->type = type;
926 *ctx = c;
927 }
928
929 if (type == HASH_MD5SUM && !c->ctx) {
930 c->ctx = av_md5_alloc();
931 if (!c->ctx)
932 return AVERROR(ENOMEM);
933 }
934
935 #if HAVE_BIGENDIAN
936 ff_bswapdsp_init(&c->bdsp);
937 #endif
938
939 return 0;
940 }
941
942 int ff_h274_hash_verify(H274HashContext *c, const H274SEIPictureHash *hash,
943 const AVFrame *frame, const int coded_width, const int coded_height)
944 {
945 const AVPixFmtDescriptor *desc;
946 int err = 0;
947
948 if (!c || !hash || !frame)
949 return AVERROR(EINVAL);
950
951 if (c->type != hash->hash_type)
952 return AVERROR(EINVAL);
953
954 desc = av_pix_fmt_desc_get(frame->format);
955 if (!desc)
956 return AVERROR(EINVAL);
957
958 for (int i = 0; i < desc->nb_components; i++) {
959 const int w = i ? (coded_width >> desc->log2_chroma_w) : coded_width;
960 const int h = i ? (coded_height >> desc->log2_chroma_h) : coded_height;
961 const int ps = desc->comp[i].step - 1;
962 const uint8_t *src = frame->data[i];
963 const int stride = frame->linesize[i];
964
965 #if HAVE_BIGENDIAN
966 if (c->type != HASH_CHECKSUM) {
967 if (ps) {
968 av_fast_malloc(&c->buf, &c->buf_size,
969 FFMAX3(frame->linesize[0], frame->linesize[1],
970 frame->linesize[2]));
971 if (!c->buf)
972 return AVERROR(ENOMEM);
973 }
974 }
975 #endif
976
977 if (c->type == HASH_MD5SUM)
978 err = verify_plane_md5(c, src, w, h, stride, ps, hash->md5[i]);
979 else if (c->type == HASH_CRC)
980 err = verify_plane_crc(c, src, w, h, stride, ps, hash->crc[i]);
981 else if (c->type == HASH_CHECKSUM)
982 err = verify_plane_checksum(src, w, h, stride, ps, hash->checksum[i]);
983 if (err < 0)
984 goto fail;
985 }
986
987 fail:
988 return err;
989 }
990