Coverage Report

Created: 2026-10-28 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/av1/encoder/hash_motion.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2018, Alliance for Open Media. All rights reserved.
3
 *
4
 * This source code is subject to the terms of the BSD 2 Clause License and
5
 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6
 * was not distributed with this source code in the LICENSE file, you can
7
 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8
 * Media Patent License 1.0 was not distributed with this source code in the
9
 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10
 */
11
12
#include <assert.h>
13
#include <stdbool.h>
14
#include <string.h>
15
16
#include "config/av1_rtcd.h"
17
18
#include "av1/encoder/block.h"
19
#include "av1/encoder/hash.h"
20
#include "av1/encoder/hash_motion.h"
21
22
0
#define kSrcBits 16
23
// kMaxAddr is the number of hash table buckets. They form 6 hash tables of
24
// 1 << kSrcBits buckets each. Each of the 6 supported block sizes (4, 8, 16,
25
// 32, 64, 128) has its own hash table, indexed by the return value of
26
// hash_block_size_to_index().
27
0
#define kMaxAddr (6 << kSrcBits)
28
0
#define kMaxCandidatesPerHashBucket 256
29
30
static void get_pixels_in_1D_char_array_by_block_2x2(const uint8_t *y_src,
31
                                                     int stride,
32
0
                                                     uint8_t *p_pixels_in1D) {
33
0
  const uint8_t *p_pel = y_src;
34
0
  int index = 0;
35
0
  for (int i = 0; i < 2; i++) {
36
0
    for (int j = 0; j < 2; j++) {
37
0
      p_pixels_in1D[index++] = p_pel[j];
38
0
    }
39
0
    p_pel += stride;
40
0
  }
41
0
}
42
43
static void get_pixels_in_1D_short_array_by_block_2x2(const uint16_t *y_src,
44
                                                      int stride,
45
0
                                                      uint16_t *p_pixels_in1D) {
46
0
  const uint16_t *p_pel = y_src;
47
0
  int index = 0;
48
0
  for (int i = 0; i < 2; i++) {
49
0
    for (int j = 0; j < 2; j++) {
50
0
      p_pixels_in1D[index++] = p_pel[j];
51
0
    }
52
0
    p_pel += stride;
53
0
  }
54
0
}
55
56
// the hash value (hash_value1) consists of two parts, the first 3 bits relate
57
// to the block size and the remaining 16 bits are the crc values. This
58
// function is used to get the first 3 bits.
59
0
static int hash_block_size_to_index(int block_size) {
60
0
  switch (block_size) {
61
0
    case 4: return 0;
62
0
    case 8: return 1;
63
0
    case 16: return 2;
64
0
    case 32: return 3;
65
0
    case 64: return 4;
66
0
    case 128: return 5;
67
0
    default: return -1;
68
0
  }
69
0
}
70
71
static uint32_t get_identity_hash_value(const uint8_t a, const uint8_t b,
72
0
                                        const uint8_t c, const uint8_t d) {
73
  // The four input values add up to 32 bits, which is the size of the output.
74
  // Just pack those values as is.
75
0
  return ((uint32_t)a << 24) + ((uint32_t)b << 16) + ((uint32_t)c << 8) +
76
0
         ((uint32_t)d);
77
0
}
78
79
static uint32_t get_xor_hash_value_hbd(const uint16_t a, const uint16_t b,
80
0
                                       const uint16_t c, const uint16_t d) {
81
0
  uint32_t result;
82
  // Pack the lower 8 bits of each input value to the 32 bit output, then xor
83
  // with the upper 8 bits of each input value.
84
0
  result = ((uint32_t)(a & 0x00ff) << 24) + ((uint32_t)(b & 0x00ff) << 16) +
85
0
           ((uint32_t)(c & 0x00ff) << 8) + ((uint32_t)(d & 0x00ff));
86
0
  result ^= ((uint32_t)(a & 0xff00) << 16) + ((uint32_t)(b & 0xff00) << 8) +
87
0
            ((uint32_t)(c & 0xff00)) + ((uint32_t)(d & 0xff00) >> 8);
88
0
  return result;
89
0
}
90
91
0
void av1_hash_table_init(IntraBCHashInfo *intrabc_hash_info) {
92
0
  if (!intrabc_hash_info->crc_initialized) {
93
0
    av1_crc32c_calculator_init(&intrabc_hash_info->crc_calculator);
94
0
    intrabc_hash_info->crc_initialized = 1;
95
0
  }
96
0
}
97
98
0
void av1_hash_table_destroy(hash_table *p_hash_table) {
99
0
  aom_free(p_hash_table->bucket_count);
100
0
  aom_free(p_hash_table->bucket_start);
101
0
  for (int i = 0; i < NELEMENTS(p_hash_table->block_hashes); i++) {
102
0
    aom_free(p_hash_table->block_hashes[i]);
103
0
  }
104
0
  memset(p_hash_table, 0, sizeof(*p_hash_table));
105
0
}
106
107
// Empties the table. The buffers are kept for the next frame.
108
0
bool av1_hash_table_create(hash_table *p_hash_table) {
109
0
  if (p_hash_table->bucket_count == NULL) {
110
0
    p_hash_table->bucket_count =
111
0
        aom_malloc(kMaxAddr * sizeof(*p_hash_table->bucket_count));
112
0
    p_hash_table->bucket_start =
113
0
        aom_malloc(kMaxAddr * sizeof(*p_hash_table->bucket_start));
114
0
    if (!p_hash_table->bucket_count || !p_hash_table->bucket_start) {
115
0
      av1_hash_table_destroy(p_hash_table);
116
0
      return false;
117
0
    }
118
0
  }
119
0
  memset(p_hash_table->bucket_count, 0,
120
0
         kMaxAddr * sizeof(*p_hash_table->bucket_count));
121
0
  return true;
122
0
}
123
124
// Makes sure block_hashes[size_index] has room for at least size entries. Its
125
// old entries are lost even when the function fails.
126
static bool hash_table_reserve_block_hashes(hash_table *p_hash_table,
127
0
                                            int size_index, uint32_t size) {
128
0
  if (size <= p_hash_table->block_hashes_size[size_index]) return true;
129
0
  aom_free(p_hash_table->block_hashes[size_index]);
130
0
  p_hash_table->block_hashes[size_index] =
131
0
      aom_malloc(size * sizeof(*p_hash_table->block_hashes[size_index]));
132
0
  if (p_hash_table->block_hashes[size_index] == NULL) {
133
0
    p_hash_table->block_hashes_size[size_index] = 0;
134
0
    return false;
135
0
  }
136
0
  p_hash_table->block_hashes_size[size_index] = size;
137
0
  return true;
138
0
}
139
140
0
static inline void add_to_bucket_count(uint16_t *count, int n) {
141
0
  *count = AOMMIN(*count + n, kMaxCandidatesPerHashBucket);
142
0
}
143
144
int32_t av1_hash_table_count(const hash_table *p_hash_table,
145
0
                             uint32_t hash_value) {
146
0
  return p_hash_table->bucket_count[hash_value];
147
0
}
148
149
const block_hash *av1_hash_get_first_block_hash(const hash_table *p_hash_table,
150
0
                                                uint32_t hash_value) {
151
0
  assert(av1_hash_table_count(p_hash_table, hash_value) > 0);
152
0
  const block_hash *const block_hashes =
153
0
      p_hash_table->block_hashes[hash_value >> kSrcBits];
154
0
  return &block_hashes[p_hash_table->bucket_start[hash_value]];
155
0
}
156
157
void av1_generate_block_2x2_hash_value(const YV12_BUFFER_CONFIG *picture,
158
0
                                       uint32_t *pic_block_hash) {
159
0
  const int width = 2;
160
0
  const int height = 2;
161
0
  const int x_end = picture->y_crop_width - width + 1;
162
0
  const int y_end = picture->y_crop_height - height + 1;
163
164
0
  if (picture->flags & YV12_FLAG_HIGHBITDEPTH) {
165
0
    uint16_t p[4];
166
0
    int pos = 0;
167
0
    for (int y_pos = 0; y_pos < y_end; y_pos++) {
168
0
      for (int x_pos = 0; x_pos < x_end; x_pos++) {
169
0
        get_pixels_in_1D_short_array_by_block_2x2(
170
0
            CONVERT_TO_SHORTPTR(picture->y_buffer) + y_pos * picture->y_stride +
171
0
                x_pos,
172
0
            picture->y_stride, p);
173
        // For HBD, we either have 40 or 48 bits of input data that the xor hash
174
        // reduce to 32 bits. We intentionally don't want to "discard" bits to
175
        // avoid any kind of biasing.
176
0
        pic_block_hash[pos] = get_xor_hash_value_hbd(p[0], p[1], p[2], p[3]);
177
0
        pos++;
178
0
      }
179
0
      pos += width - 1;
180
0
    }
181
0
  } else {
182
0
    uint8_t p[4];
183
0
    int pos = 0;
184
0
    for (int y_pos = 0; y_pos < y_end; y_pos++) {
185
0
      for (int x_pos = 0; x_pos < x_end; x_pos++) {
186
0
        get_pixels_in_1D_char_array_by_block_2x2(
187
0
            picture->y_buffer + y_pos * picture->y_stride + x_pos,
188
0
            picture->y_stride, p);
189
        // This 2x2 hash isn't used directly as a "key" for the hash table, so
190
        // we can afford to just copy the 4 8-bit pixel values as a single
191
        // 32-bit value directly. (i.e. there are no concerns of a lack of
192
        // uniform distribution)
193
0
        pic_block_hash[pos] = get_identity_hash_value(p[0], p[1], p[2], p[3]);
194
0
        pos++;
195
0
      }
196
0
      pos += width - 1;
197
0
    }
198
0
  }
199
0
}
200
201
void av1_generate_block_hash_value(IntraBCHashInfo *intrabc_hash_info,
202
                                   const YV12_BUFFER_CONFIG *picture,
203
                                   int block_size,
204
                                   const uint32_t *src_pic_block_hash,
205
0
                                   uint32_t *dst_pic_block_hash) {
206
0
  CRC32C *calc = &intrabc_hash_info->crc_calculator;
207
208
0
  const int pic_width = picture->y_crop_width;
209
0
  const int x_end = picture->y_crop_width - block_size + 1;
210
0
  const int y_end = picture->y_crop_height - block_size + 1;
211
0
  const int src_size = block_size >> 1;
212
213
0
  uint32_t p[4];
214
0
  const int length = sizeof(p);
215
216
0
  int pos = 0;
217
0
  for (int y_pos = 0; y_pos < y_end; y_pos++) {
218
0
    for (int x_pos = 0; x_pos < x_end; x_pos++) {
219
      // Build up a bigger block from 4 smaller, non-overlapping source block
220
      // hashes, and compute its hash. Note: source blocks at the right and
221
      // bottom borders cannot be part of larger blocks, therefore they won't be
222
      // considered into the block hash value generation process.
223
0
      p[0] = src_pic_block_hash[pos];
224
0
      p[1] = src_pic_block_hash[pos + src_size];
225
0
      p[2] = src_pic_block_hash[pos + src_size * pic_width];
226
0
      p[3] = src_pic_block_hash[pos + src_size * pic_width + src_size];
227
      // TODO: bug aomedia:433531610 - serialize input values in a way that's
228
      // independent of the computer architecture's endianness
229
0
      dst_pic_block_hash[pos] =
230
0
          av1_get_crc32c_value(calc, (uint8_t *)p, length);
231
0
      pos++;
232
0
    }
233
0
    pos += block_size - 1;
234
0
  }
235
0
}
236
237
// Adds the blocks of one block size to the table. The counts of that block
238
// size must be zero on entry, as av1_hash_table_create() leaves them. On
239
// return they hold the number of entries in each bucket.
240
bool av1_add_to_hash_map_by_row_with_precal_data(hash_table *p_hash_table,
241
                                                 const uint32_t *pic_hash,
242
                                                 int pic_width, int pic_height,
243
0
                                                 int block_size) {
244
0
  const int x_end = pic_width - block_size + 1;
245
0
  const int y_end = pic_height - block_size + 1;
246
247
0
  const int size_index = hash_block_size_to_index(block_size);
248
0
  assert(size_index >= 0);
249
0
  const int add_value = size_index << kSrcBits;
250
0
  const int crc_mask = (1 << kSrcBits) - 1;
251
0
  uint16_t *const bucket_count = p_hash_table->bucket_count + add_value;
252
0
  uint32_t *const bucket_start = p_hash_table->bucket_start + add_value;
253
0
  int step = block_size;
254
0
  int x_offset = 0;
255
0
  int y_offset = 0;
256
257
  // No block of this size fits in the frame.
258
0
  if (x_end <= 0 || y_end <= 0) return true;
259
260
  // The next two loops set bucket_start. The first counts the blocks of each
261
  // bucket, and the second places the buckets one after another.
262
  //
263
  // Place an upper bound each hash table bucket to up to 256 intrabc
264
  // block candidates, and ignore subsequent ones. Considering more can
265
  // unnecessarily slow down encoding for virtually no efficiency gain.
266
  // How many blocks each bucket keeps doesn't depend on the order they are
267
  // added in, so count them first in raster order. Flat areas give long runs
268
  // of the same bucket, so count a whole run at once.
269
0
  for (int y_pos = 0; y_pos < y_end; y_pos++) {
270
0
    const uint32_t *const row_hash = pic_hash + y_pos * pic_width;
271
0
    int bucket = row_hash[0] & crc_mask;
272
0
    int run = 0;
273
0
    for (int x_pos = 0; x_pos < x_end; x_pos++) {
274
0
      const int curr_bucket = row_hash[x_pos] & crc_mask;
275
0
      if (curr_bucket != bucket) {
276
0
        add_to_bucket_count(&bucket_count[bucket], run);
277
0
        bucket = curr_bucket;
278
0
        run = 0;
279
0
      }
280
0
      run++;
281
0
    }
282
0
    add_to_bucket_count(&bucket_count[bucket], run);
283
0
  }
284
285
  // Store the buckets one after another. The counts restart from zero and
286
  // track how far each bucket is filled.
287
0
  uint32_t num_block_hashes = 0;
288
0
  for (int i = 0; i <= crc_mask; i++) {
289
0
    bucket_start[i] = num_block_hashes;
290
0
    num_block_hashes += bucket_count[i];
291
0
    bucket_count[i] = 0;
292
0
  }
293
0
  if (!hash_table_reserve_block_hashes(p_hash_table, size_index,
294
0
                                       num_block_hashes)) {
295
0
    return false;
296
0
  }
297
0
  block_hash *const block_hashes = p_hash_table->block_hashes[size_index];
298
299
  // Explore the entire frame hierarchically to add intrabc candidate blocks to
300
  // the hash table, by starting with coarser steps (the block size), towards
301
  // finer-grained steps until every candidate block has been considered.
302
  // The nested for loop goes through the pic_hash array column by column.
303
304
  // Doing a hierarchical block exploration helps maximize spatial dispersion
305
  // of the first and foremost candidate blocks while minimizing overlap between
306
  // them. This is helpful because we only keep up to 256 entries of the
307
  // same candidate block (located in different places), so we want those
308
  // entries to cover the biggest area of the image to encode to maximize coding
309
  // efficiency.
310
311
  // This is the coordinate exploration order example for an 8x8 region, with
312
  // block_size = 4. The top-left corner (x, y) coordinates of each candidate
313
  // block are shown below. There are 5 * 5 (25) candidate blocks.
314
  //    x  0  1  2  3  4  5  6  7
315
  //  y +------------------------
316
  //  0 |  1 10  5 13  3
317
  //  1 | 16 22 18 24 20
318
  //  2 |  7 11  9 14  8
319
  //  3 | 17 23 19 25 21
320
  //  4 |  2 12  6 15  4--------+
321
  //  5 |              | 4 x 4  |
322
  //  6 |              | block  |
323
  //  7 |              +--------+
324
325
  // Please note that due to the way block exploration works, the smallest step
326
  // used is 2 (i.e. no two adjacent blocks will be explored consecutively).
327
  // Also, the exploration is designed to visit each block candidate only once.
328
0
  while (step > 1) {
329
0
    for (int x_pos = x_offset; x_pos < x_end; x_pos += step) {
330
0
      for (int y_pos = y_offset; y_pos < y_end; y_pos += step) {
331
0
        const int pos = y_pos * pic_width + x_pos;
332
0
        const int bucket = pic_hash[pos] & crc_mask;
333
0
        const int count = bucket_count[bucket];
334
0
        assert(count <= kMaxCandidatesPerHashBucket);
335
0
        if (count == kMaxCandidatesPerHashBucket) continue;
336
337
0
        block_hash *const curr_block_hash =
338
0
            &block_hashes[bucket_start[bucket] + count];
339
0
        curr_block_hash->x = x_pos;
340
0
        curr_block_hash->y = y_pos;
341
0
        curr_block_hash->hash_value2 = pic_hash[pos];
342
0
        bucket_count[bucket] = count + 1;
343
0
      }
344
0
    }
345
346
    // Adjust offsets and step sizes with this state machine.
347
    // State 0 is needed because no blocks in pic_hash have been explored,
348
    // so exploration requires a way to account for blocks with both zero
349
    // x_offset and zero y_offset.
350
    // State 0 is always meant to be executed first, but the relative order of
351
    // states 1, 2 and 3 can be arbitrary, as long as no two adjacent blocks
352
    // are explored consecutively.
353
0
    if (x_offset == 0 && y_offset == 0) {
354
      // State 0 -> State 1: special case
355
      // This state transition will only execute when step == block_size
356
0
      x_offset = step / 2;
357
0
    } else if (x_offset == step / 2 && y_offset == 0) {
358
      // State 1 -> State 2
359
0
      x_offset = 0;
360
0
      y_offset = step / 2;
361
0
    } else if (x_offset == 0 && y_offset == step / 2) {
362
      // State 2 -> State 3
363
0
      x_offset = step / 2;
364
0
    } else {
365
0
      assert(x_offset == step / 2 && y_offset == step / 2);
366
      // State 3 -> State 1: We've fully explored all the coordinates for the
367
      // current step size, continue by halving the step size
368
0
      step /= 2;
369
0
      x_offset = step / 2;
370
0
      y_offset = 0;
371
0
    }
372
0
  }
373
374
0
  return true;
375
0
}
376
377
int av1_hash_is_horizontal_perfect(const YV12_BUFFER_CONFIG *picture,
378
0
                                   int block_size, int x_start, int y_start) {
379
0
  const int stride = picture->y_stride;
380
0
  const uint8_t *p = picture->y_buffer + y_start * stride + x_start;
381
382
0
  if (picture->flags & YV12_FLAG_HIGHBITDEPTH) {
383
0
    const uint16_t *p16 = CONVERT_TO_SHORTPTR(p);
384
0
    for (int i = 0; i < block_size; i++) {
385
0
      for (int j = 1; j < block_size; j++) {
386
0
        if (p16[j] != p16[0]) {
387
0
          return 0;
388
0
        }
389
0
      }
390
0
      p16 += stride;
391
0
    }
392
0
  } else {
393
0
    for (int i = 0; i < block_size; i++) {
394
0
      for (int j = 1; j < block_size; j++) {
395
0
        if (p[j] != p[0]) {
396
0
          return 0;
397
0
        }
398
0
      }
399
0
      p += stride;
400
0
    }
401
0
  }
402
403
0
  return 1;
404
0
}
405
406
int av1_hash_is_vertical_perfect(const YV12_BUFFER_CONFIG *picture,
407
0
                                 int block_size, int x_start, int y_start) {
408
0
  const int stride = picture->y_stride;
409
0
  const uint8_t *p = picture->y_buffer + y_start * stride + x_start;
410
411
0
  if (picture->flags & YV12_FLAG_HIGHBITDEPTH) {
412
0
    const uint16_t *p16 = CONVERT_TO_SHORTPTR(p);
413
0
    for (int i = 0; i < block_size; i++) {
414
0
      for (int j = 1; j < block_size; j++) {
415
0
        if (p16[j * stride + i] != p16[i]) {
416
0
          return 0;
417
0
        }
418
0
      }
419
0
    }
420
0
  } else {
421
0
    for (int i = 0; i < block_size; i++) {
422
0
      for (int j = 1; j < block_size; j++) {
423
0
        if (p[j * stride + i] != p[i]) {
424
0
          return 0;
425
0
        }
426
0
      }
427
0
    }
428
0
  }
429
0
  return 1;
430
0
}
431
432
void av1_get_block_hash_value(IntraBCHashInfo *intra_bc_hash_info,
433
                              const uint8_t *y_src, int stride, int block_size,
434
                              uint32_t *hash_value1, uint32_t *hash_value2,
435
0
                              int use_highbitdepth) {
436
0
  int add_value = hash_block_size_to_index(block_size);
437
0
  assert(add_value >= 0);
438
0
  add_value <<= kSrcBits;
439
0
  const int crc_mask = (1 << kSrcBits) - 1;
440
441
0
  CRC32C *calc = &intra_bc_hash_info->crc_calculator;
442
0
  uint32_t **buf = intra_bc_hash_info->hash_value_buffer;
443
444
  // 2x2 subblock hash values in current CU
445
0
  int sub_block_in_width = (block_size >> 1);
446
0
  if (use_highbitdepth) {
447
0
    uint16_t pixel_to_hash[4];
448
0
    uint16_t *y16_src = CONVERT_TO_SHORTPTR(y_src);
449
0
    for (int y_pos = 0; y_pos < block_size; y_pos += 2) {
450
0
      for (int x_pos = 0; x_pos < block_size; x_pos += 2) {
451
0
        int pos = (y_pos >> 1) * sub_block_in_width + (x_pos >> 1);
452
0
        get_pixels_in_1D_short_array_by_block_2x2(
453
0
            y16_src + y_pos * stride + x_pos, stride, pixel_to_hash);
454
0
        assert(pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
455
        // For HBD, we either have 40 or 48 bits of input data that the xor hash
456
        // reduce to 32 bits. We intentionally don't want to "discard" bits to
457
        // avoid any kind of biasing.
458
0
        buf[0][pos] =
459
0
            get_xor_hash_value_hbd(pixel_to_hash[0], pixel_to_hash[1],
460
0
                                   pixel_to_hash[2], pixel_to_hash[3]);
461
0
      }
462
0
    }
463
0
  } else {
464
0
    uint8_t pixel_to_hash[4];
465
0
    for (int y_pos = 0; y_pos < block_size; y_pos += 2) {
466
0
      for (int x_pos = 0; x_pos < block_size; x_pos += 2) {
467
0
        int pos = (y_pos >> 1) * sub_block_in_width + (x_pos >> 1);
468
0
        get_pixels_in_1D_char_array_by_block_2x2(y_src + y_pos * stride + x_pos,
469
0
                                                 stride, pixel_to_hash);
470
0
        assert(pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
471
        // This 2x2 hash isn't used directly as a "key" for the hash table, so
472
        // we can afford to just copy the 4 8-bit pixel values as a single
473
        // 32-bit value directly. (i.e. there are no concerns of a lack of
474
        // uniform distribution)
475
0
        buf[0][pos] =
476
0
            get_identity_hash_value(pixel_to_hash[0], pixel_to_hash[1],
477
0
                                    pixel_to_hash[2], pixel_to_hash[3]);
478
0
      }
479
0
    }
480
0
  }
481
482
0
  int src_sub_block_in_width = sub_block_in_width;
483
0
  sub_block_in_width >>= 1;
484
485
0
  int src_idx = 0;
486
0
  int dst_idx = !src_idx;
487
488
  // 4x4 subblock hash values to current block hash values
489
0
  uint32_t to_hash[4];
490
0
  for (int sub_width = 4; sub_width <= block_size;
491
0
       sub_width *= 2, src_idx = !src_idx) {
492
0
    dst_idx = !src_idx;
493
494
0
    int dst_pos = 0;
495
0
    for (int y_pos = 0; y_pos < sub_block_in_width; y_pos++) {
496
0
      for (int x_pos = 0; x_pos < sub_block_in_width; x_pos++) {
497
0
        int srcPos = (y_pos << 1) * src_sub_block_in_width + (x_pos << 1);
498
499
0
        assert(srcPos + 1 < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
500
0
        assert(srcPos + src_sub_block_in_width + 1 <
501
0
               AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
502
0
        assert(dst_pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
503
504
0
        to_hash[0] = buf[src_idx][srcPos];
505
0
        to_hash[1] = buf[src_idx][srcPos + 1];
506
0
        to_hash[2] = buf[src_idx][srcPos + src_sub_block_in_width];
507
0
        to_hash[3] = buf[src_idx][srcPos + src_sub_block_in_width + 1];
508
509
        // TODO: bug aomedia:433531610 - serialize input values in a way that's
510
        // independent of the computer architecture's endianness
511
0
        buf[dst_idx][dst_pos] =
512
0
            av1_get_crc32c_value(calc, (uint8_t *)to_hash, sizeof(to_hash));
513
0
        dst_pos++;
514
0
      }
515
0
    }
516
517
0
    src_sub_block_in_width = sub_block_in_width;
518
0
    sub_block_in_width >>= 1;
519
0
  }
520
521
0
  *hash_value1 = (buf[dst_idx][0] & crc_mask) + add_value;
522
0
  *hash_value2 = buf[dst_idx][0];
523
0
}