1*77c1e3ccSAndroid Build Coastguard Worker /*
2*77c1e3ccSAndroid Build Coastguard Worker * Copyright (c) 2019, 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 "av1/encoder/tune_vmaf.h"
13*77c1e3ccSAndroid Build Coastguard Worker
14*77c1e3ccSAndroid Build Coastguard Worker #include "aom_dsp/psnr.h"
15*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/extend.h"
16*77c1e3ccSAndroid Build Coastguard Worker #include "av1/encoder/rdopt.h"
17*77c1e3ccSAndroid Build Coastguard Worker #include "config/aom_scale_rtcd.h"
18*77c1e3ccSAndroid Build Coastguard Worker
19*77c1e3ccSAndroid Build Coastguard Worker static const double kBaselineVmaf = 97.42773;
20*77c1e3ccSAndroid Build Coastguard Worker
get_layer_value(const double * array,int layer)21*77c1e3ccSAndroid Build Coastguard Worker static double get_layer_value(const double *array, int layer) {
22*77c1e3ccSAndroid Build Coastguard Worker while (array[layer] < 0.0 && layer > 0) layer--;
23*77c1e3ccSAndroid Build Coastguard Worker return AOMMAX(array[layer], 0.0);
24*77c1e3ccSAndroid Build Coastguard Worker }
25*77c1e3ccSAndroid Build Coastguard Worker
motion_search(AV1_COMP * cpi,const YV12_BUFFER_CONFIG * src,const YV12_BUFFER_CONFIG * ref,const BLOCK_SIZE block_size,const int mb_row,const int mb_col,FULLPEL_MV * ref_mv)26*77c1e3ccSAndroid Build Coastguard Worker static void motion_search(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *src,
27*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *ref,
28*77c1e3ccSAndroid Build Coastguard Worker const BLOCK_SIZE block_size, const int mb_row,
29*77c1e3ccSAndroid Build Coastguard Worker const int mb_col, FULLPEL_MV *ref_mv) {
30*77c1e3ccSAndroid Build Coastguard Worker // Block information (ONLY Y-plane is used for motion search).
31*77c1e3ccSAndroid Build Coastguard Worker const int mb_height = block_size_high[block_size];
32*77c1e3ccSAndroid Build Coastguard Worker const int mb_width = block_size_wide[block_size];
33*77c1e3ccSAndroid Build Coastguard Worker const int y_stride = src->y_stride;
34*77c1e3ccSAndroid Build Coastguard Worker assert(y_stride == ref->y_stride);
35*77c1e3ccSAndroid Build Coastguard Worker const int y_offset = mb_row * mb_height * y_stride + mb_col * mb_width;
36*77c1e3ccSAndroid Build Coastguard Worker
37*77c1e3ccSAndroid Build Coastguard Worker // Save input state.
38*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const mb = &cpi->td.mb;
39*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const mbd = &mb->e_mbd;
40*77c1e3ccSAndroid Build Coastguard Worker const struct buf_2d ori_src_buf = mb->plane[0].src;
41*77c1e3ccSAndroid Build Coastguard Worker const struct buf_2d ori_pre_buf = mbd->plane[0].pre[0];
42*77c1e3ccSAndroid Build Coastguard Worker
43*77c1e3ccSAndroid Build Coastguard Worker // Parameters used for motion search.
44*77c1e3ccSAndroid Build Coastguard Worker FULLPEL_MOTION_SEARCH_PARAMS full_ms_params;
45*77c1e3ccSAndroid Build Coastguard Worker FULLPEL_MV_STATS best_mv_stats;
46*77c1e3ccSAndroid Build Coastguard Worker const SEARCH_METHODS search_method = NSTEP;
47*77c1e3ccSAndroid Build Coastguard Worker const search_site_config *search_site_cfg =
48*77c1e3ccSAndroid Build Coastguard Worker cpi->mv_search_params.search_site_cfg[SS_CFG_FPF];
49*77c1e3ccSAndroid Build Coastguard Worker const int step_param =
50*77c1e3ccSAndroid Build Coastguard Worker av1_init_search_range(AOMMAX(src->y_crop_width, src->y_crop_height));
51*77c1e3ccSAndroid Build Coastguard Worker
52*77c1e3ccSAndroid Build Coastguard Worker // Baseline position for motion search (used for rate distortion comparison).
53*77c1e3ccSAndroid Build Coastguard Worker const MV baseline_mv = kZeroMv;
54*77c1e3ccSAndroid Build Coastguard Worker
55*77c1e3ccSAndroid Build Coastguard Worker // Setup.
56*77c1e3ccSAndroid Build Coastguard Worker mb->plane[0].src.buf = src->y_buffer + y_offset;
57*77c1e3ccSAndroid Build Coastguard Worker mb->plane[0].src.stride = y_stride;
58*77c1e3ccSAndroid Build Coastguard Worker mbd->plane[0].pre[0].buf = ref->y_buffer + y_offset;
59*77c1e3ccSAndroid Build Coastguard Worker mbd->plane[0].pre[0].stride = y_stride;
60*77c1e3ccSAndroid Build Coastguard Worker
61*77c1e3ccSAndroid Build Coastguard Worker // Unused intermediate results for motion search.
62*77c1e3ccSAndroid Build Coastguard Worker int cost_list[5];
63*77c1e3ccSAndroid Build Coastguard Worker
64*77c1e3ccSAndroid Build Coastguard Worker // Do motion search.
65*77c1e3ccSAndroid Build Coastguard Worker // Only do full search on the entire block.
66*77c1e3ccSAndroid Build Coastguard Worker av1_make_default_fullpel_ms_params(&full_ms_params, cpi, mb, block_size,
67*77c1e3ccSAndroid Build Coastguard Worker &baseline_mv, *ref_mv, search_site_cfg,
68*77c1e3ccSAndroid Build Coastguard Worker search_method,
69*77c1e3ccSAndroid Build Coastguard Worker /*fine_search_interval=*/0);
70*77c1e3ccSAndroid Build Coastguard Worker av1_full_pixel_search(*ref_mv, &full_ms_params, step_param,
71*77c1e3ccSAndroid Build Coastguard Worker cond_cost_list(cpi, cost_list), ref_mv, &best_mv_stats,
72*77c1e3ccSAndroid Build Coastguard Worker NULL);
73*77c1e3ccSAndroid Build Coastguard Worker
74*77c1e3ccSAndroid Build Coastguard Worker // Restore input state.
75*77c1e3ccSAndroid Build Coastguard Worker mb->plane[0].src = ori_src_buf;
76*77c1e3ccSAndroid Build Coastguard Worker mbd->plane[0].pre[0] = ori_pre_buf;
77*77c1e3ccSAndroid Build Coastguard Worker }
78*77c1e3ccSAndroid Build Coastguard Worker
residual_variance(const AV1_COMP * cpi,const YV12_BUFFER_CONFIG * src,const YV12_BUFFER_CONFIG * ref,const BLOCK_SIZE block_size,const int mb_row,const int mb_col,FULLPEL_MV ref_mv,unsigned int * sse)79*77c1e3ccSAndroid Build Coastguard Worker static unsigned int residual_variance(const AV1_COMP *cpi,
80*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *src,
81*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *ref,
82*77c1e3ccSAndroid Build Coastguard Worker const BLOCK_SIZE block_size,
83*77c1e3ccSAndroid Build Coastguard Worker const int mb_row, const int mb_col,
84*77c1e3ccSAndroid Build Coastguard Worker FULLPEL_MV ref_mv, unsigned int *sse) {
85*77c1e3ccSAndroid Build Coastguard Worker const int mb_height = block_size_high[block_size];
86*77c1e3ccSAndroid Build Coastguard Worker const int mb_width = block_size_wide[block_size];
87*77c1e3ccSAndroid Build Coastguard Worker const int y_stride = src->y_stride;
88*77c1e3ccSAndroid Build Coastguard Worker assert(y_stride == ref->y_stride);
89*77c1e3ccSAndroid Build Coastguard Worker const int y_offset = mb_row * mb_height * y_stride + mb_col * mb_width;
90*77c1e3ccSAndroid Build Coastguard Worker const int mv_offset = ref_mv.row * y_stride + ref_mv.col;
91*77c1e3ccSAndroid Build Coastguard Worker const unsigned int var = cpi->ppi->fn_ptr[block_size].vf(
92*77c1e3ccSAndroid Build Coastguard Worker ref->y_buffer + y_offset + mv_offset, y_stride, src->y_buffer + y_offset,
93*77c1e3ccSAndroid Build Coastguard Worker y_stride, sse);
94*77c1e3ccSAndroid Build Coastguard Worker return var;
95*77c1e3ccSAndroid Build Coastguard Worker }
96*77c1e3ccSAndroid Build Coastguard Worker
frame_average_variance(const AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * const frame)97*77c1e3ccSAndroid Build Coastguard Worker static double frame_average_variance(const AV1_COMP *const cpi,
98*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const frame) {
99*77c1e3ccSAndroid Build Coastguard Worker const MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
100*77c1e3ccSAndroid Build Coastguard Worker const uint8_t *const y_buffer = frame->y_buffer;
101*77c1e3ccSAndroid Build Coastguard Worker const int y_stride = frame->y_stride;
102*77c1e3ccSAndroid Build Coastguard Worker const BLOCK_SIZE block_size = BLOCK_64X64;
103*77c1e3ccSAndroid Build Coastguard Worker
104*77c1e3ccSAndroid Build Coastguard Worker const int block_w = mi_size_wide[block_size] * 4;
105*77c1e3ccSAndroid Build Coastguard Worker const int block_h = mi_size_high[block_size] * 4;
106*77c1e3ccSAndroid Build Coastguard Worker int row, col;
107*77c1e3ccSAndroid Build Coastguard Worker double var = 0.0, var_count = 0.0;
108*77c1e3ccSAndroid Build Coastguard Worker const int use_hbd = frame->flags & YV12_FLAG_HIGHBITDEPTH;
109*77c1e3ccSAndroid Build Coastguard Worker
110*77c1e3ccSAndroid Build Coastguard Worker // Loop through each block.
111*77c1e3ccSAndroid Build Coastguard Worker for (row = 0; row < frame->y_height / block_h; ++row) {
112*77c1e3ccSAndroid Build Coastguard Worker for (col = 0; col < frame->y_width / block_w; ++col) {
113*77c1e3ccSAndroid Build Coastguard Worker struct buf_2d buf;
114*77c1e3ccSAndroid Build Coastguard Worker const int row_offset_y = row * block_h;
115*77c1e3ccSAndroid Build Coastguard Worker const int col_offset_y = col * block_w;
116*77c1e3ccSAndroid Build Coastguard Worker
117*77c1e3ccSAndroid Build Coastguard Worker buf.buf = (uint8_t *)y_buffer + row_offset_y * y_stride + col_offset_y;
118*77c1e3ccSAndroid Build Coastguard Worker buf.stride = y_stride;
119*77c1e3ccSAndroid Build Coastguard Worker
120*77c1e3ccSAndroid Build Coastguard Worker var += av1_get_perpixel_variance(cpi, xd, &buf, block_size, AOM_PLANE_Y,
121*77c1e3ccSAndroid Build Coastguard Worker use_hbd);
122*77c1e3ccSAndroid Build Coastguard Worker var_count += 1.0;
123*77c1e3ccSAndroid Build Coastguard Worker }
124*77c1e3ccSAndroid Build Coastguard Worker }
125*77c1e3ccSAndroid Build Coastguard Worker var /= var_count;
126*77c1e3ccSAndroid Build Coastguard Worker return var;
127*77c1e3ccSAndroid Build Coastguard Worker }
128*77c1e3ccSAndroid Build Coastguard Worker
residual_frame_average_variance(AV1_COMP * cpi,const YV12_BUFFER_CONFIG * src,const YV12_BUFFER_CONFIG * ref,FULLPEL_MV * mvs)129*77c1e3ccSAndroid Build Coastguard Worker static double residual_frame_average_variance(AV1_COMP *cpi,
130*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *src,
131*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *ref,
132*77c1e3ccSAndroid Build Coastguard Worker FULLPEL_MV *mvs) {
133*77c1e3ccSAndroid Build Coastguard Worker if (ref == NULL) return frame_average_variance(cpi, src);
134*77c1e3ccSAndroid Build Coastguard Worker const BLOCK_SIZE block_size = BLOCK_16X16;
135*77c1e3ccSAndroid Build Coastguard Worker const int frame_height = src->y_height;
136*77c1e3ccSAndroid Build Coastguard Worker const int frame_width = src->y_width;
137*77c1e3ccSAndroid Build Coastguard Worker const int mb_height = block_size_high[block_size];
138*77c1e3ccSAndroid Build Coastguard Worker const int mb_width = block_size_wide[block_size];
139*77c1e3ccSAndroid Build Coastguard Worker const int mb_rows = (frame_height + mb_height - 1) / mb_height;
140*77c1e3ccSAndroid Build Coastguard Worker const int mb_cols = (frame_width + mb_width - 1) / mb_width;
141*77c1e3ccSAndroid Build Coastguard Worker const int num_planes = av1_num_planes(&cpi->common);
142*77c1e3ccSAndroid Build Coastguard Worker const int mi_h = mi_size_high_log2[block_size];
143*77c1e3ccSAndroid Build Coastguard Worker const int mi_w = mi_size_wide_log2[block_size];
144*77c1e3ccSAndroid Build Coastguard Worker assert(num_planes >= 1 && num_planes <= MAX_MB_PLANE);
145*77c1e3ccSAndroid Build Coastguard Worker
146*77c1e3ccSAndroid Build Coastguard Worker // Save input state.
147*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCK *const mb = &cpi->td.mb;
148*77c1e3ccSAndroid Build Coastguard Worker MACROBLOCKD *const mbd = &mb->e_mbd;
149*77c1e3ccSAndroid Build Coastguard Worker uint8_t *input_buffer[MAX_MB_PLANE];
150*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0; i < num_planes; i++) {
151*77c1e3ccSAndroid Build Coastguard Worker input_buffer[i] = mbd->plane[i].pre[0].buf;
152*77c1e3ccSAndroid Build Coastguard Worker }
153*77c1e3ccSAndroid Build Coastguard Worker MB_MODE_INFO **input_mb_mode_info = mbd->mi;
154*77c1e3ccSAndroid Build Coastguard Worker
155*77c1e3ccSAndroid Build Coastguard Worker bool do_motion_search = false;
156*77c1e3ccSAndroid Build Coastguard Worker if (mvs == NULL) {
157*77c1e3ccSAndroid Build Coastguard Worker do_motion_search = true;
158*77c1e3ccSAndroid Build Coastguard Worker CHECK_MEM_ERROR(&cpi->common, mvs,
159*77c1e3ccSAndroid Build Coastguard Worker (FULLPEL_MV *)aom_calloc(mb_rows * mb_cols, sizeof(*mvs)));
160*77c1e3ccSAndroid Build Coastguard Worker }
161*77c1e3ccSAndroid Build Coastguard Worker
162*77c1e3ccSAndroid Build Coastguard Worker unsigned int variance = 0;
163*77c1e3ccSAndroid Build Coastguard Worker // Perform temporal filtering block by block.
164*77c1e3ccSAndroid Build Coastguard Worker for (int mb_row = 0; mb_row < mb_rows; mb_row++) {
165*77c1e3ccSAndroid Build Coastguard Worker av1_set_mv_row_limits(&cpi->common.mi_params, &mb->mv_limits,
166*77c1e3ccSAndroid Build Coastguard Worker (mb_row << mi_h), (mb_height >> MI_SIZE_LOG2),
167*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels);
168*77c1e3ccSAndroid Build Coastguard Worker for (int mb_col = 0; mb_col < mb_cols; mb_col++) {
169*77c1e3ccSAndroid Build Coastguard Worker av1_set_mv_col_limits(&cpi->common.mi_params, &mb->mv_limits,
170*77c1e3ccSAndroid Build Coastguard Worker (mb_col << mi_w), (mb_width >> MI_SIZE_LOG2),
171*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels);
172*77c1e3ccSAndroid Build Coastguard Worker FULLPEL_MV *ref_mv = &mvs[mb_col + mb_row * mb_cols];
173*77c1e3ccSAndroid Build Coastguard Worker if (do_motion_search) {
174*77c1e3ccSAndroid Build Coastguard Worker motion_search(cpi, src, ref, block_size, mb_row, mb_col, ref_mv);
175*77c1e3ccSAndroid Build Coastguard Worker }
176*77c1e3ccSAndroid Build Coastguard Worker unsigned int mv_sse;
177*77c1e3ccSAndroid Build Coastguard Worker const unsigned int blk_var = residual_variance(
178*77c1e3ccSAndroid Build Coastguard Worker cpi, src, ref, block_size, mb_row, mb_col, *ref_mv, &mv_sse);
179*77c1e3ccSAndroid Build Coastguard Worker variance += blk_var;
180*77c1e3ccSAndroid Build Coastguard Worker }
181*77c1e3ccSAndroid Build Coastguard Worker }
182*77c1e3ccSAndroid Build Coastguard Worker
183*77c1e3ccSAndroid Build Coastguard Worker // Restore input state
184*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0; i < num_planes; i++) {
185*77c1e3ccSAndroid Build Coastguard Worker mbd->plane[i].pre[0].buf = input_buffer[i];
186*77c1e3ccSAndroid Build Coastguard Worker }
187*77c1e3ccSAndroid Build Coastguard Worker mbd->mi = input_mb_mode_info;
188*77c1e3ccSAndroid Build Coastguard Worker return (double)variance / (double)(mb_rows * mb_cols);
189*77c1e3ccSAndroid Build Coastguard Worker }
190*77c1e3ccSAndroid Build Coastguard Worker
191*77c1e3ccSAndroid Build Coastguard Worker // TODO(sdeng): Add the SIMD implementation.
highbd_unsharp_rect(const uint16_t * source,int source_stride,const uint16_t * blurred,int blurred_stride,uint16_t * dst,int dst_stride,int w,int h,double amount,int bit_depth)192*77c1e3ccSAndroid Build Coastguard Worker static inline void highbd_unsharp_rect(const uint16_t *source,
193*77c1e3ccSAndroid Build Coastguard Worker int source_stride,
194*77c1e3ccSAndroid Build Coastguard Worker const uint16_t *blurred,
195*77c1e3ccSAndroid Build Coastguard Worker int blurred_stride, uint16_t *dst,
196*77c1e3ccSAndroid Build Coastguard Worker int dst_stride, int w, int h,
197*77c1e3ccSAndroid Build Coastguard Worker double amount, int bit_depth) {
198*77c1e3ccSAndroid Build Coastguard Worker const int max_value = (1 << bit_depth) - 1;
199*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0; i < h; ++i) {
200*77c1e3ccSAndroid Build Coastguard Worker for (int j = 0; j < w; ++j) {
201*77c1e3ccSAndroid Build Coastguard Worker const double val =
202*77c1e3ccSAndroid Build Coastguard Worker (double)source[j] + amount * ((double)source[j] - (double)blurred[j]);
203*77c1e3ccSAndroid Build Coastguard Worker dst[j] = (uint16_t)clamp((int)(val + 0.5), 0, max_value);
204*77c1e3ccSAndroid Build Coastguard Worker }
205*77c1e3ccSAndroid Build Coastguard Worker source += source_stride;
206*77c1e3ccSAndroid Build Coastguard Worker blurred += blurred_stride;
207*77c1e3ccSAndroid Build Coastguard Worker dst += dst_stride;
208*77c1e3ccSAndroid Build Coastguard Worker }
209*77c1e3ccSAndroid Build Coastguard Worker }
210*77c1e3ccSAndroid Build Coastguard Worker
unsharp_rect(const uint8_t * source,int source_stride,const uint8_t * blurred,int blurred_stride,uint8_t * dst,int dst_stride,int w,int h,double amount)211*77c1e3ccSAndroid Build Coastguard Worker static inline void unsharp_rect(const uint8_t *source, int source_stride,
212*77c1e3ccSAndroid Build Coastguard Worker const uint8_t *blurred, int blurred_stride,
213*77c1e3ccSAndroid Build Coastguard Worker uint8_t *dst, int dst_stride, int w, int h,
214*77c1e3ccSAndroid Build Coastguard Worker double amount) {
215*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0; i < h; ++i) {
216*77c1e3ccSAndroid Build Coastguard Worker for (int j = 0; j < w; ++j) {
217*77c1e3ccSAndroid Build Coastguard Worker const double val =
218*77c1e3ccSAndroid Build Coastguard Worker (double)source[j] + amount * ((double)source[j] - (double)blurred[j]);
219*77c1e3ccSAndroid Build Coastguard Worker dst[j] = (uint8_t)clamp((int)(val + 0.5), 0, 255);
220*77c1e3ccSAndroid Build Coastguard Worker }
221*77c1e3ccSAndroid Build Coastguard Worker source += source_stride;
222*77c1e3ccSAndroid Build Coastguard Worker blurred += blurred_stride;
223*77c1e3ccSAndroid Build Coastguard Worker dst += dst_stride;
224*77c1e3ccSAndroid Build Coastguard Worker }
225*77c1e3ccSAndroid Build Coastguard Worker }
226*77c1e3ccSAndroid Build Coastguard Worker
unsharp(const AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * blurred,const YV12_BUFFER_CONFIG * dst,double amount)227*77c1e3ccSAndroid Build Coastguard Worker static inline void unsharp(const AV1_COMP *const cpi,
228*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *source,
229*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *blurred,
230*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *dst, double amount) {
231*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
232*77c1e3ccSAndroid Build Coastguard Worker if (cpi->common.seq_params->use_highbitdepth) {
233*77c1e3ccSAndroid Build Coastguard Worker assert(source->flags & YV12_FLAG_HIGHBITDEPTH);
234*77c1e3ccSAndroid Build Coastguard Worker assert(blurred->flags & YV12_FLAG_HIGHBITDEPTH);
235*77c1e3ccSAndroid Build Coastguard Worker assert(dst->flags & YV12_FLAG_HIGHBITDEPTH);
236*77c1e3ccSAndroid Build Coastguard Worker highbd_unsharp_rect(CONVERT_TO_SHORTPTR(source->y_buffer), source->y_stride,
237*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(blurred->y_buffer),
238*77c1e3ccSAndroid Build Coastguard Worker blurred->y_stride, CONVERT_TO_SHORTPTR(dst->y_buffer),
239*77c1e3ccSAndroid Build Coastguard Worker dst->y_stride, source->y_width, source->y_height,
240*77c1e3ccSAndroid Build Coastguard Worker amount, bit_depth);
241*77c1e3ccSAndroid Build Coastguard Worker } else {
242*77c1e3ccSAndroid Build Coastguard Worker unsharp_rect(source->y_buffer, source->y_stride, blurred->y_buffer,
243*77c1e3ccSAndroid Build Coastguard Worker blurred->y_stride, dst->y_buffer, dst->y_stride,
244*77c1e3ccSAndroid Build Coastguard Worker source->y_width, source->y_height, amount);
245*77c1e3ccSAndroid Build Coastguard Worker }
246*77c1e3ccSAndroid Build Coastguard Worker }
247*77c1e3ccSAndroid Build Coastguard Worker
248*77c1e3ccSAndroid Build Coastguard Worker // 8-tap Gaussian convolution filter with sigma = 1.0, sums to 128,
249*77c1e3ccSAndroid Build Coastguard Worker // all co-efficients must be even.
250*77c1e3ccSAndroid Build Coastguard Worker // The array is of size 9 to allow passing gauss_filter + 1 to
251*77c1e3ccSAndroid Build Coastguard Worker // _mm_loadu_si128() in prepare_coeffs_6t().
252*77c1e3ccSAndroid Build Coastguard Worker DECLARE_ALIGNED(16, static const int16_t, gauss_filter[9]) = { 0, 8, 30, 52,
253*77c1e3ccSAndroid Build Coastguard Worker 30, 8, 0, 0 };
gaussian_blur(const int bit_depth,const YV12_BUFFER_CONFIG * source,const YV12_BUFFER_CONFIG * dst)254*77c1e3ccSAndroid Build Coastguard Worker static inline void gaussian_blur(const int bit_depth,
255*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *source,
256*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *dst) {
257*77c1e3ccSAndroid Build Coastguard Worker const int block_size = BLOCK_128X128;
258*77c1e3ccSAndroid Build Coastguard Worker const int block_w = mi_size_wide[block_size] * 4;
259*77c1e3ccSAndroid Build Coastguard Worker const int block_h = mi_size_high[block_size] * 4;
260*77c1e3ccSAndroid Build Coastguard Worker const int num_cols = (source->y_width + block_w - 1) / block_w;
261*77c1e3ccSAndroid Build Coastguard Worker const int num_rows = (source->y_height + block_h - 1) / block_h;
262*77c1e3ccSAndroid Build Coastguard Worker int row, col;
263*77c1e3ccSAndroid Build Coastguard Worker
264*77c1e3ccSAndroid Build Coastguard Worker ConvolveParams conv_params = get_conv_params(0, 0, bit_depth);
265*77c1e3ccSAndroid Build Coastguard Worker InterpFilterParams filter = { .filter_ptr = gauss_filter,
266*77c1e3ccSAndroid Build Coastguard Worker .taps = 8,
267*77c1e3ccSAndroid Build Coastguard Worker .interp_filter = EIGHTTAP_REGULAR };
268*77c1e3ccSAndroid Build Coastguard Worker
269*77c1e3ccSAndroid Build Coastguard Worker for (row = 0; row < num_rows; ++row) {
270*77c1e3ccSAndroid Build Coastguard Worker for (col = 0; col < num_cols; ++col) {
271*77c1e3ccSAndroid Build Coastguard Worker const int row_offset_y = row * block_h;
272*77c1e3ccSAndroid Build Coastguard Worker const int col_offset_y = col * block_w;
273*77c1e3ccSAndroid Build Coastguard Worker
274*77c1e3ccSAndroid Build Coastguard Worker uint8_t *src_buf =
275*77c1e3ccSAndroid Build Coastguard Worker source->y_buffer + row_offset_y * source->y_stride + col_offset_y;
276*77c1e3ccSAndroid Build Coastguard Worker uint8_t *dst_buf =
277*77c1e3ccSAndroid Build Coastguard Worker dst->y_buffer + row_offset_y * dst->y_stride + col_offset_y;
278*77c1e3ccSAndroid Build Coastguard Worker
279*77c1e3ccSAndroid Build Coastguard Worker if (source->flags & YV12_FLAG_HIGHBITDEPTH) {
280*77c1e3ccSAndroid Build Coastguard Worker av1_highbd_convolve_2d_sr(
281*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(src_buf), source->y_stride,
282*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(dst_buf), dst->y_stride, block_w, block_h,
283*77c1e3ccSAndroid Build Coastguard Worker &filter, &filter, 0, 0, &conv_params, bit_depth);
284*77c1e3ccSAndroid Build Coastguard Worker } else {
285*77c1e3ccSAndroid Build Coastguard Worker av1_convolve_2d_sr(src_buf, source->y_stride, dst_buf, dst->y_stride,
286*77c1e3ccSAndroid Build Coastguard Worker block_w, block_h, &filter, &filter, 0, 0,
287*77c1e3ccSAndroid Build Coastguard Worker &conv_params);
288*77c1e3ccSAndroid Build Coastguard Worker }
289*77c1e3ccSAndroid Build Coastguard Worker }
290*77c1e3ccSAndroid Build Coastguard Worker }
291*77c1e3ccSAndroid Build Coastguard Worker }
292*77c1e3ccSAndroid Build Coastguard Worker
cal_approx_vmaf(const AV1_COMP * const cpi,double source_variance,const YV12_BUFFER_CONFIG * const source,const YV12_BUFFER_CONFIG * const sharpened)293*77c1e3ccSAndroid Build Coastguard Worker static inline double cal_approx_vmaf(
294*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMP *const cpi, double source_variance,
295*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const source,
296*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const sharpened) {
297*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
298*77c1e3ccSAndroid Build Coastguard Worker const bool cal_vmaf_neg =
299*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN;
300*77c1e3ccSAndroid Build Coastguard Worker double new_vmaf;
301*77c1e3ccSAndroid Build Coastguard Worker
302*77c1e3ccSAndroid Build Coastguard Worker aom_calc_vmaf(cpi->vmaf_info.vmaf_model, source, sharpened, bit_depth,
303*77c1e3ccSAndroid Build Coastguard Worker cal_vmaf_neg, &new_vmaf);
304*77c1e3ccSAndroid Build Coastguard Worker
305*77c1e3ccSAndroid Build Coastguard Worker const double sharpened_var = frame_average_variance(cpi, sharpened);
306*77c1e3ccSAndroid Build Coastguard Worker return source_variance / sharpened_var * (new_vmaf - kBaselineVmaf);
307*77c1e3ccSAndroid Build Coastguard Worker }
308*77c1e3ccSAndroid Build Coastguard Worker
find_best_frame_unsharp_amount_loop(const AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * const source,const YV12_BUFFER_CONFIG * const blurred,const YV12_BUFFER_CONFIG * const sharpened,double best_vmaf,const double baseline_variance,const double unsharp_amount_start,const double step_size,const int max_loop_count,const double max_amount)309*77c1e3ccSAndroid Build Coastguard Worker static double find_best_frame_unsharp_amount_loop(
310*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMP *const cpi, const YV12_BUFFER_CONFIG *const source,
311*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const blurred,
312*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const sharpened, double best_vmaf,
313*77c1e3ccSAndroid Build Coastguard Worker const double baseline_variance, const double unsharp_amount_start,
314*77c1e3ccSAndroid Build Coastguard Worker const double step_size, const int max_loop_count, const double max_amount) {
315*77c1e3ccSAndroid Build Coastguard Worker const double min_amount = 0.0;
316*77c1e3ccSAndroid Build Coastguard Worker int loop_count = 0;
317*77c1e3ccSAndroid Build Coastguard Worker double approx_vmaf = best_vmaf;
318*77c1e3ccSAndroid Build Coastguard Worker double unsharp_amount = unsharp_amount_start;
319*77c1e3ccSAndroid Build Coastguard Worker do {
320*77c1e3ccSAndroid Build Coastguard Worker best_vmaf = approx_vmaf;
321*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount += step_size;
322*77c1e3ccSAndroid Build Coastguard Worker if (unsharp_amount > max_amount || unsharp_amount < min_amount) break;
323*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, source, blurred, sharpened, unsharp_amount);
324*77c1e3ccSAndroid Build Coastguard Worker approx_vmaf = cal_approx_vmaf(cpi, baseline_variance, source, sharpened);
325*77c1e3ccSAndroid Build Coastguard Worker
326*77c1e3ccSAndroid Build Coastguard Worker loop_count++;
327*77c1e3ccSAndroid Build Coastguard Worker } while (approx_vmaf > best_vmaf && loop_count < max_loop_count);
328*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount =
329*77c1e3ccSAndroid Build Coastguard Worker approx_vmaf > best_vmaf ? unsharp_amount : unsharp_amount - step_size;
330*77c1e3ccSAndroid Build Coastguard Worker return AOMMIN(max_amount, AOMMAX(unsharp_amount, min_amount));
331*77c1e3ccSAndroid Build Coastguard Worker }
332*77c1e3ccSAndroid Build Coastguard Worker
find_best_frame_unsharp_amount(const AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * const source,const YV12_BUFFER_CONFIG * const blurred,const double unsharp_amount_start,const double step_size,const int max_loop_count,const double max_filter_amount)333*77c1e3ccSAndroid Build Coastguard Worker static double find_best_frame_unsharp_amount(
334*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMP *const cpi, const YV12_BUFFER_CONFIG *const source,
335*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const blurred, const double unsharp_amount_start,
336*77c1e3ccSAndroid Build Coastguard Worker const double step_size, const int max_loop_count,
337*77c1e3ccSAndroid Build Coastguard Worker const double max_filter_amount) {
338*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
339*77c1e3ccSAndroid Build Coastguard Worker const int width = source->y_width;
340*77c1e3ccSAndroid Build Coastguard Worker const int height = source->y_height;
341*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG sharpened;
342*77c1e3ccSAndroid Build Coastguard Worker memset(&sharpened, 0, sizeof(sharpened));
343*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(
344*77c1e3ccSAndroid Build Coastguard Worker &sharpened, width, height, source->subsampling_x, source->subsampling_y,
345*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels,
346*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
347*77c1e3ccSAndroid Build Coastguard Worker
348*77c1e3ccSAndroid Build Coastguard Worker const double baseline_variance = frame_average_variance(cpi, source);
349*77c1e3ccSAndroid Build Coastguard Worker double unsharp_amount;
350*77c1e3ccSAndroid Build Coastguard Worker if (unsharp_amount_start <= step_size) {
351*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount = find_best_frame_unsharp_amount_loop(
352*77c1e3ccSAndroid Build Coastguard Worker cpi, source, blurred, &sharpened, 0.0, baseline_variance, 0.0,
353*77c1e3ccSAndroid Build Coastguard Worker step_size, max_loop_count, max_filter_amount);
354*77c1e3ccSAndroid Build Coastguard Worker } else {
355*77c1e3ccSAndroid Build Coastguard Worker double a0 = unsharp_amount_start - step_size, a1 = unsharp_amount_start;
356*77c1e3ccSAndroid Build Coastguard Worker double v0, v1;
357*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, source, blurred, &sharpened, a0);
358*77c1e3ccSAndroid Build Coastguard Worker v0 = cal_approx_vmaf(cpi, baseline_variance, source, &sharpened);
359*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, source, blurred, &sharpened, a1);
360*77c1e3ccSAndroid Build Coastguard Worker v1 = cal_approx_vmaf(cpi, baseline_variance, source, &sharpened);
361*77c1e3ccSAndroid Build Coastguard Worker if (fabs(v0 - v1) < 0.01) {
362*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount = a0;
363*77c1e3ccSAndroid Build Coastguard Worker } else if (v0 > v1) {
364*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount = find_best_frame_unsharp_amount_loop(
365*77c1e3ccSAndroid Build Coastguard Worker cpi, source, blurred, &sharpened, v0, baseline_variance, a0,
366*77c1e3ccSAndroid Build Coastguard Worker -step_size, max_loop_count, max_filter_amount);
367*77c1e3ccSAndroid Build Coastguard Worker } else {
368*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount = find_best_frame_unsharp_amount_loop(
369*77c1e3ccSAndroid Build Coastguard Worker cpi, source, blurred, &sharpened, v1, baseline_variance, a1,
370*77c1e3ccSAndroid Build Coastguard Worker step_size, max_loop_count, max_filter_amount);
371*77c1e3ccSAndroid Build Coastguard Worker }
372*77c1e3ccSAndroid Build Coastguard Worker }
373*77c1e3ccSAndroid Build Coastguard Worker
374*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&sharpened);
375*77c1e3ccSAndroid Build Coastguard Worker return unsharp_amount;
376*77c1e3ccSAndroid Build Coastguard Worker }
377*77c1e3ccSAndroid Build Coastguard Worker
av1_vmaf_neg_preprocessing(AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * const source)378*77c1e3ccSAndroid Build Coastguard Worker void av1_vmaf_neg_preprocessing(AV1_COMP *const cpi,
379*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const source) {
380*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
381*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
382*77c1e3ccSAndroid Build Coastguard Worker const int width = source->y_width;
383*77c1e3ccSAndroid Build Coastguard Worker const int height = source->y_height;
384*77c1e3ccSAndroid Build Coastguard Worker
385*77c1e3ccSAndroid Build Coastguard Worker const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
386*77c1e3ccSAndroid Build Coastguard Worker const int layer_depth =
387*77c1e3ccSAndroid Build Coastguard Worker AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], MAX_ARF_LAYERS - 1);
388*77c1e3ccSAndroid Build Coastguard Worker const double best_frame_unsharp_amount =
389*77c1e3ccSAndroid Build Coastguard Worker get_layer_value(cpi->vmaf_info.last_frame_unsharp_amount, layer_depth);
390*77c1e3ccSAndroid Build Coastguard Worker
391*77c1e3ccSAndroid Build Coastguard Worker if (best_frame_unsharp_amount <= 0.0) return;
392*77c1e3ccSAndroid Build Coastguard Worker
393*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG blurred;
394*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred, 0, sizeof(blurred));
395*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(
396*77c1e3ccSAndroid Build Coastguard Worker &blurred, width, height, source->subsampling_x, source->subsampling_y,
397*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels,
398*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
399*77c1e3ccSAndroid Build Coastguard Worker
400*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, source, &blurred);
401*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, source, &blurred, source, best_frame_unsharp_amount);
402*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred);
403*77c1e3ccSAndroid Build Coastguard Worker }
404*77c1e3ccSAndroid Build Coastguard Worker
av1_vmaf_frame_preprocessing(AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * const source)405*77c1e3ccSAndroid Build Coastguard Worker void av1_vmaf_frame_preprocessing(AV1_COMP *const cpi,
406*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const source) {
407*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
408*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
409*77c1e3ccSAndroid Build Coastguard Worker const int width = source->y_width;
410*77c1e3ccSAndroid Build Coastguard Worker const int height = source->y_height;
411*77c1e3ccSAndroid Build Coastguard Worker
412*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG source_extended, blurred;
413*77c1e3ccSAndroid Build Coastguard Worker memset(&source_extended, 0, sizeof(source_extended));
414*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred, 0, sizeof(blurred));
415*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(
416*77c1e3ccSAndroid Build Coastguard Worker &source_extended, width, height, source->subsampling_x,
417*77c1e3ccSAndroid Build Coastguard Worker source->subsampling_y, cm->seq_params->use_highbitdepth,
418*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, 0);
419*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(
420*77c1e3ccSAndroid Build Coastguard Worker &blurred, width, height, source->subsampling_x, source->subsampling_y,
421*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels,
422*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
423*77c1e3ccSAndroid Build Coastguard Worker
424*77c1e3ccSAndroid Build Coastguard Worker av1_copy_and_extend_frame(source, &source_extended);
425*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, &source_extended, &blurred);
426*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&source_extended);
427*77c1e3ccSAndroid Build Coastguard Worker
428*77c1e3ccSAndroid Build Coastguard Worker const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
429*77c1e3ccSAndroid Build Coastguard Worker const int layer_depth =
430*77c1e3ccSAndroid Build Coastguard Worker AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], MAX_ARF_LAYERS - 1);
431*77c1e3ccSAndroid Build Coastguard Worker const double last_frame_unsharp_amount =
432*77c1e3ccSAndroid Build Coastguard Worker get_layer_value(cpi->vmaf_info.last_frame_unsharp_amount, layer_depth);
433*77c1e3ccSAndroid Build Coastguard Worker
434*77c1e3ccSAndroid Build Coastguard Worker const double best_frame_unsharp_amount = find_best_frame_unsharp_amount(
435*77c1e3ccSAndroid Build Coastguard Worker cpi, source, &blurred, last_frame_unsharp_amount, 0.05, 20, 1.01);
436*77c1e3ccSAndroid Build Coastguard Worker
437*77c1e3ccSAndroid Build Coastguard Worker cpi->vmaf_info.last_frame_unsharp_amount[layer_depth] =
438*77c1e3ccSAndroid Build Coastguard Worker best_frame_unsharp_amount;
439*77c1e3ccSAndroid Build Coastguard Worker
440*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, source, &blurred, source, best_frame_unsharp_amount);
441*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred);
442*77c1e3ccSAndroid Build Coastguard Worker }
443*77c1e3ccSAndroid Build Coastguard Worker
av1_vmaf_blk_preprocessing(AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * const source)444*77c1e3ccSAndroid Build Coastguard Worker void av1_vmaf_blk_preprocessing(AV1_COMP *const cpi,
445*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const source) {
446*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
447*77c1e3ccSAndroid Build Coastguard Worker const int width = source->y_width;
448*77c1e3ccSAndroid Build Coastguard Worker const int height = source->y_height;
449*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
450*77c1e3ccSAndroid Build Coastguard Worker const int ss_x = source->subsampling_x;
451*77c1e3ccSAndroid Build Coastguard Worker const int ss_y = source->subsampling_y;
452*77c1e3ccSAndroid Build Coastguard Worker
453*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG source_extended, blurred;
454*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred, 0, sizeof(blurred));
455*77c1e3ccSAndroid Build Coastguard Worker memset(&source_extended, 0, sizeof(source_extended));
456*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(
457*77c1e3ccSAndroid Build Coastguard Worker &blurred, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth,
458*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, 0);
459*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&source_extended, width, height, ss_x, ss_y,
460*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
461*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
462*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
463*77c1e3ccSAndroid Build Coastguard Worker
464*77c1e3ccSAndroid Build Coastguard Worker av1_copy_and_extend_frame(source, &source_extended);
465*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, &source_extended, &blurred);
466*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&source_extended);
467*77c1e3ccSAndroid Build Coastguard Worker
468*77c1e3ccSAndroid Build Coastguard Worker const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
469*77c1e3ccSAndroid Build Coastguard Worker const int layer_depth =
470*77c1e3ccSAndroid Build Coastguard Worker AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], MAX_ARF_LAYERS - 1);
471*77c1e3ccSAndroid Build Coastguard Worker const double last_frame_unsharp_amount =
472*77c1e3ccSAndroid Build Coastguard Worker get_layer_value(cpi->vmaf_info.last_frame_unsharp_amount, layer_depth);
473*77c1e3ccSAndroid Build Coastguard Worker
474*77c1e3ccSAndroid Build Coastguard Worker const double best_frame_unsharp_amount = find_best_frame_unsharp_amount(
475*77c1e3ccSAndroid Build Coastguard Worker cpi, source, &blurred, last_frame_unsharp_amount, 0.05, 20, 1.01);
476*77c1e3ccSAndroid Build Coastguard Worker
477*77c1e3ccSAndroid Build Coastguard Worker cpi->vmaf_info.last_frame_unsharp_amount[layer_depth] =
478*77c1e3ccSAndroid Build Coastguard Worker best_frame_unsharp_amount;
479*77c1e3ccSAndroid Build Coastguard Worker
480*77c1e3ccSAndroid Build Coastguard Worker const int block_size = BLOCK_64X64;
481*77c1e3ccSAndroid Build Coastguard Worker const int block_w = mi_size_wide[block_size] * 4;
482*77c1e3ccSAndroid Build Coastguard Worker const int block_h = mi_size_high[block_size] * 4;
483*77c1e3ccSAndroid Build Coastguard Worker const int num_cols = (source->y_width + block_w - 1) / block_w;
484*77c1e3ccSAndroid Build Coastguard Worker const int num_rows = (source->y_height + block_h - 1) / block_h;
485*77c1e3ccSAndroid Build Coastguard Worker double *best_unsharp_amounts =
486*77c1e3ccSAndroid Build Coastguard Worker aom_calloc(num_cols * num_rows, sizeof(*best_unsharp_amounts));
487*77c1e3ccSAndroid Build Coastguard Worker if (!best_unsharp_amounts) {
488*77c1e3ccSAndroid Build Coastguard Worker aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
489*77c1e3ccSAndroid Build Coastguard Worker "Error allocating vmaf data");
490*77c1e3ccSAndroid Build Coastguard Worker }
491*77c1e3ccSAndroid Build Coastguard Worker
492*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG source_block, blurred_block;
493*77c1e3ccSAndroid Build Coastguard Worker memset(&source_block, 0, sizeof(source_block));
494*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred_block, 0, sizeof(blurred_block));
495*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&source_block, block_w, block_h, ss_x, ss_y,
496*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
497*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
498*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
499*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&blurred_block, block_w, block_h, ss_x, ss_y,
500*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
501*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
502*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
503*77c1e3ccSAndroid Build Coastguard Worker
504*77c1e3ccSAndroid Build Coastguard Worker for (int row = 0; row < num_rows; ++row) {
505*77c1e3ccSAndroid Build Coastguard Worker for (int col = 0; col < num_cols; ++col) {
506*77c1e3ccSAndroid Build Coastguard Worker const int row_offset_y = row * block_h;
507*77c1e3ccSAndroid Build Coastguard Worker const int col_offset_y = col * block_w;
508*77c1e3ccSAndroid Build Coastguard Worker const int block_width = AOMMIN(width - col_offset_y, block_w);
509*77c1e3ccSAndroid Build Coastguard Worker const int block_height = AOMMIN(height - row_offset_y, block_h);
510*77c1e3ccSAndroid Build Coastguard Worker const int index = col + row * num_cols;
511*77c1e3ccSAndroid Build Coastguard Worker
512*77c1e3ccSAndroid Build Coastguard Worker if (cm->seq_params->use_highbitdepth) {
513*77c1e3ccSAndroid Build Coastguard Worker assert(source->flags & YV12_FLAG_HIGHBITDEPTH);
514*77c1e3ccSAndroid Build Coastguard Worker assert(blurred.flags & YV12_FLAG_HIGHBITDEPTH);
515*77c1e3ccSAndroid Build Coastguard Worker uint16_t *frame_src_buf = CONVERT_TO_SHORTPTR(source->y_buffer) +
516*77c1e3ccSAndroid Build Coastguard Worker row_offset_y * source->y_stride +
517*77c1e3ccSAndroid Build Coastguard Worker col_offset_y;
518*77c1e3ccSAndroid Build Coastguard Worker uint16_t *frame_blurred_buf = CONVERT_TO_SHORTPTR(blurred.y_buffer) +
519*77c1e3ccSAndroid Build Coastguard Worker row_offset_y * blurred.y_stride +
520*77c1e3ccSAndroid Build Coastguard Worker col_offset_y;
521*77c1e3ccSAndroid Build Coastguard Worker uint16_t *blurred_dst = CONVERT_TO_SHORTPTR(blurred_block.y_buffer);
522*77c1e3ccSAndroid Build Coastguard Worker uint16_t *src_dst = CONVERT_TO_SHORTPTR(source_block.y_buffer);
523*77c1e3ccSAndroid Build Coastguard Worker
524*77c1e3ccSAndroid Build Coastguard Worker // Copy block from source frame.
525*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0; i < block_h; ++i) {
526*77c1e3ccSAndroid Build Coastguard Worker for (int j = 0; j < block_w; ++j) {
527*77c1e3ccSAndroid Build Coastguard Worker if (i >= block_height || j >= block_width) {
528*77c1e3ccSAndroid Build Coastguard Worker src_dst[j] = 0;
529*77c1e3ccSAndroid Build Coastguard Worker blurred_dst[j] = 0;
530*77c1e3ccSAndroid Build Coastguard Worker } else {
531*77c1e3ccSAndroid Build Coastguard Worker src_dst[j] = frame_src_buf[j];
532*77c1e3ccSAndroid Build Coastguard Worker blurred_dst[j] = frame_blurred_buf[j];
533*77c1e3ccSAndroid Build Coastguard Worker }
534*77c1e3ccSAndroid Build Coastguard Worker }
535*77c1e3ccSAndroid Build Coastguard Worker frame_src_buf += source->y_stride;
536*77c1e3ccSAndroid Build Coastguard Worker frame_blurred_buf += blurred.y_stride;
537*77c1e3ccSAndroid Build Coastguard Worker src_dst += source_block.y_stride;
538*77c1e3ccSAndroid Build Coastguard Worker blurred_dst += blurred_block.y_stride;
539*77c1e3ccSAndroid Build Coastguard Worker }
540*77c1e3ccSAndroid Build Coastguard Worker } else {
541*77c1e3ccSAndroid Build Coastguard Worker uint8_t *frame_src_buf =
542*77c1e3ccSAndroid Build Coastguard Worker source->y_buffer + row_offset_y * source->y_stride + col_offset_y;
543*77c1e3ccSAndroid Build Coastguard Worker uint8_t *frame_blurred_buf =
544*77c1e3ccSAndroid Build Coastguard Worker blurred.y_buffer + row_offset_y * blurred.y_stride + col_offset_y;
545*77c1e3ccSAndroid Build Coastguard Worker uint8_t *blurred_dst = blurred_block.y_buffer;
546*77c1e3ccSAndroid Build Coastguard Worker uint8_t *src_dst = source_block.y_buffer;
547*77c1e3ccSAndroid Build Coastguard Worker
548*77c1e3ccSAndroid Build Coastguard Worker // Copy block from source frame.
549*77c1e3ccSAndroid Build Coastguard Worker for (int i = 0; i < block_h; ++i) {
550*77c1e3ccSAndroid Build Coastguard Worker for (int j = 0; j < block_w; ++j) {
551*77c1e3ccSAndroid Build Coastguard Worker if (i >= block_height || j >= block_width) {
552*77c1e3ccSAndroid Build Coastguard Worker src_dst[j] = 0;
553*77c1e3ccSAndroid Build Coastguard Worker blurred_dst[j] = 0;
554*77c1e3ccSAndroid Build Coastguard Worker } else {
555*77c1e3ccSAndroid Build Coastguard Worker src_dst[j] = frame_src_buf[j];
556*77c1e3ccSAndroid Build Coastguard Worker blurred_dst[j] = frame_blurred_buf[j];
557*77c1e3ccSAndroid Build Coastguard Worker }
558*77c1e3ccSAndroid Build Coastguard Worker }
559*77c1e3ccSAndroid Build Coastguard Worker frame_src_buf += source->y_stride;
560*77c1e3ccSAndroid Build Coastguard Worker frame_blurred_buf += blurred.y_stride;
561*77c1e3ccSAndroid Build Coastguard Worker src_dst += source_block.y_stride;
562*77c1e3ccSAndroid Build Coastguard Worker blurred_dst += blurred_block.y_stride;
563*77c1e3ccSAndroid Build Coastguard Worker }
564*77c1e3ccSAndroid Build Coastguard Worker }
565*77c1e3ccSAndroid Build Coastguard Worker
566*77c1e3ccSAndroid Build Coastguard Worker best_unsharp_amounts[index] = find_best_frame_unsharp_amount(
567*77c1e3ccSAndroid Build Coastguard Worker cpi, &source_block, &blurred_block, best_frame_unsharp_amount, 0.1, 3,
568*77c1e3ccSAndroid Build Coastguard Worker 1.5);
569*77c1e3ccSAndroid Build Coastguard Worker }
570*77c1e3ccSAndroid Build Coastguard Worker }
571*77c1e3ccSAndroid Build Coastguard Worker
572*77c1e3ccSAndroid Build Coastguard Worker // Apply best blur amounts
573*77c1e3ccSAndroid Build Coastguard Worker for (int row = 0; row < num_rows; ++row) {
574*77c1e3ccSAndroid Build Coastguard Worker for (int col = 0; col < num_cols; ++col) {
575*77c1e3ccSAndroid Build Coastguard Worker const int row_offset_y = row * block_h;
576*77c1e3ccSAndroid Build Coastguard Worker const int col_offset_y = col * block_w;
577*77c1e3ccSAndroid Build Coastguard Worker const int block_width = AOMMIN(source->y_width - col_offset_y, block_w);
578*77c1e3ccSAndroid Build Coastguard Worker const int block_height = AOMMIN(source->y_height - row_offset_y, block_h);
579*77c1e3ccSAndroid Build Coastguard Worker const int index = col + row * num_cols;
580*77c1e3ccSAndroid Build Coastguard Worker
581*77c1e3ccSAndroid Build Coastguard Worker if (cm->seq_params->use_highbitdepth) {
582*77c1e3ccSAndroid Build Coastguard Worker assert(source->flags & YV12_FLAG_HIGHBITDEPTH);
583*77c1e3ccSAndroid Build Coastguard Worker assert(blurred.flags & YV12_FLAG_HIGHBITDEPTH);
584*77c1e3ccSAndroid Build Coastguard Worker uint16_t *src_buf = CONVERT_TO_SHORTPTR(source->y_buffer) +
585*77c1e3ccSAndroid Build Coastguard Worker row_offset_y * source->y_stride + col_offset_y;
586*77c1e3ccSAndroid Build Coastguard Worker uint16_t *blurred_buf = CONVERT_TO_SHORTPTR(blurred.y_buffer) +
587*77c1e3ccSAndroid Build Coastguard Worker row_offset_y * blurred.y_stride + col_offset_y;
588*77c1e3ccSAndroid Build Coastguard Worker highbd_unsharp_rect(src_buf, source->y_stride, blurred_buf,
589*77c1e3ccSAndroid Build Coastguard Worker blurred.y_stride, src_buf, source->y_stride,
590*77c1e3ccSAndroid Build Coastguard Worker block_width, block_height,
591*77c1e3ccSAndroid Build Coastguard Worker best_unsharp_amounts[index], bit_depth);
592*77c1e3ccSAndroid Build Coastguard Worker } else {
593*77c1e3ccSAndroid Build Coastguard Worker uint8_t *src_buf =
594*77c1e3ccSAndroid Build Coastguard Worker source->y_buffer + row_offset_y * source->y_stride + col_offset_y;
595*77c1e3ccSAndroid Build Coastguard Worker uint8_t *blurred_buf =
596*77c1e3ccSAndroid Build Coastguard Worker blurred.y_buffer + row_offset_y * blurred.y_stride + col_offset_y;
597*77c1e3ccSAndroid Build Coastguard Worker unsharp_rect(src_buf, source->y_stride, blurred_buf, blurred.y_stride,
598*77c1e3ccSAndroid Build Coastguard Worker src_buf, source->y_stride, block_width, block_height,
599*77c1e3ccSAndroid Build Coastguard Worker best_unsharp_amounts[index]);
600*77c1e3ccSAndroid Build Coastguard Worker }
601*77c1e3ccSAndroid Build Coastguard Worker }
602*77c1e3ccSAndroid Build Coastguard Worker }
603*77c1e3ccSAndroid Build Coastguard Worker
604*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&source_block);
605*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred_block);
606*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred);
607*77c1e3ccSAndroid Build Coastguard Worker aom_free(best_unsharp_amounts);
608*77c1e3ccSAndroid Build Coastguard Worker }
609*77c1e3ccSAndroid Build Coastguard Worker
av1_set_mb_vmaf_rdmult_scaling(AV1_COMP * cpi)610*77c1e3ccSAndroid Build Coastguard Worker void av1_set_mb_vmaf_rdmult_scaling(AV1_COMP *cpi) {
611*77c1e3ccSAndroid Build Coastguard Worker AV1_COMMON *cm = &cpi->common;
612*77c1e3ccSAndroid Build Coastguard Worker const int y_width = cpi->source->y_width;
613*77c1e3ccSAndroid Build Coastguard Worker const int y_height = cpi->source->y_height;
614*77c1e3ccSAndroid Build Coastguard Worker const int resized_block_size = BLOCK_32X32;
615*77c1e3ccSAndroid Build Coastguard Worker const int resize_factor = 2;
616*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
617*77c1e3ccSAndroid Build Coastguard Worker const int ss_x = cpi->source->subsampling_x;
618*77c1e3ccSAndroid Build Coastguard Worker const int ss_y = cpi->source->subsampling_y;
619*77c1e3ccSAndroid Build Coastguard Worker
620*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG resized_source;
621*77c1e3ccSAndroid Build Coastguard Worker memset(&resized_source, 0, sizeof(resized_source));
622*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(
623*77c1e3ccSAndroid Build Coastguard Worker &resized_source, y_width / resize_factor, y_height / resize_factor, ss_x,
624*77c1e3ccSAndroid Build Coastguard Worker ss_y, cm->seq_params->use_highbitdepth, cpi->oxcf.border_in_pixels,
625*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
626*77c1e3ccSAndroid Build Coastguard Worker if (!av1_resize_and_extend_frame_nonnormative(
627*77c1e3ccSAndroid Build Coastguard Worker cpi->source, &resized_source, bit_depth, av1_num_planes(cm))) {
628*77c1e3ccSAndroid Build Coastguard Worker aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
629*77c1e3ccSAndroid Build Coastguard Worker "Error allocating buffers during resize");
630*77c1e3ccSAndroid Build Coastguard Worker }
631*77c1e3ccSAndroid Build Coastguard Worker
632*77c1e3ccSAndroid Build Coastguard Worker const int resized_y_width = resized_source.y_width;
633*77c1e3ccSAndroid Build Coastguard Worker const int resized_y_height = resized_source.y_height;
634*77c1e3ccSAndroid Build Coastguard Worker const int resized_block_w = mi_size_wide[resized_block_size] * 4;
635*77c1e3ccSAndroid Build Coastguard Worker const int resized_block_h = mi_size_high[resized_block_size] * 4;
636*77c1e3ccSAndroid Build Coastguard Worker const int num_cols =
637*77c1e3ccSAndroid Build Coastguard Worker (resized_y_width + resized_block_w - 1) / resized_block_w;
638*77c1e3ccSAndroid Build Coastguard Worker const int num_rows =
639*77c1e3ccSAndroid Build Coastguard Worker (resized_y_height + resized_block_h - 1) / resized_block_h;
640*77c1e3ccSAndroid Build Coastguard Worker
641*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG blurred;
642*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred, 0, sizeof(blurred));
643*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&blurred, resized_y_width, resized_y_height, ss_x,
644*77c1e3ccSAndroid Build Coastguard Worker ss_y, cm->seq_params->use_highbitdepth,
645*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
646*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
647*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, &resized_source, &blurred);
648*77c1e3ccSAndroid Build Coastguard Worker
649*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG recon;
650*77c1e3ccSAndroid Build Coastguard Worker memset(&recon, 0, sizeof(recon));
651*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&recon, resized_y_width, resized_y_height, ss_x, ss_y,
652*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
653*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
654*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
655*77c1e3ccSAndroid Build Coastguard Worker aom_yv12_copy_frame(&resized_source, &recon, 1);
656*77c1e3ccSAndroid Build Coastguard Worker
657*77c1e3ccSAndroid Build Coastguard Worker VmafContext *vmaf_context;
658*77c1e3ccSAndroid Build Coastguard Worker const bool cal_vmaf_neg =
659*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN;
660*77c1e3ccSAndroid Build Coastguard Worker aom_init_vmaf_context(&vmaf_context, cpi->vmaf_info.vmaf_model, cal_vmaf_neg);
661*77c1e3ccSAndroid Build Coastguard Worker unsigned int *sses = aom_calloc(num_rows * num_cols, sizeof(*sses));
662*77c1e3ccSAndroid Build Coastguard Worker if (!sses) {
663*77c1e3ccSAndroid Build Coastguard Worker aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
664*77c1e3ccSAndroid Build Coastguard Worker "Error allocating vmaf data");
665*77c1e3ccSAndroid Build Coastguard Worker }
666*77c1e3ccSAndroid Build Coastguard Worker
667*77c1e3ccSAndroid Build Coastguard Worker // Loop through each 'block_size' block.
668*77c1e3ccSAndroid Build Coastguard Worker for (int row = 0; row < num_rows; ++row) {
669*77c1e3ccSAndroid Build Coastguard Worker for (int col = 0; col < num_cols; ++col) {
670*77c1e3ccSAndroid Build Coastguard Worker const int index = row * num_cols + col;
671*77c1e3ccSAndroid Build Coastguard Worker const int row_offset_y = row * resized_block_h;
672*77c1e3ccSAndroid Build Coastguard Worker const int col_offset_y = col * resized_block_w;
673*77c1e3ccSAndroid Build Coastguard Worker
674*77c1e3ccSAndroid Build Coastguard Worker uint8_t *const orig_buf = resized_source.y_buffer +
675*77c1e3ccSAndroid Build Coastguard Worker row_offset_y * resized_source.y_stride +
676*77c1e3ccSAndroid Build Coastguard Worker col_offset_y;
677*77c1e3ccSAndroid Build Coastguard Worker uint8_t *const blurred_buf =
678*77c1e3ccSAndroid Build Coastguard Worker blurred.y_buffer + row_offset_y * blurred.y_stride + col_offset_y;
679*77c1e3ccSAndroid Build Coastguard Worker
680*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->fn_ptr[resized_block_size].vf(orig_buf, resized_source.y_stride,
681*77c1e3ccSAndroid Build Coastguard Worker blurred_buf, blurred.y_stride,
682*77c1e3ccSAndroid Build Coastguard Worker &sses[index]);
683*77c1e3ccSAndroid Build Coastguard Worker
684*77c1e3ccSAndroid Build Coastguard Worker uint8_t *const recon_buf =
685*77c1e3ccSAndroid Build Coastguard Worker recon.y_buffer + row_offset_y * recon.y_stride + col_offset_y;
686*77c1e3ccSAndroid Build Coastguard Worker // Set recon buf
687*77c1e3ccSAndroid Build Coastguard Worker if (cpi->common.seq_params->use_highbitdepth) {
688*77c1e3ccSAndroid Build Coastguard Worker highbd_unsharp_rect(CONVERT_TO_SHORTPTR(blurred_buf), blurred.y_stride,
689*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(blurred_buf), blurred.y_stride,
690*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(recon_buf), recon.y_stride,
691*77c1e3ccSAndroid Build Coastguard Worker resized_block_w, resized_block_h, 0.0, bit_depth);
692*77c1e3ccSAndroid Build Coastguard Worker } else {
693*77c1e3ccSAndroid Build Coastguard Worker unsharp_rect(blurred_buf, blurred.y_stride, blurred_buf,
694*77c1e3ccSAndroid Build Coastguard Worker blurred.y_stride, recon_buf, recon.y_stride,
695*77c1e3ccSAndroid Build Coastguard Worker resized_block_w, resized_block_h, 0.0);
696*77c1e3ccSAndroid Build Coastguard Worker }
697*77c1e3ccSAndroid Build Coastguard Worker
698*77c1e3ccSAndroid Build Coastguard Worker aom_read_vmaf_image(vmaf_context, &resized_source, &recon, bit_depth,
699*77c1e3ccSAndroid Build Coastguard Worker index);
700*77c1e3ccSAndroid Build Coastguard Worker
701*77c1e3ccSAndroid Build Coastguard Worker // Restore recon buf
702*77c1e3ccSAndroid Build Coastguard Worker if (cpi->common.seq_params->use_highbitdepth) {
703*77c1e3ccSAndroid Build Coastguard Worker highbd_unsharp_rect(
704*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(orig_buf), resized_source.y_stride,
705*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(orig_buf), resized_source.y_stride,
706*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(recon_buf), recon.y_stride, resized_block_w,
707*77c1e3ccSAndroid Build Coastguard Worker resized_block_h, 0.0, bit_depth);
708*77c1e3ccSAndroid Build Coastguard Worker } else {
709*77c1e3ccSAndroid Build Coastguard Worker unsharp_rect(orig_buf, resized_source.y_stride, orig_buf,
710*77c1e3ccSAndroid Build Coastguard Worker resized_source.y_stride, recon_buf, recon.y_stride,
711*77c1e3ccSAndroid Build Coastguard Worker resized_block_w, resized_block_h, 0.0);
712*77c1e3ccSAndroid Build Coastguard Worker }
713*77c1e3ccSAndroid Build Coastguard Worker }
714*77c1e3ccSAndroid Build Coastguard Worker }
715*77c1e3ccSAndroid Build Coastguard Worker aom_flush_vmaf_context(vmaf_context);
716*77c1e3ccSAndroid Build Coastguard Worker for (int row = 0; row < num_rows; ++row) {
717*77c1e3ccSAndroid Build Coastguard Worker for (int col = 0; col < num_cols; ++col) {
718*77c1e3ccSAndroid Build Coastguard Worker const int index = row * num_cols + col;
719*77c1e3ccSAndroid Build Coastguard Worker const double vmaf = aom_calc_vmaf_at_index(
720*77c1e3ccSAndroid Build Coastguard Worker vmaf_context, cpi->vmaf_info.vmaf_model, index);
721*77c1e3ccSAndroid Build Coastguard Worker const double dvmaf = kBaselineVmaf - vmaf;
722*77c1e3ccSAndroid Build Coastguard Worker
723*77c1e3ccSAndroid Build Coastguard Worker const double mse =
724*77c1e3ccSAndroid Build Coastguard Worker (double)sses[index] / (double)(resized_y_width * resized_y_height);
725*77c1e3ccSAndroid Build Coastguard Worker double weight;
726*77c1e3ccSAndroid Build Coastguard Worker const double eps = 0.01 / (num_rows * num_cols);
727*77c1e3ccSAndroid Build Coastguard Worker if (dvmaf < eps || mse < eps) {
728*77c1e3ccSAndroid Build Coastguard Worker weight = 1.0;
729*77c1e3ccSAndroid Build Coastguard Worker } else {
730*77c1e3ccSAndroid Build Coastguard Worker weight = mse / dvmaf;
731*77c1e3ccSAndroid Build Coastguard Worker }
732*77c1e3ccSAndroid Build Coastguard Worker
733*77c1e3ccSAndroid Build Coastguard Worker // Normalize it with a data fitted model.
734*77c1e3ccSAndroid Build Coastguard Worker weight = 6.0 * (1.0 - exp(-0.05 * weight)) + 0.8;
735*77c1e3ccSAndroid Build Coastguard Worker cpi->vmaf_info.rdmult_scaling_factors[index] = weight;
736*77c1e3ccSAndroid Build Coastguard Worker }
737*77c1e3ccSAndroid Build Coastguard Worker }
738*77c1e3ccSAndroid Build Coastguard Worker
739*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&resized_source);
740*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred);
741*77c1e3ccSAndroid Build Coastguard Worker aom_close_vmaf_context(vmaf_context);
742*77c1e3ccSAndroid Build Coastguard Worker aom_free(sses);
743*77c1e3ccSAndroid Build Coastguard Worker }
744*77c1e3ccSAndroid Build Coastguard Worker
av1_set_vmaf_rdmult(const AV1_COMP * const cpi,MACROBLOCK * const x,const BLOCK_SIZE bsize,const int mi_row,const int mi_col,int * const rdmult)745*77c1e3ccSAndroid Build Coastguard Worker void av1_set_vmaf_rdmult(const AV1_COMP *const cpi, MACROBLOCK *const x,
746*77c1e3ccSAndroid Build Coastguard Worker const BLOCK_SIZE bsize, const int mi_row,
747*77c1e3ccSAndroid Build Coastguard Worker const int mi_col, int *const rdmult) {
748*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
749*77c1e3ccSAndroid Build Coastguard Worker
750*77c1e3ccSAndroid Build Coastguard Worker const int bsize_base = BLOCK_64X64;
751*77c1e3ccSAndroid Build Coastguard Worker const int num_mi_w = mi_size_wide[bsize_base];
752*77c1e3ccSAndroid Build Coastguard Worker const int num_mi_h = mi_size_high[bsize_base];
753*77c1e3ccSAndroid Build Coastguard Worker const int num_cols = (cm->mi_params.mi_cols + num_mi_w - 1) / num_mi_w;
754*77c1e3ccSAndroid Build Coastguard Worker const int num_rows = (cm->mi_params.mi_rows + num_mi_h - 1) / num_mi_h;
755*77c1e3ccSAndroid Build Coastguard Worker const int num_bcols = (mi_size_wide[bsize] + num_mi_w - 1) / num_mi_w;
756*77c1e3ccSAndroid Build Coastguard Worker const int num_brows = (mi_size_high[bsize] + num_mi_h - 1) / num_mi_h;
757*77c1e3ccSAndroid Build Coastguard Worker int row, col;
758*77c1e3ccSAndroid Build Coastguard Worker double num_of_mi = 0.0;
759*77c1e3ccSAndroid Build Coastguard Worker double geom_mean_of_scale = 0.0;
760*77c1e3ccSAndroid Build Coastguard Worker
761*77c1e3ccSAndroid Build Coastguard Worker for (row = mi_row / num_mi_w;
762*77c1e3ccSAndroid Build Coastguard Worker row < num_rows && row < mi_row / num_mi_w + num_brows; ++row) {
763*77c1e3ccSAndroid Build Coastguard Worker for (col = mi_col / num_mi_h;
764*77c1e3ccSAndroid Build Coastguard Worker col < num_cols && col < mi_col / num_mi_h + num_bcols; ++col) {
765*77c1e3ccSAndroid Build Coastguard Worker const int index = row * num_cols + col;
766*77c1e3ccSAndroid Build Coastguard Worker geom_mean_of_scale += log(cpi->vmaf_info.rdmult_scaling_factors[index]);
767*77c1e3ccSAndroid Build Coastguard Worker num_of_mi += 1.0;
768*77c1e3ccSAndroid Build Coastguard Worker }
769*77c1e3ccSAndroid Build Coastguard Worker }
770*77c1e3ccSAndroid Build Coastguard Worker geom_mean_of_scale = exp(geom_mean_of_scale / num_of_mi);
771*77c1e3ccSAndroid Build Coastguard Worker
772*77c1e3ccSAndroid Build Coastguard Worker *rdmult = (int)((double)(*rdmult) * geom_mean_of_scale + 0.5);
773*77c1e3ccSAndroid Build Coastguard Worker *rdmult = AOMMAX(*rdmult, 0);
774*77c1e3ccSAndroid Build Coastguard Worker av1_set_error_per_bit(&x->errorperbit, *rdmult);
775*77c1e3ccSAndroid Build Coastguard Worker }
776*77c1e3ccSAndroid Build Coastguard Worker
777*77c1e3ccSAndroid Build Coastguard Worker // TODO(sdeng): replace them with the SIMD versions.
highbd_image_sad_c(const uint16_t * src,int src_stride,const uint16_t * ref,int ref_stride,int w,int h)778*77c1e3ccSAndroid Build Coastguard Worker static inline double highbd_image_sad_c(const uint16_t *src, int src_stride,
779*77c1e3ccSAndroid Build Coastguard Worker const uint16_t *ref, int ref_stride,
780*77c1e3ccSAndroid Build Coastguard Worker int w, int h) {
781*77c1e3ccSAndroid Build Coastguard Worker double accum = 0.0;
782*77c1e3ccSAndroid Build Coastguard Worker int i, j;
783*77c1e3ccSAndroid Build Coastguard Worker
784*77c1e3ccSAndroid Build Coastguard Worker for (i = 0; i < h; ++i) {
785*77c1e3ccSAndroid Build Coastguard Worker for (j = 0; j < w; ++j) {
786*77c1e3ccSAndroid Build Coastguard Worker double img1px = src[i * src_stride + j];
787*77c1e3ccSAndroid Build Coastguard Worker double img2px = ref[i * ref_stride + j];
788*77c1e3ccSAndroid Build Coastguard Worker
789*77c1e3ccSAndroid Build Coastguard Worker accum += fabs(img1px - img2px);
790*77c1e3ccSAndroid Build Coastguard Worker }
791*77c1e3ccSAndroid Build Coastguard Worker }
792*77c1e3ccSAndroid Build Coastguard Worker
793*77c1e3ccSAndroid Build Coastguard Worker return accum / (double)(h * w);
794*77c1e3ccSAndroid Build Coastguard Worker }
795*77c1e3ccSAndroid Build Coastguard Worker
image_sad_c(const uint8_t * src,int src_stride,const uint8_t * ref,int ref_stride,int w,int h)796*77c1e3ccSAndroid Build Coastguard Worker static inline double image_sad_c(const uint8_t *src, int src_stride,
797*77c1e3ccSAndroid Build Coastguard Worker const uint8_t *ref, int ref_stride, int w,
798*77c1e3ccSAndroid Build Coastguard Worker int h) {
799*77c1e3ccSAndroid Build Coastguard Worker double accum = 0.0;
800*77c1e3ccSAndroid Build Coastguard Worker int i, j;
801*77c1e3ccSAndroid Build Coastguard Worker
802*77c1e3ccSAndroid Build Coastguard Worker for (i = 0; i < h; ++i) {
803*77c1e3ccSAndroid Build Coastguard Worker for (j = 0; j < w; ++j) {
804*77c1e3ccSAndroid Build Coastguard Worker double img1px = src[i * src_stride + j];
805*77c1e3ccSAndroid Build Coastguard Worker double img2px = ref[i * ref_stride + j];
806*77c1e3ccSAndroid Build Coastguard Worker
807*77c1e3ccSAndroid Build Coastguard Worker accum += fabs(img1px - img2px);
808*77c1e3ccSAndroid Build Coastguard Worker }
809*77c1e3ccSAndroid Build Coastguard Worker }
810*77c1e3ccSAndroid Build Coastguard Worker
811*77c1e3ccSAndroid Build Coastguard Worker return accum / (double)(h * w);
812*77c1e3ccSAndroid Build Coastguard Worker }
813*77c1e3ccSAndroid Build Coastguard Worker
calc_vmaf_motion_score(const AV1_COMP * const cpi,const AV1_COMMON * const cm,const YV12_BUFFER_CONFIG * const cur,const YV12_BUFFER_CONFIG * const last,const YV12_BUFFER_CONFIG * const next)814*77c1e3ccSAndroid Build Coastguard Worker static double calc_vmaf_motion_score(const AV1_COMP *const cpi,
815*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm,
816*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const cur,
817*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const last,
818*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const next) {
819*77c1e3ccSAndroid Build Coastguard Worker const int y_width = cur->y_width;
820*77c1e3ccSAndroid Build Coastguard Worker const int y_height = cur->y_height;
821*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG blurred_cur, blurred_last, blurred_next;
822*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
823*77c1e3ccSAndroid Build Coastguard Worker const int ss_x = cur->subsampling_x;
824*77c1e3ccSAndroid Build Coastguard Worker const int ss_y = cur->subsampling_y;
825*77c1e3ccSAndroid Build Coastguard Worker
826*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred_cur, 0, sizeof(blurred_cur));
827*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred_last, 0, sizeof(blurred_last));
828*77c1e3ccSAndroid Build Coastguard Worker memset(&blurred_next, 0, sizeof(blurred_next));
829*77c1e3ccSAndroid Build Coastguard Worker
830*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&blurred_cur, y_width, y_height, ss_x, ss_y,
831*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
832*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
833*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
834*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&blurred_last, y_width, y_height, ss_x, ss_y,
835*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
836*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
837*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
838*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&blurred_next, y_width, y_height, ss_x, ss_y,
839*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
840*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
841*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
842*77c1e3ccSAndroid Build Coastguard Worker
843*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, cur, &blurred_cur);
844*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, last, &blurred_last);
845*77c1e3ccSAndroid Build Coastguard Worker if (next) gaussian_blur(bit_depth, next, &blurred_next);
846*77c1e3ccSAndroid Build Coastguard Worker
847*77c1e3ccSAndroid Build Coastguard Worker double motion1, motion2 = 65536.0;
848*77c1e3ccSAndroid Build Coastguard Worker if (cm->seq_params->use_highbitdepth) {
849*77c1e3ccSAndroid Build Coastguard Worker assert(blurred_cur.flags & YV12_FLAG_HIGHBITDEPTH);
850*77c1e3ccSAndroid Build Coastguard Worker assert(blurred_last.flags & YV12_FLAG_HIGHBITDEPTH);
851*77c1e3ccSAndroid Build Coastguard Worker const float scale_factor = 1.0f / (float)(1 << (bit_depth - 8));
852*77c1e3ccSAndroid Build Coastguard Worker motion1 = highbd_image_sad_c(CONVERT_TO_SHORTPTR(blurred_cur.y_buffer),
853*77c1e3ccSAndroid Build Coastguard Worker blurred_cur.y_stride,
854*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(blurred_last.y_buffer),
855*77c1e3ccSAndroid Build Coastguard Worker blurred_last.y_stride, y_width, y_height) *
856*77c1e3ccSAndroid Build Coastguard Worker scale_factor;
857*77c1e3ccSAndroid Build Coastguard Worker if (next) {
858*77c1e3ccSAndroid Build Coastguard Worker assert(blurred_next.flags & YV12_FLAG_HIGHBITDEPTH);
859*77c1e3ccSAndroid Build Coastguard Worker motion2 = highbd_image_sad_c(CONVERT_TO_SHORTPTR(blurred_cur.y_buffer),
860*77c1e3ccSAndroid Build Coastguard Worker blurred_cur.y_stride,
861*77c1e3ccSAndroid Build Coastguard Worker CONVERT_TO_SHORTPTR(blurred_next.y_buffer),
862*77c1e3ccSAndroid Build Coastguard Worker blurred_next.y_stride, y_width, y_height) *
863*77c1e3ccSAndroid Build Coastguard Worker scale_factor;
864*77c1e3ccSAndroid Build Coastguard Worker }
865*77c1e3ccSAndroid Build Coastguard Worker } else {
866*77c1e3ccSAndroid Build Coastguard Worker motion1 = image_sad_c(blurred_cur.y_buffer, blurred_cur.y_stride,
867*77c1e3ccSAndroid Build Coastguard Worker blurred_last.y_buffer, blurred_last.y_stride, y_width,
868*77c1e3ccSAndroid Build Coastguard Worker y_height);
869*77c1e3ccSAndroid Build Coastguard Worker if (next) {
870*77c1e3ccSAndroid Build Coastguard Worker motion2 = image_sad_c(blurred_cur.y_buffer, blurred_cur.y_stride,
871*77c1e3ccSAndroid Build Coastguard Worker blurred_next.y_buffer, blurred_next.y_stride,
872*77c1e3ccSAndroid Build Coastguard Worker y_width, y_height);
873*77c1e3ccSAndroid Build Coastguard Worker }
874*77c1e3ccSAndroid Build Coastguard Worker }
875*77c1e3ccSAndroid Build Coastguard Worker
876*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred_cur);
877*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred_last);
878*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&blurred_next);
879*77c1e3ccSAndroid Build Coastguard Worker
880*77c1e3ccSAndroid Build Coastguard Worker return AOMMIN(motion1, motion2);
881*77c1e3ccSAndroid Build Coastguard Worker }
882*77c1e3ccSAndroid Build Coastguard Worker
get_neighbor_frames(const AV1_COMP * const cpi,const YV12_BUFFER_CONFIG ** last,const YV12_BUFFER_CONFIG ** next)883*77c1e3ccSAndroid Build Coastguard Worker static inline void get_neighbor_frames(const AV1_COMP *const cpi,
884*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG **last,
885*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG **next) {
886*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
887*77c1e3ccSAndroid Build Coastguard Worker const GF_GROUP *gf_group = &cpi->ppi->gf_group;
888*77c1e3ccSAndroid Build Coastguard Worker const int src_index =
889*77c1e3ccSAndroid Build Coastguard Worker cm->show_frame != 0 ? 0 : gf_group->arf_src_offset[cpi->gf_frame_index];
890*77c1e3ccSAndroid Build Coastguard Worker struct lookahead_entry *last_entry = av1_lookahead_peek(
891*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->lookahead, src_index - 1, cpi->compressor_stage);
892*77c1e3ccSAndroid Build Coastguard Worker struct lookahead_entry *next_entry = av1_lookahead_peek(
893*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->lookahead, src_index + 1, cpi->compressor_stage);
894*77c1e3ccSAndroid Build Coastguard Worker *next = &next_entry->img;
895*77c1e3ccSAndroid Build Coastguard Worker *last = cm->show_frame ? cpi->last_source : &last_entry->img;
896*77c1e3ccSAndroid Build Coastguard Worker }
897*77c1e3ccSAndroid Build Coastguard Worker
898*77c1e3ccSAndroid Build Coastguard Worker // Calculates the new qindex from the VMAF motion score. This is based on the
899*77c1e3ccSAndroid Build Coastguard Worker // observation: when the motion score becomes higher, the VMAF score of the
900*77c1e3ccSAndroid Build Coastguard Worker // same source and distorted frames would become higher.
av1_get_vmaf_base_qindex(const AV1_COMP * const cpi,int current_qindex)901*77c1e3ccSAndroid Build Coastguard Worker int av1_get_vmaf_base_qindex(const AV1_COMP *const cpi, int current_qindex) {
902*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
903*77c1e3ccSAndroid Build Coastguard Worker if (cm->current_frame.frame_number == 0 || cpi->oxcf.pass == 1) {
904*77c1e3ccSAndroid Build Coastguard Worker return current_qindex;
905*77c1e3ccSAndroid Build Coastguard Worker }
906*77c1e3ccSAndroid Build Coastguard Worker const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
907*77c1e3ccSAndroid Build Coastguard Worker const int layer_depth =
908*77c1e3ccSAndroid Build Coastguard Worker AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], MAX_ARF_LAYERS - 1);
909*77c1e3ccSAndroid Build Coastguard Worker const double last_frame_ysse =
910*77c1e3ccSAndroid Build Coastguard Worker get_layer_value(cpi->vmaf_info.last_frame_ysse, layer_depth);
911*77c1e3ccSAndroid Build Coastguard Worker const double last_frame_vmaf =
912*77c1e3ccSAndroid Build Coastguard Worker get_layer_value(cpi->vmaf_info.last_frame_vmaf, layer_depth);
913*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
914*77c1e3ccSAndroid Build Coastguard Worker const double approx_sse = last_frame_ysse / (double)((1 << (bit_depth - 8)) *
915*77c1e3ccSAndroid Build Coastguard Worker (1 << (bit_depth - 8)));
916*77c1e3ccSAndroid Build Coastguard Worker const double approx_dvmaf = kBaselineVmaf - last_frame_vmaf;
917*77c1e3ccSAndroid Build Coastguard Worker const double sse_threshold =
918*77c1e3ccSAndroid Build Coastguard Worker 0.01 * cpi->source->y_width * cpi->source->y_height;
919*77c1e3ccSAndroid Build Coastguard Worker const double vmaf_threshold = 0.01;
920*77c1e3ccSAndroid Build Coastguard Worker if (approx_sse < sse_threshold || approx_dvmaf < vmaf_threshold) {
921*77c1e3ccSAndroid Build Coastguard Worker return current_qindex;
922*77c1e3ccSAndroid Build Coastguard Worker }
923*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *cur_buf = cpi->source;
924*77c1e3ccSAndroid Build Coastguard Worker if (cm->show_frame == 0) {
925*77c1e3ccSAndroid Build Coastguard Worker const int src_index = gf_group->arf_src_offset[cpi->gf_frame_index];
926*77c1e3ccSAndroid Build Coastguard Worker struct lookahead_entry *cur_entry = av1_lookahead_peek(
927*77c1e3ccSAndroid Build Coastguard Worker cpi->ppi->lookahead, src_index, cpi->compressor_stage);
928*77c1e3ccSAndroid Build Coastguard Worker cur_buf = &cur_entry->img;
929*77c1e3ccSAndroid Build Coastguard Worker }
930*77c1e3ccSAndroid Build Coastguard Worker assert(cur_buf);
931*77c1e3ccSAndroid Build Coastguard Worker
932*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *next_buf, *last_buf;
933*77c1e3ccSAndroid Build Coastguard Worker get_neighbor_frames(cpi, &last_buf, &next_buf);
934*77c1e3ccSAndroid Build Coastguard Worker assert(last_buf);
935*77c1e3ccSAndroid Build Coastguard Worker
936*77c1e3ccSAndroid Build Coastguard Worker const double motion =
937*77c1e3ccSAndroid Build Coastguard Worker calc_vmaf_motion_score(cpi, cm, cur_buf, last_buf, next_buf);
938*77c1e3ccSAndroid Build Coastguard Worker
939*77c1e3ccSAndroid Build Coastguard Worker // Get dVMAF through a data fitted model.
940*77c1e3ccSAndroid Build Coastguard Worker const double dvmaf = 26.11 * (1.0 - exp(-0.06 * motion));
941*77c1e3ccSAndroid Build Coastguard Worker const double dsse = dvmaf * approx_sse / approx_dvmaf;
942*77c1e3ccSAndroid Build Coastguard Worker
943*77c1e3ccSAndroid Build Coastguard Worker // Clamping beta to address VQ issue (aomedia:3170).
944*77c1e3ccSAndroid Build Coastguard Worker const double beta = AOMMAX(approx_sse / (dsse + approx_sse), 0.5);
945*77c1e3ccSAndroid Build Coastguard Worker const int offset =
946*77c1e3ccSAndroid Build Coastguard Worker av1_get_deltaq_offset(cm->seq_params->bit_depth, current_qindex, beta);
947*77c1e3ccSAndroid Build Coastguard Worker int qindex = current_qindex + offset;
948*77c1e3ccSAndroid Build Coastguard Worker
949*77c1e3ccSAndroid Build Coastguard Worker qindex = AOMMIN(qindex, MAXQ);
950*77c1e3ccSAndroid Build Coastguard Worker qindex = AOMMAX(qindex, MINQ);
951*77c1e3ccSAndroid Build Coastguard Worker
952*77c1e3ccSAndroid Build Coastguard Worker return qindex;
953*77c1e3ccSAndroid Build Coastguard Worker }
954*77c1e3ccSAndroid Build Coastguard Worker
cal_approx_score(AV1_COMP * const cpi,double src_variance,double new_variance,double src_score,const YV12_BUFFER_CONFIG * const src,const YV12_BUFFER_CONFIG * const recon_sharpened)955*77c1e3ccSAndroid Build Coastguard Worker static inline double cal_approx_score(
956*77c1e3ccSAndroid Build Coastguard Worker AV1_COMP *const cpi, double src_variance, double new_variance,
957*77c1e3ccSAndroid Build Coastguard Worker double src_score, const YV12_BUFFER_CONFIG *const src,
958*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const recon_sharpened) {
959*77c1e3ccSAndroid Build Coastguard Worker double score;
960*77c1e3ccSAndroid Build Coastguard Worker const uint32_t bit_depth = cpi->td.mb.e_mbd.bd;
961*77c1e3ccSAndroid Build Coastguard Worker const bool cal_vmaf_neg =
962*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN;
963*77c1e3ccSAndroid Build Coastguard Worker aom_calc_vmaf(cpi->vmaf_info.vmaf_model, src, recon_sharpened, bit_depth,
964*77c1e3ccSAndroid Build Coastguard Worker cal_vmaf_neg, &score);
965*77c1e3ccSAndroid Build Coastguard Worker return src_variance / new_variance * (score - src_score);
966*77c1e3ccSAndroid Build Coastguard Worker }
967*77c1e3ccSAndroid Build Coastguard Worker
find_best_frame_unsharp_amount_loop_neg(AV1_COMP * const cpi,double src_variance,double base_score,const YV12_BUFFER_CONFIG * const src,const YV12_BUFFER_CONFIG * const recon,const YV12_BUFFER_CONFIG * const ref,const YV12_BUFFER_CONFIG * const src_blurred,const YV12_BUFFER_CONFIG * const recon_blurred,const YV12_BUFFER_CONFIG * const src_sharpened,const YV12_BUFFER_CONFIG * const recon_sharpened,FULLPEL_MV * mvs,double best_score,const double unsharp_amount_start,const double step_size,const int max_loop_count,const double max_amount)968*77c1e3ccSAndroid Build Coastguard Worker static double find_best_frame_unsharp_amount_loop_neg(
969*77c1e3ccSAndroid Build Coastguard Worker AV1_COMP *const cpi, double src_variance, double base_score,
970*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const src, const YV12_BUFFER_CONFIG *const recon,
971*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const ref,
972*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const src_blurred,
973*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const recon_blurred,
974*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const src_sharpened,
975*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const recon_sharpened, FULLPEL_MV *mvs,
976*77c1e3ccSAndroid Build Coastguard Worker double best_score, const double unsharp_amount_start,
977*77c1e3ccSAndroid Build Coastguard Worker const double step_size, const int max_loop_count, const double max_amount) {
978*77c1e3ccSAndroid Build Coastguard Worker const double min_amount = 0.0;
979*77c1e3ccSAndroid Build Coastguard Worker int loop_count = 0;
980*77c1e3ccSAndroid Build Coastguard Worker double approx_score = best_score;
981*77c1e3ccSAndroid Build Coastguard Worker double unsharp_amount = unsharp_amount_start;
982*77c1e3ccSAndroid Build Coastguard Worker
983*77c1e3ccSAndroid Build Coastguard Worker do {
984*77c1e3ccSAndroid Build Coastguard Worker best_score = approx_score;
985*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount += step_size;
986*77c1e3ccSAndroid Build Coastguard Worker if (unsharp_amount > max_amount || unsharp_amount < min_amount) break;
987*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, recon, recon_blurred, recon_sharpened, unsharp_amount);
988*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, src, src_blurred, src_sharpened, unsharp_amount);
989*77c1e3ccSAndroid Build Coastguard Worker const double new_variance =
990*77c1e3ccSAndroid Build Coastguard Worker residual_frame_average_variance(cpi, src_sharpened, ref, mvs);
991*77c1e3ccSAndroid Build Coastguard Worker approx_score = cal_approx_score(cpi, src_variance, new_variance, base_score,
992*77c1e3ccSAndroid Build Coastguard Worker src, recon_sharpened);
993*77c1e3ccSAndroid Build Coastguard Worker
994*77c1e3ccSAndroid Build Coastguard Worker loop_count++;
995*77c1e3ccSAndroid Build Coastguard Worker } while (approx_score > best_score && loop_count < max_loop_count);
996*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount =
997*77c1e3ccSAndroid Build Coastguard Worker approx_score > best_score ? unsharp_amount : unsharp_amount - step_size;
998*77c1e3ccSAndroid Build Coastguard Worker
999*77c1e3ccSAndroid Build Coastguard Worker return AOMMIN(max_amount, AOMMAX(unsharp_amount, min_amount));
1000*77c1e3ccSAndroid Build Coastguard Worker }
1001*77c1e3ccSAndroid Build Coastguard Worker
find_best_frame_unsharp_amount_neg(AV1_COMP * const cpi,const YV12_BUFFER_CONFIG * const src,const YV12_BUFFER_CONFIG * const recon,const YV12_BUFFER_CONFIG * const ref,double base_score,const double unsharp_amount_start,const double step_size,const int max_loop_count,const double max_filter_amount)1002*77c1e3ccSAndroid Build Coastguard Worker static double find_best_frame_unsharp_amount_neg(
1003*77c1e3ccSAndroid Build Coastguard Worker AV1_COMP *const cpi, const YV12_BUFFER_CONFIG *const src,
1004*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *const recon, const YV12_BUFFER_CONFIG *const ref,
1005*77c1e3ccSAndroid Build Coastguard Worker double base_score, const double unsharp_amount_start,
1006*77c1e3ccSAndroid Build Coastguard Worker const double step_size, const int max_loop_count,
1007*77c1e3ccSAndroid Build Coastguard Worker const double max_filter_amount) {
1008*77c1e3ccSAndroid Build Coastguard Worker FULLPEL_MV *mvs = NULL;
1009*77c1e3ccSAndroid Build Coastguard Worker const double src_variance =
1010*77c1e3ccSAndroid Build Coastguard Worker residual_frame_average_variance(cpi, src, ref, mvs);
1011*77c1e3ccSAndroid Build Coastguard Worker
1012*77c1e3ccSAndroid Build Coastguard Worker const AV1_COMMON *const cm = &cpi->common;
1013*77c1e3ccSAndroid Build Coastguard Worker const int width = recon->y_width;
1014*77c1e3ccSAndroid Build Coastguard Worker const int height = recon->y_height;
1015*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
1016*77c1e3ccSAndroid Build Coastguard Worker const int ss_x = recon->subsampling_x;
1017*77c1e3ccSAndroid Build Coastguard Worker const int ss_y = recon->subsampling_y;
1018*77c1e3ccSAndroid Build Coastguard Worker
1019*77c1e3ccSAndroid Build Coastguard Worker YV12_BUFFER_CONFIG src_blurred, recon_blurred, src_sharpened, recon_sharpened;
1020*77c1e3ccSAndroid Build Coastguard Worker memset(&recon_sharpened, 0, sizeof(recon_sharpened));
1021*77c1e3ccSAndroid Build Coastguard Worker memset(&src_sharpened, 0, sizeof(src_sharpened));
1022*77c1e3ccSAndroid Build Coastguard Worker memset(&recon_blurred, 0, sizeof(recon_blurred));
1023*77c1e3ccSAndroid Build Coastguard Worker memset(&src_blurred, 0, sizeof(src_blurred));
1024*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&recon_sharpened, width, height, ss_x, ss_y,
1025*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
1026*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
1027*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
1028*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&src_sharpened, width, height, ss_x, ss_y,
1029*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
1030*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
1031*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
1032*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(&recon_blurred, width, height, ss_x, ss_y,
1033*77c1e3ccSAndroid Build Coastguard Worker cm->seq_params->use_highbitdepth,
1034*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels,
1035*77c1e3ccSAndroid Build Coastguard Worker cm->features.byte_alignment, false, 0);
1036*77c1e3ccSAndroid Build Coastguard Worker aom_alloc_frame_buffer(
1037*77c1e3ccSAndroid Build Coastguard Worker &src_blurred, width, height, ss_x, ss_y, cm->seq_params->use_highbitdepth,
1038*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.border_in_pixels, cm->features.byte_alignment, false, 0);
1039*77c1e3ccSAndroid Build Coastguard Worker
1040*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, recon, &recon_blurred);
1041*77c1e3ccSAndroid Build Coastguard Worker gaussian_blur(bit_depth, src, &src_blurred);
1042*77c1e3ccSAndroid Build Coastguard Worker
1043*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, recon, &recon_blurred, &recon_sharpened, unsharp_amount_start);
1044*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, src, &src_blurred, &src_sharpened, unsharp_amount_start);
1045*77c1e3ccSAndroid Build Coastguard Worker const double variance_start =
1046*77c1e3ccSAndroid Build Coastguard Worker residual_frame_average_variance(cpi, &src_sharpened, ref, mvs);
1047*77c1e3ccSAndroid Build Coastguard Worker const double score_start = cal_approx_score(
1048*77c1e3ccSAndroid Build Coastguard Worker cpi, src_variance, variance_start, base_score, src, &recon_sharpened);
1049*77c1e3ccSAndroid Build Coastguard Worker
1050*77c1e3ccSAndroid Build Coastguard Worker const double unsharp_amount_next = unsharp_amount_start + step_size;
1051*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, recon, &recon_blurred, &recon_sharpened, unsharp_amount_next);
1052*77c1e3ccSAndroid Build Coastguard Worker unsharp(cpi, src, &src_blurred, &src_sharpened, unsharp_amount_next);
1053*77c1e3ccSAndroid Build Coastguard Worker const double variance_next =
1054*77c1e3ccSAndroid Build Coastguard Worker residual_frame_average_variance(cpi, &src_sharpened, ref, mvs);
1055*77c1e3ccSAndroid Build Coastguard Worker const double score_next = cal_approx_score(cpi, src_variance, variance_next,
1056*77c1e3ccSAndroid Build Coastguard Worker base_score, src, &recon_sharpened);
1057*77c1e3ccSAndroid Build Coastguard Worker
1058*77c1e3ccSAndroid Build Coastguard Worker double unsharp_amount;
1059*77c1e3ccSAndroid Build Coastguard Worker if (score_next > score_start) {
1060*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount = find_best_frame_unsharp_amount_loop_neg(
1061*77c1e3ccSAndroid Build Coastguard Worker cpi, src_variance, base_score, src, recon, ref, &src_blurred,
1062*77c1e3ccSAndroid Build Coastguard Worker &recon_blurred, &src_sharpened, &recon_sharpened, mvs, score_next,
1063*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount_next, step_size, max_loop_count, max_filter_amount);
1064*77c1e3ccSAndroid Build Coastguard Worker } else {
1065*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount = find_best_frame_unsharp_amount_loop_neg(
1066*77c1e3ccSAndroid Build Coastguard Worker cpi, src_variance, base_score, src, recon, ref, &src_blurred,
1067*77c1e3ccSAndroid Build Coastguard Worker &recon_blurred, &src_sharpened, &recon_sharpened, mvs, score_start,
1068*77c1e3ccSAndroid Build Coastguard Worker unsharp_amount_start, -step_size, max_loop_count, max_filter_amount);
1069*77c1e3ccSAndroid Build Coastguard Worker }
1070*77c1e3ccSAndroid Build Coastguard Worker
1071*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&recon_sharpened);
1072*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&src_sharpened);
1073*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&recon_blurred);
1074*77c1e3ccSAndroid Build Coastguard Worker aom_free_frame_buffer(&src_blurred);
1075*77c1e3ccSAndroid Build Coastguard Worker aom_free(mvs);
1076*77c1e3ccSAndroid Build Coastguard Worker return unsharp_amount;
1077*77c1e3ccSAndroid Build Coastguard Worker }
1078*77c1e3ccSAndroid Build Coastguard Worker
av1_update_vmaf_curve(AV1_COMP * cpi)1079*77c1e3ccSAndroid Build Coastguard Worker void av1_update_vmaf_curve(AV1_COMP *cpi) {
1080*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *source = cpi->source;
1081*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *recon = &cpi->common.cur_frame->buf;
1082*77c1e3ccSAndroid Build Coastguard Worker const int bit_depth = cpi->td.mb.e_mbd.bd;
1083*77c1e3ccSAndroid Build Coastguard Worker const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
1084*77c1e3ccSAndroid Build Coastguard Worker const int layer_depth =
1085*77c1e3ccSAndroid Build Coastguard Worker AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], MAX_ARF_LAYERS - 1);
1086*77c1e3ccSAndroid Build Coastguard Worker double base_score;
1087*77c1e3ccSAndroid Build Coastguard Worker const bool cal_vmaf_neg =
1088*77c1e3ccSAndroid Build Coastguard Worker cpi->oxcf.tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN;
1089*77c1e3ccSAndroid Build Coastguard Worker aom_calc_vmaf(cpi->vmaf_info.vmaf_model, source, recon, bit_depth,
1090*77c1e3ccSAndroid Build Coastguard Worker cal_vmaf_neg, &base_score);
1091*77c1e3ccSAndroid Build Coastguard Worker cpi->vmaf_info.last_frame_vmaf[layer_depth] = base_score;
1092*77c1e3ccSAndroid Build Coastguard Worker if (cpi->common.seq_params->use_highbitdepth) {
1093*77c1e3ccSAndroid Build Coastguard Worker assert(source->flags & YV12_FLAG_HIGHBITDEPTH);
1094*77c1e3ccSAndroid Build Coastguard Worker assert(recon->flags & YV12_FLAG_HIGHBITDEPTH);
1095*77c1e3ccSAndroid Build Coastguard Worker cpi->vmaf_info.last_frame_ysse[layer_depth] =
1096*77c1e3ccSAndroid Build Coastguard Worker (double)aom_highbd_get_y_sse(source, recon);
1097*77c1e3ccSAndroid Build Coastguard Worker } else {
1098*77c1e3ccSAndroid Build Coastguard Worker cpi->vmaf_info.last_frame_ysse[layer_depth] =
1099*77c1e3ccSAndroid Build Coastguard Worker (double)aom_get_y_sse(source, recon);
1100*77c1e3ccSAndroid Build Coastguard Worker }
1101*77c1e3ccSAndroid Build Coastguard Worker
1102*77c1e3ccSAndroid Build Coastguard Worker if (cpi->oxcf.tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN) {
1103*77c1e3ccSAndroid Build Coastguard Worker const YV12_BUFFER_CONFIG *last, *next;
1104*77c1e3ccSAndroid Build Coastguard Worker get_neighbor_frames(cpi, &last, &next);
1105*77c1e3ccSAndroid Build Coastguard Worker double best_unsharp_amount_start =
1106*77c1e3ccSAndroid Build Coastguard Worker get_layer_value(cpi->vmaf_info.last_frame_unsharp_amount, layer_depth);
1107*77c1e3ccSAndroid Build Coastguard Worker const int max_loop_count = 5;
1108*77c1e3ccSAndroid Build Coastguard Worker cpi->vmaf_info.last_frame_unsharp_amount[layer_depth] =
1109*77c1e3ccSAndroid Build Coastguard Worker find_best_frame_unsharp_amount_neg(cpi, source, recon, last, base_score,
1110*77c1e3ccSAndroid Build Coastguard Worker best_unsharp_amount_start, 0.025,
1111*77c1e3ccSAndroid Build Coastguard Worker max_loop_count, 1.01);
1112*77c1e3ccSAndroid Build Coastguard Worker }
1113*77c1e3ccSAndroid Build Coastguard Worker }
1114