Commit e1a1942e2d for aom
commit e1a1942e2dcb4ae5154a6ec8d9f78e4089cc3487
Author: Ihor Buhaiov <freedbrt@gmail.com>
Date: Sat Oct 10 19:42:31 2026 +0200
rtc: Skip loop filter on mostly inactive frames
At speed 10 and up, screen content skips the loop filter when more
than thresh_active_maps_skip_lf_cdef (90) percent of the blocks are
inactive. The check sits in av1_cyclic_refresh_disable_lf_cdef(), and
av1_pick_filter_level() only calls that with aq mode 3. With any other
aq mode, an active map never gets the skip.
Move the active map check into av1_pick_filter_level() so it applies to
every aq mode. The cyclic refresh checks still need aq mode 3 and run in
the same order, so aq mode 3 output does not change. Rename
av1_cyclic_refresh_disable_lf_cdef() to av1_cyclic_refresh_disable_lf(),
since it no longer has anything to do with CDEF.
To see it, encode screen content at speed 11 with aq mode 0 and a map
that marks over 90% of the blocks inactive. The loop filter now runs on
none of those frames.
Tested on two 2560x1440 screen recordings with an active map from frame
diffs (speed 11, aq 0, q 8 to 13, VBR). 94% and 80% of the frames are
over the threshold. With 4 threads the encoder uses 9.6 to 12.2% fewer
cycles on the static recording and about 4% fewer on the other one, and
the decoder 12 to 29% fewer. Size grows 0.2 to 1.0% on the static
recording and stays the same on the other one. With a fixed 5% active
map, the BD rate on the active area is +0.04% and +1.1%.
Change-Id: I4f1455beaaba69518b8aa3dd611f4f2ffae6b75e
diff --git a/av1/encoder/aq_cyclicrefresh.c b/av1/encoder/aq_cyclicrefresh.c
index d87ceae039..b76fbf895c 100644
--- a/av1/encoder/aq_cyclicrefresh.c
+++ b/av1/encoder/aq_cyclicrefresh.c
@@ -679,13 +679,9 @@ int av1_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr) {
return cr->rdmult;
}
-int av1_cyclic_refresh_disable_lf_cdef(AV1_COMP *const cpi) {
+int av1_cyclic_refresh_disable_lf(AV1_COMP *const cpi) {
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
const int qindex = cpi->common.quant_params.base_qindex;
- if (cpi->active_map.enabled &&
- cpi->rc.percent_blocks_inactive >
- cpi->sf.rt_sf.thresh_active_maps_skip_lf_cdef)
- return 1;
if (cpi->rc.frames_since_key > 30 && cr->percent_refresh > 0 &&
cr->counter_encode_maxq_scene_change > 300 / cr->percent_refresh &&
cpi->rc.frame_source_sad < 1000 &&
diff --git a/av1/encoder/aq_cyclicrefresh.h b/av1/encoder/aq_cyclicrefresh.h
index 8fc6e15eb6..7c71a69d89 100644
--- a/av1/encoder/aq_cyclicrefresh.h
+++ b/av1/encoder/aq_cyclicrefresh.h
@@ -308,7 +308,7 @@ void av1_cyclic_refresh_setup(struct AV1_COMP *const cpi);
int av1_cyclic_refresh_get_rdmult(const CYCLIC_REFRESH *cr);
-int av1_cyclic_refresh_disable_lf_cdef(struct AV1_COMP *const cpi);
+int av1_cyclic_refresh_disable_lf(struct AV1_COMP *const cpi);
static inline int cyclic_refresh_segment_id_boosted(int segment_id) {
return segment_id == CR_SEGMENT_ID_BOOST1 ||
diff --git a/av1/encoder/picklpf.c b/av1/encoder/picklpf.c
index 36ed5d6709..cc11c1423c 100644
--- a/av1/encoder/picklpf.c
+++ b/av1/encoder/picklpf.c
@@ -247,9 +247,15 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
}
if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
- cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ &&
- cpi->sf.rt_sf.skip_lf_screen)
- disable_filter_rt_screen = av1_cyclic_refresh_disable_lf_cdef(cpi);
+ cpi->sf.rt_sf.skip_lf_screen) {
+ // Skip the filter when most of the frame is inactive, for any aq mode.
+ if (cpi->active_map.enabled &&
+ cpi->rc.percent_blocks_inactive >
+ cpi->sf.rt_sf.thresh_active_maps_skip_lf_cdef)
+ disable_filter_rt_screen = 1;
+ else if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ)
+ disable_filter_rt_screen = av1_cyclic_refresh_disable_lf(cpi);
+ }
if (disable_filter_rt_screen ||
cpi->oxcf.algo_cfg.loopfilter_control == LOOPFILTER_NONE ||