/* * 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.
*/
#if !CONFIG_REALTIME_ONLY staticinlinevoid simple_motion_search_prune_part_features(
AV1_COMP *const cpi, MACROBLOCK *x, SIMPLE_MOTION_DATA_TREE *sms_tree, int mi_row, int mi_col, BLOCK_SIZE bsize, float *features, int features_to_get);
staticbool ext_ml_model_decision_before_none(
AV1_COMP *cpi, constfloat features_from_motion[FEATURE_SIZE_SMS_SPLIT], int *partition_none_allowed, int *partition_horz_allowed, int *partition_vert_allowed, int *do_rectangular_split, int *do_square_split);
staticbool ext_ml_model_decision_before_none_part2(
AV1_COMP *cpi, constfloat features_from_motion[FEATURE_SIZE_SMS_PRUNE_PART], int *prune_horz, int *prune_vert);
staticbool ext_ml_model_decision_after_none(
ExtPartController *const ext_part_controller, constint is_intra_frame, constfloat *const features_after_none, int *do_square_split, int *do_rectangular_split);
staticbool ext_ml_model_decision_after_none_part2(
AV1_COMP *const cpi, constfloat *const features_terminate, int *terminate_partition_search);
staticbool ext_ml_model_decision_after_split(
AV1_COMP *const cpi, constfloat *const features_terminate, int *terminate_partition_search);
staticbool ext_ml_model_decision_after_split_part2(
ExtPartController *const ext_part_controller, constint is_intra_frame, constfloat *const features_prune, int *prune_rect_part_horz, int *prune_rect_part_vert);
staticbool ext_ml_model_decision_after_rect(
ExtPartController *const ext_part_controller, constint is_intra_frame, constfloat *const features_after_rect, int *horza_partition_allowed, int *horzb_partition_allowed, int *verta_partition_allowed, int *vertb_partition_allowed);
staticbool ext_ml_model_decision_after_part_ab(
AV1_COMP *const cpi, MACROBLOCK *const x, BLOCK_SIZE bsize, int part_ctx,
int64_t best_rd, int64_t rect_part_rd[NUM_RECT_PARTS][SUB_PARTITIONS_RECT],
int64_t split_rd[SUB_PARTITIONS_SPLIT], int *const partition_horz4_allowed, int *const partition_vert4_allowed, unsignedint pb_source_variance, int mi_row, int mi_col);
staticinlineint convert_bsize_to_idx(BLOCK_SIZE bsize) { switch (bsize) { case BLOCK_128X128: return 0; case BLOCK_64X64: return 1; case BLOCK_32X32: return 2; case BLOCK_16X16: return 3; case BLOCK_8X8: return 4; default: assert(0 && "Invalid bsize"); return -1;
}
}
char filename[256];
snprintf(filename, sizeof(filename), "%s/%s", path,
get_feature_file_name(id));
FILE *pfile = fopen(filename, "a"); if (pfile == NULL) return; if (!is_test_mode) {
fprintf(pfile, "%d,%d,%d,%d,%d\n", id, (int)bsize, mi_row, mi_col,
feature_size);
} for (int i = 0; i < feature_size; ++i) {
fprintf(pfile, "%.6f", features[i]); if (i < feature_size - 1) fprintf(pfile, ",");
}
fprintf(pfile, "\n");
fclose(pfile);
}
// TODO(chiyotsai@google.com): This is very much a work in progress. We still // need to the following: // -- add support for hdres // -- add support for pruning rectangular partitions // -- use reconstructed pixels instead of source pixels for padding // -- use chroma pixels in addition to luma pixels staticvoid intra_mode_cnn_partition(const AV1_COMMON *const cm, MACROBLOCK *x, int quad_tree_idx, int intra_cnn_based_part_prune_level,
PartitionSearchState *part_state) {
assert(cm->seq_params->sb_size >= BLOCK_64X64 && "Invalid sb_size for intra_cnn!"); const PartitionBlkParams *blk_params = &part_state->part_blk_params; const BLOCK_SIZE bsize = blk_params->bsize;
// Precompute the CNN part and cache the result in MACROBLOCK if (bsize == BLOCK_64X64 && !part_info->cnn_output_valid) { const CNN_CONFIG *cnn_config = &av1_intra_mode_cnn_partition_cnn_config;
if (logits[0] > split_only_thresh) { // As screen contents tend to choose larger partitions, do not prune // PARTITION_NONE when intra_cnn_based_part_prune_level=1. if (intra_cnn_based_part_prune_level != 1) {
part_state->partition_none_allowed = 0;
}
part_state->do_square_split = 1;
av1_disable_rect_partitions(part_state);
}
if (logits[0] < no_split_thresh) {
av1_disable_square_split_partition(part_state);
}
}
staticinlineint get_simple_motion_search_prune_agg(int qindex, int prune_level, int is_rect_part) {
assert(prune_level < TOTAL_AGG_LVLS); if (prune_level == NO_PRUNING) { return -1;
}
// Aggressiveness value for SIMPLE_MOTION_SEARCH_PRUNE_LEVEL except // QIDX_BASED_AGG_LVL constint sms_prune_agg_levels[TOTAL_SIMPLE_AGG_LVLS] = { 0, 1, 2, 3 }; if (prune_level < TOTAL_SIMPLE_AGG_LVLS) { return sms_prune_agg_levels[prune_level];
}
// Map the QIDX_BASED_AGG_LVL to corresponding aggressiveness value. // Aggressive pruning for lower quantizers in non-boosted frames to prune // rectangular partitions. constint qband = is_rect_part ? (qindex <= 90 ? 1 : 0) : 0; constint sms_prune_agg_qindex_based[2] = { 1, 2 }; return sms_prune_agg_qindex_based[qband];
}
// Performs a simple_motion_search with a single reference frame and extract // the variance of residues. Then use the features to determine whether we want // to go straight to splitting without trying PARTITION_NONE staticvoid simple_motion_search_based_split(AV1_COMP *const cpi, MACROBLOCK *x,
SIMPLE_MOTION_DATA_TREE *sms_tree,
PartitionSearchState *part_state) { const AV1_COMMON *const cm = &cpi->common; const PartitionBlkParams *blk_params = &part_state->part_blk_params; constint mi_row = blk_params->mi_row, mi_col = blk_params->mi_col; const BLOCK_SIZE bsize = blk_params->bsize;
constint bsize_idx = convert_bsize_to_idx(bsize); constint is_720p_or_larger = AOMMIN(cm->width, cm->height) >= 720; constint is_480p_or_larger = AOMMIN(cm->width, cm->height) >= 480; // res_idx is 0 for res < 480p, 1 for 480p, 2 for 720p+ constint res_idx = is_480p_or_larger + is_720p_or_larger;
// Write features to file
write_features_to_file(cpi->oxcf.partition_info_path,
cpi->ext_part_controller.test_mode, features,
FEATURE_SIZE_SMS_SPLIT, 0, bsize, mi_row, mi_col);
// Note: it is intended to not normalize the features here, to keep it // consistent for all features collected and passed to the external model. if (ext_ml_model_decision_before_none(
cpi, features, &part_state->partition_none_allowed,
&part_state->partition_rect_allowed[HORZ],
&part_state->partition_rect_allowed[VERT],
&part_state->do_rectangular_split, &part_state->do_square_split)) { return;
}
// If the score is very low, prune rectangular split since it is unlikely to // occur. if (cpi->sf.part_sf.simple_motion_search_rect_split) { constfloat scale = res_idx >= 2 ? 3.0f : 2.0f; constfloat rect_split_thresh =
scale * av1_simple_motion_search_no_split_thresh
[cpi->sf.part_sf.simple_motion_search_rect_split][res_idx]
[bsize_idx]; if (score < rect_split_thresh) {
part_state->do_rectangular_split = 0;
}
}
}
// Given a list of ref frames in refs, performs simple_motion_search on each of // the refs and returns the ref with the smallest sse. Returns -1 if none of the // ref in the list is available. Also stores the best sse and var in best_sse, // best_var, respectively. If save_mv is 0, don't update mv_ref_fulls in // sms_tree. If save_mv is 1, update mv_ref_fulls under sms_tree and the // subtrees. staticint simple_motion_search_get_best_ref(
AV1_COMP *const cpi, MACROBLOCK *x, SIMPLE_MOTION_DATA_TREE *sms_tree, int mi_row, int mi_col, BLOCK_SIZE bsize, constint *const refs, int num_refs, int use_subpixel, int save_mv, unsignedint *best_sse, unsignedint *best_var) { const AV1_COMMON *const cm = &cpi->common; int best_ref = -1;
if (mi_col >= cm->mi_params.mi_cols || mi_row >= cm->mi_params.mi_rows) { // If the whole block is outside of the image, set the var and sse to 0.
*best_var = 0;
*best_sse = 0;
return best_ref;
}
// Otherwise do loop through the reference frames and find the one with the // minimum SSE constint num_planes = 1;
if (bsize >= BLOCK_8X8) { for (int r_idx = 0; r_idx < SUB_PARTITIONS_SPLIT; r_idx++) { // Propagate the new motion vectors to a lower level
SIMPLE_MOTION_DATA_TREE *sub_tree = sms_tree->split[r_idx];
sub_tree->start_mvs[ref] = sms_tree->start_mvs[ref];
}
}
}
}
}
return best_ref;
}
// Collects features using simple_motion_search and store them in features. The // features are also cached in SIMPLE_MOTION_DATA_TREE. By default, the features // collected are the sse and var from the subblocks flagged by features_to_get. // Furthermore, if features is not NULL, then 7 more features are appended to // the end of features: // - log(1.0 + dc_q ** 2) // - whether an above macroblock exists // - width of above macroblock // - height of above macroblock // - whether a left marcoblock exists // - width of left macroblock // - height of left macroblock staticinlinevoid simple_motion_search_prune_part_features(
AV1_COMP *const cpi, MACROBLOCK *x, SIMPLE_MOTION_DATA_TREE *sms_tree, int mi_row, int mi_col, BLOCK_SIZE bsize, float *features, int features_to_get) { constint w_mi = mi_size_wide[bsize]; constint h_mi = mi_size_high[bsize];
assert(mi_size_wide[bsize] == mi_size_high[bsize]);
assert(bsize >= BLOCK_8X8);
assert(cpi->ref_frame_flags & av1_ref_frame_flag_list[LAST_FRAME] ||
cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]);
// Performs a simple_motion_search with two reference frames and extract // the variance of residues. Then use the features to determine whether we want // to prune some partitions. staticvoid simple_motion_search_prune_rect(AV1_COMP *const cpi, MACROBLOCK *x,
SIMPLE_MOTION_DATA_TREE *sms_tree,
PartitionSearchState *part_state) { const AV1_COMMON *const cm = &cpi->common; const PartitionBlkParams *blk_params = &part_state->part_blk_params; constint mi_row = blk_params->mi_row, mi_col = blk_params->mi_col; const BLOCK_SIZE bsize = blk_params->bsize;
constint bsize_idx = convert_bsize_to_idx(bsize); constint is_720p_or_larger = AOMMIN(cm->width, cm->height) >= 720; constint is_480p_or_larger = AOMMIN(cm->width, cm->height) >= 480; // res_idx is 0 for lowres, 1 for 48p, 2 for 720p+ constint res_idx = is_480p_or_larger + is_720p_or_larger;
// Get model parameters const NN_CONFIG *nn_config =
av1_simple_motion_search_prune_rect_nn_config[bsize_idx]; constfloat *ml_mean = av1_simple_motion_search_prune_rect_mean[bsize_idx],
*ml_std = av1_simple_motion_search_prune_rect_std[bsize_idx];
// If there is no valid threshold, return immediately. if (!nn_config || prune_thresh == 0.0f) { return;
}
// Get features float features[FEATURE_SIZE_SMS_PRUNE_PART] = { 0.0f };
simple_motion_search_prune_part_features(cpi, x, sms_tree, mi_row, mi_col,
bsize, features,
FEATURE_SMS_PRUNE_PART_FLAG);
// Note: it is intended to not normalize the features here, to keep it // consistent for all features collected and passed to the external model. if (cpi->sf.part_sf.simple_motion_search_prune_rect &&
!frame_is_intra_only(cm) &&
(part_state->partition_rect_allowed[HORZ] ||
part_state->partition_rect_allowed[VERT]) &&
bsize >= BLOCK_8X8 && !av1_superres_scaled(cm)) { // Write features to file
write_features_to_file(
cpi->oxcf.partition_info_path, cpi->ext_part_controller.test_mode,
features, FEATURE_SIZE_SMS_PRUNE_PART, 1, bsize, mi_row, mi_col);
if (ext_ml_model_decision_before_none_part2(
cpi, features, &part_state->prune_rect_part[HORZ],
&part_state->prune_rect_part[VERT])) { return;
}
}
// Determine if we should prune rectangular partitions. if (probs[PARTITION_HORZ] <= prune_thresh) {
part_state->prune_rect_part[HORZ] = 1;
} if (probs[PARTITION_VERT] <= prune_thresh) {
part_state->prune_rect_part[VERT] = 1;
}
}
// Early terminates PARTITION_NONE using simple_motion_search features and the // rate, distortion, and rdcost of PARTITION_NONE. This is only called when: // - The frame is a show frame // - The frame is not intra only // - The current bsize is > BLOCK_8X8 // - blk_row + blk_height/2 < total_rows and blk_col + blk_width/2 < total_cols void av1_simple_motion_search_early_term_none(
AV1_COMP *const cpi, MACROBLOCK *x, SIMPLE_MOTION_DATA_TREE *sms_tree, const RD_STATS *none_rdc, PartitionSearchState *part_state) { const PartitionBlkParams *blk_params = &part_state->part_blk_params; constint mi_row = blk_params->mi_row, mi_col = blk_params->mi_col; const BLOCK_SIZE bsize = blk_params->bsize;
int result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; if (cpi->sf.part_sf.auto_max_partition_based_on_simple_motion ==
DIRECT_PRED) {
result = 0; float max_score = scores[0]; for (int i = 1; i < MAX_NUM_CLASSES_MAX_MIN_PART_PRED; ++i) { if (scores[i] > max_score) {
max_score = scores[i];
result = i;
}
} return get_block_size(result);
}
if (cpi->sf.part_sf.auto_max_partition_based_on_simple_motion ==
RELAXED_PRED) { for (result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; result >= 0;
--result) { if (result < MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1) {
probs[result] += probs[result + 1];
} if (probs[result] > 0.2) break;
}
} elseif (cpi->sf.part_sf.auto_max_partition_based_on_simple_motion ==
ADAPT_PRED) { const BLOCK_SIZE sb_size = cpi->common.seq_params->sb_size; // TODO(debargha): x->source_variance is unavailable at this point, // so compute. The redundant recomputation later can be removed. constunsignedint source_variance = av1_get_perpixel_variance_facade(
cpi, &x->e_mbd, &x->plane[0].src, sb_size, AOM_PLANE_Y); if (source_variance > 16) { constdouble thresh = source_variance < 128 ? 0.05 : 0.1; for (result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; result >= 0;
--result) { if (result < MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1) {
probs[result] += probs[result + 1];
} if (probs[result] > thresh) break;
}
}
}
return get_block_size(result);
}
// Get the minimum partition block width and height(in log scale) under a // SIMPLE_MOTION_DATA_TREE. staticinlinevoid get_min_bsize(const SIMPLE_MOTION_DATA_TREE *sms_tree, int *min_bw, int *min_bh) { if (!sms_tree) return;
// Write features to file
write_features_to_file(cpi->oxcf.partition_info_path,
cpi->ext_part_controller.test_mode, features, FEATURES,
4, bsize, mi_row, mi_col);
if (ext_ml_model_decision_after_split(
cpi, features, &part_state->terminate_partition_search)) { return;
}
float score = 0.0f;
av1_nn_predict(features, nn_config, 1, &score); // Score is indicator of confidence that we should NOT terminate. if (score < thresh) {
part_state->terminate_partition_search = 1;
}
} #undef FEATURES
for (int i = 0; i < SUB_PARTITIONS_SPLIT; i++)
features[5 + i] = (float)split_variance[i] / (float)whole_block_variance;
// Write features to file
write_features_to_file(cpi->oxcf.partition_info_path,
cpi->ext_part_controller.test_mode, features, /*feature_size=*/9, 5, bsize, mi_row, mi_col);
if (ext_ml_model_decision_after_split_part2(
&cpi->ext_part_controller, frame_is_intra_only(&cpi->common),
features, &part_state->prune_rect_part[HORZ],
&part_state->prune_rect_part[VERT])) { return;
}
// 2. Do the prediction and prune 0-2 partitions based on their probabilities float raw_scores[3] = { 0.0f };
av1_nn_predict(features, nn_config, 1, raw_scores); float probs[3] = { 0.0f };
av1_nn_softmax(raw_scores, probs, 3);
// probs[0] is the probability of the fact that both rectangular partitions // are worse than current best_rd if (probs[1] <= cur_thresh) part_state->prune_rect_part[HORZ] = 1; if (probs[2] <= cur_thresh) part_state->prune_rect_part[VERT] = 1;
}
// Use a ML model to predict if horz_a, horz_b, vert_a, and vert_b should be // considered. staticvoid ml_prune_ab_partition(AV1_COMP *const cpi, int part_ctx, int var_ctx, int64_t best_rd,
PartitionSearchState *part_state, int *ab_partitions_allowed) { const PartitionBlkParams blk_params = part_state->part_blk_params; constint mi_row = blk_params.mi_row; constint mi_col = blk_params.mi_col; const BLOCK_SIZE bsize = blk_params.bsize;
if (bsize < BLOCK_8X8 || best_rd >= 1000000000) return; const NN_CONFIG *nn_config = NULL; switch (bsize) { case BLOCK_8X8: nn_config = NULL; break; case BLOCK_16X16: nn_config = &av1_ab_partition_nnconfig_16; break; case BLOCK_32X32: nn_config = &av1_ab_partition_nnconfig_32; break; case BLOCK_64X64: nn_config = &av1_ab_partition_nnconfig_64; break; case BLOCK_128X128: nn_config = &av1_ab_partition_nnconfig_128; break; default: assert(0 && "Unexpected bsize.");
} if (!nn_config) return;
// Generate features. float features[10]; int feature_index = 0;
features[feature_index++] = (float)part_ctx;
features[feature_index++] = (float)var_ctx; constint rdcost = (int)AOMMIN(INT_MAX, best_rd); int sub_block_rdcost[8] = { 0 }; int rd_index = 0; for (int i = 0; i < SUB_PARTITIONS_RECT; ++i) { const int64_t *horz_rd = part_state->rect_part_rd[HORZ]; if (horz_rd[i] > 0 && horz_rd[i] < 1000000000)
sub_block_rdcost[rd_index] = (int)horz_rd[i];
++rd_index;
} for (int i = 0; i < SUB_PARTITIONS_RECT; ++i) { const int64_t *vert_rd = part_state->rect_part_rd[VERT]; if (vert_rd[i] > 0 && vert_rd[i] < 1000000000)
sub_block_rdcost[rd_index] = (int)vert_rd[i];
++rd_index;
} for (int i = 0; i < SUB_PARTITIONS_SPLIT; ++i) { const int64_t *split_rd = part_state->split_rd; if (split_rd[i] > 0 && split_rd[i] < 1000000000)
sub_block_rdcost[rd_index] = (int)split_rd[i];
++rd_index;
} for (int i = 0; i < 8; ++i) { // Ratio between the sub-block RD and the whole-block RD. float rd_ratio = 1.0f; if (sub_block_rdcost[i] > 0 && sub_block_rdcost[i] < rdcost)
rd_ratio = (float)sub_block_rdcost[i] / (float)rdcost;
features[feature_index++] = rd_ratio;
}
assert(feature_index == 10);
// Write features to file if (!frame_is_intra_only(&cpi->common)) {
write_features_to_file(cpi->oxcf.partition_info_path,
cpi->ext_part_controller.test_mode, features, /*feature_size=*/10, 6, bsize, mi_row, mi_col);
}
// Calculate scores using the NN model. float score[16] = { 0.0f };
av1_nn_predict(features, nn_config, 1, score); int int_score[16]; int max_score = -1000; for (int i = 0; i < 16; ++i) {
int_score[i] = (int)(100 * score[i]);
max_score = AOMMAX(int_score[i], max_score);
}
// Make decisions based on the model scores. int thresh = max_score; switch (bsize) { case BLOCK_16X16: thresh -= 150; break; case BLOCK_32X32: thresh -= 100; break; default: break;
}
av1_zero_array(ab_partitions_allowed, NUM_AB_PARTS); for (int i = 0; i < 16; ++i) { if (int_score[i] >= thresh) { if ((i >> 0) & 1) ab_partitions_allowed[HORZ_A] = 1; if ((i >> 1) & 1) ab_partitions_allowed[HORZ_B] = 1; if ((i >> 2) & 1) ab_partitions_allowed[VERT_A] = 1; if ((i >> 3) & 1) ab_partitions_allowed[VERT_B] = 1;
}
}
}
#define FEATURES 18 #define LABELS 4 // Use a ML model to predict if horz4 and vert4 should be considered. void av1_ml_prune_4_partition(AV1_COMP *const cpi, MACROBLOCK *const x, int part_ctx, int64_t best_rd,
PartitionSearchState *part_state, int *part4_allowed, unsignedint pb_source_variance) { const PartitionBlkParams blk_params = part_state->part_blk_params; constint mi_row = blk_params.mi_row; constint mi_col = blk_params.mi_col; const BLOCK_SIZE bsize = blk_params.bsize;
constfloat denom = (float)(pb_source_variance + 1); constfloat low_b = 0.1f; constfloat high_b = 10.0f; for (int i = 0; i < SUB_PARTITIONS_PART4; ++i) { // Ratio between the 4:1 sub-block variance and the whole-block variance. float var_ratio = (float)(horz_4_source_var[i] + 1) / denom; if (var_ratio < low_b) var_ratio = low_b; if (var_ratio > high_b) var_ratio = high_b;
features[feature_index++] = var_ratio;
} for (int i = 0; i < SUB_PARTITIONS_PART4; ++i) { // Ratio between the 1:4 sub-block RD and the whole-block RD. float var_ratio = (float)(vert_4_source_var[i] + 1) / denom; if (var_ratio < low_b) var_ratio = low_b; if (var_ratio > high_b) var_ratio = high_b;
features[feature_index++] = var_ratio;
}
assert(feature_index == FEATURES);
// Write features to file if (!frame_is_intra_only(&cpi->common)) {
write_features_to_file(cpi->oxcf.partition_info_path,
cpi->ext_part_controller.test_mode, features,
FEATURES, 7, bsize, mi_row, mi_col);
}
// Calculate scores using the NN model. float score[LABELS] = { 0.0f };
av1_nn_predict(features, nn_config, 1, score); int int_score[LABELS]; int max_score = -1000; for (int i = 0; i < LABELS; ++i) {
int_score[i] = (int)(100 * score[i]);
max_score = AOMMAX(int_score[i], max_score);
}
// Make decisions based on the model scores. int thresh = max_score; switch (bsize) { case BLOCK_16X16: thresh -= 500; break; case BLOCK_32X32: thresh -= 500; break; case BLOCK_64X64: thresh -= 200; break; default: break;
}
av1_zero_array(part4_allowed, NUM_PART4_TYPES); for (int i = 0; i < LABELS; ++i) { if (int_score[i] >= thresh) { if ((i >> 0) & 1) part4_allowed[HORZ4] = 1; if ((i >> 1) & 1) part4_allowed[VERT4] = 1;
}
}
} #undef FEATURES #undef LABELS
if (!is_edge && block_size_wide[bsize] >= 16) { // If in second pass we used rectangular partition, then do not search for // rectangular partition in the different direction. if (third_pass_part != PARTITION_NONE) { if (third_pass_part == PARTITION_HORZ ||
third_pass_part == PARTITION_HORZ_4 ||
third_pass_part == PARTITION_HORZ_A ||
third_pass_part == PARTITION_HORZ_B) {
part_state->partition_rect_allowed[VERT] = 0;
} elseif (third_pass_part == PARTITION_VERT ||
third_pass_part == PARTITION_VERT_4 ||
third_pass_part == PARTITION_VERT_A ||
third_pass_part == PARTITION_VERT_B) {
part_state->partition_rect_allowed[HORZ] = 0;
}
}
int minSize = AOMMIN(block_size_wide[third_pass_bsize],
block_size_high[third_pass_bsize]); int maxSize = AOMMAX(block_size_wide[third_pass_bsize],
block_size_high[third_pass_bsize]); if (block_size_wide[bsize] < minSize / 4) { // Current partition is too small, just terminate
part_state->terminate_partition_search = 1; return;
} elseif (block_size_wide[bsize] < minSize / 2) { if (third_pass_part != PARTITION_NONE) { // Current partition is very small, and in second pass we used // rectangular partition. Terminate the search here then.
part_state->terminate_partition_search = 1; return;
} else { // Partition is small, but we still check this partition, only disable // further splits. // TODO(any): check why this is not covered by the termination for < // minSize/4.
av1_disable_square_split_partition(part_state);
av1_disable_rect_partitions(part_state); return;
}
} elseif (block_size_wide[bsize] > maxSize) { // Partition is larger than in the second pass. Only allow split.
av1_set_square_split_only(part_state); return;
} elseif (block_size_wide[bsize] >= minSize &&
block_size_wide[bsize] <= maxSize) { // Partition is within a range where it is very likely to find a good // choice, so do not prune anything. return;
}
}
} #endif// CONFIG_THREE_PASS
// Prune rectangular, AB and 4-way partition based on q index and block size if (cpi->sf.part_sf.prune_rectangular_split_based_on_qidx == 1) { if (bsize == BLOCK_8X8 && x->qindex < 35)
av1_disable_rect_partitions(part_state);
// Prune partition // qidx 0 to 85: prune bsize below BLOCK_32X32 // qidx 86 to 170: prune bsize below BLOCK_16X16 // qidx 171 to 255: prune bsize below BLOCK_8X8 if (bsize < max_prune_bsize) {
av1_disable_rect_partitions(part_state);
}
}
if (cpi->sf.part_sf.prune_sub_8x8_partition_level && (bsize == BLOCK_8X8)) { const MACROBLOCKD *const xd = &x->e_mbd; int prune_sub_8x8; if (cpi->sf.part_sf.prune_sub_8x8_partition_level == 2) {
prune_sub_8x8 = 1;
} else {
assert(cpi->sf.part_sf.prune_sub_8x8_partition_level == 1); // Prune if both neighbors are available and either is > BLOCK_8X8
prune_sub_8x8 = xd->left_available && xd->up_available &&
(xd->left_mbmi->bsize > BLOCK_8X8 ||
xd->above_mbmi->bsize > BLOCK_8X8);
} if (prune_sub_8x8) {
av1_disable_all_splits(part_state);
}
}
// A CNN-based speed feature pruning out either split or all non-split // partition in INTRA frame coding. constint try_intra_cnn_based_part_prune =
frame_is_intra_only(cm) &&
cpi->sf.part_sf.intra_cnn_based_part_prune_level &&
cm->seq_params->sb_size >= BLOCK_64X64 && bsize <= BLOCK_64X64 &&
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.21 Sekunden
(vorverarbeitet)
¤
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.