Commit ef2ac20fe9 for aom

commit ef2ac20fe987f8a0b7aa675f7644239a9b6cb6e7
Author: Ihor Buhaiov <freedbrt@gmail.com>
Date:   Wed Oct 7 11:00:49 2026 +0200

    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 c038838bc0..55ff863b74 100644
--- a/av1/encoder/partition_search.c
+++ b/av1/encoder/partition_search.c
@@ -2819,6 +2819,7 @@ static void direct_partition_merging(AV1_COMP *cpi, ThreadData *td,
   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 @@ static void direct_partition_merging(AV1_COMP *cpi, ThreadData *td,
                                        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 bbc94e3cd9..e1ff3a1972 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 @@ AV1_INSTANTIATE_TEST_SUITE(RTEndToEndTestThreaded,
                            ::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