/* * Copyright (c) 2020, 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.
*/
// Disable and clear down for KF if (cm->current_frame.frame_type == KEY_FRAME) { // Clear down the global segmentation map
memset(cpi->enc_seg.map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols);
seg->update_map = 0;
seg->update_data = 0;
// Clear down the segment features.
av1_clearall_segfeatures(seg);
} elseif (cpi->refresh_frame.alt_ref_frame) { // If this is an alt ref frame // Clear down the global segmentation map
memset(cpi->enc_seg.map, 0, cm->mi_params.mi_rows * cm->mi_params.mi_cols);
seg->update_map = 0;
seg->update_data = 0;
// Disable segmentation and individual segment features by default
av1_disable_segmentation(seg);
av1_clearall_segfeatures(seg);
// If segmentation was enabled set those features needed for the // arf itself. if (seg->enabled) {
seg->update_map = 1;
seg->update_data = 1;
av1_enable_segfeature(seg, 1, SEG_LVL_ALT_Q);
}
} elseif (seg->enabled) { // All other frames if segmentation has been enabled
// First normal frame in a valid gf or alt ref group if (rc->frames_since_golden == 0) { // Set up segment features for normal frames in an arf group // Disable segmentation and clear down features if alt ref // is not active for this group
av1_clearall_segfeatures(seg);
} elseif (rc->is_src_frame_alt_ref) { // Special case where we are coding over the top of a previous // alt ref frame. // Segment coding disabled for compred testing
// Enable ref frame features for segment 0 as well
av1_enable_segfeature(seg, 0, SEG_LVL_REF_FRAME);
av1_enable_segfeature(seg, 1, SEG_LVL_REF_FRAME);
// All mbs should use ALTREF_FRAME
av1_clear_segdata(seg, 0, SEG_LVL_REF_FRAME);
av1_set_segdata(seg, 0, SEG_LVL_REF_FRAME, ALTREF_FRAME);
av1_clear_segdata(seg, 1, SEG_LVL_REF_FRAME);
av1_set_segdata(seg, 1, SEG_LVL_REF_FRAME, ALTREF_FRAME);
// Skip all MBs if high Q (0,0 mv and skip coeffs) if (high_q) {
av1_enable_segfeature(seg, 0, SEG_LVL_SKIP);
av1_enable_segfeature(seg, 1, SEG_LVL_SKIP);
} // Enable data update
seg->update_data = 1;
} else { // All other frames.
// No updates.. leave things as they are.
seg->update_map = 0;
seg->update_data = 0;
}
}
}
// Disable the active_maps on intra_only frames or if the // input map for the current frame has no inactive blocks. if (frame_is_intra_only(&cpi->common) ||
cpi->rc.percent_blocks_inactive == 0) {
cpi->active_map.enabled = 0;
cpi->active_map.update = 1;
}
if (mc_dep_cost_base == 0) {
tpl_frame->is_valid = 0;
} else {
cpi->rd.r0 = exp((intra_cost_base - mc_dep_cost_base) / cbcmp_base); if (is_frame_tpl_eligible(gf_group, cpi->gf_frame_index)) { if (cpi->ppi->lap_enabled) { double min_boost_factor = sqrt(cpi->ppi->p_rc.baseline_gf_interval); constint gfu_boost = get_gfu_boost_from_r0_lap(
min_boost_factor, MAX_GFUBOOST_FACTOR, cpi->rd.r0,
cpi->ppi->p_rc.num_stats_required_for_gfu_boost); // printf("old boost %d new boost %d\n", cpi->rc.gfu_boost, // gfu_boost);
cpi->ppi->p_rc.gfu_boost = combine_prior_with_tpl_boost(
min_boost_factor, MAX_BOOST_COMBINE_FACTOR,
cpi->ppi->p_rc.gfu_boost, gfu_boost,
cpi->ppi->p_rc.num_stats_used_for_gfu_boost);
} else { // TPL may only look at a subset of frame in the gf group when the // speed feature 'reduce_num_frames' is on, which affects the r0 // calcuation. Thus, to compensate for TPL not using all frames a // factor to adjust r0 is used. constint gfu_boost =
(int)(200.0 * cpi->ppi->tpl_data.r0_adjust_factor / cpi->rd.r0);
cpi->ppi->p_rc.gfu_boost = combine_prior_with_tpl_boost(
MIN_BOOST_COMBINE_FACTOR, MAX_BOOST_COMBINE_FACTOR,
cpi->ppi->p_rc.gfu_boost, gfu_boost, cpi->rc.frames_to_key);
}
}
}
}
} #endif// !CONFIG_REALTIME_ONLY
void av1_set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index, int *top_index) {
AV1_COMMON *const cm = &cpi->common;
// Setup variables that depend on the dimensions of the frame.
av1_set_speed_features_framesize_dependent(cpi, cpi->speed);
// Configure experimental use of segmentation for enhanced coding of // static regions if indicated. // Only allowed in the second pass of a two pass encode, as it requires // lagged coding, and if the relevant speed feature flag is set. if (is_stat_consumption_stage_twopass(cpi) &&
cpi->sf.hl_sf.static_segmentation)
configure_static_seg_features(cpi);
}
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) { // Need to convert from AOM_REFFRAME to index into ref_mask (subtract 1). if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref_frame]) {
BufferPool *const pool = cm->buffer_pool; const YV12_BUFFER_CONFIG *const ref =
get_ref_frame_yv12_buf(cm, ref_frame);
// For RTC-SVC: if force_zero_mode_spatial_ref is enabled, check if the // motion search can be skipped for the references: last, golden, altref. // If so, we can skip scaling that reference. if (cpi->ppi->use_svc && cpi->svc.force_zero_mode_spatial_ref &&
cpi->ppi->rtc_ref.set_ref_frame_config) { if (ref_frame == LAST_FRAME && cpi->svc.skip_mvsearch_last) continue; if (ref_frame == GOLDEN_FRAME && cpi->svc.skip_mvsearch_gf) continue; if (ref_frame == ALTREF_FRAME && cpi->svc.skip_mvsearch_altref) continue;
} // For RTC with superres on: golden reference only needs to be scaled // if it was refreshed in previous frame. if (is_one_pass_rt_params(cpi) &&
cpi->oxcf.superres_cfg.enable_superres && ref_frame == GOLDEN_FRAME &&
cpi->rc.frame_num_last_gf_refresh <
(int)cm->current_frame.frame_number - 1) { continue;
}
if (ref->y_crop_width != cm->width || ref->y_crop_height != cm->height) { // Replace the reference buffer with a copy having a thicker border, // if the reference buffer is higher resolution than the current // frame, and the border is thin. if ((ref->y_crop_width > cm->width ||
ref->y_crop_height > cm->height) &&
ref->border < AOM_BORDER_IN_PIXELS) {
RefCntBuffer *ref_fb = get_ref_frame_buf(cm, ref_frame); if (aom_yv12_realloc_with_new_border(
&ref_fb->buf, AOM_BORDER_IN_PIXELS,
cm->features.byte_alignment, cpi->alloc_pyramid,
num_planes) != 0) {
aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Failed to allocate frame buffer");
}
} int force_scaling = 0;
RefCntBuffer *new_fb = cpi->scaled_ref_buf[ref_frame - 1]; if (new_fb == NULL) { constint new_fb_idx = get_free_fb(cm); if (new_fb_idx == INVALID_IDX) {
aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR, "Unable to find free frame buffer");
}
force_scaling = 1;
new_fb = &pool->frame_bufs[new_fb_idx];
}
BLOCK_SIZE av1_select_sb_size(const AV1EncoderConfig *const oxcf, int width, int height, int number_spatial_layers) { if (oxcf->tool_cfg.superblock_size == AOM_SUPERBLOCK_SIZE_64X64) { return BLOCK_64X64;
} if (oxcf->tool_cfg.superblock_size == AOM_SUPERBLOCK_SIZE_128X128) { return BLOCK_128X128;
} #if CONFIG_TFLITE if (oxcf->q_cfg.deltaq_mode == DELTA_Q_USER_RATING_BASED) return BLOCK_64X64; #endif // Force 64x64 superblock size to increase resolution in perceptual // AQ and user rating based modes. if (oxcf->mode == ALLINTRA &&
(oxcf->q_cfg.deltaq_mode == DELTA_Q_PERCEPTUAL_AI ||
oxcf->q_cfg.deltaq_mode == DELTA_Q_USER_RATING_BASED)) { return BLOCK_64X64;
} // Variance Boost only supports 64x64 superblocks. if (oxcf->q_cfg.deltaq_mode == DELTA_Q_VARIANCE_BOOST) { return BLOCK_64X64;
}
assert(oxcf->tool_cfg.superblock_size == AOM_SUPERBLOCK_SIZE_DYNAMIC);
if (number_spatial_layers > 1 ||
oxcf->resize_cfg.resize_mode != RESIZE_NONE) { // Use the configured size (top resolution) for spatial layers or // on resize. return AOMMIN(oxcf->frm_dim_cfg.width, oxcf->frm_dim_cfg.height) > 720
? BLOCK_128X128
: BLOCK_64X64;
} elseif (oxcf->mode == REALTIME) { if (oxcf->tune_cfg.content == AOM_CONTENT_SCREEN) { const TileConfig *const tile_cfg = &oxcf->tile_cfg; constint num_tiles =
(1 << tile_cfg->tile_columns) * (1 << tile_cfg->tile_rows); // For multi-thread encode: if the number of (128x128) superblocks // per tile is low use 64X64 superblock. if (oxcf->row_mt == 1 && oxcf->max_threads >= 4 &&
oxcf->max_threads >= num_tiles && AOMMIN(width, height) >= 720 &&
(width * height) / (128 * 128 * num_tiles) < 40) return BLOCK_64X64; else return AOMMIN(width, height) >= 720 ? BLOCK_128X128 : BLOCK_64X64;
} else { return AOMMIN(width, height) > 720 ? BLOCK_128X128 : BLOCK_64X64;
}
}
// TODO(any): Possibly could improve this with a heuristic. // When superres / resize is on, 'cm->width / height' can change between // calls, so we don't apply this heuristic there. // Things break if superblock size changes between the first pass and second // pass encoding, which is why this heuristic is not configured as a // speed-feature. if (oxcf->superres_cfg.superres_mode == AOM_SUPERRES_NONE &&
oxcf->resize_cfg.resize_mode == RESIZE_NONE) { int is_480p_or_lesser = AOMMIN(width, height) <= 480; if (oxcf->speed >= 1 && is_480p_or_lesser) return BLOCK_64X64;
// For 1080p and lower resolutions, choose SB size adaptively based on // resolution and speed level for multi-thread encode. int is_1080p_or_lesser = AOMMIN(width, height) <= 1080; if (!is_480p_or_lesser && is_1080p_or_lesser && oxcf->mode == GOOD &&
oxcf->row_mt == 1 && oxcf->max_threads > 1 && oxcf->speed >= 5) return BLOCK_64X64;
// For allintra encode, since the maximum partition size is set to 32X32 for // speed>=6, superblock size is set to 64X64 instead of 128X128. This // improves the multithread performance due to reduction in top right delay // and thread sync wastage. Currently, this setting is selectively enabled // only for speed>=9 and resolutions less than 4k since cost update // frequency is set to INTERNAL_COST_UPD_OFF in these cases. constint is_4k_or_larger = AOMMIN(width, height) >= 2160; if (oxcf->mode == ALLINTRA && oxcf->speed >= 9 && !is_4k_or_larger) return BLOCK_64X64;
} return BLOCK_128X128;
}
void av1_setup_frame(AV1_COMP *cpi) {
AV1_COMMON *const cm = &cpi->common; // Set up entropy context depending on frame type. The decoder mandates // the use of the default context, index 0, for keyframes and inter // frames where the error_resilient_mode or intra_only flag is set. For // other inter-frames the encoder currently uses only two contexts; // context 1 for ALTREF frames and context 0 for the others.
if (frame_is_intra_only(cm) || cm->features.error_resilient_mode ||
cpi->ext_flags.use_primary_ref_none) {
av1_setup_past_independence(cm);
}
#define STRICT_PSNR_DIFF_THRESH 0.9 // Encode key frame with/without screen content tools to determine whether // screen content tools should be enabled for this key frame group or not. // The first encoding is without screen content tools. // The second encoding is with screen content tools. // We compare the psnr and frame size to make the decision. staticvoid screen_content_tools_determination(
AV1_COMP *cpi, constint allow_screen_content_tools_orig_decision, constint allow_intrabc_orig_decision, constint use_screen_content_tools_orig_decision, constint is_screen_content_type_orig_decision, constint pass, int *projected_size_pass, PSNR_STATS *psnr) {
AV1_COMMON *const cm = &cpi->common;
FeatureFlags *const features = &cm->features;
constdouble psnr_diff = psnr[1].psnr[0] - psnr[0].psnr[0]; // Calculate % of palette mode to be chosen in a frame from mode decision. constdouble palette_ratio =
(double)cpi->palette_pixel_num / (double)(cm->height * cm->width); constint psnr_diff_is_large = (psnr_diff > STRICT_PSNR_DIFF_THRESH); constint ratio_is_large =
((palette_ratio >= 0.0001) && ((psnr_diff / palette_ratio) > 4)); constint is_sc_encoding_much_better = (psnr_diff_is_large || ratio_is_large); if (is_sc_encoding_much_better) { // Use screen content tools, if we get coding gain.
features->allow_screen_content_tools = 1;
features->allow_intrabc = cpi->intrabc_used;
cpi->use_screen_content_tools = 1;
cpi->is_screen_content_type = 1;
} else { // Use original screen content decision.
features->allow_screen_content_tools =
allow_screen_content_tools_orig_decision;
features->allow_intrabc = allow_intrabc_orig_decision;
cpi->use_screen_content_tools = use_screen_content_tools_orig_decision;
cpi->is_screen_content_type = is_screen_content_type_orig_decision;
}
}
// Set some encoding parameters to make the encoding process fast. // A fixed block partition size, and a large q is used. staticvoid set_encoding_params_for_screen_content(AV1_COMP *cpi, constint pass) {
AV1_COMMON *const cm = &cpi->common; if (pass == 0) { // In the first pass, encode without screen content tools. // Use a high q, and a fixed block size for fast encoding.
cm->features.allow_screen_content_tools = 0;
cm->features.allow_intrabc = 0;
cpi->use_screen_content_tools = 0;
cpi->sf.part_sf.partition_search_type = FIXED_PARTITION;
cpi->sf.part_sf.fixed_partition_size = BLOCK_32X32; return;
}
assert(pass == 1); // In the second pass, encode with screen content tools. // Use a high q, and a fixed block size for fast encoding.
cm->features.allow_screen_content_tools = 1; // TODO(chengchen): turn intrabc on could lead to data race issue. // cm->allow_intrabc = 1;
cpi->use_screen_content_tools = 1;
cpi->sf.part_sf.partition_search_type = FIXED_PARTITION;
cpi->sf.part_sf.fixed_partition_size = BLOCK_32X32;
}
// Determines whether to use screen content tools for the key frame group. // This function modifies "cm->features.allow_screen_content_tools", // "cm->features.allow_intrabc" and "cpi->use_screen_content_tools". void av1_determine_sc_tools_with_encoding(AV1_COMP *cpi, constint q_orig) {
AV1_COMMON *const cm = &cpi->common; const AV1EncoderConfig *const oxcf = &cpi->oxcf; const QuantizationCfg *const q_cfg = &oxcf->q_cfg; // Variables to help determine if we should allow screen content tools. int projected_size_pass[3] = { 0 };
PSNR_STATS psnr[3]; constint is_key_frame = cm->current_frame.frame_type == KEY_FRAME; constint allow_screen_content_tools_orig_decision =
cm->features.allow_screen_content_tools; constint allow_intrabc_orig_decision = cm->features.allow_intrabc; constint use_screen_content_tools_orig_decision =
cpi->use_screen_content_tools; constint is_screen_content_type_orig_decision = cpi->is_screen_content_type; // Turn off the encoding trial for forward key frame and superres. if (cpi->sf.rt_sf.use_nonrd_pick_mode || oxcf->kf_cfg.fwd_kf_enabled ||
cpi->superres_mode != AOM_SUPERRES_NONE || oxcf->mode == REALTIME ||
use_screen_content_tools_orig_decision || !is_key_frame) { return;
}
// TODO(chengchen): multiple encoding for the lossless mode is time consuming. // Find a better way to determine whether screen content tools should be used // for lossless coding. // Use a high q and a fixed partition to do quick encoding. constint q_for_screen_content_quick_run =
is_lossless_requested(&oxcf->rc_cfg) ? q_orig : AOMMAX(q_orig, 244); constint partition_search_type_orig = cpi->sf.part_sf.partition_search_type; const BLOCK_SIZE fixed_partition_block_size_orig =
cpi->sf.part_sf.fixed_partition_size;
// Setup necessary params for encoding, including frame source, etc.
cpi->source = av1_realloc_and_scale_if_required(
cm, cpi->unscaled_source, &cpi->scaled_source, cm->features.interp_filter,
0, false, false, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid); if (cpi->unscaled_last_source != NULL) {
cpi->last_source = av1_realloc_and_scale_if_required(
cm, cpi->unscaled_last_source, &cpi->scaled_last_source,
cm->features.interp_filter, 0, false, false, cpi->oxcf.border_in_pixels,
cpi->alloc_pyramid);
}
// The two encoding passes aim to help determine whether to use screen // content tools, with a high q and fixed partition. for (int pass = 0; pass < 2; ++pass) {
set_encoding_params_for_screen_content(cpi, pass);
av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel,
q_for_screen_content_quick_run,
q_cfg->enable_chroma_deltaq, q_cfg->enable_hdr_deltaq,
oxcf->mode == ALLINTRA, oxcf->tune_cfg.tuning);
av1_set_speed_features_qindex_dependent(cpi, oxcf->speed);
av1_init_quantizer(&cpi->enc_quant_dequant_params, &cm->quant_params,
cm->seq_params->bit_depth);
// Free token related info if screen content coding tools are not enabled. if (!cm->features.allow_screen_content_tools)
free_token_info(&cpi->token_info);
} #endif// CONFIG_REALTIME_ONLY
staticvoid fix_interp_filter(InterpFilter *const interp_filter, const FRAME_COUNTS *const counts) { if (*interp_filter == SWITCHABLE) { // Check to see if only one of the filters is actually used int count[SWITCHABLE_FILTERS] = { 0 }; int num_filters_used = 0; for (int i = 0; i < SWITCHABLE_FILTERS; ++i) { for (int j = 0; j < SWITCHABLE_FILTER_CONTEXTS; ++j)
count[i] += counts->switchable_interp[j][i];
num_filters_used += (count[i] > 0);
} if (num_filters_used == 1) { // Only one filter is used. So set the filter at frame level for (int i = 0; i < SWITCHABLE_FILTERS; ++i) { if (count[i]) {
*interp_filter = i; break;
}
}
}
}
}
if (!cm->seq_params->reduced_still_picture_hdr &&
encode_show_existing_frame(cm)) {
RefCntBuffer *const frame_to_show =
cm->ref_frame_map[cpi->existing_fb_idx_to_show];
if (frame_to_show == NULL) {
aom_internal_error(cm->error, AOM_CODEC_UNSUP_BITSTREAM, "Buffer does not contain a reconstructed frame");
}
assert(frame_to_show->ref_count > 0);
assign_frame_buffer_p(&cm->cur_frame, frame_to_show);
}
if (!encode_show_existing_frame(cm) &&
cm->seq_params->film_grain_params_present &&
(cm->show_frame || cm->showable_frame)) { // Copy the current frame's film grain params to the its corresponding // RefCntBuffer slot.
cm->cur_frame->film_grain_params = cm->film_grain_params;
// We must update the parameters if this is not an INTER_FRAME if (current_frame->frame_type != INTER_FRAME)
cm->cur_frame->film_grain_params.update_parameters = 1;
// Iterate the random seed for the next frame.
cm->film_grain_params.random_seed += 3381; if (cm->film_grain_params.random_seed == 0)
cm->film_grain_params.random_seed = 7391;
}
// Initialise all tiles' contexts from the global frame context for (int tile_col = 0; tile_col < cm->tiles.cols; tile_col++) { for (int tile_row = 0; tile_row < cm->tiles.rows; tile_row++) { constint tile_idx = tile_row * cm->tiles.cols + tile_col;
cpi->tile_data[tile_idx].tctx = *cm->fc;
}
}
if (!frame_is_intra_only(cm))
fix_interp_filter(&cm->features.interp_filter, cpi->td.counts);
}
int av1_is_integer_mv(const YV12_BUFFER_CONFIG *cur_picture, const YV12_BUFFER_CONFIG *last_picture,
ForceIntegerMVInfo *const force_intpel_info) { // check use hash ME int k;
constint block_size = FORCE_INT_MV_DECISION_BLOCK_SIZE; constdouble threshold_current = 0.8; constdouble threshold_average = 0.95; constint max_history_size = 32; int T = 0; // total block int C = 0; // match with collocated block int S = 0; // smooth region but not match with collocated block
constint pic_width = cur_picture->y_width; constint pic_height = cur_picture->y_height; for (int i = 0; i + block_size <= pic_height; i += block_size) { for (int j = 0; j + block_size <= pic_width; j += block_size) { constint x_pos = j; constint y_pos = i; int match = 1;
T++;
// check whether collocated block match with current
uint8_t *p_cur = cur_picture->y_buffer;
uint8_t *p_ref = last_picture->y_buffer; int stride_cur = cur_picture->y_stride; int stride_ref = last_picture->y_stride;
p_cur += (y_pos * stride_cur + x_pos);
p_ref += (y_pos * stride_ref + x_pos);
var += av1_get_perpixel_variance_facade(cpi, xd, &buf, BLOCK_8X8,
AOM_PLANE_Y);
num_of_var += 1.0;
}
}
var = var / num_of_var;
// Curve fitting with an exponential model on all 16x16 blocks from the // midres dataset.
var = 67.035434 * (1 - exp(-0.0021489 * var)) + 17.492222;
// As per the above computation, var will be in the range of // [17.492222, 84.527656], assuming the data type is of infinite // precision. The following assert conservatively checks if var is in the // range of [17.0, 85.0] to avoid any issues due to the precision of the // relevant data type.
assert(var > 17.0 && var < 85.0);
cpi->ssim_rdmult_scaling_factors[index] = var;
log_sum += log(var);
}
}
// As log_sum holds the geometric mean, it will be in the range // [17.492222, 84.527656]. Hence, in the below loop, the value of // cpi->ssim_rdmult_scaling_factors[index] would be in the range // [0.2069, 4.8323].
log_sum = exp(log_sum / (double)(num_rows * num_cols));
for (int row = 0; row < num_rows; ++row) { for (int col = 0; col < num_cols; ++col) { constint index = row * num_cols + col;
cpi->ssim_rdmult_scaling_factors[index] /= log_sum;
}
}
}
// Coding context that only needs to be saved when recode loop includes // filtering (deblocking, CDEF, superres post-encode upscale and/or loop // restoraton). staticvoid save_extra_coding_context(AV1_COMP *cpi) {
CODING_CONTEXT *const cc = &cpi->coding_context;
AV1_COMMON *cm = &cpi->common;
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.