/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 |