diff options
Diffstat (limited to 'av1/encoder/aq_cyclicrefresh.c')
-rw-r--r-- | av1/encoder/aq_cyclicrefresh.c | 186 |
1 files changed, 95 insertions, 91 deletions
diff --git a/av1/encoder/aq_cyclicrefresh.c b/av1/encoder/aq_cyclicrefresh.c index 89c4ac33c..616d52f2e 100644 --- a/av1/encoder/aq_cyclicrefresh.c +++ b/av1/encoder/aq_cyclicrefresh.c @@ -26,6 +26,8 @@ CYCLIC_REFRESH *av1_cyclic_refresh_alloc(int mi_rows, int mi_cols) { cr->map = aom_calloc(mi_rows * mi_cols, sizeof(*cr->map)); cr->counter_encode_maxq_scene_change = 0; + cr->percent_refresh_adjustment = 5; + cr->rate_ratio_qdelta_adjustment = 0.25; if (cr->map == NULL) { av1_cyclic_refresh_free(cr); return NULL; @@ -73,10 +75,8 @@ static int candidate_refresh_aq(const CYCLIC_REFRESH *cr, // Compute delta-q for the segment. static int compute_deltaq(const AV1_COMP *cpi, int q, double rate_factor) { const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; - const RATE_CONTROL *const rc = &cpi->rc; int deltaq = av1_compute_qdelta_by_rate( - rc, cpi->common.current_frame.frame_type, q, rate_factor, - cpi->is_screen_content_type, cpi->common.seq_params->bit_depth); + cpi, cpi->common.current_frame.frame_type, q, rate_factor); if ((-deltaq) > cr->max_qdelta_perc * q / 100) { deltaq = -cr->max_qdelta_perc * q / 100; } @@ -86,9 +86,7 @@ static int compute_deltaq(const AV1_COMP *cpi, int q, double rate_factor) { int av1_cyclic_refresh_estimate_bits_at_q(const AV1_COMP *cpi, double correction_factor) { const AV1_COMMON *const cm = &cpi->common; - const FRAME_TYPE frame_type = cm->current_frame.frame_type; const int base_qindex = cm->quant_params.base_qindex; - const int bit_depth = cm->seq_params->bit_depth; const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; const int mbs = cm->mi_params.MBs; const int num4x4bl = mbs << 4; @@ -105,17 +103,13 @@ int av1_cyclic_refresh_estimate_bits_at_q(const AV1_COMP *cpi, // Take segment weighted average for estimated bits. const int estimated_bits = (int)((1.0 - weight_segment1 - weight_segment2) * - av1_estimate_bits_at_q(frame_type, base_qindex, mbs, - correction_factor, bit_depth, - cpi->is_screen_content_type) + - weight_segment1 * av1_estimate_bits_at_q( - frame_type, base_qindex + cr->qindex_delta[1], - mbs, correction_factor, bit_depth, - cpi->is_screen_content_type) + - weight_segment2 * av1_estimate_bits_at_q( - frame_type, base_qindex + cr->qindex_delta[2], - mbs, correction_factor, bit_depth, - cpi->is_screen_content_type)); + av1_estimate_bits_at_q(cpi, base_qindex, correction_factor) + + weight_segment1 * + av1_estimate_bits_at_q(cpi, base_qindex + cr->qindex_delta[1], + correction_factor) + + weight_segment2 * + av1_estimate_bits_at_q(cpi, base_qindex + cr->qindex_delta[2], + correction_factor)); return estimated_bits; } @@ -141,21 +135,21 @@ int av1_cyclic_refresh_rc_bits_per_mb(const AV1_COMP *cpi, int i, } // Compute delta-q corresponding to qindex i. int deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta); + const int accurate_estimate = cpi->sf.hl_sf.accurate_bit_estimate; // Take segment weighted average for bits per mb. bits_per_mb = (int)((1.0 - weight_segment) * - av1_rc_bits_per_mb(cm->current_frame.frame_type, i, - correction_factor, cm->seq_params->bit_depth, - cpi->is_screen_content_type) + - weight_segment * av1_rc_bits_per_mb(cm->current_frame.frame_type, - i + deltaq, correction_factor, - cm->seq_params->bit_depth, - cpi->is_screen_content_type)); + av1_rc_bits_per_mb(cpi, cm->current_frame.frame_type, i, + correction_factor, accurate_estimate) + + weight_segment * av1_rc_bits_per_mb( + cpi, cm->current_frame.frame_type, i + deltaq, + correction_factor, accurate_estimate)); return bits_per_mb; } void av1_cyclic_reset_segment_skip(const AV1_COMP *cpi, MACROBLOCK *const x, - int mi_row, int mi_col, BLOCK_SIZE bsize) { + int mi_row, int mi_col, BLOCK_SIZE bsize, + RUN_TYPE dry_run) { int cdf_num; const AV1_COMMON *const cm = &cpi->common; MACROBLOCKD *const xd = &x->e_mbd; @@ -174,21 +168,22 @@ void av1_cyclic_reset_segment_skip(const AV1_COMP *cpi, MACROBLOCK *const x, av1_get_spatial_seg_pred(cm, xd, &cdf_num, cr->skip_over4x4); if (prev_segment_id != mbmi->segment_id) { const int block_index = mi_row * cm->mi_params.mi_cols + mi_col; + const int mi_stride = cm->mi_params.mi_cols; + const uint8_t segment_id = mbmi->segment_id; for (int mi_y = 0; mi_y < ymis; mi_y++) { - for (int mi_x = 0; mi_x < xmis; mi_x++) { - const int map_offset = - block_index + mi_y * cm->mi_params.mi_cols + mi_x; - cr->map[map_offset] = 0; - cpi->enc_seg.map[map_offset] = mbmi->segment_id; - cm->cur_frame->seg_map[map_offset] = mbmi->segment_id; - } + const int map_offset = block_index + mi_y * mi_stride; + memset(&cr->map[map_offset], 0, xmis); + memset(&cpi->enc_seg.map[map_offset], segment_id, xmis); + memset(&cm->cur_frame->seg_map[map_offset], segment_id, xmis); } } } - if (cyclic_refresh_segment_id(prev_segment_id) == CR_SEGMENT_ID_BOOST1) - x->actual_num_seg1_blocks -= xmis * ymis; - else if (cyclic_refresh_segment_id(prev_segment_id) == CR_SEGMENT_ID_BOOST2) - x->actual_num_seg2_blocks -= xmis * ymis; + if (!dry_run) { + if (cyclic_refresh_segment_id(prev_segment_id) == CR_SEGMENT_ID_BOOST1) + x->actual_num_seg1_blocks -= xmis * ymis; + else if (cyclic_refresh_segment_id(prev_segment_id) == CR_SEGMENT_ID_BOOST2) + x->actual_num_seg2_blocks -= xmis * ymis; + } } void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi, MACROBLOCK *const x, @@ -219,12 +214,13 @@ void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi, MACROBLOCK *const x, // Reset segment_id if will be skipped. if (skip) mbmi->segment_id = CR_SEGMENT_ID_BASE; } + const uint8_t segment_id = mbmi->segment_id; // Update the cyclic refresh map, to be used for setting segmentation map // for the next frame. If the block will be refreshed this frame, mark it // as clean. The magnitude of the -ve influences how long before we consider // it for refresh again. - if (cyclic_refresh_segment_id_boosted(mbmi->segment_id)) { + if (cyclic_refresh_segment_id_boosted(segment_id)) { new_map_value = -cr->time_for_refresh; } else if (refresh_this_block) { // Else if it is accepted as candidate for refresh, and has not already @@ -238,30 +234,19 @@ void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi, MACROBLOCK *const x, // Update entries in the cyclic refresh map with new_map_value, and // copy mbmi->segment_id into global segmentation map. - if (sh == 1) { - for (int mi_y = 0; mi_y < ymis; mi_y += sh) { - const int map_offset = block_index + mi_y * cm->mi_params.mi_cols; - memset(&cr->map[map_offset], new_map_value, xmis); - memset(&cpi->enc_seg.map[map_offset], mbmi->segment_id, xmis); - memset(&cm->cur_frame->seg_map[map_offset], mbmi->segment_id, xmis); - } - } else { - for (int mi_y = 0; mi_y < ymis; mi_y += sh) { - for (int mi_x = 0; mi_x < xmis; mi_x += sh) { - const int map_offset = - block_index + mi_y * cm->mi_params.mi_cols + mi_x; - cr->map[map_offset] = new_map_value; - cpi->enc_seg.map[map_offset] = mbmi->segment_id; - cm->cur_frame->seg_map[map_offset] = mbmi->segment_id; - } - } + const int mi_stride = cm->mi_params.mi_cols; + for (int mi_y = 0; mi_y < ymis; mi_y += sh) { + const int map_offset = block_index + mi_y * mi_stride; + memset(&cr->map[map_offset], new_map_value, xmis); + memset(&cpi->enc_seg.map[map_offset], segment_id, xmis); + memset(&cm->cur_frame->seg_map[map_offset], segment_id, xmis); } + // Accumulate cyclic refresh update counters. if (!dry_run) { - if (cyclic_refresh_segment_id(mbmi->segment_id) == CR_SEGMENT_ID_BOOST1) + if (cyclic_refresh_segment_id(segment_id) == CR_SEGMENT_ID_BOOST1) x->actual_num_seg1_blocks += xmis * ymis; - else if (cyclic_refresh_segment_id(mbmi->segment_id) == - CR_SEGMENT_ID_BOOST2) + else if (cyclic_refresh_segment_id(segment_id) == CR_SEGMENT_ID_BOOST2) x->actual_num_seg2_blocks += xmis * ymis; } } @@ -314,15 +299,14 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { uint64_t sb_sad = 0; uint64_t thresh_sad_low = 0; uint64_t thresh_sad = INT64_MAX; - memset(seg_map, CR_SEGMENT_ID_BASE, mi_params->mi_rows * mi_params->mi_cols); - sb_cols = (mi_params->mi_cols + cm->seq_params->mib_size - 1) / - cm->seq_params->mib_size; - sb_rows = (mi_params->mi_rows + cm->seq_params->mib_size - 1) / - cm->seq_params->mib_size; + const int mi_rows = mi_params->mi_rows, mi_cols = mi_params->mi_cols; + const int mi_stride = mi_cols; + memset(seg_map, CR_SEGMENT_ID_BASE, mi_rows * mi_cols); + sb_cols = (mi_cols + cm->seq_params->mib_size - 1) / cm->seq_params->mib_size; + sb_rows = (mi_rows + cm->seq_params->mib_size - 1) / cm->seq_params->mib_size; sbs_in_frame = sb_cols * sb_rows; // Number of target blocks to get the q delta (segment 1). - block_count = - cr->percent_refresh * mi_params->mi_rows * mi_params->mi_cols / 100; + block_count = cr->percent_refresh * mi_rows * mi_cols / 100; // Set the segmentation map: cycle through the superblocks, starting at // cr->mb_index, and stopping when either block_count blocks have been found // to be refreshed, or we have passed through whole frame. @@ -337,16 +321,17 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { int sb_col_index = i - sb_row_index * sb_cols; int mi_row = sb_row_index * cm->seq_params->mib_size; int mi_col = sb_col_index * cm->seq_params->mib_size; - assert(mi_row >= 0 && mi_row < mi_params->mi_rows); - assert(mi_col >= 0 && mi_col < mi_params->mi_cols); - bl_index = mi_row * mi_params->mi_cols + mi_col; + assert(mi_row >= 0 && mi_row < mi_rows); + assert(mi_col >= 0 && mi_col < mi_cols); + bl_index = mi_row * mi_stride + mi_col; // Loop through all MI blocks in superblock and update map. - xmis = AOMMIN(mi_params->mi_cols - mi_col, cm->seq_params->mib_size); - ymis = AOMMIN(mi_params->mi_rows - mi_row, cm->seq_params->mib_size); - if (cpi->sf.rt_sf.sad_based_comp_prune && cr->use_block_sad_scene_det && - cpi->rc.frames_since_key > 30 && + xmis = AOMMIN(mi_cols - mi_col, cm->seq_params->mib_size); + ymis = AOMMIN(mi_rows - mi_row, cm->seq_params->mib_size); + if (cr->use_block_sad_scene_det && cpi->rc.frames_since_key > 30 && cr->counter_encode_maxq_scene_change > 30 && - cpi->src_sad_blk_64x64 != NULL) { + cpi->src_sad_blk_64x64 != NULL && + cpi->svc.number_temporal_layers == 1 && + cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1) { sb_sad = cpi->src_sad_blk_64x64[sb_col_index + sb_cols * sb_row_index]; int scale = (cm->width * cm->height < 640 * 360) ? 6 : 8; int scale_low = 2; @@ -356,7 +341,7 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { // cr_map only needed at 8x8 blocks. for (y = 0; y < ymis; y += 2) { for (x = 0; x < xmis; x += 2) { - const int bl_index2 = bl_index + y * mi_params->mi_cols + x; + const int bl_index2 = bl_index + y * mi_stride + x; // If the block is as a candidate for clean up then mark it // for possible boost/refresh (segment 1). The segment id may get // reset to 0 later if block gets coded anything other than low motion. @@ -372,10 +357,8 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { // If segment is at least half of superblock, set to 1. // Enforce that block sad (sb_sad) is not too high. if (sum_map >= (xmis * ymis) >> 1 && sb_sad < thresh_sad) { - for (y = 0; y < ymis; y++) - for (x = 0; x < xmis; x++) { - seg_map[bl_index + y * mi_params->mi_cols + x] = CR_SEGMENT_ID_BOOST1; - } + set_segment_id(seg_map, bl_index, xmis, ymis, mi_stride, + CR_SEGMENT_ID_BOOST1); cr->target_num_seg_blocks += xmis * ymis; } i++; @@ -390,6 +373,10 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) { } } +static int is_scene_change_detected(AV1_COMP *const cpi) { + return cpi->rc.high_source_sad; +} + // Set cyclic refresh parameters. void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { // TODO(marpan): Parameters need to be tuned. @@ -405,9 +392,15 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN) qp_thresh = AOMMIN(35, rc->best_quality << 1); int qp_max_thresh = 118 * MAXQ >> 7; - const int scene_change_detected = - cpi->rc.high_source_sad || - (cpi->ppi->use_svc && cpi->svc.high_source_sad_superframe); + const int scene_change_detected = is_scene_change_detected(cpi); + + // Cases to reset the cyclic refresh adjustment parameters. + if (frame_is_intra_only(cm) || scene_change_detected) { + // Reset adaptive elements for intra only frames and scene changes. + cr->percent_refresh_adjustment = 5; + cr->rate_ratio_qdelta_adjustment = 0.25; + } + // Although this segment feature for RTC is only used for // blocks >= 8X8, for more efficient coding of the seg map // cur_frame->seg_map needs to set at 4x4 along with the @@ -417,6 +410,8 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { // Also if loop-filter deltas is applied via segment, then // we need to set cr->skip_over4x4 = 1. cr->skip_over4x4 = (cpi->oxcf.speed > 9) ? 1 : 0; + + // should we enable cyclic refresh on this frame. cr->apply_cyclic_refresh = 1; if (frame_is_intra_only(cm) || is_lossless_requested(&cpi->oxcf.rc_cfg) || scene_change_detected || cpi->svc.temporal_layer_id > 0 || @@ -430,14 +425,13 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { cr->apply_cyclic_refresh = 0; return; } - cr->percent_refresh = 10; - // Increase the amount of refresh for #temporal_layers > 2, and for some - // frames after scene change that is encoded at high Q. + + // Increase the amount of refresh for #temporal_layers > 2 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 = 15; + else + cr->percent_refresh = 10 + cr->percent_refresh_adjustment; + cr->max_qdelta_perc = 60; cr->time_for_refresh = 0; cr->use_block_sad_scene_det = @@ -454,9 +448,9 @@ void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) { if (cr->percent_refresh > 0 && rc->frames_since_key < (4 * cpi->svc.number_temporal_layers) * (100 / cr->percent_refresh)) { - cr->rate_ratio_qdelta = 3.0; + cr->rate_ratio_qdelta = 3.0 + cr->rate_ratio_qdelta_adjustment; } else { - cr->rate_ratio_qdelta = 2.0; + cr->rate_ratio_qdelta = 2.25 + cr->rate_ratio_qdelta_adjustment; } // Adjust some parameters for low resolutions. if (cm->width * cm->height <= 352 * 288) { @@ -508,12 +502,16 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { const RATE_CONTROL *const rc = &cpi->rc; CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; struct segmentation *const seg = &cm->seg; - const int scene_change_detected = - cpi->rc.high_source_sad || - (cpi->ppi->use_svc && cpi->svc.high_source_sad_superframe); + const int scene_change_detected = is_scene_change_detected(cpi); + const GF_GROUP *const gf_group = &cpi->ppi->gf_group; + const int boost_index = AOMMIN(15, (cpi->ppi->p_rc.gfu_boost / 100)); + const int layer_depth = AOMMIN(gf_group->layer_depth[cpi->gf_frame_index], 6); + const FRAME_TYPE frame_type = cm->current_frame.frame_type; + 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); if (!cr->apply_cyclic_refresh) { // Set segmentation map to 0 and disable. @@ -572,7 +570,11 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) { const int qindex2 = clamp( quant_params->base_qindex + quant_params->y_dc_delta_q + qindex_delta, 0, MAXQ); - cr->rdmult = av1_compute_rd_mult(cpi, qindex2); + cr->rdmult = av1_compute_rd_mult( + qindex2, cm->seq_params->bit_depth, + cpi->ppi->gf_group.update_type[cpi->gf_frame_index], layer_depth, + boost_index, frame_type, cpi->oxcf.q_cfg.use_fixed_qp_offsets, + is_stat_consumption_stage(cpi)); av1_set_segdata(seg, CR_SEGMENT_ID_BOOST1, SEG_LVL_ALT_Q, qindex_delta); @@ -601,6 +603,8 @@ void av1_cyclic_refresh_reset_resize(AV1_COMP *const cpi) { cpi->refresh_frame.golden_frame = true; cr->apply_cyclic_refresh = 0; cr->counter_encode_maxq_scene_change = 0; + cr->percent_refresh_adjustment = 5; + cr->rate_ratio_qdelta_adjustment = 0.25; } int av1_cyclic_refresh_disable_lf_cdef(AV1_COMP *const cpi) { |