Commit 415a98a147 for aom

commit 415a98a147b854e71b1f73604e0ab62a80d769f3
Author: Ihor Buhaiov <freedbrt@gmail.com>
Date:   Wed Oct 7 15:35:04 2026 +0200

    rtc: Fix selective CDF when cyclic refresh is off

    selective_disable_cdf_rtc() keeps CDF updates on while
    counter_encode_maxq_scene_change is below 30. The counter only moves
    on frames that apply cyclic refresh. If cyclic refresh stays off, the
    counter never reaches 30 and CDF updates run on every frame. An active
    map with most blocks inactive does this, since percent_refresh scales
    down to 0. In the default build every CDF update also rebuilds the
    coefficient, mode and MV cost tables per superblock, so speed 11 camera
    content gets slower with an active map than without one.

    When an active map is set and cyclic refresh is off on the frame,
    check frames_since_scene_change instead. Streams without an active
    map don't change.

    Speed 11, camera content, aq 3, CBR, 1 thread, 300 frames, active map
    with 3% of the blocks active. Encoder instructions, default build:

      niklas_1280_720_30 at 1000 kbps: 22.7G before, 9.6G after
      niklas_640_480_30 at 500 kbps: 8.3G before, 3.6G after
      hantro_collage_w352h288 at 300 kbps: 3.7G before, 1.9G after

    The realtime only build gains 3% to 5%, since it doesn't update cost
    tables per superblock. BD rate on the active area over 4 rates is 1.2%
    to 2.5% worse. Without an active map, selective_cdf_update already
    costs 0.9% to 1.8% against CDF updates on every frame, so this is the
    same trade.

    Change-Id: I1d833fcf44aaaa5e5ac715d02b36fdc01a2d6a22

diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index cd38437aa2..731ec35b98 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -4063,14 +4063,20 @@ static inline int selective_disable_cdf_rtc(const AV1_COMP *cpi) {
   // For single layer.
   if (cpi->svc.number_spatial_layers == 1 &&
       cpi->svc.number_temporal_layers == 1) {
+    const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
     // Don't disable on intra_only, scene change (high_source_sad = 1),
     // or resized frame. To avoid quality loss force enable at
     // for ~30 frames after key or scene/slide change, and
     // after 8 frames since last update if frame_source_sad > 0.
+    // The cyclic refresh counter only advances on frames that apply
+    // cyclic refresh. An active map can keep cyclic refresh off for the
+    // whole stream, so use frames_since_scene_change then.
     if (frame_is_intra_only(cm) || is_frame_resize_pending(cpi) ||
         rc->high_source_sad || rc->frames_since_key < 30 ||
         (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ &&
-         cpi->cyclic_refresh->counter_encode_maxq_scene_change < 30) ||
+         (cr->apply_cyclic_refresh || !cpi->active_map.enabled
+              ? cr->counter_encode_maxq_scene_change
+              : rc->frames_since_scene_change) < 30) ||
         (cpi->frames_since_last_update > 8 && cpi->rc.frame_source_sad > 0))
       return 0;
     else