rtc: Some fixes to cyclic refresh This change sets the segment on skipped blocks such that segment_id is the same on encoder/decoder for skip_txfm=1 blocks. Also cm->cur_frame->seg_map needs to be updated, and over 4x4 blocks. These changes are needed to allow for loopfilter-delta on the segments in the cyclic refresh: https://aomedia-review.googlesource.com/c/aom/+/135621 bdrate gain for speed 9: 0.25%, negligble change in speed Change-Id: I42984f198d90f717ea5fe9a5a2ff0a8719926da5
diff --git a/av1/encoder/aq_cyclicrefresh.c b/av1/encoder/aq_cyclicrefresh.c index 63f99b3..f78d90c 100644 --- a/av1/encoder/aq_cyclicrefresh.c +++ b/av1/encoder/aq_cyclicrefresh.c
@@ -12,6 +12,7 @@ #include <limits.h> #include <math.h> +#include "av1/common/pred_common.h" #include "av1/common/seg_common.h" #include "av1/encoder/aq_cyclicrefresh.h" #include "av1/encoder/ratectrl.h" @@ -147,6 +148,42 @@ 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 cdf_num; + const AV1_COMMON *const cm = &cpi->common; + MACROBLOCKD *const xd = &x->e_mbd; + MB_MODE_INFO *const mbmi = xd->mi[0]; + const int prev_segment_id = mbmi->segment_id; + mbmi->segment_id = av1_get_spatial_seg_pred(cm, xd, &cdf_num); + if (prev_segment_id != mbmi->segment_id) { + CYCLIC_REFRESH *const cr = cpi->cyclic_refresh; + const int bw = mi_size_wide[bsize]; + const int bh = mi_size_high[bsize]; + const int xmis = AOMMIN(cm->mi_params.mi_cols - mi_col, bw); + const int ymis = AOMMIN(cm->mi_params.mi_rows - mi_row, bh); + const int block_index = mi_row * cm->mi_params.mi_cols + mi_col; + 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; + } + } + 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 (cyclic_refresh_segment_id(mbmi->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) + x->actual_num_seg2_blocks += xmis * ymis; + } +} + void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi, MACROBLOCK *const x, int mi_row, int mi_col, BLOCK_SIZE bsize, int64_t rate, int64_t dist, int skip, @@ -191,22 +228,21 @@ // Update entries in the cyclic refresh map with new_map_value, and // copy mbmi->segment_id into global segmentation map. - // 8x8 is smallest coding block size for non-key frames. - const int sh = bw << 1; - for (int mi_y = 0; mi_y < ymis; mi_y += 2) { - for (int mi_x = 0; mi_x < xmis; mi_x += 2) { - int map_offset = block_index + mi_y * cm->mi_params.mi_cols + mi_x; + 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] = new_map_value; cpi->enc_seg.map[map_offset] = mbmi->segment_id; + cm->cur_frame->seg_map[map_offset] = mbmi->segment_id; } - // Accumulate cyclic refresh update counters. - if (!dry_run && !frame_is_intra_only(cm)) { - if (cyclic_refresh_segment_id(mbmi->segment_id) == CR_SEGMENT_ID_BOOST1) - x->actual_num_seg1_blocks += sh; - else if (cyclic_refresh_segment_id(mbmi->segment_id) == - CR_SEGMENT_ID_BOOST2) - x->actual_num_seg2_blocks += sh; - } + } + // Accumulate cyclic refresh update counters. + if (!dry_run) { + if (cyclic_refresh_segment_id(mbmi->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) + x->actual_num_seg2_blocks += xmis * ymis; } }
diff --git a/av1/encoder/aq_cyclicrefresh.h b/av1/encoder/aq_cyclicrefresh.h index 97bd6f2..1c0d5cb 100644 --- a/av1/encoder/aq_cyclicrefresh.h +++ b/av1/encoder/aq_cyclicrefresh.h
@@ -161,6 +161,30 @@ int av1_cyclic_refresh_rc_bits_per_mb(const struct AV1_COMP *cpi, int i, double correction_factor); +/*!\brief Update segment_id for blocks are skipped. + * + * After encoding a given prediction block, of size bsize at (mi_row, mi_col), + * check if we should reset the segment_id based on skip_txfm, + * and update the cyclic_refresh map and segmentation counters. + * + * \ingroup cyclic_refresh + * \callgraph + * \callergraph + * + * \param[in] cpi Top level encoder structure + * \param[in] x Pointer to MACROBLOCK structure + * \param[in] mi_row Row coordinate of the block in a step size of MI_SIZE + * \param[in] mi_col Col coordinate of the block in a step size of MI_SIZE + * \param[in] bsize Block size + * + * \return Update the \c mbmi->segment_id, the \c cpi->cyclic_refresh and + * the \c cm->cpi->enc_seg.map. + */ + +void av1_cyclic_reset_segment_skip(const struct AV1_COMP *cpi, + MACROBLOCK *const x, int mi_row, int mi_col, + BLOCK_SIZE bsize); + /*!\brief Update segment_id for block based on mode selected. * * Prior to coding a given prediction block, of size bsize at (mi_row, mi_col),
diff --git a/av1/encoder/partition_search.c b/av1/encoder/partition_search.c index da46762..3265e76 100644 --- a/av1/encoder/partition_search.c +++ b/av1/encoder/partition_search.c
@@ -1855,6 +1855,8 @@ update_cb_offsets(x, bsize, subsampling_x, subsampling_y); if (tile_data->allow_update_cdf) update_stats(&cpi->common, td); } + if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && mbmi->skip_txfm) + av1_cyclic_reset_segment_skip(cpi, x, mi_row, mi_col, bsize); // TODO(Ravi/Remya): Move this copy function to a better logical place // This function will copy the best mode information from block // level (x->mbmi_ext) to frame level (cpi->mbmi_ext_info.frame_base). This