Commit 3712e6af6f for aom

commit 3712e6af6f142785a2059e2fc03d73ac76c62f80
Author: Mudassir Galaganath <mudassir.galaganath@ittiam.com>
Date:   Thu Jun 4 14:24:46 2026 +0530

    Fix mode_ref_delta_update signaling when delta is disabled

    When mode_ref_delta_enabled is false (0), the encoder was
    unconditionally writing the mode_ref_delta_update flag to the
    bitstream. However, standard AV1 decoders (following Section
    5.9.11 of the specification) only parse the update flag and
    delta lists if loop_filter_delta_enabled is true.

    This patch fixes the issue by nesting the delta update signaling
    inside the mode_ref_delta_enabled check in encode_loopfilter(),
    matching the parsing logic of the decoder. To validate this,
    a codec control API (AV1E_SET_MODE_REF_DELTA_ENABLED) is added to
    the encoder and 'LFControlModeRefDeltaEndToEndTestTest' unit test is
    added in loopfilter_control_test.cc using the exisiting framework.

    Change-Id: I3fa91f6c6d7eb818f3ea164fb950690aefa37891

diff --git a/aom/aomcx.h b/aom/aomcx.h
index 0e33a398c7..b1a4bed8b7 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -1647,6 +1647,15 @@ enum aome_enc_control_id {
    */
   AOME_SET_VALIDATE_HBD_INPUT = 175,

+  /*!\brief Codec control function to toggle loopfilter mode_ref_delta_enabled.
+   *
+   * - 0 = disable
+   * - 1 = enable (default)
+   *
+   * \note This is only used in loopfilter control unit test.
+   */
+  AV1E_SET_MODE_REF_DELTA_ENABLED = 176,
+
   // Any new encoder control IDs should be added above.
   // Maximum allowed encoder control ID is 229.
   // No encoder control ID should be added below.
@@ -2433,6 +2442,9 @@ AOM_CTRL_USE_TYPE(AV1E_SET_EXTERNAL_RATE_CONTROL, aom_rc_funcs_t *)
 AOM_CTRL_USE_TYPE(AV1E_GET_GOP_INFO, aom_gop_info_t *)
 #define AOM_CTRL_AV1E_GET_GOP_INFO

+AOM_CTRL_USE_TYPE(AV1E_SET_MODE_REF_DELTA_ENABLED, int)
+#define AOM_CTRL_AV1E_SET_MODE_REF_DELTA_ENABLED
+
 /*!\endcond */
 /*! @} - end defgroup aom_encoder */
 #ifdef __cplusplus
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 9e921bd240..ba59e9e21d 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -227,6 +227,7 @@ struct av1_extracfg {
   // Indicates if the application of post-processing filters should be skipped
   // on reconstructed frame.
   unsigned int skip_postproc_filtering;
+  int mode_ref_delta_enabled;
   // the name of the second pass output file when passes > 2
   const char *two_pass_output;
   const char *second_pass_log;
@@ -397,6 +398,7 @@ static const struct av1_extracfg default_extra_cfg = {
   -1,              // fwd_kf_dist
   LOOPFILTER_ALL,  // loopfilter_control
   0,               // skip_postproc_filtering
+  1,               // mode_ref_delta_enabled
   NULL,            // two_pass_output
   NULL,            // second_pass_log
   0,               // auto_intra_tools_off
@@ -555,6 +557,7 @@ static const struct av1_extracfg default_extra_cfg = {
   -1,              // fwd_kf_dist
   LOOPFILTER_ALL,  // loopfilter_control
   0,               // skip_postproc_filtering
+  1,               // mode_ref_delta_enabled
   NULL,            // two_pass_output
   NULL,            // second_pass_log
   0,               // auto_intra_tools_off
@@ -946,6 +949,7 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
   RANGE_CHECK_HI(extra_cfg, deltaq_strength, 1000);
   RANGE_CHECK_HI(extra_cfg, loopfilter_control, 3);
   RANGE_CHECK_BOOL(extra_cfg, skip_postproc_filtering);
+  RANGE_CHECK_BOOL(extra_cfg, mode_ref_delta_enabled);
   RANGE_CHECK_HI(extra_cfg, enable_cdef, 3);
   RANGE_CHECK_BOOL(extra_cfg, auto_intra_tools_off);
   RANGE_CHECK_BOOL(extra_cfg, strict_level_conformance);
@@ -1366,6 +1370,7 @@ static void set_encoder_config(AV1EncoderConfig *oxcf,
       resize_cfg->resize_mode ? 0 : extra_cfg->enable_tpl_model;
   algo_cfg->loopfilter_control = extra_cfg->loopfilter_control;
   algo_cfg->skip_postproc_filtering = extra_cfg->skip_postproc_filtering;
+  algo_cfg->mode_ref_delta_enabled = extra_cfg->mode_ref_delta_enabled;
   algo_cfg->screen_detection_mode = extra_cfg->screen_detection_mode;

   // Set two-pass stats configuration.
@@ -2838,6 +2843,14 @@ static aom_codec_err_t ctrl_set_skip_postproc_filtering(
   return update_extra_cfg(ctx, &extra_cfg);
 }

+static aom_codec_err_t ctrl_set_mode_ref_delta_enabled(
+    aom_codec_alg_priv_t *ctx, va_list args) {
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.mode_ref_delta_enabled =
+      CAST(AV1E_SET_MODE_REF_DELTA_ENABLED, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+}
+
 static aom_codec_err_t ctrl_set_rtc_external_rc(aom_codec_alg_priv_t *ctx,
                                                 va_list args) {
   ctx->ppi->cpi->rc.rtc_external_ratectrl =
@@ -5086,6 +5099,7 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
   { AV1E_SET_ENABLE_TX_SIZE_SEARCH, ctrl_set_enable_tx_size_search },
   { AV1E_SET_LOOPFILTER_CONTROL, ctrl_set_loopfilter_control },
   { AV1E_SET_SKIP_POSTPROC_FILTERING, ctrl_set_skip_postproc_filtering },
+  { AV1E_SET_MODE_REF_DELTA_ENABLED, ctrl_set_mode_ref_delta_enabled },
   { AV1E_SET_AUTO_INTRA_TOOLS_OFF, ctrl_set_auto_intra_tools_off },
   { AV1E_SET_RTC_EXTERNAL_RC, ctrl_set_rtc_external_rc },
   { AV1E_SET_QUANTIZER_ONE_PASS, ctrl_set_quantizer_one_pass },
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index 558ac361e8..53ca4adac1 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -2047,35 +2047,39 @@ static inline void encode_loopfilter(AV1_COMMON *cm,

   aom_wb_write_bit(wb, lf->mode_ref_delta_enabled);

-  // Write out loop filter deltas applied at the MB level based on mode or
-  // ref frame (if they are enabled), only if there is information to write.
-  int meaningful = is_mode_ref_delta_meaningful(cm);
-  aom_wb_write_bit(wb, meaningful);
-  if (!meaningful) {
-    return;
-  }
+  if (lf->mode_ref_delta_enabled) {
+    // Check if the loop filter deltas have changed from the previous frame.
+    // If mode_ref_delta_update_decision is 1, signal the update and write out
+    // the actual delta values. Otherwise, signal 0 and skip writing delta
+    // values.
+    int mode_ref_delta_update = is_mode_ref_delta_meaningful(cm);
+    aom_wb_write_bit(wb, mode_ref_delta_update);
+    if (!mode_ref_delta_update) {
+      return;
+    }

-  const RefCntBuffer *buf = get_primary_ref_frame_buf(cm);
-  int8_t last_ref_deltas[REF_FRAMES];
-  int8_t last_mode_deltas[MAX_MODE_LF_DELTAS];
-  if (buf == NULL) {
-    av1_set_default_ref_deltas(last_ref_deltas);
-    av1_set_default_mode_deltas(last_mode_deltas);
-  } else {
-    memcpy(last_ref_deltas, buf->ref_deltas, REF_FRAMES);
-    memcpy(last_mode_deltas, buf->mode_deltas, MAX_MODE_LF_DELTAS);
-  }
-  for (int i = 0; i < REF_FRAMES; i++) {
-    const int delta = lf->ref_deltas[i];
-    const int changed = delta != last_ref_deltas[i];
-    aom_wb_write_bit(wb, changed);
-    if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6);
-  }
-  for (int i = 0; i < MAX_MODE_LF_DELTAS; i++) {
-    const int delta = lf->mode_deltas[i];
-    const int changed = delta != last_mode_deltas[i];
-    aom_wb_write_bit(wb, changed);
-    if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6);
+    const RefCntBuffer *buf = get_primary_ref_frame_buf(cm);
+    int8_t last_ref_deltas[REF_FRAMES];
+    int8_t last_mode_deltas[MAX_MODE_LF_DELTAS];
+    if (buf == NULL) {
+      av1_set_default_ref_deltas(last_ref_deltas);
+      av1_set_default_mode_deltas(last_mode_deltas);
+    } else {
+      memcpy(last_ref_deltas, buf->ref_deltas, REF_FRAMES);
+      memcpy(last_mode_deltas, buf->mode_deltas, MAX_MODE_LF_DELTAS);
+    }
+    for (int i = 0; i < REF_FRAMES; i++) {
+      const int delta = lf->ref_deltas[i];
+      const int changed = delta != last_ref_deltas[i];
+      aom_wb_write_bit(wb, changed);
+      if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6);
+    }
+    for (int i = 0; i < MAX_MODE_LF_DELTAS; i++) {
+      const int delta = lf->mode_deltas[i];
+      const int changed = delta != last_mode_deltas[i];
+      aom_wb_write_bit(wb, changed);
+      if (changed) aom_wb_write_inv_signed_literal(wb, delta, 6);
+    }
   }
 }

diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 8170c1d857..1ccff9e631 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -2384,6 +2384,7 @@ static inline void encode_frame_internal(AV1_COMP *cpi) {
     memcpy(cm->lf.ref_deltas, cm->prev_frame->ref_deltas, REF_FRAMES);
     memcpy(cm->lf.mode_deltas, cm->prev_frame->mode_deltas, MAX_MODE_LF_DELTAS);
   }
+  cm->lf.mode_ref_delta_enabled = oxcf->algo_cfg.mode_ref_delta_enabled;
   memcpy(cm->cur_frame->ref_deltas, cm->lf.ref_deltas, REF_FRAMES);
   memcpy(cm->cur_frame->mode_deltas, cm->lf.mode_deltas, MAX_MODE_LF_DELTAS);

diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index ab858ea9ba..601a111d35 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -886,6 +886,12 @@ typedef struct {
    */
   bool skip_postproc_filtering;

+  /*!
+   * Indicates if mode and reference frame delta should be enabled during
+   * loopfiltering.
+   */
+  int mode_ref_delta_enabled;
+
   /*!
    * Controls screen content detection mode
    */
diff --git a/test/loopfilter_control_test.cc b/test/loopfilter_control_test.cc
index f498559858..7a19a7fbb1 100644
--- a/test/loopfilter_control_test.cc
+++ b/test/loopfilter_control_test.cc
@@ -67,17 +67,18 @@ const TestVideoParam kTestVectors[] = {
   { "niklas_1280_720_30.y4m", 8, AOM_IMG_FMT_I420, AOM_BITS_8, 0 },
 };

-// Params: test video, lf_control, aq mode, threads, tile columns.
+// Params: test video, lf_control, aq mode, threads, tile columns,
+// mode_ref_delta_enabled.
 class LFControlEndToEndTest
-    : public ::libaom_test::CodecTestWith5Params<TestVideoParam, int,
-                                                 unsigned int, int, int>,
+    : public ::libaom_test::CodecTestWith6Params<TestVideoParam, int,
+                                                 unsigned int, int, int, int>,
       public ::libaom_test::EncoderTest {
  protected:
   LFControlEndToEndTest()
       : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(1)),
         lf_control_(GET_PARAM(2)), psnr_(0.0), nframes_(0),
         aq_mode_(GET_PARAM(3)), threads_(GET_PARAM(4)),
-        tile_columns_(GET_PARAM(5)) {}
+        tile_columns_(GET_PARAM(5)), mode_ref_delta_enabled_(GET_PARAM(6)) {}

   ~LFControlEndToEndTest() override = default;

@@ -123,6 +124,8 @@ class LFControlEndToEndTest
       encoder->Control(AV1E_SET_MV_COST_UPD_FREQ, 2);
       encoder->Control(AV1E_SET_DV_COST_UPD_FREQ, 2);
       encoder->Control(AV1E_SET_LOOPFILTER_CONTROL, lf_control_);
+      encoder->Control(AV1E_SET_MODE_REF_DELTA_ENABLED,
+                       mode_ref_delta_enabled_);
     }
   }

@@ -164,14 +167,19 @@ class LFControlEndToEndTest
   unsigned int aq_mode_;
   int threads_;
   int tile_columns_;
+  int mode_ref_delta_enabled_;
 };

 class LFControlEndToEndTestThreaded : public LFControlEndToEndTest {};

+class LFControlModeRefDeltaEndToEndTestTest : public LFControlEndToEndTest {};
+
 TEST_P(LFControlEndToEndTest, EndtoEndPSNRTest) { DoTest(); }

 TEST_P(LFControlEndToEndTestThreaded, EndtoEndPSNRTest) { DoTest(); }

+TEST_P(LFControlModeRefDeltaEndToEndTestTest, EndtoEndPSNRTest) { DoTest(); }
+
 TEST(LFControlGetterTest, NullptrInput) {
   int *lf_level = nullptr;
   aom_codec_ctx_t encoder;
@@ -188,11 +196,20 @@ AV1_INSTANTIATE_TEST_SUITE(LFControlEndToEndTest,
                            ::testing::ValuesIn(kTestVectors),
                            ::testing::Range(0, 4),
                            ::testing::Values<unsigned int>(0, 3),
-                           ::testing::Values(1), ::testing::Values(1));
+                           ::testing::Values(1), ::testing::Values(1),
+                           ::testing::Values(1));

 AV1_INSTANTIATE_TEST_SUITE(LFControlEndToEndTestThreaded,
                            ::testing::ValuesIn(kTestVectors),
                            ::testing::Range(0, 4),
                            ::testing::Values<unsigned int>(0, 3),
-                           ::testing::Range(2, 5), ::testing::Range(2, 5));
+                           ::testing::Range(2, 5), ::testing::Range(2, 5),
+                           ::testing::Values(1));
+
+AV1_INSTANTIATE_TEST_SUITE(LFControlModeRefDeltaEndToEndTestTest,
+                           ::testing::Values(kTestVectors[0]),
+                           ::testing::Range(0, 4),
+                           ::testing::Values<unsigned int>(0, 3),
+                           ::testing::Values(1), ::testing::Values(1),
+                           ::testing::Values(0));
 }  // namespace