From aec12b097630b9751bcf33306b4f4291c6b98b67 Mon Sep 17 00:00:00 2001 From: Jingning Han Date: Fri, 15 Mar 2019 11:42:39 -0700 Subject: [PATCH] Setup AQ mode for perceptual quality Adapt the quantization to provide higher quality at smooth regions where the Wiener variance is smaller. Change-Id: Ibfd594d1de2ba34d2440d0aa7991b0fdac057ea5 --- vp9/encoder/vp9_encodeframe.c | 26 ++++++++++++++++---------- vp9/encoder/vp9_segmentation.c | 41 +++++++++++++++++++++++++++++++++++++++++ vp9/encoder/vp9_segmentation.h | 3 +++ 3 files changed, 60 insertions(+), 10 deletions(-) diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 0141b48..414551a 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -3594,7 +3594,7 @@ static int wiener_var_rdmult(VP9_COMP *cpi, BLOCK_SIZE bsize, int mi_row, wiener_variance += cpi->mb_wiener_variance[row * cm->mb_cols + col]; kmeans_data = &cpi->kmeans_data_arr[cpi->kmeans_data_size++]; - kmeans_data->value = log(1 + wiener_variance); + kmeans_data->value = log(1.0 + wiener_variance) / log(2.0); kmeans_data->pos = mi_row * cpi->kmeans_data_stride + mi_col; if (wiener_variance) wiener_variance /= @@ -5874,17 +5874,23 @@ static void encode_frame_internal(VP9_COMP *cpi) { } // Frame segmentation - if (cpi->sf.enable_wiener_variance && cm->show_frame) { - int mi_row, mi_col; - cpi->kmeans_data_size = 0; - cpi->kmeans_ctr_num = 5; + if (cpi->sf.enable_wiener_variance) { + vp9_disable_segmentation(&cm->seg); + if (cm->show_frame) { + int mi_row, mi_col; + cpi->kmeans_data_size = 0; + cpi->kmeans_ctr_num = 5; - for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MI_BLOCK_SIZE) - for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE) - wiener_var_rdmult(cpi, BLOCK_64X64, mi_row, mi_col, cpi->rd.RDMULT); + for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MI_BLOCK_SIZE) + for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE) + wiener_var_rdmult(cpi, BLOCK_64X64, mi_row, mi_col, cpi->rd.RDMULT); - vp9_kmeans(cpi->kmeans_ctr_ls, cpi->kmeans_boundary_ls, cpi->kmeans_ctr_num, - cpi->kmeans_data_arr, cpi->kmeans_data_size); + vp9_kmeans(cpi->kmeans_ctr_ls, cpi->kmeans_boundary_ls, + cpi->kmeans_ctr_num, cpi->kmeans_data_arr, + cpi->kmeans_data_size); + + vp9_perceptual_aq_mode_setup(cpi, &cm->seg); + } } { diff --git a/vp9/encoder/vp9_segmentation.c b/vp9/encoder/vp9_segmentation.c index 812d3fc..846ee3b 100644 --- a/vp9/encoder/vp9_segmentation.c +++ b/vp9/encoder/vp9_segmentation.c @@ -9,6 +9,7 @@ */ #include +#include #include "vpx_mem/vpx_mem.h" @@ -59,6 +60,46 @@ void vp9_psnr_aq_mode_setup(struct segmentation *seg) { } } +void vp9_perceptual_aq_mode_setup(struct VP9_COMP *cpi, + struct segmentation *seg) { + const VP9_COMMON *cm = &cpi->common; + const int seg_counts = cpi->kmeans_ctr_num; + const int base_qindex = cm->base_qindex; + const double base_qstep = vp9_convert_qindex_to_q(base_qindex, cm->bit_depth); + const double mid_ctr = cpi->kmeans_ctr_ls[seg_counts / 2]; + const double var_diff_scale = 8.0; + int i; + + assert(seg_counts <= MAX_SEGMENTS); + + vp9_enable_segmentation(seg); + vp9_clearall_segfeatures(seg); + seg->abs_delta = SEGMENT_DELTADATA; + + for (i = 0; i < seg_counts / 2; ++i) { + double wiener_var_diff = mid_ctr - cpi->kmeans_ctr_ls[i]; + double target_qstep = base_qstep / (1.0 + wiener_var_diff / var_diff_scale); + int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth); + assert(wiener_var_diff >= 0.0); + + vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex); + vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); + } + + vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, 0); + vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); + + for (; i < seg_counts; ++i) { + double wiener_var_diff = cpi->kmeans_ctr_ls[i] - mid_ctr; + double target_qstep = base_qstep * (1.0 + wiener_var_diff / var_diff_scale); + int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth); + assert(wiener_var_diff >= 0.0); + + vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex); + vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); + } +} + // Based on set of segment counts calculate a probability tree static void calc_segtree_probs(int *segcounts, vpx_prob *segment_tree_probs) { // Work out probabilities of each segment diff --git a/vp9/encoder/vp9_segmentation.h b/vp9/encoder/vp9_segmentation.h index aa34dc8..9404c38 100644 --- a/vp9/encoder/vp9_segmentation.h +++ b/vp9/encoder/vp9_segmentation.h @@ -28,6 +28,9 @@ void vp9_clear_segdata(struct segmentation *seg, int segment_id, void vp9_psnr_aq_mode_setup(struct segmentation *seg); +void vp9_perceptual_aq_mode_setup(struct VP9_COMP *cpi, + struct segmentation *seg); + // The values given for each segment can be either deltas (from the default // value chosen for the frame) or absolute values. // -- 2.7.4