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;