Move per-frame speed-level into EncodeFrameParams
Move speed-level into EncodeFrameParams so that, in theory, a different
speed-level can be set per frame (though this is currently untested and
the per-frame speed level is just set to oxcf->speed).
This forms part of wider restructuring and refactoring in order to
achieve a clean API separation at the entry to the low-level encoder.
BUG=aomedia:2244
Change-Id: I54f81ecb8ffa01bac26b406305108553b17ceea7
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index ffde6b7..3680a9a 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -324,10 +324,13 @@
int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
uint8_t *const dest, unsigned int *frame_flags,
struct lookahead_entry *source) {
- EncodeFrameParams frame_params = { 0, 0, 0 };
- EncodeFrameResults frame_results = { 0 };
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
+ EncodeFrameParams frame_params;
+ EncodeFrameResults frame_results;
+ memset(&frame_params, 0, sizeof(frame_params));
+ memset(&frame_results, 0, sizeof(frame_results));
+
frame_params.frame_flags = frame_flags;
// TODO(david.turner@argondesign.com): Move all the encode strategy
@@ -336,6 +339,11 @@
// TODO(david.turner@argondesign.com): Change all the encode strategy to
// modify frame_params instead of cm or cpi.
+ // Per-frame encode speed. In theory this can vary, but things may have been
+ // written assuming speed-level will not change within a sequence, so this
+ // parameter should be used with caution.
+ frame_params.speed = oxcf->speed;
+
if (oxcf->pass == 0) { // Single pass encode
if (Pass0Encode(cpi, dest, &frame_params, &frame_results) != AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index b97d2f2..82fec7a 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -358,6 +358,9 @@
// When superres / resize is on, 'cm->width / height' can change between
// calls, so we don't apply this heuristic there. Also, this heuristic gives
// compression gain for speed >= 2 only.
+ // Things break if superblock size changes per-frame which is why this
+ // heuristic is set based on configured speed rather than actual
+ // speed-features (which may change per-frame in future)
if (cpi->oxcf.superres_mode == SUPERRES_NONE &&
cpi->oxcf.resize_mode == RESIZE_NONE && cpi->oxcf.speed >= 2) {
return (cm->width >= 480 && cm->height >= 360) ? BLOCK_128X128
@@ -2806,8 +2809,8 @@
(int32_t *)aom_memalign(
16, MAX_SB_SQUARE * sizeof(*cpi->td.mb.mask_buf)));
- av1_set_speed_features_framesize_independent(cpi);
- av1_set_speed_features_framesize_dependent(cpi);
+ av1_set_speed_features_framesize_independent(cpi, oxcf->speed);
+ av1_set_speed_features_framesize_dependent(cpi, oxcf->speed);
for (int frame = 0; frame < MAX_LAG_BUFFERS; ++frame) {
int mi_cols = ALIGN_POWER_OF_TWO(cm->mi_cols, MAX_MIB_SIZE_LOG2);
@@ -3907,7 +3910,7 @@
cm->global_motion[i] = default_warp_params;
}
cpi->global_motion_search_done = 0;
- av1_set_speed_features_framesize_independent(cpi);
+ av1_set_speed_features_framesize_independent(cpi, cpi->speed);
av1_set_rd_speed_thresholds(cpi);
cm->interp_filter = SWITCHABLE;
cm->switchable_motion_mode = 1;
@@ -3934,7 +3937,7 @@
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
// Setup variables that depend on the dimensions of the frame.
- av1_set_speed_features_framesize_dependent(cpi);
+ av1_set_speed_features_framesize_dependent(cpi, cpi->speed);
// Decide q and q bounds.
*q = av1_rc_pick_q_and_bounds(cpi, cm->width, cm->height, bottom_index,
@@ -5557,6 +5560,7 @@
cm->error_resilient_mode = frame_params->error_resilient_mode;
cpi->ref_frame_flags = frame_params->ref_frame_flags;
+ cpi->speed = frame_params->speed;
if (encode_frame_to_data_rate(cpi, &frame_results->size, dest,
frame_params->frame_flags) != AOM_CODEC_OK) {
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index cc46404..7292525 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -719,6 +719,9 @@
int ref_frame_flags;
int ext_ref_frame_flags;
+ // speed is passed as a per-frame parameter into the encoder
+ int speed;
+ // sf contains fine-grained config set internally based on speed
SPEED_FEATURES sf;
unsigned int max_mv_magnitude;
@@ -876,6 +879,9 @@
// This is a bitmask of which reference slots can be used in this frame
int ref_frame_flags;
+ // Speed level to use for this frame: Bigger number means faster.
+ int speed;
+
unsigned int *frame_flags;
} EncodeFrameParams;
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 5b6e6f1..f6aa389 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -80,7 +80,7 @@
// partly on the screen area that over which they propogate. Propogation is
// limited by transform block size but the screen area take up by a given block
// size will be larger for a small image format stretched to full screen.
-static BLOCK_SIZE set_partition_min_limit(AV1_COMMON *const cm) {
+static BLOCK_SIZE set_partition_min_limit(const AV1_COMMON *const cm) {
unsigned int screen_area = (cm->width * cm->height);
// Select block size based on image format size.
@@ -103,10 +103,9 @@
(cpi->twopass.this_frame_stats.inactive_zone_cols > 0));
}
-static void set_good_speed_feature_framesize_dependent(AV1_COMP *cpi,
- SPEED_FEATURES *sf,
- int speed) {
- AV1_COMMON *const cm = &cpi->common;
+static void set_good_speed_feature_framesize_dependent(
+ const AV1_COMP *const cpi, SPEED_FEATURES *const sf, int speed) {
+ const AV1_COMMON *const cm = &cpi->common;
const int is_720p_or_larger = AOMMIN(cm->width, cm->height) >= 720;
const int is_480p_or_larger = AOMMIN(cm->width, cm->height) >= 480;
@@ -201,10 +200,9 @@
}
}
-static void set_good_speed_features_framesize_independent(AV1_COMP *cpi,
- SPEED_FEATURES *sf,
- int speed) {
- AV1_COMMON *const cm = &cpi->common;
+static void set_good_speed_features_framesize_independent(
+ const AV1_COMP *const cpi, SPEED_FEATURES *const sf, int speed) {
+ const AV1_COMMON *const cm = &cpi->common;
const int boosted = frame_is_boosted(cpi);
// Speed 0 for all speed features that give neutral coding performance change.
@@ -409,12 +407,12 @@
}
}
-void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi) {
+void av1_set_speed_features_framesize_dependent(AV1_COMP *cpi, int speed) {
SPEED_FEATURES *const sf = &cpi->sf;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
if (oxcf->mode == GOOD) {
- set_good_speed_feature_framesize_dependent(cpi, sf, oxcf->speed);
+ set_good_speed_feature_framesize_dependent(cpi, sf, speed);
}
if (sf->disable_split_mask == DISABLE_ALL_SPLIT) {
@@ -428,7 +426,7 @@
cpi->find_fractional_mv_step = av1_return_min_sub_pixel_mv;
}
-void av1_set_speed_features_framesize_independent(AV1_COMP *cpi) {
+void av1_set_speed_features_framesize_independent(AV1_COMP *cpi, int speed) {
AV1_COMMON *const cm = &cpi->common;
SPEED_FEATURES *const sf = &cpi->sf;
MACROBLOCK *const x = &cpi->td.mb;
@@ -577,7 +575,7 @@
sf->perform_coeff_opt = 0;
if (oxcf->mode == GOOD)
- set_good_speed_features_framesize_independent(cpi, sf, oxcf->speed);
+ set_good_speed_features_framesize_independent(cpi, sf, speed);
if (!cpi->seq_params_locked) {
cpi->common.seq_params.enable_dual_filter &= !sf->disable_dual_filter;
@@ -592,28 +590,31 @@
cpi->diamond_search_sad = av1_diamond_search_sad;
sf->allow_exhaustive_searches = 1;
- int speed = (oxcf->speed > MAX_MESH_SPEED) ? MAX_MESH_SPEED : oxcf->speed;
+
+ const int mesh_speed = AOMMIN(speed, MAX_MESH_SPEED);
if (cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION)
sf->exhaustive_searches_thresh = (1 << 24);
else
sf->exhaustive_searches_thresh = (1 << 25);
- sf->max_exaustive_pct = good_quality_max_mesh_pct[speed];
- if (speed > 0)
+ sf->max_exaustive_pct = good_quality_max_mesh_pct[mesh_speed];
+ if (mesh_speed > 0)
sf->exhaustive_searches_thresh = sf->exhaustive_searches_thresh << 1;
for (i = 0; i < MAX_MESH_STEP; ++i) {
- sf->mesh_patterns[i].range = good_quality_mesh_patterns[speed][i].range;
+ sf->mesh_patterns[i].range =
+ good_quality_mesh_patterns[mesh_speed][i].range;
sf->mesh_patterns[i].interval =
- good_quality_mesh_patterns[speed][i].interval;
+ good_quality_mesh_patterns[mesh_speed][i].interval;
}
if ((frame_is_intra_only(cm) && cm->allow_screen_content_tools) &&
(cpi->twopass.fr_content_type == FC_GRAPHICS_ANIMATION ||
cpi->oxcf.content == AOM_CONTENT_SCREEN)) {
for (i = 0; i < MAX_MESH_STEP; ++i) {
- sf->mesh_patterns[i].range = intrabc_mesh_patterns[speed][i].range;
- sf->mesh_patterns[i].interval = intrabc_mesh_patterns[speed][i].interval;
+ sf->mesh_patterns[i].range = intrabc_mesh_patterns[mesh_speed][i].range;
+ sf->mesh_patterns[i].interval =
+ intrabc_mesh_patterns[mesh_speed][i].interval;
}
- sf->max_exaustive_pct = intrabc_max_mesh_pct[speed];
+ sf->max_exaustive_pct = intrabc_max_mesh_pct[mesh_speed];
}
// Slow quant, dct and trellis not worthwhile for first pass
@@ -654,9 +655,7 @@
comp_type_rd_threshold_mul[sf->prune_comp_type_by_comp_avg];
cpi->max_comp_type_rd_threshold_div =
comp_type_rd_threshold_div[sf->prune_comp_type_by_comp_avg];
- int tx_domain_speed = (oxcf->speed >= MAX_TX_DOMAIN_EVAL_SPEED)
- ? MAX_TX_DOMAIN_EVAL_SPEED
- : oxcf->speed;
+ const int tx_domain_speed = AOMMIN(speed, MAX_TX_DOMAIN_EVAL_SPEED);
cpi->tx_domain_dist_threshold = tx_domain_dist_thresholds[tx_domain_speed];
// assert ensures that coeff_opt_dist_thresholds is accessed correctly
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index c7debb1..2216c7b 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -656,8 +656,10 @@
struct AV1_COMP;
-void av1_set_speed_features_framesize_independent(struct AV1_COMP *cpi);
-void av1_set_speed_features_framesize_dependent(struct AV1_COMP *cpi);
+void av1_set_speed_features_framesize_independent(struct AV1_COMP *cpi,
+ int speed);
+void av1_set_speed_features_framesize_dependent(struct AV1_COMP *cpi,
+ int speed);
#ifdef __cplusplus
} // extern "C"