Coverage Report

Created: 2026-07-25 07:06

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