Fix stale search_site_config in IntraBC motion search Use av1_get_search_site_config() in rd_pick_intrabc_mode_sb() and av1_search_intrabc_nonrd() instead of reading search_site_cfg[SS_CFG_LOOKAHEAD] directly, and also check y_stride_src in init_motion_estimation(). Fix is suggested by Yuan Tong. Unittests written by Yuan Tong. Bug: 568044446 Change-Id: Id25d82bed48b4fa4bdcc2175af4e6448e2ab05fc (cherry picked from commit ae410fe8b7bd45f3cf61dc8f112dc783e2a08089)
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c index 3842190..4485b49 100644 --- a/av1/encoder/encoder.c +++ b/av1/encoder/encoder.c
@@ -2499,7 +2499,9 @@ !mv_search_params->search_site_cfg[SS_CFG_SRC][DIAMOND].stride || !mv_search_params->search_site_cfg[SS_CFG_LOOKAHEAD][DIAMOND].stride || (y_stride != - mv_search_params->search_site_cfg[SS_CFG_SRC][DIAMOND].stride); + mv_search_params->search_site_cfg[SS_CFG_SRC][DIAMOND].stride) || + (y_stride_src != + mv_search_params->search_site_cfg[SS_CFG_LOOKAHEAD][DIAMOND].stride); if (!should_update) { return;
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c index f43c8df..6c86499 100644 --- a/av1/encoder/nonrd_pickmode.c +++ b/av1/encoder/nonrd_pickmode.c
@@ -1633,12 +1633,12 @@ FULLPEL_MOTION_SEARCH_PARAMS fullms_params; const SEARCH_METHODS search_method = av1_get_default_mv_search_method(x, &cpi->sf.mv_sf, bsize); - const search_site_config *lookahead_search_sites = - cpi->mv_search_params.search_site_cfg[SS_CFG_LOOKAHEAD]; + const search_site_config *src_search_sites = + av1_get_search_site_config(cpi, x, search_method); const FULLPEL_MV start_mv = get_fullmv_from_mv(&dv_ref.as_mv); av1_make_default_fullpel_ms_params(&fullms_params, cpi, x, bsize, - &dv_ref.as_mv, start_mv, - lookahead_search_sites, search_method, + &dv_ref.as_mv, start_mv, src_search_sites, + search_method, /*fine_search_interval=*/0); av1_set_ms_to_intra_mode(&fullms_params, x->dv_costs); fullms_params.mv_limits.col_min = (xd->tile.mi_col_start - mi_col) * MI_SIZE;
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c index b0ea574..e8a6e83 100644 --- a/av1/encoder/rdopt.c +++ b/av1/encoder/rdopt.c
@@ -3377,12 +3377,12 @@ FULLPEL_MOTION_SEARCH_PARAMS fullms_params; const SEARCH_METHODS search_method = av1_get_default_mv_search_method(x, &cpi->sf.mv_sf, bsize); - const search_site_config *lookahead_search_sites = - cpi->mv_search_params.search_site_cfg[SS_CFG_LOOKAHEAD]; + const search_site_config *src_search_sites = + av1_get_search_site_config(cpi, x, search_method); const FULLPEL_MV start_mv = get_fullmv_from_mv(&dv_ref.as_mv); av1_make_default_fullpel_ms_params(&fullms_params, cpi, x, bsize, - &dv_ref.as_mv, start_mv, - lookahead_search_sites, search_method, + &dv_ref.as_mv, start_mv, src_search_sites, + search_method, /*fine_search_interval=*/0); const IntraBCMVCosts *const dv_costs = x->dv_costs; av1_set_ms_to_intra_mode(&fullms_params, dv_costs);
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc index a5eeec6..4c4445e 100644 --- a/test/encode_api_test.cc +++ b/test/encode_api_test.cc
@@ -1505,6 +1505,115 @@ /*speed=*/testing::Values(6, 7, 10), /*aq_mode=*/testing::Values(0, 1, 2, 3))); +// Triggers the IntraBC motion search by using screen content tools to encode a +// key frame. +// Note: The speed must be low enough to run the IntraBC pixel search. +void IntraBCFrameSizeIncreaseTest(unsigned int usage, int speed) { + aom_codec_iface_t *iface = aom_codec_av1_cx(); + aom_codec_enc_cfg_t cfg; + ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, usage), AOM_CODEC_OK); + cfg.g_w = 64; + cfg.g_h = 16; + cfg.g_forced_max_frame_width = 64; + cfg.g_forced_max_frame_height = 64; + cfg.g_lag_in_frames = 0; + cfg.g_threads = 1; + + aom_codec_ctx_t enc; + ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, speed), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN), + AOM_CODEC_OK); + + aom_image_t *img_small = aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 64, 16, 1); + ASSERT_NE(img_small, nullptr); + FillImageRandom(img_small); + aom_image_t *img_large = aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 64, 64, 1); + ASSERT_NE(img_large, nullptr); + FillImageRandom(img_large); + + EncodeOne(&enc, img_small, 0); + + // Only the height grows, so the reconstructed frame keeps its stride while + // the source buffer gets a new one. + cfg.g_h = 64; + ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_encode(&enc, img_large, 1, 1, AOM_EFLAG_FORCE_KF), + AOM_CODEC_OK); + bool got_key_frame = false; + aom_codec_iter_t iter = nullptr; + while (const aom_codec_cx_pkt_t *pkt = aom_codec_get_cx_data(&enc, &iter)) { + if (pkt->kind == AOM_CODEC_CX_FRAME_PKT && + (pkt->data.frame.flags & AOM_FRAME_IS_KEY)) { + got_key_frame = true; + } + } + EXPECT_TRUE(got_key_frame); + + aom_img_free(img_small); + aom_img_free(img_large); + ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); +} + +#if !CONFIG_REALTIME_ONLY +TEST(EncodeAPI, IntraBCFrameSizeIncreaseGoodQuality) { + IntraBCFrameSizeIncreaseTest(AOM_USAGE_GOOD_QUALITY, 2); +} + +TEST(EncodeAPI, IntraBCFrameSizeIncreaseAllIntra) { + IntraBCFrameSizeIncreaseTest(AOM_USAGE_ALL_INTRA, 5); +} +#endif // !CONFIG_REALTIME_ONLY + +TEST(EncodeAPI, IntraBCFrameSizeIncreaseRealtime) { + IntraBCFrameSizeIncreaseTest(AOM_USAGE_REALTIME, 7); +} + +// Encodes a narrow key frame after a wide one with screen content tools in +// realtime mode. The source buffer of the narrow frame has a smaller stride +// than the buffer of the wide frame, so the IntraBC motion search must not use +// search sites built for the wider stride. The assertion in +// av1_full_pixel_search() checks that the strides match. +TEST(EncodeAPI, IntraBCFrameSizeDecreaseRealtime) { + aom_codec_iface_t *iface = aom_codec_av1_cx(); + aom_codec_enc_cfg_t cfg; + ASSERT_EQ(aom_codec_enc_config_default(iface, &cfg, AOM_USAGE_REALTIME), + AOM_CODEC_OK); + cfg.g_w = 1024; + cfg.g_h = 512; + cfg.g_lag_in_frames = 0; + cfg.g_threads = 1; + + aom_codec_ctx_t enc; + ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_control(&enc, AOME_SET_CPUUSED, 7), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_control(&enc, AV1E_SET_TUNE_CONTENT, AOM_CONTENT_SCREEN), + AOM_CODEC_OK); + + aom_image_t *img_wide = + aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 1024, 512, 1); + ASSERT_NE(img_wide, nullptr); + FillImageRandom(img_wide); + aom_image_t *img_narrow = + aom_img_alloc(nullptr, AOM_IMG_FMT_I420, 32, 512, 1); + ASSERT_NE(img_narrow, nullptr); + FillImageRandom(img_narrow); + + EncodeOne(&enc, img_wide, 0); + + cfg.g_w = 32; + ASSERT_EQ(aom_codec_enc_config_set(&enc, &cfg), AOM_CODEC_OK); + ASSERT_EQ(aom_codec_encode(&enc, img_narrow, 1, 1, AOM_EFLAG_FORCE_KF), + AOM_CODEC_OK); + aom_codec_iter_t iter = nullptr; + while (aom_codec_get_cx_data(&enc, &iter) != nullptr) { + } + + aom_img_free(img_wide); + aom_img_free(img_narrow); + ASSERT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK); +} + #if !CONFIG_REALTIME_ONLY TEST(EncodeAPI, AllIntraMode) { aom_codec_iface_t *iface = aom_codec_av1_cx();