Add FLEX_STEPS experiment to research-quant
*Replace strtok to custom fn
*followed recommendation of geritt to use snprintf
* Revert new 25 q-step based AC/DC Q derivation for FLEX_STEPS code path
Change-Id: I4d31ffdbd48345033895cc06aac74ed45e26d8ef
diff --git a/aom/aom_encoder.h b/aom/aom_encoder.h
index 33326ff..a21753b 100644
--- a/aom/aom_encoder.h
+++ b/aom/aom_encoder.h
@@ -354,6 +354,17 @@
*
*/
unsigned int reduced_tx_type_set;
+
+#if CONFIG_FLEX_STEPS
+ /*!\brief qstep mode
+ *
+ */
+ unsigned int qstep_mode;
+ /*!\brief qstep config path
+ *
+ */
+ const char *qstep_config_path;
+#endif
} cfg_options_t;
/*!\brief Encoded Frame Flags
diff --git a/aom/aomcx.h b/aom/aomcx.h
index db2a744..cf9e914 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -1307,6 +1307,14 @@
/*!\brief Control to get frame info
*/
AV1E_GET_FRAME_INFO = 165,
+
+#if CONFIG_FLEX_STEPS
+
+ /*!\brief Control to get frame info
+ */
+ AV1E_SET_QSTEP_CONFIG_PATH = 165,
+
+#endif
};
/*!\brief aom 1-D scaling mode
@@ -1848,6 +1856,11 @@
AOM_CTRL_USE_TYPE(AV1E_SET_SUBGOP_CONFIG_PATH, const char *)
#define AOM_CTRL_AV1E_SET_SUBGOP_CONFIG_PATH
+#if CONFIG_FLEX_STEPS
+AOM_CTRL_USE_TYPE(AV1E_SET_QSTEP_CONFIG_PATH, const char *)
+#define AOM_CTRL_AV1E_SET_QSTEP_CONFIG_PATH
+#endif
+
/*!\endcond */
/*! @} - end defgroup aom_encoder */
#ifdef __cplusplus
diff --git a/apps/aomenc.c b/apps/aomenc.c
index 005b4cb..b0d79e2 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -51,6 +51,10 @@
#include "third_party/libyuv/include/libyuv/scale.h"
#endif
+#if CONFIG_FLEX_STEPS
+#include "aom_mem/aom_mem.h"
+#endif
+
#if UINTPTR_MAX == 0xffffffff
#define ENV_BITS "32 bit "
#elif UINTPTR_MAX == 0xffffffffffffffff
@@ -853,6 +857,11 @@
"If this option is not specified (default), the configurations "
"are chosen by the encoder using a default algorithm.");
+#if CONFIG_FLEX_STEPS
+static const arg_def_t qstep_config_path =
+ ARG_DEF(NULL, "qstep-config-path", 1, "Path to the qStep cofig file");
+#endif
+
static const arg_def_t *av1_args[] = { &cpu_used_av1,
&auto_altref,
&sharpness,
@@ -959,6 +968,9 @@
#endif
&subgop_config_str,
&subgop_config_path,
+#if CONFIG_FLEX_STEPS
+ &qstep_config_path,
+#endif
NULL };
static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
AOME_SET_ENABLEAUTOALTREF,
@@ -1066,6 +1078,9 @@
#endif
AV1E_SET_SUBGOP_CONFIG_STR,
AV1E_SET_SUBGOP_CONFIG_PATH,
+#if CONFIG_FLEX_STEPS
+ AV1E_SET_QSTEP_CONFIG_PATH,
+#endif
0 };
#endif // CONFIG_AV1_ENCODER
@@ -1143,6 +1158,9 @@
#endif
const char *subgop_config_str;
const char *subgop_config_path;
+#if CONFIG_FLEX_STEPS
+ const char *qstep_config_path;
+#endif
};
struct stream_state {
@@ -1427,6 +1445,13 @@
return;
}
+#if CONFIG_FLEX_STEPS
+ if (key == AV1E_SET_QSTEP_CONFIG_PATH) {
+ config->qstep_config_path = arg->val;
+ return;
+ }
+#endif
+
// For target level, the settings should accumulate rather than overwrite,
// so we simply append it.
if (key == AV1E_SET_TARGET_SEQ_LEVEL_IDX) {
@@ -1935,7 +1960,10 @@
"LoopRestortion (%d)\n",
encoder_cfg->enable_deblocking, encoder_cfg->enable_cdef,
encoder_cfg->enable_restoration);
-
+#if CONFIG_FLEX_STEPS
+ fprintf(stdout, "Tool setting (Quantization) : Mode (%d)\n",
+ encoder_cfg->qstep_mode);
+#endif
fprintf(stdout,
"Tool setting (Others) : Palette (%d), IntraBC (%d)\n",
encoder_cfg->enable_palette, encoder_cfg->enable_intrabc);
@@ -2025,6 +2053,20 @@
flags |= stream->config.use_16bit_internal ? AOM_CODEC_USE_HIGHBITDEPTH : 0;
flags |= global->quiet ? 0 : AOM_CODEC_USE_PER_FRAME_STATS;
+#if CONFIG_FLEX_STEPS
+ struct stream_config *sc_cfg = &stream->config;
+ if (sc_cfg->qstep_config_path != NULL) {
+ sc_cfg->cfg.encoder_cfg.qstep_config_path =
+ (char *)aom_malloc((strlen(sc_cfg->qstep_config_path) + 1) *
+ sizeof(*sc_cfg->qstep_config_path));
+ // strcpy((char *)sc_cfg->cfg.encoder_cfg.qstep_config_path,
+ // sc_cfg->qstep_config_path);
+ snprintf((char *)sc_cfg->cfg.encoder_cfg.qstep_config_path,
+ (strlen(sc_cfg->qstep_config_path) + 1) *
+ sizeof(*sc_cfg->qstep_config_path),
+ "%s", sc_cfg->qstep_config_path);
+ }
+#endif
/* Construct Encoder Context */
aom_codec_enc_init(&stream->encoder, global->codec, &stream->config.cfg,
flags);
@@ -2059,6 +2101,13 @@
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_SUBGOP_CONFIG_PATH,
stream->config.subgop_config_path);
}
+#if CONFIG_FLEX_STEPS
+ if (stream->config.qstep_config_path) {
+ AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_QSTEP_CONFIG_PATH,
+ stream->config.qstep_config_path);
+ }
+#endif
+
#if CONFIG_AV1_DECODER
if (global->test_decode != TEST_DECODE_OFF) {
aom_codec_iface_t *decoder = get_aom_decoder_by_short_name(
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 8b0d50e..27feb82 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -27,6 +27,10 @@
#include "av1/encoder/ethread.h"
#include "av1/encoder/firstpass.h"
+#if CONFIG_FLEX_STEPS
+#include "av1/encoder/encoder_utils.h"
+#endif
+
#include "aom_dsp/psnr.h"
#include "aom_ports/aom_timer.h"
@@ -54,6 +58,9 @@
const char *vmaf_model_path;
const char *subgop_config_str;
const char *subgop_config_path;
+#if CONFIG_FLEX_STEPS
+ const char *qstep_config_path;
+#endif
unsigned int qp; // constant/constrained quality level
unsigned int rc_max_intra_bitrate_pct;
unsigned int rc_max_inter_bitrate_pct;
@@ -298,25 +305,28 @@
"/usr/local/share/model/vmaf_v0.6.1.pkl", // VMAF model path
NULL, // subgop_config_str
NULL, // subgop_config_path
- 40, // qp
- 0, // rc_max_intra_bitrate_pct
- 0, // rc_max_inter_bitrate_pct
- 0, // gf_cbr_boost_pct
- 0, // lossless
- 1, // enable_deblocking
- 1, // enable_cdef
- 1, // enable_restoration
- 0, // force_video_mode
- 1, // enable_obmc
- 3, // enable_trellis_quant
- 0, // enable_qm
- DEFAULT_QM_Y, // qm_y
- DEFAULT_QM_U, // qm_u
- DEFAULT_QM_V, // qm_v
- DEFAULT_QM_FIRST, // qm_min
- DEFAULT_QM_LAST, // qm_max
- 1, // max number of tile groups
- 0, // mtu_size
+#if CONFIG_FLEX_STEPS
+ NULL, // qstep_config_path
+#endif
+ 40, // qp
+ 0, // rc_max_intra_bitrate_pct
+ 0, // rc_max_inter_bitrate_pct
+ 0, // gf_cbr_boost_pct
+ 0, // lossless
+ 1, // enable_deblocking
+ 1, // enable_cdef
+ 1, // enable_restoration
+ 0, // force_video_mode
+ 1, // enable_obmc
+ 3, // enable_trellis_quant
+ 0, // enable_qm
+ DEFAULT_QM_Y, // qm_y
+ DEFAULT_QM_U, // qm_u
+ DEFAULT_QM_V, // qm_v
+ DEFAULT_QM_FIRST, // qm_min
+ DEFAULT_QM_LAST, // qm_max
+ 1, // max number of tile groups
+ 0, // mtu_size
AOM_TIMING_UNSPECIFIED, // No picture timing signaling in bitstream
0, // frame_parallel_decoding_mode
#if !CONFIG_REMOVE_DUAL_FILTER
@@ -1142,6 +1152,9 @@
}
}
+#if CONFIG_FLEX_STEPS
+ oxcf->qstep_config_path = extra_cfg->qstep_config_path;
+#endif
// Set tune related configuration.
tune_cfg->tuning = extra_cfg->tuning;
tune_cfg->vmaf_model_path = extra_cfg->vmaf_model_path;
@@ -2087,6 +2100,15 @@
return update_extra_cfg(ctx, &extra_cfg);
}
+#if CONFIG_FLEX_STEPS
+static aom_codec_err_t ctrl_set_qstep_config_path(aom_codec_alg_priv_t *ctx,
+ va_list args) {
+ struct av1_extracfg extra_cfg = ctx->extra_cfg;
+ extra_cfg.qstep_config_path = CAST(AV1E_SET_QSTEP_CONFIG_PATH, args);
+ return update_extra_cfg(ctx, &extra_cfg);
+}
+#endif
+
static aom_codec_err_t ctrl_set_film_grain_test_vector(
aom_codec_alg_priv_t *ctx, va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@@ -2303,6 +2325,33 @@
priv->cfg = *ctx->config.enc;
ctx->config.enc = &priv->cfg;
}
+#if CONFIG_FLEX_STEPS
+ QuantizationCfg *q_cfg = &priv->oxcf.q_cfg;
+ // initialize defualt mode
+ q_cfg->qStep_mode = 0;
+ q_cfg->num_qStep_intervals = 9;
+ int defaultQSteps[] = { 8, 8, 16, 32, 32, 32, 32, 32, 32, 32 };
+ for (int idx = 0; idx <= q_cfg->num_qStep_intervals; idx++) {
+ q_cfg->num_qsteps_in_interval[idx] = defaultQSteps[idx];
+ }
+
+ if (ctx->config.enc->encoder_cfg.qstep_config_path != NULL) {
+ priv->oxcf.qstep_config_path = (char *)aom_malloc(
+ (strlen(ctx->config.enc->encoder_cfg.qstep_config_path) + 1) *
+ sizeof(*ctx->config.enc->encoder_cfg.qstep_config_path));
+ // strcpy((char *)priv->oxcf.qstep_config_path,
+ // ctx->config.enc->encoder_cfg.qstep_config_path);
+ snprintf((char *)priv->oxcf.qstep_config_path,
+ (strlen(ctx->config.enc->encoder_cfg.qstep_config_path) + 1) *
+ sizeof(*ctx->config.enc->encoder_cfg.qstep_config_path),
+ "%s", ctx->config.enc->encoder_cfg.qstep_config_path);
+ initialize_qstep_param(priv->oxcf.qstep_config_path, &priv->oxcf);
+ }
+
+ set_enc_qstep_table(&priv->oxcf);
+ priv->cfg.encoder_cfg.qstep_mode = q_cfg->qStep_mode;
+ // dump_qStep_table(q_cfg->qStep_mode, 0);
+#endif
priv->extra_cfg = default_extra_cfg;
aom_once(av1_initialize_enc);
@@ -2344,6 +2393,20 @@
priv->frame_stats_buffer, ENCODE_STAGE, *num_lap_buffers, -1,
&priv->stats_buf_context);
+#if CONFIG_FLEX_STEPS
+ if (res == AOM_CODEC_OK) {
+ if (priv->oxcf.qstep_config_path != NULL) {
+ priv->cpi->qstep_config_path =
+ (char *)aom_malloc((strlen(priv->oxcf.qstep_config_path) + 1) *
+ sizeof(*priv->oxcf.qstep_config_path));
+ // strcpy(priv->cpi->qstep_config_path, priv->oxcf.qstep_config_path);
+ snprintf(priv->cpi->qstep_config_path,
+ (strlen(priv->oxcf.qstep_config_path) + 1) *
+ sizeof(*priv->oxcf.qstep_config_path),
+ "%s", priv->oxcf.qstep_config_path);
+ }
+ }
+#endif
// Create another compressor if look ahead is enabled
if (res == AOM_CODEC_OK && *num_lap_buffers) {
res = create_context_and_bufferpool(
@@ -3298,6 +3361,9 @@
{ AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP, ctrl_set_vbr_corpus_complexity_lap },
{ AV1E_ENABLE_SB_MULTIPASS_UNIT_TEST, ctrl_enable_sb_multipass_unit_test },
{ AV1E_ENABLE_SUBGOP_STATS, ctrl_enable_subgop_stats },
+#if CONFIG_FLEX_STEPS
+ { AV1E_SET_QSTEP_CONFIG_PATH, ctrl_set_qstep_config_path },
+#endif
// Getters
{ AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer },
@@ -3382,15 +3448,19 @@
{ 0 }, // tile_heights
0, // use_fixed_qp_offsets
{ -1, -1, -1, -1, -1 }, // fixed_qp_offsets
- { 0, 128, 128, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ { 0, 128, 128, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
#if !CONFIG_REMOVE_DIST_WTD_COMP
1,
#endif // !CONFIG_REMOVE_DIST_WTD_COMP
1, 1, 1, 0, 0, 1, 1, 1, 1,
#if !CONFIG_REMOVE_DUAL_FILTER
1,
-#endif // !CONFIG_REMOVE_DUAL_FILTER
+#endif // !CONFIG_REMOVE_DUAL_FILTER
+#if CONFIG_FLEX_STEPS
+ 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0, 0, NULL }, // cfg
+#else
1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0 }, // cfg
+#endif
},
{
// NOLINT
@@ -3457,15 +3527,19 @@
{ 0 }, // tile_heights
0, // use_fixed_qp_offsets
{ -1, -1, -1, -1, -1 }, // fixed_qp_offsets
- { 0, 128, 128, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ { 0, 128, 128, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
#if !CONFIG_REMOVE_DIST_WTD_COMP
1,
#endif // !CONFIG_REMOVE_DIST_WTD_COMP
1, 1, 1, 0, 0, 1, 1, 1, 1,
#if !CONFIG_REMOVE_DUAL_FILTER
1,
-#endif // !CONFIG_REMOVE_DUAL_FILTER
+#endif // !CONFIG_REMOVE_DUAL_FILTER
+#if CONFIG_FLEX_STEPS
+ 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0, 0, NULL }, // cfg
+#else
1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 0 }, // cfg
+#endif
},
};
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h
index 2f4c22e..4017e77 100644
--- a/av1/common/av1_common_int.h
+++ b/av1/common/av1_common_int.h
@@ -309,6 +309,26 @@
int8_t base_y_dc_delta_q;
int8_t base_uv_dc_delta_q;
#endif // CONFIG_EXTQUANT
+#if CONFIG_FLEX_STEPS
+ int qStep_mode;
+ // mode 0,1,2
+ int num_qStep_intervals;
+ // mode 0, 1
+ int num_qsteps_in_interval[MAX_NUM_Q_STEP_INTERVALS];
+ // mode 2
+ int num_qStep_levels;
+ int qSteps_level[MAX_NUM_Q_STEP_VAL];
+ // For mode 3
+ // template tables
+ int num_table_templates_minus1;
+ int num_entries_in_table_minus1[MAX_NUM_Q_STEP_VAL];
+ int qSteps_level_in_table[MAX_NUM_TABLES][MAX_NUM_Q_STEP_VAL];
+ // derivation
+ int template_table_idx[MAX_NUM_Q_STEP_INTERVALS];
+ int table_start_region_idx[MAX_NUM_Q_STEP_VAL];
+ int num_qsteps_in_table[MAX_NUM_Q_STEP_INTERVALS];
+#endif // CONFIG_FLEX_STEPS
+
uint8_t film_grain_params_present;
// Operating point info.
diff --git a/av1/common/quant_common.c b/av1/common/quant_common.c
index 44bb833..d11838e 100644
--- a/av1/common/quant_common.c
+++ b/av1/common/quant_common.c
@@ -122,6 +122,9 @@
57926, 59624, 61371
};
#else
+#if CONFIG_FLEX_STEPS
+static uint16_t ac_qlookup_QTX[QINDEX_RANGE_8_BITS];
+#else
// 32, q_index = 0
// Q = 40 * 2^((q_index - 1)/24) q_index in [1, 24]
// Q[(q_index - 1) % 24) + 1] * 2^((q_index-1)/24) q_index in [25, 255]
@@ -130,6 +133,7 @@
53, 55, 57, 58, 60, 62, 63, 65, 67, 69, 71,
73, 76, 78
};
+#endif
#ifndef NDEBUG
static const uint16_t ac_qlookup_QTX_full[QINDEX_RANGE_8_BITS] = {
32, 40, 41, 42, 44, 45, 46, 48, 49, 50, 52,
@@ -266,6 +270,110 @@
// addition, the minimum allowable quantizer is 4; smaller values will
// underflow to 0 in the actual quantization routines.
+#if CONFIG_FLEX_STEPS
+int getShiftVal(int val) {
+ int logVal = 0;
+ while (val > 0) {
+ val >>= 1;
+ logVal++;
+ }
+ return logVal - 1;
+}
+void set_qStep_table_mode_0_1(int qStep_mode, int num_qStep_intervals,
+ int *num_qsteps_in_interval) {
+ int mask = (1 << 16) - 1;
+ assert(qStep_mode == 0 || qStep_mode == 1);
+ assert(num_qStep_intervals >= 1);
+
+ (void)qStep_mode;
+
+ ac_qlookup_QTX[0] = 32;
+ int qIdx = 1;
+ int Initial_qIdx_factor = 32;
+
+ for (int i = 0; i <= num_qStep_intervals && (qIdx < QINDEX_RANGE_8_BITS);
+ i++) {
+ int idx = 1;
+ int log_val = getShiftVal(num_qsteps_in_interval[i]);
+ while (idx <= num_qsteps_in_interval[i]) {
+ ac_qlookup_QTX[qIdx] = CLIP(
+ ((Initial_qIdx_factor *
+ ((num_qsteps_in_interval[i] + (idx % num_qsteps_in_interval[i]))
+ << (idx >> log_val))) >>
+ log_val),
+ 0, mask);
+ qIdx++;
+ idx++;
+ }
+ Initial_qIdx_factor = ac_qlookup_QTX[qIdx - 1];
+ }
+}
+
+void set_qStep_table_mode_2(int qStep_mode, int num_qStep_levels,
+ int *qSteps_level) {
+ int mask = (1 << 16) - 1;
+ assert(qStep_mode == 2);
+ (void)qStep_mode;
+
+ int qIdx = 0;
+ num_qStep_levels = num_qStep_levels + 1;
+ int num_periods = (int)(QINDEX_RANGE_8_BITS / num_qStep_levels);
+ if ((QINDEX_RANGE_8_BITS - (num_periods * num_qStep_levels)) > 0)
+ num_periods = num_periods + 1;
+
+ for (int i = 0; i < num_periods; i++) {
+ int idx = 0;
+ while ((idx < num_qStep_levels) && (qIdx < QINDEX_RANGE_8_BITS)) {
+ ac_qlookup_QTX[qIdx] = CLIP((qSteps_level[idx] << i), 0, mask);
+ qIdx++;
+ idx++;
+ }
+ }
+}
+
+void set_qStep_table_mode_3(int qStep_mode, int num_qStep_intervals,
+ int *template_table_idx,
+ int *table_start_region_idx,
+ int *num_qsteps_in_table,
+ int *qSteps_level_in_table) {
+ int mask = (1 << 16) - 1;
+ assert(qStep_mode == 3);
+ (void)qStep_mode;
+
+ int qIdx = 0;
+ // int Initial_qIdx_factor = 0;
+
+ for (int k = 0; k <= num_qStep_intervals && (qIdx < QINDEX_RANGE_8_BITS);
+ k++) {
+ for (int idx = table_start_region_idx[k];
+ idx <= num_qsteps_in_table[k] + table_start_region_idx[k]; idx++) {
+ ac_qlookup_QTX[qIdx] =
+ CLIP(*(qSteps_level_in_table +
+ template_table_idx[k] * (MAX_NUM_Q_STEP_VAL) + idx),
+ 0, mask);
+ qIdx++;
+ }
+ // Initial_qIdx_factor = ac_qlookup_QTX[qIdx-1];
+ }
+}
+
+#if 0
+void dump_qStep_table(int mode, int expt) {
+ FILE *fp;
+ char fname[500];
+ snprintf(fname, sizeof(fname), "log_QMatrix_mode%d_expt_%d", mode, expt);
+ fp = fopen(fname, "wb");
+ for (int ii = 0; ii < 256; ii++) {
+ fprintf(fp, "%d,", ac_qlookup_QTX[ii]);
+ if (ii % 8 == 0) {
+ fprintf(fp, "\n");
+ }
+ }
+ fclose(fp);
+}
+#endif
+#endif
+
#if CONFIG_EXTQUANT
int32_t av1_dc_quant_QTX(int qindex, int delta, int base_dc_delta_q,
aom_bit_depth_t bit_depth) {
@@ -290,6 +398,12 @@
if (q_clamped > MAXQ_8_BITS) {
switch (bit_depth) {
case AOM_BITS_8: assert(q_clamped <= MAXQ_8_BITS);
+#if CONFIG_FLEX_STEPS
+ case AOM_BITS_10:
+ return 4 * (int32_t)ac_qlookup_QTX[q_clamped - qindex_offset];
+ case AOM_BITS_12:
+ return 16 * (int32_t)ac_qlookup_QTX[q_clamped - qindex_offset];
+#else
case AOM_BITS_10: {
int32_t Q;
if ((q_clamped - qindex_offset) < 25) {
@@ -312,12 +426,16 @@
}
return 16 * Q;
}
+#endif
default:
assert(0 &&
"bit_depth should be AOM_BITS_8, AOM_BITS_10 or AOM_BITS_12");
return -1;
}
} else {
+#if CONFIG_FLEX_STEPS
+ return (int32_t)ac_qlookup_QTX[q_clamped];
+#else
int32_t Q;
if (q_clamped < 25) {
Q = ac_qlookup_QTX[q_clamped];
@@ -326,6 +444,7 @@
assert(Q == ac_qlookup_QTX_full[q_clamped]);
}
return Q;
+#endif
}
}
#else
@@ -365,6 +484,12 @@
if (q_clamped > MAXQ_8_BITS) {
switch (bit_depth) {
case AOM_BITS_8: assert(q_clamped <= MAXQ_8_BITS);
+#if CONFIG_FLEX_STEPS
+ case AOM_BITS_10:
+ return 4 * (int32_t)ac_qlookup_QTX[q_clamped - qindex_offset];
+ case AOM_BITS_12:
+ return 16 * (int32_t)ac_qlookup_QTX[q_clamped - qindex_offset];
+#else
case AOM_BITS_10: {
int32_t Q;
if ((q_clamped - qindex_offset) < 25) {
@@ -387,12 +512,16 @@
}
return 16 * Q;
}
+#endif
default:
assert(0 &&
"bit_depth should be AOM_BITS_8, AOM_BITS_10 or AOM_BITS_12");
return -1;
}
} else {
+#if CONFIG_FLEX_STEPS
+ return (int32_t)ac_qlookup_QTX[q_clamped];
+#else
int32_t Q;
if (q_clamped < 25) {
Q = ac_qlookup_QTX[q_clamped];
@@ -401,6 +530,7 @@
assert(Q == ac_qlookup_QTX_full[q_clamped]);
}
return Q;
+#endif
}
}
#else
diff --git a/av1/common/quant_common.h b/av1/common/quant_common.h
index 5cde276..2651167 100644
--- a/av1/common/quant_common.h
+++ b/av1/common/quant_common.h
@@ -54,6 +54,23 @@
struct CommonQuantParams;
struct macroblockd;
+#if CONFIG_FLEX_STEPS
+#define MAX_NUM_Q_STEP_INTERVALS 16
+#define MAX_NUM_TABLES 8
+#define MAX_NUM_Q_STEP_VAL 256
+
+void set_qStep_table_mode_0_1(int qStep_mode, int num_qStep_intervals,
+ int *num_qsteps_in_interval);
+void set_qStep_table_mode_2(int qStep_mode, int num_qStep_levels,
+ int *qSteps_level);
+void set_qStep_table_mode_3(int qStep_mode, int num_qStep_intervals,
+ int *template_table_idx,
+ int *table_start_region_idx,
+ int *num_qsteps_in_table,
+ int *qSteps_level_in_table);
+// void dump_qStep_table(int mode, int expt); // kk delete
+#endif
+
#if CONFIG_EXTQUANT
int32_t av1_dc_quant_QTX(int qindex, int delta, int base_dc_delta_q,
aom_bit_depth_t bit_depth);
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 01aed0d..ef97d70 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -4274,6 +4274,55 @@
seq_params->enable_restoration = aom_rb_read_bit(rb);
}
+#if CONFIG_FLEX_STEPS
+void av1_read_qStep_config(AV1_COMMON *cm, struct aom_read_bit_buffer *rb,
+ SequenceHeader *seq_params) {
+ (void)cm;
+ seq_params->qStep_mode = aom_rb_read_literal(rb, 2);
+ if (seq_params->qStep_mode == 0 || seq_params->qStep_mode == 1) {
+ seq_params->num_qStep_intervals = aom_rb_read_literal(rb, 4);
+ seq_params->num_qsteps_in_interval[0] = aom_rb_read_uvlc(rb);
+ for (int idx = 1; idx <= seq_params->num_qStep_intervals; idx++) {
+ // int delta_qsteps_sign = aom_rb_read_bit(rb);
+ int delta_val = aom_rb_read_uvlc(rb);
+ assert(delta_val >= 0);
+ seq_params->num_qsteps_in_interval[idx] =
+ delta_val + seq_params->num_qsteps_in_interval[idx - 1];
+ }
+ } else if (seq_params->qStep_mode == 2) {
+ seq_params->num_qStep_levels = aom_rb_read_literal(rb, 8);
+ seq_params->qSteps_level[0] = aom_rb_read_uvlc(rb);
+ for (int idx = 1; idx <= seq_params->num_qStep_levels; idx++) {
+ int delta_qsteps_sign = aom_rb_read_bit(rb);
+ int delta_val = aom_rb_read_uvlc(rb);
+ seq_params->qSteps_level[idx] =
+ (delta_val * (delta_qsteps_sign ? -1 : 1)) +
+ seq_params->qSteps_level[idx - 1];
+ }
+ } else if (seq_params->qStep_mode == 3) {
+ seq_params->num_table_templates_minus1 = aom_rb_read_literal(rb, 2);
+ for (int i = 0; i <= seq_params->num_table_templates_minus1; i++) {
+ seq_params->num_entries_in_table_minus1[i] = aom_rb_read_literal(rb, 8);
+ seq_params->qSteps_level_in_table[i][0] = aom_rb_read_uvlc(rb);
+ for (int idx = 1; idx <= seq_params->num_entries_in_table_minus1[i];
+ idx++) {
+ int delta_qsteps_sign = aom_rb_read_bit(rb);
+ int delta_val = aom_rb_read_uvlc(rb);
+ seq_params->qSteps_level_in_table[i][idx] =
+ (delta_val * (delta_qsteps_sign ? -1 : 1)) +
+ seq_params->qSteps_level_in_table[i][idx - 1];
+ }
+ }
+ seq_params->num_qStep_intervals = aom_rb_read_literal(rb, 4);
+ for (int idx = 0; idx <= seq_params->num_qStep_intervals; idx++) {
+ seq_params->template_table_idx[idx] = aom_rb_read_literal(rb, 2);
+ seq_params->num_qsteps_in_table[idx] = aom_rb_read_literal(rb, 8);
+ seq_params->table_start_region_idx[idx] = aom_rb_read_literal(rb, 8);
+ }
+ }
+}
+#endif
+
static int read_global_motion_params(WarpedMotionParams *params,
const WarpedMotionParams *ref_params,
struct aom_read_bit_buffer *rb,
@@ -5175,6 +5224,26 @@
}
xd->global_motion = cm->global_motion;
+#if CONFIG_FLEX_STEPS
+ SequenceHeader *const seq_params = &cm->seq_params;
+ if ((seq_params->qStep_mode == 0) || (seq_params->qStep_mode == 1)) {
+ set_qStep_table_mode_0_1(seq_params->qStep_mode,
+ seq_params->num_qStep_intervals,
+ &seq_params->num_qsteps_in_interval[0]);
+ } else if (seq_params->qStep_mode == 2) {
+ set_qStep_table_mode_2(seq_params->qStep_mode, seq_params->num_qStep_levels,
+ &seq_params->qSteps_level[0]);
+ } else if (seq_params->qStep_mode == 3) {
+ set_qStep_table_mode_3(seq_params->qStep_mode,
+ seq_params->num_qStep_intervals,
+ &seq_params->template_table_idx[0],
+ &seq_params->table_start_region_idx[0],
+ &seq_params->num_qsteps_in_table[0],
+ (int *)seq_params->qSteps_level_in_table);
+ }
+ // dump_qStep_table(seq_params->qStep_mode, 1);
+#endif
+
read_uncompressed_header(pbi, rb);
if (trailing_bits_present) av1_check_trailing_bits(pbi, rb);
diff --git a/av1/decoder/decodeframe.h b/av1/decoder/decodeframe.h
index 95b3c9f..d7898dc 100644
--- a/av1/decoder/decodeframe.h
+++ b/av1/decoder/decodeframe.h
@@ -26,6 +26,13 @@
void av1_read_sequence_header(AV1_COMMON *cm, struct aom_read_bit_buffer *rb,
SequenceHeader *seq_params);
+#if CONFIG_FLEX_STEPS
+// Implements the qStep_config() function in the spec. Reports errors by
+// calling rb->error_handler() or aom_internal_error().
+void av1_read_qStep_config(AV1_COMMON *cm, struct aom_read_bit_buffer *rb,
+ SequenceHeader *seq_params);
+#endif
+
void av1_read_frame_size(struct aom_read_bit_buffer *rb, int num_bits_width,
int num_bits_height, int *width, int *height);
BITSTREAM_PROFILE av1_read_profile(struct aom_read_bit_buffer *rb);
diff --git a/av1/decoder/obu.c b/av1/decoder/obu.c
index 0c9cce4..0e0889a 100644
--- a/av1/decoder/obu.c
+++ b/av1/decoder/obu.c
@@ -240,6 +240,10 @@
av1_read_sequence_header(cm, rb, seq_params);
+#if CONFIG_FLEX_STEPS
+ av1_read_qStep_config(cm, rb, seq_params);
+#endif
+
av1_read_color_config(rb, pbi->allow_lowbitdepth, seq_params, &cm->error);
if (!(seq_params->subsampling_x == 0 && seq_params->subsampling_y == 0) &&
!(seq_params->subsampling_x == 1 && seq_params->subsampling_y == 1) &&
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index c5e50e2..d3a301d 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2705,6 +2705,56 @@
aom_wb_write_bit(wb, seq_params->enable_restoration);
}
+#if CONFIG_FLEX_STEPS
+static AOM_INLINE void write_qStepinfo(const SequenceHeader *const seq_params,
+ struct aom_write_bit_buffer *wb) {
+ aom_wb_write_literal(wb, seq_params->qStep_mode, 2);
+ if (seq_params->qStep_mode == 0 || seq_params->qStep_mode == 1) {
+ aom_wb_write_literal(wb, seq_params->num_qStep_intervals, 4);
+ aom_wb_write_uvlc(wb, seq_params->num_qsteps_in_interval[0]);
+ for (int idx = 1; idx <= seq_params->num_qStep_intervals; idx++) {
+ int delta_qsteps = seq_params->num_qsteps_in_interval[idx] -
+ seq_params->num_qsteps_in_interval[idx - 1];
+ assert(delta_qsteps >= 0);
+ // int delta_qsteps_sign = (delta_qsteps < 0) ? 1 : 0;
+ // aom_wb_write_bit(wb, delta_qsteps_sign);
+ aom_wb_write_uvlc(wb, abs(delta_qsteps));
+ }
+ } else if (seq_params->qStep_mode == 2) {
+ aom_wb_write_literal(wb, seq_params->num_qStep_levels, 8);
+ aom_wb_write_uvlc(wb, seq_params->qSteps_level[0]);
+ for (int idx = 1; idx <= seq_params->num_qStep_levels; idx++) {
+ int delta_qsteps =
+ seq_params->qSteps_level[idx] - seq_params->qSteps_level[idx - 1];
+ int delta_qsteps_sign = (delta_qsteps < 0) ? 1 : 0;
+ aom_wb_write_bit(wb, delta_qsteps_sign);
+ aom_wb_write_uvlc(wb, abs(delta_qsteps));
+ }
+ } else if (seq_params->qStep_mode == 3) {
+ aom_wb_write_literal(wb, seq_params->num_table_templates_minus1, 2);
+ for (int i = 0; i <= seq_params->num_table_templates_minus1; i++) {
+ aom_wb_write_literal(wb, seq_params->num_entries_in_table_minus1[i], 8);
+ aom_wb_write_uvlc(wb, seq_params->qSteps_level_in_table[i][0]);
+ for (int idx = 1; idx <= seq_params->num_entries_in_table_minus1[i];
+ idx++) {
+ int delta_qsteps = seq_params->qSteps_level_in_table[i][idx] -
+ seq_params->qSteps_level_in_table[i][idx - 1];
+ int delta_qsteps_sign = (delta_qsteps < 0) ? 1 : 0;
+ aom_wb_write_bit(wb, delta_qsteps_sign);
+ aom_wb_write_uvlc(wb, abs(delta_qsteps));
+ }
+ }
+ aom_wb_write_literal(wb, seq_params->num_qStep_intervals, 4);
+ for (int idx = 0; idx <= seq_params->num_qStep_intervals; idx++) {
+ aom_wb_write_literal(wb, seq_params->template_table_idx[idx], 2);
+ aom_wb_write_literal(wb, seq_params->num_qsteps_in_table[idx], 8);
+ aom_wb_write_literal(wb, seq_params->table_start_region_idx[idx], 8);
+ }
+ }
+}
+
+#endif
+
static AOM_INLINE void write_global_motion_params(
const WarpedMotionParams *params, const WarpedMotionParams *ref_params,
struct aom_write_bit_buffer *wb, int allow_hp) {
@@ -3439,6 +3489,9 @@
}
write_sequence_header(seq_params, &wb);
+#if CONFIG_FLEX_STEPS
+ write_qStepinfo(seq_params, &wb);
+#endif
write_color_config(seq_params, &wb);
aom_wb_write_bit(&wb, seq_params->film_grain_params_present);
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index d5b5552..3cb0af5 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -569,6 +569,10 @@
av1_update_film_grain_parameters(cpi, oxcf);
+#if CONFIG_FLEX_STEPS
+ update_qstep_parameters(cpi, oxcf);
+#endif
+
// Single thread case: use counts in common.
cpi->td.counts = &cpi->counts;
@@ -604,6 +608,31 @@
return strcmp(a, b);
}
+#if CONFIG_FLEX_STEPS
+void set_enc_qstep_table(const AV1EncoderConfig *oxcf) {
+ QuantizationCfg *q_cfg = (QuantizationCfg *)&oxcf->q_cfg;
+
+ if ((q_cfg->qStep_mode == 0) || (q_cfg->qStep_mode == 1)) {
+ set_qStep_table_mode_0_1(q_cfg->qStep_mode, q_cfg->num_qStep_intervals,
+ &q_cfg->num_qsteps_in_interval[0]);
+ } else if (q_cfg->qStep_mode == 2) {
+ set_qStep_table_mode_2(q_cfg->qStep_mode, q_cfg->num_qStep_levels,
+ &q_cfg->qSteps_level[0]);
+ } else if (q_cfg->qStep_mode == 3) {
+ set_qStep_table_mode_3(
+ q_cfg->qStep_mode, q_cfg->num_qStep_intervals,
+ &q_cfg->template_table_idx[0], &q_cfg->table_start_region_idx[0],
+ &q_cfg->num_qsteps_in_table[0], (int *)q_cfg->qSteps_level_in_table);
+ }
+}
+
+void initialize_qstep_param(const char *qStep_fname, AV1EncoderConfig *oxcf) {
+ // Wrapper added to extend the custom initializations
+ // not in the qstep config file.
+ process_qStep_config_from_file(qStep_fname, oxcf);
+}
+#endif
+
void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) {
AV1_COMMON *const cm = &cpi->common;
SequenceHeader *const seq_params = &cm->seq_params;
@@ -666,6 +695,32 @@
10; // Default value (not signaled)
}
+#if CONFIG_FLEX_STEPS
+ bool qstep_config_changed = false;
+ if (aom_strcmp(cpi->qstep_config_path, oxcf->qstep_config_path)) {
+ assert(1); // kk hack
+ aom_free(cpi->qstep_config_path);
+ cpi->qstep_config_path = NULL;
+ if (oxcf->qstep_config_path != NULL) {
+ cpi->qstep_config_path =
+ (char *)aom_malloc((strlen(oxcf->qstep_config_path) + 1) *
+ sizeof(*oxcf->qstep_config_path));
+ // strcpy(cpi->qstep_config_path, oxcf->qstep_config_path);
+ snprintf(cpi->qstep_config_path,
+ (strlen(oxcf->qstep_config_path) + 1) *
+ sizeof(*oxcf->qstep_config_path),
+ "%s", oxcf->qstep_config_path);
+ }
+ qstep_config_changed = true;
+ }
+ if (qstep_config_changed) {
+ initialize_qstep_param(oxcf->qstep_config_path, (AV1EncoderConfig *)oxcf);
+ set_enc_qstep_table(oxcf);
+ }
+ update_qstep_parameters(cpi, oxcf);
+
+#endif
+
av1_update_film_grain_parameters(cpi, oxcf);
cpi->oxcf = *oxcf;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 5b726bb..abc7a87 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -48,6 +48,10 @@
#include "av1/encoder/tpl_model.h"
#include "av1/encoder/av1_noise_estimate.h"
+#if CONFIG_FLEX_STEPS
+#include "av1/common/quant_common.h"
+#endif
+
#if CONFIG_INTERNAL_STATS
#include "aom_dsp/ssim.h"
#endif
@@ -691,6 +695,25 @@
bool enable_chroma_deltaq;
// Indicates if encoding with quantization matrices should be enabled.
bool using_qm;
+#if CONFIG_FLEX_STEPS
+ int qStep_mode;
+ // mode 0 and mode 1
+ int num_qStep_intervals;
+ int num_qsteps_in_interval[MAX_NUM_Q_STEP_INTERVALS];
+ // mode 2
+ int num_qStep_levels;
+ int qSteps_level[MAX_NUM_Q_STEP_VAL];
+ // For mode 3
+ // template tables
+ int num_table_templates_minus1;
+ int num_entries_in_table_minus1[MAX_NUM_Q_STEP_VAL];
+ int qSteps_level_in_table[MAX_NUM_TABLES][MAX_NUM_Q_STEP_VAL];
+ // derivation
+ int template_table_idx[MAX_NUM_Q_STEP_INTERVALS];
+ int table_start_region_idx[MAX_NUM_Q_STEP_VAL];
+ int num_qsteps_in_table[MAX_NUM_Q_STEP_INTERVALS];
+
+#endif // CONFIG_FLEX_STEPS
} QuantizationCfg;
/*!\endcond */
@@ -933,6 +956,11 @@
// SubGOP config.
const char *subgop_config_path;
+#if CONFIG_FLEX_STEPS
+ // qStep config.
+ const char *qstep_config_path;
+#endif
+
// Configuration related to encoder toolsets.
ToolCfg tool_cfg;
@@ -2331,6 +2359,13 @@
*/
char *subgop_config_path;
+#if CONFIG_FLEX_STEPS
+ /*!
+ * qStep configuration file path
+ */
+ char *qstep_config_path;
+#endif
+
/*!
* Information related to subGOP configuration if specified.
*/
@@ -2749,6 +2784,11 @@
void av1_init_seq_coding_tools(SequenceHeader *seq, AV1_COMMON *cm,
const AV1EncoderConfig *oxcf, int use_svc);
+#if CONFIG_FLEX_STEPS
+void set_enc_qstep_table(const AV1EncoderConfig *oxcf);
+void initialize_qstep_param(const char *qStep_fname, AV1EncoderConfig *oxcf);
+#endif
+
/*!\endcond */
/*!\brief Obtain the raw frame data
diff --git a/av1/encoder/encoder_utils.c b/av1/encoder/encoder_utils.c
index f4e4630..3615eed 100644
--- a/av1/encoder/encoder_utils.c
+++ b/av1/encoder/encoder_utils.c
@@ -29,6 +29,12 @@
#include "av1/encoder/tune_vmaf.h"
#endif
+#if CONFIG_FLEX_STEPS
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#endif
+
#define MIN_BOOST_COMBINE_FACTOR 4.0
#define MAX_BOOST_COMBINE_FACTOR 12.0
@@ -452,6 +458,264 @@
memset(pars->ar_coeffs_cb, 0, sizeof(pars->ar_coeffs_cb));
}
+#if CONFIG_FLEX_STEPS
+/* Note the read_token_after and readline helper functions are same
+ to what is defined in subgop.c as static functins. This needs to be unified
+ <TBD> */
+static char *qStep_strtok_r(char *str, const char *delim, char **saveptr) {
+ if (str == NULL) return NULL;
+ if (strlen(str) == 0) return NULL;
+ char *ptr = str;
+ char *x = strstr(str, delim);
+ if (x) {
+ *x = 0;
+ if (saveptr) *saveptr = x + strlen(delim);
+ } else {
+ if (saveptr) *saveptr = NULL;
+ return ptr;
+ }
+ return ptr;
+}
+
+static char *qStep_read_token_after(char *str, const char *delim,
+ char **saveptr) {
+ if (str == NULL) return NULL;
+ if (strlen(str) == 0) return NULL;
+ char *ptr = str;
+ char *x = strstr(str, delim);
+ if (x) {
+ ptr = x + strlen(delim);
+ while (*x != 0 && !isspace(*x)) x++;
+ *x = 0;
+ if (saveptr) *saveptr = x + 1;
+ return ptr;
+ } else {
+ if (saveptr) *saveptr = str;
+ return NULL;
+ }
+}
+
+static bool qStep_readline(char *buf, int size, FILE *fp) {
+ buf[0] = '\0';
+ buf[size - 1] = '\0';
+ char *tmp;
+ while (1) {
+ if (fgets(buf, size, fp) == NULL) {
+ *buf = '\0';
+ return false;
+ } else {
+ if ((tmp = strrchr(buf, '\n')) != NULL) *tmp = '\0';
+ if ((tmp = strchr(buf, '#')) != NULL) *tmp = '\0';
+ for (int i = 0; i < (int)strlen(buf); ++i) {
+ if (!isspace(buf[i])) return true;
+ }
+ }
+ }
+ return true;
+}
+
+int process_qStep_config_from_file(const char *paramfile,
+ AV1EncoderConfig *oxcf) {
+ int qStepMode;
+ char *token;
+ char *str;
+ char line[8192];
+ int linesize = 8192;
+
+ if (!paramfile) {
+ return 1;
+ }
+
+ if (!strlen(paramfile)) {
+ return 1;
+ }
+
+ FILE *fp = fopen(paramfile, "r");
+ if (!fp) {
+ return 0;
+ }
+
+ oxcf->q_cfg.qStep_mode = 0;
+ while (qStep_readline(line, linesize, fp)) {
+ if (qStep_read_token_after(line, "qStepMode:", NULL)) {
+ str = line;
+ qStepMode = atoi(qStep_read_token_after(str, "qStepMode:", &str));
+ assert(qStepMode == 0 || qStepMode == 1 || qStepMode == 2 ||
+ qStepMode == 3);
+ oxcf->q_cfg.qStep_mode = qStepMode;
+ }
+
+ if (oxcf->q_cfg.qStep_mode == 1) {
+ int num_transition_interval_minus1 = 0;
+ if (qStep_read_token_after(line,
+ "num_transition_interval_minus1:", NULL)) {
+ str = line;
+ num_transition_interval_minus1 = atoi(qStep_read_token_after(
+ str, "num_transition_interval_minus1:", &str));
+ assert(num_transition_interval_minus1 >= 1);
+ oxcf->q_cfg.num_qStep_intervals = num_transition_interval_minus1;
+ }
+ if (qStep_read_token_after(line, "num_Qsteps_in_interval:", NULL)) {
+ int idx = 0;
+ str = line;
+ token = qStep_read_token_after(str, "num_Qsteps_in_interval:", &str);
+ char *token1 =
+ qStep_strtok_r(token, ",", &str); // strtok(token, ","); //
+ while (token1) {
+ oxcf->q_cfg.num_qsteps_in_interval[idx++] = atoi(token1);
+ token1 = qStep_strtok_r(str, ",", &str); // strtok(NULL,",");
+ }
+ assert((idx - 1) >= oxcf->q_cfg.num_qStep_intervals);
+ }
+ } else if (oxcf->q_cfg.qStep_mode == 2) {
+ int num_qStep_levels_minus1 = 0;
+ if (qStep_read_token_after(line, "num_q_step_periods_minus1:", NULL)) {
+ str = line;
+ num_qStep_levels_minus1 = atoi(
+ qStep_read_token_after(str, "num_q_step_periods_minus1:", &str));
+ assert(num_qStep_levels_minus1 >= 1);
+ oxcf->q_cfg.num_qStep_levels = num_qStep_levels_minus1;
+ }
+ if (qStep_read_token_after(line, "num_Qsteps_in_period:", NULL)) {
+ int idx = 0;
+ str = line;
+ token = qStep_read_token_after(str, "num_Qsteps_in_period:", &str);
+ char *token1 = qStep_strtok_r(token, ",", &str); // strtok(token, ",");
+ while (token1) {
+ oxcf->q_cfg.qSteps_level[idx++] = atoi(token1);
+ token1 = qStep_strtok_r(str, ",", &str); // strtok(NULL,",");
+ }
+ assert((idx - 1) >= oxcf->q_cfg.num_qStep_intervals);
+ }
+ } else if (oxcf->q_cfg.qStep_mode == 3) {
+ int num_table_templates_minus1 = 0;
+ if (qStep_read_token_after(line, "num_table_templates_minus1:", NULL)) {
+ str = line;
+ num_table_templates_minus1 = atoi(
+ qStep_read_token_after(str, "num_table_templates_minus1:", &str));
+ assert(num_table_templates_minus1 >= 1);
+ oxcf->q_cfg.num_table_templates_minus1 = num_table_templates_minus1;
+ }
+ if (qStep_read_token_after(line, "num_entries_in_table_minus1:", NULL)) {
+ int idx = 0;
+ str = line;
+ token =
+ qStep_read_token_after(str, "num_entries_in_table_minus1:", &str);
+ char *token1 = qStep_strtok_r(token, ",", &str); // strtok(token, ",");
+ while (token1) {
+ oxcf->q_cfg.num_entries_in_table_minus1[idx++] = atoi(token1);
+ token1 = qStep_strtok_r(str, ",", &str); // strtok(NULL,",");
+ }
+ assert((idx - 1) >= oxcf->q_cfg.num_table_templates_minus1);
+ }
+ for (int kk = 0; kk <= oxcf->q_cfg.num_table_templates_minus1; kk++) {
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "qsteps_level_period_%d:", kk);
+ if (qStep_read_token_after(line, buffer, NULL)) {
+ int idx = 0;
+ str = line;
+ token = qStep_read_token_after(str, buffer, &str);
+ char *token1 =
+ qStep_strtok_r(token, ",", &str); // strtok(token, ",");
+ while (token1) {
+ oxcf->q_cfg.qSteps_level_in_table[kk][idx++] = atoi(token1);
+ token1 = qStep_strtok_r(str, ",", &str); // strtok(NULL,",");
+ }
+ assert((idx - 1) >= oxcf->q_cfg.num_entries_in_table_minus1[kk]);
+ }
+ }
+
+ int num_transition_interval_minus1 = 0;
+ if (qStep_read_token_after(line,
+ "num_transition_interval_minus1:", NULL)) {
+ str = line;
+ num_transition_interval_minus1 = atoi(qStep_read_token_after(
+ str, "num_transition_interval_minus1:", &str));
+ assert(num_transition_interval_minus1 >= 1);
+ oxcf->q_cfg.num_qStep_intervals = num_transition_interval_minus1;
+ }
+ if (qStep_read_token_after(line, "template_table_idx:", NULL)) {
+ int idx = 0;
+ str = line;
+ token = qStep_read_token_after(str, "template_table_idx:", &str);
+ char *token1 = qStep_strtok_r(token, ",", &str); // strtok(token, ",");
+ while (token1) {
+ oxcf->q_cfg.template_table_idx[idx++] = atoi(token1);
+ token1 = qStep_strtok_r(str, ",", &str); // strtok(NULL,",");
+ }
+ assert((idx - 1) >= oxcf->q_cfg.num_qStep_intervals);
+ }
+
+ if (qStep_read_token_after(line, "num_qsteps_in_interval:", NULL)) {
+ int idx = 0;
+ str = line;
+ token = qStep_read_token_after(str, "num_qsteps_in_interval:", &str);
+ char *token1 = qStep_strtok_r(token, ",", &str); // strtok(token, ",");
+ while (token1) {
+ oxcf->q_cfg.num_qsteps_in_table[idx++] = atoi(token1);
+ token1 = qStep_strtok_r(str, ",", &str); // strtok(NULL,",");
+ }
+ assert((idx - 1) >= oxcf->q_cfg.num_qStep_intervals);
+ }
+ if (qStep_read_token_after(line, "table_start_region_idx:", NULL)) {
+ int idx = 0;
+ str = line;
+ token = qStep_read_token_after(str, "table_start_region_idx:", &str);
+ char *token1 = qStep_strtok_r(token, ",", &str); // strtok(token, ",");
+ while (token1) {
+ oxcf->q_cfg.table_start_region_idx[idx++] = atoi(token1);
+ token1 = qStep_strtok_r(str, ",", &str); // strtok(NULL,",");
+ }
+ assert((idx - 1) >= oxcf->q_cfg.num_qStep_intervals);
+ }
+ }
+ }
+ fclose(fp);
+ return 1;
+}
+
+void update_qstep_parameters(struct AV1_COMP *cpi,
+ const AV1EncoderConfig *oxcf) {
+ AV1_COMMON *const cm = &cpi->common;
+ SequenceHeader *seq_params = &cm->seq_params;
+ cpi->oxcf = *oxcf;
+
+ seq_params->qStep_mode = oxcf->q_cfg.qStep_mode;
+
+ if ((seq_params->qStep_mode == 0) || (seq_params->qStep_mode == 1)) {
+ seq_params->num_qStep_intervals = oxcf->q_cfg.num_qStep_intervals;
+ for (int idx = 0; idx <= seq_params->num_qStep_intervals; idx++) {
+ seq_params->num_qsteps_in_interval[idx] =
+ oxcf->q_cfg.num_qsteps_in_interval[idx];
+ }
+ } else if (seq_params->qStep_mode == 2) {
+ seq_params->num_qStep_levels = oxcf->q_cfg.num_qStep_levels;
+ for (int idx = 0; idx <= seq_params->num_qStep_levels; idx++) {
+ seq_params->qSteps_level[idx] = oxcf->q_cfg.qSteps_level[idx];
+ }
+ } else if (seq_params->qStep_mode == 3) {
+ seq_params->num_table_templates_minus1 =
+ oxcf->q_cfg.num_table_templates_minus1;
+ for (int idx = 0; idx <= seq_params->num_table_templates_minus1; idx++) {
+ seq_params->num_entries_in_table_minus1[idx] =
+ oxcf->q_cfg.num_entries_in_table_minus1[idx];
+ for (int i = 0; i <= seq_params->num_entries_in_table_minus1[idx]; i++) {
+ seq_params->qSteps_level_in_table[idx][i] =
+ oxcf->q_cfg.qSteps_level_in_table[idx][i];
+ }
+ }
+ seq_params->num_qStep_intervals = oxcf->q_cfg.num_qStep_intervals;
+ for (int idx = 0; idx <= seq_params->num_qStep_intervals; idx++) {
+ seq_params->template_table_idx[idx] = oxcf->q_cfg.template_table_idx[idx];
+ seq_params->table_start_region_idx[idx] =
+ oxcf->q_cfg.table_start_region_idx[idx];
+ seq_params->num_qsteps_in_table[idx] =
+ oxcf->q_cfg.num_qsteps_in_table[idx];
+ }
+ }
+}
+#endif
+
void av1_update_film_grain_parameters(struct AV1_COMP *cpi,
const AV1EncoderConfig *oxcf) {
AV1_COMMON *const cm = &cpi->common;
diff --git a/av1/encoder/encoder_utils.h b/av1/encoder/encoder_utils.h
index 138606d..099bcc2 100644
--- a/av1/encoder/encoder_utils.h
+++ b/av1/encoder/encoder_utils.h
@@ -951,6 +951,13 @@
void av1_update_film_grain_parameters(struct AV1_COMP *cpi,
const AV1EncoderConfig *oxcf);
+#if CONFIG_FLEX_STEPS
+int process_qStep_config_from_file(const char *paramfile,
+ AV1EncoderConfig *oxcf);
+void update_qstep_parameters(struct AV1_COMP *cpi,
+ const AV1EncoderConfig *oxcf);
+#endif
+
void av1_scale_references(AV1_COMP *cpi, const InterpFilter filter,
const int phase, const int use_optimized_scaler);
diff --git a/build/cmake/aom_config_defaults.cmake b/build/cmake/aom_config_defaults.cmake
index 6f33143..678141b 100644
--- a/build/cmake/aom_config_defaults.cmake
+++ b/build/cmake/aom_config_defaults.cmake
@@ -139,7 +139,9 @@
"AV2 experiment flag to remove dual filter.")
set_aom_config_var(CONFIG_EXTQUANT 0
"AV2 extended quantization experiment flag")
-
+set_aom_config_var(CONFIG_FLEX_STEPS 0
+ "AV2 flexible quantization experiment flag (enable with
+ CONFIG_EXTQUANT")
#
# Variables in this section control optional features of the build system.
#
diff --git a/build/cmake/aom_experiment_deps.cmake b/build/cmake/aom_experiment_deps.cmake
index 2e36157..00ea141 100644
--- a/build/cmake/aom_experiment_deps.cmake
+++ b/build/cmake/aom_experiment_deps.cmake
@@ -25,4 +25,8 @@
change_config_and_warn(CONFIG_DIST_8X8 0 CONFIG_MULTITHREAD)
endif()
+ if(CONFIG_FLEX_STEPS)
+ change_config_and_warn(CONFIG_EXTQUANT 1 CONFIG_FLEX_STEPS)
+ endif()
+
endmacro()
diff --git a/examples/qstepcfg/qstepcfg_mode1.cfg b/examples/qstepcfg/qstepcfg_mode1.cfg
new file mode 100644
index 0000000..5075012
--- /dev/null
+++ b/examples/qstepcfg/qstepcfg_mode1.cfg
@@ -0,0 +1,27 @@
+#default is qStepMode = 0
+
+
+#qStepMode 1 example
+qStepMode:1
+num_transition_interval_minus1:9
+num_Qsteps_in_interval:8,8,16,32,32,32,32,32,32,32
+
+
+#qStepMode 2 example
+#qStepMode:2
+#num_q_step_periods_minus1:31
+#num_Qsteps_in_period:32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
+
+
+#qStepMode 3 example
+#qStepMode:3
+#num_table_templates_minus1:3
+#num_entries_in_table_minus1:63,63,63,63
+#qsteps_level_period_0:4,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70
+#qsteps_level_period_1:71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,155,158,161,164,167,170,173
+#qsteps_level_period_2:176,179,182,185,188,191,194,197,200,203,207,211,215,219,223,227,231,235,239,243,247,251,255,260,265,270,275,280,285,290,295,300,305,311,317,323,329,335,341,347,353,359,366,373,380,387,394,401,408,416,424,432,440,448,456,465,474,483,492,501,510,520,530,540
+#qsteps_level_period_3:550,560,571,582,593,604,615,627,639,651,663,676,689,702,715,729,743,757,771,786,801,816,832,848,864,881,898,915,933,951,969,988,1007,1026,1046,1066,1087,1108,1129,1151,1173,1196,1219,1243,1267,1292,1317,1343,1369,1396,1423,1451,1479,1508,1537,1567,1597,1628,1660,1692,1725,1759,1793,1828
+#num_transition_interval_minus1:3
+#template_table_idx:0,1,2,3
+#num_qsteps_in_interval:63,63,63,63
+#table_start_region_idx:0,0,0,0
\ No newline at end of file
diff --git a/examples/qstepcfg/qstepcfg_mode2.cfg b/examples/qstepcfg/qstepcfg_mode2.cfg
new file mode 100644
index 0000000..811d3a4
--- /dev/null
+++ b/examples/qstepcfg/qstepcfg_mode2.cfg
@@ -0,0 +1,27 @@
+#default is qStepMode = 0
+
+
+#qStepMode 1 example
+#qStepMode:1
+#num_transition_interval_minus1:9
+#num_Qsteps_in_interval:8,8,16,32,32,32,32,32,32,32
+
+
+#qStepMode 2 example
+qStepMode:2
+num_q_step_periods_minus1:31
+num_Qsteps_in_period:32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
+
+
+#qStepMode 3 example
+#qStepMode:3
+#num_table_templates_minus1:3
+#num_entries_in_table_minus1:63,63,63,63
+#qsteps_level_period_0:4,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70
+#qsteps_level_period_1:71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,155,158,161,164,167,170,173
+#qsteps_level_period_2:176,179,182,185,188,191,194,197,200,203,207,211,215,219,223,227,231,235,239,243,247,251,255,260,265,270,275,280,285,290,295,300,305,311,317,323,329,335,341,347,353,359,366,373,380,387,394,401,408,416,424,432,440,448,456,465,474,483,492,501,510,520,530,540
+#qsteps_level_period_3:550,560,571,582,593,604,615,627,639,651,663,676,689,702,715,729,743,757,771,786,801,816,832,848,864,881,898,915,933,951,969,988,1007,1026,1046,1066,1087,1108,1129,1151,1173,1196,1219,1243,1267,1292,1317,1343,1369,1396,1423,1451,1479,1508,1537,1567,1597,1628,1660,1692,1725,1759,1793,1828
+#num_transition_interval_minus1:3
+#template_table_idx:0,1,2,3
+#num_qsteps_in_interval:63,63,63,63
+#table_start_region_idx:0,0,0,0
\ No newline at end of file
diff --git a/examples/qstepcfg/qstepcfg_mode3.cfg b/examples/qstepcfg/qstepcfg_mode3.cfg
new file mode 100644
index 0000000..dde3b05
--- /dev/null
+++ b/examples/qstepcfg/qstepcfg_mode3.cfg
@@ -0,0 +1,27 @@
+#default is qStepMode = 0
+
+
+#qStepMode 1 example
+#qStepMode:1
+#num_transition_interval_minus1:9
+#num_Qsteps_in_interval:8,8,16,32,32,32,32,32,32,32
+
+
+#qStepMode 2 example
+#qStepMode:2
+#num_q_step_periods_minus1:31
+#num_Qsteps_in_period:32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
+
+
+#qStepMode 3 example
+qStepMode:3
+num_table_templates_minus1:3
+num_entries_in_table_minus1:63,63,63,63
+qsteps_level_period_0:4,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70
+qsteps_level_period_1:71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,140,142,144,146,148,150,152,155,158,161,164,167,170,173
+qsteps_level_period_2:176,179,182,185,188,191,194,197,200,203,207,211,215,219,223,227,231,235,239,243,247,251,255,260,265,270,275,280,285,290,295,300,305,311,317,323,329,335,341,347,353,359,366,373,380,387,394,401,408,416,424,432,440,448,456,465,474,483,492,501,510,520,530,540
+qsteps_level_period_3:550,560,571,582,593,604,615,627,639,651,663,676,689,702,715,729,743,757,771,786,801,816,832,848,864,881,898,915,933,951,969,988,1007,1026,1046,1066,1087,1108,1129,1151,1173,1196,1219,1243,1267,1292,1317,1343,1369,1396,1423,1451,1479,1508,1537,1567,1597,1628,1660,1692,1725,1759,1793,1828
+num_transition_interval_minus1:3
+template_table_idx:0,1,2,3
+num_qsteps_in_interval:63,63,63,63
+table_start_region_idx:0,0,0,0
\ No newline at end of file