#include <string.h>
#include "aom/aomcx.h"
#include "av1/common/av1_common_int.h"
#include "av1/encoder/bitstream.h"
#include "av1/encoder/encodeframe.h"
#include "av1/encoder/encoder.h"
#include "av1/encoder/encoder_alloc.h"
#include "av1/encoder/encodetxb.h"
#include "av1/encoder/encoder_utils.h"
#include "av1/encoder/grain_test_vectors.h"
#include "av1/encoder/mv_prec.h"
#include "av1/encoder/rc_utils.h"
#include "av1/encoder/rdopt.h"
#include "av1/encoder/segmentation.h"
#include "av1/encoder/superres_scale.h"
#include "av1/encoder/tpl_model.h"
#include "av1/encoder/var_based_part.h"
#if CONFIG_TUNE_VMAF
#include "av1/encoder/tune_vmaf.h"
#endif
#define MIN_BOOST_COMBINE_FACTOR …
#define MAX_BOOST_COMBINE_FACTOR …
const int default_tx_type_probs[FRAME_UPDATE_TYPES][TX_SIZES_ALL][TX_TYPES] = …;
const int default_obmc_probs[FRAME_UPDATE_TYPES][BLOCK_SIZES_ALL] = …;
const int default_warped_probs[FRAME_UPDATE_TYPES] = …;
const int default_switchable_interp_probs[FRAME_UPDATE_TYPES]
[SWITCHABLE_FILTER_CONTEXTS]
[SWITCHABLE_FILTERS] = …;
static void configure_static_seg_features(AV1_COMP *cpi) { … }
void av1_apply_active_map(AV1_COMP *cpi) { … }
#if !CONFIG_REALTIME_ONLY
static void process_tpl_stats_frame(AV1_COMP *cpi) {
const GF_GROUP *const gf_group = &cpi->ppi->gf_group;
AV1_COMMON *const cm = &cpi->common;
assert(IMPLIES(gf_group->size > 0, cpi->gf_frame_index < gf_group->size));
const int tpl_idx = cpi->gf_frame_index;
TplParams *const tpl_data = &cpi->ppi->tpl_data;
TplDepFrame *tpl_frame = &tpl_data->tpl_frame[tpl_idx];
TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
if (tpl_frame->is_valid) {
int tpl_stride = tpl_frame->stride;
double intra_cost_base = 0;
double mc_dep_cost_base = 0;
double cbcmp_base = 1;
const int step = 1 << tpl_data->tpl_stats_block_mis_log2;
const int row_step = step;
const int col_step_sr =
coded_to_superres_mi(step, cm->superres_scale_denominator);
const int mi_cols_sr = av1_pixels_to_mi(cm->superres_upscaled_width);
for (int row = 0; row < cm->mi_params.mi_rows; row += row_step) {
for (int col = 0; col < mi_cols_sr; col += col_step_sr) {
TplDepStats *this_stats = &tpl_stats[av1_tpl_ptr_pos(
row, col, tpl_stride, tpl_data->tpl_stats_block_mis_log2)];
double cbcmp = (double)(this_stats->srcrf_dist);
int64_t mc_dep_delta =
RDCOST(tpl_frame->base_rdmult, this_stats->mc_dep_rate,
this_stats->mc_dep_dist);
double dist_scaled = (double)(this_stats->recrf_dist << RDDIV_BITS);
intra_cost_base += log(dist_scaled) * cbcmp;
mc_dep_cost_base += log(dist_scaled + mc_dep_delta) * cbcmp;
cbcmp_base += cbcmp;
}
}
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 {
const int 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
void av1_set_size_dependent_vars(AV1_COMP *cpi, int *q, int *bottom_index,
int *top_index) { … }
static void reset_film_grain_chroma_params(aom_film_grain_t *pars) { … }
void av1_update_film_grain_parameters_seq(struct AV1_PRIMARY *ppi,
const AV1EncoderConfig *oxcf) { … }
void av1_update_film_grain_parameters(struct AV1_COMP *cpi,
const AV1EncoderConfig *oxcf) { … }
void av1_scale_references(AV1_COMP *cpi, const InterpFilter filter,
const int phase, const int use_optimized_scaler) { … }
BLOCK_SIZE av1_select_sb_size(const AV1EncoderConfig *const oxcf, int width,
int height, int number_spatial_layers) { … }
void av1_setup_frame(AV1_COMP *cpi) { … }
#if !CONFIG_REALTIME_ONLY
static int get_interp_filter_selected(const AV1_COMMON *const cm,
MV_REFERENCE_FRAME ref,
InterpFilter ifilter) {
const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref);
if (buf == NULL) return 0;
return buf->interp_filter_selected[ifilter];
}
uint16_t av1_setup_interp_filter_search_mask(AV1_COMP *cpi) {
const AV1_COMMON *const cm = &cpi->common;
int ref_total[REF_FRAMES] = { 0 };
uint16_t mask = ALLOW_ALL_INTERP_FILT_MASK;
if (cpi->last_frame_type == KEY_FRAME || cpi->refresh_frame.alt_ref_frame)
return mask;
for (MV_REFERENCE_FRAME ref = LAST_FRAME; ref <= ALTREF_FRAME; ++ref) {
for (InterpFilter ifilter = EIGHTTAP_REGULAR; ifilter <= MULTITAP_SHARP;
++ifilter) {
ref_total[ref] += get_interp_filter_selected(cm, ref, ifilter);
}
}
int ref_total_total = (ref_total[LAST2_FRAME] + ref_total[LAST3_FRAME] +
ref_total[GOLDEN_FRAME] + ref_total[BWDREF_FRAME] +
ref_total[ALTREF2_FRAME] + ref_total[ALTREF_FRAME]);
for (InterpFilter ifilter = EIGHTTAP_REGULAR; ifilter <= MULTITAP_SHARP;
++ifilter) {
int last_score = get_interp_filter_selected(cm, LAST_FRAME, ifilter) * 30;
if (ref_total[LAST_FRAME] && last_score <= ref_total[LAST_FRAME]) {
int filter_score =
get_interp_filter_selected(cm, LAST2_FRAME, ifilter) * 20 +
get_interp_filter_selected(cm, LAST3_FRAME, ifilter) * 20 +
get_interp_filter_selected(cm, GOLDEN_FRAME, ifilter) * 20 +
get_interp_filter_selected(cm, BWDREF_FRAME, ifilter) * 10 +
get_interp_filter_selected(cm, ALTREF2_FRAME, ifilter) * 10 +
get_interp_filter_selected(cm, ALTREF_FRAME, ifilter) * 10;
if (filter_score < ref_total_total) {
DUAL_FILTER_TYPE filt_type = ifilter + SWITCHABLE_FILTERS * ifilter;
reset_interp_filter_allowed_mask(&mask, filt_type);
}
}
}
return mask;
}
#define STRICT_PSNR_DIFF_THRESH …
static void 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,
int *projected_size_pass, PSNR_STATS *psnr) {
AV1_COMMON *const cm = &cpi->common;
FeatureFlags *const features = &cm->features;
#if CONFIG_FPMT_TEST
projected_size_pass[pass] =
((cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] > 0) &&
(cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE))
? cpi->ppi->p_rc.temp_projected_frame_size
: cpi->rc.projected_frame_size;
#else
projected_size_pass[pass] = cpi->rc.projected_frame_size;
#endif
#if CONFIG_AV1_HIGHBITDEPTH
const uint32_t in_bit_depth = cpi->oxcf.input_cfg.input_bit_depth;
const uint32_t bit_depth = cpi->td.mb.e_mbd.bd;
aom_calc_highbd_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr[pass],
bit_depth, in_bit_depth);
#else
aom_calc_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr[pass]);
#endif
if (pass != 1) return;
const double psnr_diff = psnr[1].psnr[0] - psnr[0].psnr[0];
const double 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) {
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 {
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;
}
}
static void set_encoding_params_for_screen_content(AV1_COMP *cpi,
const int pass) {
AV1_COMMON *const cm = &cpi->common;
if (pass == 0) {
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);
cm->features.allow_screen_content_tools = 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;
}
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;
int projected_size_pass[3] = { 0 };
PSNR_STATS psnr[3];
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;
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;
}
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;
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);
}
av1_setup_frame(cpi);
if (cm->seg.enabled) {
if (!cm->seg.update_data && cm->prev_frame) {
segfeatures_copy(&cm->seg, &cm->prev_frame->seg);
cm->seg.enabled = cm->prev_frame->seg.enabled;
} else {
av1_calculate_segdata(&cm->seg);
}
} else {
memset(&cm->seg, 0, sizeof(cm->seg));
}
segfeatures_copy(&cm->cur_frame->seg, &cm->seg);
cm->cur_frame->seg.enabled = cm->seg.enabled;
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);
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);
av1_set_variance_partition_thresholds(cpi, q_for_screen_content_quick_run,
0);
av1_encode_frame(cpi);
screen_content_tools_determination(
cpi, allow_screen_content_tools_orig_decision,
allow_intrabc_orig_decision, use_screen_content_tools_orig_decision,
is_screen_content_type_orig_decision, pass, projected_size_pass, psnr);
}
cpi->sf.part_sf.partition_search_type = partition_search_type_orig;
cpi->sf.part_sf.fixed_partition_size = fixed_partition_block_size_orig;
if (!cm->features.allow_screen_content_tools)
free_token_info(&cpi->token_info);
}
#endif
static void fix_interp_filter(InterpFilter *const interp_filter,
const FRAME_COUNTS *const counts) { … }
void av1_finalize_encoded_frame(AV1_COMP *const cpi) { … }
int av1_is_integer_mv(const YV12_BUFFER_CONFIG *cur_picture,
const YV12_BUFFER_CONFIG *last_picture,
ForceIntegerMVInfo *const force_intpel_info) { … }
void av1_set_mb_ssim_rdmult_scaling(AV1_COMP *cpi) { … }
static void save_extra_coding_context(AV1_COMP *cpi) { … }
void av1_save_all_coding_context(AV1_COMP *cpi) { … }
#if DUMP_RECON_FRAMES == 1
void av1_dump_filtered_recon_frames(AV1_COMP *cpi) {
AV1_COMMON *const cm = &cpi->common;
const CurrentFrame *const current_frame = &cm->current_frame;
const YV12_BUFFER_CONFIG *recon_buf = &cm->cur_frame->buf;
if (recon_buf == NULL) {
printf("Frame %d is not ready.\n", current_frame->frame_number);
return;
}
static const int flag_list[REF_FRAMES] = { 0,
AOM_LAST_FLAG,
AOM_LAST2_FLAG,
AOM_LAST3_FLAG,
AOM_GOLD_FLAG,
AOM_BWD_FLAG,
AOM_ALT2_FLAG,
AOM_ALT_FLAG };
printf(
"\n***Frame=%d (frame_offset=%d, show_frame=%d, "
"show_existing_frame=%d) "
"[LAST LAST2 LAST3 GOLDEN BWD ALT2 ALT]=[",
current_frame->frame_number, current_frame->order_hint, cm->show_frame,
cm->show_existing_frame);
for (int ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref_frame);
const int ref_offset = buf != NULL ? (int)buf->order_hint : -1;
printf(" %d(%c)", ref_offset,
(cpi->ref_frame_flags & flag_list[ref_frame]) ? 'Y' : 'N');
}
printf(" ]\n");
if (!cm->show_frame) {
printf("Frame %d is a no show frame, so no image dump.\n",
current_frame->frame_number);
return;
}
int h;
char file_name[256] = "/tmp/enc_filtered_recon.yuv";
FILE *f_recon = NULL;
if (current_frame->frame_number == 0) {
if ((f_recon = fopen(file_name, "wb")) == NULL) {
printf("Unable to open file %s to write.\n", file_name);
return;
}
} else {
if ((f_recon = fopen(file_name, "ab")) == NULL) {
printf("Unable to open file %s to append.\n", file_name);
return;
}
}
printf(
"\nFrame=%5d, encode_update_type[%5d]=%1d, frame_offset=%d, "
"show_frame=%d, show_existing_frame=%d, source_alt_ref_active=%d, "
"refresh_alt_ref_frame=%d, "
"y_stride=%4d, uv_stride=%4d, cm->width=%4d, cm->height=%4d\n\n",
current_frame->frame_number, cpi->gf_frame_index,
cpi->ppi->gf_group.update_type[cpi->gf_frame_index],
current_frame->order_hint, cm->show_frame, cm->show_existing_frame,
cpi->rc.source_alt_ref_active, cpi->refresh_frame.alt_ref_frame,
recon_buf->y_stride, recon_buf->uv_stride, cm->width, cm->height);
#if 0
int ref_frame;
printf("get_ref_frame_map_idx: [");
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame)
printf(" %d", get_ref_frame_map_idx(cm, ref_frame));
printf(" ]\n");
#endif
for (h = 0; h < cm->height; ++h) {
fwrite(&recon_buf->y_buffer[h * recon_buf->y_stride], 1, cm->width,
f_recon);
}
for (h = 0; h < (cm->height >> 1); ++h) {
fwrite(&recon_buf->u_buffer[h * recon_buf->uv_stride], 1, (cm->width >> 1),
f_recon);
}
for (h = 0; h < (cm->height >> 1); ++h) {
fwrite(&recon_buf->v_buffer[h * recon_buf->uv_stride], 1, (cm->width >> 1),
f_recon);
}
fclose(f_recon);
}
#endif