Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions av2/encoder/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -1324,6 +1324,13 @@ typedef struct {
} CoeffCosts;

/*!\cond */
typedef enum {
kZeroSad = 0,
kVeryLowSad = 1,
kLowSad = 2,
kMedSad = 3,
kHighSad = 4
} SOURCE_SAD;
#define SINGLE_REF_MODES ((REF_FRAMES - 1) * 4)
/*!\endcond */
struct inter_modes_info;
Expand Down Expand Up @@ -1659,6 +1666,10 @@ typedef struct macroblock {
/**@{*/
//! Variance of the source frame.
unsigned int source_variance;
//! Superblock source SAD.
unsigned int source_sad;
//! Superblock source SAD level.
SOURCE_SAD source_sad_level;
//! SSE of the current predictor.
unsigned int pred_sse[SINGLE_REF_FRAMES];
/*! Simple motion search buffers. */
Expand Down
59 changes: 58 additions & 1 deletion av2/encoder/encodeframe.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,53 @@ static BLOCK_SIZE get_rd_var_based_fixed_partition(AV2_COMP *cpi, MACROBLOCK *x,
return BLOCK_8X8;
}

static unsigned int get_sb_source_sad(const AV2_COMP *cpi, const MACROBLOCK *x,
int mi_row, int mi_col) {
if (cpi->last_source == NULL || cpi->source == NULL) return UINT_MAX;
if (frame_is_intra_only(&cpi->common)) return UINT_MAX;
if (cpi->last_source->y_width != cpi->source->y_width ||
cpi->last_source->y_height != cpi->source->y_height)
return UINT_MAX;

const BLOCK_SIZE sb_size = cpi->common.seq_params.sb_size;
const int block_width = mi_size_wide[sb_size];
const int block_height = mi_size_high[sb_size];
// Avoid border superblocks as sdf reads extended border padding.
if (mi_row + block_height > cpi->common.mi_params.mi_rows ||
mi_col + block_width > cpi->common.mi_params.mi_cols)
return UINT_MAX;

const uint16_t *src_y = x->plane[AVM_PLANE_Y].src.buf;
const int src_stride = x->plane[AVM_PLANE_Y].src.stride;
const int last_src_offset =
(mi_row * MI_SIZE) * cpi->last_source->y_stride + (mi_col * MI_SIZE);
const uint16_t *last_src_y = cpi->last_source->y_buffer + last_src_offset;
const int last_src_stride = cpi->last_source->y_stride;

return cpi->fn_ptr[sb_size].sdf(src_y, src_stride, last_src_y,
last_src_stride);
}

static SOURCE_SAD get_source_sad_level(unsigned int sb_source_sad,
BLOCK_SIZE sb_size, int bit_depth) {
if (sb_source_sad == UINT_MAX) return kMedSad;
if (sb_source_sad == 0) return kZeroSad;

const int num_64x64 = (sb_size == BLOCK_256X256) ? 16
: (sb_size == BLOCK_128X128) ? 4
: 1;
unsigned int avg_64x64_sad = (sb_source_sad + (num_64x64 >> 1)) / num_64x64;

if (bit_depth > 8) {
avg_64x64_sad >>= (bit_depth - 8);
}

if (avg_64x64_sad < 8000) return kVeryLowSad;
if (avg_64x64_sad < 25000) return kLowSad;
if (avg_64x64_sad > 50000) return kHighSad;
return kMedSad;
}

void av2_setup_src_planes(MACROBLOCK *x, const YV12_BUFFER_CONFIG *src,
int mi_row, int mi_col, const int num_planes,
const CHROMA_REF_INFO *chroma_ref_info) {
Expand Down Expand Up @@ -840,7 +887,15 @@ static AVM_INLINE void encode_rd_sb(AV2_COMP *cpi, ThreadData *td,
xd->tree_type = SHARED_PART;
} else if (sf->part_sf.partition_search_type == VAR_BASED_PARTITION) {
av2_set_offsets(cpi, tile_info, x, mi_row, mi_col, sb_size, NULL);
av2_choose_var_based_partitioning(cpi, tile_info, td, x, mi_row, mi_col);
unsigned int source_sad = UINT_MAX;
if (cpi->sf.rt_sf.source_metrics_sb) {
source_sad = get_sb_source_sad(cpi, x, mi_row, mi_col);
}
x->source_sad = source_sad;
x->source_sad_level = get_source_sad_level(
source_sad, sb_size, cpi->common.seq_params.bit_depth);
av2_choose_var_based_partitioning(cpi, tile_info, td, x, mi_row, mi_col,
source_sad);
for (int loop_idx = 0; loop_idx < total_loop_num; loop_idx++) {
xd->tree_type =
(total_loop_num == 1 ? SHARED_PART
Expand Down Expand Up @@ -1371,6 +1426,8 @@ static AVM_INLINE void encode_sb_row(AV2_COMP *cpi, ThreadData *td,

xd->cur_frame_force_integer_mv = cm->features.cur_frame_force_integer_mv;
x->source_variance = UINT_MAX;
x->source_sad = UINT_MAX;
x->source_sad_level = kMedSad;
td->mb.cb_coef_buff = av2_get_cb_coeff_buffer(cpi, mi_row, mi_col);

av2_reset_refmv_bank(cm, xd, tile_info, mi_row, mi_col);
Expand Down
8 changes: 8 additions & 0 deletions av2/encoder/speed_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,7 @@ static void set_rt_speed_features_framesize_independent(
sf->rd_sf.tx_domain_dist_thres_level = 2;
sf->rt_sf.use_nonrd_partition = 1;
sf->rt_sf.use_only_dc_intra_interframe = true;
sf->rt_sf.source_metrics_sb = 1;
sf->winner_mode_sf.tx_size_search_level = USE_FAST_RD;
sf->tx_sf.restrict_tx_partition_type_search = 3;
}
Expand Down Expand Up @@ -1084,6 +1085,12 @@ static AVM_INLINE void init_lc_sf(LC_DEC_SPEED_FEATURES *lc_sf) {
lc_sf->enable_partition_size_bias = 0;
}

static AVM_INLINE void init_rt_sf(REALTIME_SPEED_FEATURES *rt_sf) {
rt_sf->use_nonrd_partition = 0;
rt_sf->use_only_dc_intra_interframe = false;
rt_sf->source_metrics_sb = 0;
}

static AVM_INLINE void set_erp_speed_features_framesize_dependent(
AV2_COMP *cpi) {
SPEED_FEATURES *const sf = &cpi->sf;
Expand Down Expand Up @@ -1297,6 +1304,7 @@ void av2_set_speed_features_framesize_independent(AV2_COMP *cpi, int speed) {
init_lpf_sf(&sf->lpf_sf);
init_flexmv_sf(&sf->flexmv_sf);
init_lc_sf(&sf->lc_sf);
init_rt_sf(&sf->rt_sf);

if (oxcf->mode == GOOD) {
set_good_speed_features_framesize_independent(cpi, sf, speed);
Expand Down
3 changes: 3 additions & 0 deletions av2/encoder/speed_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,9 @@ typedef struct REALTIME_SPEED_FEATURES {

// Flag to disable all but DC intra mode for inter frame prediction.
bool use_only_dc_intra_interframe;

// Compute source sad metrics for superblock.
int source_metrics_sb;
} REALTIME_SPEED_FEATURES;

typedef struct LC_DEC_SPEED_FEATURES {
Expand Down
54 changes: 41 additions & 13 deletions av2/encoder/var_based_part.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,16 +377,18 @@ static inline int64_t interpolate_threshold(int64_t low_val, int64_t high_val,
(q_high - q_low);
}

static inline void tune_thresh_based_on_resolution(AV2_COMP *cpi,
int64_t thresholds[],
int64_t threshold_base,
int current_qindex,
int num_pixels) {
static inline void tune_thresh_based_on_resolution(
AV2_COMP *cpi, int64_t thresholds[], int64_t threshold_base,
int current_qindex, int num_pixels, SOURCE_SAD source_sad_level) {
const bool is_screen = (cpi->oxcf.tune_cfg.content == AVM_CONTENT_SCREEN);
if (num_pixels >= RESOLUTION_720P) thresholds[4] = thresholds[4] << 1;
if (num_pixels <= RESOLUTION_288P) {
const int q_low = 110;
const int q_high = 135;
int q_low = 110;
int q_high = 135;
if (source_sad_level <= kLowSad) {
q_low = 95;
q_high = 120;
}
thresholds[2] = threshold_base >> 3;
if (num_pixels <= RESOLUTION_180P) {
thresholds[3] = interpolate_threshold((3 * threshold_base) >> 3,
Expand Down Expand Up @@ -510,7 +512,7 @@ static void set_vbp_thresholds_key_frame(int64_t thresholds[],
* threshold
*/
static inline void set_vbp_thresholds(AV2_COMP *cpi, int64_t thresholds[],
int qindex) {
int qindex, SOURCE_SAD source_sad_level) {
AV2_COMMON *const cm = &cpi->common;
const int is_key_frame = frame_is_intra_only(cm);
const int threshold_multiplier = is_key_frame ? 120 : 1;
Expand Down Expand Up @@ -545,7 +547,21 @@ static inline void set_vbp_thresholds(AV2_COMP *cpi, int64_t thresholds[],
thresholds[5] = INT64_MAX;

tune_thresh_based_on_resolution(cpi, thresholds, threshold_base,
current_qindex, num_pixels);
current_qindex, num_pixels, source_sad_level);

if (source_sad_level <= kLowSad) {
thresholds[1] = (5 * thresholds[1]) >> 2;
thresholds[2] = (5 * thresholds[2]) >> 2;
thresholds[3] = (3 * thresholds[3]) >> 1;
thresholds[4] = (3 * thresholds[4]) >> 1;
}
if (source_sad_level <= kVeryLowSad) {
thresholds[4] = thresholds[4] << 1;
}
if (source_sad_level <= kVeryLowSad && current_qindex > 130 &&
num_pixels <= RESOLUTION_360P) {
thresholds[4] = INT64_MAX;
}
}

static inline void force_split_ancestors(PART_EVAL_STATUS *force_split,
Expand Down Expand Up @@ -792,7 +808,8 @@ static void set_vt_partitioning_64x64(AV2_COMP *cpi, MACROBLOCKD *xd,
void av2_choose_var_based_partitioning(AV2_COMP *cpi,
const TileInfo *const tile,
ThreadData *td, MACROBLOCK *x,
int mi_row, int mi_col) {
int mi_row, int mi_col,
unsigned int source_sad) {
AV2_COMMON *const cm = &cpi->common;
MACROBLOCKD *xd = &x->e_mbd;
// Flat array representing quadtree nodes up to 16x16 level for 256x256 SB
Expand All @@ -813,6 +830,7 @@ void av2_choose_var_based_partitioning(AV2_COMP *cpi,
bool is_key_frame = frame_is_intra_only(cm);
bool scaled_ref_last = false;
const int is_360p_or_smaller = cm->width * cm->height <= RESOLUTION_360P;
const SOURCE_SAD source_sad_level = x->source_sad_level;

assert(cm->seq_params.sb_size == BLOCK_64X64 ||
cm->seq_params.sb_size == BLOCK_128X128 ||
Expand All @@ -827,7 +845,7 @@ void av2_choose_var_based_partitioning(AV2_COMP *cpi,
int64_t thresholds[6];
const int qindex = cm->quant_params.base_qindex;

set_vbp_thresholds(cpi, thresholds, qindex);
set_vbp_thresholds(cpi, thresholds, qindex, source_sad_level);

src_buf = x->plane[AVM_PLANE_Y].src.buf;
int src_stride = x->plane[AVM_PLANE_Y].src.stride;
Expand All @@ -844,6 +862,15 @@ void av2_choose_var_based_partitioning(AV2_COMP *cpi,
dst_buf = xd->plane[AVM_PLANE_Y].pre[0].buf;
dst_stride = xd->plane[AVM_PLANE_Y].pre[0].stride;
}

const int block_width = mi_size_wide[cm->seq_params.sb_size];
const int block_height = mi_size_high[cm->seq_params.sb_size];
if (source_sad == 0 && y_sad == 0 &&
mi_col + block_width <= tile->mi_col_end &&
mi_row + block_height <= tile->mi_row_end) {
set_block_size(cpi, mi_row, mi_col, cm->seq_params.sb_size);
return;
}
} else {
dst_buf = NULL;
dst_stride = 0;
Expand Down Expand Up @@ -938,6 +965,7 @@ void av2_choose_var_based_partitioning(AV2_COMP *cpi,
force_split_ancestors(force_split, offset_64x64, offset_32x32,
blk64_idx, lvl1_idx);
} else if (!is_key_frame && !is_screen &&
(source_sad_level > kVeryLowSad) &&
((is_360p_or_smaller &&
((max_min_var_16X16_diff > (thresholds[3] >> 1) &&
maxvar_16x16[blk64_idx][lvl1_idx] > thresholds[3]) ||
Expand Down Expand Up @@ -967,8 +995,8 @@ void av2_choose_var_based_partitioning(AV2_COMP *cpi,
const int check_max_var = max_var_32x32[blk64_idx] > (thresholds[2] >> 1);
const int64_t set_threshold = 3 * (thresholds[2] >> 3);

if (!is_key_frame && max_min_var_32x32_diff > set_threshold &&
check_max_var) {
if (!is_key_frame && (source_sad_level > kVeryLowSad) &&
max_min_var_32x32_diff > set_threshold && check_max_var) {
force_split[offset_64x64 + blk64_idx] = PART_EVAL_ONLY_SPLIT;
force_split[0] = PART_EVAL_ONLY_SPLIT;
}
Expand Down
3 changes: 2 additions & 1 deletion av2/encoder/var_based_part.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ extern "C" {
void av2_choose_var_based_partitioning(AV2_COMP *cpi,
const TileInfo *const tile,
ThreadData *td, MACROBLOCK *x,
int mi_row, int mi_col);
int mi_row, int mi_col,
unsigned int source_sad);

#ifdef __cplusplus
} // extern "C"
Expand Down
Loading