aom_qm_ext: add signaling for separate QM for U/V Change-Id: I9879264011f6450bd2eb6648e39e9ad47f13a7d8
diff --git a/aom/aomcx.h b/aom/aomcx.h index 1cedd58..45cd64c 100644 --- a/aom/aomcx.h +++ b/aom/aomcx.h
@@ -565,6 +565,45 @@ */ AV1E_SET_QM_MAX, + /*!\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 flatness for luma (Y). + * + * By default, the encoder sets this minimum at half the available + * range. + * + * Experiment: AOM_QM + */ + AV1E_SET_QM_Y, + + /*!\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 flatness for chroma (U). + * + * By default, the encoder sets this minimum at half the available + * range. + * + * Experiment: AOM_QM + */ + AV1E_SET_QM_U, + + /*!\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 flatness for chrome (V). + * + * By default, the encoder sets this minimum at half the available + * range. + * + * Experiment: AOM_QM + */ + AV1E_SET_QM_V, + /*!\brief Codec control function to encode with dist_8x8. * * The dist_8x8 is enabled automatically for model tuning parameters that @@ -882,6 +921,15 @@ AOM_CTRL_USE_TYPE(AV1E_SET_QM_MAX, unsigned int) #define AOM_CTRL_AV1E_SET_QM_MAX +AOM_CTRL_USE_TYPE(AV1E_SET_QM_Y, unsigned int) +#define AOM_CTRL_AV1E_SET_QM_Y + +AOM_CTRL_USE_TYPE(AV1E_SET_QM_U, unsigned int) +#define AOM_CTRL_AV1E_SET_QM_U + +AOM_CTRL_USE_TYPE(AV1E_SET_QM_V, unsigned int) +#define AOM_CTRL_AV1E_SET_QM_V + AOM_CTRL_USE_TYPE(AV1E_SET_NUM_TG, unsigned int) #define AOM_CTRL_AV1E_SET_NUM_TG AOM_CTRL_USE_TYPE(AV1E_SET_MTU, unsigned int)
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index 20fef35..9430a47 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -67,9 +67,14 @@ unsigned int enable_cdef; #if CONFIG_AOM_QM unsigned int enable_qm; +#if CONFIG_AOM_QM_EXT + unsigned int qm_y; + unsigned int qm_u; + unsigned int qm_v; +#endif // CONFIG_AOM_QM_EXT unsigned int qm_min; unsigned int qm_max; -#endif +#endif // CONFIG_AOM_QM #if CONFIG_DIST_8X8 unsigned int enable_dist_8x8; #endif @@ -143,7 +148,12 @@ 0, // lossless 1, // enable_cdef #if CONFIG_AOM_QM - 0, // enable_qm + 0, // enable_qm +#if CONFIG_AOM_QM_EXT + DEFAULT_QM_Y, // qm_y + DEFAULT_QM_U, // qm_u + DEFAULT_QM_V, // qm_v +#endif // CONFIG_AOM_QM_EXT DEFAULT_QM_FIRST, // qm_min DEFAULT_QM_LAST, // qm_max #endif @@ -564,6 +574,11 @@ oxcf->using_cdef = extra_cfg->enable_cdef; #if CONFIG_AOM_QM oxcf->using_qm = extra_cfg->enable_qm; +#if CONFIG_AOM_QM_EXT + oxcf->qm_y = extra_cfg->qm_y; + oxcf->qm_u = extra_cfg->qm_u; + oxcf->qm_v = extra_cfg->qm_v; +#endif // CONFIG_AOM_QM_EXT oxcf->qm_minlevel = extra_cfg->qm_min; oxcf->qm_maxlevel = extra_cfg->qm_max; #endif @@ -986,6 +1001,23 @@ extra_cfg.enable_qm = CAST(AV1E_SET_ENABLE_QM, args); return update_extra_cfg(ctx, &extra_cfg); } +#if CONFIG_AOM_QM_EXT +static aom_codec_err_t ctrl_set_qm_y(aom_codec_alg_priv_t *ctx, va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.qm_y = CAST(AV1E_SET_QM_Y, args); + return update_extra_cfg(ctx, &extra_cfg); +} +static aom_codec_err_t ctrl_set_qm_u(aom_codec_alg_priv_t *ctx, va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.qm_u = CAST(AV1E_SET_QM_U, args); + return update_extra_cfg(ctx, &extra_cfg); +} +static aom_codec_err_t ctrl_set_qm_v(aom_codec_alg_priv_t *ctx, va_list args) { + struct av1_extracfg extra_cfg = ctx->extra_cfg; + extra_cfg.qm_v = CAST(AV1E_SET_QM_V, args); + return update_extra_cfg(ctx, &extra_cfg); +} +#endif // CONFIG_AOM_QM_EXT static aom_codec_err_t ctrl_set_qm_min(aom_codec_alg_priv_t *ctx, va_list args) { @@ -1774,8 +1806,14 @@ { AV1E_SET_ENABLE_CDEF, ctrl_set_enable_cdef }, #if CONFIG_AOM_QM { AV1E_SET_ENABLE_QM, ctrl_set_enable_qm }, +#if CONFIG_AOM_QM_EXT + { AV1E_SET_QM_Y, ctrl_set_qm_y }, + { AV1E_SET_QM_U, ctrl_set_qm_u }, + { AV1E_SET_QM_V, ctrl_set_qm_v }, +#endif // CONFIG_AOM_QM_EXT { AV1E_SET_QM_MIN, ctrl_set_qm_min }, { AV1E_SET_QM_MAX, ctrl_set_qm_max }, + #endif #if CONFIG_DIST_8X8 { AV1E_SET_ENABLE_DIST_8X8, ctrl_set_enable_dist_8x8 },
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h index b7e44a8..e7520ad 100644 --- a/av1/common/onyxc_int.h +++ b/av1/common/onyxc_int.h
@@ -371,6 +371,11 @@ // Encoder int using_qmatrix; +#if CONFIG_AOM_QM_EXT + int qm_y; + int qm_u; + int qm_v; +#endif // CONFIG_AOM_QM_EXT int min_qmlevel; int max_qmlevel; #endif
diff --git a/av1/common/quant_common.h b/av1/common/quant_common.h index e3b4f84..0f2fc6e 100644 --- a/av1/common/quant_common.h +++ b/av1/common/quant_common.h
@@ -31,6 +31,11 @@ #define NUM_QM_LEVELS (1 << QM_LEVEL_BITS) /* Range of QMS is between first and last value, with offset applied to inter * blocks*/ +#if CONFIG_AOM_QM_EXT +#define DEFAULT_QM_Y 10 +#define DEFAULT_QM_U 11 +#define DEFAULT_QM_V 12 +#endif // CONFIG_AOM_QM_EXT #define DEFAULT_QM_FIRST 5 #define DEFAULT_QM_LAST 9 #endif
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index 18fa2f0..c649c8e 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -1062,11 +1062,28 @@ #if CONFIG_AOM_QM cm->using_qmatrix = aom_rb_read_bit(rb); if (cm->using_qmatrix) { +#if CONFIG_AOM_QM_EXT + cm->qm_y = aom_rb_read_literal(rb, QM_LEVEL_BITS); + cm->qm_u = aom_rb_read_literal(rb, QM_LEVEL_BITS); +#if CONFIG_EXT_QM + if (!cm->separate_uv_delta_q) + cm->qm_v = cm->qm_u; + else +#endif + cm->qm_v = aom_rb_read_literal(rb, QM_LEVEL_BITS); +#else cm->min_qmlevel = aom_rb_read_literal(rb, QM_LEVEL_BITS); cm->max_qmlevel = aom_rb_read_literal(rb, QM_LEVEL_BITS); +#endif } else { +#if CONFIG_AOM_QM_EXT + cm->qm_y = 0; + cm->qm_u = 0; + cm->qm_v = 0; +#else cm->min_qmlevel = 0; cm->max_qmlevel = 0; +#endif } #endif } @@ -1075,8 +1092,10 @@ static void setup_segmentation_dequant(AV1_COMMON *const cm) { #if CONFIG_AOM_QM const int using_qm = cm->using_qmatrix; +#if !CONFIG_AOM_QM_EXT const int minqm = cm->min_qmlevel; const int maxqm = cm->max_qmlevel; +#endif // !CONFIG_AOM_QM_EXT #endif // When segmentation is disabled, only the first value is used. The // remaining are don't cares. @@ -1098,14 +1117,28 @@ const int lossless = qindex == 0 && cm->y_dc_delta_q == 0 && cm->u_dc_delta_q == 0 && cm->u_ac_delta_q == 0 && cm->v_dc_delta_q == 0 && cm->v_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 +// NB: depends on base index so there is only 1 set per frame +// No quant weighting when lossless or signalled not using QM +#if CONFIG_AOM_QM_EXT + int qmlevel = (lossless || using_qm == 0) ? NUM_QM_LEVELS - 1 : cm->qm_y; +#else const int qmlevel = (lossless || using_qm == 0) ? NUM_QM_LEVELS - 1 : aom_get_qmlevel(cm->base_qindex, minqm, maxqm); +#endif for (int j = 0; j < TX_SIZES_ALL; ++j) { cm->y_iqmatrix[i][j] = aom_iqmatrix(cm, qmlevel, AOM_PLANE_Y, j); + } +#if CONFIG_AOM_QM_EXT + qmlevel = (lossless || using_qm == 0) ? NUM_QM_LEVELS - 1 : cm->qm_u; +#endif + for (int j = 0; j < TX_SIZES_ALL; ++j) { cm->u_iqmatrix[i][j] = aom_iqmatrix(cm, qmlevel, AOM_PLANE_U, j); + } +#if CONFIG_AOM_QM_EXT + qmlevel = (lossless || using_qm == 0) ? NUM_QM_LEVELS - 1 : cm->qm_v; +#endif + for (int j = 0; j < TX_SIZES_ALL; ++j) { cm->v_iqmatrix[i][j] = aom_iqmatrix(cm, qmlevel, AOM_PLANE_V, j); } #endif // CONFIG_AOM_QM
diff --git a/av1/encoder/av1_quantize.c b/av1/encoder/av1_quantize.c index 2e62dee..b1df95c 100644 --- a/av1/encoder/av1_quantize.c +++ b/av1/encoder/av1_quantize.c
@@ -2065,12 +2065,18 @@ const int qindex = av1_get_qindex(&cm->seg, segment_id, current_q_index); const int rdmult = av1_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q); #if CONFIG_AOM_QM +#if CONFIG_AOM_QM_EXT + int qmlevel = (xd->lossless[segment_id] || cm->using_qmatrix == 0) + ? NUM_QM_LEVELS - 1 + : cm->qm_y; +#else 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 = (xd->lossless[segment_id] || cm->using_qmatrix == 0) ? NUM_QM_LEVELS - 1 : aom_get_qmlevel(cm->base_qindex, minqm, maxqm); +#endif // CONFIG_AOM_QM_EXT #endif // Y @@ -2100,7 +2106,14 @@ } #endif // CONFIG_NEW_QUANT - // U +// U +#if CONFIG_AOM_QM +#if CONFIG_AOM_QM_EXT + qmlevel = (xd->lossless[segment_id] || cm->using_qmatrix == 0) + ? NUM_QM_LEVELS - 1 + : cm->qm_u; +#endif +#endif { x->plane[1].quant_QTX = quants->u_quant[qindex]; x->plane[1].quant_fp_QTX = quants->u_quant_fp[qindex]; @@ -2129,7 +2142,14 @@ } #endif // CONFIG_NEW_QUANT } - // V +// V +#if CONFIG_AOM_QM +#if CONFIG_AOM_QM_EXT + qmlevel = (xd->lossless[segment_id] || cm->using_qmatrix == 0) + ? NUM_QM_LEVELS - 1 + : cm->qm_v; +#endif +#endif { x->plane[2].quant_QTX = quants->v_quant[qindex]; x->plane[2].quant_fp_QTX = quants->v_quant_fp[qindex]; @@ -2181,6 +2201,21 @@ cm->u_ac_delta_q = 0; cm->v_dc_delta_q = 0; cm->v_ac_delta_q = 0; +#if CONFIG_AOM_QM +#if CONFIG_AOM_QM_EXT + cm->qm_y = aom_get_qmlevel(cm->base_qindex, cm->min_qmlevel, cm->max_qmlevel); + cm->qm_u = aom_get_qmlevel(cm->base_qindex + cm->u_ac_delta_q, + cm->min_qmlevel, cm->max_qmlevel); + +#if CONFIG_EXT_QM + if (!cm->separate_uv_delta_q) + cm->qm_v = cm->qm_u; + else +#endif + cm->qm_v = aom_get_qmlevel(cm->base_qindex + cm->v_ac_delta_q, + cm->min_qmlevel, cm->max_qmlevel); +#endif +#endif } // Table that converts 0-63 Q-range values passed in outside to the Qindex
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index 6b3dfa4..0429b52 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c
@@ -2473,8 +2473,19 @@ #if CONFIG_AOM_QM aom_wb_write_bit(wb, cm->using_qmatrix); if (cm->using_qmatrix) { +#if CONFIG_AOM_QM_EXT + aom_wb_write_literal(wb, cm->qm_y, QM_LEVEL_BITS); + aom_wb_write_literal(wb, cm->qm_u, QM_LEVEL_BITS); +#if CONFIG_EXT_QM + if (!cm->separate_uv_delta_q) + assert(cm->qm_u == cm->qm_v); + else +#endif + aom_wb_write_literal(wb, cm->qm_v, QM_LEVEL_BITS); +#else aom_wb_write_literal(wb, cm->min_qmlevel, QM_LEVEL_BITS); aom_wb_write_literal(wb, cm->max_qmlevel, QM_LEVEL_BITS); +#endif } #endif }
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index dab0ea4..9c18941 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -193,6 +193,11 @@ int using_cdef; #if CONFIG_AOM_QM int using_qm; +#if CONFIG_AOM_QM_EXT + int qm_y; + int qm_u; + int qm_v; +#endif int qm_minlevel; int qm_maxlevel; #endif