// For the given bit depth, returns a constant array used to assist the // calculation of source block variance, which will then be used to decide // adaptive quantizers. staticconst uint8_t *get_var_offs(int use_hbd, int bd) { #if CONFIG_AV1_HIGHBITDEPTH if (use_hbd) {
assert(bd == 8 || bd == 10 || bd == 12); constint off_index = (bd - 8) >> 1; staticconst uint16_t *high_var_offs[3] = { AV1_HIGH_VAR_OFFS_8,
AV1_HIGH_VAR_OFFS_10,
AV1_HIGH_VAR_OFFS_12 }; return CONVERT_TO_BYTEPTR(high_var_offs[off_index]);
} #else
(void)use_hbd;
(void)bd;
assert(!use_hbd); #endif
assert(bd == 8); return AV1_VAR_OFFS;
}
// pre-set the delta lf for loop filter. Note that this value is set // before mi is assigned for each block in current superblock for (int j = 0; j < AOMMIN(mib_size, mi_params->mi_rows - mi_row); j++) { for (int k = 0; k < AOMMIN(mib_size, mi_params->mi_cols - mi_col); k++) { constint grid_idx = get_mi_grid_idx(mi_params, mi_row + j, mi_col + k);
mi_params->mi_alloc[grid_idx].delta_lf_from_base = delta_lf; for (int lf_id = 0; lf_id < frame_lf_count; ++lf_id) {
mi_params->mi_alloc[grid_idx].delta_lf[lf_id] = delta_lf;
}
}
}
}
}
if (!av1_tpl_stats_ready(tpl_data, frame_idx)) return; if (!is_frame_tpl_eligible(gf_group, cpi->gf_frame_index)) return; if (cpi->oxcf.q_cfg.aq_mode != NO_AQ) return;
int cutoff_ref = 0; for (int idx = 0; idx < INTER_REFS_PER_FRAME - 1; ++idx) {
x->tpl_keep_ref_frame[rank_index[idx] + LAST_FRAME] = 1; if (idx > 2) { if (!cutoff_ref) { // If the predictive coding gains are smaller than the previous more // relevant frame over certain amount, discard this frame and all the // frames afterwards. if (llabs(inter_cost[rank_index[idx]]) <
llabs(inter_cost[rank_index[idx - 1]]) / 8 ||
inter_cost[rank_index[idx]] == 0)
cutoff_ref = 1;
}
if (cutoff_ref) x->tpl_keep_ref_frame[rank_index[idx] + LAST_FRAME] = 0;
}
}
}
staticinlinevoid adjust_rdmult_tpl_model(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col) { const BLOCK_SIZE sb_size = cpi->common.seq_params->sb_size; constint orig_rdmult = cpi->rd.RDMULT;
#if CONFIG_RT_ML_PARTITIONING // Get a prediction(stored in x->est_pred) for the whole superblock. staticvoid get_estimated_pred(AV1_COMP *cpi, const TileInfo *const tile,
MACROBLOCK *x, int mi_row, int mi_col) {
AV1_COMMON *const cm = &cpi->common; constint is_key_frame = frame_is_intra_only(cm);
MACROBLOCKD *xd = &x->e_mbd;
// TODO(kyslov) Extend to 128x128
assert(cm->seq_params->sb_size == BLOCK_64X64);
// Initialize the flag to skip cdef to 1. if (sf->rt_sf.skip_cdef_sb) { constint block64_in_sb = (sb_size == BLOCK_128X128) ? 2 : 1; // If 128x128 block is used, we need to set the flag for all 4 64x64 sub // "blocks". for (int r = 0; r < block64_in_sb; ++r) { for (int c = 0; c < block64_in_sb; ++c) { constint idx_in_sb =
r * MI_SIZE_64X64 * cm->mi_params.mi_stride + c * MI_SIZE_64X64; if (mi[idx_in_sb]) mi[idx_in_sb]->cdef_strength = 1;
}
}
}
// pre-set the delta lf for loop filter. Note that this value is set // before mi is assigned for each block in current superblock for (int j = 0; j < AOMMIN(mib_size, mi_params->mi_rows - mi_row); j++) { for (int k = 0; k < AOMMIN(mib_size, mi_params->mi_cols - mi_col); k++) { constint grid_idx = get_mi_grid_idx(mi_params, mi_row + j, mi_col + k);
mi_params->mi_alloc[grid_idx].delta_lf_from_base = delta_lf; for (int lf_id = 0; lf_id < frame_lf_count; ++lf_id) {
mi_params->mi_alloc[grid_idx].delta_lf[lf_id] = delta_lf;
}
}
}
}
// Estimate the maximum square partition block size, which will be used // as the starting block size for partitioning the sb
set_max_min_partition_size(sb_enc, cpi, x, sf, sb_size, mi_row, mi_col);
// The superblock can be searched only once, or twice consecutively for // better quality. Note that the meaning of passes here is different from // the general concept of 1-pass/2-pass encoders. constint num_passes =
cpi->oxcf.unit_test_cfg.sb_multipass_unit_test ? 2 : 1;
// Reset to 0 so that it wouldn't be used elsewhere mistakenly.
sb_enc->tpl_data_count = 0; #if CONFIG_COLLECT_COMPONENT_TIMING
end_timing(cpi, rd_pick_partition_time); #endif
} #endif// !CONFIG_REALTIME_ONLY
// Update the inter rd model // TODO(angiebird): Let inter_mode_rd_model_estimation support multi-tile. if (cpi->sf.inter_sf.inter_mode_rd_model_estimation == 1 &&
cm->tiles.cols == 1 && cm->tiles.rows == 1) {
av1_inter_mode_data_fit(tile_data, x->rdmult);
}
}
// Check if the cost update of symbols mode, coeff and dv are tile or off. staticinlineint is_mode_coeff_dv_upd_freq_tile_or_off( const AV1_COMP *const cpi) { const INTER_MODE_SPEED_FEATURES *const inter_sf = &cpi->sf.inter_sf;
// When row-mt is enabled and cost update frequencies are set to off/tile, // processing of current SB can start even before processing of top-right SB // is finished. This function checks if it is sufficient to wait for top SB // to finish processing before current SB starts processing. staticinlineint delay_wait_for_top_right_sb(const AV1_COMP *const cpi) { const MODE mode = cpi->oxcf.mode; if (mode == GOOD) return0;
/*!\brief Calculate source SAD at superblock level using 64x64 block source SAD * *\ingrouppartition_search *\callgraph *\callergraph
*/ staticinline uint64_t get_sb_source_sad(const AV1_COMP *cpi, int mi_row, int mi_col) { if (cpi->src_sad_blk_64x64 == NULL) return UINT64_MAX;
const AV1_COMMON *const cm = &cpi->common; constint blk_64x64_in_mis = (cm->seq_params->sb_size == BLOCK_128X128)
? (cm->seq_params->mib_size >> 1)
: cm->seq_params->mib_size; constint num_blk_64x64_cols =
(cm->mi_params.mi_cols + blk_64x64_in_mis - 1) / blk_64x64_in_mis; constint num_blk_64x64_rows =
(cm->mi_params.mi_rows + blk_64x64_in_mis - 1) / blk_64x64_in_mis; constint blk_64x64_col_index = mi_col / blk_64x64_in_mis; constint blk_64x64_row_index = mi_row / blk_64x64_in_mis;
uint64_t curr_sb_sad = UINT64_MAX; // Avoid the border as sad_blk_64x64 may not be set for the border // in the scene detection. if ((blk_64x64_row_index >= num_blk_64x64_rows - 1) ||
(blk_64x64_col_index >= num_blk_64x64_cols - 1)) { return curr_sb_sad;
} const uint64_t *const src_sad_blk_64x64_data =
&cpi->src_sad_blk_64x64[blk_64x64_col_index +
blk_64x64_row_index * num_blk_64x64_cols]; if (cm->seq_params->sb_size == BLOCK_128X128) { // Calculate SB source SAD by accumulating source SAD of 64x64 blocks in the // superblock
curr_sb_sad = src_sad_blk_64x64_data[0] + src_sad_blk_64x64_data[1] +
src_sad_blk_64x64_data[num_blk_64x64_cols] +
src_sad_blk_64x64_data[num_blk_64x64_cols + 1];
} elseif (cm->seq_params->sb_size == BLOCK_64X64) {
curr_sb_sad = src_sad_blk_64x64_data[0];
} return curr_sb_sad;
}
/*!\brief Determine whether grading content can be skipped based on sad stat * *\ingrouppartition_search *\callgraph *\callergraph
*/ staticinlinebool is_calc_src_content_needed(AV1_COMP *cpi,
MACROBLOCK *const x, int mi_row, int mi_col) { if (cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1) returntrue; const uint64_t curr_sb_sad = get_sb_source_sad(cpi, mi_row, mi_col); if (curr_sb_sad == UINT64_MAX) returntrue; if (curr_sb_sad == 0) {
x->content_state_sb.source_sad_nonrd = kZeroSad; returnfalse;
}
AV1_COMMON *const cm = &cpi->common; bool do_calc_src_content = true;
if (cpi->oxcf.speed < 9) return do_calc_src_content;
// TODO(yunqing): Tune/validate the thresholds for 128x128 SB size. if (AOMMIN(cm->width, cm->height) < 360) { // Derive Average 64x64 block source SAD from SB source SAD const uint64_t avg_64x64_blk_sad =
(cm->seq_params->sb_size == BLOCK_128X128) ? ((curr_sb_sad + 2) >> 2)
: curr_sb_sad;
// The threshold is determined based on kLowSad and kHighSad threshold and // test results.
uint64_t thresh_low = 15000;
uint64_t thresh_high = 40000;
if (avg_64x64_blk_sad > thresh_low && avg_64x64_blk_sad < thresh_high) {
do_calc_src_content = false; // Note: set x->content_state_sb.source_sad_rd as well if this is extended // to RTC rd path.
x->content_state_sb.source_sad_nonrd = kMedSad;
}
}
return do_calc_src_content;
}
/*!\brief Determine whether grading content is needed based on sf and frame stat * *\ingrouppartition_search *\callgraph *\callergraph
*/ // TODO(any): consolidate sfs to make interface cleaner staticinlinevoid grade_source_content_sb(AV1_COMP *cpi, MACROBLOCK *const x,
TileDataEnc *tile_data, int mi_row, int mi_col) {
AV1_COMMON *const cm = &cpi->common; if (cm->current_frame.frame_type == KEY_FRAME ||
(cpi->ppi->use_svc &&
cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame)) {
assert(x->content_state_sb.source_sad_nonrd == kMedSad);
assert(x->content_state_sb.source_sad_rd == kMedSad); return;
} bool calc_src_content = false;
// Initialize the left context for the new SB row
av1_zero_left_context(xd);
// Reset delta for quantizer and loof filters at the beginning of every tile if (mi_row == tile_info->mi_row_start || row_mt_enabled) { if (cpi->cb_delta_rdmult_enabled)
xd->current_base_qindex = cm->quant_params.base_qindex; if (cm->delta_q_info.delta_lf_present_flag) {
av1_reset_loop_filter_delta(xd, av1_num_planes(cm));
}
}
reset_thresh_freq_fact(x);
// Code each SB in the row for (int mi_col = tile_info->mi_col_start, sb_col_in_tile = 0;
mi_col < tile_info->mi_col_end; mi_col += mib_size, sb_col_in_tile++) { // In realtime/allintra mode and when frequency of cost updates is off/tile, // wait for the top superblock to finish encoding. Otherwise, wait for the // top-right superblock to finish encoding.
enc_row_mt->sync_read_ptr(
row_mt_sync, sb_row, sb_col_in_tile - delay_wait_for_top_right_sb(cpi));
#if CONFIG_MULTITHREAD if (row_mt_enabled) {
pthread_mutex_lock(enc_row_mt->mutex_); constbool row_mt_exit = enc_row_mt->row_mt_exit;
pthread_mutex_unlock(enc_row_mt->mutex_); // Exit in case any worker has encountered an error. if (row_mt_exit) return;
} #endif
constint update_cdf = tile_data->allow_update_cdf && row_mt_enabled; if (update_cdf && (tile_info->mi_row_start != mi_row)) { if ((tile_info->mi_col_start == mi_col)) { // restore frame context at the 1st column sb
*xd->tile_ctx = *x->row_ctx;
} else { // update context int wt_left = AVG_CDF_WEIGHT_LEFT; int wt_tr = AVG_CDF_WEIGHT_TOP_RIGHT; if (tile_info->mi_col_end > (mi_col + mib_size))
av1_avg_cdf_symbols(xd->tile_ctx, x->row_ctx + sb_col_in_tile,
wt_left, wt_tr); else
av1_avg_cdf_symbols(xd->tile_ctx, x->row_ctx + sb_col_in_tile - 1,
wt_left, wt_tr);
}
}
// Update the rate cost tables for some symbols
av1_set_cost_upd_freq(cpi, td, tile_info, mi_row, mi_col);
// Grade the temporal variation of the sb, the grade will be used to decide // fast mode search strategy for coding blocks if (!seg_skip) grade_source_content_sb(cpi, x, tile_data, mi_row, mi_col);
if (!is_stat_generation_stage(cpi) &&
cm->features.allow_screen_content_tools) { // Number of tokens for which token info needs to be allocated. unsignedint tokens_required =
get_token_alloc(cm->mi_params.mb_rows, cm->mi_params.mb_cols,
MAX_SB_SIZE_LOG2, num_planes); // Allocate/reallocate memory for token related info if the number of tokens // required is more than the number of tokens already allocated. This could // occur in case of the following: // 1) If the memory is not yet allocated // 2) If the frame dimensions have changed constbool realloc_tokens = tokens_required > token_info->tokens_allocated; if (realloc_tokens) {
free_token_info(token_info);
alloc_token_info(cm, token_info, tokens_required);
pre_tok = token_info->tile_tok[0][0];
tplist = token_info->tplist[0][0];
}
}
// Populate the start palette token info prior to encoding an SB row. staticinlinevoid get_token_start(AV1_COMP *cpi, const TileInfo *tile_info, int tile_row, int tile_col, int mi_row,
TokenExtra **tp) { const TokenInfo *token_info = &cpi->token_info; if (!is_token_info_allocated(token_info)) return;
// Populate the token count after encoding an SB row. staticinlinevoid populate_token_count(AV1_COMP *cpi, const TileInfo *tile_info, int tile_row, int tile_col, int mi_row,
TokenExtra *tok) { const TokenInfo *token_info = &cpi->token_info; if (!is_token_info_allocated(token_info)) return;
staticint check_skip_mode_enabled(AV1_COMP *const cpi) {
AV1_COMMON *const cm = &cpi->common;
av1_setup_skip_mode_allowed(cm); if (!cm->current_frame.skip_mode_info.skip_mode_allowed) return0;
// Turn off skip mode if the temporal distances of the reference pair to the // current frame are different by more than 1 frame. constint cur_offset = (int)cm->current_frame.order_hint; int ref_offset[2];
get_skip_mode_ref_offsets(cm, ref_offset); constint cur_to_ref0 = get_relative_dist(&cm->seq_params->order_hint_info,
cur_offset, ref_offset[0]); constint cur_to_ref1 = abs(get_relative_dist(
&cm->seq_params->order_hint_info, cur_offset, ref_offset[1])); if (abs(cur_to_ref0 - cur_to_ref1) > 1) return0;
// High Latency: Turn off skip mode if all refs are fwd. if (cpi->all_one_sided_refs && cpi->oxcf.gf_cfg.lag_in_frames > 0) return0;
/*!\cond */ typedefstruct { // Scoring function for usefulness of references (the lower score, the more // useful) int score; // Index in the reference buffer int index;
} RefScoreData; /*!\endcond */
// Determines whether a given reference frame is "good" based on temporal // distance and base_qindex. The "good" reference frames are not allowed to be // pruned by the speed feature "prune_single_ref" and "prune_comp_ref_frames" // at block level. staticinlinevoid setup_keep_ref_frame_mask(AV1_COMP *cpi) { constint prune_single_ref = cpi->sf.inter_sf.prune_single_ref; constint prune_comp_ref_frames = cpi->sf.inter_sf.prune_comp_ref_frames; const AV1_COMMON *const cm = &cpi->common;
cpi->keep_single_ref_frame_mask = 0;
cpi->keep_comp_ref_frame_mask = 0; if (frame_is_intra_only(cm)) return;
RefScoreData ref_score_data[INTER_REFS_PER_FRAME]; for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
ref_score_data[i].score = INT_MAX;
ref_score_data[i].index = i;
}
// Calculate score for each reference frame based on relative distance to // the current frame and its base_qindex. A lower score means that the // reference is potentially more useful. for (MV_REFERENCE_FRAME ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME;
++ref_frame) { if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) { const RefFrameDistanceInfo *const ref_frame_dist_info =
&cpi->ref_frame_dist_info; const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
ref_score_data[ref_frame - LAST_FRAME].score =
abs(ref_frame_dist_info->ref_relative_dist[ref_frame - LAST_FRAME]) +
buf->base_qindex;
}
}
// Decide the number of reference frames for which pruning via the speed // feature prune_single_ref is disallowed. // prune_single_ref = 0 => None of the 7 reference frames are pruned. // prune_single_ref = 1 => The best 5 reference frames are not pruned. // prune_single_ref = 2 => The best 3 reference frames are not pruned. // prune_single_ref = 3, 4 => All the 7 references are allowed to be pruned. staticconstint num_single_ref_to_keep_lookup[5] = { INTER_REFS_PER_FRAME, 5, 3, 0, 0 };
assert(prune_single_ref >= 0 && prune_single_ref <= 4); constint num_single_ref_to_keep =
num_single_ref_to_keep_lookup[prune_single_ref]; for (int i = 0; i < num_single_ref_to_keep; ++i) { constint idx = ref_score_data[i].index;
cpi->keep_single_ref_frame_mask |= 1 << idx;
}
// Decide the number of reference frame pairs for which pruning via the speed // feature "prune_comp_ref_frames" is disallowed. // prune_comp_ref_frames = 0 => None of the allowed reference frame pairs // are pruned. // prune_comp_ref_frames = 1 => The best 3 reference frame pairs are not // allowed to be pruned, i.e, reference frame // pairs with rank (1, 2), (1, 3), (2, 3) are // not pruned. // prune_comp_ref_frames = 2, 3 => All the reference frame pairs are allowed // to be pruned. staticconstint num_comp_ref_to_keep_lookup[4] = { INTER_REFS_PER_FRAME, 3, 0, 0 };
assert(prune_comp_ref_frames >= 0 && prune_comp_ref_frames <= 3); constint num_comp_ref_to_keep =
num_comp_ref_to_keep_lookup[prune_comp_ref_frames]; for (int i = 0; i < num_comp_ref_to_keep; ++i) { constint idx = ref_score_data[i].index;
cpi->keep_comp_ref_frame_mask |= 1 << idx;
}
}
if (!cpi->all_one_sided_refs) { int ref_dist[2]; for (int i = 0; i < 2; ++i) {
ref_dist[i] = av1_encoder_get_relative_dist(
ref_display_order_hint[rf[i] - LAST_FRAME],
cur_frame_display_order_hint);
}
// One-sided compound is used only when all reference frames are // one-sided. if ((ref_dist[0] > 0) == (ref_dist[1] > 0)) {
cpi->prune_ref_frame_mask |= 1 << ref_idx;
}
}
if (cpi->sf.inter_sf.selective_ref_frame >= 4 &&
(rf[0] == ALTREF2_FRAME || rf[1] == ALTREF2_FRAME) &&
(cpi->ref_frame_flags & av1_ref_frame_flag_list[BWDREF_FRAME])) { // Check if both ALTREF2_FRAME and BWDREF_FRAME are future references. if (arf2_dist > 0 && bwd_dist > 0 && bwd_dist <= arf2_dist) { // Drop ALTREF2_FRAME as a reference if BWDREF_FRAME is a closer // reference to the current frame than ALTREF2_FRAME
cpi->prune_ref_frame_mask |= 1 << ref_idx;
}
}
}
}
}
staticint allow_deltaq_mode(AV1_COMP *cpi) { #if !CONFIG_REALTIME_ONLY
AV1_COMMON *const cm = &cpi->common;
BLOCK_SIZE sb_size = cm->seq_params->sb_size; int sbs_wide = mi_size_wide[sb_size]; int sbs_high = mi_size_high[sb_size];
// Populates block level thresholds for force zeromv-skip decision staticvoid populate_thresh_to_force_zeromv_skip(AV1_COMP *cpi) { if (cpi->sf.rt_sf.part_early_exit_zeromv == 0) return;
// Threshold for forcing zeromv-skip decision is as below: // For 128x128 blocks, threshold is 10000 and per pixel threshold is 0.6103. // For 64x64 blocks, threshold is 5000 and per pixel threshold is 1.221 // allowing slightly higher error for smaller blocks. // Per Pixel Threshold of 64x64 block Area of 64x64 block 1 1 // ------------------------------------=sqrt(---------------------)=sqrt(-)=- // Per Pixel Threshold of 128x128 block Area of 128x128 block 4 2 // Thus, per pixel thresholds for blocks of size 32x32, 16x16,... can be // chosen as 2.442, 4.884,.... As the per pixel error tends to be higher for // small blocks, the same is clipped to 4. constunsignedint thresh_exit_128x128_part = FORCE_ZMV_SKIP_128X128_BLK_DIFF; constint num_128x128_pix =
block_size_wide[BLOCK_128X128] * block_size_high[BLOCK_128X128];
/*!\brief Determines delta_q_res value for Variance Boost modulation.
*/ staticint aom_get_variance_boost_delta_q_res(int qindex) { // Signaling delta_q changes across superblocks comes with inherent syntax // element overhead, which adds up to total payload size. This overhead // becomes proportionally bigger the higher the base qindex (i.e. lower // quality, smaller file size), so a balance needs to be struck. // - Smaller delta_q_res: more granular delta_q control, more bits spent // signaling deltas. // - Larger delta_q_res: coarser delta_q control, less bits spent signaling // deltas. // // At the same time, SB qindex fluctuations become larger the higher // the base qindex (between lowest and highest-variance regions): // - For QP 5: up to 8 qindexes // - For QP 60: up to 52 qindexes // // With these factors in mind, it was found that the best strategy that // maximizes quality per bitrate is by having very finely-grained delta_q // values for the lowest picture qindexes (to preserve tiny qindex SB deltas), // and progressively making them coarser as base qindex increases (to reduce // total signaling overhead). int delta_q_res = 1;
staticint is_inside_frame_border(int mi_row, int mi_col, int row_offset, int col_offset, int num_mi_rows, int num_mi_cols) { if (mi_row + row_offset < 0 || mi_row + row_offset >= num_mi_rows ||
mi_col + col_offset < 0 || mi_col + col_offset >= num_mi_cols) return0;
return1;
}
// Compute the minimum MV error between current MV and spatial MV predictors. staticint get_spatial_mvpred_err(AV1_COMMON *cm, TplParams *const tpl_data, int tpl_idx, int mi_row, int mi_col, int ref_idx, int_mv cur_mv, int allow_hp, int is_integer) { const TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx];
TplDepStats *tpl_ptr = tpl_frame->tpl_stats_ptr; const uint8_t block_mis_log2 = tpl_data->tpl_stats_block_mis_log2;
for (int i = 0; i < 8; i++) { int row_offset = mv_pred_pos_in_mis[i][0]; int col_offset = mv_pred_pos_in_mis[i][1]; if (!is_inside_frame_border(mi_row, mi_col, row_offset, col_offset,
tpl_frame->mi_rows, tpl_frame->mi_cols)) { continue;
}
// Compute the minimum MV error between current MV and temporal MV predictors. staticint get_temporal_mvpred_err(AV1_COMMON *cm, int mi_row, int mi_col, int num_mi_rows, int num_mi_cols, int ref_idx, int_mv cur_mv, int allow_hp, int is_integer) { const RefCntBuffer *ref_buf = get_ref_frame_buf(cm, ref_idx + LAST_FRAME); if (ref_buf == NULL) return INT32_MAX; int cur_to_ref_dist =
get_relative_dist(&cm->seq_params->order_hint_info,
cm->cur_frame->order_hint, ref_buf->order_hint);
// Determine whether to disable temporal MV prediction for the current frame // based on TPL and motion field data. Temporal MV prediction is disabled if the // reduction in MV error by including temporal MVs as MV predictors is small. staticvoid check_to_disable_ref_frame_mvs(AV1_COMP *cpi) {
AV1_COMMON *cm = &cpi->common; if (!cm->features.allow_ref_frame_mvs || cpi->sf.hl_sf.ref_frame_mvs_lvl != 1) return;
// Reset the flag.
cpi->intrabc_used = 0; // Need to disable intrabc when superres is selected if (av1_superres_scaled(cm)) {
features->allow_intrabc = 0;
}
av1_hash_table_init(intrabc_hash_info); if (error ||
!av1_hash_table_create(&intrabc_hash_info->intrabc_hash_table)) {
free_block_hash_buffers(block_hash_values);
aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Error allocating intrabc_hash_table and buffers");
}
hash_table_created = 1;
av1_generate_block_2x2_hash_value(cpi->source, block_hash_values[0]); // Hash data generated for screen contents is used for intraBC ME constint min_alloc_size = block_size_wide[mi_params->mi_alloc_bsize]; int max_sb_size = (1 << (cm->seq_params->mib_size_log2 + MI_SIZE_LOG2));
if (cpi->sf.mv_sf.hash_max_8x8_intrabc_blocks) {
max_sb_size = AOMMIN(8, max_sb_size);
}
cm->delta_q_info.delta_q_res = 0; if (cpi->use_ducky_encode) {
cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_DUCKY_ENCODE;
} elseif (cpi->oxcf.q_cfg.aq_mode != CYCLIC_REFRESH_AQ &&
!cpi->roi.enabled) { if (deltaq_mode == DELTA_Q_OBJECTIVE)
cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_OBJECTIVE; elseif (deltaq_mode == DELTA_Q_PERCEPTUAL)
cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_PERCEPTUAL; elseif (deltaq_mode == DELTA_Q_PERCEPTUAL_AI)
cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_PERCEPTUAL; elseif (deltaq_mode == DELTA_Q_USER_RATING_BASED)
cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_PERCEPTUAL; elseif (deltaq_mode == DELTA_Q_HDR)
cm->delta_q_info.delta_q_res = DEFAULT_DELTA_Q_RES_PERCEPTUAL; elseif (deltaq_mode == DELTA_Q_VARIANCE_BOOST)
cm->delta_q_info.delta_q_res =
aom_get_variance_boost_delta_q_res(quant_params->base_qindex); // Set delta_q_present_flag before it is used for the first time
cm->delta_q_info.delta_lf_res = DEFAULT_DELTA_LF_RES;
cm->delta_q_info.delta_q_present_flag = deltaq_mode != NO_DELTA_Q;
// Turn off cm->delta_q_info.delta_q_present_flag if objective delta_q // is used for ineligible frames. That effectively will turn off row_mt // usage. Note objective delta_q and tpl eligible frames are only altref // frames currently. if (cm->delta_q_info.delta_q_present_flag) { if (deltaq_mode == DELTA_Q_OBJECTIVE && !enable_delta_q(cpi))
cm->delta_q_info.delta_q_present_flag = 0;
cpi->prune_ref_frame_mask = 0; // Figure out which ref frames can be skipped at frame level.
setup_prune_ref_frame_mask(cpi); // Disable certain reference frame pruning based on temporal distance and // quality of that reference frame.
setup_keep_ref_frame_mask(cpi);
// Initialization of skip mode cost depends on the value of // 'skip_mode_flag'. This initialization happens in the function // av1_fill_mode_rates(), which is in turn called in // av1_initialize_rd_consts(). Thus, av1_initialize_rd_consts() // has to be called after 'skip_mode_flag' is initialized.
av1_initialize_rd_consts(cpi);
av1_set_sad_per_bit(cpi, &x->sadperbit, quant_params->base_qindex);
populate_thresh_to_force_zeromv_skip(cpi);
// If intrabc is allowed but never selected, reset the allow_intrabc flag. if (features->allow_intrabc && !cpi->intrabc_used) {
features->allow_intrabc = 0;
} if (features->allow_intrabc) {
cm->delta_q_info.delta_lf_present_flag = 0;
}
// Retain the frame level probability update conditions for parallel frames. // These conditions will be consumed during postencode stage to update the // probability. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
cpi->do_update_frame_probs_txtype[cpi->num_frame_recode] =
cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats;
cpi->do_update_frame_probs_obmc[cpi->num_frame_recode] =
(cpi->sf.inter_sf.prune_obmc_prob_thresh > 0 &&
cpi->sf.inter_sf.prune_obmc_prob_thresh < INT_MAX);
cpi->do_update_frame_probs_warp[cpi->num_frame_recode] =
(features->allow_warped_motion &&
cpi->sf.inter_sf.prune_warped_prob_thresh > 0);
cpi->do_update_frame_probs_interpfilter[cpi->num_frame_recode] =
(cm->current_frame.frame_type != KEY_FRAME &&
cpi->sf.interp_sf.adaptive_interp_filter_search == 2 &&
features->interp_filter == SWITCHABLE);
}
if (cpi->sf.tx_sf.tx_type_search.prune_tx_type_using_stats ||
((cpi->sf.tx_sf.tx_type_search.fast_inter_tx_type_prob_thresh !=
INT_MAX) &&
(cpi->sf.tx_sf.tx_type_search.fast_inter_tx_type_prob_thresh != 0))) { const FRAME_UPDATE_TYPE update_type =
get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); for (i = 0; i < TX_SIZES_ALL; i++) { int sum = 0; int j; int left = MAX_TX_TYPE_PROB;
for (j = 0; j < TX_TYPES; j++)
sum += cpi->td.rd_counts.tx_type_used[i][j];
for (j = TX_TYPES - 1; j >= 0; j--) { int update_txtype_frameprobs = 1; constint new_prob =
sum ? (int)((int64_t)MAX_TX_TYPE_PROB *
cpi->td.rd_counts.tx_type_used[i][j] / sum)
: (j ? 0 : MAX_TX_TYPE_PROB); #if CONFIG_FPMT_TEST if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { int prob =
(temp_frame_probs_simulation->tx_type_probs[update_type][i][j] +
new_prob) >> 1;
left -= prob; if (j == 0) prob += left;
temp_frame_probs_simulation->tx_type_probs[update_type][i][j] =
prob; // Copy temp_frame_probs_simulation to temp_frame_probs for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
update_type_idx++) {
temp_frame_probs->tx_type_probs[update_type_idx][i][j] =
temp_frame_probs_simulation
->tx_type_probs[update_type_idx][i][j];
}
}
update_txtype_frameprobs = 0;
} #endif// CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
update_txtype_frameprobs = 0;
cpi->frame_new_probs[cpi->num_frame_recode]
.tx_type_probs[update_type][i][j] = new_prob;
} if (update_txtype_frameprobs) { int prob =
(frame_probs->tx_type_probs[update_type][i][j] + new_prob) >> 1;
left -= prob; if (j == 0) prob += left;
frame_probs->tx_type_probs[update_type][i][j] = prob;
}
}
}
}
if (cm->seg.enabled) {
cm->seg.temporal_update = 1; if (rdc->seg_tmp_pred_cost[0] < rdc->seg_tmp_pred_cost[1])
cm->seg.temporal_update = 0;
}
for (i = 0; i < BLOCK_SIZES_ALL; i++) { int sum = 0; int update_obmc_frameprobs = 1; for (int j = 0; j < 2; j++) sum += cpi->td.rd_counts.obmc_used[i][j];
constint new_prob =
sum ? 128 * cpi->td.rd_counts.obmc_used[i][1] / sum : 0; #if CONFIG_FPMT_TEST if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) {
temp_frame_probs_simulation->obmc_probs[update_type][i] =
(temp_frame_probs_simulation->obmc_probs[update_type][i] +
new_prob) >> 1; // Copy temp_frame_probs_simulation to temp_frame_probs for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
update_type_idx++) {
temp_frame_probs->obmc_probs[update_type_idx][i] =
temp_frame_probs_simulation->obmc_probs[update_type_idx][i];
}
}
update_obmc_frameprobs = 0;
} #endif// CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
update_obmc_frameprobs = 0;
cpi->frame_new_probs[cpi->num_frame_recode].obmc_probs[update_type][i] =
new_prob;
} if (update_obmc_frameprobs) {
frame_probs->obmc_probs[update_type][i] =
(frame_probs->obmc_probs[update_type][i] + new_prob) >> 1;
}
}
}
if (features->allow_warped_motion &&
cpi->sf.inter_sf.prune_warped_prob_thresh > 0) { const FRAME_UPDATE_TYPE update_type =
get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); int update_warp_frameprobs = 1; int sum = 0; for (i = 0; i < 2; i++) sum += cpi->td.rd_counts.warped_used[i]; constint new_prob = sum ? 128 * cpi->td.rd_counts.warped_used[1] / sum : 0; #if CONFIG_FPMT_TEST if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) {
temp_frame_probs_simulation->warped_probs[update_type] =
(temp_frame_probs_simulation->warped_probs[update_type] +
new_prob) >> 1; // Copy temp_frame_probs_simulation to temp_frame_probs for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
update_type_idx++) {
temp_frame_probs->warped_probs[update_type_idx] =
temp_frame_probs_simulation->warped_probs[update_type_idx];
}
}
update_warp_frameprobs = 0;
} #endif// CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
update_warp_frameprobs = 0;
cpi->frame_new_probs[cpi->num_frame_recode].warped_probs[update_type] =
new_prob;
} if (update_warp_frameprobs) {
frame_probs->warped_probs[update_type] =
(frame_probs->warped_probs[update_type] + new_prob) >> 1;
}
}
for (i = 0; i < SWITCHABLE_FILTER_CONTEXTS; i++) { int sum = 0; int j; int left = 1536;
for (j = 0; j < SWITCHABLE_FILTERS; j++) {
sum += cpi->td.counts->switchable_interp[i][j];
}
for (j = SWITCHABLE_FILTERS - 1; j >= 0; j--) { int update_interpfilter_frameprobs = 1; constint new_prob =
sum ? 1536 * cpi->td.counts->switchable_interp[i][j] / sum
: (j ? 0 : 1536); #if CONFIG_FPMT_TEST if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) { if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) { int prob = (temp_frame_probs_simulation
->switchable_interp_probs[update_type][i][j] +
new_prob) >> 1;
left -= prob; if (j == 0) prob += left;
temp_frame_probs_simulation
->switchable_interp_probs[update_type][i][j] = prob; // Copy temp_frame_probs_simulation to temp_frame_probs for (int update_type_idx = 0; update_type_idx < FRAME_UPDATE_TYPES;
update_type_idx++) {
temp_frame_probs->switchable_interp_probs[update_type_idx][i][j] =
temp_frame_probs_simulation
->switchable_interp_probs[update_type_idx][i][j];
}
}
update_interpfilter_frameprobs = 0;
} #endif// CONFIG_FPMT_TEST // Track the frame probabilities of parallel encode frames to update // during postencode stage. if (cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) {
update_interpfilter_frameprobs = 0;
cpi->frame_new_probs[cpi->num_frame_recode]
.switchable_interp_probs[update_type][i][j] = new_prob;
} if (update_interpfilter_frameprobs) { int prob = (frame_probs->switchable_interp_probs[update_type][i][j] +
new_prob) >> 1;
left -= prob; if (j == 0) prob += left;
frame_probs->switchable_interp_probs[update_type][i][j] = prob;
}
}
}
} if (hash_table_created) {
av1_hash_table_destroy(&intrabc_hash_info->intrabc_hash_table);
}
}
/*!\brief Setup reference frame buffers and encode a frame * *\ingrouphigh_level_algo *\callgraph *\callergraph * *\param[in]cpiTop-levelencoderstructure
*/ void av1_encode_frame(AV1_COMP *cpi) {
AV1_COMMON *const cm = &cpi->common;
CurrentFrame *const current_frame = &cm->current_frame;
FeatureFlags *const features = &cm->features;
RD_COUNTS *const rdc = &cpi->td.rd_counts; const AV1EncoderConfig *const oxcf = &cpi->oxcf; // Indicates whether or not to use a default reduced set for ext-tx // rather than the potential full set of 16 transforms
features->reduced_tx_set_used = oxcf->txfm_cfg.reduced_tx_type_set;
// Make sure segment_id is no larger than last_active_segid. if (cm->seg.enabled && cm->seg.update_map) { constint mi_rows = cm->mi_params.mi_rows; constint mi_cols = cm->mi_params.mi_cols; constint last_active_segid = cm->seg.last_active_segid;
uint8_t *map = cpi->enc_seg.map; for (int mi_row = 0; mi_row < mi_rows; ++mi_row) { for (int mi_col = 0; mi_col < mi_cols; ++mi_col) {
map[mi_col] = AOMMIN(map[mi_col], last_active_segid);
}
map += mi_cols;
}
}
// If global motion is enabled, then every buffer which is used as either // a source or a ref frame should have an image pyramid allocated. // Check here so that issues can be caught early in debug mode #if !defined(NDEBUG) && !CONFIG_REALTIME_ONLY if (cpi->alloc_pyramid) {
assert(cpi->source->y_pyramid); for (int ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame); if (buf != NULL) {
assert(buf->buf.y_pyramid);
}
}
} #endif// !defined(NDEBUG) && !CONFIG_REALTIME_ONLY
if (current_frame->reference_mode == REFERENCE_MODE_SELECT) { // Use a flag that includes 4x4 blocks if (rdc->compound_ref_used_flag == 0) {
current_frame->reference_mode = SINGLE_REFERENCE; #if CONFIG_ENTROPY_STATS
av1_zero(cpi->td.counts->comp_inter); #endif// CONFIG_ENTROPY_STATS
}
} // Re-check on the skip mode status as reference mode may have been // changed.
SkipModeInfo *const skip_mode_info = ¤t_frame->skip_mode_info; if (frame_is_intra_only(cm) ||
current_frame->reference_mode == SINGLE_REFERENCE) {
skip_mode_info->skip_mode_allowed = 0;
skip_mode_info->skip_mode_flag = 0;
} if (skip_mode_info->skip_mode_flag && rdc->skip_mode_used_flag == 0)
skip_mode_info->skip_mode_flag = 0;
if (!cm->tiles.large_scale) { if (features->tx_mode == TX_MODE_SELECT &&
cpi->td.mb.txfm_search_info.txb_split_count == 0)
features->tx_mode = TX_MODE_LARGEST;
}
} else { // This is needed if real-time speed setting is changed on the fly // from one using compound prediction to one using single reference. if (current_frame->reference_mode == REFERENCE_MODE_SELECT)
current_frame->reference_mode = SINGLE_REFERENCE;
encode_frame_internal(cpi);
}
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.63Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-24)
¤
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.