aboutsummaryrefslogtreecommitdiff
path: root/av1/encoder/var_based_part.c
diff options
context:
space:
mode:
Diffstat (limited to 'av1/encoder/var_based_part.c')
-rw-r--r--av1/encoder/var_based_part.c248
1 files changed, 171 insertions, 77 deletions
diff --git a/av1/encoder/var_based_part.c b/av1/encoder/var_based_part.c
index ab27d1f88..a953a6fb4 100644
--- a/av1/encoder/var_based_part.c
+++ b/av1/encoder/var_based_part.c
@@ -383,14 +383,16 @@ static AOM_INLINE void fill_variance_4x4avg(const uint8_t *s, int sp,
int highbd_flag,
#endif
int pixels_wide, int pixels_high,
- int is_key_frame) {
+ int is_key_frame,
+ int border_offset_4x4) {
int k;
for (k = 0; k < 4; k++) {
int x4_idx = x8_idx + ((k & 1) << 2);
int y4_idx = y8_idx + ((k >> 1) << 2);
unsigned int sse = 0;
int sum = 0;
- if (x4_idx < pixels_wide && y4_idx < pixels_high) {
+ if (x4_idx < pixels_wide - border_offset_4x4 &&
+ y4_idx < pixels_high - border_offset_4x4) {
int s_avg;
int d_avg = 128;
#if CONFIG_AV1_HIGHBITDEPTH
@@ -429,8 +431,7 @@ static int64_t scale_part_thresh_content(int64_t threshold_base, int speed,
}
static AOM_INLINE void tune_thresh_based_on_qindex_window(
- int qindex, int th, int source_sad, int ag_idx, int64_t thresholds[]) {
- const int win = 45;
+ int qindex, int th, int win, int fac, int64_t thresholds[]) {
double weight;
if (qindex < th - win)
@@ -443,7 +444,6 @@ static AOM_INLINE void tune_thresh_based_on_qindex_window(
(int)((1 - weight) * (thresholds[1] << 1) + weight * thresholds[1]);
thresholds[2] =
(int)((1 - weight) * (thresholds[2] << 1) + weight * thresholds[2]);
- const int fac = (!ag_idx && source_sad != kLowSad) ? 1 : 2;
thresholds[3] =
(int)((1 - weight) * (thresholds[3] << fac) + weight * thresholds[3]);
}
@@ -451,7 +451,9 @@ static AOM_INLINE void tune_thresh_based_on_qindex_window(
static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[],
int q, int content_lowsumdiff,
int source_sad_nonrd,
- int source_sad_rd, int segment_id) {
+ int source_sad_rd, int segment_id,
+ uint64_t blk_sad,
+ int lighting_change) {
AV1_COMMON *const cm = &cpi->common;
const int is_key_frame = frame_is_intra_only(cm);
const int threshold_multiplier = is_key_frame ? 120 : 1;
@@ -510,12 +512,12 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[],
else
threshold_base =
scale_part_thresh_content(threshold_base, cpi->oxcf.speed, cm->width,
- cm->height, cpi->svc.non_reference_frame);
+ cm->height, cpi->ppi->rtc_ref.non_reference_frame);
#else
// Increase base variance threshold based on content_state/sum_diff level.
- threshold_base =
- scale_part_thresh_content(threshold_base, cpi->oxcf.speed, cm->width,
- cm->height, cpi->svc.non_reference_frame);
+ threshold_base = scale_part_thresh_content(
+ threshold_base, cpi->oxcf.speed, cm->width, cm->height,
+ cpi->ppi->rtc_ref.non_reference_frame);
#endif
thresholds[0] = threshold_base >> 1;
thresholds[1] = threshold_base;
@@ -565,11 +567,13 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[],
thresholds[2] = (5 * threshold_base) >> 2;
} else if (cm->width < 1920 && cm->height < 1080) {
thresholds[2] = threshold_base << 1;
- } else {
+ } else if (cm->width < 2560 && cm->height < 1440) {
thresholds[2] = (5 * threshold_base) >> 1;
+ } else {
+ thresholds[2] = (7 * threshold_base) >> 1;
}
// Tune thresholds less or more aggressively to prefer larger partitions
- if (cpi->sf.rt_sf.prefer_large_partition_blocks >= 4) {
+ if (cpi->sf.rt_sf.prefer_large_partition_blocks >= 3) {
double weight;
const int win = 20;
if (current_qindex < QINDEX_LARGE_BLOCK_THR - win)
@@ -585,14 +589,23 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[],
}
}
if (cm->width * cm->height <= 352 * 288) {
- thresholds[3] = INT32_MAX;
+ thresholds[3] = INT64_MAX;
if (segment_id == 0) {
thresholds[1] <<= 2;
- thresholds[2] <<= (source_sad_nonrd == kLowSad) ? 5 : 4;
+ thresholds[2] <<= (source_sad_nonrd <= kLowSad) ? 5 : 4;
} else {
thresholds[1] <<= 1;
thresholds[2] <<= 3;
}
+ // Allow for split to 8x8 for superblocks where part of it has
+ // moving boundary. So allow for sb with source_sad above threshold,
+ // and avoid very large source_sad or high source content, to avoid
+ // too many 8x8 within superblock.
+ if (segment_id == 0 && cpi->rc.avg_source_sad < 25000 &&
+ blk_sad > 25000 && blk_sad < 50000 && !lighting_change) {
+ thresholds[2] = (3 * thresholds[2]) >> 2;
+ thresholds[3] = thresholds[2] << 3;
+ }
// Condition the increase of partition thresholds on the segment
// and the content. Avoid the increase for superblocks which have
// high source sad, unless the whole frame has very high motion
@@ -602,7 +615,7 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[],
(source_sad_nonrd != kHighSad ||
cpi->rc.avg_source_sad > 50000)) {
thresholds[0] = (3 * thresholds[0]) >> 1;
- thresholds[3] = INT32_MAX;
+ thresholds[3] = INT64_MAX;
if (current_qindex > QINDEX_LARGE_BLOCK_THR) {
thresholds[1] =
(int)((1 - weight) * (thresholds[1] << 1) + weight * thresholds[1]);
@@ -616,16 +629,16 @@ static AOM_INLINE void set_vbp_thresholds(AV1_COMP *cpi, int64_t thresholds[],
(int)((1 - weight) * (thresholds[1] << 2) + weight * thresholds[1]);
thresholds[2] =
(int)((1 - weight) * (thresholds[2] << 4) + weight * thresholds[2]);
- thresholds[3] = INT32_MAX;
+ thresholds[3] = INT64_MAX;
}
} else if (cpi->sf.rt_sf.prefer_large_partition_blocks >= 2) {
- tune_thresh_based_on_qindex_window(
- current_qindex, QINDEX_LARGE_BLOCK_THR, source_sad_nonrd,
- cpi->sf.rt_sf.prefer_large_partition_blocks - 2, thresholds);
+ thresholds[1] <<= (source_sad_nonrd <= kLowSad) ? 2 : 0;
+ thresholds[2] =
+ (source_sad_nonrd <= kLowSad) ? (3 * thresholds[2]) : thresholds[2];
} else if (cpi->sf.rt_sf.prefer_large_partition_blocks >= 1) {
- thresholds[3] <<= 2;
- thresholds[1] <<= (source_sad_nonrd == kLowSad) ? 1 : 0;
- thresholds[2] <<= (source_sad_nonrd == kLowSad) ? 1 : 0;
+ const int fac = (source_sad_nonrd <= kLowSad) ? 2 : 1;
+ tune_thresh_based_on_qindex_window(current_qindex, QINDEX_LARGE_BLOCK_THR,
+ 45, fac, thresholds);
}
if (cpi->sf.part_sf.disable_8x8_part_based_on_qidx && (current_qindex < 128))
thresholds[3] = INT64_MAX;
@@ -916,7 +929,7 @@ void av1_set_variance_partition_thresholds(AV1_COMP *cpi, int q,
return;
} else {
set_vbp_thresholds(cpi, cpi->vbp_info.thresholds, q, content_lowsumdiff, 0,
- 0, 0);
+ 0, 0, 0, 0);
// The threshold below is not changed locally.
cpi->vbp_info.threshold_minmax = 15 + (q >> 3);
}
@@ -1010,13 +1023,23 @@ static void fill_variance_tree_leaves(
const int compute_minmax_variance = 0;
const int segment_id = xd->mi[0]->segment_id;
int pixels_wide = 128, pixels_high = 128;
-
+ int border_offset_4x4 = 0;
+ int temporal_denoising = cpi->sf.rt_sf.use_rtc_tf;
if (is_small_sb) {
pixels_wide = 64;
pixels_high = 64;
}
if (xd->mb_to_right_edge < 0) pixels_wide += (xd->mb_to_right_edge >> 3);
if (xd->mb_to_bottom_edge < 0) pixels_high += (xd->mb_to_bottom_edge >> 3);
+#if CONFIG_AV1_TEMPORAL_DENOISING
+ temporal_denoising |= cpi->oxcf.noise_sensitivity;
+#endif
+ // For temporal filtering or temporal denoiser enabled: since the source
+ // is modified we need to avoid 4x4 avg along superblock boundary, since
+ // simd code will load 8 pixels for 4x4 avg and so can access source
+ // data outside superblock (while its being modified by temporal filter).
+ // Temporal filtering is never done on key frames.
+ if (!is_key_frame && temporal_denoising) border_offset_4x4 = 4;
for (int m = 0; m < num_64x64_blocks; m++) {
const int x64_idx = ((m & 1) << 6);
const int y64_idx = ((m >> 1) << 6);
@@ -1096,12 +1119,12 @@ static void fill_variance_tree_leaves(
int x8_idx = x16_idx + ((k & 1) << 3);
int y8_idx = y16_idx + ((k >> 1) << 3);
VP8x8 *vst2 = is_key_frame ? &vst->split[k] : &vt2[i2 + j].split[k];
- fill_variance_4x4avg(src, src_stride, dst, dst_stride, x8_idx,
- y8_idx, vst2,
+ fill_variance_4x4avg(
+ src, src_stride, dst, dst_stride, x8_idx, y8_idx, vst2,
#if CONFIG_AV1_HIGHBITDEPTH
- xd->cur_buf->flags,
+ xd->cur_buf->flags,
#endif
- pixels_wide, pixels_high, is_key_frame);
+ pixels_wide, pixels_high, is_key_frame, border_offset_4x4);
}
}
}
@@ -1110,7 +1133,8 @@ static void fill_variance_tree_leaves(
}
static void setup_planes(AV1_COMP *cpi, MACROBLOCK *x, unsigned int *y_sad,
- unsigned int *y_sad_g, unsigned int *y_sad_last,
+ unsigned int *y_sad_g, unsigned int *y_sad_alt,
+ unsigned int *y_sad_last,
MV_REFERENCE_FRAME *ref_frame_partition, int mi_row,
int mi_col) {
AV1_COMMON *const cm = &cpi->common;
@@ -1118,17 +1142,24 @@ static void setup_planes(AV1_COMP *cpi, MACROBLOCK *x, unsigned int *y_sad,
const int num_planes = av1_num_planes(cm);
const int is_small_sb = (cm->seq_params->sb_size == BLOCK_64X64);
BLOCK_SIZE bsize = is_small_sb ? BLOCK_64X64 : BLOCK_128X128;
- // TODO(kyslov): we are assuming that the ref is LAST_FRAME! Check if it
- // is!!
MB_MODE_INFO *mi = xd->mi[0];
const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, LAST_FRAME);
assert(yv12 != NULL);
const YV12_BUFFER_CONFIG *yv12_g = NULL;
-
- // For non-SVC GOLDEN is another temporal reference. Check if it should be
- // used as reference for partitioning.
- if (!cpi->ppi->use_svc && (cpi->ref_frame_flags & AOM_GOLD_FLAG) &&
- x->content_state_sb.source_sad_nonrd != kZeroSad) {
+ const YV12_BUFFER_CONFIG *yv12_alt = NULL;
+ // Check if LAST is a reference. For spatial layers always use it as
+ // reference scaling (golden or altref being lower resolution) is not
+ // handled/check here.
+ int use_last_ref = (cpi->ref_frame_flags & AOM_LAST_FLAG) ||
+ cpi->svc.number_spatial_layers > 1;
+ int use_golden_ref = cpi->ref_frame_flags & AOM_GOLD_FLAG;
+ int use_alt_ref = cpi->ppi->rtc_ref.set_ref_frame_config ||
+ cpi->sf.rt_sf.use_nonrd_altref_frame;
+
+ // For 1 spatial layer: GOLDEN is another temporal reference.
+ // Check if it should be used as reference for partitioning.
+ if (cpi->svc.number_spatial_layers == 1 && use_golden_ref &&
+ (x->content_state_sb.source_sad_nonrd != kZeroSad || !use_last_ref)) {
yv12_g = get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
if (yv12_g && yv12_g != yv12) {
av1_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col,
@@ -1139,30 +1170,47 @@ static void setup_planes(AV1_COMP *cpi, MACROBLOCK *x, unsigned int *y_sad,
}
}
- av1_setup_pre_planes(xd, 0, yv12, mi_row, mi_col,
- get_ref_scale_factors(cm, LAST_FRAME), num_planes);
- mi->ref_frame[0] = LAST_FRAME;
- mi->ref_frame[1] = NONE_FRAME;
- mi->bsize = cm->seq_params->sb_size;
- mi->mv[0].as_int = 0;
- mi->interp_filters = av1_broadcast_interp_filter(BILINEAR);
- if (cpi->sf.rt_sf.estimate_motion_for_var_based_partition) {
- if (xd->mb_to_right_edge >= 0 && xd->mb_to_bottom_edge >= 0) {
- const MV dummy_mv = { 0, 0 };
- *y_sad = av1_int_pro_motion_estimation(cpi, x, cm->seq_params->sb_size,
- mi_row, mi_col, &dummy_mv);
+ // For 1 spatial layer: ALTREF is another temporal reference.
+ // Check if it should be used as reference for partitioning.
+ if (cpi->svc.number_spatial_layers == 1 && use_alt_ref &&
+ (cpi->ref_frame_flags & AOM_ALT_FLAG) &&
+ (x->content_state_sb.source_sad_nonrd != kZeroSad || !use_last_ref)) {
+ yv12_alt = get_ref_frame_yv12_buf(cm, ALTREF_FRAME);
+ if (yv12_alt && yv12_alt != yv12) {
+ av1_setup_pre_planes(xd, 0, yv12_alt, mi_row, mi_col,
+ get_ref_scale_factors(cm, ALTREF_FRAME), num_planes);
+ *y_sad_alt = cpi->ppi->fn_ptr[bsize].sdf(
+ x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].pre[0].buf,
+ xd->plane[0].pre[0].stride);
}
}
- if (*y_sad == UINT_MAX) {
- *y_sad = cpi->ppi->fn_ptr[bsize].sdf(
- x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].pre[0].buf,
- xd->plane[0].pre[0].stride);
+
+ if (use_last_ref) {
+ av1_setup_pre_planes(xd, 0, yv12, mi_row, mi_col,
+ get_ref_scale_factors(cm, LAST_FRAME), num_planes);
+ mi->ref_frame[0] = LAST_FRAME;
+ mi->ref_frame[1] = NONE_FRAME;
+ mi->bsize = cm->seq_params->sb_size;
+ mi->mv[0].as_int = 0;
+ mi->interp_filters = av1_broadcast_interp_filter(BILINEAR);
+ if (cpi->sf.rt_sf.estimate_motion_for_var_based_partition) {
+ if (xd->mb_to_right_edge >= 0 && xd->mb_to_bottom_edge >= 0) {
+ const MV dummy_mv = { 0, 0 };
+ *y_sad = av1_int_pro_motion_estimation(cpi, x, cm->seq_params->sb_size,
+ mi_row, mi_col, &dummy_mv);
+ }
+ }
+ if (*y_sad == UINT_MAX) {
+ *y_sad = cpi->ppi->fn_ptr[bsize].sdf(
+ x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].pre[0].buf,
+ xd->plane[0].pre[0].stride);
+ }
+ *y_sad_last = *y_sad;
}
- *y_sad_last = *y_sad;
- // Pick the ref frame for partitioning, use golden frame only if its
- // lower sad.
- if (*y_sad_g < 0.9 * *y_sad) {
+ // Pick the ref frame for partitioning, use golden or altref frame only if
+ // its lower sad, bias to LAST with factor 0.9.
+ if (*y_sad_g < 0.9 * *y_sad && *y_sad_g < *y_sad_alt) {
av1_setup_pre_planes(xd, 0, yv12_g, mi_row, mi_col,
get_ref_scale_factors(cm, GOLDEN_FRAME), num_planes);
mi->ref_frame[0] = GOLDEN_FRAME;
@@ -1170,6 +1218,14 @@ static void setup_planes(AV1_COMP *cpi, MACROBLOCK *x, unsigned int *y_sad,
*y_sad = *y_sad_g;
*ref_frame_partition = GOLDEN_FRAME;
x->nonrd_prune_ref_frame_search = 0;
+ } else if (*y_sad_alt < 0.9 * *y_sad && *y_sad_alt < *y_sad_g) {
+ av1_setup_pre_planes(xd, 0, yv12_alt, mi_row, mi_col,
+ get_ref_scale_factors(cm, ALTREF_FRAME), num_planes);
+ mi->ref_frame[0] = ALTREF_FRAME;
+ mi->mv[0].as_int = 0;
+ *y_sad = *y_sad_alt;
+ *ref_frame_partition = ALTREF_FRAME;
+ x->nonrd_prune_ref_frame_search = 0;
} else {
*ref_frame_partition = LAST_FRAME;
x->nonrd_prune_ref_frame_search =
@@ -1181,7 +1237,7 @@ static void setup_planes(AV1_COMP *cpi, MACROBLOCK *x, unsigned int *y_sad,
set_ref_ptrs(cm, xd, mi->ref_frame[0], mi->ref_frame[1]);
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL,
cm->seq_params->sb_size, AOM_PLANE_Y,
- AOM_PLANE_V);
+ num_planes - 1);
}
}
@@ -1205,6 +1261,18 @@ static AOM_INLINE PART_EVAL_STATUS get_part_eval_based_on_sub_blk_var(
: PART_EVAL_ONLY_NONE;
}
+static AOM_INLINE bool is_set_force_zeromv_skip_based_on_src_sad(
+ int set_zeromv_skip_based_on_source_sad, SOURCE_SAD source_sad_nonrd) {
+ if (set_zeromv_skip_based_on_source_sad == 0) return false;
+
+ if (set_zeromv_skip_based_on_source_sad >= 2)
+ return source_sad_nonrd <= kVeryLowSad;
+ else if (set_zeromv_skip_based_on_source_sad >= 1)
+ return source_sad_nonrd == kZeroSad;
+
+ return false;
+}
+
int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
ThreadData *td, MACROBLOCK *x, int mi_row,
int mi_col) {
@@ -1250,6 +1318,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
unsigned int y_sad = UINT_MAX;
unsigned int y_sad_g = UINT_MAX;
+ unsigned int y_sad_alt = UINT_MAX;
unsigned int y_sad_last = UINT_MAX;
BLOCK_SIZE bsize = is_small_sb ? BLOCK_64X64 : BLOCK_128X128;
@@ -1267,6 +1336,17 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
const int low_res = (cm->width <= 352 && cm->height <= 288);
int variance4x4downsample[64];
const int segment_id = xd->mi[0]->segment_id;
+ uint64_t blk_sad = 0;
+ if (cpi->src_sad_blk_64x64 != NULL && !cpi->ppi->use_svc) {
+ const int sb_size_by_mb = (cm->seq_params->sb_size == BLOCK_128X128)
+ ? (cm->seq_params->mib_size >> 1)
+ : cm->seq_params->mib_size;
+ const int sb_cols =
+ (cm->mi_params.mi_cols + sb_size_by_mb - 1) / sb_size_by_mb;
+ const int sbi_col = mi_col / sb_size_by_mb;
+ const int sbi_row = mi_row / sb_size_by_mb;
+ blk_sad = cpi->src_sad_blk_64x64[sbi_col + sbi_row * sb_cols];
+ }
if (cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ && cm->seg.enabled &&
cyclic_refresh_segment_id_boosted(segment_id)) {
@@ -1274,12 +1354,14 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
av1_get_qindex(&cm->seg, segment_id, cm->quant_params.base_qindex);
set_vbp_thresholds(cpi, thresholds, q, x->content_state_sb.low_sumdiff,
x->content_state_sb.source_sad_nonrd,
- x->content_state_sb.source_sad_rd, 1);
+ x->content_state_sb.source_sad_rd, 1, blk_sad,
+ x->content_state_sb.lighting_change);
} else {
set_vbp_thresholds(cpi, thresholds, cm->quant_params.base_qindex,
x->content_state_sb.low_sumdiff,
x->content_state_sb.source_sad_nonrd,
- x->content_state_sb.source_sad_rd, 0);
+ x->content_state_sb.source_sad_rd, 0, blk_sad,
+ x->content_state_sb.lighting_change);
}
// For non keyframes, disable 4x4 average for low resolution when speed = 8
@@ -1310,8 +1392,8 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
}
if (!is_key_frame) {
- setup_planes(cpi, x, &y_sad, &y_sad_g, &y_sad_last, &ref_frame_partition,
- mi_row, mi_col);
+ setup_planes(cpi, x, &y_sad, &y_sad_g, &y_sad_alt, &y_sad_last,
+ &ref_frame_partition, mi_row, mi_col);
MB_MODE_INFO *mi = xd->mi[0];
// Use reference SB directly for zero mv.
@@ -1333,32 +1415,40 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
chroma_check(cpi, x, bsize, y_sad_last, y_sad_g, is_key_frame, zero_motion,
uv_sad);
- x->force_zeromv_skip = 0;
- const unsigned int thresh_exit_part =
- (cm->seq_params->sb_size == BLOCK_64X64) ? 5000 : 10000;
+ x->force_zeromv_skip_for_sb = 0;
+ const bool is_set_force_zeromv_skip =
+ is_set_force_zeromv_skip_based_on_src_sad(
+ cpi->sf.rt_sf.set_zeromv_skip_based_on_source_sad,
+ x->content_state_sb.source_sad_nonrd);
+
// If the superblock is completely static (zero source sad) and
// the y_sad (relative to LAST ref) is very small, take the sb_size partition
// and exit, and force zeromv_last skip mode for nonrd_pickmode.
- // Only do this when the cyclic refresh is applied, and only on the base
- // segment (so the QP-boosted segment can still contnue cleaning/ramping
- // up the quality). Condition on color uv_sad is also added.
+ // Only do this on the base segment (so the QP-boosted segment, if applied,
+ // can still continue cleaning/ramping up the quality).
+ // Condition on color uv_sad is also added.
if (!is_key_frame && cpi->sf.rt_sf.part_early_exit_zeromv &&
- cpi->oxcf.q_cfg.aq_mode == CYCLIC_REFRESH_AQ &&
- cpi->cyclic_refresh->apply_cyclic_refresh &&
- segment_id == CR_SEGMENT_ID_BASE &&
- x->content_state_sb.source_sad_nonrd == kZeroSad &&
- ref_frame_partition == LAST_FRAME && xd->mi[0]->mv[0].as_int == 0 &&
- y_sad < thresh_exit_part && uv_sad[0]<(3 * thresh_exit_part)>> 2 &&
- uv_sad[1]<(3 * thresh_exit_part)>> 2) {
+ cpi->rc.frames_since_key > 30 && segment_id == CR_SEGMENT_ID_BASE &&
+ is_set_force_zeromv_skip && ref_frame_partition == LAST_FRAME &&
+ xd->mi[0]->mv[0].as_int == 0) {
const int block_width = mi_size_wide[cm->seq_params->sb_size];
const int block_height = mi_size_high[cm->seq_params->sb_size];
+ const unsigned int thresh_exit_part_y =
+ cpi->zeromv_skip_thresh_exit_part[bsize];
+ const unsigned int thresh_exit_part_uv =
+ CALC_CHROMA_THRESH_FOR_ZEROMV_SKIP(thresh_exit_part_y);
if (mi_col + block_width <= tile->mi_col_end &&
- mi_row + block_height <= tile->mi_row_end) {
+ mi_row + block_height <= tile->mi_row_end &&
+ y_sad < thresh_exit_part_y && uv_sad[0] < thresh_exit_part_uv &&
+ uv_sad[1] < thresh_exit_part_uv) {
set_block_size(cpi, mi_row, mi_col, bsize);
- x->force_zeromv_skip = 1;
+ x->force_zeromv_skip_for_sb = 1;
if (vt2) aom_free(vt2);
if (vt) aom_free(vt);
return 0;
+ } else if (x->content_state_sb.source_sad_nonrd == kZeroSad &&
+ cpi->sf.rt_sf.part_early_exit_zeromv >= 2) {
+ x->force_zeromv_skip_for_sb = 2;
}
}
@@ -1407,6 +1497,10 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
// (some threshold of) the average variance over the sub-16x16 blocks,
// then force this block to split. This also forces a split on the upper
// (64x64) level.
+ uint64_t frame_sad_thresh = 20000;
+ if (cpi->svc.number_temporal_layers > 2 &&
+ cpi->svc.temporal_layer_id == 0)
+ frame_sad_thresh = frame_sad_thresh << 1;
if (force_split[5 + m2 + i] == PART_EVAL_ALL) {
get_variance(&vt->split[m].split[i].part_variances.none);
var_32x32 = vt->split[m].split[i].part_variances.none.variance;
@@ -1428,7 +1522,7 @@ int av1_choose_var_based_partitioning(AV1_COMP *cpi, const TileInfo *const tile,
maxvar_16x16[m][i] > thresholds[2]) ||
(cpi->sf.rt_sf.prefer_large_partition_blocks &&
x->content_state_sb.source_sad_nonrd > kLowSad &&
- cpi->rc.frame_source_sad < 20000 &&
+ cpi->rc.frame_source_sad < frame_sad_thresh &&
maxvar_16x16[m][i] > (thresholds[2] >> 4) &&
maxvar_16x16[m][i] > (minvar_16x16[m][i] << 2)))) {
force_split[5 + m2 + i] = PART_EVAL_ONLY_SPLIT;