Commit 15d987ce53 for aom

commit 15d987ce53366326b3773d9a1d87bfe1f68a1dec
Author: Marco Paniconi <marpan@google.com>
Date:   Wed Jun 3 05:05:28 2026 +0000

    Fix to update num_proj_ref for nonrd mode

    Issue occurs when warped_motion is used for real-time mode.
    The mi->num_proj_ref was not updated on the final selected
    mode in the nonrd_pick_inter_mode(), and not updated
    when blocks were merged in the direct_partition_merging().
    This causes the decode failure in the issue below.

    Note warped-motion is disabled for CONFIG_REALTIME_ONLY.
    And the direct_partition_merging speed feature is only
    used for real-time speed >= 8.

    Unittest added.

    Bug: 514696186
    Change-Id: I4279b8a0fbe430608044a2068eea1aac767bbd48

diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index dd94a24458..82159e83e6 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -4514,6 +4514,13 @@ static inline bool is_switchable_motion_mode_allowed(bool allow_warped_motion,
   return (allow_warped_motion || enable_obmc);
 }

+static inline int warped_motion_update_num_proj_ref(
+    const struct AV1_COMP *const cpi, const MB_MODE_INFO *const mi) {
+  return cpi->oxcf.motion_mode_cfg.allow_warped_motion && is_inter_block(mi) &&
+         !mi->skip_mode && is_motion_variation_allowed_bsize(mi->bsize) &&
+         !has_second_ref(mi);
+}
+
 #if CONFIG_AV1_TEMPORAL_DENOISING
 static inline int denoise_svc(const struct AV1_COMP *const cpi) {
   return (!cpi->ppi->use_svc ||
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
index 57cae24ba5..aa0d2e2a6e 100644
--- a/av1/encoder/nonrd_pickmode.c
+++ b/av1/encoder/nonrd_pickmode.c
@@ -3748,6 +3748,12 @@ void av1_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data,

   *rd_cost = search_state.best_rdc;

+  mi->num_proj_ref = 0;
+  if (warped_motion_update_num_proj_ref(cpi, mi)) {
+    int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
+    mi->num_proj_ref = av1_findSamples(cm, xd, pts, pts_inref);
+  }
+
   // Reset the xd->block_ref_scale_factors[i], as they may have
   // been set to pointer &sf_no_scale, which becomes invalid afer
   // this function.
diff --git a/av1/encoder/partition_search.c b/av1/encoder/partition_search.c
index 2feb14fd3f..09838846b8 100644
--- a/av1/encoder/partition_search.c
+++ b/av1/encoder/partition_search.c
@@ -2924,6 +2924,12 @@ static void direct_partition_merging(AV1_COMP *cpi, ThreadData *td,
         this_mi[x_idx + y * mi_params->mi_stride] = this_mi[0];
       }
     }
+
+    this_mi[0]->num_proj_ref = 0;
+    if (warped_motion_update_num_proj_ref(cpi, this_mi[0])) {
+      int pts[SAMPLES_ARRAY_SIZE], pts_inref[SAMPLES_ARRAY_SIZE];
+      this_mi[0]->num_proj_ref = av1_findSamples(cm, xd, pts, pts_inref);
+    }
   }
 }

diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index c777d4a9c0..c33f6365d4 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -759,6 +759,23 @@ TEST_P(DatarateTestPsnr, PerFramePsnr) {
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
 }

+// Test to reproduce decode failure in issue: 514696186.
+TEST_P(DatarateTestRealtime, WarpedMotionEnabled) {
+  if (GET_PARAM(2) != 8) GTEST_SKIP() << "Only run for cpu-used=8";
+
+  ResetModel();
+
+  cfg_.rc_end_usage = AOM_CBR;
+  cfg_.rc_target_bitrate = 100;
+  cfg_.rc_min_quantizer = 2;
+  cfg_.rc_max_quantizer = 52;
+  enable_warped_motion_ = true;
+
+  ::libaom_test::YUVVideoSource video("hantro_odd.yuv", AOM_IMG_FMT_I420, 208,
+                                      144, 30, 1, 0, 30);
+  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+}
+
 AV1_INSTANTIATE_TEST_SUITE(DatarateTestLarge,
                            ::testing::Values(::libaom_test::kRealTime),
                            ::testing::Range(5, 7), ::testing::Values(0, 3),
diff --git a/test/datarate_test.h b/test/datarate_test.h
index 9b91cb4148..d531b936e2 100644
--- a/test/datarate_test.h
+++ b/test/datarate_test.h
@@ -70,6 +70,7 @@ class DatarateTest : public ::libaom_test::EncoderTest {
     }
     avif_mode_ = 0;
     lag_realtime_mode_ = 0;
+    enable_warped_motion_ = false;
   }

   void PreEncodeFrameHook(::libaom_test::VideoSource *video,
@@ -86,7 +87,7 @@ class DatarateTest : public ::libaom_test::EncoderTest {
       encoder->Control(AV1E_SET_ROW_MT, 1);
       if (cfg_.g_usage == AOM_USAGE_REALTIME) {
         encoder->Control(AV1E_SET_ENABLE_GLOBAL_MOTION, 0);
-        encoder->Control(AV1E_SET_ENABLE_WARPED_MOTION, 0);
+        encoder->Control(AV1E_SET_ENABLE_WARPED_MOTION, enable_warped_motion_);
         encoder->Control(AV1E_SET_ENABLE_RESTORATION, 0);
         encoder->Control(AV1E_SET_ENABLE_OBMC, 0);
         encoder->Control(AV1E_SET_DELTAQ_MODE, 0);
@@ -290,6 +291,7 @@ class DatarateTest : public ::libaom_test::EncoderTest {
   int frame_number_dynamic_[3];
   int avif_mode_;
   int lag_realtime_mode_;
+  bool enable_warped_motion_;
 };

 }  // namespace