target level API: specify per operating point Modify the API to allow specifying target level for each operating point. BUG=aomedia:2332 Change-Id: I890103a7cbf06c2584585e7f6cbae37917eb91ab
diff --git a/aom/aomcx.h b/aom/aomcx.h index 97b329f..fb79583 100644 --- a/aom/aomcx.h +++ b/aom/aomcx.h
@@ -512,11 +512,19 @@ */ AV1E_SET_RENDER_SIZE, - /*!\brief Control to set target sequence level index - * Possible values are: - * -1: Not enabled (default) - * 0~23: Target for the given sequence level index - * 31: Passively measure the level of the encoded bitstream + /*!\brief Control to set target sequence level index for a certain operating + * point(OP). + * Possible values are in the form of "ABxy"(pad leading zeros if less than + * 4 digits). + * AB: OP index. + * xy: Target level index for the OP. Can be values 0~23(corresponding to + * level 2.0 ~ 7.3) or 31(maximum level parameter, no level-based + * constraints). + * E.g. "0" means target level index 0 for the 0th OP; + * "111" means target level index 11 for the 1st OP; + * "1021" means target level index 21 for the 10th OP. + * If the target level is not specified for an OP, the maximum level parameter + * of 31 is used as default. */ AV1E_SET_TARGET_SEQ_LEVEL_IDX,
diff --git a/apps/aomenc.c b/apps/aomenc.c index b16baa1..00b398f 100644 --- a/apps/aomenc.c +++ b/apps/aomenc.c
@@ -628,9 +628,12 @@ static const arg_def_t target_seq_level_idx = ARG_DEF(NULL, "target-seq-level-idx", 1, "Target sequence level index. " - "(0~23: Target for the given level index; " - "31(default): Maximum level parameter, no level-based " - "constraints.)"); + "Possible values are in the form of \"ABxy\"(pad leading zeros if " + "less than 4 digits). " + "AB: Operating point(OP) index; " + "xy: Target level index for the OP. " + "E.g. \"0\" means target level index 0 for the 0th OP; " + "\"1021\" means target level index 21 for the 10th OP."); static const struct arg_enum_list color_primaries_enum[] = { { "bt709", AOM_CICP_CP_BT_709 }, @@ -1280,6 +1283,17 @@ return; } + // For target level, the settings should accumulate rather than overwrite, + // so we simply append it. + if (key == AV1E_SET_TARGET_SEQ_LEVEL_IDX) { + j = config->arg_ctrl_cnt; + assert(j < (int)ARG_CTRL_CNT_MAX); + config->arg_ctrls[j][0] = key; + config->arg_ctrls[j][1] = arg_parse_enum_or_int(arg); + ++config->arg_ctrl_cnt; + return; + } + /* Point either to the next free element or the first instance of this * control. */
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c index b71a15f..a453588 100644 --- a/av1/av1_cx_iface.c +++ b/av1/av1_cx_iface.c
@@ -129,7 +129,7 @@ int use_inter_dct_only; int use_intra_default_tx_only; int quant_b_adapt; - AV1_LEVEL target_seq_level_idx; + AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS]; // Bit mask to specify which tier each of the 32 possible operating points // conforms to. unsigned int tier_mask; @@ -227,14 +227,17 @@ 0, // noise_level 32, // noise_block_size #endif - 0, // chroma_subsampling_x - 0, // chroma_subsampling_y - 0, // reduced_tx_type_set - 0, // use_intra_dct_only - 0, // use_inter_dct_only - 0, // use_intra_default_tx_only - 0, // quant_b_adapt - 31, // target_seq_level_idx + 0, // chroma_subsampling_x + 0, // chroma_subsampling_y + 0, // reduced_tx_type_set + 0, // use_intra_dct_only + 0, // use_inter_dct_only + 0, // use_intra_default_tx_only + 0, // quant_b_adapt + { + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + }, // target_seq_level_idx 0, // tier_mask COST_UPD_SB, // coeff_cost_upd_freq COST_UPD_SB, // mode_cost_upd_freq @@ -451,8 +454,10 @@ RANGE_CHECK(extra_cfg, coeff_cost_upd_freq, 0, 2); RANGE_CHECK(extra_cfg, mode_cost_upd_freq, 0, 2); - if (!is_valid_seq_level_idx(extra_cfg->target_seq_level_idx)) - ERROR("Target sequence level index is invalid"); + for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { + if (!is_valid_seq_level_idx(extra_cfg->target_seq_level_idx[i])) + ERROR("Target sequence level index is invalid"); + } return AOM_CODEC_OK; } @@ -814,7 +819,8 @@ oxcf->border_in_pixels = (oxcf->resize_mode || oxcf->superres_mode) ? AOM_BORDER_IN_PIXELS : AOM_ENC_NO_SCALE_BORDER; - oxcf->target_seq_level_idx = extra_cfg->target_seq_level_idx; + memcpy(oxcf->target_seq_level_idx, extra_cfg->target_seq_level_idx, + sizeof(oxcf->target_seq_level_idx)); oxcf->tier_mask = extra_cfg->tier_mask; return AOM_CODEC_OK; } @@ -1463,7 +1469,13 @@ static aom_codec_err_t ctrl_set_target_seq_level_idx(aom_codec_alg_priv_t *ctx, va_list args) { struct av1_extracfg extra_cfg = ctx->extra_cfg; - extra_cfg.target_seq_level_idx = CAST(AV1E_SET_TARGET_SEQ_LEVEL_IDX, args); + const int val = CAST(AV1E_SET_TARGET_SEQ_LEVEL_IDX, args); + const int level = val % 100; + const int operating_point_idx = val / 100; + if (operating_point_idx >= 0 && + operating_point_idx < MAX_NUM_OPERATING_POINTS) { + extra_cfg.target_seq_level_idx[operating_point_idx] = (AV1_LEVEL)level; + } return update_extra_cfg(ctx, &extra_cfg); }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 9366660..76a9b27 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -2393,8 +2393,15 @@ assert(IMPLIES(seq_params->profile <= PROFILE_1, seq_params->bit_depth <= AOM_BITS_10)); - cpi->target_seq_level_idx = oxcf->target_seq_level_idx; - cpi->keep_level_stats = cpi->target_seq_level_idx < SEQ_LEVELS; + memcpy(cpi->target_seq_level_idx, oxcf->target_seq_level_idx, + sizeof(cpi->target_seq_level_idx)); + cpi->keep_level_stats = 0; + for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) { + if (cpi->target_seq_level_idx[i] < SEQ_LEVELS) { + cpi->keep_level_stats = 1; + break; + } + } cm->timing_info_present = oxcf->timing_info_present; cm->timing_info.num_units_in_display_tick =
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h index 9729e08..8b64998 100644 --- a/av1/encoder/encoder.h +++ b/av1/encoder/encoder.h
@@ -392,7 +392,7 @@ COST_UPDATE_TYPE coeff_cost_upd_freq; COST_UPDATE_TYPE mode_cost_upd_freq; int border_in_pixels; - AV1_LEVEL target_seq_level_idx; + AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS]; // Bit mask to specify which tier each of the 32 possible operating points // conforms to. unsigned int tier_mask; @@ -995,7 +995,7 @@ uint64_t frame_component_time[kTimingComponents]; #endif // level info and flags - AV1_LEVEL target_seq_level_idx; + AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS]; int keep_level_stats; AV1LevelInfo level_info[MAX_NUM_OPERATING_POINTS]; } AV1_COMP;
diff --git a/av1/encoder/level.c b/av1/encoder/level.c index fdaab76..3a5f937 100644 --- a/av1/encoder/level.c +++ b/av1/encoder/level.c
@@ -231,9 +231,10 @@ "Too many tiles are used.", }; -static void check_level_constraints(AV1_COMP *cpi, +static void check_level_constraints(AV1_COMP *cpi, int operating_point_idx, const AV1LevelSpec *level_spec) { - const AV1_LEVEL target_seq_level_idx = cpi->target_seq_level_idx; + const AV1_LEVEL target_seq_level_idx = + cpi->target_seq_level_idx[operating_point_idx]; if (target_seq_level_idx >= SEQ_LEVELS) return; TARGET_LEVEL_FAIL_ID fail_id = TARGET_LEVEL_FAIL_IDS; // Check level conformance @@ -351,6 +352,6 @@ (void)ts_start; (void)ts_end; - check_level_constraints(cpi, level_spec); + check_level_constraints(cpi, i, level_spec); } }