// 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);
} else if (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);
}
} else if (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);
} else if (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;
}
}
}
void av1_apply_roi_map(AV1_COMP *cpi) {
AV1_COMMON *cm = &cpi->common; struct segmentation *const seg = &cm->seg; unsigned char *const seg_map = cpi->enc_seg.map;
aom_roi_map_t *roi = &cpi->roi; const int *delta_q = roi->delta_q; const int *delta_lf = roi->delta_lf; const int *skip = roi->skip;
int ref_frame[8];
int internal_delta_q[MAX_SEGMENTS];
int skip_enabled = 0;
int qindex = cm->quant_params.base_qindex;
// Force disable of ROI if active_map is enabled. ROI for now // only supported/tested for realtime mode with speed >= 7.
if (!roi->enabled || cpi->active_map.enabled || cpi->oxcf.speed < 7 ||
cpi->oxcf.mode != REALTIME) {
roi->enabled = 0;
roi->delta_qp_enabled = 0;
roi->reference_enabled = 0; return;
}
for (int i = 0; i < MAX_SEGMENTS; ++i) { // Default: disable all feautures.
av1_disable_segfeature(seg, i, SEG_LVL_ALT_Q);
av1_disable_segfeature(seg, i, SEG_LVL_SKIP);
av1_disable_segfeature(seg, i, SEG_LVL_REF_FRAME);
av1_disable_segfeature(seg, i, SEG_LVL_ALT_LF_Y_H);
av1_disable_segfeature(seg, i, SEG_LVL_ALT_LF_Y_V);
av1_disable_segfeature(seg, i, SEG_LVL_ALT_LF_U);
av1_disable_segfeature(seg, i, SEG_LVL_ALT_LF_V); // Translate the external delta q values to internal values.
internal_delta_q[i] = av1_quantizer_to_qindex(abs(delta_q[i]));
if (delta_q[i] < 0) internal_delta_q[i] = -internal_delta_q[i]; // Clamp to allowed best/worst quality. For best quality clamp to 1 // to avoid qindex = 0 case (lossless segment) which can happen for // best_quality = 0.
if (qindex + internal_delta_q[i] <= cpi->rc.best_quality)
internal_delta_q[i] = AOMMAX(1, cpi->rc.best_quality) - qindex;
if (qindex + internal_delta_q[i] > cpi->rc.worst_quality)
internal_delta_q[i] =
cpi->rc.worst_quality - cm->quant_params.base_qindex;
if (internal_delta_q[i] != 0) {
av1_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
av1_set_segdata(seg, i, SEG_LVL_ALT_Q, internal_delta_q[i]);
roi->delta_qp_enabled = 1;
qindex = cm->quant_params.base_qindex + internal_delta_q[i];
}
if (delta_lf[i] != 0) { // Disable loopfilter delta from ROI, as it requires // additional changes and settings: DELTAQ_MODE and DELTALF_MODE // are needed to be enabled, along with additional internal fix. return;
} // Skip only allowed on delta frames.
if (skip[i] != 0 && !frame_is_intra_only(cm)) {
av1_enable_segfeature(seg, i, SEG_LVL_SKIP); // Also force skip on loopfilter.
av1_enable_segfeature(seg, i, SEG_LVL_ALT_LF_Y_H);
av1_enable_segfeature(seg, i, SEG_LVL_ALT_LF_Y_V);
av1_enable_segfeature(seg, i, SEG_LVL_ALT_LF_U);
av1_enable_segfeature(seg, i, SEG_LVL_ALT_LF_V);
av1_set_segdata(seg, i, SEG_LVL_ALT_LF_Y_H, -MAX_LOOP_FILTER);
av1_set_segdata(seg, i, SEG_LVL_ALT_LF_Y_V, -MAX_LOOP_FILTER);
av1_set_segdata(seg, i, SEG_LVL_ALT_LF_U, -MAX_LOOP_FILTER);
av1_set_segdata(seg, i, SEG_LVL_ALT_LF_V, -MAX_LOOP_FILTER);
skip_enabled = 1;
}
if (ref_frame[i] >= 0 && !frame_is_intra_only(cm)) { // Only allowed for LAST, GOLDEN, and ALTREF, and check that if either // is set as a reference.
if ((ref_frame[i] == LAST_FRAME &&
cpi->ref_frame_flags & AOM_LAST_FLAG) ||
(ref_frame[i] == GOLDEN_FRAME &&
cpi->ref_frame_flags & AOM_GOLD_FLAG) ||
(ref_frame[i] == ALTREF_FRAME &&
cpi->ref_frame_flags & AOM_ALT_FLAG)) {
av1_enable_segfeature(seg, i, SEG_LVL_REF_FRAME);
av1_set_segdata(seg, i, SEG_LVL_REF_FRAME, ref_frame[i]);
roi->reference_enabled = 1;
}
}
}
if (roi->delta_qp_enabled || skip_enabled || roi->reference_enabled) {
roi->enabled = 1;
if (roi->delta_qp_enabled) {
roi->rdmult_delta_qp = av1_compute_rd_mult(
qindex, cm->seq_params->bit_depth,
cpi->ppi->gf_group.update_type[cpi->gf_frame_index], 0, 15,
INTER_FRAME, cpi->oxcf.q_cfg.use_fixed_qp_offsets,
is_stat_consumption_stage(cpi), cpi->oxcf.tune_cfg.tuning,
cpi->oxcf.mode);
}
} else {
av1_disable_segmentation(seg);
roi->enabled = 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); const int 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);
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. const int gfu_boost =
(int)(200.0 * cpi->ppi->tpl_data.r0_adjust_factor / cpi->rd.r0);
// 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);
if (cpi->oxcf.rc_cfg.over_shoot_pct == 0) *top_index = MAXQ;
if (cpi->oxcf.rc_cfg.under_shoot_pct == 0) *bottom_index = MINQ;
}
void av1_scale_references(AV1_COMP *cpi, const InterpFilter filter, const int phase, const int use_optimized_scaler) {
AV1_COMMON *cm = &cpi->common; const int num_planes = av1_num_planes(cm);
MV_REFERENCE_FRAME ref_frame;
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) { const int 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) { // For spatial layers better selection may be done given the resolutions // used across the layers, but for now use 64x64 for spatial layers. return BLOCK_64X64;
} else if (oxcf->resize_cfg.resize_mode != RESIZE_NONE) { // Use the configured size (top resolution) for resize. return AOMMIN(oxcf->frm_dim_cfg.width, oxcf->frm_dim_cfg.height) > 720
? BLOCK_128X128
: BLOCK_64X64;
} else if (oxcf->mode == REALTIME) {
if (oxcf->tune_cfg.content == AOM_CONTENT_SCREEN) { const TileConfig *const tile_cfg = &oxcf->tile_cfg; const int 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. const int 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, const int allow_screen_content_tools_orig_decision, const int allow_intrabc_orig_decision, const int use_screen_content_tools_orig_decision, const int is_screen_content_type_orig_decision, const int pass,
PSNR_STATS *psnr) {
AV1_COMMON *const cm = &cpi->common;
FeatureFlags *const features = &cm->features;
#if CONFIG_AV1_HIGHBITDEPTH const uint32_t bit_depth = cpi->td.mb.e_mbd.bd; // The decision to enable screen content tools is based on PSNR evaluated only // at the stream bit-depth. Hence, PSNR computation against the actual input // source is skipped by passing the codec bit-depth instead of the source // bit-depth in the final arg.
aom_calc_highbd_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr[pass],
bit_depth, bit_depth); #else
aom_calc_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr[pass]); #endif
if (pass != 1) return;
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); const int psnr_diff_is_large = (psnr_diff > STRICT_PSNR_DIFF_THRESH); const int ratio_is_large =
((palette_ratio >= 0.0001) && ((psnr_diff / palette_ratio) > 4)); const int 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, const int 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, const int 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.
PSNR_STATS psnr[2]; const int is_key_frame = cm->current_frame.frame_type == KEY_FRAME; const int allow_screen_content_tools_orig_decision =
cm->features.allow_screen_content_tools; const int allow_intrabc_orig_decision = cm->features.allow_intrabc; const int use_screen_content_tools_orig_decision =
cpi->use_screen_content_tools; const int 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;
}
// 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. const int q_for_screen_content_quick_run =
is_lossless_requested(&oxcf->rc_cfg) ? q_orig : AOMMAX(q_orig, 244); const int 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);
// 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 (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++) { const int 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;
const int block_size = FORCE_INT_MV_DECISION_BLOCK_SIZE; constdouble threshold_current = 0.8; constdouble threshold_average = 0.95; const int 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
const int pic_width = cur_picture->y_width; const int 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) { const int x_pos = j; const int 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);
const int num_mi_w = mi_size_wide[block_size]; const int num_mi_h = mi_size_high[block_size]; const int num_cols = (mi_params->mi_cols + num_mi_w - 1) / num_mi_w; const int num_rows = (mi_params->mi_rows + num_mi_h - 1) / num_mi_h; double log_sum = 0.0;
// Loop through each 16x16 block.
for (int row = 0; row < num_rows; ++row) {
for (int col = 0; col < num_cols; ++col) { double var = 0.0, num_of_var = 0.0; const int index = row * num_cols + col;
// Loop through each 8x8 block.
for (int mi_row = row * num_mi_h;
mi_row < mi_params->mi_rows && mi_row < (row + 1) * num_mi_h;
mi_row += 2) {
for (int mi_col = col * num_mi_w;
mi_col < mi_params->mi_cols && mi_col < (col + 1) * num_mi_w;
mi_col += 2) { struct buf_2d buf; const int row_offset_y = mi_row << 2; const int col_offset_y = mi_col << 2;
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) { const int 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.