/* * Copyright (c) 2016, 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.
*/
// 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;
}
void av1_setup_src_planes(MACROBLOCK *x, const YV12_BUFFER_CONFIG *src, int mi_row, int mi_col, constint num_planes,
BLOCK_SIZE bsize) { // Set current frame pointer.
x->e_mbd.cur_buf = src;
// We use AOMMIN(num_planes, MAX_MB_PLANE) instead of num_planes to quiet // the static analysis warnings. for (int i = 0; i < AOMMIN(num_planes, MAX_MB_PLANE); i++) { constint is_uv = i > 0;
setup_pred_plane(
&x->plane[i].src, bsize, src->buffers[i], src->crop_widths[is_uv],
src->crop_heights[is_uv], src->strides[is_uv], mi_row, mi_col, NULL,
x->e_mbd.plane[i].subsampling_x, x->e_mbd.plane[i].subsampling_y);
}
}
#if !CONFIG_REALTIME_ONLY /*!\brief Assigns different quantization parameters to each super * block based on its TPL weight. * * \ingroup tpl_modelling * * \param[in] cpi Top level encoder instance structure * \param[in,out] td Thread data structure * \param[in,out] x Macro block level data for this block. * \param[in] tile_info Tile infromation / identification * \param[in] mi_row Block row (in "MI_SIZE" units) index * \param[in] mi_col Block column (in "MI_SIZE" units) index * \param[out] num_planes Number of image planes (e.g. Y,U,V) * * \remark No return value but updates macroblock and thread data * related to the q / q delta to be used.
*/ staticinlinevoid setup_delta_q(AV1_COMP *const cpi, ThreadData *td,
MACROBLOCK *const x, const TileInfo *const tile_info, int mi_row, int mi_col, int num_planes) {
AV1_COMMON *const cm = &cpi->common; const CommonModeInfoParams *const mi_params = &cm->mi_params; const DeltaQInfo *const delta_q_info = &cm->delta_q_info;
assert(delta_q_info->delta_q_present_flag);
const BLOCK_SIZE sb_size = cm->seq_params->sb_size; // Delta-q modulation based on variance
av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, sb_size);
// 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) return 0;
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 * * \ingroup partition_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 (cm->delta_q_info.delta_q_present_flag)
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
memcpy(xd->tile_ctx, x->row_ctx, sizeof(*xd->tile_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) return 0;
// 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) return 0;
// 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) return 0;
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;
// Reset the flag.
cpi->intrabc_used = 0; // Need to disable intrabc when superres is selected if (av1_superres_scaled(cm)) {
features->allow_intrabc = 0;
}
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) { 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. const GF_GROUP *gf_group = &cpi->ppi->gf_group; if (cm->delta_q_info.delta_q_present_flag) { if (deltaq_mode == DELTA_Q_OBJECTIVE &&
gf_group->update_type[cpi->gf_frame_index] == LF_UPDATE)
cm->delta_q_info.delta_q_present_flag = 0;
// 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 * * \ingroup high_level_algo * \callgraph * \callergraph * * \param[in] cpi Top-level encoder structure
*/ 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
¤ Dauer der Verarbeitung: 0.61 Sekunden
(vorverarbeitet am 2026-04-26)
¤
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.