Split delta_lf from delta_q mode and refactor
Splits delta_lf mode from delta q mode as a separate
control and command line option. Also, makes space
for a new delta q mode based on prediction efficiency
along with the existing mode based on spatial perceptual
characteristics.
Change-Id: I594e5665ae00a0c683f5340fe0469e49241ebab3
diff --git a/aom/aomcx.h b/aom/aomcx.h
index 2c4309a..2cf4ad7 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -990,16 +990,23 @@
/*!\brief Codec control function to set the delta q mode
*
- * AV1 has a segment based feature that allows encoder to adaptively change
- * quantization parameter for each segment within a frame to improve the
- * subjective quality. the delta q mode is added on top of segment based
- * feature, and allows control per 64x64 q and lf delta.This control makes
- * encoder operate in one of the several DELTA_Q_modes supported.
+ * AV1 supports a delta q mode feature, that allows modulating q per
+ * superblock. This control makes encoder operate in one of several
+ * DELTA_Q_modes supported:
+ * 0: Not Supported
+ * 1: Use modulation to maximize objective quality
+ * 2: Use modulation to maximize perceptual quality
*
* By default, encoder operates with DELTAQ_Mode 0(deltaq signaling off).
*/
AV1E_SET_DELTAQ_MODE,
+ /*!\brief Codec control function to turn on/off loopfilter modulation
+ * when delta q modulation is enabled. Note AV1 only supports loopfilter
+ * modulation when delta q modulation is enabled as well.
+ */
+ AV1E_SET_DELTALF_MODE,
+
/*!\brief Codec control function to set the single tile decoding mode to 0 or
* 1.
*
@@ -1406,6 +1413,9 @@
AOM_CTRL_USE_TYPE(AV1E_SET_DELTAQ_MODE, unsigned int)
#define AOM_CTRL_AV1E_SET_DELTAQ_MODE
+AOM_CTRL_USE_TYPE(AV1E_SET_DELTALF_MODE, unsigned int)
+#define AOM_CTRL_AV1E_SET_DELTALF_MODE
+
AOM_CTRL_USE_TYPE(AV1E_SET_FRAME_PERIODIC_BOOST, unsigned int)
#define AOM_CTRL_AV1E_SET_FRAME_PERIODIC_BOOST
diff --git a/apps/aomenc.c b/apps/aomenc.c
index 3663dff..cfbf8e2 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -629,9 +629,12 @@
NULL, "aq-mode", 1,
"Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
"3: cyclic refresh)");
-static const arg_def_t deltaq_mode = ARG_DEF(
- NULL, "deltaq-mode", 1,
- "Delta qindex mode (0: off (default), 1: deltaq 2: deltaq + deltalf)");
+static const arg_def_t deltaq_mode =
+ ARG_DEF(NULL, "deltaq-mode", 1,
+ "Delta qindex mode (0: off (default), 1: deltaq pred efficiency, "
+ "2: deltaq perceptual)");
+static const arg_def_t deltalf_mode = ARG_DEF(
+ NULL, "delta-lf-mode", 1, "Enable delta-lf-mode (0: off (default), 1: on)");
static const arg_def_t frame_periodic_boost =
ARG_DEF(NULL, "frame-boost", 1,
"Enable frame periodic boost (0: off (default), 1: on)");
@@ -840,6 +843,7 @@
&error_resilient_mode,
&aq_mode,
&deltaq_mode,
+ &deltalf_mode,
&frame_periodic_boost,
&noise_sens,
&tune_content,
@@ -939,6 +943,7 @@
AV1E_SET_ERROR_RESILIENT_MODE,
AV1E_SET_AQ_MODE,
AV1E_SET_DELTAQ_MODE,
+ AV1E_SET_DELTALF_MODE,
AV1E_SET_FRAME_PERIODIC_BOOST,
AV1E_SET_NOISE_SENSITIVITY,
AV1E_SET_TUNE_CONTENT,
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index e9a9b82..398d672 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -72,6 +72,7 @@
int enable_dual_filter;
AQ_MODE aq_mode;
DELTAQ_MODE deltaq_mode;
+ int deltalf_mode;
unsigned int frame_periodic_boost;
aom_bit_depth_t bit_depth;
aom_tune_content content;
@@ -186,6 +187,7 @@
1, // enable dual filter
NO_AQ, // aq_mode
NO_DELTA_Q, // deltaq_mode
+ 0, // delta lf mode
0, // frame_periodic_delta_q
AOM_BITS_8, // Bit depth
AOM_CONTENT_DEFAULT, // content
@@ -324,7 +326,8 @@
RANGE_CHECK_HI(cfg, rc_min_quantizer, cfg->rc_max_quantizer);
RANGE_CHECK_BOOL(extra_cfg, lossless);
RANGE_CHECK_HI(extra_cfg, aq_mode, AQ_MODE_COUNT - 1);
- RANGE_CHECK_HI(extra_cfg, deltaq_mode, DELTAQ_MODE_COUNT - 1);
+ RANGE_CHECK_HI(extra_cfg, deltaq_mode, DELTA_Q_MODE_COUNT - 1);
+ RANGE_CHECK_HI(extra_cfg, deltalf_mode, 1);
RANGE_CHECK_HI(extra_cfg, frame_periodic_boost, 1);
RANGE_CHECK_HI(cfg, g_usage, 1);
RANGE_CHECK_HI(cfg, g_threads, MAX_NUM_THREADS);
@@ -683,9 +686,6 @@
}
}
- oxcf->enable_tpl_model =
- extra_cfg->enable_tpl_model && (oxcf->superres_mode == SUPERRES_NONE);
-
oxcf->maximum_buffer_size_ms = is_vbr ? 240000 : cfg->rc_buf_sz;
oxcf->starting_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_initial_sz;
oxcf->optimal_buffer_level_ms = is_vbr ? 60000 : cfg->rc_buf_optimal_sz;
@@ -833,8 +833,23 @@
oxcf->timing_info_present = 0;
}
+ oxcf->enable_tpl_model =
+ extra_cfg->enable_tpl_model && (oxcf->superres_mode == SUPERRES_NONE);
+
oxcf->aq_mode = extra_cfg->aq_mode;
oxcf->deltaq_mode = extra_cfg->deltaq_mode;
+ // Turn on tpl model for deltaq_mode == DELTA_Q_OBJECTIVE and no
+ // superres. If superres is being used on the other hand, turn
+ // delta_q off.
+ if (oxcf->deltaq_mode == DELTA_Q_OBJECTIVE) {
+ if (oxcf->superres_mode == SUPERRES_NONE)
+ oxcf->enable_tpl_model = 1;
+ else
+ oxcf->deltaq_mode = NO_DELTA_Q;
+ }
+
+ oxcf->deltalf_mode =
+ (oxcf->deltaq_mode != NO_DELTA_Q) && extra_cfg->deltalf_mode;
oxcf->save_as_annexb = cfg->save_as_annexb;
@@ -1507,6 +1522,13 @@
return update_extra_cfg(ctx, &extra_cfg);
}
+static aom_codec_err_t ctrl_set_deltalf_mode(aom_codec_alg_priv_t *ctx,
+ va_list args) {
+ struct av1_extracfg extra_cfg = ctx->extra_cfg;
+ extra_cfg.deltalf_mode = CAST(AV1E_SET_DELTALF_MODE, args);
+ return update_extra_cfg(ctx, &extra_cfg);
+}
+
static aom_codec_err_t ctrl_set_min_gf_interval(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@@ -2231,6 +2253,7 @@
{ AV1E_SET_COEFF_COST_UPD_FREQ, ctrl_set_coeff_cost_upd_freq },
{ AV1E_SET_MODE_COST_UPD_FREQ, ctrl_set_mode_cost_upd_freq },
{ AV1E_SET_DELTAQ_MODE, ctrl_set_deltaq_mode },
+ { AV1E_SET_DELTALF_MODE, ctrl_set_deltalf_mode },
{ AV1E_SET_FRAME_PERIODIC_BOOST, ctrl_set_frame_periodic_boost },
{ AV1E_SET_TUNE_CONTENT, ctrl_set_tune_content },
{ AV1E_SET_CDF_UPDATE_MODE, ctrl_set_cdf_update_mode },
diff --git a/av1/encoder/aq_variance.c b/av1/encoder/aq_variance.c
index d572948..9b58363 100644
--- a/av1/encoder/aq_variance.c
+++ b/av1/encoder/aq_variance.c
@@ -185,7 +185,7 @@
int rate_level;
const AV1_COMMON *const cm = &cpi->common;
- if (DELTAQ_MODULATION == 1) {
+ if (DELTA_Q_PERCEPTUAL_MODULATION == 1) {
ENERGY_IN_BOUNDS(block_var_level);
rate_level = SEGMENT_ID(block_var_level);
} else {
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index f079d90..61e1d2b 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -634,7 +634,7 @@
x->rdmult = x->cb_rdmult;
}
- if (deltaq_mode > 0) x->rdmult = set_deltaq_rdmult(cpi, xd);
+ if (deltaq_mode != NO_DELTA_Q) x->rdmult = set_deltaq_rdmult(cpi, xd);
// Find best coding mode & reconstruct the MB so it is available
// as a predictor for MBs that follow in the SB
@@ -1486,7 +1486,7 @@
mbmi->partition = partition;
update_state(cpi, tile_data, td, ctx, mi_row, mi_col, bsize, dry_run);
if (cpi->oxcf.enable_tpl_model && cpi->oxcf.aq_mode == NO_AQ &&
- cpi->oxcf.deltaq_mode == 0) {
+ cpi->oxcf.deltaq_mode == NO_DELTA_Q) {
x->rdmult = x->cb_rdmult;
}
@@ -4250,7 +4250,7 @@
av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, sb_size);
int offset_qindex;
- if (DELTAQ_MODULATION == 1) {
+ if (DELTA_Q_PERCEPTUAL_MODULATION == 1) {
const int block_wavelet_energy_level =
av1_block_wavelet_energy_level(cpi, x, sb_size);
x->sb_energy_level = block_wavelet_energy_level;
@@ -4275,7 +4275,7 @@
set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size);
xd->mi[0]->current_qindex = current_qindex;
av1_init_plane_quantizers(cpi, x, xd->mi[0]->segment_id);
- if (cpi->oxcf.deltaq_mode == DELTA_Q_LF) {
+ if (cpi->oxcf.deltaq_mode != NO_DELTA_Q && cpi->oxcf.deltalf_mode) {
const int lfmask = ~(delta_q_info->delta_lf_res - 1);
const int delta_lf_from_base =
((offset_qindex / 2 + delta_q_info->delta_lf_res / 2) & lfmask);
@@ -4707,7 +4707,7 @@
const int orig_rdmult = cpi->rd.RDMULT;
x->cb_rdmult = orig_rdmult;
if (cpi->twopass.gf_group.index > 0 && cpi->oxcf.enable_tpl_model &&
- cpi->oxcf.aq_mode == NO_AQ && cpi->oxcf.deltaq_mode == 0) {
+ cpi->oxcf.aq_mode == NO_AQ && cpi->oxcf.deltaq_mode == NO_DELTA_Q) {
const int dr =
get_rdmult_delta(cpi, BLOCK_128X128, mi_row, mi_col, orig_rdmult);
@@ -5332,7 +5332,8 @@
// Set delta_q_present_flag before it is used for the first time
cm->delta_q_info.delta_lf_res = DEFAULT_DELTA_LF_RES;
cm->delta_q_info.delta_q_present_flag = cpi->oxcf.deltaq_mode != NO_DELTA_Q;
- cm->delta_q_info.delta_lf_present_flag = cpi->oxcf.deltaq_mode == DELTA_Q_LF;
+ cm->delta_q_info.delta_lf_present_flag =
+ cpi->oxcf.deltaq_mode != NO_DELTA_Q && cpi->oxcf.deltalf_mode;
cm->delta_q_info.delta_lf_multi = DEFAULT_DELTA_LF_MULTI;
// update delta_q_present_flag and delta_lf_present_flag based on
// base_qindex
diff --git a/av1/encoder/encodeframe.h b/av1/encoder/encodeframe.h
index 3b1730d..e4c4841 100644
--- a/av1/encoder/encodeframe.h
+++ b/av1/encoder/encodeframe.h
@@ -20,7 +20,9 @@
extern "C" {
#endif
-#define DELTAQ_MODULATION 1 // 0: variance based, 1: wavelet AC energy based
+#define DELTA_Q_PERCEPTUAL_MODULATION \
+ 1 // 0: variance based
+ // 1: wavelet AC energy based
struct macroblock;
struct yv12_buffer_config;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index bf02394..edb9507 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -110,9 +110,9 @@
} UENUM1BYTE(AQ_MODE);
enum {
NO_DELTA_Q = 0,
- DELTA_Q_ONLY = 1,
- DELTA_Q_LF = 2,
- DELTAQ_MODE_COUNT // This should always be the last member of the enum
+ DELTA_Q_OBJECTIVE = 1, // Modulation to improve objective quality
+ DELTA_Q_PERCEPTUAL = 2, // Modulation to improve perceptual quality
+ DELTA_Q_MODE_COUNT // This should always be the last member of the enum
} UENUM1BYTE(DELTAQ_MODE);
enum {
@@ -237,6 +237,7 @@
int cq_level;
AQ_MODE aq_mode; // Adaptive Quantization mode
DELTAQ_MODE deltaq_mode;
+ int deltalf_mode;
int enable_cdef;
int enable_restoration;
int enable_obmc;
diff --git a/av1/encoder/encodetxb.c b/av1/encoder/encodetxb.c
index 37f4bb9..ee30e63 100644
--- a/av1/encoder/encodetxb.c
+++ b/av1/encoder/encodetxb.c
@@ -1690,15 +1690,15 @@
const LV_MAP_EOB_COST *txb_eob_costs =
&x->eob_costs[eob_multi_size][plane_type];
- const int rshift =
- (sharpness +
- (cpi->oxcf.aq_mode == VARIANCE_AQ && mbmi->segment_id < 4
- ? 7 - mbmi->segment_id
- : 2) +
- (cpi->oxcf.aq_mode != VARIANCE_AQ &&
- cpi->oxcf.deltaq_mode > NO_DELTA_Q && x->sb_energy_level < 0
- ? (3 - x->sb_energy_level)
- : 0));
+ const int rshift = (sharpness +
+ (cpi->oxcf.aq_mode == VARIANCE_AQ && mbmi->segment_id < 4
+ ? 7 - mbmi->segment_id
+ : 2) +
+ (cpi->oxcf.aq_mode != VARIANCE_AQ &&
+ cpi->oxcf.deltaq_mode == DELTA_Q_PERCEPTUAL &&
+ x->sb_energy_level < 0
+ ? (3 - x->sb_energy_level)
+ : 0));
const int64_t rdmult =
(((int64_t)x->rdmult *
(plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8)))) +
diff --git a/av1/encoder/picklpf.c b/av1/encoder/picklpf.c
index aca089c..bc222f1 100644
--- a/av1/encoder/picklpf.c
+++ b/av1/encoder/picklpf.c
@@ -57,7 +57,7 @@
if (plane == 0 && dir == 0) filter_level[1] = cm->lf.filter_level[1];
if (plane == 0 && dir == 1) filter_level[0] = cm->lf.filter_level[0];
- // set base filters for use of get_filter_level when in DELTA_Q_LF mode
+ // set base filters for use of get_filter_level when in DELTA_LF mode
switch (plane) {
case 0:
cm->lf.filter_level[0] = filter_level[0];