rtc: Restore num_proj_ref after a rejected merge direct_partition_merging() calls find_predictors() on the top left block to test the merge, and find_predictors() sets num_proj_ref to 1. When the merge is rejected, the block keeps that 1 instead of the sample count from pickmode. The bitstream writer reads num_proj_ref in motion_mode_allowed(). If the real count is 0, the encoder writes a motion_mode symbol, but the decoder computes the count itself and reads an obmc symbol. Decoding fails from that frame on. It only happens with warped motion allowed, camera content, speed 8 or higher and a frame without CDF updates. Restore num_proj_ref after a rejected merge. Add RTMotionModeTest. It fails without the fix with a decode error on frame 83. Change-Id: I12b17e7e0e23e597fe2324a1045b7dcfa5d7fda9
diff --git a/av1/encoder/partition_search.c b/av1/encoder/partition_search.c index c038838..55ff863 100644 --- a/av1/encoder/partition_search.c +++ b/av1/encoder/partition_search.c
@@ -2819,6 +2819,7 @@ MB_MODE_INFO **this_mi = mib; BLOCK_SIZE orig_bsize = this_mi[0]->bsize; const PARTITION_TYPE orig_partition = this_mi[0]->partition; + const uint8_t orig_num_proj_ref = this_mi[0]->num_proj_ref; this_mi[0]->bsize = bsize; this_mi[0]->partition = PARTITION_NONE; @@ -2864,6 +2865,7 @@ mi_col, this_mi[0]->bsize); find_predictors(cpi, x, ref_frame, frame_mv, yv12_mb, this_mi[0]->bsize, force_skip_low_temp_var, skip_pred_mv, &use_scaled_ref); + this_mi[0]->num_proj_ref = orig_num_proj_ref; } else { struct scale_factors *sf = get_ref_scale_factors(cm, ref_frame); const int is_scaled = av1_is_scaled(sf);
diff --git a/test/rt_end_to_end_test.cc b/test/rt_end_to_end_test.cc index bbc94e3..e1ff3a1 100644 --- a/test/rt_end_to_end_test.cc +++ b/test/rt_end_to_end_test.cc
@@ -16,8 +16,11 @@ #include "gtest/gtest.h" +#include "config/aom_config.h" + #include "test/codec_factory.h" #include "test/encode_test_driver.h" +#include "test/i420_video_source.h" #include "test/util.h" #include "test/y4m_video_source.h" #include "test/yuv_video_source.h" @@ -205,4 +208,44 @@ ::testing::Values<unsigned int>(0, 3), ::testing::Range(2, 6), ::testing::Range(1, 5), ::testing::Range(1, 5)); + +#if !CONFIG_REALTIME_ONLY +// Keeps warped motion and OBMC at their defaults, so motion mode symbols are +// coded. +class RTMotionModeTest : public ::libaom_test::CodecTestWithParam<int>, + public ::libaom_test::EncoderTest { + protected: + RTMotionModeTest() : EncoderTest(GET_PARAM(0)), cpu_used_(GET_PARAM(1)) {} + ~RTMotionModeTest() override = default; + + void SetUp() override { + InitializeConfig(::libaom_test::kRealTime); + cfg_.g_threads = 1; + cfg_.rc_end_usage = AOM_CBR; + cfg_.rc_target_bitrate = 150; + } + + void PreEncodeFrameHook(::libaom_test::VideoSource *video, + ::libaom_test::Encoder *encoder) override { + if (video->frame() == 0) { + encoder->Control(AOME_SET_CPUUSED, cpu_used_); + encoder->Control(AV1E_SET_TUNE_CONTENT, AOM_CONTENT_DEFAULT); + // Partition merging only runs on frames without CDF updates. + encoder->Control(AV1E_SET_CDF_UPDATE_MODE, 0); + } + } + + int cpu_used_; +}; + +// A rejected partition merge must not change the motion mode inputs of the +// block it tried to merge. +TEST_P(RTMotionModeTest, RejectedMergeKeepsEncoderDecoderMatch) { + ::libaom_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1, + 0, 100); + ASSERT_NO_FATAL_FAILURE(RunLoop(&video)); +} + +AV1_INSTANTIATE_TEST_SUITE(RTMotionModeTest, ::testing::Values(8)); +#endif // !CONFIG_REALTIME_ONLY } // namespace