Coverage Report

Created: 2026-09-14 07:37

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