Commit 77f51c64f6 for aom
commit 77f51c64f67322cc88b8852be80b529c51b95980
Author: Diksha Singh <diksha.singh@ittiam.com>
Date: Thu Mar 12 10:59:49 2026 +0530
Extend sf 'prune_single_ref' to speed 3, 4
The speed feature 'prune_single_ref' is extended to speed 3, 4
conservatively by disallowing pruning of certain reference frames
based on the relative distance to the current frame and base_qindex.
Encoder performance results averaged over all resolutions are as follows:
Instruction Count BD-Rate Loss(%)
cpu Reduction(%) avg.psnr ovr.psnr ssim vmaf vmaf_neg
3 2.33 0.0112 -0.0007 -0.0130 -0.0120 -0.0216
4 1.57 0.0047 0.0079 -0.0047 0.0309 0.0014
STATS_CHAGNED for speed=3,4
Change-Id: I1aceac2f0107c88b16cd0df9713fa446b57170d3
diff --git a/av1/common/av1_common_int.h b/av1/common/av1_common_int.h
index 715fe2ced7..e083c2b0d5 100644
--- a/av1/common/av1_common_int.h
+++ b/av1/common/av1_common_int.h
@@ -139,6 +139,7 @@ typedef struct RefCntBuffer {
unsigned int ref_display_order_hint[INTER_REFS_PER_FRAME];
// Frame's level within the hierarchical structure.
unsigned int pyramid_level;
+ int base_qindex;
MV_REF *mvs;
uint8_t *seg_map;
struct segmentation seg;
diff --git a/av1/common/mvref_common.c b/av1/common/mvref_common.c
index fdb2c8d870..3f86c1ddb6 100644
--- a/av1/common/mvref_common.c
+++ b/av1/common/mvref_common.c
@@ -844,6 +844,7 @@ void av1_setup_frame_buf_refs(AV1_COMMON *cm) {
cm->cur_frame->order_hint = cm->current_frame.order_hint;
cm->cur_frame->display_order_hint = cm->current_frame.display_order_hint;
cm->cur_frame->pyramid_level = cm->current_frame.pyramid_level;
+ cm->cur_frame->base_qindex = cm->quant_params.base_qindex;
cm->cur_frame->filter_level[0] = -1;
cm->cur_frame->filter_level[1] = -1;
MV_REFERENCE_FRAME ref_frame;
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 6f3bbc21aa..76c73aca98 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -1696,6 +1696,71 @@ static inline void set_default_interp_skip_flags(
: INTERP_SKIP_LUMA_SKIP_CHROMA;
}
+/*!\cond */
+typedef struct {
+ // Scoring function for usefulness of references (the lower score, the more
+ // useful)
+ int score;
+ // Index in the reference buffer
+ int index;
+} RefScoreData;
+/*!\endcond */
+
+// Comparison function to sort reference frames in ascending score order.
+static int compare_score_data_asc(const void *a, const void *b) {
+ const RefScoreData *ra = (const RefScoreData *)a;
+ const RefScoreData *rb = (const RefScoreData *)b;
+
+ const int score_diff = ra->score - rb->score;
+ if (score_diff != 0) return score_diff;
+
+ return ra->index - rb->index;
+}
+
+// Determines whether a given reference frame is "good" based on temporal
+// distance and base_qindex. The "good" reference frames are not allowed to be
+// pruned by the speed feature "prune_single_ref" frame at block level.
+static inline void setup_keep_single_ref_frame_mask(AV1_COMP *cpi) {
+ const int prune_single_ref = cpi->sf.inter_sf.prune_single_ref;
+ const AV1_COMMON *const cm = &cpi->common;
+
+ if (prune_single_ref != 1 || frame_is_intra_only(cm)) {
+ cpi->keep_single_ref_frame_mask =
+ (prune_single_ref == 0) ? ((1 << REF_FRAMES) - 1) : 0;
+ return;
+ }
+ RefScoreData ref_score_data[INTER_REFS_PER_FRAME];
+ for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+ ref_score_data[i].score = INT_MAX;
+ ref_score_data[i].index = i;
+ }
+
+ // Calculate score for each reference frame based on relative distance to
+ // the current frame and its base_qindex. A lower score means that the
+ // reference is potentially more useful.
+ for (MV_REFERENCE_FRAME ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME;
+ ++ref_frame) {
+ if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
+ const RefFrameDistanceInfo *const ref_frame_dist_info =
+ &cpi->ref_frame_dist_info;
+ const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
+ ref_score_data[ref_frame - LAST_FRAME].score =
+ abs(ref_frame_dist_info->ref_relative_dist[ref_frame - LAST_FRAME]) +
+ buf->base_qindex;
+ }
+ }
+
+ qsort(ref_score_data, INTER_REFS_PER_FRAME, sizeof(ref_score_data[0]),
+ compare_score_data_asc);
+
+ cpi->keep_single_ref_frame_mask = 0;
+ const int num_frames_to_keep = 3;
+ for (int i = 0; i < num_frames_to_keep; ++i) {
+ const int idx = ref_score_data[i].index;
+ cpi->keep_single_ref_frame_mask |= 1 << idx;
+ }
+}
+
static inline void setup_prune_ref_frame_mask(AV1_COMP *cpi) {
if ((!cpi->oxcf.ref_frm_cfg.enable_onesided_comp ||
cpi->sf.inter_sf.disable_onesided_comp) &&
@@ -2263,6 +2328,9 @@ static inline void encode_frame_internal(AV1_COMP *cpi) {
cpi->prune_ref_frame_mask = 0;
// Figure out which ref frames can be skipped at frame level.
setup_prune_ref_frame_mask(cpi);
+ // Disable certain reference frame pruning based on temporal distance and
+ // quality of that reference frame.
+ setup_keep_single_ref_frame_mask(cpi);
x->txfm_search_info.txb_split_count = 0;
#if CONFIG_SPEED_STATS
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 28c07c0659..f708c7e33a 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -3339,6 +3339,13 @@ typedef struct AV1_COMP {
*/
int prune_ref_frame_mask;
+ /*!
+ * Mark the reference frames which are important (based on the temporal
+ * distance and quality) to prevent pruning the reference frame at block
+ * level.
+ */
+ int keep_single_ref_frame_mask;
+
/*!
* Loop Restoration context.
*/
diff --git a/av1/encoder/rdopt.c b/av1/encoder/rdopt.c
index dde46f697f..01e4bf7227 100644
--- a/av1/encoder/rdopt.c
+++ b/av1/encoder/rdopt.c
@@ -4180,8 +4180,8 @@ static inline void init_mode_skip_mask(mode_skip_mask_t *mask,
// Prune reference frames which are not the closest to the current
// frame and with large pred_mv_sad.
if (inter_sf->prune_single_ref) {
- assert(inter_sf->prune_single_ref > 0 && inter_sf->prune_single_ref < 3);
- const double prune_threshes[2] = { 1.20, 1.05 };
+ assert(inter_sf->prune_single_ref > 0 && inter_sf->prune_single_ref < 4);
+ const double prune_threshes[3] = { 1.20, 1.20, 1.05 };
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
const RefFrameDistanceInfo *const ref_frame_dist_info =
@@ -4189,8 +4189,10 @@ static inline void init_mode_skip_mask(mode_skip_mask_t *mask,
const int is_closest_ref =
(ref_frame == ref_frame_dist_info->nearest_past_ref) ||
(ref_frame == ref_frame_dist_info->nearest_future_ref);
+ const int ref_idx = ref_frame - LAST_FRAME;
- if (!is_closest_ref) {
+ if (!(cpi->keep_single_ref_frame_mask & (1 << ref_idx) ||
+ is_closest_ref)) {
const int dir =
(ref_frame_dist_info->ref_relative_dist[ref_frame - LAST_FRAME] < 0)
? 0
diff --git a/av1/encoder/speed_features.c b/av1/encoder/speed_features.c
index 9537f0a2f8..876ed33e29 100644
--- a/av1/encoder/speed_features.c
+++ b/av1/encoder/speed_features.c
@@ -1285,6 +1285,7 @@ static void set_good_speed_features_framesize_independent(
set_txfm_rd_gate_level(sf->inter_sf.txfm_rd_gate_level,
boosted ? 0 : (is_boosted_arf2_bwd_type ? 1 : 2));
sf->inter_sf.inter_mode_txfm_breakout = boosted ? 0 : 2;
+ sf->inter_sf.prune_single_ref = 1;
sf->interp_sf.adaptive_interp_filter_search = 2;
@@ -1401,7 +1402,7 @@ static void set_good_speed_features_framesize_independent(
sf->mv_sf.warp_search_method = WARP_SEARCH_DIAMOND;
sf->inter_sf.prune_inter_modes_if_skippable = 1;
- sf->inter_sf.prune_single_ref = is_boosted_arf2_bwd_type ? 0 : 1;
+ sf->inter_sf.prune_single_ref = is_boosted_arf2_bwd_type ? 0 : 2;
sf->inter_sf.txfm_rd_gate_level[TX_SEARCH_DEFAULT] = boosted ? 0 : 4;
sf->inter_sf.txfm_rd_gate_level[TX_SEARCH_COMP_TYPE_MODE] = boosted ? 0 : 5;
sf->inter_sf.enable_fast_compound_mode_search = 2;
@@ -1439,7 +1440,7 @@ static void set_good_speed_features_framesize_independent(
sf->inter_sf.prune_inter_modes_based_on_tpl = boosted ? 1 : 4;
sf->inter_sf.selective_ref_frame = 6;
- sf->inter_sf.prune_single_ref = is_boosted_arf2_bwd_type ? 0 : 2;
+ sf->inter_sf.prune_single_ref = is_boosted_arf2_bwd_type ? 0 : 3;
sf->inter_sf.prune_ext_comp_using_neighbors = 3;
sf->intra_sf.chroma_intra_pruning_with_hog = 4;
diff --git a/av1/encoder/speed_features.h b/av1/encoder/speed_features.h
index 7b87f3cd67..3d81c3b4f2 100644
--- a/av1/encoder/speed_features.h
+++ b/av1/encoder/speed_features.h
@@ -1023,7 +1023,7 @@ typedef struct INTER_MODE_SPEED_FEATURES {
int alt_ref_search_fp;
// Prune reference frames for single prediction modes based on temporal
- // distance and pred MV SAD. Feasible values are 0, 1, 2. The feature is
+ // distance and pred MV SAD. Feasible values are 0, 1, 2, 3. The feature is
// disabled for 0. An increasing value indicates more aggressive pruning
// threshold.
int prune_single_ref;