FFmpeg coverage


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