From a4d706932c5861c896a20f50120bcef499f50ca8 Mon Sep 17 00:00:00 2001 From: Yunqing Wang Date: Thu, 20 Aug 2026 15:27:31 -0700 Subject: [PATCH] Bias towards large partition block Bias towards large partition block is enabled for high QP area in low complexity decode (LC) mode. Only enabled for >=2160p now, CTC performance (65 frames, speed 1): baseline commit: 5d628d84 Test_Set PSNR-YUV SSIM VMAF ENC_TIME DEC_TIME A1 0.04% -0.24% -0.02% 97% 96% STATS_CHANGED only for LC mode --- av2/encoder/partition_search.c | 65 ++++++++++++++++++++++++++++++++++ av2/encoder/speed_features.c | 19 ++++++++-- av2/encoder/speed_features.h | 9 +++++ 3 files changed, 91 insertions(+), 2 deletions(-) diff --git a/av2/encoder/partition_search.c b/av2/encoder/partition_search.c index ec698bcc4e..09fe661f87 100644 --- a/av2/encoder/partition_search.c +++ b/av2/encoder/partition_search.c @@ -52,6 +52,64 @@ #include "av2/encoder/partition_ml.h" #endif +static double get_partition_size_multiplier(BLOCK_SIZE bsize) { + switch (bsize) { + case BLOCK_128X128: + case BLOCK_128X64: + case BLOCK_64X128: return 1.0; + case BLOCK_64X64: + case BLOCK_64X32: + case BLOCK_32X64: return 1.005; // 0.5% penalty + case BLOCK_32X32: + case BLOCK_32X16: + case BLOCK_16X32: + case BLOCK_16X64: + case BLOCK_64X16: + case BLOCK_8X64: + case BLOCK_64X8: return 1.01; // 1% penalty + case BLOCK_16X16: + case BLOCK_16X8: + case BLOCK_8X16: + case BLOCK_8X32: + case BLOCK_32X8: + case BLOCK_4X32: + case BLOCK_32X4: return 1.02; // 2% penalty + case BLOCK_8X8: + case BLOCK_8X4: + case BLOCK_4X8: + case BLOCK_4X16: + case BLOCK_16X4: return 1.04; // 4% penalty + case BLOCK_4X4: return 1.08; // 8% penalty + default: return 1.0; + } +} + +static inline int allow_partition_size_bias(const AV2_COMP *const cpi) { + return cpi->sf.lc_sf.enable_partition_size_bias && + cpi->common.current_frame.frame_type == INTER_FRAME; +} + +static void apply_partition_size_bias(RD_STATS *rdc, BLOCK_SIZE bsize, + bool found_partition) { + if (found_partition && rdc->rdcost < INT64_MAX && rdc->rate < INT_MAX && + rdc->dist < INT64_MAX) { + const double mult = get_partition_size_multiplier(bsize); + if (mult > 1.0) { + rdc->rate = (rdc->rate * mult > (double)INT_MAX) + ? INT_MAX + : (int)(rdc->rate * mult); + // Since (double)INT64_MAX rounds up to 2^63, any double greater than OR + // EQUAL to it is an overflow. + rdc->dist = (rdc->dist * mult >= (double)INT64_MAX) + ? INT64_MAX + : (int64_t)(rdc->dist * mult); + rdc->rdcost = (rdc->rdcost * mult >= (double)INT64_MAX) + ? INT64_MAX + : (int64_t)(rdc->rdcost * mult); + } + } +} + static void update_partition_cdfs_and_counts(MACROBLOCKD *xd, int blk_col, int blk_row, TX_SIZE max_tx_size, int allow_update_cdf, @@ -5788,7 +5846,11 @@ bool av2_rd_pick_partition( none_rd, &part_none_rd, &level_banks, ptree_luma, multi_pass_mode); } + if (is_intra_child_of_mixed_region(pc_tree) && xd->tree_type == CHROMA_PART) { + if (allow_partition_size_bias(cpi)) + apply_partition_size_bias(&best_rdc, bsize, + part_search_state.found_best_partition); *rd_cost = best_rdc; x->rdmult = orig_rdmult; return part_search_state.found_best_partition; @@ -5952,6 +6014,9 @@ bool av2_rd_pick_partition( } // Store the final rd cost + if (allow_partition_size_bias(cpi)) + apply_partition_size_bias(&best_rdc, bsize, + part_search_state.found_best_partition); *rd_cost = best_rdc; xd->ref_mv_bank = level_banks.best_level_bank; xd->warp_param_bank = level_banks.best_level_warp_bank; diff --git a/av2/encoder/speed_features.c b/av2/encoder/speed_features.c index 60cb853853..14a11b5a63 100644 --- a/av2/encoder/speed_features.c +++ b/av2/encoder/speed_features.c @@ -710,7 +710,9 @@ static void set_good_speed_features_framesize_independent( // Define frame size independent speed features for low complexity decoding // mode. static void set_good_speed_features_lc_dec_framesize_independent( - AV2_COMP *cpi) { + AV2_COMP *cpi, SPEED_FEATURES *const sf) { + const AV2_COMMON *const cm = &cpi->common; + // Standard low-complexity level cpi->oxcf.tool_cfg.enable_mv_traj = 0; cpi->oxcf.tool_cfg.enable_gdf = 0; @@ -718,6 +720,14 @@ static void set_good_speed_features_lc_dec_framesize_independent( cpi->oxcf.tool_cfg.enable_tip_refinemv = 0; cpi->oxcf.tool_cfg.reduced_ref_frame_mvs_mode = 1; + // TODO(yunqing): extend this SF to other resolutions. + const int is_2k_or_larger = AVMMIN(cm->width, cm->height) >= 2160; + const int qindex_offset = MAXQ_OFFSET * (cm->seq_params.bit_depth - 8); + const int qindex_thresh = 112 + qindex_offset; + sf->lc_sf.enable_partition_size_bias = + (is_2k_or_larger && cm->quant_params.base_qindex >= qindex_thresh) ? 1 + : 0; + // Aggressive low-complexity level if (cpi->oxcf.enable_low_complexity_decode > 1) { cpi->oxcf.tool_cfg.enable_opfl_refine = 0; @@ -1061,6 +1071,10 @@ static void av2_disable_ml_based_partition_sf( } } +static AVM_INLINE void init_lc_sf(LC_DEC_SPEED_FEATURES *lc_sf) { + lc_sf->enable_partition_size_bias = 0; +} + static AVM_INLINE void set_erp_speed_features_framesize_dependent( AV2_COMP *cpi) { SPEED_FEATURES *const sf = &cpi->sf; @@ -1273,6 +1287,7 @@ void av2_set_speed_features_framesize_independent(AV2_COMP *cpi, int speed) { init_winner_mode_sf(&sf->winner_mode_sf); init_lpf_sf(&sf->lpf_sf); init_flexmv_sf(&sf->flexmv_sf); + init_lc_sf(&sf->lc_sf); if (oxcf->mode == GOOD) { set_good_speed_features_framesize_independent(cpi, sf, speed); @@ -1282,7 +1297,7 @@ void av2_set_speed_features_framesize_independent(AV2_COMP *cpi, int speed) { if (oxcf->mode == GOOD && cpi->oxcf.enable_low_complexity_decode) { // TODO (yunqingwang): LC speed features are added below. - set_good_speed_features_lc_dec_framesize_independent(cpi); + set_good_speed_features_lc_dec_framesize_independent(cpi, sf); // Adjust sequence flags for LC decode mode. if (!cpi->seq_params_locked) { diff --git a/av2/encoder/speed_features.h b/av2/encoder/speed_features.h index 176a0835fb..239594af2e 100644 --- a/av2/encoder/speed_features.h +++ b/av2/encoder/speed_features.h @@ -1099,6 +1099,11 @@ typedef struct REALTIME_SPEED_FEATURES { bool use_only_dc_intra_interframe; } REALTIME_SPEED_FEATURES; +typedef struct LC_DEC_SPEED_FEATURES { + // Bias towards large partitions. + int enable_partition_size_bias; +} LC_DEC_SPEED_FEATURES; + typedef struct FLEXMV_PRECISION_SPEED_FEATURES { // Do not search 8-pel precision int do_not_search_8_pel_precision; @@ -1204,6 +1209,10 @@ typedef struct SPEED_FEATURES { */ REALTIME_SPEED_FEATURES rt_sf; + /*! + * Low complexity decode mode speed features: + */ + LC_DEC_SPEED_FEATURES lc_sf; } SPEED_FEATURES; /*!\cond */