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