FFmpeg coverage


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