Commit be42dc72 authored by Yaowu Xu's avatar Yaowu Xu

Separate quantizaton for U and V plane

This commit adds code to support separate regular quantization for U
and V. They currently always use same quantization parameter, hence
this commit does not change bitstream at all.

Change-Id: Ifaf43e4fd0bcd01b1483f2dacf3ac498003d5db1
parent 07ec5e8a
......@@ -301,14 +301,16 @@ typedef struct AV1Common {
int base_qindex;
int y_dc_delta_q;
int uv_dc_delta_q;
int uv_ac_delta_q;
int u_dc_delta_q;
int v_dc_delta_q;
int u_ac_delta_q;
int v_ac_delta_q;
// The dequantizers below are true dequntizers used only in the
// dequantization process. They have the same coefficient
// shift/scale as TX.
int16_t y_dequant_QTX[MAX_SEGMENTS][2];
int16_t uv_dequant_QTX[MAX_SEGMENTS][2];
int16_t u_dequant_QTX[MAX_SEGMENTS][2];
int16_t v_dequant_QTX[MAX_SEGMENTS][2];
#if CONFIG_AOM_QM
// Global quant matrix tables
......@@ -318,6 +320,7 @@ typedef struct AV1Common {
// Local quant matrix tables for each frame
qm_val_t *y_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL];
qm_val_t *uv_iqmatrix[MAX_SEGMENTS][TX_SIZES_ALL];
// Encoder
qm_val_t *y_qmatrix[MAX_SEGMENTS][TX_SIZES_ALL];
qm_val_t *uv_qmatrix[MAX_SEGMENTS][TX_SIZES_ALL];
......@@ -329,8 +332,10 @@ typedef struct AV1Common {
#if CONFIG_NEW_QUANT
dequant_val_type_nuq y_dequant_nuq_QTX[MAX_SEGMENTS][QUANT_PROFILES]
[COEF_BANDS];
dequant_val_type_nuq uv_dequant_nuq_QTX[MAX_SEGMENTS][QUANT_PROFILES]
[COEF_BANDS];
dequant_val_type_nuq u_dequant_nuq_QTX[MAX_SEGMENTS][QUANT_PROFILES]
[COEF_BANDS];
dequant_val_type_nuq v_dequant_nuq_QTX[MAX_SEGMENTS][QUANT_PROFILES]
[COEF_BANDS];
#endif
/* We allocate a MODE_INFO struct for each macroblock, together with
......@@ -699,17 +704,28 @@ static INLINE void av1_init_macroblockd(AV1_COMMON *cm, MACROBLOCKD *xd,
#if CONFIG_NEW_QUANT
memcpy(xd->plane[i].seg_dequant_nuq_QTX, cm->y_dequant_nuq_QTX,
sizeof(cm->y_dequant_nuq_QTX));
#endif
} else if (xd->plane[i].plane_type == 1) {
memcpy(xd->plane[i].seg_dequant_QTX, cm->u_dequant_QTX,
sizeof(cm->u_dequant_QTX));
#if CONFIG_AOM_QM
memcpy(xd->plane[i].seg_iqmatrix, cm->uv_iqmatrix,
sizeof(cm->uv_iqmatrix));
#endif
#if CONFIG_NEW_QUANT
memcpy(xd->plane[i].seg_dequant_nuq_QTX, cm->u_dequant_nuq_QTX,
sizeof(cm->u_dequant_nuq_QTX));
#endif
} else {
memcpy(xd->plane[i].seg_dequant_QTX, cm->uv_dequant_QTX,
sizeof(cm->uv_dequant_QTX));
memcpy(xd->plane[i].seg_dequant_QTX, cm->v_dequant_QTX,
sizeof(cm->v_dequant_QTX));
#if CONFIG_AOM_QM
memcpy(xd->plane[i].seg_iqmatrix, cm->uv_iqmatrix,
sizeof(cm->uv_iqmatrix));
#endif
#if CONFIG_NEW_QUANT
memcpy(xd->plane[i].seg_dequant_nuq_QTX, cm->uv_dequant_nuq_QTX,
sizeof(cm->uv_dequant_nuq_QTX));
memcpy(xd->plane[i].seg_dequant_nuq_QTX, cm->v_dequant_nuq_QTX,
sizeof(cm->v_dequant_nuq_QTX));
#endif
}
}
......
......@@ -498,8 +498,11 @@ static void decode_token_and_recon_block(AV1Decoder *const pbi,
#endif // CONFIG_EXT_DELTA_Q
int j;
for (j = 0; j < MAX_MB_PLANE; ++j) {
const int dc_delta_q = j == 0 ? cm->y_dc_delta_q : cm->uv_dc_delta_q;
const int ac_delta_q = j == 0 ? 0 : cm->uv_ac_delta_q;
const int dc_delta_q =
j == 0 ? cm->y_dc_delta_q
: (j == 1 ? cm->u_dc_delta_q : cm->v_dc_delta_q);
const int ac_delta_q =
j == 0 ? 0 : (j == 1 ? cm->u_ac_delta_q : cm->v_ac_delta_q);
xd->plane[j].seg_dequant_QTX[i][0] = dequant_Q3_to_QTX(
av1_dc_quant(current_qindex, dc_delta_q, cm->bit_depth),
cm->bit_depth);
......@@ -1370,8 +1373,10 @@ static void setup_quantization(AV1_COMMON *const cm,
struct aom_read_bit_buffer *rb) {
cm->base_qindex = aom_rb_read_literal(rb, QINDEX_BITS);
cm->y_dc_delta_q = read_delta_q(rb);
cm->uv_dc_delta_q = read_delta_q(rb);
cm->uv_ac_delta_q = read_delta_q(rb);
cm->u_dc_delta_q = read_delta_q(rb);
cm->u_ac_delta_q = read_delta_q(rb);
cm->v_dc_delta_q = cm->u_dc_delta_q;
cm->v_ac_delta_q = cm->u_ac_delta_q;
cm->dequant_bit_depth = cm->bit_depth;
#if CONFIG_AOM_QM
cm->using_qmatrix = aom_rb_read_bit(rb);
......@@ -1405,13 +1410,18 @@ static void setup_segmentation_dequant(AV1_COMMON *const cm) {
av1_dc_quant(qindex, cm->y_dc_delta_q, cm->bit_depth), cm->bit_depth);
cm->y_dequant_QTX[i][1] = dequant_Q3_to_QTX(
av1_ac_quant(qindex, 0, cm->bit_depth), cm->bit_depth);
cm->uv_dequant_QTX[i][0] = dequant_Q3_to_QTX(
av1_dc_quant(qindex, cm->uv_dc_delta_q, cm->bit_depth), cm->bit_depth);
cm->uv_dequant_QTX[i][1] = dequant_Q3_to_QTX(
av1_ac_quant(qindex, cm->uv_ac_delta_q, cm->bit_depth), cm->bit_depth);
cm->u_dequant_QTX[i][0] = dequant_Q3_to_QTX(
av1_dc_quant(qindex, cm->u_dc_delta_q, cm->bit_depth), cm->bit_depth);
cm->u_dequant_QTX[i][1] = dequant_Q3_to_QTX(
av1_ac_quant(qindex, cm->u_ac_delta_q, cm->bit_depth), cm->bit_depth);
cm->v_dequant_QTX[i][0] = dequant_Q3_to_QTX(
av1_dc_quant(qindex, cm->v_dc_delta_q, cm->bit_depth), cm->bit_depth);
cm->v_dequant_QTX[i][1] = dequant_Q3_to_QTX(
av1_ac_quant(qindex, cm->v_ac_delta_q, cm->bit_depth), cm->bit_depth);
#if CONFIG_AOM_QM
const int lossless = qindex == 0 && cm->y_dc_delta_q == 0 &&
cm->uv_dc_delta_q == 0 && cm->uv_ac_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
const int qmlevel = (lossless || using_qm == 0)
......@@ -1427,8 +1437,10 @@ static void setup_segmentation_dequant(AV1_COMMON *const cm) {
for (int b = 0; b < COEF_BANDS; ++b) {
av1_get_dequant_val_nuq(cm->y_dequant_QTX[i][b != 0], b,
cm->y_dequant_nuq_QTX[i][dq][b], NULL, dq);
av1_get_dequant_val_nuq(cm->uv_dequant_QTX[i][b != 0], b,
cm->uv_dequant_nuq_QTX[i][dq][b], NULL, dq);
av1_get_dequant_val_nuq(cm->u_dequant_QTX[i][b != 0], b,
cm->u_dequant_nuq_QTX[i][dq][b], NULL, dq);
av1_get_dequant_val_nuq(cm->v_dequant_QTX[i][b != 0], b,
cm->v_dequant_nuq_QTX[i][dq][b], NULL, dq);
}
}
#endif // CONFIG_NEW_QUANT
......@@ -3250,7 +3262,8 @@ static size_t read_uncompressed_header(AV1Decoder *pbi,
#endif
: cm->base_qindex;
xd->lossless[i] = qindex == 0 && cm->y_dc_delta_q == 0 &&
cm->uv_dc_delta_q == 0 && cm->uv_ac_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;
xd->qindex[i] = qindex;
}
cm->all_lossless = all_lossless(cm, xd);
......
......@@ -62,7 +62,8 @@ int ifd_inspect(insp_frame_data *fd, void *decoder) {
for (i = 0; i < MAX_SEGMENTS; i++) {
for (j = 0; j < 2; j++) {
fd->y_dequant[i][j] = cm->y_dequant_QTX[i][j];
fd->uv_dequant[i][j] = cm->uv_dequant_QTX[i][j];
fd->u_dequant[i][j] = cm->u_dequant_QTX[i][j];
fd->v_dequant[i][j] = cm->v_dequant_QTX[i][j];
}
}
for (j = 0; j < cm->mi_rows; j++) {
......
......@@ -75,7 +75,8 @@ struct insp_frame_data {
int tile_mi_rows;
int tile_mi_cols;
int16_t y_dequant[MAX_SEGMENTS][2];
int16_t uv_dequant[MAX_SEGMENTS][2];
int16_t u_dequant[MAX_SEGMENTS][2];
int16_t v_dequant[MAX_SEGMENTS][2];
#if CONFIG_CDEF
// TODO(negge): add per frame CDEF data
#endif
......
This diff is collapsed.
......@@ -50,7 +50,10 @@ typedef struct {
y_cuml_bins_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS][NUQ_KNOTS]);
DECLARE_ALIGNED(
16, tran_low_t,
uv_cuml_bins_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS][NUQ_KNOTS]);
u_cuml_bins_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS][NUQ_KNOTS]);
DECLARE_ALIGNED(
16, tran_low_t,
v_cuml_bins_nuq[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS][NUQ_KNOTS]);
#endif // CONFIG_NEW_QUANT
// 0: dc 1: ac 2-8: ac repeated to SIMD width
DECLARE_ALIGNED(16, int16_t, y_quant[QINDEX_RANGE][8]);
......@@ -61,14 +64,20 @@ typedef struct {
// TODO(jingning): in progress of re-working the quantization. will decide
// if we want to deprecate the current use of y_quant.
DECLARE_ALIGNED(16, int16_t, y_quant_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_quant_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, u_quant_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, v_quant_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, y_round_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_round_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_quant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_quant_shift[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_zbin[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, uv_round[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, u_round_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, v_round_fp[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, u_quant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, v_quant[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, u_quant_shift[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, v_quant_shift[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, u_zbin[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, v_zbin[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, u_round[QINDEX_RANGE][8]);
DECLARE_ALIGNED(16, int16_t, v_round[QINDEX_RANGE][8]);
} QUANTS;
// The Dequants structure is used only for internal quantizer setup in
......@@ -79,17 +88,22 @@ typedef struct {
DECLARE_ALIGNED(16, int16_t,
y_dequant_QTX[QINDEX_RANGE][8]); // 8: SIMD width
DECLARE_ALIGNED(16, int16_t,
uv_dequant_QTX[QINDEX_RANGE][8]); // 8: SIMD width
DECLARE_ALIGNED(16, int16_t, y_dequant_Q3[QINDEX_RANGE][8]); // 8: SIMD width
u_dequant_QTX[QINDEX_RANGE][8]); // 8: SIMD width
DECLARE_ALIGNED(16, int16_t,
uv_dequant_Q3[QINDEX_RANGE][8]); // 8: SIMD width
v_dequant_QTX[QINDEX_RANGE][8]); // 8: SIMD width
DECLARE_ALIGNED(16, int16_t, y_dequant_Q3[QINDEX_RANGE][8]); // 8: SIMD width
DECLARE_ALIGNED(16, int16_t, u_dequant_Q3[QINDEX_RANGE][8]); // 8: SIMD width
DECLARE_ALIGNED(16, int16_t, v_dequant_Q3[QINDEX_RANGE][8]); // 8: SIMD width
#if CONFIG_NEW_QUANT
DECLARE_ALIGNED(
16, dequant_val_type_nuq,
y_dequant_val_nuq_QTX[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
DECLARE_ALIGNED(
16, dequant_val_type_nuq,
uv_dequant_val_nuq_QTX[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
u_dequant_val_nuq_QTX[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
DECLARE_ALIGNED(
16, dequant_val_type_nuq,
v_dequant_val_nuq_QTX[QUANT_PROFILES][QINDEX_RANGE][COEF_BANDS]);
#endif // CONFIG_NEW_QUANT
} Dequants;
......@@ -106,8 +120,9 @@ void av1_init_plane_quantizers(const struct AV1_COMP *cpi, MACROBLOCK *x,
#endif
void av1_build_quantizer(aom_bit_depth_t bit_depth, int y_dc_delta_q,
int uv_dc_delta_q, int uv_ac_delta_q,
QUANTS *const quants, Dequants *const deq);
int u_dc_delta_q, int u_ac_delta_q, int v_dc_delta_q,
int v_ac_delta_q, QUANTS *const quants,
Dequants *const deq);
void av1_init_quantizer(struct AV1_COMP *cpi);
......
......@@ -2773,8 +2773,10 @@ static void encode_quantization(const AV1_COMMON *const cm,
struct aom_write_bit_buffer *wb) {
aom_wb_write_literal(wb, cm->base_qindex, QINDEX_BITS);
write_delta_q(wb, cm->y_dc_delta_q);
write_delta_q(wb, cm->uv_dc_delta_q);
write_delta_q(wb, cm->uv_ac_delta_q);
assert(cm->u_dc_delta_q == cm->v_dc_delta_q);
write_delta_q(wb, cm->u_dc_delta_q);
assert(cm->u_ac_delta_q == cm->v_ac_delta_q);
write_delta_q(wb, cm->u_ac_delta_q);
#if CONFIG_AOM_QM
aom_wb_write_bit(wb, cm->using_qmatrix);
if (cm->using_qmatrix) {
......
......@@ -4148,7 +4148,8 @@ static void encode_frame_internal(AV1_COMP *cpi) {
#endif
: cm->base_qindex;
xd->lossless[i] = qindex == 0 && cm->y_dc_delta_q == 0 &&
cm->uv_dc_delta_q == 0 && cm->uv_ac_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;
xd->qindex[i] = qindex;
}
cm->all_lossless = all_lossless(cm, xd);
......
......@@ -117,8 +117,10 @@ class AvxEncoderParmsGetToDecoder
if (encode_parms.lossless) {
EXPECT_EQ(0, common->base_qindex);
EXPECT_EQ(0, common->y_dc_delta_q);
EXPECT_EQ(0, common->uv_dc_delta_q);
EXPECT_EQ(0, common->uv_ac_delta_q);
EXPECT_EQ(0, common->u_dc_delta_q);
EXPECT_EQ(0, common->u_ac_delta_q);
EXPECT_EQ(0, common->v_dc_delta_q);
EXPECT_EQ(0, common->v_ac_delta_q);
EXPECT_EQ(ONLY_4X4, common->tx_mode);
}
EXPECT_EQ(encode_parms.error_resilient, common->error_resilient_mode);
......
......@@ -98,7 +98,7 @@ class QuantizeTest : public ::testing::TestWithParam<QuantizeParam> {
}
void InitQuantizer() {
av1_build_quantizer(bd_, 0, 0, 0, &qtab_->quant, &qtab_->dequant);
av1_build_quantizer(bd_, 0, 0, 0, 0, 0, &qtab_->quant, &qtab_->dequant);
}
void QuantizeRun(bool is_loop, int q = 0, int test_num = 1) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment