Coverage Report

Created: 2026-10-28 07:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/aom/av1/encoder/allintra_vis.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2021, 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
14
#include "config/aom_config.h"
15
16
#include "aom_util/aom_pthread.h"
17
18
#if CONFIG_TFLITE
19
#include "tensorflow/lite/c/c_api.h"
20
#include "av1/encoder/deltaq4_model.c"
21
#endif
22
23
#include "av1/common/common_data.h"
24
#include "av1/common/enums.h"
25
#include "av1/common/idct.h"
26
#include "av1/common/reconinter.h"
27
#include "av1/encoder/allintra_vis.h"
28
#include "av1/encoder/aq_variance.h"
29
#include "av1/encoder/encoder.h"
30
#include "av1/encoder/ethread.h"
31
#include "av1/encoder/hybrid_fwd_txfm.h"
32
#include "av1/encoder/model_rd.h"
33
#include "av1/encoder/rdopt_utils.h"
34
35
0
#define MB_WIENER_PRED_BLOCK_SIZE BLOCK_128X128
36
0
#define MB_WIENER_PRED_BUF_STRIDE 128
37
38
// Maximum delta-q range allowed for Variance Boost after scaling
39
#define VAR_BOOST_MAX_DELTAQ_RANGE 80
40
// Maximum quantization step boost allowed for Variance Boost
41
0
#define VAR_BOOST_MAX_BOOST 8.0
42
43
0
void av1_alloc_mb_wiener_var_pred_buf(AV1_COMMON *cm, ThreadData *td) {
44
0
  const int is_high_bitdepth = is_cur_buf_hbd(&td->mb.e_mbd);
45
0
  assert(MB_WIENER_PRED_BLOCK_SIZE < BLOCK_SIZES_ALL);
46
0
  const int buf_width = block_size_wide[MB_WIENER_PRED_BLOCK_SIZE];
47
0
  const int buf_height = block_size_high[MB_WIENER_PRED_BLOCK_SIZE];
48
0
  assert(buf_width == MB_WIENER_PRED_BUF_STRIDE);
49
0
  const size_t buf_size =
50
0
      (buf_width * buf_height * sizeof(*td->wiener_tmp_pred_buf))
51
0
      << is_high_bitdepth;
52
0
  CHECK_MEM_ERROR(cm, td->wiener_tmp_pred_buf, aom_memalign(32, buf_size));
53
0
}
54
55
0
void av1_dealloc_mb_wiener_var_pred_buf(ThreadData *td) {
56
0
  aom_free(td->wiener_tmp_pred_buf);
57
0
  td->wiener_tmp_pred_buf = NULL;
58
0
}
59
60
0
void av1_init_mb_wiener_var_buffer(AV1_COMP *cpi) {
61
0
  AV1_COMMON *cm = &cpi->common;
62
0
  const int current_size = cpi->frame_info.mi_rows * cpi->frame_info.mi_cols;
63
64
  // This block size is also used to determine number of workers in
65
  // multi-threading. If it is changed, one needs to change it accordingly in
66
  // "compute_num_ai_workers()".
67
0
  cpi->weber_bsize = BLOCK_8X8;
68
69
0
  if (cpi->mb_weber_stats && cpi->mb_weber_stats_alloc_size < current_size) {
70
0
    aom_free(cpi->mb_weber_stats);
71
0
    cpi->mb_weber_stats = NULL;
72
0
    aom_free(cpi->prep_rate_estimates);
73
0
    cpi->prep_rate_estimates = NULL;
74
0
    aom_free(cpi->ext_rate_distribution);
75
0
    cpi->ext_rate_distribution = NULL;
76
0
    cpi->mb_weber_stats_alloc_size = 0;
77
0
  }
78
79
0
  if (!cpi->mb_weber_stats) {
80
0
    CHECK_MEM_ERROR(cm, cpi->mb_weber_stats,
81
0
                    aom_calloc(current_size, sizeof(*cpi->mb_weber_stats)));
82
0
    cpi->mb_weber_stats_alloc_size = current_size;
83
0
  }
84
85
0
  if (cpi->oxcf.enable_rate_guide_deltaq) {
86
0
    if (!cpi->prep_rate_estimates) {
87
0
      CHECK_MEM_ERROR(cm, cpi->prep_rate_estimates,
88
0
                      aom_calloc(cpi->mb_weber_stats_alloc_size,
89
0
                                 sizeof(*cpi->prep_rate_estimates)));
90
0
    }
91
92
0
    if (!cpi->ext_rate_distribution) {
93
0
      CHECK_MEM_ERROR(cm, cpi->ext_rate_distribution,
94
0
                      aom_calloc(cpi->mb_weber_stats_alloc_size,
95
0
                                 sizeof(*cpi->ext_rate_distribution)));
96
0
    }
97
0
  }
98
0
}
99
100
static int64_t get_satd(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row,
101
0
                        int mi_col) {
102
0
  AV1_COMMON *const cm = &cpi->common;
103
0
  const int mi_wide = mi_size_wide[bsize];
104
0
  const int mi_high = mi_size_high[bsize];
105
106
0
  const int mi_step = mi_size_wide[cpi->weber_bsize];
107
0
  int mb_stride = cpi->frame_info.mi_cols;
108
0
  int mb_count = 0;
109
0
  int64_t satd = 0;
110
111
0
  for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
112
0
    for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
113
0
      if (row < 0 || col < 0 || row >= cm->mi_params.mi_rows ||
114
0
          col >= cm->mi_params.mi_cols)
115
0
        continue;
116
117
0
      satd += cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)]
118
0
                  .satd;
119
0
      ++mb_count;
120
0
    }
121
0
  }
122
123
0
  if (mb_count) satd = satd / mb_count;
124
0
  satd = AOMMAX(1, satd);
125
126
0
  return satd;
127
0
}
128
129
static int64_t get_sse(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row,
130
0
                       int mi_col) {
131
0
  AV1_COMMON *const cm = &cpi->common;
132
0
  const int mi_wide = mi_size_wide[bsize];
133
0
  const int mi_high = mi_size_high[bsize];
134
135
0
  const int mi_step = mi_size_wide[cpi->weber_bsize];
136
0
  int mb_stride = cpi->frame_info.mi_cols;
137
0
  int mb_count = 0;
138
0
  int64_t distortion = 0;
139
140
0
  for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
141
0
    for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
142
0
      if (row < 0 || col < 0 || row >= cm->mi_params.mi_rows ||
143
0
          col >= cm->mi_params.mi_cols)
144
0
        continue;
145
146
0
      distortion +=
147
0
          cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)]
148
0
              .distortion;
149
0
      ++mb_count;
150
0
    }
151
0
  }
152
153
0
  if (mb_count) distortion = distortion / mb_count;
154
0
  distortion = AOMMAX(1, distortion);
155
156
0
  return distortion;
157
0
}
158
159
static double get_max_scale(const AV1_COMP *const cpi, BLOCK_SIZE bsize,
160
0
                            int mi_row, int mi_col) {
161
0
  const AV1_COMMON *const cm = &cpi->common;
162
0
  const int mi_wide = mi_size_wide[bsize];
163
0
  const int mi_high = mi_size_high[bsize];
164
0
  const int mi_step = mi_size_wide[cpi->weber_bsize];
165
0
  int mb_stride = cpi->frame_info.mi_cols;
166
0
  double min_max_scale = 10.0;
167
168
0
  for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
169
0
    for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
170
0
      if (row < 0 || col < 0 || row >= cm->mi_params.mi_rows ||
171
0
          col >= cm->mi_params.mi_cols)
172
0
        continue;
173
0
      const WeberStats *weber_stats =
174
0
          &cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)];
175
0
      if (weber_stats->max_scale < 1.0) continue;
176
0
      if (weber_stats->max_scale < min_max_scale)
177
0
        min_max_scale = weber_stats->max_scale;
178
0
    }
179
0
  }
180
0
  return min_max_scale;
181
0
}
182
183
static int get_window_wiener_var(const AV1_COMP *const cpi, BLOCK_SIZE bsize,
184
0
                                 int mi_row, int mi_col) {
185
0
  const AV1_COMMON *const cm = &cpi->common;
186
0
  const int mi_wide = mi_size_wide[bsize];
187
0
  const int mi_high = mi_size_high[bsize];
188
189
0
  const int mi_step = mi_size_wide[cpi->weber_bsize];
190
0
  int sb_wiener_var = 0;
191
0
  int mb_stride = cpi->frame_info.mi_cols;
192
0
  int mb_count = 0;
193
0
  double base_num = 1;
194
0
  double base_den = 1;
195
0
  double base_reg = 1;
196
197
0
  for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
198
0
    for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
199
0
      if (row < 0 || col < 0 || row >= cm->mi_params.mi_rows ||
200
0
          col >= cm->mi_params.mi_cols)
201
0
        continue;
202
203
0
      const WeberStats *weber_stats =
204
0
          &cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)];
205
206
0
      base_num += ((double)weber_stats->distortion) *
207
0
                  sqrt((double)weber_stats->src_variance) *
208
0
                  weber_stats->rec_pix_max;
209
210
0
      base_den += fabs(
211
0
          weber_stats->rec_pix_max * sqrt((double)weber_stats->src_variance) -
212
0
          weber_stats->src_pix_max * sqrt((double)weber_stats->rec_variance));
213
214
0
      base_reg += sqrt((double)weber_stats->distortion) *
215
0
                  sqrt((double)weber_stats->src_pix_max) * 0.1;
216
0
      ++mb_count;
217
0
    }
218
0
  }
219
220
0
  if (mb_count == 0) return 1;
221
0
  sb_wiener_var =
222
0
      (int)(((base_num + base_reg) / (base_den + base_reg)) / mb_count);
223
0
  sb_wiener_var = AOMMAX(1, sb_wiener_var);
224
225
0
  return (int)sb_wiener_var;
226
0
}
227
228
static int get_var_perceptual_ai(const AV1_COMP *const cpi, BLOCK_SIZE bsize,
229
0
                                 int mi_row, int mi_col) {
230
0
  const AV1_COMMON *const cm = &cpi->common;
231
0
  const int mi_wide = mi_size_wide[bsize];
232
0
  const int mi_high = mi_size_high[bsize];
233
234
0
  int sb_wiener_var = get_window_wiener_var(cpi, bsize, mi_row, mi_col);
235
236
0
  if (mi_row >= (mi_high / 2)) {
237
0
    sb_wiener_var =
238
0
        AOMMIN(sb_wiener_var,
239
0
               get_window_wiener_var(cpi, bsize, mi_row - mi_high / 2, mi_col));
240
0
  }
241
0
  if (mi_row <= (cm->mi_params.mi_rows - mi_high - (mi_high / 2))) {
242
0
    sb_wiener_var =
243
0
        AOMMIN(sb_wiener_var,
244
0
               get_window_wiener_var(cpi, bsize, mi_row + mi_high / 2, mi_col));
245
0
  }
246
0
  if (mi_col >= (mi_wide / 2)) {
247
0
    sb_wiener_var =
248
0
        AOMMIN(sb_wiener_var,
249
0
               get_window_wiener_var(cpi, bsize, mi_row, mi_col - mi_wide / 2));
250
0
  }
251
0
  if (mi_col <= (cm->mi_params.mi_cols - mi_wide - (mi_wide / 2))) {
252
0
    sb_wiener_var =
253
0
        AOMMIN(sb_wiener_var,
254
0
               get_window_wiener_var(cpi, bsize, mi_row, mi_col + mi_wide / 2));
255
0
  }
256
257
0
  return sb_wiener_var;
258
0
}
259
260
0
static int rate_estimator(const tran_low_t *qcoeff, int eob, TX_SIZE tx_size) {
261
0
  const SCAN_ORDER *const scan_order = &av1_scan_orders[tx_size][DCT_DCT];
262
263
0
  assert((1 << num_pels_log2_lookup[txsize_to_bsize[tx_size]]) >= eob);
264
0
  int rate_cost = 1;
265
266
0
  for (int idx = 0; idx < eob; ++idx) {
267
0
    int abs_level = abs(qcoeff[scan_order->scan[idx]]);
268
0
    rate_cost += (int)(log1p(abs_level) / log(2.0)) + 1 + (abs_level > 0);
269
0
  }
270
271
0
  return (rate_cost << AV1_PROB_COST_SHIFT);
272
0
}
273
274
void av1_calc_mb_wiener_var_row(AV1_COMP *const cpi, MACROBLOCK *x,
275
                                MACROBLOCKD *xd, const int mi_row,
276
                                int16_t *src_diff, tran_low_t *coeff,
277
                                tran_low_t *qcoeff, tran_low_t *dqcoeff,
278
                                double *sum_rec_distortion,
279
0
                                double *sum_est_rate, uint8_t *pred_buffer) {
280
0
  AV1_COMMON *const cm = &cpi->common;
281
0
  uint8_t *buffer = cpi->source->y_buffer;
282
0
  int buf_stride = cpi->source->y_stride;
283
0
  MB_MODE_INFO mbmi;
284
0
  memset(&mbmi, 0, sizeof(mbmi));
285
0
  MB_MODE_INFO *mbmi_ptr = &mbmi;
286
0
  xd->mi = &mbmi_ptr;
287
0
  const BLOCK_SIZE bsize = cpi->weber_bsize;
288
0
  const TX_SIZE tx_size = max_txsize_lookup[bsize];
289
0
  const int block_size = tx_size_wide[tx_size];
290
0
  const int coeff_count = block_size * block_size;
291
0
  const int mb_step = mi_size_wide[bsize];
292
0
  const BitDepthInfo bd_info = get_bit_depth_info(xd);
293
0
  const MultiThreadInfo *const mt_info = &cpi->mt_info;
294
0
  const AV1EncAllIntraMultiThreadInfo *const intra_mt = &mt_info->intra_mt;
295
0
  AV1EncRowMultiThreadSync *const intra_row_mt_sync =
296
0
      &cpi->ppi->intra_row_mt_sync;
297
0
  const int mi_cols = cm->mi_params.mi_cols;
298
0
  const int mt_thread_id = mi_row / mb_step;
299
  // TODO(chengchen): test different unit step size
300
0
  const int mt_unit_step = mi_size_wide[MB_WIENER_MT_UNIT_SIZE];
301
0
  const int mt_unit_cols = (mi_cols + (mt_unit_step >> 1)) / mt_unit_step;
302
0
  int mt_unit_col = 0;
303
0
  const int is_high_bitdepth = is_cur_buf_hbd(xd);
304
305
0
  uint8_t *dst_buffer = pred_buffer;
306
0
  const int dst_buffer_stride = MB_WIENER_PRED_BUF_STRIDE;
307
308
0
  if (is_high_bitdepth) {
309
0
    uint16_t *pred_buffer_16 = (uint16_t *)pred_buffer;
310
0
    dst_buffer = CONVERT_TO_BYTEPTR(pred_buffer_16);
311
0
  }
312
313
0
  for (int mi_col = 0; mi_col < mi_cols; mi_col += mb_step) {
314
0
    if (mi_col % mt_unit_step == 0) {
315
0
      intra_mt->intra_sync_read_ptr(intra_row_mt_sync, mt_thread_id,
316
0
                                    mt_unit_col);
317
0
#if CONFIG_MULTITHREAD
318
0
      const int num_workers =
319
0
          AOMMIN(mt_info->num_mod_workers[MOD_AI], mt_info->num_workers);
320
0
      if (num_workers > 1) {
321
0
        const AV1EncRowMultiThreadInfo *const enc_row_mt = &mt_info->enc_row_mt;
322
0
        pthread_mutex_lock(enc_row_mt->mutex_);
323
0
        const bool exit = enc_row_mt->mb_wiener_mt_exit;
324
0
        pthread_mutex_unlock(enc_row_mt->mutex_);
325
        // Stop further processing in case any worker has encountered an error.
326
0
        if (exit) break;
327
0
      }
328
0
#endif
329
0
    }
330
331
0
    PREDICTION_MODE best_mode = DC_PRED;
332
0
    int best_intra_cost = INT_MAX;
333
0
    const int mi_width = mi_size_wide[bsize];
334
0
    const int mi_height = mi_size_high[bsize];
335
0
    set_mode_info_offsets(&cpi->common.mi_params, &cpi->mbmi_ext_info, x, xd,
336
0
                          mi_row, mi_col);
337
0
    set_mi_row_col(xd, &xd->tile, mi_row, mi_height, mi_col, mi_width,
338
0
                   AOMMIN(mi_row + mi_height, cm->mi_params.mi_rows),
339
0
                   AOMMIN(mi_col + mi_width, cm->mi_params.mi_cols));
340
0
    set_plane_n4(xd, mi_size_wide[bsize], mi_size_high[bsize],
341
0
                 av1_num_planes(cm));
342
0
    xd->mi[0]->bsize = bsize;
343
0
    xd->mi[0]->motion_mode = SIMPLE_TRANSLATION;
344
    // Set above and left mbmi to NULL as they are not available in the
345
    // preprocessing stage.
346
    // They are used to detemine intra edge filter types in intra prediction.
347
0
    if (xd->up_available) {
348
0
      xd->above_mbmi = NULL;
349
0
    }
350
0
    if (xd->left_available) {
351
0
      xd->left_mbmi = NULL;
352
0
    }
353
0
    uint8_t *mb_buffer =
354
0
        buffer + mi_row * MI_SIZE * buf_stride + mi_col * MI_SIZE;
355
0
    for (PREDICTION_MODE mode = INTRA_MODE_START; mode < INTRA_MODE_END;
356
0
         ++mode) {
357
      // TODO(chengchen): Here we use src instead of reconstructed frame as
358
      // the intra predictor to make single and multithread version match.
359
      // Ideally we want to use the reconstructed.
360
0
      av1_predict_intra_block(
361
0
          xd, cm->seq_params->sb_size, cm->seq_params->enable_intra_edge_filter,
362
0
          block_size, block_size, tx_size, mode, 0, 0, FILTER_INTRA_MODES,
363
0
          mb_buffer, buf_stride, dst_buffer, dst_buffer_stride, 0, 0, 0);
364
0
      av1_subtract_block(x, block_size, block_size, src_diff, block_size,
365
0
                         mb_buffer, buf_stride, dst_buffer, dst_buffer_stride,
366
0
                         PLANE_TYPE_Y, bsize, 0, 0, DCT_DCT,
367
0
                         cpi->do_border_pad);
368
0
      av1_quick_txfm(0, tx_size, bd_info, src_diff, block_size, coeff);
369
0
      int intra_cost = aom_satd(coeff, coeff_count);
370
0
      if (intra_cost < best_intra_cost) {
371
0
        best_intra_cost = intra_cost;
372
0
        best_mode = mode;
373
0
      }
374
0
    }
375
376
0
    av1_predict_intra_block(
377
0
        xd, cm->seq_params->sb_size, cm->seq_params->enable_intra_edge_filter,
378
0
        block_size, block_size, tx_size, best_mode, 0, 0, FILTER_INTRA_MODES,
379
0
        mb_buffer, buf_stride, dst_buffer, dst_buffer_stride, 0, 0, 0);
380
0
    av1_subtract_block(x, block_size, block_size, src_diff, block_size,
381
0
                       mb_buffer, buf_stride, dst_buffer, dst_buffer_stride,
382
0
                       PLANE_TYPE_Y, bsize, 0, 0, DCT_DCT, cpi->do_border_pad);
383
0
    av1_quick_txfm(0, tx_size, bd_info, src_diff, block_size, coeff);
384
385
0
    const struct macroblock_plane *const p = &x->plane[0];
386
0
    uint16_t eob;
387
0
    const SCAN_ORDER *const scan_order = &av1_scan_orders[tx_size][DCT_DCT];
388
0
    QUANT_PARAM quant_param;
389
0
    int pix_num = 1 << num_pels_log2_lookup[txsize_to_bsize[tx_size]];
390
0
    av1_setup_quant(tx_size, 0, AV1_XFORM_QUANT_FP, 0, &quant_param);
391
0
#if CONFIG_AV1_HIGHBITDEPTH
392
0
    if (is_cur_buf_hbd(xd)) {
393
0
      av1_highbd_quantize_fp_facade(coeff, pix_num, p, qcoeff, dqcoeff, &eob,
394
0
                                    scan_order, &quant_param);
395
0
    } else {
396
0
      av1_quantize_fp_facade(coeff, pix_num, p, qcoeff, dqcoeff, &eob,
397
0
                             scan_order, &quant_param);
398
0
    }
399
#else
400
    av1_quantize_fp_facade(coeff, pix_num, p, qcoeff, dqcoeff, &eob, scan_order,
401
                           &quant_param);
402
#endif  // CONFIG_AV1_HIGHBITDEPTH
403
404
0
    if (cpi->oxcf.enable_rate_guide_deltaq) {
405
0
      const int rate_cost = rate_estimator(qcoeff, eob, tx_size);
406
0
      cpi->prep_rate_estimates[(mi_row / mb_step) * cpi->frame_info.mi_cols +
407
0
                               (mi_col / mb_step)] = rate_cost;
408
0
    }
409
410
0
    av1_inverse_transform_block(xd, dqcoeff, 0, DCT_DCT, tx_size, dst_buffer,
411
0
                                dst_buffer_stride, eob, 0);
412
0
    WeberStats *weber_stats =
413
0
        &cpi->mb_weber_stats[(mi_row / mb_step) * cpi->frame_info.mi_cols +
414
0
                             (mi_col / mb_step)];
415
416
0
    weber_stats->rec_pix_max = 1;
417
0
    weber_stats->rec_variance = 0;
418
0
    weber_stats->src_pix_max = 1;
419
0
    weber_stats->src_variance = 0;
420
0
    weber_stats->distortion = 0;
421
422
0
    int64_t src_mean = 0;
423
0
    int64_t rec_mean = 0;
424
0
    int64_t dist_mean = 0;
425
426
0
    for (int pix_row = 0; pix_row < block_size; ++pix_row) {
427
0
      for (int pix_col = 0; pix_col < block_size; ++pix_col) {
428
0
        int src_pix, rec_pix;
429
0
#if CONFIG_AV1_HIGHBITDEPTH
430
0
        if (is_cur_buf_hbd(xd)) {
431
0
          uint16_t *src = CONVERT_TO_SHORTPTR(mb_buffer);
432
0
          uint16_t *rec = CONVERT_TO_SHORTPTR(dst_buffer);
433
0
          src_pix = src[pix_row * buf_stride + pix_col];
434
0
          rec_pix = rec[pix_row * dst_buffer_stride + pix_col];
435
0
        } else {
436
0
          src_pix = mb_buffer[pix_row * buf_stride + pix_col];
437
0
          rec_pix = dst_buffer[pix_row * dst_buffer_stride + pix_col];
438
0
        }
439
#else
440
        src_pix = mb_buffer[pix_row * buf_stride + pix_col];
441
        rec_pix = dst_buffer[pix_row * dst_buffer_stride + pix_col];
442
#endif
443
0
        src_mean += src_pix;
444
0
        rec_mean += rec_pix;
445
0
        dist_mean += src_pix - rec_pix;
446
0
        weber_stats->src_variance += src_pix * src_pix;
447
0
        weber_stats->rec_variance += rec_pix * rec_pix;
448
0
        weber_stats->src_pix_max = AOMMAX(weber_stats->src_pix_max, src_pix);
449
0
        weber_stats->rec_pix_max = AOMMAX(weber_stats->rec_pix_max, rec_pix);
450
0
        weber_stats->distortion += (src_pix - rec_pix) * (src_pix - rec_pix);
451
0
      }
452
0
    }
453
454
0
    if (cpi->oxcf.intra_mode_cfg.auto_intra_tools_off) {
455
0
      *sum_rec_distortion += weber_stats->distortion;
456
0
      int est_block_rate = 0;
457
0
      int64_t est_block_dist = 0;
458
0
      model_rd_sse_fn[MODELRD_LEGACY](cpi, x, bsize, 0, weber_stats->distortion,
459
0
                                      pix_num, &est_block_rate,
460
0
                                      &est_block_dist);
461
0
      *sum_est_rate += est_block_rate;
462
0
    }
463
464
0
    weber_stats->src_variance -= (src_mean * src_mean) / pix_num;
465
0
    weber_stats->rec_variance -= (rec_mean * rec_mean) / pix_num;
466
0
    weber_stats->distortion -= (dist_mean * dist_mean) / pix_num;
467
0
    weber_stats->satd = best_intra_cost;
468
469
0
    qcoeff[0] = 0;
470
0
    int max_scale = 0;
471
0
    for (int idx = 1; idx < coeff_count; ++idx) {
472
0
      const int abs_qcoeff = abs(qcoeff[idx]);
473
0
      max_scale = AOMMAX(max_scale, abs_qcoeff);
474
0
    }
475
0
    weber_stats->max_scale = max_scale;
476
477
0
    if ((mi_col + mb_step) % mt_unit_step == 0 ||
478
0
        (mi_col + mb_step) >= mi_cols) {
479
0
      intra_mt->intra_sync_write_ptr(intra_row_mt_sync, mt_thread_id,
480
0
                                     mt_unit_col, mt_unit_cols);
481
0
      ++mt_unit_col;
482
0
    }
483
0
  }
484
  // Set the pointer to null since mbmi is only allocated inside this function.
485
0
  xd->mi = NULL;
486
0
}
487
488
static void calc_mb_wiener_var(AV1_COMP *const cpi, double *sum_rec_distortion,
489
0
                               double *sum_est_rate) {
490
0
  MACROBLOCK *x = &cpi->td.mb;
491
0
  MACROBLOCKD *xd = &x->e_mbd;
492
0
  const BLOCK_SIZE bsize = cpi->weber_bsize;
493
0
  const int mb_step = mi_size_wide[bsize];
494
0
  DECLARE_ALIGNED(32, int16_t, src_diff[32 * 32]);
495
0
  DECLARE_ALIGNED(32, tran_low_t, coeff[32 * 32]);
496
0
  DECLARE_ALIGNED(32, tran_low_t, qcoeff[32 * 32]);
497
0
  DECLARE_ALIGNED(32, tran_low_t, dqcoeff[32 * 32]);
498
0
  for (int mi_row = 0; mi_row < cpi->frame_info.mi_rows; mi_row += mb_step) {
499
0
    av1_calc_mb_wiener_var_row(cpi, x, xd, mi_row, src_diff, coeff, qcoeff,
500
0
                               dqcoeff, sum_rec_distortion, sum_est_rate,
501
0
                               cpi->td.wiener_tmp_pred_buf);
502
0
  }
503
0
}
504
505
static int64_t estimate_wiener_var_norm(AV1_COMP *const cpi,
506
0
                                        const BLOCK_SIZE norm_block_size) {
507
0
  const AV1_COMMON *const cm = &cpi->common;
508
0
  int64_t norm_factor = 1;
509
0
  assert(norm_block_size >= BLOCK_16X16 && norm_block_size <= BLOCK_128X128);
510
0
  const int norm_step = mi_size_wide[norm_block_size];
511
0
  double sb_wiener_log = 0;
512
0
  double sb_count = 0;
513
0
  for (int mi_row = 0; mi_row < cm->mi_params.mi_rows; mi_row += norm_step) {
514
0
    for (int mi_col = 0; mi_col < cm->mi_params.mi_cols; mi_col += norm_step) {
515
0
      const int sb_wiener_var =
516
0
          get_var_perceptual_ai(cpi, norm_block_size, mi_row, mi_col);
517
0
      const int64_t satd = get_satd(cpi, norm_block_size, mi_row, mi_col);
518
0
      const int64_t sse = get_sse(cpi, norm_block_size, mi_row, mi_col);
519
0
      const double scaled_satd = (double)satd / sqrt((double)sse);
520
0
      sb_wiener_log += scaled_satd * log(sb_wiener_var);
521
0
      sb_count += scaled_satd;
522
0
    }
523
0
  }
524
0
  if (sb_count > 0) norm_factor = (int64_t)(exp(sb_wiener_log / sb_count));
525
0
  norm_factor = AOMMAX(1, norm_factor);
526
527
0
  return norm_factor;
528
0
}
529
530
static void automatic_intra_tools_off(AV1_COMP *cpi,
531
                                      const double sum_rec_distortion,
532
0
                                      const double sum_est_rate) {
533
0
  if (!cpi->oxcf.intra_mode_cfg.auto_intra_tools_off) return;
534
535
  // Thresholds
536
0
  const int high_quality_qindex = 128;
537
0
  const double high_quality_bpp = 2.0;
538
0
  const double high_quality_dist_per_pix = 4.0;
539
540
0
  AV1_COMMON *const cm = &cpi->common;
541
0
  const int qindex = cm->quant_params.base_qindex;
542
0
  const double dist_per_pix =
543
0
      (double)sum_rec_distortion / (cm->width * cm->height);
544
  // The estimate bpp is not accurate, an empirical constant 100 is divided.
545
0
  const double estimate_bpp = sum_est_rate / (cm->width * cm->height * 100);
546
547
0
  if (qindex < high_quality_qindex && estimate_bpp > high_quality_bpp &&
548
0
      dist_per_pix < high_quality_dist_per_pix) {
549
0
    cpi->oxcf.intra_mode_cfg.enable_smooth_intra = 0;
550
0
    cpi->oxcf.intra_mode_cfg.enable_paeth_intra = 0;
551
0
    cpi->oxcf.intra_mode_cfg.enable_cfl_intra = 0;
552
0
    cpi->oxcf.intra_mode_cfg.enable_diagonal_intra = 0;
553
0
  }
554
0
}
555
556
0
static void ext_rate_guided_quantization(AV1_COMP *cpi) {
557
  // Calculation uses 8x8.
558
0
  const int mb_step = mi_size_wide[cpi->weber_bsize];
559
  // Accumulate to 16x16, step size is in the unit of mi.
560
0
  const int block_step = 4;
561
562
0
  const char *filename = cpi->oxcf.rate_distribution_info;
563
0
  FILE *pfile = fopen(filename, "r");
564
0
  if (pfile == NULL) {
565
0
    assert(pfile != NULL);
566
0
    return;
567
0
  }
568
569
0
  double ext_rate_sum = 0.0;
570
0
  for (int row = 0; row < cpi->frame_info.mi_rows; row += block_step) {
571
0
    for (int col = 0; col < cpi->frame_info.mi_cols; col += block_step) {
572
0
      float val;
573
0
      const int fields_converted = fscanf(pfile, "%f", &val);
574
0
      if (fields_converted != 1) {
575
0
        assert(fields_converted == 1);
576
0
        fclose(pfile);
577
0
        return;
578
0
      }
579
0
      ext_rate_sum += val;
580
0
      cpi->ext_rate_distribution[(row / mb_step) * cpi->frame_info.mi_cols +
581
0
                                 (col / mb_step)] = val;
582
0
    }
583
0
  }
584
0
  fclose(pfile);
585
586
0
  int uniform_rate_sum = 0;
587
0
  for (int row = 0; row < cpi->frame_info.mi_rows; row += block_step) {
588
0
    for (int col = 0; col < cpi->frame_info.mi_cols; col += block_step) {
589
0
      int rate_sum = 0;
590
0
      for (int r = 0; r < block_step; r += mb_step) {
591
0
        for (int c = 0; c < block_step; c += mb_step) {
592
0
          const int mi_row = row + r;
593
0
          const int mi_col = col + c;
594
0
          rate_sum += cpi->prep_rate_estimates[(mi_row / mb_step) *
595
0
                                                   cpi->frame_info.mi_cols +
596
0
                                               (mi_col / mb_step)];
597
0
        }
598
0
      }
599
0
      uniform_rate_sum += rate_sum;
600
0
    }
601
0
  }
602
603
0
  const double scale = uniform_rate_sum / ext_rate_sum;
604
0
  cpi->ext_rate_scale = scale;
605
0
}
606
607
0
void av1_set_mb_wiener_variance(AV1_COMP *cpi) {
608
0
  AV1_COMMON *const cm = &cpi->common;
609
0
  const SequenceHeader *const seq_params = cm->seq_params;
610
0
  if (aom_realloc_frame_buffer(
611
0
          &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x,
612
0
          seq_params->subsampling_y, seq_params->use_highbitdepth,
613
0
          cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL,
614
0
          NULL, cpi->alloc_pyramid, 0))
615
0
    aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
616
0
                       "Failed to allocate frame buffer");
617
0
  av1_alloc_mb_wiener_var_pred_buf(&cpi->common, &cpi->td);
618
0
  cpi->norm_wiener_variance = 0;
619
620
0
  MACROBLOCK *x = &cpi->td.mb;
621
0
  MACROBLOCKD *xd = &x->e_mbd;
622
  // xd->mi needs to be setup since it is used in av1_frame_init_quantizer.
623
0
  MB_MODE_INFO mbmi;
624
0
  memset(&mbmi, 0, sizeof(mbmi));
625
0
  MB_MODE_INFO *mbmi_ptr = &mbmi;
626
0
  xd->mi = &mbmi_ptr;
627
0
  cm->quant_params.base_qindex = cpi->oxcf.rc_cfg.cq_level;
628
0
  av1_frame_init_quantizer(cpi);
629
630
0
  double sum_rec_distortion = 0.0;
631
0
  double sum_est_rate = 0.0;
632
633
0
  MultiThreadInfo *const mt_info = &cpi->mt_info;
634
0
  const int num_workers =
635
0
      AOMMIN(mt_info->num_mod_workers[MOD_AI], mt_info->num_workers);
636
0
  AV1EncAllIntraMultiThreadInfo *const intra_mt = &mt_info->intra_mt;
637
0
  intra_mt->intra_sync_read_ptr = av1_row_mt_sync_read_dummy;
638
0
  intra_mt->intra_sync_write_ptr = av1_row_mt_sync_write_dummy;
639
  // Calculate differential contrast for each block for the entire image.
640
  // TODO(chengchen): properly accumulate the distortion and rate in
641
  // av1_calc_mb_wiener_var_mt(). Until then, call calc_mb_wiener_var() if
642
  // auto_intra_tools_off is true.
643
0
  if (num_workers > 1 && !cpi->oxcf.intra_mode_cfg.auto_intra_tools_off) {
644
0
    intra_mt->intra_sync_read_ptr = av1_row_mt_sync_read;
645
0
    intra_mt->intra_sync_write_ptr = av1_row_mt_sync_write;
646
0
    av1_calc_mb_wiener_var_mt(cpi, num_workers, &sum_rec_distortion,
647
0
                              &sum_est_rate);
648
0
  } else {
649
0
    calc_mb_wiener_var(cpi, &sum_rec_distortion, &sum_est_rate);
650
0
  }
651
652
  // Determine whether to turn off several intra coding tools.
653
0
  automatic_intra_tools_off(cpi, sum_rec_distortion, sum_est_rate);
654
655
  // Read external rate distribution and use it to guide delta quantization
656
0
  if (cpi->oxcf.enable_rate_guide_deltaq) ext_rate_guided_quantization(cpi);
657
658
0
  const BLOCK_SIZE norm_block_size = cm->seq_params->sb_size;
659
0
  cpi->norm_wiener_variance = estimate_wiener_var_norm(cpi, norm_block_size);
660
0
  const int norm_step = mi_size_wide[norm_block_size];
661
662
0
  double sb_wiener_log = 0;
663
0
  double sb_count = 0;
664
0
  for (int its_cnt = 0; its_cnt < 2; ++its_cnt) {
665
0
    sb_wiener_log = 0;
666
0
    sb_count = 0;
667
0
    for (int mi_row = 0; mi_row < cm->mi_params.mi_rows; mi_row += norm_step) {
668
0
      for (int mi_col = 0; mi_col < cm->mi_params.mi_cols;
669
0
           mi_col += norm_step) {
670
0
        int sb_wiener_var =
671
0
            get_var_perceptual_ai(cpi, norm_block_size, mi_row, mi_col);
672
673
0
        double beta = (double)cpi->norm_wiener_variance / sb_wiener_var;
674
0
        double min_max_scale = AOMMAX(
675
0
            1.0, get_max_scale(cpi, cm->seq_params->sb_size, mi_row, mi_col));
676
677
0
        beta = AOMMIN(beta, 4);
678
0
        beta = AOMMAX(beta, 0.25);
679
680
0
        if (beta < 1 / min_max_scale) continue;
681
682
0
        sb_wiener_var = (int)(cpi->norm_wiener_variance / beta);
683
684
0
        int64_t satd = get_satd(cpi, norm_block_size, mi_row, mi_col);
685
0
        int64_t sse = get_sse(cpi, norm_block_size, mi_row, mi_col);
686
0
        double scaled_satd = (double)satd / sqrt((double)sse);
687
0
        sb_wiener_log += scaled_satd * log(sb_wiener_var);
688
0
        sb_count += scaled_satd;
689
0
      }
690
0
    }
691
692
0
    if (sb_count > 0)
693
0
      cpi->norm_wiener_variance = (int64_t)(exp(sb_wiener_log / sb_count));
694
0
    cpi->norm_wiener_variance = AOMMAX(1, cpi->norm_wiener_variance);
695
0
  }
696
697
  // Set the pointer to null since mbmi is only allocated inside this function.
698
0
  xd->mi = NULL;
699
0
  aom_free_frame_buffer(&cm->cur_frame->buf);
700
0
  av1_dealloc_mb_wiener_var_pred_buf(&cpi->td);
701
0
}
702
703
static int get_rate_guided_quantizer(const AV1_COMP *const cpi,
704
0
                                     BLOCK_SIZE bsize, int mi_row, int mi_col) {
705
0
  const AV1_COMMON *const cm = &cpi->common;
706
  // Calculation uses 8x8.
707
0
  const int mb_step = mi_size_wide[cpi->weber_bsize];
708
  // Accumulate to 16x16
709
0
  const int block_step = mi_size_wide[BLOCK_16X16];
710
0
  double sb_rate_hific = 0.0;
711
0
  double sb_rate_uniform = 0.0;
712
0
  for (int row = mi_row; row < mi_row + mi_size_high[bsize];
713
0
       row += block_step) {
714
0
    for (int col = mi_col; col < mi_col + mi_size_wide[bsize];
715
0
         col += block_step) {
716
0
      if (row < 0 || col < 0 || row >= cm->mi_params.mi_rows ||
717
0
          col >= cm->mi_params.mi_cols)
718
0
        continue;
719
0
      sb_rate_hific +=
720
0
          cpi->ext_rate_distribution[(row / mb_step) * cpi->frame_info.mi_cols +
721
0
                                     (col / mb_step)];
722
723
0
      for (int r = 0; r < block_step; r += mb_step) {
724
0
        for (int c = 0; c < block_step; c += mb_step) {
725
0
          const int this_row = row + r;
726
0
          const int this_col = col + c;
727
0
          if (this_row < 0 || this_col < 0 ||
728
0
              this_row >= cm->mi_params.mi_rows ||
729
0
              this_col >= cm->mi_params.mi_cols)
730
0
            continue;
731
0
          sb_rate_uniform +=
732
0
              cpi->prep_rate_estimates[(this_row / mb_step) *
733
0
                                           cpi->frame_info.mi_cols +
734
0
                                       (this_col / mb_step)];
735
0
        }
736
0
      }
737
0
    }
738
0
  }
739
0
  sb_rate_hific *= cpi->ext_rate_scale;
740
741
0
  const double weight = 1.0;
742
0
  const double rate_diff =
743
0
      weight * (sb_rate_hific - sb_rate_uniform) / sb_rate_uniform;
744
0
  double scale = pow(2, rate_diff);
745
746
0
  scale = scale * scale;
747
0
  double min_max_scale = AOMMAX(1.0, get_max_scale(cpi, bsize, mi_row, mi_col));
748
0
  scale = 1.0 / AOMMIN(1.0 / scale, min_max_scale);
749
750
0
  const int base_qindex = cm->quant_params.base_qindex;
751
0
  int offset =
752
0
      av1_get_deltaq_offset(cm->seq_params->bit_depth, base_qindex, scale);
753
0
  const DeltaQInfo *const delta_q_info = &cm->delta_q_info;
754
0
  const int max_offset = delta_q_info->delta_q_res * 10;
755
0
  offset = AOMMIN(offset, max_offset - 1);
756
0
  offset = AOMMAX(offset, -max_offset + 1);
757
0
  int qindex = cm->quant_params.base_qindex + offset;
758
0
  qindex = AOMMIN(qindex, MAXQ);
759
0
  qindex = AOMMAX(qindex, MINQ);
760
0
  if (base_qindex > MINQ) qindex = AOMMAX(qindex, MINQ + 1);
761
762
0
  return qindex;
763
0
}
764
765
int av1_get_sbq_perceptual_ai(const AV1_COMP *const cpi, BLOCK_SIZE bsize,
766
0
                              int mi_row, int mi_col) {
767
0
  if (cpi->oxcf.enable_rate_guide_deltaq) {
768
0
    return get_rate_guided_quantizer(cpi, bsize, mi_row, mi_col);
769
0
  }
770
771
0
  const AV1_COMMON *const cm = &cpi->common;
772
0
  const int base_qindex = cm->quant_params.base_qindex;
773
0
  int sb_wiener_var = get_var_perceptual_ai(cpi, bsize, mi_row, mi_col);
774
0
  int offset = 0;
775
0
  double beta = (double)cpi->norm_wiener_variance / sb_wiener_var;
776
0
  double min_max_scale = AOMMAX(1.0, get_max_scale(cpi, bsize, mi_row, mi_col));
777
0
  beta = 1.0 / AOMMIN(1.0 / beta, min_max_scale);
778
779
  // Cap beta such that the delta q value is not much far away from the base q.
780
0
  beta = AOMMIN(beta, 4);
781
0
  beta = AOMMAX(beta, 0.25);
782
0
  offset = av1_get_deltaq_offset(cm->seq_params->bit_depth, base_qindex, beta);
783
0
  const DeltaQInfo *const delta_q_info = &cm->delta_q_info;
784
0
  offset = AOMMIN(offset, delta_q_info->delta_q_res * 20 - 1);
785
0
  offset = AOMMAX(offset, -delta_q_info->delta_q_res * 20 + 1);
786
0
  int qindex = cm->quant_params.base_qindex + offset;
787
0
  qindex = AOMMIN(qindex, MAXQ);
788
0
  qindex = AOMMAX(qindex, MINQ);
789
0
  if (base_qindex > MINQ) qindex = AOMMAX(qindex, MINQ + 1);
790
791
0
  return qindex;
792
0
}
793
794
0
void av1_init_mb_ur_var_buffer(AV1_COMP *cpi) {
795
0
  AV1_COMMON *cm = &cpi->common;
796
0
  const int current_size = cpi->frame_info.mb_rows * cpi->frame_info.mb_cols;
797
798
0
  if (cpi->mb_delta_q && cpi->mb_delta_q_alloc_size < current_size) {
799
0
    aom_free(cpi->mb_delta_q);
800
0
    cpi->mb_delta_q = NULL;
801
0
    cpi->mb_delta_q_alloc_size = 0;
802
0
  }
803
804
0
  if (!cpi->mb_delta_q) {
805
0
    CHECK_MEM_ERROR(cm, cpi->mb_delta_q,
806
0
                    aom_calloc(current_size, sizeof(*cpi->mb_delta_q)));
807
0
    cpi->mb_delta_q_alloc_size = current_size;
808
0
  }
809
0
}
810
811
#if CONFIG_TFLITE
812
static int model_predict(BLOCK_SIZE block_size, int num_cols, int num_rows,
813
                         int bit_depth, uint8_t *y_buffer, int y_stride,
814
                         float *predicts0, float *predicts1) {
815
  // Create the model and interpreter options.
816
  TfLiteModel *model =
817
      TfLiteModelCreate(av1_deltaq4_model_file, av1_deltaq4_model_fsize);
818
  if (model == NULL) return 1;
819
820
  TfLiteInterpreterOptions *options = TfLiteInterpreterOptionsCreate();
821
  TfLiteInterpreterOptionsSetNumThreads(options, 2);
822
  if (options == NULL) {
823
    TfLiteModelDelete(model);
824
    return 1;
825
  }
826
827
  // Create the interpreter.
828
  TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, options);
829
  if (interpreter == NULL) {
830
    TfLiteInterpreterOptionsDelete(options);
831
    TfLiteModelDelete(model);
832
    return 1;
833
  }
834
835
  // Allocate tensors and populate the input tensor data.
836
  TfLiteInterpreterAllocateTensors(interpreter);
837
  TfLiteTensor *input_tensor = TfLiteInterpreterGetInputTensor(interpreter, 0);
838
  if (input_tensor == NULL) {
839
    TfLiteInterpreterDelete(interpreter);
840
    TfLiteInterpreterOptionsDelete(options);
841
    TfLiteModelDelete(model);
842
    return 1;
843
  }
844
845
  size_t input_size = TfLiteTensorByteSize(input_tensor);
846
  float *input_data = aom_calloc(input_size, 1);
847
  if (input_data == NULL) {
848
    TfLiteInterpreterDelete(interpreter);
849
    TfLiteInterpreterOptionsDelete(options);
850
    TfLiteModelDelete(model);
851
    return 1;
852
  }
853
854
  const int num_mi_w = mi_size_wide[block_size];
855
  const int num_mi_h = mi_size_high[block_size];
856
  for (int row = 0; row < num_rows; ++row) {
857
    for (int col = 0; col < num_cols; ++col) {
858
      const int row_offset = (row * num_mi_h) << 2;
859
      const int col_offset = (col * num_mi_w) << 2;
860
861
      uint8_t *buf = y_buffer + row_offset * y_stride + col_offset;
862
      int r = row_offset, pos = 0;
863
      const float base = (float)((1 << bit_depth) - 1);
864
      while (r < row_offset + (num_mi_h << 2)) {
865
        for (int c = 0; c < (num_mi_w << 2); ++c) {
866
          input_data[pos++] = bit_depth > 8
867
                                  ? (float)*CONVERT_TO_SHORTPTR(buf + c) / base
868
                                  : (float)*(buf + c) / base;
869
        }
870
        buf += y_stride;
871
        ++r;
872
      }
873
      TfLiteTensorCopyFromBuffer(input_tensor, input_data, input_size);
874
875
      // Execute inference.
876
      if (TfLiteInterpreterInvoke(interpreter) != kTfLiteOk) {
877
        TfLiteInterpreterDelete(interpreter);
878
        TfLiteInterpreterOptionsDelete(options);
879
        TfLiteModelDelete(model);
880
        return 1;
881
      }
882
883
      // Extract the output tensor data.
884
      const TfLiteTensor *output_tensor =
885
          TfLiteInterpreterGetOutputTensor(interpreter, 0);
886
      if (output_tensor == NULL) {
887
        TfLiteInterpreterDelete(interpreter);
888
        TfLiteInterpreterOptionsDelete(options);
889
        TfLiteModelDelete(model);
890
        return 1;
891
      }
892
893
      size_t output_size = TfLiteTensorByteSize(output_tensor);
894
      float output_data[2];
895
896
      TfLiteTensorCopyToBuffer(output_tensor, output_data, output_size);
897
      predicts0[row * num_cols + col] = output_data[0];
898
      predicts1[row * num_cols + col] = output_data[1];
899
    }
900
  }
901
902
  // Dispose of the model and interpreter objects.
903
  TfLiteInterpreterDelete(interpreter);
904
  TfLiteInterpreterOptionsDelete(options);
905
  TfLiteModelDelete(model);
906
  aom_free(input_data);
907
  return 0;
908
}
909
910
void av1_set_mb_ur_variance(AV1_COMP *cpi) {
911
  const AV1_COMMON *cm = &cpi->common;
912
  const CommonModeInfoParams *const mi_params = &cm->mi_params;
913
  uint8_t *y_buffer = cpi->source->y_buffer;
914
  const int y_stride = cpi->source->y_stride;
915
  const int block_size = cpi->common.seq_params->sb_size;
916
  const uint32_t bit_depth = cpi->td.mb.e_mbd.bd;
917
918
  const int num_mi_w = mi_size_wide[block_size];
919
  const int num_mi_h = mi_size_high[block_size];
920
  const int num_cols = (mi_params->mi_cols + num_mi_w - 1) / num_mi_w;
921
  const int num_rows = (mi_params->mi_rows + num_mi_h - 1) / num_mi_h;
922
923
  // TODO(sdeng): fit a better model_1; disable it at this time.
924
  float *mb_delta_q0, *mb_delta_q1, delta_q_avg0 = 0.0f;
925
  CHECK_MEM_ERROR(cm, mb_delta_q0,
926
                  aom_calloc(num_rows * num_cols, sizeof(float)));
927
  CHECK_MEM_ERROR(cm, mb_delta_q1,
928
                  aom_calloc(num_rows * num_cols, sizeof(float)));
929
930
  if (model_predict(block_size, num_cols, num_rows, bit_depth, y_buffer,
931
                    y_stride, mb_delta_q0, mb_delta_q1)) {
932
    aom_internal_error(cm->error, AOM_CODEC_ERROR,
933
                       "Failed to call TFlite functions.");
934
  }
935
936
  // Loop through each SB block.
937
  for (int row = 0; row < num_rows; ++row) {
938
    for (int col = 0; col < num_cols; ++col) {
939
      const int index = row * num_cols + col;
940
      delta_q_avg0 += mb_delta_q0[index];
941
    }
942
  }
943
944
  delta_q_avg0 /= (float)(num_rows * num_cols);
945
946
  float scaling_factor;
947
  const float cq_level = (float)cpi->oxcf.rc_cfg.cq_level / (float)MAXQ;
948
  if (cq_level < delta_q_avg0) {
949
    scaling_factor = cq_level / delta_q_avg0;
950
  } else {
951
    scaling_factor = 1.0f - (cq_level - delta_q_avg0) / (1.0f - delta_q_avg0);
952
  }
953
954
  for (int row = 0; row < num_rows; ++row) {
955
    for (int col = 0; col < num_cols; ++col) {
956
      const int index = row * num_cols + col;
957
      cpi->mb_delta_q[index] =
958
          RINT((float)cpi->oxcf.q_cfg.deltaq_strength / 100.0f * (float)MAXQ *
959
               scaling_factor * (mb_delta_q0[index] - delta_q_avg0));
960
    }
961
  }
962
963
  aom_free(mb_delta_q0);
964
  aom_free(mb_delta_q1);
965
}
966
#else  // !CONFIG_TFLITE
967
0
void av1_set_mb_ur_variance(AV1_COMP *cpi) {
968
0
  const AV1_COMMON *cm = &cpi->common;
969
0
  const CommonModeInfoParams *const mi_params = &cm->mi_params;
970
0
  const MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
971
0
  uint8_t *y_buffer = cpi->source->y_buffer;
972
0
  const int y_stride = cpi->source->y_stride;
973
0
  const int block_size = cpi->common.seq_params->sb_size;
974
975
0
  const int num_mi_w = mi_size_wide[block_size];
976
0
  const int num_mi_h = mi_size_high[block_size];
977
0
  const int num_cols = (mi_params->mi_cols + num_mi_w - 1) / num_mi_w;
978
0
  const int num_rows = (mi_params->mi_rows + num_mi_h - 1) / num_mi_h;
979
980
0
  int *mb_delta_q[2];
981
0
  CHECK_MEM_ERROR(cm, mb_delta_q[0],
982
0
                  aom_calloc(num_rows * num_cols, sizeof(*mb_delta_q[0])));
983
0
  CHECK_MEM_ERROR(cm, mb_delta_q[1],
984
0
                  aom_calloc(num_rows * num_cols, sizeof(*mb_delta_q[1])));
985
986
  // Approximates the model change between current version (Spet 2021) and the
987
  // baseline (July 2021).
988
0
  const double model_change[] = { 3.0, 3.0 };
989
  // The following parameters are fitted from user labeled data.
990
0
  const double a[] = { -24.50 * 4.0, -17.20 * 4.0 };
991
0
  const double b[] = { 0.004898, 0.003093 };
992
0
  const double c[] = { (29.932 + model_change[0]) * 4.0,
993
0
                       (42.100 + model_change[1]) * 4.0 };
994
0
  int delta_q_avg[2] = { 0, 0 };
995
  // Loop through each SB block.
996
0
  for (int row = 0; row < num_rows; ++row) {
997
0
    for (int col = 0; col < num_cols; ++col) {
998
0
      double var = 0.0, num_of_var = 0.0;
999
0
      const int index = row * num_cols + col;
1000
1001
      // Loop through each 8x8 block.
1002
0
      for (int mi_row = row * num_mi_h;
1003
0
           mi_row < mi_params->mi_rows && mi_row < (row + 1) * num_mi_h;
1004
0
           mi_row += 2) {
1005
0
        for (int mi_col = col * num_mi_w;
1006
0
             mi_col < mi_params->mi_cols && mi_col < (col + 1) * num_mi_w;
1007
0
             mi_col += 2) {
1008
0
          struct buf_2d buf;
1009
0
          const int row_offset_y = mi_row << 2;
1010
0
          const int col_offset_y = mi_col << 2;
1011
1012
0
          buf.buf = y_buffer + row_offset_y * y_stride + col_offset_y;
1013
0
          buf.stride = y_stride;
1014
1015
0
          unsigned int block_variance;
1016
0
          block_variance = av1_get_perpixel_variance_facade(
1017
0
              cpi, xd, &buf, BLOCK_8X8, AOM_PLANE_Y);
1018
1019
0
          block_variance = AOMMAX(block_variance, 1);
1020
0
          var += log((double)block_variance);
1021
0
          num_of_var += 1.0;
1022
0
        }
1023
0
      }
1024
0
      var = exp(var / num_of_var);
1025
0
      mb_delta_q[0][index] = RINT(a[0] * exp(-b[0] * var) + c[0]);
1026
0
      mb_delta_q[1][index] = RINT(a[1] * exp(-b[1] * var) + c[1]);
1027
0
      delta_q_avg[0] += mb_delta_q[0][index];
1028
0
      delta_q_avg[1] += mb_delta_q[1][index];
1029
0
    }
1030
0
  }
1031
1032
0
  delta_q_avg[0] = RINT((double)delta_q_avg[0] / (num_rows * num_cols));
1033
0
  delta_q_avg[1] = RINT((double)delta_q_avg[1] / (num_rows * num_cols));
1034
1035
0
  int model_idx;
1036
0
  double scaling_factor;
1037
0
  const int cq_level = cpi->oxcf.rc_cfg.cq_level;
1038
0
  if (cq_level < delta_q_avg[0]) {
1039
0
    model_idx = 0;
1040
0
    scaling_factor = (double)cq_level / delta_q_avg[0];
1041
0
  } else if (cq_level < delta_q_avg[1]) {
1042
0
    model_idx = 2;
1043
0
    scaling_factor =
1044
0
        (double)(cq_level - delta_q_avg[0]) / (delta_q_avg[1] - delta_q_avg[0]);
1045
0
  } else {
1046
0
    model_idx = 1;
1047
0
    scaling_factor = (double)(MAXQ - cq_level) / (MAXQ - delta_q_avg[1]);
1048
0
  }
1049
1050
0
  const double new_delta_q_avg =
1051
0
      delta_q_avg[0] + scaling_factor * (delta_q_avg[1] - delta_q_avg[0]);
1052
0
  for (int row = 0; row < num_rows; ++row) {
1053
0
    for (int col = 0; col < num_cols; ++col) {
1054
0
      const int index = row * num_cols + col;
1055
0
      if (model_idx == 2) {
1056
0
        const double delta_q =
1057
0
            mb_delta_q[0][index] +
1058
0
            scaling_factor * (mb_delta_q[1][index] - mb_delta_q[0][index]);
1059
0
        cpi->mb_delta_q[index] = RINT((double)cpi->oxcf.q_cfg.deltaq_strength /
1060
0
                                      100.0 * (delta_q - new_delta_q_avg));
1061
0
      } else {
1062
0
        cpi->mb_delta_q[index] = RINT(
1063
0
            (double)cpi->oxcf.q_cfg.deltaq_strength / 100.0 * scaling_factor *
1064
0
            (mb_delta_q[model_idx][index] - delta_q_avg[model_idx]));
1065
0
      }
1066
0
    }
1067
0
  }
1068
1069
0
  aom_free(mb_delta_q[0]);
1070
0
  aom_free(mb_delta_q[1]);
1071
0
}
1072
#endif
1073
1074
int av1_get_sbq_user_rating_based(const AV1_COMP *const cpi, int mi_row,
1075
0
                                  int mi_col) {
1076
0
  const BLOCK_SIZE bsize = cpi->common.seq_params->sb_size;
1077
0
  const CommonModeInfoParams *const mi_params = &cpi->common.mi_params;
1078
0
  const AV1_COMMON *const cm = &cpi->common;
1079
0
  const int base_qindex = cm->quant_params.base_qindex;
1080
0
  if (base_qindex == MINQ || base_qindex == MAXQ) return base_qindex;
1081
1082
0
  const int num_mi_w = mi_size_wide[bsize];
1083
0
  const int num_mi_h = mi_size_high[bsize];
1084
0
  const int num_cols = (mi_params->mi_cols + num_mi_w - 1) / num_mi_w;
1085
0
  const int index = (mi_row / num_mi_h) * num_cols + (mi_col / num_mi_w);
1086
0
  const int delta_q = cpi->mb_delta_q[index];
1087
1088
0
  int qindex = base_qindex + delta_q;
1089
0
  qindex = AOMMIN(qindex, MAXQ);
1090
0
  qindex = AOMMAX(qindex, MINQ + 1);
1091
1092
0
  return qindex;
1093
0
}
1094
1095
#if !CONFIG_REALTIME_ONLY
1096
1097
// Variance Boost: a variance adaptive quantization implementation
1098
// SVT-AV1 appendix with an overview and a graphical, step-by-step explanation
1099
// of the implementation
1100
// https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/master/Docs/Appendix-Variance-Boost.md
1101
0
int av1_get_sbq_variance_boost(const AV1_COMP *cpi, const MACROBLOCK *x) {
1102
0
  const AV1_COMMON *cm = &cpi->common;
1103
0
  const int base_qindex = cm->quant_params.base_qindex;
1104
0
  const aom_bit_depth_t bit_depth = cm->seq_params->bit_depth;
1105
1106
  // Variance Boost only supports 64x64 SBs.
1107
0
  assert(cm->seq_params->sb_size == BLOCK_64X64);
1108
1109
0
  unsigned int variance = av1_get_variance_boost_block_variance(cpi, x);
1110
  // Compute Variance Boost strength from the deltaq_strength value.
1111
0
  double strength = (cpi->oxcf.q_cfg.deltaq_strength / 100.0) * 3.0;
1112
1113
  // Clamp strength to a reasonable range.
1114
  // deltaq_strength can go up to 1000%, which is too strong for the Variance
1115
  // Boost scaling. Testing revealed strengths as high as 6 (200%) are still
1116
  // reasonable for some specific scenarios.
1117
0
  strength = fclamp(strength, 0.0, 6.0);
1118
1119
  // Variance = 0 areas are either completely flat patches or have very fine
1120
  // gradients. Boost these blocks as if they have a variance of 1.
1121
0
  if (variance == 0) {
1122
0
    variance = 1;
1123
0
  }
1124
1125
  // Compute a boost based on a fast-growing formula.
1126
  // High and medium variance SBs essentially get no boost, while lower variance
1127
  // SBs get increasingly stronger boosts.
1128
  // Still picture curve, with variance crossover point at 1024.
1129
0
  double qstep_ratio = 0.15 * strength * (-log2((double)variance) + 10.0) + 1.0;
1130
0
  qstep_ratio = fclamp(qstep_ratio, 1.0, VAR_BOOST_MAX_BOOST);
1131
1132
0
  double base_q = av1_convert_qindex_to_q(base_qindex, bit_depth);
1133
0
  double target_q = base_q / qstep_ratio;
1134
0
  int target_qindex = av1_convert_q_to_qindex(target_q, bit_depth);
1135
1136
  // Determine the SB's delta_q boost by computing an (unscaled) delta_q from
1137
  // the base and target q values, then scale that delta_q according to the
1138
  // frame's base qindex.
1139
  // The scaling coefficients were chosen empirically to maximize SSIMULACRA 2
1140
  // scores, 10th percentile scores, and subjective quality. Boosts become
1141
  // smaller (for a given variance) the lower the base qindex.
1142
0
  int boost = (int)round((base_qindex + 544.0) * (base_qindex - target_qindex) /
1143
0
                         1279.0);
1144
0
  boost = AOMMIN(VAR_BOOST_MAX_DELTAQ_RANGE, boost);
1145
1146
  // Variance Boost was designed to always operate in the lossy domain, so MINQ
1147
  // is excluded.
1148
0
  int sb_qindex = AOMMAX(base_qindex - boost, MINQ + 1);
1149
1150
0
  return sb_qindex;
1151
0
}
1152
#endif