Coverage Report

Created: 2026-11-12 08:20

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