1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker * Copyright (c) 2016, Alliance for Open Media. All rights reserved.
3*77c1e3ccSAndroid Build Coastguard Worker *
4*77c1e3ccSAndroid Build Coastguard Worker * This source code is subject to the terms of the BSD 2 Clause License and
5*77c1e3ccSAndroid Build Coastguard Worker * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6*77c1e3ccSAndroid Build Coastguard Worker * was not distributed with this source code in the LICENSE file, you can
7*77c1e3ccSAndroid Build Coastguard Worker * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8*77c1e3ccSAndroid Build Coastguard Worker * Media Patent License 1.0 was not distributed with this source code in the
9*77c1e3ccSAndroid Build Coastguard Worker * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10*77c1e3ccSAndroid Build Coastguard Worker */
11*77c1e3ccSAndroid Build Coastguard Worker
12*77c1e3ccSAndroid Build Coastguard Worker #include <math.h>
13*77c1e3ccSAndroid Build Coastguard Worker
14*77c1e3ccSAndroid Build Coastguard Worker #include "aom_ports/mem.h"
15*77c1e3ccSAndroid Build Coastguard Worker
16*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/aq_variance.h"
17*77c1e3ccSAndroid Build Coastguard Worker #include "av1/common/seg_common.h"
18*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/encodeframe.h"
19*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/ratectrl.h"
20*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/rd.h"
21*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/segmentation.h"
22*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/dwt.h"
23*77c1e3ccSAndroid Build Coastguard Worker #include "config/aom_config.h"
24*77c1e3ccSAndroid Build Coastguard Worker
25*77c1e3ccSAndroid Build Coastguard Worker #if !CONFIG_REALTIME_ONLY
26*77c1e3ccSAndroid Build Coastguard Worker static const double rate_ratio[MAX_SEGMENTS] = { 2.2, 1.7, 1.3, 1.0,
27*77c1e3ccSAndroid Build Coastguard Worker 0.9, .8, .7, .6 };
28*77c1e3ccSAndroid Build Coastguard Worker
29*77c1e3ccSAndroid Build Coastguard Worker static const double deltaq_rate_ratio[MAX_SEGMENTS] = { 2.5, 2.0, 1.5, 1.0,
30*77c1e3ccSAndroid Build Coastguard Worker 0.75, 1.0, 1.0, 1.0 };
31*77c1e3ccSAndroid Build Coastguard Worker #define ENERGY_MIN (-4)
32*77c1e3ccSAndroid Build Coastguard Worker #define ENERGY_MAX (1)
33*77c1e3ccSAndroid Build Coastguard Worker #define ENERGY_SPAN (ENERGY_MAX - ENERGY_MIN + 1)
34*77c1e3ccSAndroid Build Coastguard Worker #define ENERGY_IN_BOUNDS(energy) \
35*77c1e3ccSAndroid Build Coastguard Worker assert((energy) >= ENERGY_MIN && (energy) <= ENERGY_MAX)
36*77c1e3ccSAndroid Build Coastguard Worker
37*77c1e3ccSAndroid Build Coastguard Worker static const int segment_id[ENERGY_SPAN] = { 0, 1, 1, 2, 3, 4 };
38*77c1e3ccSAndroid Build Coastguard Worker
39*77c1e3ccSAndroid Build Coastguard Worker #define SEGMENT_ID(i) segment_id[(i)-ENERGY_MIN]
40*77c1e3ccSAndroid Build Coastguard Worker
av1_vaq_frame_setup(AV1_COMP * cpi)41*77c1e3ccSAndroid Build Coastguard Worker void av1_vaq_frame_setup(AV1_COMP *cpi) {
42*77c1e3ccSAndroid Build Coastguard Worker AV1_COMMON *cm = &cpi->common;
43*77c1e3ccSAndroid Build Coastguard Worker const RefreshFrameInfo *const refresh_frame = &cpi->refresh_frame;
44*77c1e3ccSAndroid Build Coastguard Worker const int base_qindex = cm->quant_params.base_qindex;
45*77c1e3ccSAndroid Build Coastguard Worker struct segmentation *seg = &cm->seg;
46*77c1e3ccSAndroid Build Coastguard Worker int i;
47*77c1e3ccSAndroid Build Coastguard Worker
48*77c1e3ccSAndroid Build Coastguard Worker int resolution_change =
49*77c1e3ccSAndroid Build Coastguard Worker cm->prev_frame && (cm->width != cm->prev_frame->width ||
50*77c1e3ccSAndroid Build Coastguard Worker cm->height != cm->prev_frame->height);
51*77c1e3ccSAndroid Build Coastguard Worker int avg_energy = (int)(cpi->twopass_frame.mb_av_energy - 2);
52*77c1e3ccSAndroid Build Coastguard Worker double avg_ratio;
53*77c1e3ccSAndroid Build Coastguard Worker if (avg_energy > 7) avg_energy = 7;
54*77c1e3ccSAndroid Build Coastguard Worker if (avg_energy < 0) avg_energy = 0;
55*77c1e3ccSAndroid Build Coastguard Worker avg_ratio = rate_ratio[avg_energy];
56*77c1e3ccSAndroid Build Coastguard Worker
57*77c1e3ccSAndroid Build Coastguard Worker if (resolution_change) {
58*77c1e3ccSAndroid Build Coastguard Worker memset(cpi->enc_seg.map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols);
59*77c1e3ccSAndroid Build Coastguard Worker av1_clearall_segfeatures(seg);
60*77c1e3ccSAndroid Build Coastguard Worker av1_disable_segmentation(seg);
61*77c1e3ccSAndroid Build Coastguard Worker return;
62*77c1e3ccSAndroid Build Coastguard Worker }
63*77c1e3ccSAndroid Build Coastguard Worker if (frame_is_intra_only(cm) || cm->features.error_resilient_mode ||
64*77c1e3ccSAndroid Build Coastguard Worker refresh_frame->alt_ref_frame ||
65*77c1e3ccSAndroid Build Coastguard Worker (refresh_frame->golden_frame && !cpi->rc.is_src_frame_alt_ref)) {
66*77c1e3ccSAndroid Build Coastguard Worker cpi->vaq_refresh = 1;
67*77c1e3ccSAndroid Build Coastguard Worker
68*77c1e3ccSAndroid Build Coastguard Worker av1_enable_segmentation(seg);
69*77c1e3ccSAndroid Build Coastguard Worker av1_clearall_segfeatures(seg);
70*77c1e3ccSAndroid Build Coastguard Worker
71*77c1e3ccSAndroid Build Coastguard Worker for (i = 0; i < MAX_SEGMENTS; ++i) {
72*77c1e3ccSAndroid Build Coastguard Worker // Set up avg segment id to be 1.0 and adjust the other segments around
73*77c1e3ccSAndroid Build Coastguard Worker // it.
74*77c1e3ccSAndroid Build Coastguard Worker int qindex_delta =
75*77c1e3ccSAndroid Build Coastguard Worker av1_compute_qdelta_by_rate(cpi, cm->current_frame.frame_type,
76*77c1e3ccSAndroid Build Coastguard Worker base_qindex, rate_ratio[i] / avg_ratio);
77*77c1e3ccSAndroid Build Coastguard Worker
78*77c1e3ccSAndroid Build Coastguard Worker // We don't allow qindex 0 in a segment if the base value is not 0.
79*77c1e3ccSAndroid Build Coastguard Worker // Q index 0 (lossless) implies 4x4 encoding only and in AQ mode a segment
80*77c1e3ccSAndroid Build Coastguard Worker // Q delta is sometimes applied without going back around the rd loop.
81*77c1e3ccSAndroid Build Coastguard Worker // This could lead to an illegal combination of partition size and q.
82*77c1e3ccSAndroid Build Coastguard Worker if ((base_qindex != 0) && ((base_qindex + qindex_delta) == 0)) {
83*77c1e3ccSAndroid Build Coastguard Worker qindex_delta = -base_qindex + 1;
84*77c1e3ccSAndroid Build Coastguard Worker }
85*77c1e3ccSAndroid Build Coastguard Worker
86*77c1e3ccSAndroid Build Coastguard Worker av1_set_segdata(seg, i, SEG_LVL_ALT_Q, qindex_delta);
87*77c1e3ccSAndroid Build Coastguard Worker av1_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
88*77c1e3ccSAndroid Build Coastguard Worker }
89*77c1e3ccSAndroid Build Coastguard Worker }
90*77c1e3ccSAndroid Build Coastguard Worker }
91*77c1e3ccSAndroid Build Coastguard Worker
av1_log_block_avg(const AV1_COMP * cpi,MACROBLOCK * x,BLOCK_SIZE bs,int mi_row,int mi_col)92*77c1e3ccSAndroid Build Coastguard Worker int av1_log_block_avg(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs,
93*77c1e3ccSAndroid Build Coastguard Worker int mi_row, int mi_col) {
94*77c1e3ccSAndroid Build Coastguard Worker // This functions returns the block average of luma block
95*77c1e3ccSAndroid Build Coastguard Worker unsigned int sum, avg, num_pix;
96*77c1e3ccSAndroid Build Coastguard Worker int r, c;
97*77c1e3ccSAndroid Build Coastguard Worker const int pic_w = cpi->common.width;
98*77c1e3ccSAndroid Build Coastguard Worker const int pic_h = cpi->common.height;
99*77c1e3ccSAndroid Build Coastguard Worker const int bw = MI_SIZE * mi_size_wide[bs];
100*77c1e3ccSAndroid Build Coastguard Worker const int bh = MI_SIZE * mi_size_high[bs];
101*77c1e3ccSAndroid Build Coastguard Worker const uint16_t *x16 = CONVERT_TO_SHORTPTR(x->plane[0].src.buf);
102*77c1e3ccSAndroid Build Coastguard Worker
103*77c1e3ccSAndroid Build Coastguard Worker sum = 0;
104*77c1e3ccSAndroid Build Coastguard Worker num_pix = 0;
105*77c1e3ccSAndroid Build Coastguard Worker avg = 0;
106*77c1e3ccSAndroid Build Coastguard Worker int row = mi_row << MI_SIZE_LOG2;
107*77c1e3ccSAndroid Build Coastguard Worker int col = mi_col << MI_SIZE_LOG2;
108*77c1e3ccSAndroid Build Coastguard Worker for (r = row; (r < (row + bh)) && (r < pic_h); r++) {
109*77c1e3ccSAndroid Build Coastguard Worker for (c = col; (c < (col + bw)) && (c < pic_w); c++) {
110*77c1e3ccSAndroid Build Coastguard Worker sum += *(x16 + r * x->plane[0].src.stride + c);
111*77c1e3ccSAndroid Build Coastguard Worker num_pix++;
112*77c1e3ccSAndroid Build Coastguard Worker }
113*77c1e3ccSAndroid Build Coastguard Worker }
114*77c1e3ccSAndroid Build Coastguard Worker if (num_pix != 0) {
115*77c1e3ccSAndroid Build Coastguard Worker avg = sum / num_pix;
116*77c1e3ccSAndroid Build Coastguard Worker }
117*77c1e3ccSAndroid Build Coastguard Worker return avg;
118*77c1e3ccSAndroid Build Coastguard Worker }
119*77c1e3ccSAndroid Build Coastguard Worker
120*77c1e3ccSAndroid Build Coastguard Worker #define DEFAULT_E_MIDPOINT 10.0
121*77c1e3ccSAndroid Build Coastguard Worker
haar_ac_energy(MACROBLOCK * x,BLOCK_SIZE bs)122*77c1e3ccSAndroid Build Coastguard Worker static unsigned int haar_ac_energy(MACROBLOCK *x, BLOCK_SIZE bs) {
123*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *xd = &x->e_mbd;
124*77c1e3ccSAndroid Build Coastguard Worker int stride = x->plane[0].src.stride;
125*77c1e3ccSAndroid Build Coastguard Worker uint8_t *buf = x->plane[0].src.buf;
126*77c1e3ccSAndroid Build Coastguard Worker const int num_8x8_cols = block_size_wide[bs] / 8;
127*77c1e3ccSAndroid Build Coastguard Worker const int num_8x8_rows = block_size_high[bs] / 8;
128*77c1e3ccSAndroid Build Coastguard Worker const int hbd = is_cur_buf_hbd(xd);
129*77c1e3ccSAndroid Build Coastguard Worker
130*77c1e3ccSAndroid Build Coastguard Worker int64_t var = av1_haar_ac_sad_mxn_uint8_input(buf, stride, hbd, num_8x8_rows,
131*77c1e3ccSAndroid Build Coastguard Worker num_8x8_cols);
132*77c1e3ccSAndroid Build Coastguard Worker
133*77c1e3ccSAndroid Build Coastguard Worker return (unsigned int)((uint64_t)var * 256) >> num_pels_log2_lookup[bs];
134*77c1e3ccSAndroid Build Coastguard Worker }
135*77c1e3ccSAndroid Build Coastguard Worker
log_block_wavelet_energy(MACROBLOCK * x,BLOCK_SIZE bs)136*77c1e3ccSAndroid Build Coastguard Worker static double log_block_wavelet_energy(MACROBLOCK *x, BLOCK_SIZE bs) {
137*77c1e3ccSAndroid Build Coastguard Worker unsigned int haar_sad = haar_ac_energy(x, bs);
138*77c1e3ccSAndroid Build Coastguard Worker return log1p(haar_sad);
139*77c1e3ccSAndroid Build Coastguard Worker }
140*77c1e3ccSAndroid Build Coastguard Worker
av1_block_wavelet_energy_level(const AV1_COMP * cpi,MACROBLOCK * x,BLOCK_SIZE bs)141*77c1e3ccSAndroid Build Coastguard Worker int av1_block_wavelet_energy_level(const AV1_COMP *cpi, MACROBLOCK *x,
142*77c1e3ccSAndroid Build Coastguard Worker BLOCK_SIZE bs) {
143*77c1e3ccSAndroid Build Coastguard Worker double energy, energy_midpoint;
144*77c1e3ccSAndroid Build Coastguard Worker energy_midpoint = (is_stat_consumption_stage_twopass(cpi))
145*77c1e3ccSAndroid Build Coastguard Worker ? cpi->twopass_frame.frame_avg_haar_energy
146*77c1e3ccSAndroid Build Coastguard Worker : DEFAULT_E_MIDPOINT;
147*77c1e3ccSAndroid Build Coastguard Worker energy = log_block_wavelet_energy(x, bs) - energy_midpoint;
148*77c1e3ccSAndroid Build Coastguard Worker return clamp((int)round(energy), ENERGY_MIN, ENERGY_MAX);
149*77c1e3ccSAndroid Build Coastguard Worker }
150*77c1e3ccSAndroid Build Coastguard Worker
av1_compute_q_from_energy_level_deltaq_mode(const AV1_COMP * const cpi,int block_var_level)151*77c1e3ccSAndroid Build Coastguard Worker int av1_compute_q_from_energy_level_deltaq_mode(const AV1_COMP *const cpi,
152*77c1e3ccSAndroid Build Coastguard Worker int block_var_level) {
153*77c1e3ccSAndroid Build Coastguard Worker int rate_level;
154*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
155*77c1e3ccSAndroid Build Coastguard Worker
156*77c1e3ccSAndroid Build Coastguard Worker if (DELTA_Q_PERCEPTUAL_MODULATION == 1) {
157*77c1e3ccSAndroid Build Coastguard Worker ENERGY_IN_BOUNDS(block_var_level);
158*77c1e3ccSAndroid Build Coastguard Worker rate_level = SEGMENT_ID(block_var_level);
159*77c1e3ccSAndroid Build Coastguard Worker } else {
160*77c1e3ccSAndroid Build Coastguard Worker rate_level = block_var_level;
161*77c1e3ccSAndroid Build Coastguard Worker }
162*77c1e3ccSAndroid Build Coastguard Worker const int base_qindex = cm->quant_params.base_qindex;
163*77c1e3ccSAndroid Build Coastguard Worker int qindex_delta =
164*77c1e3ccSAndroid Build Coastguard Worker av1_compute_qdelta_by_rate(cpi, cm->current_frame.frame_type, base_qindex,
165*77c1e3ccSAndroid Build Coastguard Worker deltaq_rate_ratio[rate_level]);
166*77c1e3ccSAndroid Build Coastguard Worker
167*77c1e3ccSAndroid Build Coastguard Worker if ((base_qindex != 0) && ((base_qindex + qindex_delta) == 0)) {
168*77c1e3ccSAndroid Build Coastguard Worker qindex_delta = -base_qindex + 1;
169*77c1e3ccSAndroid Build Coastguard Worker }
170*77c1e3ccSAndroid Build Coastguard Worker return base_qindex + qindex_delta;
171*77c1e3ccSAndroid Build Coastguard Worker }
172*77c1e3ccSAndroid Build Coastguard Worker #endif // !CONFIG_REALTIME_ONLY
173*77c1e3ccSAndroid Build Coastguard Worker
av1_log_block_var(const AV1_COMP * cpi,MACROBLOCK * x,BLOCK_SIZE bs)174*77c1e3ccSAndroid Build Coastguard Worker int av1_log_block_var(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bs) {
175*77c1e3ccSAndroid Build Coastguard Worker DECLARE_ALIGNED(16, static const uint16_t,
176*77c1e3ccSAndroid Build Coastguard Worker av1_highbd_all_zeros[MAX_SB_SIZE]) = { 0 };
177*77c1e3ccSAndroid Build Coastguard Worker DECLARE_ALIGNED(16, static const uint8_t, av1_all_zeros[MAX_SB_SIZE]) = { 0 };
178*77c1e3ccSAndroid Build Coastguard Worker
179*77c1e3ccSAndroid Build Coastguard Worker // This function returns a score for the blocks local variance as calculated
180*77c1e3ccSAndroid Build Coastguard Worker // by: sum of the log of the (4x4 variances) of each subblock to the current
181*77c1e3ccSAndroid Build Coastguard Worker // block (x,bs)
182*77c1e3ccSAndroid Build Coastguard Worker // * 32 / number of pixels in the block_size.
183*77c1e3ccSAndroid Build Coastguard Worker // This is used for segmentation because to avoid situations in which a large
184*77c1e3ccSAndroid Build Coastguard Worker // block with a gentle gradient gets marked high variance even though each
185*77c1e3ccSAndroid Build Coastguard Worker // subblock has a low variance. This allows us to assign the same segment
186*77c1e3ccSAndroid Build Coastguard Worker // number for the same sorts of area regardless of how the partitioning goes.
187*77c1e3ccSAndroid Build Coastguard Worker
188*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *xd = &x->e_mbd;
189*77c1e3ccSAndroid Build Coastguard Worker double var = 0;
190*77c1e3ccSAndroid Build Coastguard Worker unsigned int sse;
191*77c1e3ccSAndroid Build Coastguard Worker int i, j;
192*77c1e3ccSAndroid Build Coastguard Worker
193*77c1e3ccSAndroid Build Coastguard Worker int right_overflow =
194*77c1e3ccSAndroid Build Coastguard Worker (xd->mb_to_right_edge < 0) ? ((-xd->mb_to_right_edge) >> 3) : 0;
195*77c1e3ccSAndroid Build Coastguard Worker int bottom_overflow =
196*77c1e3ccSAndroid Build Coastguard Worker (xd->mb_to_bottom_edge < 0) ? ((-xd->mb_to_bottom_edge) >> 3) : 0;
197*77c1e3ccSAndroid Build Coastguard Worker
198*77c1e3ccSAndroid Build Coastguard Worker const int bw = MI_SIZE * mi_size_wide[bs] - right_overflow;
199*77c1e3ccSAndroid Build Coastguard Worker const int bh = MI_SIZE * mi_size_high[bs] - bottom_overflow;
200*77c1e3ccSAndroid Build Coastguard Worker
201*77c1e3ccSAndroid Build Coastguard Worker for (i = 0; i < bh; i += 4) {
202*77c1e3ccSAndroid Build Coastguard Worker for (j = 0; j < bw; j += 4) {
203*77c1e3ccSAndroid Build Coastguard Worker if (is_cur_buf_hbd(xd)) {
204*77c1e3ccSAndroid Build Coastguard Worker var += log1p(cpi->ppi->fn_ptr[BLOCK_4X4].vf(
205*77c1e3ccSAndroid Build Coastguard Worker x->plane[0].src.buf + i * x->plane[0].src.stride + j,
206*77c1e3ccSAndroid Build Coastguard Worker x->plane[0].src.stride,
207*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_BYTEPTR(av1_highbd_all_zeros), 0, &sse) /
208*77c1e3ccSAndroid Build Coastguard Worker 16.0);
209*77c1e3ccSAndroid Build Coastguard Worker } else {
210*77c1e3ccSAndroid Build Coastguard Worker var += log1p(cpi->ppi->fn_ptr[BLOCK_4X4].vf(
211*77c1e3ccSAndroid Build Coastguard Worker x->plane[0].src.buf + i * x->plane[0].src.stride + j,
212*77c1e3ccSAndroid Build Coastguard Worker x->plane[0].src.stride, av1_all_zeros, 0, &sse) /
213*77c1e3ccSAndroid Build Coastguard Worker 16.0);
214*77c1e3ccSAndroid Build Coastguard Worker }
215*77c1e3ccSAndroid Build Coastguard Worker }
216*77c1e3ccSAndroid Build Coastguard Worker }
217*77c1e3ccSAndroid Build Coastguard Worker // Use average of 4x4 log variance. The range for 8 bit 0 - 9.704121561.
218*77c1e3ccSAndroid Build Coastguard Worker var /= (bw / 4 * bh / 4);
219*77c1e3ccSAndroid Build Coastguard Worker if (var > 7) var = 7;
220*77c1e3ccSAndroid Build Coastguard Worker
221*77c1e3ccSAndroid Build Coastguard Worker return (int)(var);
222*77c1e3ccSAndroid Build Coastguard Worker }
223