Fix ref_mv for int_pro_motion_estimation() in nonrd_pickmode

For nonrd_pickmode (speed >= 7): fix the ref_mv input to
the int_pro_motion_estimation(), used for newmv search on
non-last reference.

The ref_mv used there should be set via av1_get_ref_mv(),
which gets the ref_mv properly (i.e., gets the mv from
mbmi_ext->ref_mv_stack[] or mbmi_ext->global_mvs[] depending
on ref_mv_idx). In this assert case it was taking ref_mv
directly from ref_mv_stack[], when it should be taking
global_mvs (which is zeromv).

No changes in stats for all rtc sets, speed >= 7.

Added a test that triggers the issue without the fix.
Since it was only triggered on high resolution, the
test upsamples a QVGA clip, using libyuv.

Bug: b:396169342
Change-Id: Ic93dc733017ab0c80db0e1d8a30cc03e3b625139
(cherry picked from commit 127be6a600e56735c6b73a2f23c7bd0577a9d3f3)
diff --git a/av1/encoder/nonrd_pickmode.c b/av1/encoder/nonrd_pickmode.c
index 96070ab..fd01565 100644
--- a/av1/encoder/nonrd_pickmode.c
+++ b/av1/encoder/nonrd_pickmode.c
@@ -322,10 +322,10 @@
 
     int me_search_size_col = block_size_wide[bsize] >> 1;
     int me_search_size_row = block_size_high[bsize] >> 1;
+    MV ref_mv = av1_get_ref_mv(x, 0).as_mv;
     tmp_sad = av1_int_pro_motion_estimation(
-        cpi, x, bsize, mi_row, mi_col,
-        &x->mbmi_ext.ref_mv_stack[ref_frame][0].this_mv.as_mv, &y_sad_zero,
-        me_search_size_col, me_search_size_row);
+        cpi, x, bsize, mi_row, mi_col, &ref_mv, &y_sad_zero, me_search_size_col,
+        me_search_size_row);
 
     if (tmp_sad > x->pred_mv_sad[LAST_FRAME]) return -1;
 
@@ -333,7 +333,6 @@
     int_mv best_mv = mi->mv[0];
     best_mv.as_mv.row >>= 3;
     best_mv.as_mv.col >>= 3;
-    MV ref_mv = av1_get_ref_mv(x, 0).as_mv;
     this_ref_frm_newmv->as_mv.row >>= 3;
     this_ref_frm_newmv->as_mv.col >>= 3;
 
diff --git a/test/datarate_test.cc b/test/datarate_test.cc
index e1d6a1d..97fa32a 100644
--- a/test/datarate_test.cc
+++ b/test/datarate_test.cc
@@ -21,9 +21,59 @@
 #include "test/y4m_video_source.h"
 #include "aom/aom_codec.h"
 
+#if CONFIG_LIBYUV
+#include "third_party/libyuv/include/libyuv/scale.h"
+#endif
+
 namespace datarate_test {
 namespace {
 
+#if CONFIG_LIBYUV
+class ResizingVideoSource : public ::libaom_test::DummyVideoSource {
+ public:
+  ResizingVideoSource(const int width, const int height, const int input_width,
+                      const int input_height, const std::string file_name,
+                      int limit)
+      : width_(width), height_(height), input_width_(input_width),
+        input_height_(input_height), limit_(limit) {
+    SetSize(width_, height_);
+    img_input_ = aom_img_alloc(nullptr, AOM_IMG_FMT_I420, input_width_,
+                               input_height_, 32);
+    raw_size_ = input_width_ * input_height_ * 3 / 2;
+    input_file_ = ::libaom_test::OpenTestDataFile(file_name);
+  }
+
+  ~ResizingVideoSource() override {
+    aom_img_free(img_input_);
+    fclose(input_file_);
+  }
+
+ protected:
+  void FillFrame() override {
+    // Read frame from input_file and scale up.
+    ASSERT_NE(input_file_, nullptr);
+    fread(img_input_->img_data, raw_size_, 1, input_file_);
+    libyuv::I420Scale(
+        img_input_->planes[AOM_PLANE_Y], img_input_->stride[AOM_PLANE_Y],
+        img_input_->planes[AOM_PLANE_U], img_input_->stride[AOM_PLANE_U],
+        img_input_->planes[AOM_PLANE_V], img_input_->stride[AOM_PLANE_V],
+        input_width_, input_height_, img_->planes[AOM_PLANE_Y],
+        img_->stride[AOM_PLANE_Y], img_->planes[AOM_PLANE_U],
+        img_->stride[AOM_PLANE_U], img_->planes[AOM_PLANE_V],
+        img_->stride[AOM_PLANE_V], width_, height_, libyuv::kFilterBox);
+  }
+
+  const int width_;
+  const int height_;
+  const int input_width_;
+  const int input_height_;
+  const int limit_;
+  aom_image_t *img_input_;
+  size_t raw_size_;
+  FILE *input_file_;
+};
+#endif  // CONFIG_LIBYUV
+
 // Params: test mode, speed, aq mode and index for bitrate array.
 class DatarateTestLarge
     : public ::libaom_test::CodecTestWith4Params<libaom_test::TestMode, int,
@@ -86,6 +136,27 @@
         << " The datarate for the file is greater than target by too much!";
   }
 
+#if CONFIG_LIBYUV
+  // Test for an encoding mode that triggers an assert in nonrd_pickmode
+  // (in av1_is_subpelmv_in_range), issue b:396169342.
+  // The assert is triggered on a 2456x2054 resolution with settings defined
+  // with the flag avif_mode_. This test upsamples a QVGA clip to the target
+  // resolution, using libyuv for the scaling.
+  virtual void BasicRateTargetingCBRAssertAvifModeTest() {
+    cfg_.rc_min_quantizer = 0;
+    cfg_.rc_max_quantizer = 63;
+    cfg_.rc_end_usage = AOM_CBR;
+    cfg_.g_lag_in_frames = 0;
+    ResizingVideoSource video(2456, 2054, 320, 240,
+                              "pixel_capture_w320h240.yuv", 100);
+    const int bitrate_array[2] = { 1000, 2000 };
+    cfg_.rc_target_bitrate = bitrate_array[GET_PARAM(4)];
+    ResetModel();
+    avif_mode_ = 1;
+    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+  }
+#endif  // CONFIG_LIBYUV
+
   virtual void BasicRateTargetingCBRSpikeTest() {
     cfg_.rc_buf_initial_sz = 500;
     cfg_.rc_buf_optimal_sz = 500;
@@ -555,6 +626,13 @@
   BasicRateTargetingCBRTest();
 }
 
+#if CONFIG_LIBYUV
+// Check basic rate targeting for CBR, special case.
+TEST_P(DatarateTestRealtime, BasicRateTargetingCBRAssertAvifMode) {
+  BasicRateTargetingCBRAssertAvifModeTest();
+}
+#endif
+
 // Check basic rate targeting for CBR. Use a longer clip,
 // and verify #encode size spikes above threshold.
 TEST_P(DatarateTestRealtime, BasicRateTargetingCBRSpike) {
diff --git a/test/datarate_test.h b/test/datarate_test.h
index 9c88ef5..a83a386 100644
--- a/test/datarate_test.h
+++ b/test/datarate_test.h
@@ -57,6 +57,7 @@
       bits_total_dynamic_[i] = 0;
       effective_datarate_dynamic_[i] = 0.0;
     }
+    avif_mode_ = 0;
   }
 
   void PreEncodeFrameHook(::libaom_test::VideoSource *video,
@@ -90,6 +91,17 @@
         encoder->Control(AV1E_SET_ENABLE_PALETTE, 1);
         encoder->Control(AV1E_SET_ENABLE_INTRABC, 0);
       }
+      if (avif_mode_) {
+        encoder->Control(AV1E_SET_COEFF_COST_UPD_FREQ, 0);
+        encoder->Control(AV1E_SET_MODE_COST_UPD_FREQ, 0);
+        encoder->Control(AV1E_SET_MV_COST_UPD_FREQ, 0);
+        encoder->Control(AV1E_SET_DELTAQ_MODE, 3);
+        encoder->Control(AV1E_SET_ENABLE_QM, 1);
+        encoder->Control(AOME_SET_SHARPNESS, 1);
+        encoder->Control(AV1E_SET_ENABLE_CHROMA_DELTAQ, 1);
+        encoder->Control(AOME_SET_CQ_LEVEL, 0);
+        encoder->Control(AV1E_SET_AQ_MODE, (aq_mode_ > 0) ? 1 : 0);
+      }
     }
 
     if (speed_change_test_) {
@@ -227,6 +239,7 @@
   double effective_datarate_dynamic_[3];
   int64_t bits_total_dynamic_[3];
   int frame_number_dynamic_[3];
+  int avif_mode_;
 };
 
 }  // namespace
diff --git a/test/test.cmake b/test/test.cmake
index b3227b8..55fcc14 100644
--- a/test/test.cmake
+++ b/test/test.cmake
@@ -501,7 +501,13 @@
     endif()
   endif()
 
-  target_link_libraries(test_libaom ${AOM_LIB_LINK_TYPE} aom aom_gtest)
+  if(CONFIG_LIBYUV)
+    # link test_libaom with yuv
+    target_link_libraries(test_libaom ${AOM_LIB_LINK_TYPE} aom aom_gtest yuv)
+  else()
+    # do not link test_libaom with yuv
+    target_link_libraries(test_libaom ${AOM_LIB_LINK_TYPE} aom aom_gtest)
+  endif()
 
   if(CONFIG_WEBM_IO)
     target_sources(test_libaom PRIVATE $<TARGET_OBJECTS:webm>)