• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "av1/common/common_data.h"
13 #include "av1/common/enums.h"
14 #include "av1/common/idct.h"
15 
16 #include "av1/common/reconinter.h"
17 #include "av1/encoder/allintra_vis.h"
18 #include "av1/encoder/hybrid_fwd_txfm.h"
19 #include "av1/encoder/rdopt_utils.h"
20 
21 // Process the wiener variance in 16x16 block basis.
qsort_comp(const void * elem1,const void * elem2)22 static int qsort_comp(const void *elem1, const void *elem2) {
23   int a = *((const int *)elem1);
24   int b = *((const int *)elem2);
25   if (a > b) return 1;
26   if (a < b) return -1;
27   return 0;
28 }
29 
av1_init_mb_wiener_var_buffer(AV1_COMP * cpi)30 void av1_init_mb_wiener_var_buffer(AV1_COMP *cpi) {
31   AV1_COMMON *cm = &cpi->common;
32 
33   cpi->weber_bsize = BLOCK_8X8;
34 
35   if (cpi->mb_weber_stats) return;
36 
37   CHECK_MEM_ERROR(cm, cpi->mb_weber_stats,
38                   aom_calloc(cpi->frame_info.mi_rows * cpi->frame_info.mi_cols,
39                              sizeof(*cpi->mb_weber_stats)));
40 }
41 
get_satd(AV1_COMP * const cpi,BLOCK_SIZE bsize,int mi_row,int mi_col)42 static int64_t get_satd(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row,
43                         int mi_col) {
44   AV1_COMMON *const cm = &cpi->common;
45   const int mi_wide = mi_size_wide[bsize];
46   const int mi_high = mi_size_high[bsize];
47 
48   const int mi_step = mi_size_wide[cpi->weber_bsize];
49   int mb_stride = cpi->frame_info.mi_cols;
50   int mb_count = 0;
51   int64_t satd = 0;
52 
53   for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
54     for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
55       if (row >= cm->mi_params.mi_rows || col >= cm->mi_params.mi_cols)
56         continue;
57 
58       satd += cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)]
59                   .satd;
60       ++mb_count;
61     }
62   }
63 
64   if (mb_count) satd = (int)(satd / mb_count);
65   satd = AOMMAX(1, satd);
66 
67   return (int)satd;
68 }
69 
get_sse(AV1_COMP * const cpi,BLOCK_SIZE bsize,int mi_row,int mi_col)70 static int64_t get_sse(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row,
71                        int mi_col) {
72   AV1_COMMON *const cm = &cpi->common;
73   const int mi_wide = mi_size_wide[bsize];
74   const int mi_high = mi_size_high[bsize];
75 
76   const int mi_step = mi_size_wide[cpi->weber_bsize];
77   int mb_stride = cpi->frame_info.mi_cols;
78   int mb_count = 0;
79   int64_t distortion = 0;
80 
81   for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
82     for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
83       if (row >= cm->mi_params.mi_rows || col >= cm->mi_params.mi_cols)
84         continue;
85 
86       distortion +=
87           cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)]
88               .distortion;
89       ++mb_count;
90     }
91   }
92 
93   if (mb_count) distortion = (int)(distortion / mb_count);
94   distortion = AOMMAX(1, distortion);
95 
96   return (int)distortion;
97 }
98 
get_max_scale(AV1_COMP * const cpi,BLOCK_SIZE bsize,int mi_row,int mi_col)99 static double get_max_scale(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row,
100                             int mi_col) {
101   AV1_COMMON *const cm = &cpi->common;
102   const int mi_wide = mi_size_wide[bsize];
103   const int mi_high = mi_size_high[bsize];
104   const int mi_step = mi_size_wide[cpi->weber_bsize];
105   int mb_stride = cpi->frame_info.mi_cols;
106   double min_max_scale = 10.0;
107 
108   for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
109     for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
110       if (row >= cm->mi_params.mi_rows || col >= cm->mi_params.mi_cols)
111         continue;
112       WeberStats *weber_stats =
113           &cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)];
114       if (weber_stats->max_scale < 1.0) continue;
115       if (weber_stats->max_scale < min_max_scale)
116         min_max_scale = weber_stats->max_scale;
117     }
118   }
119   return min_max_scale;
120 }
121 
get_window_wiener_var(AV1_COMP * const cpi,BLOCK_SIZE bsize,int mi_row,int mi_col)122 static int get_window_wiener_var(AV1_COMP *const cpi, BLOCK_SIZE bsize,
123                                  int mi_row, int mi_col) {
124   AV1_COMMON *const cm = &cpi->common;
125   const int mi_wide = mi_size_wide[bsize];
126   const int mi_high = mi_size_high[bsize];
127 
128   const int mi_step = mi_size_wide[cpi->weber_bsize];
129   int sb_wiener_var = 0;
130   int mb_stride = cpi->frame_info.mi_cols;
131   int mb_count = 0;
132   double base_num = 1;
133   double base_den = 1;
134   double base_reg = 1;
135 
136   for (int row = mi_row; row < mi_row + mi_high; row += mi_step) {
137     for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) {
138       if (row >= cm->mi_params.mi_rows || col >= cm->mi_params.mi_cols)
139         continue;
140 
141       WeberStats *weber_stats =
142           &cpi->mb_weber_stats[(row / mi_step) * mb_stride + (col / mi_step)];
143 
144       base_num += ((double)weber_stats->distortion) *
145                   sqrt((double)weber_stats->src_variance) *
146                   weber_stats->rec_pix_max;
147 
148       base_den += fabs(
149           weber_stats->rec_pix_max * sqrt((double)weber_stats->src_variance) -
150           weber_stats->src_pix_max * sqrt((double)weber_stats->rec_variance));
151 
152       base_reg += sqrt((double)weber_stats->distortion) *
153                   sqrt((double)weber_stats->src_pix_max) * 0.1;
154       ++mb_count;
155     }
156   }
157 
158   sb_wiener_var = (int)((base_num + base_reg) / (base_den + base_reg));
159   sb_wiener_var = AOMMAX(1, sb_wiener_var);
160 
161   return (int)sb_wiener_var;
162 }
163 
get_var_perceptual_ai(AV1_COMP * const cpi,BLOCK_SIZE bsize,int mi_row,int mi_col)164 static int get_var_perceptual_ai(AV1_COMP *const cpi, BLOCK_SIZE bsize,
165                                  int mi_row, int mi_col) {
166   AV1_COMMON *const cm = &cpi->common;
167   const int mi_wide = mi_size_wide[bsize];
168   const int mi_high = mi_size_high[bsize];
169 
170   int sb_wiener_var = get_window_wiener_var(cpi, bsize, mi_row, mi_col);
171 
172   if (mi_row >= (mi_high / 2)) {
173     sb_wiener_var =
174         AOMMIN(sb_wiener_var,
175                get_window_wiener_var(cpi, bsize, mi_row - mi_high / 2, mi_col));
176   }
177   if (mi_row <= (cm->mi_params.mi_rows - mi_high - (mi_high / 2))) {
178     sb_wiener_var =
179         AOMMIN(sb_wiener_var,
180                get_window_wiener_var(cpi, bsize, mi_row + mi_high / 2, mi_col));
181   }
182   if (mi_col >= (mi_wide / 2)) {
183     sb_wiener_var =
184         AOMMIN(sb_wiener_var,
185                get_window_wiener_var(cpi, bsize, mi_row, mi_col - mi_wide / 2));
186   }
187   if (mi_col <= (cm->mi_params.mi_cols - mi_wide - (mi_wide / 2))) {
188     sb_wiener_var =
189         AOMMIN(sb_wiener_var,
190                get_window_wiener_var(cpi, bsize, mi_row, mi_col + mi_wide / 2));
191   }
192 
193   return sb_wiener_var;
194 }
195 
av1_set_mb_wiener_variance(AV1_COMP * cpi)196 void av1_set_mb_wiener_variance(AV1_COMP *cpi) {
197   AV1_COMMON *const cm = &cpi->common;
198   uint8_t *buffer = cpi->source->y_buffer;
199   int buf_stride = cpi->source->y_stride;
200   ThreadData *td = &cpi->td;
201   MACROBLOCK *x = &td->mb;
202   MACROBLOCKD *xd = &x->e_mbd;
203   MB_MODE_INFO mbmi;
204   memset(&mbmi, 0, sizeof(mbmi));
205   MB_MODE_INFO *mbmi_ptr = &mbmi;
206   xd->mi = &mbmi_ptr;
207   xd->cur_buf = cpi->source;
208 
209   const SequenceHeader *const seq_params = cm->seq_params;
210   if (aom_realloc_frame_buffer(
211           &cm->cur_frame->buf, cm->width, cm->height, seq_params->subsampling_x,
212           seq_params->subsampling_y, seq_params->use_highbitdepth,
213           cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL,
214           NULL, cpi->oxcf.tool_cfg.enable_global_motion))
215     aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
216                        "Failed to allocate frame buffer");
217 
218   cm->quant_params.base_qindex = cpi->oxcf.rc_cfg.cq_level;
219   av1_frame_init_quantizer(cpi);
220 
221   DECLARE_ALIGNED(32, int16_t, src_diff[32 * 32]);
222   DECLARE_ALIGNED(32, tran_low_t, coeff[32 * 32]);
223   DECLARE_ALIGNED(32, tran_low_t, qcoeff[32 * 32]);
224   DECLARE_ALIGNED(32, tran_low_t, dqcoeff[32 * 32]);
225 
226   int mi_row, mi_col;
227 
228   BLOCK_SIZE bsize = cpi->weber_bsize;
229   const TX_SIZE tx_size = max_txsize_lookup[bsize];
230   const int block_size = tx_size_wide[tx_size];
231   const int coeff_count = block_size * block_size;
232 
233   const BitDepthInfo bd_info = get_bit_depth_info(xd);
234   cpi->norm_wiener_variance = 0;
235   int mb_step = mi_size_wide[bsize];
236 
237   for (mi_row = 0; mi_row < cpi->frame_info.mi_rows; mi_row += mb_step) {
238     for (mi_col = 0; mi_col < cpi->frame_info.mi_cols; mi_col += mb_step) {
239       PREDICTION_MODE best_mode = DC_PRED;
240       int best_intra_cost = INT_MAX;
241 
242       xd->up_available = mi_row > 0;
243       xd->left_available = mi_col > 0;
244 
245       const int mi_width = mi_size_wide[bsize];
246       const int mi_height = mi_size_high[bsize];
247       set_mode_info_offsets(&cpi->common.mi_params, &cpi->mbmi_ext_info, x, xd,
248                             mi_row, mi_col);
249       set_mi_row_col(xd, &xd->tile, mi_row, mi_height, mi_col, mi_width,
250                      cm->mi_params.mi_rows, cm->mi_params.mi_cols);
251       set_plane_n4(xd, mi_size_wide[bsize], mi_size_high[bsize],
252                    av1_num_planes(cm));
253       xd->mi[0]->bsize = bsize;
254       xd->mi[0]->motion_mode = SIMPLE_TRANSLATION;
255 
256       av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row,
257                            mi_col, 0, av1_num_planes(cm));
258 
259       int dst_buffer_stride = xd->plane[0].dst.stride;
260       uint8_t *dst_buffer = xd->plane[0].dst.buf;
261       uint8_t *mb_buffer =
262           buffer + mi_row * MI_SIZE * buf_stride + mi_col * MI_SIZE;
263 
264       for (PREDICTION_MODE mode = INTRA_MODE_START; mode < INTRA_MODE_END;
265            ++mode) {
266         av1_predict_intra_block(
267             xd, cm->seq_params->sb_size,
268             cm->seq_params->enable_intra_edge_filter, block_size, block_size,
269             tx_size, mode, 0, 0, FILTER_INTRA_MODES, dst_buffer,
270             dst_buffer_stride, dst_buffer, dst_buffer_stride, 0, 0, 0);
271 
272         av1_subtract_block(bd_info, block_size, block_size, src_diff,
273                            block_size, mb_buffer, buf_stride, dst_buffer,
274                            dst_buffer_stride);
275         av1_quick_txfm(0, tx_size, bd_info, src_diff, block_size, coeff);
276         int intra_cost = aom_satd(coeff, coeff_count);
277         if (intra_cost < best_intra_cost) {
278           best_intra_cost = intra_cost;
279           best_mode = mode;
280         }
281       }
282 
283       int idx;
284       av1_predict_intra_block(xd, cm->seq_params->sb_size,
285                               cm->seq_params->enable_intra_edge_filter,
286                               block_size, block_size, tx_size, best_mode, 0, 0,
287                               FILTER_INTRA_MODES, dst_buffer, dst_buffer_stride,
288                               dst_buffer, dst_buffer_stride, 0, 0, 0);
289       av1_subtract_block(bd_info, block_size, block_size, src_diff, block_size,
290                          mb_buffer, buf_stride, dst_buffer, dst_buffer_stride);
291       av1_quick_txfm(0, tx_size, bd_info, src_diff, block_size, coeff);
292 
293       const struct macroblock_plane *const p = &x->plane[0];
294       uint16_t eob;
295       const SCAN_ORDER *const scan_order = &av1_scan_orders[tx_size][DCT_DCT];
296       QUANT_PARAM quant_param;
297       int pix_num = 1 << num_pels_log2_lookup[txsize_to_bsize[tx_size]];
298       av1_setup_quant(tx_size, 0, AV1_XFORM_QUANT_FP, 0, &quant_param);
299 #if CONFIG_AV1_HIGHBITDEPTH
300       if (is_cur_buf_hbd(xd)) {
301         av1_highbd_quantize_fp_facade(coeff, pix_num, p, qcoeff, dqcoeff, &eob,
302                                       scan_order, &quant_param);
303       } else {
304         av1_quantize_fp_facade(coeff, pix_num, p, qcoeff, dqcoeff, &eob,
305                                scan_order, &quant_param);
306       }
307 #else
308       av1_quantize_fp_facade(coeff, pix_num, p, qcoeff, dqcoeff, &eob,
309                              scan_order, &quant_param);
310 #endif  // CONFIG_AV1_HIGHBITDEPTH
311       av1_inverse_transform_block(xd, dqcoeff, 0, DCT_DCT, tx_size, dst_buffer,
312                                   dst_buffer_stride, eob, 0);
313       WeberStats *weber_stats =
314           &cpi->mb_weber_stats[(mi_row / mb_step) * cpi->frame_info.mi_cols +
315                                (mi_col / mb_step)];
316 
317       weber_stats->rec_pix_max = 1;
318       weber_stats->rec_variance = 0;
319       weber_stats->src_pix_max = 1;
320       weber_stats->src_variance = 0;
321       weber_stats->distortion = 0;
322 
323       int64_t src_mean = 0;
324       int64_t rec_mean = 0;
325       int64_t dist_mean = 0;
326 
327       for (int pix_row = 0; pix_row < block_size; ++pix_row) {
328         for (int pix_col = 0; pix_col < block_size; ++pix_col) {
329           int src_pix, rec_pix;
330 #if CONFIG_AV1_HIGHBITDEPTH
331           if (is_cur_buf_hbd(xd)) {
332             uint16_t *src = CONVERT_TO_SHORTPTR(mb_buffer);
333             uint16_t *rec = CONVERT_TO_SHORTPTR(dst_buffer);
334             src_pix = src[pix_row * buf_stride + pix_col];
335             rec_pix = rec[pix_row * dst_buffer_stride + pix_col];
336           } else {
337             src_pix = mb_buffer[pix_row * buf_stride + pix_col];
338             rec_pix = dst_buffer[pix_row * dst_buffer_stride + pix_col];
339           }
340 #else
341           src_pix = mb_buffer[pix_row * buf_stride + pix_col];
342           rec_pix = dst_buffer[pix_row * dst_buffer_stride + pix_col];
343 #endif
344           src_mean += src_pix;
345           rec_mean += rec_pix;
346           dist_mean += src_pix - rec_pix;
347           weber_stats->src_variance += src_pix * src_pix;
348           weber_stats->rec_variance += rec_pix * rec_pix;
349           weber_stats->src_pix_max = AOMMAX(weber_stats->src_pix_max, src_pix);
350           weber_stats->rec_pix_max = AOMMAX(weber_stats->rec_pix_max, rec_pix);
351           weber_stats->distortion += (src_pix - rec_pix) * (src_pix - rec_pix);
352         }
353       }
354 
355       weber_stats->src_variance -= (src_mean * src_mean) / pix_num;
356       weber_stats->rec_variance -= (rec_mean * rec_mean) / pix_num;
357       weber_stats->distortion -= (dist_mean * dist_mean) / pix_num;
358       weber_stats->satd = best_intra_cost;
359 
360       double reg = sqrt((double)weber_stats->distortion) *
361                    sqrt((double)weber_stats->src_pix_max) * 0.1;
362       double alpha_den = fabs(weber_stats->rec_pix_max *
363                                   sqrt((double)weber_stats->src_variance) -
364                               weber_stats->src_pix_max *
365                                   sqrt((double)weber_stats->rec_variance)) +
366                          reg;
367       double alpha_num = ((double)weber_stats->distortion) *
368                              sqrt((double)weber_stats->src_variance) *
369                              weber_stats->rec_pix_max +
370                          reg;
371 
372       weber_stats->alpha = AOMMAX(alpha_num, 1.0) / AOMMAX(alpha_den, 1.0);
373 
374       qcoeff[0] = 0;
375       for (idx = 1; idx < coeff_count; ++idx) qcoeff[idx] = abs(qcoeff[idx]);
376       qsort(qcoeff, coeff_count, sizeof(*coeff), qsort_comp);
377 
378       weber_stats->max_scale = (double)qcoeff[coeff_count - 1];
379     }
380   }
381 
382   int sb_step = mi_size_wide[cm->seq_params->sb_size];
383   double sb_wiener_log = 0;
384   double sb_count = 0;
385 
386   for (mi_row = 0; mi_row < cm->mi_params.mi_rows; mi_row += sb_step) {
387     for (mi_col = 0; mi_col < cm->mi_params.mi_cols; mi_col += sb_step) {
388       int sb_wiener_var =
389           get_var_perceptual_ai(cpi, cm->seq_params->sb_size, mi_row, mi_col);
390       int64_t satd = get_satd(cpi, cm->seq_params->sb_size, mi_row, mi_col);
391       int64_t sse = get_sse(cpi, cm->seq_params->sb_size, mi_row, mi_col);
392       double scaled_satd = (double)satd / sqrt((double)sse);
393       sb_wiener_log += scaled_satd * log(sb_wiener_var);
394       sb_count += scaled_satd;
395     }
396   }
397 
398   if (sb_count > 0)
399     cpi->norm_wiener_variance = (int64_t)(exp(sb_wiener_log / sb_count));
400   cpi->norm_wiener_variance = AOMMAX(1, cpi->norm_wiener_variance);
401 
402   for (int its_cnt = 0; its_cnt < 2; ++its_cnt) {
403     sb_wiener_log = 0;
404     sb_count = 0;
405     for (mi_row = 0; mi_row < cm->mi_params.mi_rows; mi_row += sb_step) {
406       for (mi_col = 0; mi_col < cm->mi_params.mi_cols; mi_col += sb_step) {
407         int sb_wiener_var =
408             get_var_perceptual_ai(cpi, cm->seq_params->sb_size, mi_row, mi_col);
409 
410         double beta = (double)cpi->norm_wiener_variance / sb_wiener_var;
411         double min_max_scale =
412             AOMMAX(1.0, get_max_scale(cpi, bsize, mi_row, mi_col));
413         beta = 1.0 / AOMMIN(1.0 / beta, min_max_scale);
414         beta = AOMMIN(beta, 4);
415         beta = AOMMAX(beta, 0.25);
416 
417         sb_wiener_var = (int)(cpi->norm_wiener_variance / beta);
418 
419         int64_t satd = get_satd(cpi, cm->seq_params->sb_size, mi_row, mi_col);
420         int64_t sse = get_sse(cpi, cm->seq_params->sb_size, mi_row, mi_col);
421         double scaled_satd = (double)satd / sqrt((double)sse);
422         sb_wiener_log += scaled_satd * log(sb_wiener_var);
423         sb_count += scaled_satd;
424       }
425     }
426 
427     if (sb_count > 0)
428       cpi->norm_wiener_variance = (int64_t)(exp(sb_wiener_log / sb_count));
429     cpi->norm_wiener_variance = AOMMAX(1, cpi->norm_wiener_variance);
430   }
431 
432   aom_free_frame_buffer(&cm->cur_frame->buf);
433 }
434 
av1_get_sbq_perceptual_ai(AV1_COMP * const cpi,BLOCK_SIZE bsize,int mi_row,int mi_col)435 int av1_get_sbq_perceptual_ai(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row,
436                               int mi_col) {
437   AV1_COMMON *const cm = &cpi->common;
438   const int base_qindex = cm->quant_params.base_qindex;
439   int sb_wiener_var = get_var_perceptual_ai(cpi, bsize, mi_row, mi_col);
440   int offset = 0;
441   double beta = (double)cpi->norm_wiener_variance / sb_wiener_var;
442   double min_max_scale = AOMMAX(1.0, get_max_scale(cpi, bsize, mi_row, mi_col));
443   beta = 1.0 / AOMMIN(1.0 / beta, min_max_scale);
444 
445   // Cap beta such that the delta q value is not much far away from the base q.
446   beta = AOMMIN(beta, 4);
447   beta = AOMMAX(beta, 0.25);
448   offset = av1_get_deltaq_offset(cm->seq_params->bit_depth, base_qindex, beta);
449   const DeltaQInfo *const delta_q_info = &cm->delta_q_info;
450   offset = AOMMIN(offset, delta_q_info->delta_q_res * 20 - 1);
451   offset = AOMMAX(offset, -delta_q_info->delta_q_res * 20 + 1);
452   int qindex = cm->quant_params.base_qindex + offset;
453   qindex = AOMMIN(qindex, MAXQ);
454   qindex = AOMMAX(qindex, MINQ);
455   if (base_qindex > MINQ) qindex = AOMMAX(qindex, MINQ + 1);
456 
457   return qindex;
458 }
459 
av1_init_mb_ur_var_buffer(AV1_COMP * cpi)460 void av1_init_mb_ur_var_buffer(AV1_COMP *cpi) {
461   AV1_COMMON *cm = &cpi->common;
462 
463   if (cpi->mb_delta_q) return;
464 
465   CHECK_MEM_ERROR(cm, cpi->mb_delta_q,
466                   aom_calloc(cpi->frame_info.mb_rows * cpi->frame_info.mb_cols,
467                              sizeof(*cpi->mb_delta_q)));
468 }
469 
av1_set_mb_ur_variance(AV1_COMP * cpi)470 void av1_set_mb_ur_variance(AV1_COMP *cpi) {
471   const CommonModeInfoParams *const mi_params = &cpi->common.mi_params;
472   ThreadData *td = &cpi->td;
473   MACROBLOCK *x = &td->mb;
474   MACROBLOCKD *xd = &x->e_mbd;
475   uint8_t *y_buffer = cpi->source->y_buffer;
476   const int y_stride = cpi->source->y_stride;
477   const int block_size = cpi->common.seq_params->sb_size;
478 
479   const int num_mi_w = mi_size_wide[block_size];
480   const int num_mi_h = mi_size_high[block_size];
481   const int num_cols = (mi_params->mi_cols + num_mi_w - 1) / num_mi_w;
482   const int num_rows = (mi_params->mi_rows + num_mi_h - 1) / num_mi_h;
483   const int use_hbd = cpi->source->flags & YV12_FLAG_HIGHBITDEPTH;
484 
485   double a = -23.06 * 4.0, b = 0.004065, c = 30.516 * 4.0;
486   int delta_q_avg = 0;
487   // Loop through each SB block.
488   for (int row = 0; row < num_rows; ++row) {
489     for (int col = 0; col < num_cols; ++col) {
490       double var = 0.0, num_of_var = 0.0;
491       const int index = row * num_cols + col;
492 
493       // Loop through each 8x8 block.
494       for (int mi_row = row * num_mi_h;
495            mi_row < mi_params->mi_rows && mi_row < (row + 1) * num_mi_h;
496            mi_row += 2) {
497         for (int mi_col = col * num_mi_w;
498              mi_col < mi_params->mi_cols && mi_col < (col + 1) * num_mi_w;
499              mi_col += 2) {
500           struct buf_2d buf;
501           const int row_offset_y = mi_row << 2;
502           const int col_offset_y = mi_col << 2;
503 
504           buf.buf = y_buffer + row_offset_y * y_stride + col_offset_y;
505           buf.stride = y_stride;
506 
507           double block_variance;
508           if (use_hbd) {
509             block_variance = av1_high_get_sby_perpixel_variance(
510                 cpi, &buf, BLOCK_8X8, xd->bd);
511           } else {
512             block_variance =
513                 av1_get_sby_perpixel_variance(cpi, &buf, BLOCK_8X8);
514           }
515 
516           block_variance = block_variance < 1.0 ? 1.0 : block_variance;
517           var += log(block_variance);
518           num_of_var += 1.0;
519         }
520       }
521       var = exp(var / num_of_var);
522       cpi->mb_delta_q[index] = (int)(a * exp(-b * var) + c + 0.5);
523       delta_q_avg += cpi->mb_delta_q[index];
524     }
525   }
526 
527   delta_q_avg = (int)((double)delta_q_avg / (num_rows * num_cols) + 0.5);
528 
529   for (int row = 0; row < num_rows; ++row) {
530     for (int col = 0; col < num_cols; ++col) {
531       const int index = row * num_cols + col;
532       cpi->mb_delta_q[index] -= delta_q_avg;
533     }
534   }
535 }
536 
av1_get_sbq_user_rating_based(AV1_COMP * const cpi,int mi_row,int mi_col)537 int av1_get_sbq_user_rating_based(AV1_COMP *const cpi, int mi_row, int mi_col) {
538   const BLOCK_SIZE bsize = cpi->common.seq_params->sb_size;
539   const CommonModeInfoParams *const mi_params = &cpi->common.mi_params;
540   AV1_COMMON *const cm = &cpi->common;
541   const int base_qindex = cm->quant_params.base_qindex;
542   if (base_qindex == MINQ || base_qindex == MAXQ) return base_qindex;
543 
544   const int num_mi_w = mi_size_wide[bsize];
545   const int num_mi_h = mi_size_high[bsize];
546   const int num_cols = (mi_params->mi_cols + num_mi_w - 1) / num_mi_w;
547   const int index = (mi_row / num_mi_h) * num_cols + (mi_col / num_mi_w);
548   const int delta_q = cpi->mb_delta_q[index];
549 
550   int qindex = base_qindex + delta_q;
551   qindex = AOMMIN(qindex, MAXQ);
552   qindex = AOMMAX(qindex, MINQ + 1);
553 
554   return qindex;
555 }
556