From c297fd006315f53d9e01d1915a7410fb8f03d56a Mon Sep 17 00:00:00 2001 From: Thomas <thdavies@cisco.com> Date: Tue, 23 Feb 2016 13:31:18 +0000 Subject: [PATCH] Add quantisation matrix range parameters. Change-Id: I25911ea7666465ff19821b07e20c26586e88401c --- vp10/common/onyxc_int.h | 2 ++ vp10/common/quant_common.c | 10 +++---- vp10/common/quant_common.h | 14 ++++----- vp10/decoder/decodeframe.c | 37 +++++++++++++++--------- vp10/encoder/bitstream.c | 4 +++ vp10/encoder/encoder.c | 2 ++ vp10/encoder/encoder.h | 4 +++ vp10/encoder/quantize.c | 10 +++++-- vp10/vp10_cx_iface.c | 58 ++++++++++++++++++++++++++------------ vpx/vp8cx.h | 33 ++++++++++++++++++++++ vpxenc.c | 44 ++++++++++++++++------------- 11 files changed, 152 insertions(+), 66 deletions(-) diff --git a/vp10/common/onyxc_int.h b/vp10/common/onyxc_int.h index c17de2c60c..63cbf1942f 100644 --- a/vp10/common/onyxc_int.h +++ b/vp10/common/onyxc_int.h @@ -212,6 +212,8 @@ typedef struct VP10Common { qm_val_t *uv_qmatrix[MAX_SEGMENTS][2][TX_SIZES]; int using_qmatrix; + int min_qmlevel; + int max_qmlevel; #endif /* We allocate a MODE_INFO struct for each macroblock, together with diff --git a/vp10/common/quant_common.c b/vp10/common/quant_common.c index 8895d51a77..f993dd2cb8 100644 --- a/vp10/common/quant_common.c +++ b/vp10/common/quant_common.c @@ -212,15 +212,13 @@ int vp10_get_qindex(const struct segmentation *seg, int segment_id, } #if CONFIG_AOM_QM -qm_val_t* aom_iqmatrix(VP10_COMMON* cm, int qindex, int is_chroma, +qm_val_t* aom_iqmatrix(VP10_COMMON* cm, int qmlevel, int is_chroma, int log2sizem2, int is_intra) { - int scaled_q_index = aom_get_qmlevel(qindex); - return &cm->giqmatrix[scaled_q_index][!!is_chroma][!!is_intra][log2sizem2][0]; + return &cm->giqmatrix[qmlevel][!!is_chroma][!!is_intra][log2sizem2][0]; } -qm_val_t* aom_qmatrix(VP10_COMMON* cm, int qindex, int is_chroma, +qm_val_t* aom_qmatrix(VP10_COMMON* cm, int qmlevel, int is_chroma, int log2sizem2, int is_intra) { - int scaled_q_index = aom_get_qmlevel(qindex); - return &cm->gqmatrix[scaled_q_index][!!is_chroma][!!is_intra][log2sizem2][0]; + return &cm->gqmatrix[qmlevel][!!is_chroma][!!is_intra][log2sizem2][0]; } static uint16_t diff --git a/vp10/common/quant_common.h b/vp10/common/quant_common.h index c968908555..be71861439 100644 --- a/vp10/common/quant_common.h +++ b/vp10/common/quant_common.h @@ -25,12 +25,13 @@ extern "C" { #define QINDEX_BITS 8 #if CONFIG_AOM_QM // Total number of QM sets stored -#define NUM_QM_LEVELS 16 +#define QM_LEVEL_BITS 4 +#define NUM_QM_LEVELS (1 << QM_LEVEL_BITS) /* Offset into the list of QMs. Actual number of levels used is (NUM_QM_LEVELS-AOM_QM_OFFSET) Lower value of AOM_QM_OFFSET implies more heavily weighted matrices.*/ -#define AOM_QM_FIRST 8 -#define AOM_QM_LAST NUM_QM_LEVELS +#define DEFAULT_QM_FIRST (NUM_QM_LEVELS / 2) +#define DEFAULT_QM_LAST (NUM_QM_LEVELS - 1) #endif struct VP10Common; @@ -43,10 +44,9 @@ int vp10_get_qindex(const struct segmentation *seg, int segment_id, #if CONFIG_AOM_QM // Reduce the large number of quantizers to a smaller number of levels for which // different matrices may be defined -static inline int aom_get_qmlevel(int qindex) { - int qmlevel = - (qindex * (AOM_QM_LAST - AOM_QM_FIRST) + QINDEX_RANGE / 2) / QINDEX_RANGE; - qmlevel = VPXMIN(qmlevel + AOM_QM_FIRST, NUM_QM_LEVELS - 1); +static inline int aom_get_qmlevel(int qindex, int first, int last) { + int qmlevel = (qindex * (last + 1 - first) + QINDEX_RANGE / 2) / QINDEX_RANGE; + qmlevel = VPXMIN(qmlevel + first, NUM_QM_LEVELS - 1); return qmlevel; } void aom_qm_init(struct VP10Common *cm); diff --git a/vp10/decoder/decodeframe.c b/vp10/decoder/decodeframe.c index 706914ce7a..0d76b78095 100644 --- a/vp10/decoder/decodeframe.c +++ b/vp10/decoder/decodeframe.c @@ -1118,6 +1118,13 @@ static void setup_quantization(VP10_COMMON *const cm, cm->dequant_bit_depth = cm->bit_depth; #if CONFIG_AOM_QM cm->using_qmatrix = vpx_rb_read_bit(rb); + if (cm->using_qmatrix) { + cm->min_qmlevel = vpx_rb_read_literal(rb, QM_LEVEL_BITS); + cm->max_qmlevel = vpx_rb_read_literal(rb, QM_LEVEL_BITS); + } else { + cm->min_qmlevel = 0; + cm->max_qmlevel = 0; + } #endif } @@ -1127,8 +1134,10 @@ static void setup_segmentation_dequant(VP10_COMMON *const cm) { #if CONFIG_AOM_QM int lossless; int j = 0; - int qmindex; + int qmlevel; int using_qm = cm->using_qmatrix; + int minqm = cm->min_qmlevel; + int maxqm = cm->max_qmlevel; #endif if (cm->seg.enabled) { for (i = 0; i < MAX_SEGMENTS; ++i) { @@ -1145,13 +1154,14 @@ static void setup_segmentation_dequant(VP10_COMMON *const cm) { cm->uv_dc_delta_q == 0 && cm->uv_ac_delta_q == 0; // NB: depends on base index so there is only 1 set per frame // No quant weighting when lossless or signalled not using QM - qmindex = (lossless || using_qm == 0) ? - QINDEX_RANGE - 1 : cm->base_qindex; + qmlevel = (lossless || using_qm == 0) + ? NUM_QM_LEVELS - 1 + : aom_get_qmlevel(cm->base_qindex, minqm, maxqm); for (j = 0; j < TX_SIZES; ++j) { - cm->y_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmindex, 0, j, 1); - cm->y_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmindex, 0, j, 0); - cm->uv_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmindex, 1, j, 1); - cm->uv_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmindex, 1, j, 0); + cm->y_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmlevel, 0, j, 1); + cm->y_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmlevel, 0, j, 0); + cm->uv_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmlevel, 1, j, 1); + cm->uv_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmlevel, 1, j, 0); } #endif } @@ -1170,13 +1180,14 @@ static void setup_segmentation_dequant(VP10_COMMON *const cm) { lossless = qindex == 0 && cm->y_dc_delta_q == 0 && cm->uv_dc_delta_q == 0 && cm->uv_ac_delta_q == 0; // No quant weighting when lossless or signalled not using QM - qmindex = (lossless || using_qm == 0) ? - QINDEX_RANGE - 1 : cm->base_qindex; + qmlevel = (lossless || using_qm == 0) + ? NUM_QM_LEVELS - 1 + : aom_get_qmlevel(cm->base_qindex, minqm, maxqm); for (j = 0; j < TX_SIZES; ++j) { - cm->y_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmindex, 0, j, 1); - cm->y_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmindex, 0, j, 0); - cm->uv_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmindex, 1, j, 1); - cm->uv_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmindex, 1, j, 0); + cm->y_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmlevel, 0, j, 1); + cm->y_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmlevel, 0, j, 0); + cm->uv_iqmatrix[i][1][j] = aom_iqmatrix(cm, qmlevel, 1, j, 1); + cm->uv_iqmatrix[i][0][j] = aom_iqmatrix(cm, qmlevel, 1, j, 0); } #endif } diff --git a/vp10/encoder/bitstream.c b/vp10/encoder/bitstream.c index d4fd08ca14..57ad9921f7 100644 --- a/vp10/encoder/bitstream.c +++ b/vp10/encoder/bitstream.c @@ -865,6 +865,10 @@ static void encode_quantization(const VP10_COMMON *const cm, write_delta_q(wb, cm->uv_ac_delta_q); #if CONFIG_AOM_QM vpx_wb_write_bit(wb, cm->using_qmatrix); + if (cm->using_qmatrix) { + vpx_wb_write_literal(wb, cm->min_qmlevel, QM_LEVEL_BITS); + vpx_wb_write_literal(wb, cm->max_qmlevel, QM_LEVEL_BITS); + } #endif } diff --git a/vp10/encoder/encoder.c b/vp10/encoder/encoder.c index 881ec99d2d..9857c0ee2d 100644 --- a/vp10/encoder/encoder.c +++ b/vp10/encoder/encoder.c @@ -3828,6 +3828,8 @@ int vp10_get_compressed_data(VP10_COMP *cpi, unsigned int *frame_flags, #if CONFIG_AOM_QM cm->using_qmatrix = cpi->oxcf.using_qm; + cm->min_qmlevel = cpi->oxcf.qm_minlevel; + cm->max_qmlevel = cpi->oxcf.qm_maxlevel; #endif if (oxcf->pass == 1) { diff --git a/vp10/encoder/encoder.h b/vp10/encoder/encoder.h index 697da51169..62b261b9c0 100644 --- a/vp10/encoder/encoder.h +++ b/vp10/encoder/encoder.h @@ -168,7 +168,11 @@ typedef struct VP10EncoderConfig { int best_allowed_q; int cq_level; AQ_MODE aq_mode; // Adaptive Quantization mode +#if CONFIG_AOM_QM int using_qm; + int qm_minlevel; + int qm_maxlevel; +#endif // Internal frame size scaling. RESIZE_TYPE resize_mode; diff --git a/vp10/encoder/quantize.c b/vp10/encoder/quantize.c index ae5c97931e..678b3045fe 100644 --- a/vp10/encoder/quantize.c +++ b/vp10/encoder/quantize.c @@ -8,6 +8,7 @@ * be found in the AUTHORS file in the root of the source tree. */ +#include <math.h> #include "./vpx_dsp_rtcd.h" #include "vpx_mem/vpx_mem.h" #include "vpx_ports/mem.h" @@ -388,12 +389,15 @@ void vp10_init_plane_quantizers(VP10_COMP *cpi, MACROBLOCK *x) { const int segment_id = xd->mi[0]->mbmi.segment_id; const int qindex = vp10_get_qindex(&cm->seg, segment_id, cm->base_qindex); const int rdmult = vp10_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q); + const int lossless = xd->lossless[segment_id]; int i; #if CONFIG_AOM_QM - const int lossless = xd->lossless[segment_id]; + int minqm = cm->min_qmlevel; + int maxqm = cm->max_qmlevel; // Quant matrix only depends on the base QP so there is only one set per frame - int qmlevel = (lossless || cm->using_qmatrix == 0) ? - NUM_QM_LEVELS - 1 : aom_get_qmlevel(cm->base_qindex); + int qmlevel = (lossless || cm->using_qmatrix == 0) + ? NUM_QM_LEVELS - 1 + : aom_get_qmlevel(cm->base_qindex, minqm, maxqm); #endif // Y diff --git a/vp10/vp10_cx_iface.c b/vp10/vp10_cx_iface.c index 840c4a7f5b..e5748abb44 100644 --- a/vp10/vp10_cx_iface.c +++ b/vp10/vp10_cx_iface.c @@ -41,6 +41,8 @@ struct vp10_extracfg { unsigned int lossless; #if CONFIG_AOM_QM unsigned int enable_qm; + unsigned int qm_min; + unsigned int qm_max; #endif unsigned int frame_parallel_decoding_mode; AQ_MODE aq_mode; @@ -54,25 +56,27 @@ struct vp10_extracfg { }; static struct vp10_extracfg default_extra_cfg = { - 0, // cpu_used - 1, // enable_auto_alt_ref - 0, // noise_sensitivity - 0, // sharpness - 0, // static_thresh - 6, // tile_columns - 0, // tile_rows - 7, // arnr_max_frames - 5, // arnr_strength - 0, // min_gf_interval; 0 -> default decision - 0, // max_gf_interval; 0 -> default decision - VPX_TUNE_PSNR, // tuning - 10, // cq_level - 0, // rc_max_intra_bitrate_pct - 0, // rc_max_inter_bitrate_pct - 0, // gf_cbr_boost_pct - 0, // lossless + 0, // cpu_used + 1, // enable_auto_alt_ref + 0, // noise_sensitivity + 0, // sharpness + 0, // static_thresh + 6, // tile_columns + 0, // tile_rows + 7, // arnr_max_frames + 5, // arnr_strength + 0, // min_gf_interval; 0 -> default decision + 0, // max_gf_interval; 0 -> default decision + VPX_TUNE_PSNR, // tuning + 10, // cq_level + 0, // rc_max_intra_bitrate_pct + 0, // rc_max_inter_bitrate_pct + 0, // gf_cbr_boost_pct + 0, // lossless #if CONFIG_AOM_QM - 0, // enable_qm + 0, // enable_qm + DEFAULT_QM_FIRST, // qm_min + DEFAULT_QM_LAST, // qm_max #endif 1, // frame_parallel_decoding_mode NO_AQ, // aq_mode @@ -365,6 +369,8 @@ static vpx_codec_err_t set_encoder_config( #if CONFIG_AOM_QM oxcf->using_qm = extra_cfg->enable_qm; + oxcf->qm_minlevel = extra_cfg->qm_min; + oxcf->qm_maxlevel = extra_cfg->qm_max; #endif oxcf->under_shoot_pct = cfg->rc_undershoot_pct; @@ -649,6 +655,20 @@ static vpx_codec_err_t ctrl_set_enable_qm(vpx_codec_alg_priv_t *ctx, extra_cfg.enable_qm = CAST(VP9E_SET_ENABLE_QM, args); return update_extra_cfg(ctx, &extra_cfg); } + +static vpx_codec_err_t ctrl_set_qm_min(vpx_codec_alg_priv_t *ctx, + va_list args) { + struct vp10_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.qm_min = CAST(VP9E_SET_QM_MIN, args); + return update_extra_cfg(ctx, &extra_cfg); +} + +static vpx_codec_err_t ctrl_set_qm_max(vpx_codec_alg_priv_t *ctx, + va_list args) { + struct vp10_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.qm_max = CAST(VP9E_SET_QM_MAX, args); + return update_extra_cfg(ctx, &extra_cfg); +} #endif static vpx_codec_err_t ctrl_set_frame_parallel_decoding_mode( @@ -1249,6 +1269,8 @@ static vpx_codec_ctrl_fn_map_t encoder_ctrl_maps[] = { { VP9E_SET_LOSSLESS, ctrl_set_lossless }, #if CONFIG_AOM_QM { VP9E_SET_ENABLE_QM, ctrl_set_enable_qm }, + { VP9E_SET_QM_MIN, ctrl_set_qm_min }, + { VP9E_SET_QM_MAX, ctrl_set_qm_max }, #endif { VP9E_SET_FRAME_PARALLEL_DECODING, ctrl_set_frame_parallel_decoding_mode }, { VP9E_SET_AQ_MODE, ctrl_set_aq_mode }, diff --git a/vpx/vp8cx.h b/vpx/vp8cx.h index 0f033ffb79..ddeaff6c0a 100644 --- a/vpx/vp8cx.h +++ b/vpx/vp8cx.h @@ -324,6 +324,33 @@ enum vp8e_enc_control_id { */ VP9E_SET_ENABLE_QM, + + /*!\brief Codec control function to set the min quant matrix flatness. + * + * AOM can operate with different ranges of quantisation matrices. + * As quantisation levels increase, the matrices get flatter. This + * control sets the minimum level of flatness from which the matrices + * are determined. + * + * By default, the encoder sets this minimum at half the available + * range. + * + * Supported in codecs: AOM + */ + VP9E_SET_QM_MIN, + + /*!\brief Codec control function to set the max quant matrix flatness. + * + * AOM can operate with different ranges of quantisation matrices. + * As quantisation levels increase, the matrices get flatter. This + * control sets the maximum level of flatness possible. + * + * By default, the encoder sets this maximum at the top of the + * available range. + * + * Supported in codecs: AOM + */ + VP9E_SET_QM_MAX, #endif /*!\brief Codec control function to set number of tile columns. @@ -763,6 +790,12 @@ VPX_CTRL_USE_TYPE(VP9E_SET_LOSSLESS, unsigned int) #if CONFIG_AOM_QM VPX_CTRL_USE_TYPE(VP9E_SET_ENABLE_QM, unsigned int) #define VPX_CTRL_VP9E_SET_ENABLE_QM + +VPX_CTRL_USE_TYPE(VP9E_SET_QM_MIN, unsigned int) +#define VPX_CTRL_VP9E_SET_QM_MIN + +VPX_CTRL_USE_TYPE(VP9E_SET_QM_MAX, unsigned int) +#define VPX_CTRL_VP9E_SET_QM_MAX #endif VPX_CTRL_USE_TYPE(VP9E_SET_FRAME_PARALLEL_DECODING, unsigned int) diff --git a/vpxenc.c b/vpxenc.c index 8fbeb3659a..41a1605e47 100644 --- a/vpxenc.c +++ b/vpxenc.c @@ -369,6 +369,10 @@ static const arg_def_t lossless = static const arg_def_t enable_qm = ARG_DEF(NULL, "enable_qm", 1, "Enable quantisation matrices (0: false (default), 1: true)"); +static const arg_def_t qm_min = ARG_DEF( + NULL, "qm_min", 1, "Min quant matrix flatness (0..15), default is 8"); +static const arg_def_t qm_max = ARG_DEF( + NULL, "qm_max", 1, "Max quant matrix flatness (0..15), default is 16"); #endif static const arg_def_t frame_parallel_decoding = ARG_DEF( NULL, "frame-parallel", 1, "Enable frame parallel decodability features"); @@ -432,33 +436,35 @@ static const arg_def_t tune_content = ARG_DEF_ENUM( #if CONFIG_VP10_ENCODER /* clang-format off */ static const arg_def_t *vp10_args[] = { - &cpu_used_vp9, &auto_altref, &sharpness, &static_thresh, - &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type, - &tune_ssim, &cq_level, &max_intra_rate_pct, &max_inter_rate_pct, - &gf_cbr_boost_pct, &lossless, + &cpu_used_vp9, &auto_altref, &sharpness, + &static_thresh, &tile_cols, &tile_rows, + &arnr_maxframes, &arnr_strength, &arnr_type, + &tune_ssim, &cq_level, &max_intra_rate_pct, + &max_inter_rate_pct, &gf_cbr_boost_pct, &lossless, #if CONFIG_AOM_QM - &enable_qm, + &enable_qm, &qm_min, &qm_max, #endif - &frame_parallel_decoding, &aq_mode, &frame_periodic_boost, - &noise_sens, &tune_content, &input_color_space, - &min_gf_interval, &max_gf_interval, - NULL + &frame_parallel_decoding, &aq_mode, &frame_periodic_boost, + &noise_sens, &tune_content, &input_color_space, + &min_gf_interval, &max_gf_interval, NULL }; static const int vp10_arg_ctrl_map[] = { - VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, - VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, - VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS, - VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE, - VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, - VP9E_SET_MAX_INTER_BITRATE_PCT, VP9E_SET_GF_CBR_BOOST_PCT, + VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, + VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, + VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS, + VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, + VP8E_SET_ARNR_TYPE, VP8E_SET_TUNING, + VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, + VP9E_SET_MAX_INTER_BITRATE_PCT, VP9E_SET_GF_CBR_BOOST_PCT, VP9E_SET_LOSSLESS, #if CONFIG_AOM_QM - VP9E_SET_ENABLE_QM, + VP9E_SET_ENABLE_QM, VP9E_SET_QM_MIN, + VP9E_SET_QM_MAX, #endif VP9E_SET_FRAME_PARALLEL_DECODING, VP9E_SET_AQ_MODE, - VP9E_SET_FRAME_PERIODIC_BOOST, VP9E_SET_NOISE_SENSITIVITY, - VP9E_SET_TUNE_CONTENT, VP9E_SET_COLOR_SPACE, - VP9E_SET_MIN_GF_INTERVAL, VP9E_SET_MAX_GF_INTERVAL, + VP9E_SET_FRAME_PERIODIC_BOOST, VP9E_SET_NOISE_SENSITIVITY, + VP9E_SET_TUNE_CONTENT, VP9E_SET_COLOR_SPACE, + VP9E_SET_MIN_GF_INTERVAL, VP9E_SET_MAX_GF_INTERVAL, 0 }; /* clang-format on */ -- GitLab