diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.c b/vp9/encoder/vp9_aq_cyclicrefresh.c index 154068052..44a6f9877 100644 --- a/vp9/encoder/vp9_aq_cyclicrefresh.c +++ b/vp9/encoder/vp9_aq_cyclicrefresh.c @@ -47,6 +47,7 @@ struct CYCLIC_REFRESH { int16_t motion_thresh; // Rate target ratio to set q delta. double rate_ratio_qdelta; + double low_content_avg; }; CYCLIC_REFRESH *vp9_cyclic_refresh_alloc(int mi_rows, int mi_cols) { @@ -244,7 +245,7 @@ void vp9_cyclic_refresh_update_segment(VP9_COMP *const cpi, } // Update the actual number of blocks that were applied the segment delta q. -void vp9_cyclic_refresh_update_actual_count(struct VP9_COMP *const cpi) { +void vp9_cyclic_refresh_postencode(VP9_COMP *const cpi) { VP9_COMMON *const cm = &cpi->common; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; unsigned char *const seg_map = cpi->segmentation_map; @@ -257,6 +258,47 @@ void vp9_cyclic_refresh_update_actual_count(struct VP9_COMP *const cpi) { } } +// Set golden frame update interval, for non-svc 1 pass CBR mode. +void vp9_cyclic_refresh_set_golden_update(VP9_COMP *const cpi) { + RATE_CONTROL *const rc = &cpi->rc; + CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; + // Set minimum gf_interval for GF update to a multiple (== 2) of refresh + // period. Depending on past encoding stats, GF flag may be reset and update + // may not occur until next baseline_gf_interval. + if (cr->percent_refresh > 0) + rc->baseline_gf_interval = 2 * (100 / cr->percent_refresh); + else + rc->baseline_gf_interval = 20; +} + +// Update some encoding stats (from the just encoded frame), and if the golden +// reference is to be updated check if we should NOT update the golden ref. +void vp9_cyclic_refresh_check_golden_update(VP9_COMP *const cpi) { + VP9_COMMON *const cm = &cpi->common; + CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; + int mi_row, mi_col; + double fraction_low = 0.0; + int low_content_frame = 0; + for (mi_row = 0; mi_row < cm->mi_rows; mi_row++) + for (mi_col = 0; mi_col < cm->mi_cols; mi_col++) { + if (cr->map[mi_row * cm->mi_cols + mi_col] < 1) + low_content_frame++; + } + fraction_low = + (double)low_content_frame / (cm->mi_rows * cm->mi_cols); + // Update average. + cr->low_content_avg = (fraction_low + 3 * cr->low_content_avg) / 4; + if (cpi->refresh_golden_frame == 1) { + // Don't update golden reference if the amount of low_content for the + // current encoded frame is small, or if the recursive average of the + // low_content over the update interval window falls below threshold. + if (fraction_low < 0.8 || cr->low_content_avg < 0.7) + cpi->refresh_golden_frame = 0; + // Reset for next internal. + cr->low_content_avg = fraction_low; + } +} + // Update the segmentation map, and related quantities: cyclic refresh map, // refresh sb_index, and target number of blocks to be refreshed. // The map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or to @@ -347,6 +389,8 @@ void vp9_cyclic_refresh_setup(VP9_COMP *const cpi) { CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; struct segmentation *const seg = &cm->seg; const int apply_cyclic_refresh = apply_cyclic_refresh_bitrate(cm, rc); + if (cm->current_video_frame == 0) + cr->low_content_avg = 0.0; // Don't apply refresh on key frame or enhancement layer frames. if (!apply_cyclic_refresh || (cm->frame_type == KEY_FRAME) || diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.h b/vp9/encoder/vp9_aq_cyclicrefresh.h index dc1b968a2..048a0ed35 100644 --- a/vp9/encoder/vp9_aq_cyclicrefresh.h +++ b/vp9/encoder/vp9_aq_cyclicrefresh.h @@ -62,7 +62,13 @@ void vp9_cyclic_refresh_update_segment(struct VP9_COMP *const cpi, void vp9_cyclic_refresh_update__map(struct VP9_COMP *const cpi); // Update the actual number of blocks that were applied the segment delta q. -void vp9_cyclic_refresh_update_actual_count(struct VP9_COMP *const cpi); +void vp9_cyclic_refresh_postencode(struct VP9_COMP *const cpi); + +// Set golden frame update interval, for non-svc 1 pass CBR mode. +void vp9_cyclic_refresh_set_golden_update(struct VP9_COMP *cpi); + +// Check if we should not update golden reference, based on past refresh stats. +void vp9_cyclic_refresh_check_golden_update(struct VP9_COMP *const cpi); // Set/update global/frame level refresh parameters. void vp9_cyclic_refresh_update_parameters(struct VP9_COMP *const cpi); diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index 249c2363d..32bf88061 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -2843,6 +2843,14 @@ static void encode_without_recode_loop(VP9_COMP *cpi) { // transform / motion compensation build reconstruction frame vp9_encode_frame(cpi); + // Update some stats from cyclic refresh, and check if we should not update + // golden reference, for non-SVC 1 pass CBR. + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && + cm->frame_type != KEY_FRAME && + !cpi->use_svc && + (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == VPX_CBR)) + vp9_cyclic_refresh_check_golden_update(cpi); + // Update the skip mb flag probabilities based on the distribution // seen in the last encoder iteration. // update_base_skip_probs(cpi); @@ -3220,7 +3228,6 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, TX_SIZE t; set_ext_overrides(cpi); - vp9_clear_system_state(); // Set the arf sign bias for this frame. diff --git a/vp9/encoder/vp9_ratectrl.c b/vp9/encoder/vp9_ratectrl.c index 79a89af90..eb6eef082 100644 --- a/vp9/encoder/vp9_ratectrl.c +++ b/vp9/encoder/vp9_ratectrl.c @@ -1229,7 +1229,7 @@ void vp9_rc_postencode_update(VP9_COMP *cpi, uint64_t bytes_used) { const int qindex = cm->base_qindex; if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled) { - vp9_cyclic_refresh_update_actual_count(cpi); + vp9_cyclic_refresh_postencode(cpi); } // Update rate control heuristics @@ -1535,7 +1535,10 @@ void vp9_rc_get_one_pass_cbr_params(VP9_COMP *cpi) { cm->frame_type = INTER_FRAME; } if (rc->frames_till_gf_update_due == 0) { - rc->baseline_gf_interval = DEFAULT_GF_INTERVAL; + if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ) + vp9_cyclic_refresh_set_golden_update(cpi); + else + rc->baseline_gf_interval = DEFAULT_GF_INTERVAL; rc->frames_till_gf_update_due = rc->baseline_gf_interval; // NOTE: frames_till_gf_update_due must be <= frames_to_key. if (rc->frames_till_gf_update_due > rc->frames_to_key)