Commit 6f75fec9dc for aom

commit 6f75fec9dc36361af93dd6bab9cfeea1f1c67c40
Author: Ranjit Kumar Tulabandu <ranjit.tulabandu@ittiam.com>
Date:   Wed May 13 12:29:43 2026 +0530

    Avoid unintended RD evaluation of second MV

    The function find_fractional_mv_step() exits early during second MV
    search in av1_single_motion_search(), if sub-pel ME is converging
    to same result as that of first MV. However, av1_estimate_txfm_yrd()
    was still called to choose best of these MVs in parent version
    though second MV is partially evaluated.

    In this CL, av1_estimate_txfm_yrd() is avoided for both the MVs in
    these scenarios and the CL is applicable when
    cpi->sf.mv_sf.disable_second_mv = 0. The CL is not bit-exact as
    second sub-pel MV was a result of partial evaluation and was
    winning occasionally though not intended which is avoided in this
    CL.

        Instruction Count             BD-Rate Loss(%)
    cpu  Reduction(%)     avg.psnr   ovr.psnr   ssim     vmaf    vmaf_neg
     1      0.534         -0.0015    -0.0028   0.0084   0.0115   -0.0002
     2      0.027         -0.0016     0.0007  -0.0109  -0.0277   -0.0285
     3      0.008          0.0066     0.0147   0.0244   0.0098    0.0101
     4      0.021          0.0094     0.0142   0.0145   0.0135    0.0090
     5     -0.005         -0.0108    -0.0106   0.0001   0.0097    0.0138
     6      0.039          0.0008     0.0017  -0.0001   0.0018    0.0009

    STATS_CHANGED

    Change-Id: I0759bd3e3e38668f859949e350963e7ede38c9c2

diff --git a/av1/encoder/motion_search_facade.c b/av1/encoder/motion_search_facade.c
index 0bd7d9db73..4c6d4f8b4f 100644
--- a/av1/encoder/motion_search_facade.c
+++ b/av1/encoder/motion_search_facade.c
@@ -426,23 +426,6 @@ void av1_single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x,
               { p[0].dst.buf, p[1].dst.buf, p[2].dst.buf },
               { p[0].dst.stride, p[1].dst.stride, p[2].dst.stride },
             };
-            int64_t rd = INT64_MAX;
-            if (!mv_sf->disable_second_mv) {
-              // Calculate actual rd cost.
-              mbmi->mv[0].as_mv = best_mv->as_mv;
-              av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
-                                            bsize, 0, 0);
-              av1_subtract_plane(x, bsize, 0);
-              RD_STATS this_rd_stats;
-              av1_init_rd_stats(&this_rd_stats);
-              av1_estimate_txfm_yrd(cpi, x, &this_rd_stats, INT64_MAX, bsize,
-                                    max_txsize_rect_lookup[bsize]);
-              int this_mv_rate = av1_mv_bit_cost(
-                  &best_mv->as_mv, &ref_mv, mv_costs->nmv_joint_cost,
-                  mv_costs->mv_cost_stack, MV_COST_WEIGHT);
-              rd = RDCOST(x->rdmult, this_mv_rate + this_rd_stats.rate,
-                          this_rd_stats.dist);
-            }

             MV this_best_mv;
             subpel_start_mv = get_mv_from_fullmv(&second_best_mv.as_fullmv);
@@ -453,9 +436,26 @@ void av1_single_motion_search(const AV1_COMP *const cpi, MACROBLOCK *x,
                   xd, cm, &ms_params, subpel_start_mv, NULL, &this_best_mv,
                   &dis, &sse, fractional_ms_list);

-              if (!mv_sf->disable_second_mv) {
-                // If cpi->sf.mv_sf.disable_second_mv is 0, use actual rd cost
-                // to choose the better MV.
+              // If cpi->sf.mv_sf.disable_second_mv is 0 and both MVs are valid,
+              // use actual rd cost to choose the better MV.
+              if (!mv_sf->disable_second_mv && this_var != INT32_MAX) {
+                // Calculate rd cost of first MV.
+                mbmi->mv[0].as_mv = best_mv->as_mv;
+                av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
+                                              bsize, 0, 0);
+                av1_subtract_plane(x, bsize, 0);
+                RD_STATS this_rd_stats;
+                av1_init_rd_stats(&this_rd_stats);
+                av1_estimate_txfm_yrd(cpi, x, &this_rd_stats, INT64_MAX, bsize,
+                                      max_txsize_rect_lookup[bsize]);
+                int this_mv_rate = av1_mv_bit_cost(
+                    &best_mv->as_mv, &ref_mv, mv_costs->nmv_joint_cost,
+                    mv_costs->mv_cost_stack, MV_COST_WEIGHT);
+                const int64_t rd =
+                    RDCOST(x->rdmult, this_mv_rate + this_rd_stats.rate,
+                           this_rd_stats.dist);
+
+                // Calculate rd cost of second MV.
                 mbmi->mv[0].as_mv = this_best_mv;
                 av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, &orig_dst,
                                               bsize, 0, 0);