Support for delta-q at superblock level Change-Id: I4128af44776d1f361bddc1fdffb75ed2224dbfa5
diff --git a/aomenc.c b/aomenc.c index 3f9a87d..3b34ed8 100644 --- a/aomenc.c +++ b/aomenc.c
@@ -392,10 +392,17 @@ ARG_DEF(NULL, "frame-parallel", 1, "Enable frame parallel decodability features " "(0: false (default), 1: true)"); +#if CONFIG_DELTA_Q +static const arg_def_t aq_mode = ARG_DEF( + NULL, "aq-mode", 1, + "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, " + "3: cyclic refresh)"); +#else static const arg_def_t aq_mode = ARG_DEF( NULL, "aq-mode", 1, "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, " "3: cyclic refresh, 4: equator360)"); +#endif static const arg_def_t frame_periodic_boost = ARG_DEF(NULL, "frame-boost", 1, "Enable frame periodic boost (0: off (default), 1: on)");
diff --git a/av1/common/blockd.h b/av1/common/blockd.h index cc990ea..3ff4943 100644 --- a/av1/common/blockd.h +++ b/av1/common/blockd.h
@@ -246,6 +246,9 @@ #endif // CONFIG_NEW_QUANT /* deringing gain *per-superblock* */ int8_t dering_gain; +#if CONFIG_DELTA_Q + int current_q_index; +#endif } MB_MODE_INFO; typedef struct MODE_INFO { @@ -401,6 +404,11 @@ #if CONFIG_GLOBAL_MOTION Global_Motion_Params *global_motion; #endif // CONFIG_GLOBAL_MOTION +#if CONFIG_DELTA_Q + int prev_qindex; + int delta_qindex; + int current_qindex; +#endif } MACROBLOCKD; static INLINE BLOCK_SIZE get_subsize(BLOCK_SIZE bsize,
diff --git a/av1/common/onyxc_int.h b/av1/common/onyxc_int.h index cf8d7b4..525680f 100644 --- a/av1/common/onyxc_int.h +++ b/av1/common/onyxc_int.h
@@ -395,6 +395,9 @@ #if CONFIG_DERING int dering_level; #endif +#if CONFIG_DELTA_Q + int delta_q_present_flag; +#endif } AV1_COMMON; // TODO(hkuang): Don't need to lock the whole pool after implementing atomic
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c index e4f2ee7..e3c7698 100644 --- a/av1/decoder/decodeframe.c +++ b/av1/decoder/decodeframe.c
@@ -1209,6 +1209,26 @@ } #endif // CONFIG_SUPERTX +#if CONFIG_DELTA_Q + if (cm->delta_q_present_flag) { + int i; + for (i = 0; i < MAX_SEGMENTS; i++) { + xd->plane[0].seg_dequant[i][0] = + av1_dc_quant(xd->current_qindex, cm->y_dc_delta_q, cm->bit_depth); + xd->plane[0].seg_dequant[i][1] = + av1_ac_quant(xd->current_qindex, 0, cm->bit_depth); + xd->plane[1].seg_dequant[i][0] = + av1_dc_quant(xd->current_qindex, cm->uv_dc_delta_q, cm->bit_depth); + xd->plane[1].seg_dequant[i][1] = + av1_ac_quant(xd->current_qindex, cm->uv_ac_delta_q, cm->bit_depth); + xd->plane[2].seg_dequant[i][0] = + av1_dc_quant(xd->current_qindex, cm->uv_dc_delta_q, cm->bit_depth); + xd->plane[2].seg_dequant[i][1] = + av1_ac_quant(xd->current_qindex, cm->uv_ac_delta_q, cm->bit_depth); + } + } +#endif + if (mbmi->skip) { dec_reset_skip_context(xd); } @@ -3485,6 +3505,27 @@ setup_segmentation(cm, rb); +#if CONFIG_DELTA_Q + { + struct segmentation *const seg = &cm->seg; + int segment_quantizer_active = 0; + for (i = 0; i < MAX_SEGMENTS; i++) { + if (segfeature_active(seg, i, SEG_LVL_ALT_Q)) { + segment_quantizer_active = 1; + } + } + + if (segment_quantizer_active == 0) { + cm->delta_q_present_flag = aom_rb_read_bit(rb); + } else { + cm->delta_q_present_flag = 0; + } + if (cm->delta_q_present_flag) { + xd->prev_qindex = cm->base_qindex; + } + } +#endif + for (i = 0; i < MAX_SEGMENTS; ++i) { const int qindex = cm->seg.enabled ? av1_get_qindex(&cm->seg, i, cm->base_qindex)
diff --git a/av1/decoder/decodemv.c b/av1/decoder/decodemv.c index 66056c0..37bc0f4 100644 --- a/av1/decoder/decodemv.c +++ b/av1/decoder/decodemv.c
@@ -598,6 +598,38 @@ mbmi->segment_id = read_intra_segment_id(cm, xd, mi_offset, x_mis, y_mis, r); mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r); + +#if CONFIG_DELTA_Q + if (cm->delta_q_present_flag) { + int b_col = mi_col & 7; + int b_row = mi_row & 7; + int read_delta_q_flag = (b_col == 0 && b_row == 0); + if ((bsize != BLOCK_64X64 || mbmi->skip == 0) && read_delta_q_flag) { + int sign, abs, tmp, delta_qindex; + + abs = 0; + tmp = aom_read_bit(r, ACCT_STR); + while (tmp == 0 && abs < 2) { + tmp = aom_read_bit(r, ACCT_STR); + abs++; + } + if (tmp == 0) { + abs = aom_read_literal(r, 6, ACCT_STR); + } + + if (abs) { + sign = aom_read_bit(r, ACCT_STR); + } else { + sign = 1; + } + + delta_qindex = sign ? -abs : abs; + xd->current_qindex = xd->prev_qindex + delta_qindex; + xd->prev_qindex = xd->current_qindex; + } + } +#endif + mbmi->tx_size = read_tx_size_intra(cm, xd, r); mbmi->ref_frame[0] = INTRA_FRAME; mbmi->ref_frame[1] = NONE; @@ -1655,6 +1687,35 @@ if (!supertx_enabled) { #endif // CONFIG_SUPERTX mbmi->skip = read_skip(cm, xd, mbmi->segment_id, r); +#if CONFIG_DELTA_Q + if (cm->delta_q_present_flag) { + BLOCK_SIZE bsize = mbmi->sb_type; + int b_col = mi_col & 7; + int b_row = mi_row & 7; + int read_delta_q_flag = (b_col == 0 && b_row == 0); + if ((bsize != BLOCK_64X64 || mbmi->skip == 0) && read_delta_q_flag) { + int sign, abs, tmp, delta_qindex; + + abs = 0; + tmp = aom_read_bit(r, ACCT_STR); + while (tmp == 0 && abs < 2) { + tmp = aom_read_bit(r, ACCT_STR); + abs++; + } + if (tmp == 0) { + abs = aom_read_literal(r, 6, ACCT_STR); + } + if (abs) { + sign = aom_read_bit(r, ACCT_STR); + } else { + sign = 1; + } + delta_qindex = sign ? -abs : abs; + xd->current_qindex = xd->prev_qindex + delta_qindex; + xd->prev_qindex = xd->current_qindex; + } + } +#endif inter_block = read_is_inter_block(cm, xd, mbmi->segment_id, r); #if CONFIG_VAR_TX
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c index b7cbc00..fe6ffe7 100644 --- a/av1/encoder/bitstream.c +++ b/av1/encoder/bitstream.c
@@ -488,6 +488,22 @@ } } +#if CONFIG_DELTA_Q +static void write_delta_qindex(int delta_qindex, aom_writer *w) { + int sign = delta_qindex < 0; + int abs = sign ? -delta_qindex : delta_qindex; + if (abs < 3) { + aom_write_literal(w, 1, abs + 1); + } else { + aom_write_literal(w, 0, 3); + aom_write_literal(w, abs, 6); + } + if (abs > 0) { + aom_write_bit(w, sign); + } +} +#endif + static void update_skip_probs(AV1_COMMON *cm, aom_writer *w, FRAME_COUNTS *counts) { int k; @@ -1069,8 +1085,14 @@ #if !CONFIG_REF_MV const nmv_context *nmvc = &cm->fc->nmvc; #endif + +#if CONFIG_DELTA_Q + MACROBLOCK *const x = &cpi->td.mb; + MACROBLOCKD *const xd = &x->e_mbd; +#else const MACROBLOCK *x = &cpi->td.mb; const MACROBLOCKD *xd = &x->e_mbd; +#endif const struct segmentation *const seg = &cm->seg; const struct segmentation_probs *const segp = &cm->fc->seg; const MB_MODE_INFO *const mbmi = &mi->mbmi; @@ -1102,6 +1124,18 @@ #else skip = write_skip(cm, xd, segment_id, mi, w); #endif // CONFIG_SUPERTX +#if CONFIG_DELTA_Q + if (cm->delta_q_present_flag) { + int mi_row = (-xd->mb_to_top_edge) >> 6; + int mi_col = (-xd->mb_to_left_edge) >> 6; + int super_block_upper_left = ((mi_row & 7) == 0) && ((mi_col & 7) == 0); + if ((bsize != BLOCK_64X64 || skip == 0) && super_block_upper_left) { + int delta_qindex = mbmi->current_q_index - xd->prev_qindex; + write_delta_qindex(delta_qindex, w); + xd->prev_qindex = mbmi->current_q_index; + } + } +#endif #if CONFIG_SUPERTX if (!supertx_enabled) @@ -1503,8 +1537,14 @@ } } +#if CONFIG_DELTA_Q +static void write_mb_modes_kf(const AV1_COMMON *cm, MACROBLOCKD *xd, + MODE_INFO **mi_8x8, aom_writer *w) { + int skip; +#else static void write_mb_modes_kf(const AV1_COMMON *cm, const MACROBLOCKD *xd, MODE_INFO **mi_8x8, aom_writer *w) { +#endif const struct segmentation *const seg = &cm->seg; const struct segmentation_probs *const segp = &cm->fc->seg; const MODE_INFO *const mi = mi_8x8[0]; @@ -1515,7 +1555,21 @@ if (seg->update_map) write_segment_id(w, seg, segp, mbmi->segment_id); +#if CONFIG_DELTA_Q + skip = write_skip(cm, xd, mbmi->segment_id, mi, w); + if (cm->delta_q_present_flag) { + int mi_row = (-xd->mb_to_top_edge) >> 6; + int mi_col = (-xd->mb_to_left_edge) >> 6; + int super_block_upper_left = ((mi_row & 7) == 0) && ((mi_col & 7) == 0); + if ((bsize != BLOCK_64X64 || skip == 0) && super_block_upper_left) { + int delta_qindex = mbmi->current_q_index - xd->prev_qindex; + write_delta_qindex(delta_qindex, w); + xd->prev_qindex = mbmi->current_q_index; + } + } +#else write_skip(cm, xd, mbmi->segment_id, mi, w); +#endif if (bsize >= BLOCK_8X8 && cm->tx_mode == TX_MODE_SELECT && !xd->lossless[mbmi->segment_id]) @@ -2000,8 +2054,12 @@ const int mi_col_start = tile->mi_col_start; const int mi_col_end = tile->mi_col_end; int mi_row, mi_col; - av1_zero_above_context(cm, mi_col_start, mi_col_end); +#if CONFIG_DELTA_Q + if (cpi->common.delta_q_present_flag) { + xd->prev_qindex = cpi->common.base_qindex; + } +#endif for (mi_row = mi_row_start; mi_row < mi_row_end; mi_row += cm->mib_size) { av1_zero_left_context(xd); @@ -3337,6 +3395,26 @@ #endif // CONFIG_LOOP_RESTORATION encode_quantization(cm, wb); encode_segmentation(cm, xd, wb); +#if CONFIG_DELTA_Q + { + int i; + struct segmentation *const seg = &cm->seg; + int segment_quantizer_active = 0; + for (i = 0; i < MAX_SEGMENTS; i++) { + if (segfeature_active(seg, i, SEG_LVL_ALT_Q)) { + segment_quantizer_active = 1; + } + } + if (segment_quantizer_active == 0) { + cm->delta_q_present_flag = cpi->oxcf.aq_mode == DELTA_AQ; + aom_wb_write_bit(wb, cm->delta_q_present_flag); + if (cm->delta_q_present_flag) { + xd->prev_qindex = cm->base_qindex; + } + } + } +#endif + if (!cm->seg.enabled && xd->lossless[0]) cm->tx_mode = ONLY_4X4; else
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c index 004ad68..dce26dd 100644 --- a/av1/encoder/encodeframe.c +++ b/av1/encoder/encodeframe.c
@@ -1114,8 +1114,13 @@ xd->mi[x_idx + y * mis] = mi_addr; } +#if CONFIG_DELTA_Q + if (cpi->oxcf.aq_mode > NO_AQ && cpi->oxcf.aq_mode < DELTA_AQ) + av1_init_plane_quantizers(cpi, x); +#else if (cpi->oxcf.aq_mode) av1_init_plane_quantizers(cpi, x, xd->mi[0]->mbmi.segment_id); +#endif if (is_inter_block(mbmi) && mbmi->sb_type < BLOCK_8X8) { mbmi->mv[0].as_int = mi->bmi[3].as_mv[0].as_int; @@ -4188,6 +4193,22 @@ seg_skip = segfeature_active(seg, segment_id, SEG_LVL_SKIP); } +#if CONFIG_DELTA_Q + if (cpi->oxcf.aq_mode == DELTA_AQ) { + int sb_row = mi_row >> 3; + int sb_col = mi_col >> 3; + int sb_stride = (cm->width + MAX_SB_SIZE - 1) >> MAX_SB_SIZE_LOG2; + int index = ((sb_row * sb_stride + sb_col + 8) & 31) - 16; + int offset_qindex = index < 0 ? -index - 8 : index - 8; + int current_qindex = clamp(cm->base_qindex + offset_qindex, 1, 255); + xd->delta_qindex = current_qindex - cm->base_qindex; + set_offsets(cpi, tile_info, x, mi_row, mi_col, BLOCK_64X64); + xd->mi[0]->mbmi.current_q_index = current_qindex; + xd->mi[0]->mbmi.segment_id = 0; + av1_init_plane_quantizers(cpi, x); + } +#endif + x->source_variance = UINT_MAX; if (sf->partition_search_type == FIXED_PARTITION || seg_skip) { BLOCK_SIZE bsize;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index e2046ec..b55481b 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -133,6 +133,9 @@ VARIANCE_AQ = 1, COMPLEXITY_AQ = 2, CYCLIC_REFRESH_AQ = 3, +#if CONFIG_DELTA_Q + DELTA_AQ = 4, +#endif AQ_MODE_COUNT // This should always be the last member of the enum } AQ_MODE;
diff --git a/av1/encoder/quantize.c b/av1/encoder/quantize.c index 554a38b..db2fdb8 100644 --- a/av1/encoder/quantize.c +++ b/av1/encoder/quantize.c
@@ -1219,7 +1219,15 @@ const AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; const QUANTS *const quants = &cpi->quants; + +#if CONFIG_DELTA_Q + int current_q_index = cpi->oxcf.aq_mode == DELTA_AQ + ? cm->base_qindex + xd->delta_qindex + : cm->base_qindex; + const int qindex = av1_get_qindex(&cm->seg, segment_id, current_q_index); +#else const int qindex = av1_get_qindex(&cm->seg, segment_id, cm->base_qindex); +#endif const int rdmult = av1_compute_rd_mult(cpi, qindex + cm->y_dc_delta_q); int i; #if CONFIG_AOM_QM
diff --git a/configure b/configure index 4e9a52c..c396632 100755 --- a/configure +++ b/configure
@@ -285,6 +285,7 @@ daala_ec cb4x4 frame_size + delta_q " CONFIG_LIST=" dependency_tracking