diff options
author | Marco Paniconi <marpan@google.com> | 2024-03-12 14:51:48 -0700 |
---|---|---|
committer | Marco Paniconi <marpan@google.com> | 2024-03-14 23:34:32 -0700 |
commit | 74d1ea7c5151e06bbf83159479bac2da647a9bca (patch) | |
tree | 8318f7cea59addd0b872549f2874af887f268123 | |
parent | fdd6af31b1f6ea19464daf961b46ad6a5befd89f (diff) | |
download | libaom-74d1ea7c5151e06bbf83159479bac2da647a9bca.tar.gz |
rtc: Skip scene detection for inactive blocks
For active_maps in real-time mode: the source sad in
the scene detection may be skipped based on inactive
blocks via the active_maps input. This reduces some
calculations, and is bitexact behavior.
Change-Id: I21d53a6fc1da63ecdcdbfb0ebcb9f2c85c4a6870
-rw-r--r-- | av1/encoder/encoder.c | 7 | ||||
-rw-r--r-- | av1/encoder/ratectrl.c | 50 | ||||
-rw-r--r-- | av1/encoder/ratectrl.h | 3 |
3 files changed, 55 insertions, 5 deletions
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 36ce8ae27..88862de69 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c @@ -154,14 +154,19 @@ int av1_set_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows, const int mi_rows = mi_params->mi_rows; const int mi_cols = mi_params->mi_cols; cpi->active_map.update = 0; + cpi->rc.percent_blocks_inactive = 0; assert(mi_rows % 2 == 0); assert(mi_cols % 2 == 0); if (new_map_16x16) { + int num_samples = 0; + int num_blocks_inactive = 0; for (int r = 0; r < mi_rows; r += 4) { for (int c = 0; c < mi_cols; c += 4) { const uint8_t val = new_map_16x16[(r >> 2) * cols + (c >> 2)] ? AM_SEGMENT_ID_ACTIVE : AM_SEGMENT_ID_INACTIVE; + num_samples++; + if (val == AM_SEGMENT_ID_INACTIVE) num_blocks_inactive++; const int row_max = AOMMIN(4, mi_rows - r); const int col_max = AOMMIN(4, mi_cols - c); for (int x = 0; x < row_max; ++x) { @@ -173,6 +178,8 @@ int av1_set_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows, } cpi->active_map.enabled = 1; cpi->active_map.update = 1; + cpi->rc.percent_blocks_inactive = + (num_blocks_inactive * 100) / num_samples; } return 0; } diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c index b7cc06e8e..7639484df 100644 --- a/av1/encoder/ratectrl.c +++ b/av1/encoder/ratectrl.c @@ -30,6 +30,7 @@ #include "av1/common/seg_common.h" #include "av1/encoder/encodemv.h" +#include "av1/encoder/encoder_utils.h" #include "av1/encoder/encode_strategy.h" #include "av1/encoder/gop_structure.h" #include "av1/encoder/random.h" @@ -439,6 +440,7 @@ void av1_rc_init(const AV1EncoderConfig *oxcf, RATE_CONTROL *rc) { rc->rtc_external_ratectrl = 0; rc->frame_level_fast_extra_bits = 0; rc->use_external_qp_one_pass = 0; + rc->percent_blocks_inactive = 0; } static bool check_buffer_below_thresh(AV1_COMP *cpi, int64_t buffer_level, @@ -2989,6 +2991,24 @@ void av1_set_rtc_reference_structure_one_layer(AV1_COMP *cpi, int gf_update) { cpi->rt_reduce_num_ref_buffers &= (rtc_ref->ref_idx[2] < 7); } +static int set_block_is_active(unsigned char *const active_map_4x4, int mi_cols, + int mi_rows, int sbi_col, int sbi_row, int sh, + int num_4x4) { + int r = sbi_row << sh; + int c = sbi_col << sh; + const int row_max = AOMMIN(num_4x4, mi_rows - r); + const int col_max = AOMMIN(num_4x4, mi_cols - c); + // Active map is set for 16x16 blocks, so only need to + // check over16x16, + for (int x = 0; x < row_max; x += 4) { + for (int y = 0; y < col_max; y += 4) { + if (active_map_4x4[(r + x) * mi_cols + (c + y)] == AM_SEGMENT_ID_ACTIVE) + return 1; + } + } + return 0; +} + /*!\brief Check for scene detection, for 1 pass real-time mode. * * Compute average source sad (temporal sad: between current source and @@ -3091,11 +3111,26 @@ static void rc_scene_detection_onepass_rt(AV1_COMP *cpi, sizeof(*cpi->src_sad_blk_64x64))); } } + const CommonModeInfoParams *const mi_params = &cpi->common.mi_params; + const int mi_cols = mi_params->mi_cols; + const int mi_rows = mi_params->mi_rows; + int sh = (cm->seq_params->sb_size == BLOCK_128X128) ? 5 : 4; + int num_4x4 = (cm->seq_params->sb_size == BLOCK_128X128) ? 32 : 16; + unsigned char *const active_map_4x4 = cpi->active_map.map; // Avoid bottom and right border. for (int sbi_row = 0; sbi_row < sb_rows - border; ++sbi_row) { for (int sbi_col = 0; sbi_col < sb_cols; ++sbi_col) { - tmp_sad = cpi->ppi->fn_ptr[bsize].sdf(src_y, src_ystride, last_src_y, - last_src_ystride); + int block_is_active = 1; + if (cpi->active_map.enabled && rc->percent_blocks_inactive > 0) { + block_is_active = set_block_is_active(active_map_4x4, mi_cols, mi_rows, + sbi_col, sbi_row, sh, num_4x4); + } + if (block_is_active) { + tmp_sad = cpi->ppi->fn_ptr[bsize].sdf(src_y, src_ystride, last_src_y, + last_src_ystride); + } else { + tmp_sad = 0; + } if (cpi->src_sad_blk_64x64 != NULL) cpi->src_sad_blk_64x64[sbi_col + sbi_row * sb_cols] = tmp_sad; if (check_light_change) { @@ -3454,8 +3489,13 @@ void av1_get_one_pass_rt_params(AV1_COMP *cpi, FRAME_TYPE *const frame_type, } } } - // Check for scene change: for SVC check on base spatial layer only. - if (cpi->sf.rt_sf.check_scene_detection && svc->spatial_layer_id == 0) { + if (cpi->active_map.enabled && cpi->rc.percent_blocks_inactive == 100) { + rc->frame_source_sad = 0; + rc->avg_source_sad = (3 * rc->avg_source_sad + rc->frame_source_sad) >> 2; + rc->percent_blocks_with_motion = 0; + rc->high_source_sad = 0; + } else if (cpi->sf.rt_sf.check_scene_detection && + svc->spatial_layer_id == 0) { if (rc->prev_coded_width == cm->width && rc->prev_coded_height == cm->height) { rc_scene_detection_onepass_rt(cpi, frame_input); @@ -3602,4 +3642,4 @@ int av1_encodedframe_overshoot_cbr(AV1_COMP *cpi, int *q) { } } return 1; -}
\ No newline at end of file +} diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h index 6802ad42d..0dd8e32b7 100644 --- a/av1/encoder/ratectrl.h +++ b/av1/encoder/ratectrl.h @@ -249,6 +249,9 @@ typedef struct { // signals if number of blocks with motion is high int percent_blocks_with_motion; + // signals percentge of 16x16 blocks that are inactive, via active_maps + int percent_blocks_inactive; + // Maximum value of source sad across all blocks of frame. uint64_t max_block_source_sad; |