/* * Copyright (c) 2019, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. If the Alliance for Open * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
// Possible values for the force_split variable while evaluating variance based // partitioning. enum { // Evaluate all partition types
PART_EVAL_ALL = 0, // Force PARTITION_SPLIT
PART_EVAL_ONLY_SPLIT = 1, // Force PARTITION_NONE
PART_EVAL_ONLY_NONE = 2
} UENUM1BYTE(PART_EVAL_STATUS);
staticint set_vt_partitioning(AV1_COMP *cpi, MACROBLOCKD *const xd, const TileInfo *const tile, void *data,
BLOCK_SIZE bsize, int mi_row, int mi_col,
int64_t threshold, BLOCK_SIZE bsize_min,
PART_EVAL_STATUS force_split) {
AV1_COMMON *const cm = &cpi->common;
variance_node vt; constint block_width = mi_size_wide[bsize]; constint block_height = mi_size_high[bsize]; int bs_width_check = block_width; int bs_height_check = block_height; int bs_width_vert_check = block_width >> 1; int bs_height_horiz_check = block_height >> 1; // On the right and bottom boundary we only need to check // if half the bsize fits, because boundary is extended // up to 64. So do this check only for sb_size = 64X64. if (cm->seq_params->sb_size == BLOCK_64X64) { if (tile->mi_col_end == cm->mi_params.mi_cols) {
bs_width_check = (block_width >> 1) + 1;
bs_width_vert_check = (block_width >> 2) + 1;
} if (tile->mi_row_end == cm->mi_params.mi_rows) {
bs_height_check = (block_height >> 1) + 1;
bs_height_horiz_check = (block_height >> 2) + 1;
}
}
// For bsize=bsize_min (16x16/8x8 for 8x8/4x4 downsampling), select if // variance is below threshold, otherwise split will be selected. // No check for vert/horiz split as too few samples for variance. if (bsize == bsize_min) { // Variance already computed to set the force_split. if (frame_is_intra_only(cm)) get_variance(&vt.part_variances->none); if (mi_col + bs_width_check <= tile->mi_col_end &&
mi_row + bs_height_check <= tile->mi_row_end &&
vt.part_variances->none.variance < threshold) {
set_block_size(cpi, mi_row, mi_col, bsize); return 1;
} return 0;
} elseif (bsize > bsize_min) { // Variance already computed to set the force_split. if (frame_is_intra_only(cm)) get_variance(&vt.part_variances->none); // For key frame: take split for bsize above 32X32 or very high variance. if (frame_is_intra_only(cm) &&
(bsize > BLOCK_32X32 ||
vt.part_variances->none.variance > (threshold << 4))) { return 0;
} // If variance is low, take the bsize (no split). if (mi_col + bs_width_check <= tile->mi_col_end &&
mi_row + bs_height_check <= tile->mi_row_end &&
vt.part_variances->none.variance < threshold) {
set_block_size(cpi, mi_row, mi_col, bsize); return 1;
} // Check vertical split. if (mi_row + bs_height_check <= tile->mi_row_end &&
mi_col + bs_width_vert_check <= tile->mi_col_end) {
BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_VERT);
BLOCK_SIZE plane_bsize =
get_plane_block_size(subsize, xd->plane[AOM_PLANE_U].subsampling_x,
xd->plane[AOM_PLANE_U].subsampling_y);
get_variance(&vt.part_variances->vert[0]);
get_variance(&vt.part_variances->vert[1]); if (vt.part_variances->vert[0].variance < threshold &&
vt.part_variances->vert[1].variance < threshold &&
plane_bsize < BLOCK_INVALID) {
set_block_size(cpi, mi_row, mi_col, subsize);
set_block_size(cpi, mi_row, mi_col + block_width / 2, subsize); return 1;
}
} // Check horizontal split. if (mi_col + bs_width_check <= tile->mi_col_end &&
mi_row + bs_height_horiz_check <= tile->mi_row_end) {
BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_HORZ);
BLOCK_SIZE plane_bsize =
get_plane_block_size(subsize, xd->plane[AOM_PLANE_U].subsampling_x,
xd->plane[AOM_PLANE_U].subsampling_y);
get_variance(&vt.part_variances->horz[0]);
get_variance(&vt.part_variances->horz[1]); if (vt.part_variances->horz[0].variance < threshold &&
vt.part_variances->horz[1].variance < threshold &&
plane_bsize < BLOCK_INVALID) {
set_block_size(cpi, mi_row, mi_col, subsize);
set_block_size(cpi, mi_row + block_height / 2, mi_col, subsize); return 1;
}
} return 0;
} return 0;
}
staticinlineint all_blks_inside(int x16_idx, int y16_idx, int pixels_wide, int pixels_high) { int all_inside = 1; for (int idx = 0; idx < 4; idx++) {
all_inside &= ((x16_idx + GET_BLK_IDX_X(idx, 3)) < pixels_wide);
all_inside &= ((y16_idx + GET_BLK_IDX_Y(idx, 3)) < pixels_high);
} return all_inside;
}
#if CONFIG_AV1_HIGHBITDEPTH // TODO(yunqingwang): Perform average of four 8x8 blocks similar to lowbd staticinlinevoid fill_variance_8x8avg_highbd( const uint8_t *src_buf, int src_stride, const uint8_t *dst_buf, int dst_stride, int x16_idx, int y16_idx, VP16x16 *vst, int pixels_wide, int pixels_high) { for (int idx = 0; idx < 4; idx++) { constint x8_idx = x16_idx + GET_BLK_IDX_X(idx, 3); constint y8_idx = y16_idx + GET_BLK_IDX_Y(idx, 3); unsignedint sse = 0; int sum = 0; if (x8_idx < pixels_wide && y8_idx < pixels_high) { int src_avg = aom_highbd_avg_8x8(src_buf + y8_idx * src_stride + x8_idx,
src_stride); int dst_avg = aom_highbd_avg_8x8(dst_buf + y8_idx * dst_stride + x8_idx,
dst_stride);
sum = src_avg - dst_avg;
sse = sum * sum;
}
fill_variance(sse, sum, 0, &vst->split[idx].part_variances.none);
}
} #endif
staticinlinevoid fill_variance_8x8avg_lowbd( const uint8_t *src_buf, int src_stride, const uint8_t *dst_buf, int dst_stride, int x16_idx, int y16_idx, VP16x16 *vst, int pixels_wide, int pixels_high) { unsignedint sse[4] = { 0 }; int sum[4] = { 0 };
// Obtain parameters required to calculate variance (such as sum, sse, etc,.) // at 8x8 sub-block level for a given 16x16 block. // The function can be called only when is_key_frame is false since sum is // computed between source and reference frames. staticinlinevoid fill_variance_8x8avg(const uint8_t *src_buf, int src_stride, const uint8_t *dst_buf, int dst_stride, int x16_idx, int y16_idx, VP16x16 *vst, int highbd_flag, int pixels_wide, int pixels_high) { #if CONFIG_AV1_HIGHBITDEPTH if (highbd_flag) {
fill_variance_8x8avg_highbd(src_buf, src_stride, dst_buf, dst_stride,
x16_idx, y16_idx, vst, pixels_wide,
pixels_high); return;
} #else
(void)highbd_flag; #endif// CONFIG_AV1_HIGHBITDEPTH
fill_variance_8x8avg_lowbd(src_buf, src_stride, dst_buf, dst_stride, x16_idx,
y16_idx, vst, pixels_wide, pixels_high);
}
staticint compute_minmax_8x8(const uint8_t *src_buf, int src_stride, const uint8_t *dst_buf, int dst_stride, int x16_idx, int y16_idx, #if CONFIG_AV1_HIGHBITDEPTH int highbd_flag, #endif int pixels_wide, int pixels_high) { int minmax_max = 0; int minmax_min = 255; // Loop over the 4 8x8 subblocks. for (int idx = 0; idx < 4; idx++) { constint x8_idx = x16_idx + GET_BLK_IDX_X(idx, 3); constint y8_idx = y16_idx + GET_BLK_IDX_Y(idx, 3); int min = 0; int max = 0; if (x8_idx < pixels_wide && y8_idx < pixels_high) { #if CONFIG_AV1_HIGHBITDEPTH if (highbd_flag & YV12_FLAG_HIGHBITDEPTH) {
aom_highbd_minmax_8x8(
src_buf + y8_idx * src_stride + x8_idx, src_stride,
dst_buf + y8_idx * dst_stride + x8_idx, dst_stride, &min, &max);
} else {
aom_minmax_8x8(src_buf + y8_idx * src_stride + x8_idx, src_stride,
dst_buf + y8_idx * dst_stride + x8_idx, dst_stride, &min,
&max);
} #else
aom_minmax_8x8(src_buf + y8_idx * src_stride + x8_idx, src_stride,
dst_buf + y8_idx * dst_stride + x8_idx, dst_stride, &min,
&max); #endif if ((max - min) > minmax_max) minmax_max = (max - min); if ((max - min) < minmax_min) minmax_min = (max - min);
}
} return (minmax_max - minmax_min);
}
// Function to compute average and variance of 4x4 sub-block. // The function can be called only when is_key_frame is true since sum is // computed using source frame only. staticinlinevoid fill_variance_4x4avg(const uint8_t *src_buf, int src_stride, int x8_idx, int y8_idx, VP8x8 *vst, #if CONFIG_AV1_HIGHBITDEPTH int highbd_flag, #endif int pixels_wide, int pixels_high, int border_offset_4x4) { for (int idx = 0; idx < 4; idx++) { constint x4_idx = x8_idx + GET_BLK_IDX_X(idx, 2); constint y4_idx = y8_idx + GET_BLK_IDX_Y(idx, 2); unsignedint sse = 0; int sum = 0; if (x4_idx < pixels_wide - border_offset_4x4 &&
y4_idx < pixels_high - border_offset_4x4) { int src_avg; int dst_avg = 128; #if CONFIG_AV1_HIGHBITDEPTH if (highbd_flag & YV12_FLAG_HIGHBITDEPTH) {
src_avg = aom_highbd_avg_4x4(src_buf + y4_idx * src_stride + x4_idx,
src_stride);
} else {
src_avg =
aom_avg_4x4(src_buf + y4_idx * src_stride + x4_idx, src_stride);
} #else
src_avg = aom_avg_4x4(src_buf + y4_idx * src_stride + x4_idx, src_stride); #endif
sum = src_avg - dst_avg;
sse = sum * sum;
}
fill_variance(sse, sum, 0, &vst->split[idx].part_variances.none);
}
}
static int64_t scale_part_thresh_content(int64_t threshold_base, int speed, int non_reference_frame, int is_static) {
int64_t threshold = threshold_base; if (non_reference_frame && !is_static) threshold = (3 * threshold) >> 1; if (speed >= 8) { return (5 * threshold) >> 2;
} return threshold;
}
// Tune thresholds less or more aggressively to prefer larger partitions staticinlinevoid tune_thresh_based_on_qindex(
AV1_COMP *cpi, int64_t thresholds[], uint64_t block_sad, int current_qindex, int num_pixels, bool is_segment_id_boosted, int source_sad_nonrd, int lighting_change) { double weight; if (cpi->sf.rt_sf.prefer_large_partition_blocks >= 3) { constint win = 20; if (current_qindex < QINDEX_LARGE_BLOCK_THR - win)
weight = 1.0; elseif (current_qindex > QINDEX_LARGE_BLOCK_THR + win)
weight = 0.0; else
weight =
1.0 - (current_qindex - QINDEX_LARGE_BLOCK_THR + win) / (2 * win); if (num_pixels > RESOLUTION_480P) { for (int i = 0; i < 4; i++) {
thresholds[i] <<= 1;
}
} if (num_pixels <= RESOLUTION_288P) {
thresholds[3] = INT64_MAX; if (is_segment_id_boosted == false) {
thresholds[1] <<= 2;
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.
uint64_t avg_source_sad_thresh = 25000;
uint64_t block_sad_low = 25000;
uint64_t block_sad_high = 50000; if (cpi->svc.temporal_layer_id == 0 &&
cpi->svc.number_temporal_layers > 1) { // Increase the sad thresholds for base TL0, as reference/LAST is // 2/4 frames behind (for 2/3 #TL).
avg_source_sad_thresh = 40000;
block_sad_high = 70000;
} if (is_segment_id_boosted == false &&
cpi->rc.avg_source_sad < avg_source_sad_thresh &&
block_sad > block_sad_low && block_sad < block_sad_high &&
!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 // (i.e, cpi->rc.avg_source_sad is very large, in which case all blocks // have high source sad).
} elseif (num_pixels > RESOLUTION_480P && is_segment_id_boosted == false &&
(source_sad_nonrd != kHighSad ||
cpi->rc.avg_source_sad > 50000)) {
thresholds[0] = (3 * thresholds[0]) >> 1;
thresholds[3] = INT64_MAX; if (current_qindex > QINDEX_LARGE_BLOCK_THR) {
thresholds[1] =
(int)((1 - weight) * (thresholds[1] << 1) + weight * thresholds[1]);
thresholds[2] =
(int)((1 - weight) * (thresholds[2] << 1) + weight * thresholds[2]);
}
} elseif (current_qindex > QINDEX_LARGE_BLOCK_THR &&
is_segment_id_boosted == false &&
(source_sad_nonrd != kHighSad ||
cpi->rc.avg_source_sad > 50000)) {
thresholds[1] =
(int)((1 - weight) * (thresholds[1] << 2) + weight * thresholds[1]);
thresholds[2] =
(int)((1 - weight) * (thresholds[2] << 4) + weight * thresholds[2]);
thresholds[3] = INT64_MAX;
}
} elseif (cpi->sf.rt_sf.prefer_large_partition_blocks >= 2) {
thresholds[1] <<= (source_sad_nonrd <= kLowSad) ? 2 : 0;
thresholds[2] =
(source_sad_nonrd <= kLowSad) ? (3 * thresholds[2]) : thresholds[2];
} elseif (cpi->sf.rt_sf.prefer_large_partition_blocks >= 1) { constint fac = (source_sad_nonrd <= kLowSad) ? 2 : 1; if (current_qindex < QINDEX_LARGE_BLOCK_THR - 45)
weight = 1.0; elseif (current_qindex > QINDEX_LARGE_BLOCK_THR + 45)
weight = 0.0; else
weight = 1.0 - (current_qindex - QINDEX_LARGE_BLOCK_THR + 45) / (2 * 45);
thresholds[1] =
(int)((1 - weight) * (thresholds[1] << 1) + weight * thresholds[1]);
thresholds[2] =
(int)((1 - weight) * (thresholds[2] << 1) + weight * thresholds[2]);
thresholds[3] =
(int)((1 - weight) * (thresholds[3] << fac) + weight * thresholds[3]);
} if (cpi->sf.part_sf.disable_8x8_part_based_on_qidx && (current_qindex < 128))
thresholds[3] = INT64_MAX;
}
if (mi_params->mi_cols <=
mi_col + idx64[lvl1_idx][1] + idx32[lvl2_idx][1] ||
mi_params->mi_rows <=
mi_row + idx64[lvl1_idx][0] + idx32[lvl2_idx][0]) continue; const int64_t threshold_32x32 = (5 * thresholds[2]) >> 3; if ((*mi_32)->bsize == BLOCK_32X32) { if (vt->split[lvl1_idx]
.split[lvl2_idx]
.part_variances.none.variance < threshold_32x32)
part_info->variance_low[25 + (lvl1_idx << 2) + lvl2_idx] = 1;
} else { // For 32x16 and 16x32 blocks, the flag is set on each 16x16 block // inside. if ((*mi_32)->bsize == BLOCK_16X16 ||
(*mi_32)->bsize == BLOCK_32X16 ||
(*mi_32)->bsize == BLOCK_16X32) { for (int lvl3_idx = 0; lvl3_idx < 4; lvl3_idx++) {
VPartVar *none_var = &vt->split[lvl1_idx]
.split[lvl2_idx]
.split[lvl3_idx]
.part_variances.none; if (none_var->variance < (thresholds[3] >> 8))
part_info->variance_low[41 + (lvl1_idx << 4) +
(lvl2_idx << 2) + lvl3_idx] = 1;
}
}
}
}
}
}
}
}
staticinlinevoid set_low_temp_var_flag(
AV1_COMP *cpi, PartitionSearchInfo *part_info, MACROBLOCKD *xd,
VP128x128 *vt, int64_t thresholds[], MV_REFERENCE_FRAME ref_frame_partition, int mi_col, int mi_row, constbool is_small_sb) {
AV1_COMMON *const cm = &cpi->common; // Check temporal variance for bsize >= 16x16, if LAST_FRAME was selected. // If the temporal variance is small set the flag // variance_low for the block. The variance threshold can be adjusted, the // higher the more aggressive. if (ref_frame_partition == LAST_FRAME) { if (is_small_sb)
set_low_temp_var_flag_64x64(&cm->mi_params, part_info, xd,
&(vt->split[0]), thresholds, mi_col, mi_row); else
set_low_temp_var_flag_128x128(&cm->mi_params, part_info, xd, vt,
thresholds, mi_col, mi_row);
}
}
// Use lower threshold (more conservative in setting color flag) for // higher resolutions non-screen, which tend to have more camera noise. // Since this may be used to skip compound mode in nonrd pickmode, which // is generally more effective for higher resolutions, better to be more // conservative. if (cpi->oxcf.tune_cfg.content != AOM_CONTENT_SCREEN) { if (cpi->common.width * cpi->common.height >= RESOLUTION_1080P)
fac_uv = 3; else
fac_uv = 5;
} if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
cpi->rc.high_source_sad) {
shift_lower_limit = 7;
} elseif (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
cpi->rc.percent_blocks_with_motion > 90 &&
cpi->rc.frame_source_sad > 10000 && source_sad_nonrd > kLowSad) {
shift_lower_limit = 8;
shift_upper_limit = 3;
} elseif (source_sad_nonrd >= kMedSad && x->source_variance > 500 &&
cpi->common.width * cpi->common.height >= 640 * 360) {
shift_upper_limit = 2;
shift_lower_limit = source_sad_nonrd > kMedSad ? 5 : 4;
}
staticvoid fill_variance_tree_leaves(
AV1_COMP *cpi, MACROBLOCK *x, VP128x128 *vt, PART_EVAL_STATUS *force_split, int avg_16x16[][4], int maxvar_16x16[][4], int minvar_16x16[][4],
int64_t *thresholds, const uint8_t *src_buf, int src_stride, const uint8_t *dst_buf, int dst_stride, bool is_key_frame, constbool is_small_sb) {
MACROBLOCKD *xd = &x->e_mbd; constint num_64x64_blocks = is_small_sb ? 1 : 4; // TODO(kyslov) Bring back compute_minmax_variance with content type detection constint compute_minmax_variance = 0; constint 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; // dst_buf pointer is not used for is_key_frame, so it should be NULL.
assert(IMPLIES(is_key_frame, dst_buf == NULL)); 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 blk64_idx = 0; blk64_idx < num_64x64_blocks; blk64_idx++) { constint x64_idx = GET_BLK_IDX_X(blk64_idx, 6); constint y64_idx = GET_BLK_IDX_Y(blk64_idx, 6); constint blk64_scale_idx = blk64_idx << 2;
force_split[blk64_idx + 1] = PART_EVAL_ALL;
staticinlinevoid evaluate_neighbour_mvs(AV1_COMP *cpi, MACROBLOCK *x, unsignedint *y_sad, bool is_small_sb, int est_motion) { constint source_sad_nonrd = x->content_state_sb.source_sad_nonrd; // TODO(yunqingwang@google.com): test if this condition works with other // speeds. if (est_motion > 2 && source_sad_nonrd > kMedSad) return;
int est_motion = cpi->sf.rt_sf.estimate_motion_for_var_based_partition; // TODO(b/290596301): Look into adjusting this condition. // There is regression on color content when // estimate_motion_for_var_based_partition = 3 and high motion, // so for now force it to 2 based on superblock sad. if (est_motion > 2 && source_sad_nonrd > kMedSad) est_motion = 2;
if (est_motion == 1 || est_motion == 2) { if (xd->mb_to_right_edge >= 0 && xd->mb_to_bottom_edge >= 0) { // For screen only do int_pro_motion for spatial variance above // threshold and motion level above LowSad. if (x->source_variance > 100 && source_sad_nonrd > kLowSad) { int is_screen = cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN; int me_search_size_col =
is_screen ? source_sad_nonrd > kMedSad ? 160 : 96
: block_size_wide[cm->seq_params->sb_size] >> 1; // For screen use larger search size row motion to capture // vertical scroll, which can be larger motion. int me_search_size_row =
is_screen ? source_sad_nonrd > kMedSad ? 512 : 192
: block_size_high[cm->seq_params->sb_size] >> 1; unsignedint y_sad_zero;
*y_sad = av1_int_pro_motion_estimation(
cpi, x, cm->seq_params->sb_size, mi_row, mi_col, &kZeroMv,
&y_sad_zero, me_search_size_col, me_search_size_row); // The logic below selects whether the motion estimated in the // int_pro_motion() will be used in nonrd_pickmode. Only do this // for screen for now. if (is_screen) { unsignedint thresh_sad =
(cm->seq_params->sb_size == BLOCK_128X128) ? 50000 : 20000; if (*y_sad < (y_sad_zero >> 1) && *y_sad < thresh_sad) {
x->sb_me_partition = 1;
x->sb_me_mv.as_int = mi->mv[0].as_int;
} else {
x->sb_me_partition = 0; // Fall back to using zero motion.
*y_sad = y_sad_zero;
mi->mv[0].as_int = 0;
}
}
}
}
}
// Evaluate if neighbours' MVs give better predictions. Zero MV is tested // already, so only non-zero MVs are tested here. Here the neighbour blocks // are the first block above or left to this superblock. if (est_motion >= 2 && (xd->up_available || xd->left_available))
evaluate_neighbour_mvs(cpi, x, y_sad, is_small_sb, est_motion);
*y_sad_last = *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.
set_ref_frame_for_partition(cpi, x, xd, ref_frame_partition, mi, y_sad,
y_sad_g, y_sad_alt, yv12_g, yv12_alt, mi_row,
mi_col, num_planes);
// Only calculate the predictor for non-zero MV. if (mi->mv[0].as_int != 0) { if (!scaled_ref_last) {
set_ref_ptrs(cm, xd, mi->ref_frame[0], mi->ref_frame[1]);
} else {
xd->block_ref_scale_factors[0] = sf_no_scale;
xd->block_ref_scale_factors[1] = sf_no_scale;
}
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL,
cm->seq_params->sb_size, AOM_PLANE_Y,
num_planes - 1);
}
}
// Decides whether to split or merge a 16x16 partition block in variance based // partitioning based on the 8x8 sub-block variances. staticinline PART_EVAL_STATUS get_part_eval_based_on_sub_blk_var(
VP16x16 *var_16x16_info, int64_t threshold16) { int max_8x8_var = 0, min_8x8_var = INT_MAX; for (int split_idx = 0; split_idx < 4; split_idx++) {
get_variance(&var_16x16_info->split[split_idx].part_variances.none); int this_8x8_var =
var_16x16_info->split[split_idx].part_variances.none.variance;
max_8x8_var = AOMMAX(this_8x8_var, max_8x8_var);
min_8x8_var = AOMMIN(this_8x8_var, min_8x8_var);
} // If the difference between maximum and minimum sub-block variances is high, // then only evaluate PARTITION_SPLIT for the 16x16 block. Otherwise, evaluate // only PARTITION_NONE. The shift factor for threshold16 has been derived // empirically. return ((max_8x8_var - min_8x8_var) > (threshold16 << 2))
? PART_EVAL_ONLY_SPLIT
: PART_EVAL_ONLY_NONE;
}
staticinlinebool 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) returnfalse;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.