rtc: Adjust cyclic refresh for screen
Reset the refresh on slide change and set larger
refresh period for some frames after scene change
that is encoded at high Q for faster cleanup.
Also make sure source_sad speed feature is always on
for screen mode.
Visual quality improvement after scene change,
average psnr increase of ~0.25dB on 1850x1110 slide change
clip, with little/no change in speed/fps.
Change-Id: If9d29a830a3f1b9483e112de65b3d650d7148fa1
diff --git a/av1/encoder/aq_cyclicrefresh.c b/av1/encoder/aq_cyclicrefresh.c
index 71393dc..9d95788 100644
--- a/av1/encoder/aq_cyclicrefresh.c
+++ b/av1/encoder/aq_cyclicrefresh.c
@@ -25,6 +25,7 @@
if (cr == NULL) return NULL;
cr->map = aom_calloc(mi_rows * mi_cols, sizeof(*cr->map));
+ cr->counter_encode_maxq_scene_change = 0;
if (cr->map == NULL) {
av1_cyclic_refresh_free(cr);
return NULL;
@@ -426,11 +427,18 @@
return;
}
cr->percent_refresh = 10;
- if (cpi->svc.number_temporal_layers > 2) cr->percent_refresh = 15;
+ // Increase the amount of refresh for #temporal_layers > 2, and for some
+ // frames after scene change that is encoded at high Q.
+ if (cpi->svc.number_temporal_layers > 2)
+ cr->percent_refresh = 15;
+ else if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
+ cr->counter_encode_maxq_scene_change < 20)
+ cr->percent_refresh = 20;
cr->max_qdelta_perc = 60;
cr->time_for_refresh = 0;
cr->motion_thresh = 32;
- cr->rate_boost_fac = 15;
+ cr->rate_boost_fac =
+ (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN) ? 10 : 15;
// Use larger delta-qp (increase rate_ratio_qdelta) for first few (~4)
// periods of the refresh cycle, after a key frame.
// Account for larger interval on base layer for temporal layers.
@@ -491,7 +499,10 @@
const RATE_CONTROL *const rc = &cpi->rc;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
struct segmentation *const seg = &cm->seg;
- int resolution_change =
+ const int scene_change_detected =
+ cpi->rc.high_source_sad ||
+ (cpi->ppi->use_svc && cpi->svc.high_source_sad_superframe);
+ const int resolution_change =
cm->prev_frame && (cm->width != cm->prev_frame->width ||
cm->height != cm->prev_frame->height);
if (resolution_change) av1_cyclic_refresh_reset_resize(cpi);
@@ -500,11 +511,13 @@
unsigned char *const seg_map = cpi->enc_seg.map;
memset(seg_map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols);
av1_disable_segmentation(&cm->seg);
- if (cm->current_frame.frame_type == KEY_FRAME) {
+ if (cm->current_frame.frame_type == KEY_FRAME || scene_change_detected) {
cr->sb_index = 0;
+ cr->counter_encode_maxq_scene_change = 0;
}
return;
} else {
+ cr->counter_encode_maxq_scene_change++;
const double q = av1_convert_qindex_to_q(cm->quant_params.base_qindex,
cm->seq_params->bit_depth);
// Set rate threshold to some multiple (set to 2 for now) of the target
@@ -578,4 +591,5 @@
cr->sb_index = 0;
cpi->refresh_frame.golden_frame = true;
cr->apply_cyclic_refresh = 0;
+ cr->counter_encode_maxq_scene_change = 0;
}
diff --git a/av1/encoder/aq_cyclicrefresh.h b/av1/encoder/aq_cyclicrefresh.h
index 4e4e1f2..484f88f 100644
--- a/av1/encoder/aq_cyclicrefresh.h
+++ b/av1/encoder/aq_cyclicrefresh.h
@@ -108,6 +108,7 @@
double weight_segment;
int apply_cyclic_refresh;
int skip_over4x4;
+ int counter_encode_maxq_scene_change;
/*!\endcond */
};
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index b5448d5..8b4abc9 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -3084,6 +3084,7 @@
double q2;
int enumerator;
*q = (3 * cpi->rc.worst_quality + *q) >> 2;
+ cpi->cyclic_refresh->counter_encode_maxq_scene_change = 0;
// Adjust avg_frame_qindex, buffer_level, and rate correction factors, as
// these parameters will affect QP selection for subsequent frames. If they
// have settled down to a very different (low QP) state, then not adjusting
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 8ab710c..7dbabbc 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1289,8 +1289,10 @@
cpi->svc.ref_frame_comp[2] && cpi->svc.reference[ALTREF_FRAME - 1];
}
}
- if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN)
+ if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN) {
sf->rt_sf.use_comp_ref_nonrd = 0;
+ sf->rt_sf.source_metrics_sb_nonrd = 1;
+ }
}
// TODO(kyslov): now this is very similar to