Superres recode bugfix
When we try recoding the 1st frame with/without superres, different
superblock sizes may be picked depending on frame resolution. This
change in superblock size leads to some dimensions like 'mi_cols',
'mi_rows', 'mi_stride' etc becoming invalid. In turn, allocated sizes
and strides of some arrays become invalid as well.
We avoid this by separate variables for superres_mode provided by user
(existing one in 'oxcf'), and the one used by current encoding (new one
in 'cpi').
Certain top-level decisions like superblock size use the user-provided
oxcf->superres_mode, while most other logic uses cpi->superres_mode.
Fixes a couple of bugs.
Tested that SUPERRES_RECODE_ALL_RATIOS=1 works correctly as well.
BUG=aomedia:2536
BUG=aomedia:2569
Change-Id: I581951e1942779913ab2b7450e0e3cc58d79d87a
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 142959a..44992c4 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -295,7 +295,7 @@
if (tpl_frame->is_valid == 0) return deltaq_rdmult;
if (!is_frame_tpl_eligible((AV1_COMP *)cpi)) return deltaq_rdmult;
if (tpl_idx >= MAX_LAG_BUFFERS) return deltaq_rdmult;
- if (cpi->oxcf.superres_mode != SUPERRES_NONE) return deltaq_rdmult;
+ if (cpi->superres_mode != SUPERRES_NONE) return deltaq_rdmult;
if (cpi->oxcf.aq_mode != NO_AQ) return deltaq_rdmult;
const int bsize_base = BLOCK_16X16;
@@ -3970,7 +3970,7 @@
int mi_col, int64_t *intra_cost_b,
int64_t *inter_cost_b, int *stride) {
if (!cpi->oxcf.enable_tpl_model) return 0;
- if (cpi->oxcf.superres_mode != SUPERRES_NONE) return 0;
+ if (cpi->superres_mode != SUPERRES_NONE) return 0;
if (cpi->common.current_frame.frame_type == KEY_FRAME) return 0;
const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group);
if (update_type == INTNL_OVERLAY_UPDATE || update_type == OVERLAY_UPDATE)
@@ -4567,7 +4567,7 @@
if (tpl_frame->is_valid == 0) return;
if (!is_frame_tpl_eligible(cpi)) return;
if (frame_idx >= MAX_LAG_BUFFERS) return;
- if (cpi->oxcf.superres_mode != SUPERRES_NONE) return;
+ if (cpi->superres_mode != SUPERRES_NONE) return;
if (cpi->oxcf.aq_mode != NO_AQ) return;
const int is_overlay = cpi->gf_group.update_type[frame_idx] == OVERLAY_UPDATE;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index a70df19..1ee38b6 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2829,6 +2829,7 @@
update_film_grain_parameters(cpi, oxcf);
cpi->oxcf = *oxcf;
+ cpi->superres_mode = oxcf->superres_mode; // default
x->e_mbd.bd = (int)seq_params->bit_depth;
x->e_mbd.global_motion = cm->global_motion;
@@ -4533,6 +4534,7 @@
*/
#if CONFIG_SUPERRES_IN_RECODE
if (superres_in_recode_allowed(cpi)) {
+ assert(cpi->superres_mode != SUPERRES_NONE);
// Force superres to be tried in the recode loop, as full-res is also going
// to be tried anyway.
denom = AOMMAX(denom, SCALE_NUMERATOR + 1);
@@ -4558,8 +4560,14 @@
cpi->common.seq_params.enable_superres));
assert(IMPLIES(!cpi->common.seq_params.enable_superres,
oxcf->superres_mode == SUPERRES_NONE));
+ // Make sure that superres mode for current encoding is consistent with user
+ // provided superres mode.
+ assert(IMPLIES(oxcf->superres_mode != SUPERRES_AUTO,
+ cpi->superres_mode == oxcf->superres_mode));
- switch (oxcf->superres_mode) {
+ // Note: we must look at the current superres_mode to be tried in 'cpi' here,
+ // not the user given mode in 'oxcf'.
+ switch (cpi->superres_mode) {
case SUPERRES_NONE: new_denom = SCALE_NUMERATOR; break;
case SUPERRES_FIXED:
if (cpi->common.current_frame.frame_type == KEY_FRAME)
@@ -4713,7 +4721,7 @@
resize_denom);
}
rsz.superres_denom = calculate_next_superres_scale(cpi);
- if (!validate_size_scales(oxcf->resize_mode, oxcf->superres_mode, oxcf->width,
+ if (!validate_size_scales(oxcf->resize_mode, cpi->superres_mode, oxcf->width,
oxcf->height, &rsz))
assert(0 && "Invalid scale parameters");
return rsz;
@@ -5303,7 +5311,7 @@
const int is_screen_content_type_orig_decision = cpi->is_screen_content_type;
// Turn off the encoding trial for forward key frame and superres.
if (cpi->sf.rt_sf.use_nonrd_pick_mode || cpi->oxcf.fwd_kf_enabled ||
- cpi->oxcf.superres_mode != SUPERRES_NONE || cpi->oxcf.mode == REALTIME ||
+ cpi->superres_mode != SUPERRES_NONE || cpi->oxcf.mode == REALTIME ||
is_screen_content_type_orig_decision || !is_key_frame) {
return;
}
@@ -5396,10 +5404,11 @@
av1_setup_frame_size(cpi);
#if CONFIG_SUPERRES_IN_RECODE
- if (superres_in_recode_allowed(cpi) &&
+ if (superres_in_recode_allowed(cpi) && cpi->superres_mode != SUPERRES_NONE &&
cm->superres_scale_denominator == SCALE_NUMERATOR) {
- // Superres won't be picked, so no need to try, as we will go through
- // another recode loop for full-resolution after this anyway.
+ // Superres mode in currently enabled, but the denominator selected will
+ // disable superres. So no need to continue, as we will go through another
+ // recode loop for full-resolution after this anyway.
return -1;
}
#endif // CONFIG_SUPERRES_IN_RECODE
@@ -5827,7 +5836,6 @@
uint8_t *dest,
int *largest_tile_id) {
const AV1_COMMON *const cm = &cpi->common;
- AV1EncoderConfig *const oxcf = &cpi->oxcf;
assert(cm->seq_params.enable_superres);
assert(superres_in_recode_allowed(cpi));
aom_codec_err_t err = AOM_CODEC_OK;
@@ -5835,6 +5843,7 @@
// Encode with superres.
#if SUPERRES_RECODE_ALL_RATIOS
+ AV1EncoderConfig *const oxcf = &cpi->oxcf;
int64_t superres_sses[SCALE_NUMERATOR];
int64_t superres_rates[SCALE_NUMERATOR];
int superres_largest_tile_ids[SCALE_NUMERATOR];
@@ -5878,10 +5887,11 @@
int64_t sse2 = INT64_MAX;
int64_t rate2 = INT64_MAX;
int largest_tile_id2;
- oxcf->superres_mode = SUPERRES_NONE; // To force full-res.
+ cpi->superres_mode = SUPERRES_NONE; // To force full-res.
err = encode_with_recode_loop_and_filter(cpi, size, dest, &sse2, &rate2,
&largest_tile_id2);
- oxcf->superres_mode = SUPERRES_AUTO; // Reset.
+ cpi->superres_mode = cpi->oxcf.superres_mode; // Reset.
+ assert(cpi->oxcf.superres_mode == SUPERRES_AUTO);
if (err != AOM_CODEC_OK) return err;
// Note: Both use common rdmult based on base qindex of fullres.
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 4274aec..06c093a 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1247,6 +1247,11 @@
int max_qmlevel;
int use_quant_b_adapt;
int num_tg;
+
+ // Super-resolution mode currently being used by the encoder.
+ // This may / may not be same as user-supplied mode in oxcf->superres_mode
+ // (when we are recoding to try multiple options for example).
+ SUPERRES_MODE superres_mode;
} AV1_COMP;
typedef struct {
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 3c8bb80..144d9e0 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -865,15 +865,15 @@
static int get_active_cq_level(const RATE_CONTROL *rc,
const AV1EncoderConfig *const oxcf,
- int intra_only, int superres_denom) {
+ int intra_only, SUPERRES_MODE superres_mode,
+ int superres_denom) {
static const double cq_adjust_threshold = 0.1;
int active_cq_level = oxcf->cq_level;
(void)intra_only;
if (oxcf->rc_mode == AOM_CQ || oxcf->rc_mode == AOM_Q) {
// printf("Superres %d %d %d = %d\n", superres_denom, intra_only,
// rc->frames_to_key, !(intra_only && rc->frames_to_key <= 1));
- if ((oxcf->superres_mode == SUPERRES_QTHRESH ||
- oxcf->superres_mode == SUPERRES_AUTO) &&
+ if ((superres_mode == SUPERRES_QTHRESH || superres_mode == SUPERRES_AUTO) &&
superres_denom != SCALE_NUMERATOR) {
int mult = SUPERRES_QADJ_PER_DENOM_KEYFRAME_SOLO;
if (intra_only && rc->frames_to_key <= 1) {
@@ -941,8 +941,9 @@
const RATE_CONTROL *const rc = &cpi->rc;
const CurrentFrame *const current_frame = &cm->current_frame;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
- const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
- cm->superres_scale_denominator);
+ const int cq_level =
+ get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode,
+ cm->superres_scale_denominator);
const int bit_depth = cm->seq_params.bit_depth;
if (oxcf->use_fixed_qp_offsets) {
@@ -1216,8 +1217,8 @@
// Tweak active_best_quality for AOM_Q mode when superres is on, as this
// will be used directly as 'q' later.
if (oxcf->rc_mode == AOM_Q &&
- (oxcf->superres_mode == SUPERRES_QTHRESH ||
- oxcf->superres_mode == SUPERRES_AUTO) &&
+ (cpi->superres_mode == SUPERRES_QTHRESH ||
+ cpi->superres_mode == SUPERRES_AUTO) &&
cm->superres_scale_denominator != SCALE_NUMERATOR) {
active_best_quality =
AOMMAX(active_best_quality -
@@ -1394,8 +1395,9 @@
const RATE_CONTROL *const rc = &cpi->rc;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
const GF_GROUP *gf_group = &cpi->gf_group;
- const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
- cm->superres_scale_denominator);
+ const int cq_level =
+ get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode,
+ cm->superres_scale_denominator);
const int bit_depth = cm->seq_params.bit_depth;
if (oxcf->use_fixed_qp_offsets) {
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 7973412..7c34de7 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -984,7 +984,7 @@
EncodeFrameParams this_frame_params = *frame_params;
TplParams *const tpl_data = &cpi->tpl_data;
- if (cpi->oxcf.superres_mode != SUPERRES_NONE) return 0;
+ if (cpi->superres_mode != SUPERRES_NONE) return 0;
cm->current_frame.frame_type = frame_params->frame_type;
for (int gf_index = gf_group->index; gf_index < gf_group->size; ++gf_index) {
@@ -1087,7 +1087,7 @@
const TplDepFrame *const tpl_frame = &tpl_data->tpl_frame[tpl_idx];
if (!tpl_frame->is_valid) return;
- if (cpi->oxcf.superres_mode != SUPERRES_NONE) return;
+ if (cpi->superres_mode != SUPERRES_NONE) return;
const TplDepStats *const tpl_stats = tpl_frame->tpl_stats_ptr;
const int tpl_stride = tpl_frame->stride;
@@ -1142,7 +1142,7 @@
if (tpl_frame->is_valid == 0) return;
if (!is_frame_tpl_eligible(cpi)) return;
if (tpl_idx >= MAX_LAG_BUFFERS) return;
- if (cpi->oxcf.superres_mode != SUPERRES_NONE) return;
+ if (cpi->superres_mode != SUPERRES_NONE) return;
if (cpi->oxcf.aq_mode != NO_AQ) return;
const int bsize_base = BLOCK_16X16;