Commit 84b0dd1652 for aom

commit 84b0dd16528d804f546530d22d8f7f44f20fa6fc
Author: Lin Zheng <linzhen@google.com>
Date:   Thu Sep 17 21:27:25 2026 +0000

    Stabilize temporal filtering and TPL motion search for HBD

    Favor zero motion vector (0,0) in stationary/near-stationary regions
    during temporal filtering motion search and TPL mode estimation.
    Disable sub-block motion estimation in temporal filtering and clamp
    filter strength to 0 for low-contrast blocks when sharpness is 3.

    Bug: 548701298
    Change-Id: Id5f1a8ed67a1b609159a15a969064419b053beab

diff --git a/av1/encoder/temporal_filter.c b/av1/encoder/temporal_filter.c
index be7ff38d2f..97be8fc2b8 100644
--- a/av1/encoder/temporal_filter.c
+++ b/av1/encoder/temporal_filter.c
@@ -382,6 +382,27 @@ static void tf_motion_search(AV1_COMP *cpi, MACROBLOCK *mb,
     *is_dc_diff_large = 50 * error < sse;
     if (src_var <= 2 * (int64_t)distortion) *is_low_cntras = 1;

+#if CONFIG_AV1_HIGHBITDEPTH
+    const MACROBLOCKD *xd = &mb->e_mbd;
+    if (xd->bd > 8 && cpi->oxcf.algo_cfg.sharpness == 3) {
+      // Favor zero motion vector (0,0) for stationary/near-stationary regions
+      // when zero-motion error is close to the best found error or sufficiently
+      // small.
+      unsigned int zero_sse;
+      unsigned int zero_error = cpi->ppi->fn_ptr[block_size].vf(
+          ref_frame->y_buffer + y_offset, y_stride,
+          frame_to_filter->y_buffer + y_offset, y_stride, &zero_sse);
+      if (zero_error <= error + (error >> 4) || (zero_error / mb_pels) < 16) {
+        best_mv.as_mv = kZeroMv;
+        block_mv = kZeroMv;
+        *ref_mv = kZeroMv;
+        error = zero_error;
+        distortion = (int)zero_error;
+        block_mse = DIVIDE_AND_ROUND(error, mb_pels);
+      }
+    }
+#endif
+
     // On 4 mid-blocks in the 64x64 tf block.
     if (allow_me_for_sub_blks) {
       // midblock_size is 32x32, which corresponds to each 32x32 block in the
@@ -1092,7 +1113,12 @@ void av1_tf_do_filtering_row(AV1_COMP *cpi, ThreadData *td, int mb_row) {
     // partition only if the difference between max and min source variance of
     // 4x4 blocks is greater than a threshold (which is derived empirically).
     bool allow_me_for_sub_blks = true;
-    if (cpi->sf.hl_sf.allow_sub_blk_me_in_tf) {
+    // In high bit-depth sharpness mode, disable sub-block motion estimation to
+    // avoid inconsistent filtering across sub-partitions and preserve
+    // sharpness.
+    if (mbd->bd > 8 && cpi->oxcf.algo_cfg.sharpness == 3) {
+      allow_me_for_sub_blks = false;
+    } else if (cpi->sf.hl_sf.allow_sub_blk_me_in_tf) {
       const int is_hbd = is_frame_high_bitdepth(frame_to_filter);
       // Initialize minimum variance to a large value and maximum variance to 0.
       double blk_4x4_var_min = DBL_MAX;
@@ -1139,7 +1165,7 @@ void av1_tf_do_filtering_row(AV1_COMP *cpi, ThreadData *td, int mb_row) {
         filter_strength = AOMMIN(filter_strength, 1);

       if (cpi->oxcf.algo_cfg.sharpness == 3 && is_low_cntras)
-        filter_strength = AOMMIN(filter_strength, 3);
+        filter_strength = AOMMIN(filter_strength, mbd->bd > 8 ? 0 : 3);

       // Perform weighted averaging.
       if (frame == filter_frame_idx) {  // Frame to be filtered.
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index a22341bd6a..34cf2bfd9b 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -854,6 +854,20 @@ static inline void mode_estimation(AV1_COMP *cpi, TplTxfmStats *tpl_txfm_stats,
           cpi, x, src_mb_buffer, ref_mb, src_stride, ref_stride, src_width,
           ref_width, bsize, center_mvs[idx].mv.as_mv, &this_mv);

+#if CONFIG_AV1_HIGHBITDEPTH
+      if (xd->bd > 8 && cpi->oxcf.algo_cfg.sharpness == 3) {
+        // Bias towards (0,0) / short motion vectors in stationary background.
+        // Require a noticeable SAD improvement before replacing (0,0) with a
+        // non-zero MV.
+        if (bestsme != UINT32_MAX && best_rfidx_mv.as_int == 0 &&
+            this_mv.as_int != 0) {
+          if (thissme + (thissme >> 4) >= bestsme) {
+            continue;
+          }
+        }
+      }
+#endif
+
       if (thissme < bestsme) {
         bestsme = thissme;
         best_rfidx_mv = this_mv;