Coverage Report

Created: 2025-06-22 08:04

/src/aom/av1/encoder/hash_motion.c
Line
Count
Source (jump to first uncovered line)
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
15
#include "config/av1_rtcd.h"
16
17
#include "av1/encoder/block.h"
18
#include "av1/encoder/hash.h"
19
#include "av1/encoder/hash_motion.h"
20
21
0
#define kSrcBits 16
22
0
#define kBlockSizeBits 3
23
0
#define kMaxAddr (1 << (kSrcBits + kBlockSizeBits))
24
25
// TODO(youzhou@microsoft.com): is higher than 8 bits screen content supported?
26
// If yes, fix this function
27
static void get_pixels_in_1D_char_array_by_block_2x2(const uint8_t *y_src,
28
                                                     int stride,
29
0
                                                     uint8_t *p_pixels_in1D) {
30
0
  const uint8_t *p_pel = y_src;
31
0
  int index = 0;
32
0
  for (int i = 0; i < 2; i++) {
33
0
    for (int j = 0; j < 2; j++) {
34
0
      p_pixels_in1D[index++] = p_pel[j];
35
0
    }
36
0
    p_pel += stride;
37
0
  }
38
0
}
39
40
static void get_pixels_in_1D_short_array_by_block_2x2(const uint16_t *y_src,
41
                                                      int stride,
42
0
                                                      uint16_t *p_pixels_in1D) {
43
0
  const uint16_t *p_pel = y_src;
44
0
  int index = 0;
45
0
  for (int i = 0; i < 2; i++) {
46
0
    for (int j = 0; j < 2; j++) {
47
0
      p_pixels_in1D[index++] = p_pel[j];
48
0
    }
49
0
    p_pel += stride;
50
0
  }
51
0
}
52
53
0
static int is_block_2x2_row_same_value(const uint8_t *p) {
54
0
  if (p[0] != p[1] || p[2] != p[3]) {
55
0
    return 0;
56
0
  }
57
0
  return 1;
58
0
}
59
60
0
static int is_block16_2x2_row_same_value(const uint16_t *p) {
61
0
  if (p[0] != p[1] || p[2] != p[3]) {
62
0
    return 0;
63
0
  }
64
0
  return 1;
65
0
}
66
67
0
static int is_block_2x2_col_same_value(const uint8_t *p) {
68
0
  if ((p[0] != p[2]) || (p[1] != p[3])) {
69
0
    return 0;
70
0
  }
71
0
  return 1;
72
0
}
73
74
0
static int is_block16_2x2_col_same_value(const uint16_t *p) {
75
0
  if ((p[0] != p[2]) || (p[1] != p[3])) {
76
0
    return 0;
77
0
  }
78
0
  return 1;
79
0
}
80
81
// the hash value (hash_value1 consists two parts, the first 3 bits relate to
82
// the block size and the remaining 16 bits are the crc values. This fuction
83
// is used to get the first 3 bits.
84
0
static int hash_block_size_to_index(int block_size) {
85
0
  switch (block_size) {
86
0
    case 4: return 0;
87
0
    case 8: return 1;
88
0
    case 16: return 2;
89
0
    case 32: return 3;
90
0
    case 64: return 4;
91
0
    case 128: return 5;
92
0
    default: return -1;
93
0
  }
94
0
}
95
96
0
void av1_hash_table_init(IntraBCHashInfo *intrabc_hash_info) {
97
0
  if (!intrabc_hash_info->g_crc_initialized) {
98
0
    av1_crc_calculator_init(&intrabc_hash_info->crc_calculator1, 24, 0x5D6DCB);
99
0
    av1_crc_calculator_init(&intrabc_hash_info->crc_calculator2, 24, 0x864CFB);
100
0
    intrabc_hash_info->g_crc_initialized = 1;
101
0
  }
102
0
  intrabc_hash_info->intrabc_hash_table.p_lookup_table = NULL;
103
0
}
104
105
0
static void clear_all(hash_table *p_hash_table) {
106
0
  if (p_hash_table->p_lookup_table == NULL) {
107
0
    return;
108
0
  }
109
0
  for (int i = 0; i < kMaxAddr; i++) {
110
0
    if (p_hash_table->p_lookup_table[i] != NULL) {
111
0
      aom_vector_destroy(p_hash_table->p_lookup_table[i]);
112
0
      aom_free(p_hash_table->p_lookup_table[i]);
113
0
      p_hash_table->p_lookup_table[i] = NULL;
114
0
    }
115
0
  }
116
0
}
117
118
0
void av1_hash_table_destroy(hash_table *p_hash_table) {
119
0
  clear_all(p_hash_table);
120
0
  aom_free(p_hash_table->p_lookup_table);
121
0
  p_hash_table->p_lookup_table = NULL;
122
0
}
123
124
0
bool av1_hash_table_create(hash_table *p_hash_table) {
125
0
  if (p_hash_table->p_lookup_table != NULL) {
126
0
    clear_all(p_hash_table);
127
0
    return true;
128
0
  }
129
0
  p_hash_table->p_lookup_table =
130
0
      (Vector **)aom_calloc(kMaxAddr, sizeof(p_hash_table->p_lookup_table[0]));
131
0
  if (!p_hash_table->p_lookup_table) return false;
132
0
  return true;
133
0
}
134
135
static bool hash_table_add_to_table(hash_table *p_hash_table,
136
                                    uint32_t hash_value,
137
0
                                    block_hash *curr_block_hash) {
138
0
  if (p_hash_table->p_lookup_table[hash_value] == NULL) {
139
0
    p_hash_table->p_lookup_table[hash_value] =
140
0
        aom_malloc(sizeof(p_hash_table->p_lookup_table[0][0]));
141
0
    if (p_hash_table->p_lookup_table[hash_value] == NULL) {
142
0
      return false;
143
0
    }
144
0
    if (aom_vector_setup(p_hash_table->p_lookup_table[hash_value], 10,
145
0
                         sizeof(curr_block_hash[0])) == VECTOR_ERROR)
146
0
      return false;
147
0
    if (aom_vector_push_back(p_hash_table->p_lookup_table[hash_value],
148
0
                             curr_block_hash) == VECTOR_ERROR)
149
0
      return false;
150
0
  } else {
151
0
    if (aom_vector_push_back(p_hash_table->p_lookup_table[hash_value],
152
0
                             curr_block_hash) == VECTOR_ERROR)
153
0
      return false;
154
0
  }
155
0
  return true;
156
0
}
157
158
int32_t av1_hash_table_count(const hash_table *p_hash_table,
159
0
                             uint32_t hash_value) {
160
0
  if (p_hash_table->p_lookup_table[hash_value] == NULL) {
161
0
    return 0;
162
0
  } else {
163
0
    return (int32_t)(p_hash_table->p_lookup_table[hash_value]->size);
164
0
  }
165
0
}
166
167
Iterator av1_hash_get_first_iterator(hash_table *p_hash_table,
168
0
                                     uint32_t hash_value) {
169
0
  assert(av1_hash_table_count(p_hash_table, hash_value) > 0);
170
0
  return aom_vector_begin(p_hash_table->p_lookup_table[hash_value]);
171
0
}
172
173
void av1_generate_block_2x2_hash_value(IntraBCHashInfo *intrabc_hash_info,
174
                                       const YV12_BUFFER_CONFIG *picture,
175
                                       uint32_t *pic_block_hash[2],
176
0
                                       int8_t *pic_block_same_info[3]) {
177
0
  const int width = 2;
178
0
  const int height = 2;
179
0
  const int x_end = picture->y_crop_width - width + 1;
180
0
  const int y_end = picture->y_crop_height - height + 1;
181
0
  CRC_CALCULATOR *calc_1 = &intrabc_hash_info->crc_calculator1;
182
0
  CRC_CALCULATOR *calc_2 = &intrabc_hash_info->crc_calculator2;
183
184
0
  const int length = width * 2;
185
0
  if (picture->flags & YV12_FLAG_HIGHBITDEPTH) {
186
0
    uint16_t p[4];
187
0
    int pos = 0;
188
0
    for (int y_pos = 0; y_pos < y_end; y_pos++) {
189
0
      for (int x_pos = 0; x_pos < x_end; x_pos++) {
190
0
        get_pixels_in_1D_short_array_by_block_2x2(
191
0
            CONVERT_TO_SHORTPTR(picture->y_buffer) + y_pos * picture->y_stride +
192
0
                x_pos,
193
0
            picture->y_stride, p);
194
0
        pic_block_same_info[0][pos] = is_block16_2x2_row_same_value(p);
195
0
        pic_block_same_info[1][pos] = is_block16_2x2_col_same_value(p);
196
197
0
        pic_block_hash[0][pos] =
198
0
            av1_get_crc_value(calc_1, (uint8_t *)p, length * sizeof(p[0]));
199
0
        pic_block_hash[1][pos] =
200
0
            av1_get_crc_value(calc_2, (uint8_t *)p, length * sizeof(p[0]));
201
0
        pos++;
202
0
      }
203
0
      pos += width - 1;
204
0
    }
205
0
  } else {
206
0
    uint8_t p[4];
207
0
    int pos = 0;
208
0
    for (int y_pos = 0; y_pos < y_end; y_pos++) {
209
0
      for (int x_pos = 0; x_pos < x_end; x_pos++) {
210
0
        get_pixels_in_1D_char_array_by_block_2x2(
211
0
            picture->y_buffer + y_pos * picture->y_stride + x_pos,
212
0
            picture->y_stride, p);
213
0
        pic_block_same_info[0][pos] = is_block_2x2_row_same_value(p);
214
0
        pic_block_same_info[1][pos] = is_block_2x2_col_same_value(p);
215
216
0
        pic_block_hash[0][pos] =
217
0
            av1_get_crc_value(calc_1, p, length * sizeof(p[0]));
218
0
        pic_block_hash[1][pos] =
219
0
            av1_get_crc_value(calc_2, p, length * sizeof(p[0]));
220
0
        pos++;
221
0
      }
222
0
      pos += width - 1;
223
0
    }
224
0
  }
225
0
}
226
227
void av1_generate_block_hash_value(IntraBCHashInfo *intrabc_hash_info,
228
                                   const YV12_BUFFER_CONFIG *picture,
229
                                   int block_size,
230
                                   uint32_t *src_pic_block_hash[2],
231
                                   uint32_t *dst_pic_block_hash[2],
232
                                   int8_t *src_pic_block_same_info[3],
233
0
                                   int8_t *dst_pic_block_same_info[3]) {
234
0
  CRC_CALCULATOR *calc_1 = &intrabc_hash_info->crc_calculator1;
235
0
  CRC_CALCULATOR *calc_2 = &intrabc_hash_info->crc_calculator2;
236
237
0
  const int pic_width = picture->y_crop_width;
238
0
  const int x_end = picture->y_crop_width - block_size + 1;
239
0
  const int y_end = picture->y_crop_height - block_size + 1;
240
241
0
  const int src_size = block_size >> 1;
242
0
  const int quad_size = block_size >> 2;
243
244
0
  uint32_t p[4];
245
0
  const int length = sizeof(p);
246
247
0
  int pos = 0;
248
0
  for (int y_pos = 0; y_pos < y_end; y_pos++) {
249
0
    for (int x_pos = 0; x_pos < x_end; x_pos++) {
250
0
      p[0] = src_pic_block_hash[0][pos];
251
0
      p[1] = src_pic_block_hash[0][pos + src_size];
252
0
      p[2] = src_pic_block_hash[0][pos + src_size * pic_width];
253
0
      p[3] = src_pic_block_hash[0][pos + src_size * pic_width + src_size];
254
0
      dst_pic_block_hash[0][pos] =
255
0
          av1_get_crc_value(calc_1, (uint8_t *)p, length);
256
257
0
      p[0] = src_pic_block_hash[1][pos];
258
0
      p[1] = src_pic_block_hash[1][pos + src_size];
259
0
      p[2] = src_pic_block_hash[1][pos + src_size * pic_width];
260
0
      p[3] = src_pic_block_hash[1][pos + src_size * pic_width + src_size];
261
0
      dst_pic_block_hash[1][pos] =
262
0
          av1_get_crc_value(calc_2, (uint8_t *)p, length);
263
264
0
      dst_pic_block_same_info[0][pos] =
265
0
          src_pic_block_same_info[0][pos] &&
266
0
          src_pic_block_same_info[0][pos + quad_size] &&
267
0
          src_pic_block_same_info[0][pos + src_size] &&
268
0
          src_pic_block_same_info[0][pos + src_size * pic_width] &&
269
0
          src_pic_block_same_info[0][pos + src_size * pic_width + quad_size] &&
270
0
          src_pic_block_same_info[0][pos + src_size * pic_width + src_size];
271
272
0
      dst_pic_block_same_info[1][pos] =
273
0
          src_pic_block_same_info[1][pos] &&
274
0
          src_pic_block_same_info[1][pos + src_size] &&
275
0
          src_pic_block_same_info[1][pos + quad_size * pic_width] &&
276
0
          src_pic_block_same_info[1][pos + quad_size * pic_width + src_size] &&
277
0
          src_pic_block_same_info[1][pos + src_size * pic_width] &&
278
0
          src_pic_block_same_info[1][pos + src_size * pic_width + src_size];
279
0
      pos++;
280
0
    }
281
0
    pos += block_size - 1;
282
0
  }
283
284
0
  if (block_size >= 4) {
285
0
    const int size_minus_1 = block_size - 1;
286
0
    pos = 0;
287
0
    for (int y_pos = 0; y_pos < y_end; y_pos++) {
288
0
      for (int x_pos = 0; x_pos < x_end; x_pos++) {
289
0
        dst_pic_block_same_info[2][pos] =
290
0
            (!dst_pic_block_same_info[0][pos] &&
291
0
             !dst_pic_block_same_info[1][pos]) ||
292
0
            (((x_pos & size_minus_1) == 0) && ((y_pos & size_minus_1) == 0));
293
0
        pos++;
294
0
      }
295
0
      pos += block_size - 1;
296
0
    }
297
0
  }
298
0
}
299
300
bool av1_add_to_hash_map_by_row_with_precal_data(hash_table *p_hash_table,
301
                                                 uint32_t *pic_hash[2],
302
                                                 int8_t *pic_is_same,
303
                                                 int pic_width, int pic_height,
304
0
                                                 int block_size) {
305
0
  const int x_end = pic_width - block_size + 1;
306
0
  const int y_end = pic_height - block_size + 1;
307
308
0
  const int8_t *src_is_added = pic_is_same;
309
0
  const uint32_t *src_hash[2] = { pic_hash[0], pic_hash[1] };
310
311
0
  int add_value = hash_block_size_to_index(block_size);
312
0
  assert(add_value >= 0);
313
0
  add_value <<= kSrcBits;
314
0
  const int crc_mask = (1 << kSrcBits) - 1;
315
316
0
  for (int x_pos = 0; x_pos < x_end; x_pos++) {
317
0
    for (int y_pos = 0; y_pos < y_end; y_pos++) {
318
0
      const int pos = y_pos * pic_width + x_pos;
319
      // valid data
320
0
      if (src_is_added[pos]) {
321
0
        block_hash curr_block_hash;
322
0
        curr_block_hash.x = x_pos;
323
0
        curr_block_hash.y = y_pos;
324
325
0
        const uint32_t hash_value1 = (src_hash[0][pos] & crc_mask) + add_value;
326
0
        curr_block_hash.hash_value2 = src_hash[1][pos];
327
328
0
        if (!hash_table_add_to_table(p_hash_table, hash_value1,
329
0
                                     &curr_block_hash)) {
330
0
          return false;
331
0
        }
332
0
      }
333
0
    }
334
0
  }
335
0
  return true;
336
0
}
337
338
int av1_hash_is_horizontal_perfect(const YV12_BUFFER_CONFIG *picture,
339
0
                                   int block_size, int x_start, int y_start) {
340
0
  const int stride = picture->y_stride;
341
0
  const uint8_t *p = picture->y_buffer + y_start * stride + x_start;
342
343
0
  if (picture->flags & YV12_FLAG_HIGHBITDEPTH) {
344
0
    const uint16_t *p16 = CONVERT_TO_SHORTPTR(p);
345
0
    for (int i = 0; i < block_size; i++) {
346
0
      for (int j = 1; j < block_size; j++) {
347
0
        if (p16[j] != p16[0]) {
348
0
          return 0;
349
0
        }
350
0
      }
351
0
      p16 += stride;
352
0
    }
353
0
  } else {
354
0
    for (int i = 0; i < block_size; i++) {
355
0
      for (int j = 1; j < block_size; j++) {
356
0
        if (p[j] != p[0]) {
357
0
          return 0;
358
0
        }
359
0
      }
360
0
      p += stride;
361
0
    }
362
0
  }
363
364
0
  return 1;
365
0
}
366
367
int av1_hash_is_vertical_perfect(const YV12_BUFFER_CONFIG *picture,
368
0
                                 int block_size, int x_start, int y_start) {
369
0
  const int stride = picture->y_stride;
370
0
  const uint8_t *p = picture->y_buffer + y_start * stride + x_start;
371
372
0
  if (picture->flags & YV12_FLAG_HIGHBITDEPTH) {
373
0
    const uint16_t *p16 = CONVERT_TO_SHORTPTR(p);
374
0
    for (int i = 0; i < block_size; i++) {
375
0
      for (int j = 1; j < block_size; j++) {
376
0
        if (p16[j * stride + i] != p16[i]) {
377
0
          return 0;
378
0
        }
379
0
      }
380
0
    }
381
0
  } else {
382
0
    for (int i = 0; i < block_size; i++) {
383
0
      for (int j = 1; j < block_size; j++) {
384
0
        if (p[j * stride + i] != p[i]) {
385
0
          return 0;
386
0
        }
387
0
      }
388
0
    }
389
0
  }
390
0
  return 1;
391
0
}
392
393
void av1_get_block_hash_value(IntraBCHashInfo *intrabc_hash_info,
394
                              const uint8_t *y_src, int stride, int block_size,
395
                              uint32_t *hash_value1, uint32_t *hash_value2,
396
0
                              int use_highbitdepth) {
397
0
  int add_value = hash_block_size_to_index(block_size);
398
0
  assert(add_value >= 0);
399
0
  add_value <<= kSrcBits;
400
0
  const int crc_mask = (1 << kSrcBits) - 1;
401
402
0
  CRC_CALCULATOR *calc_1 = &intrabc_hash_info->crc_calculator1;
403
0
  CRC_CALCULATOR *calc_2 = &intrabc_hash_info->crc_calculator2;
404
0
  uint32_t **buf_1 = intrabc_hash_info->hash_value_buffer[0];
405
0
  uint32_t **buf_2 = intrabc_hash_info->hash_value_buffer[1];
406
407
  // 2x2 subblock hash values in current CU
408
0
  int sub_block_in_width = (block_size >> 1);
409
0
  if (use_highbitdepth) {
410
0
    uint16_t pixel_to_hash[4];
411
0
    uint16_t *y16_src = CONVERT_TO_SHORTPTR(y_src);
412
0
    for (int y_pos = 0; y_pos < block_size; y_pos += 2) {
413
0
      for (int x_pos = 0; x_pos < block_size; x_pos += 2) {
414
0
        int pos = (y_pos >> 1) * sub_block_in_width + (x_pos >> 1);
415
0
        get_pixels_in_1D_short_array_by_block_2x2(
416
0
            y16_src + y_pos * stride + x_pos, stride, pixel_to_hash);
417
0
        assert(pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
418
0
        buf_1[0][pos] = av1_get_crc_value(calc_1, (uint8_t *)pixel_to_hash,
419
0
                                          sizeof(pixel_to_hash));
420
0
        buf_2[0][pos] = av1_get_crc_value(calc_2, (uint8_t *)pixel_to_hash,
421
0
                                          sizeof(pixel_to_hash));
422
0
      }
423
0
    }
424
0
  } else {
425
0
    uint8_t pixel_to_hash[4];
426
0
    for (int y_pos = 0; y_pos < block_size; y_pos += 2) {
427
0
      for (int x_pos = 0; x_pos < block_size; x_pos += 2) {
428
0
        int pos = (y_pos >> 1) * sub_block_in_width + (x_pos >> 1);
429
0
        get_pixels_in_1D_char_array_by_block_2x2(y_src + y_pos * stride + x_pos,
430
0
                                                 stride, pixel_to_hash);
431
0
        assert(pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
432
0
        buf_1[0][pos] =
433
0
            av1_get_crc_value(calc_1, pixel_to_hash, sizeof(pixel_to_hash));
434
0
        buf_2[0][pos] =
435
0
            av1_get_crc_value(calc_2, pixel_to_hash, sizeof(pixel_to_hash));
436
0
      }
437
0
    }
438
0
  }
439
440
0
  int src_sub_block_in_width = sub_block_in_width;
441
0
  sub_block_in_width >>= 1;
442
443
0
  int src_idx = 1;
444
0
  int dst_idx = 0;
445
446
  // 4x4 subblock hash values to current block hash values
447
0
  uint32_t to_hash[4];
448
0
  for (int sub_width = 4; sub_width <= block_size; sub_width *= 2) {
449
0
    src_idx = 1 - src_idx;
450
0
    dst_idx = 1 - dst_idx;
451
452
0
    int dst_pos = 0;
453
0
    for (int y_pos = 0; y_pos < sub_block_in_width; y_pos++) {
454
0
      for (int x_pos = 0; x_pos < sub_block_in_width; x_pos++) {
455
0
        int srcPos = (y_pos << 1) * src_sub_block_in_width + (x_pos << 1);
456
457
0
        assert(srcPos + 1 < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
458
0
        assert(srcPos + src_sub_block_in_width + 1 <
459
0
               AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
460
0
        assert(dst_pos < AOM_BUFFER_SIZE_FOR_BLOCK_HASH);
461
0
        to_hash[0] = buf_1[src_idx][srcPos];
462
0
        to_hash[1] = buf_1[src_idx][srcPos + 1];
463
0
        to_hash[2] = buf_1[src_idx][srcPos + src_sub_block_in_width];
464
0
        to_hash[3] = buf_1[src_idx][srcPos + src_sub_block_in_width + 1];
465
466
0
        buf_1[dst_idx][dst_pos] =
467
0
            av1_get_crc_value(calc_1, (uint8_t *)to_hash, sizeof(to_hash));
468
469
0
        to_hash[0] = buf_2[src_idx][srcPos];
470
0
        to_hash[1] = buf_2[src_idx][srcPos + 1];
471
0
        to_hash[2] = buf_2[src_idx][srcPos + src_sub_block_in_width];
472
0
        to_hash[3] = buf_2[src_idx][srcPos + src_sub_block_in_width + 1];
473
0
        buf_2[dst_idx][dst_pos] =
474
0
            av1_get_crc_value(calc_2, (uint8_t *)to_hash, sizeof(to_hash));
475
0
        dst_pos++;
476
0
      }
477
0
    }
478
479
0
    src_sub_block_in_width = sub_block_in_width;
480
0
    sub_block_in_width >>= 1;
481
0
  }
482
483
0
  *hash_value1 = (buf_1[dst_idx][0] & crc_mask) + add_value;
484
0
  *hash_value2 = buf_2[dst_idx][0];
485
0
}