FFmpeg coverage


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