Add a SB AQ mode for all intra frame perceptual quality Allow the codec to offset QPs on superblock basis, based on the relative variance metric after Wiener filter. Change-Id: I2838a0c87a841c542742727b4899ca58514cabe1
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index b998c6d..136a5db 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c
@@ -248,6 +248,7 @@ // Delta-q modulation based on variance av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, sb_size); + const int delta_q_res = delta_q_info->delta_q_res; int current_qindex = cm->quant_params.base_qindex; if (cpi->oxcf.q_cfg.deltaq_mode == DELTA_Q_PERCEPTUAL) { if (DELTA_Q_PERCEPTUAL_MODULATION == 1) { @@ -267,9 +268,12 @@ // Setup deltaq based on tpl stats current_qindex = av1_get_q_for_deltaq_objective(cpi, sb_size, mi_row, mi_col); + } else if (cpi->oxcf.q_cfg.deltaq_mode == DELTA_Q_PERCEPTUAL_AI) { + current_qindex = av1_get_sbq_perceptual_ai(cpi, sb_size, mi_row, mi_col); + current_qindex = + clamp(current_qindex, delta_q_res, 256 - delta_q_info->delta_q_res); } - const int delta_q_res = delta_q_info->delta_q_res; // Right now deltaq only works with tpl model. So if tpl is disabled, we set // the current_qindex to base_qindex. if (cpi->oxcf.algo_cfg.enable_tpl_model && @@ -1395,6 +1399,8 @@ cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_OBJECTIVE; else if (deltaq_mode == DELTA_Q_PERCEPTUAL) cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_PERCEPTUAL; + else if (deltaq_mode == DELTA_Q_PERCEPTUAL_AI) + cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_PERCEPTUAL; // Set delta_q_present_flag before it is used for the first time cm->delta_q_info.delta_lf_res = DEFAULT_DELTA_LF_RES; cm->delta_q_info.delta_q_present_flag = deltaq_mode != NO_DELTA_Q;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index e18c943..ce9fdcc 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -3212,6 +3212,49 @@ cpi->norm_wiener_variance = AOMMAX(1, cpi->norm_wiener_variance); } +int av1_get_sbq_perceptual_ai(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row, + int mi_col) { + AV1_COMMON *const cm = &cpi->common; + const int mi_wide = mi_size_wide[bsize]; + const int mi_high = mi_size_high[bsize]; + const int base_qindex = cm->quant_params.base_qindex; + + const int mi_step = mi_size_wide[BLOCK_16X16]; + int64_t sb_wiener_var; + int mb_stride = cpi->frame_info.mb_cols; + int mb_count = 0; + int mb_wiener_var[64]; + + for (int row = mi_row; row < mi_row + mi_high; row += mi_step) { + for (int col = mi_col; col < mi_col + mi_wide; col += mi_step) { + if (row >= cm->mi_params.mi_rows || col >= cm->mi_params.mi_cols) + continue; + + mb_wiener_var[mb_count] = + (int)cpi->mb_wiener_variance[(row / mi_step) * mb_stride + + (col / mi_step)]; + ++mb_count; + } + } + qsort(mb_wiener_var, mb_count - 1, sizeof(*mb_wiener_var), qsort_comp); + + sb_wiener_var = mb_wiener_var[mb_count / 2]; + sb_wiener_var = AOMMAX(1, sb_wiener_var); + + int offset = 0; + double beta = (double)cpi->norm_wiener_variance / sb_wiener_var; + offset = av1_get_deltaq_offset(cm->seq_params->bit_depth, base_qindex, beta); + const DeltaQInfo *const delta_q_info = &cm->delta_q_info; + offset = AOMMIN(offset, delta_q_info->delta_q_res * 9 - 1); + offset = AOMMAX(offset, -delta_q_info->delta_q_res * 9 + 1); + int qindex = cm->quant_params.base_qindex + offset; + qindex = AOMMIN(qindex, MAXQ); + qindex = AOMMAX(qindex, MINQ); + if (base_qindex > MINQ) qindex = AOMMAX(qindex, MINQ + 1); + + return qindex; +} + extern void av1_print_frame_contexts(const FRAME_CONTEXT *fc, const char *filename);
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index d694753..fe9d76e 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -3159,6 +3159,9 @@ void av1_update_frame_size(AV1_COMP *cpi); +int av1_get_sbq_perceptual_ai(AV1_COMP *const cpi, BLOCK_SIZE bsize, int mi_row, + int mi_col); + #if CONFIG_FRAME_PARALLEL_ENCODE typedef struct { int pyr_level;