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);
}
}