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