#include <assert.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "av1/common/scale.h"
#include "config/aom_config.h"
#include "config/aom_dsp_rtcd.h"
#include "aom/aomcx.h"
#if CONFIG_DENOISE
#include "aom_dsp/grain_table.h"
#include "aom_dsp/noise_util.h"
#include "aom_dsp/noise_model.h"
#endif
#include "aom_dsp/flow_estimation/corner_detect.h"
#include "aom_dsp/psnr.h"
#if CONFIG_INTERNAL_STATS
#include "aom_dsp/ssim.h"
#endif
#include "aom_ports/aom_timer.h"
#include "aom_ports/mem.h"
#include "aom_util/aom_pthread.h"
#if CONFIG_BITSTREAM_DEBUG
#include "aom_util/debug_util.h"
#endif
#include "av1/common/alloccommon.h"
#include "av1/common/debugmodes.h"
#include "av1/common/filter.h"
#include "av1/common/idct.h"
#include "av1/common/reconinter.h"
#include "av1/common/reconintra.h"
#include "av1/common/resize.h"
#include "av1/common/tile_common.h"
#include "av1/encoder/allintra_vis.h"
#include "av1/encoder/aq_complexity.h"
#include "av1/encoder/aq_cyclicrefresh.h"
#include "av1/encoder/aq_variance.h"
#include "av1/encoder/bitstream.h"
#if CONFIG_INTERNAL_STATS
#include "av1/encoder/blockiness.h"
#endif
#include "av1/encoder/context_tree.h"
#include "av1/encoder/dwt.h"
#include "av1/encoder/encodeframe.h"
#include "av1/encoder/encodemv.h"
#include "av1/encoder/encode_strategy.h"
#include "av1/encoder/encoder.h"
#include "av1/encoder/encoder_alloc.h"
#include "av1/encoder/encoder_utils.h"
#include "av1/encoder/encodetxb.h"
#include "av1/encoder/ethread.h"
#include "av1/encoder/firstpass.h"
#include "av1/encoder/hash_motion.h"
#include "av1/encoder/hybrid_fwd_txfm.h"
#include "av1/encoder/intra_mode_search.h"
#include "av1/encoder/mv_prec.h"
#include "av1/encoder/pass2_strategy.h"
#include "av1/encoder/pickcdef.h"
#include "av1/encoder/picklpf.h"
#include "av1/encoder/pickrst.h"
#include "av1/encoder/random.h"
#include "av1/encoder/ratectrl.h"
#include "av1/encoder/rc_utils.h"
#include "av1/encoder/rd.h"
#include "av1/encoder/rdopt.h"
#if CONFIG_SALIENCY_MAP
#include "av1/encoder/saliency_map.h"
#endif
#include "av1/encoder/segmentation.h"
#include "av1/encoder/speed_features.h"
#include "av1/encoder/superres_scale.h"
#if CONFIG_THREE_PASS
#include "av1/encoder/thirdpass.h"
#endif
#include "av1/encoder/tpl_model.h"
#include "av1/encoder/reconinter_enc.h"
#include "av1/encoder/var_based_part.h"
#define DEFAULT_EXPLICIT_ORDER_HINT_BITS …
#ifdef OUTPUT_YUV_REC
FILE *yuv_rec_file;
#define FILE_NAME_LEN …
#endif
#ifdef OUTPUT_YUV_DENOISED
FILE *yuv_denoised_file = NULL;
#endif
static inline void Scale2Ratio(AOM_SCALING_MODE mode, int *hr, int *hs) { … }
int av1_set_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows,
int cols) { … }
int av1_get_active_map(AV1_COMP *cpi, unsigned char *new_map_16x16, int rows,
int cols) { … }
void av1_initialize_enc(unsigned int usage, enum aom_rc_mode end_usage) { … }
void av1_new_framerate(AV1_COMP *cpi, double framerate) { … }
double av1_get_compression_ratio(const AV1_COMMON *const cm,
size_t encoded_frame_size) { … }
static void auto_tile_size_balancing(AV1_COMMON *const cm, int num_sbs,
int num_tiles_lg, int tile_col_row) { … }
static void set_tile_info(AV1_COMMON *const cm,
const TileConfig *const tile_cfg) { … }
void av1_update_frame_size(AV1_COMP *cpi) { … }
static inline int does_level_match(int width, int height, double fps,
int lvl_width, int lvl_height,
double lvl_fps, int lvl_dim_mult) { … }
static void set_bitstream_level_tier(AV1_PRIMARY *const ppi, int width,
int height, double init_framerate) { … }
static void init_seq_coding_tools(AV1_PRIMARY *const ppi,
const AV1EncoderConfig *oxcf,
int disable_frame_id_numbers) { … }
static void init_config_sequence(struct AV1_PRIMARY *ppi,
const AV1EncoderConfig *oxcf) { … }
static void init_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf) { … }
void av1_change_config_seq(struct AV1_PRIMARY *ppi,
const AV1EncoderConfig *oxcf,
bool *is_sb_size_changed) { … }
void av1_change_config(struct AV1_COMP *cpi, const AV1EncoderConfig *oxcf,
bool is_sb_size_changed) { … }
static inline void init_frame_info(FRAME_INFO *frame_info,
const AV1_COMMON *const cm) { … }
static inline void init_frame_index_set(FRAME_INDEX_SET *frame_index_set) { … }
static inline void update_counters_for_show_frame(AV1_COMP *const cpi) { … }
AV1_PRIMARY *av1_create_primary_compressor(
struct aom_codec_pkt_list *pkt_list_head, int num_lap_buffers,
const AV1EncoderConfig *oxcf) { … }
AV1_COMP *av1_create_compressor(AV1_PRIMARY *ppi, const AV1EncoderConfig *oxcf,
BufferPool *const pool, COMPRESSOR_STAGE stage,
int lap_lag_in_frames) { … }
#if CONFIG_INTERNAL_STATS
#define SNPRINT …
#define SNPRINT2 …
#endif
void av1_remove_primary_compressor(AV1_PRIMARY *ppi) { … }
void av1_remove_compressor(AV1_COMP *cpi) { … }
static void generate_psnr_packet(AV1_COMP *cpi) { … }
int av1_use_as_reference(int *ext_ref_frame_flags, int ref_frame_flags) { … }
int av1_copy_reference_enc(AV1_COMP *cpi, int idx, YV12_BUFFER_CONFIG *sd) { … }
int av1_set_reference_enc(AV1_COMP *cpi, int idx, YV12_BUFFER_CONFIG *sd) { … }
#ifdef OUTPUT_YUV_REC
void aom_write_one_yuv_frame(AV1_COMMON *cm, YV12_BUFFER_CONFIG *s) {
uint8_t *src = s->y_buffer;
int h = cm->height;
if (yuv_rec_file == NULL) return;
if (s->flags & YV12_FLAG_HIGHBITDEPTH) {
uint16_t *src16 = CONVERT_TO_SHORTPTR(s->y_buffer);
do {
fwrite(src16, s->y_width, 2, yuv_rec_file);
src16 += s->y_stride;
} while (--h);
src16 = CONVERT_TO_SHORTPTR(s->u_buffer);
h = s->uv_height;
do {
fwrite(src16, s->uv_width, 2, yuv_rec_file);
src16 += s->uv_stride;
} while (--h);
src16 = CONVERT_TO_SHORTPTR(s->v_buffer);
h = s->uv_height;
do {
fwrite(src16, s->uv_width, 2, yuv_rec_file);
src16 += s->uv_stride;
} while (--h);
fflush(yuv_rec_file);
return;
}
do {
fwrite(src, s->y_width, 1, yuv_rec_file);
src += s->y_stride;
} while (--h);
src = s->u_buffer;
h = s->uv_height;
do {
fwrite(src, s->uv_width, 1, yuv_rec_file);
src += s->uv_stride;
} while (--h);
src = s->v_buffer;
h = s->uv_height;
do {
fwrite(src, s->uv_width, 1, yuv_rec_file);
src += s->uv_stride;
} while (--h);
fflush(yuv_rec_file);
}
#endif
void av1_set_mv_search_params(AV1_COMP *cpi) { … }
void av1_set_screen_content_options(AV1_COMP *cpi, FeatureFlags *features) { … }
static void init_motion_estimation(AV1_COMP *cpi) { … }
static void init_ref_frame_bufs(AV1_COMP *cpi) { … }
aom_codec_err_t av1_check_initial_width(AV1_COMP *cpi, int use_highbitdepth,
int subsampling_x, int subsampling_y) { … }
#if CONFIG_AV1_TEMPORAL_DENOISING
static void setup_denoiser_buffer(AV1_COMP *cpi) { … }
#endif
static int set_size_literal(AV1_COMP *cpi, int width, int height) { … }
void av1_set_frame_size(AV1_COMP *cpi, int width, int height) { … }
static inline int extend_borders_mt(const AV1_COMP *cpi,
MULTI_THREADED_MODULES stage, int plane) { … }
static void cdef_restoration_frame(AV1_COMP *cpi, AV1_COMMON *cm,
MACROBLOCKD *xd, int use_restoration,
int use_cdef,
unsigned int skip_apply_postproc_filters) { … }
static void extend_frame_borders(AV1_COMP *cpi) { … }
static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) { … }
static void update_motion_stat(AV1_COMP *const cpi) { … }
static int encode_without_recode(AV1_COMP *cpi) { … }
#if !CONFIG_REALTIME_ONLY
static int encode_with_recode_loop(AV1_COMP *cpi, size_t *size, uint8_t *dest,
size_t dest_size) {
AV1_COMMON *const cm = &cpi->common;
RATE_CONTROL *const rc = &cpi->rc;
GlobalMotionInfo *const gm_info = &cpi->gm_info;
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
const QuantizationCfg *const q_cfg = &oxcf->q_cfg;
const int allow_recode = (cpi->sf.hl_sf.recode_loop != DISALLOW_RECODE);
assert(IMPLIES(oxcf->rc_cfg.min_cr > 0, allow_recode));
set_size_independent_vars(cpi);
if (is_stat_consumption_stage_twopass(cpi) &&
cpi->sf.interp_sf.adaptive_interp_filter_search)
cpi->interp_search_flags.interp_filter_search_mask =
av1_setup_interp_filter_search_mask(cpi);
av1_setup_frame_size(cpi);
if (av1_superres_in_recode_allowed(cpi) &&
cpi->superres_mode != AOM_SUPERRES_NONE &&
cm->superres_scale_denominator == SCALE_NUMERATOR) {
return -1;
}
int top_index = 0, bottom_index = 0;
int q = 0, q_low = 0, q_high = 0;
av1_set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
q_low = bottom_index;
q_high = top_index;
av1_set_mv_search_params(cpi);
allocate_gradient_info_for_hog(cpi);
allocate_src_var_of_4x4_sub_block_buf(cpi);
if (cpi->sf.part_sf.partition_search_type == VAR_BASED_PARTITION)
variance_partition_alloc(cpi);
if (cm->current_frame.frame_type == KEY_FRAME) copy_frame_prob_info(cpi);
#if CONFIG_COLLECT_COMPONENT_TIMING
printf("\n Encoding a frame: \n");
#endif
#if !CONFIG_RD_COMMAND
if (!cpi->sf.hl_sf.disable_extra_sc_testing && !cpi->use_ducky_encode)
av1_determine_sc_tools_with_encoding(cpi, q);
#endif
#if CONFIG_TUNE_VMAF
if (oxcf->tune_cfg.tuning == AOM_TUNE_VMAF_NEG_MAX_GAIN) {
av1_vmaf_neg_preprocessing(cpi, cpi->unscaled_source);
}
#endif
#if CONFIG_TUNE_BUTTERAUGLI
cpi->butteraugli_info.recon_set = false;
int original_q = 0;
#endif
cpi->num_frame_recode = 0;
int loop = 0;
int loop_count = 0;
int overshoot_seen = 0;
int undershoot_seen = 0;
int low_cr_seen = 0;
int last_loop_allow_hp = 0;
do {
loop = 0;
int do_mv_stats_collection = 1;
if (loop_count > 0 && cpi->source && gm_info->search_done) {
if (cpi->source->y_crop_width != cm->width ||
cpi->source->y_crop_height != cm->height) {
gm_info->search_done = 0;
}
}
cpi->source = av1_realloc_and_scale_if_required(
cm, cpi->unscaled_source, &cpi->scaled_source, EIGHTTAP_REGULAR, 0,
false, false, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid);
#if CONFIG_TUNE_BUTTERAUGLI
if (oxcf->tune_cfg.tuning == AOM_TUNE_BUTTERAUGLI) {
if (loop_count == 0) {
original_q = q;
q = 96;
av1_setup_butteraugli_source(cpi);
} else {
q = original_q;
}
}
#endif
if (cpi->unscaled_last_source != NULL) {
cpi->last_source = av1_realloc_and_scale_if_required(
cm, cpi->unscaled_last_source, &cpi->scaled_last_source,
EIGHTTAP_REGULAR, 0, false, false, cpi->oxcf.border_in_pixels,
cpi->alloc_pyramid);
}
int scale_references = 0;
#if CONFIG_FPMT_TEST
scale_references =
cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE ? 1 : 0;
#endif
if (scale_references ||
cpi->ppi->gf_group.frame_parallel_level[cpi->gf_frame_index] == 0) {
if (!frame_is_intra_only(cm)) {
if (loop_count > 0) {
release_scaled_references(cpi);
}
av1_scale_references(cpi, EIGHTTAP_REGULAR, 0, 0);
}
}
#if CONFIG_TUNE_VMAF
if (oxcf->tune_cfg.tuning >= AOM_TUNE_VMAF_WITH_PREPROCESSING &&
oxcf->tune_cfg.tuning <= AOM_TUNE_VMAF_NEG_MAX_GAIN) {
cpi->vmaf_info.original_qindex = q;
q = av1_get_vmaf_base_qindex(cpi, q);
}
#endif
#if CONFIG_RD_COMMAND
RD_COMMAND *rd_command = &cpi->rd_command;
RD_OPTION option = rd_command->option_ls[rd_command->frame_index];
if (option == RD_OPTION_SET_Q || option == RD_OPTION_SET_Q_RDMULT) {
q = rd_command->q_index_ls[rd_command->frame_index];
}
#endif
#if CONFIG_BITRATE_ACCURACY
#if CONFIG_THREE_PASS
if (oxcf->pass == AOM_RC_THIRD_PASS && cpi->vbr_rc_info.ready == 1) {
int frame_coding_idx =
av1_vbr_rc_frame_coding_idx(&cpi->vbr_rc_info, cpi->gf_frame_index);
if (frame_coding_idx < cpi->vbr_rc_info.total_frame_count) {
q = cpi->vbr_rc_info.q_index_list[frame_coding_idx];
} else {
q = cpi->vbr_rc_info.base_q_index;
}
}
#else
if (cpi->vbr_rc_info.q_index_list_ready) {
q = cpi->vbr_rc_info.q_index_list[cpi->gf_frame_index];
}
#endif
#endif
#if CONFIG_RATECTRL_LOG && CONFIG_THREE_PASS && CONFIG_BITRATE_ACCURACY
if (oxcf->pass == AOM_RC_THIRD_PASS) {
int frame_coding_idx =
av1_vbr_rc_frame_coding_idx(&cpi->vbr_rc_info, cpi->gf_frame_index);
double qstep_ratio = cpi->vbr_rc_info.qstep_ratio_list[frame_coding_idx];
FRAME_UPDATE_TYPE update_type =
cpi->vbr_rc_info.update_type_list[frame_coding_idx];
rc_log_frame_encode_param(&cpi->rc_log, frame_coding_idx, qstep_ratio, q,
update_type);
}
#endif
if (cpi->use_ducky_encode) {
const DuckyEncodeFrameInfo *frame_info =
&cpi->ducky_encode_info.frame_info;
if (frame_info->qp_mode == DUCKY_ENCODE_FRAME_MODE_QINDEX) {
q = frame_info->q_index;
cm->delta_q_info.delta_q_present_flag = frame_info->delta_q_enabled;
}
}
av1_set_quantizer(cm, q_cfg->qm_minlevel, q_cfg->qm_maxlevel, q,
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, 0);
if (loop_count == 0) {
av1_setup_frame(cpi);
} else if (get_primary_ref_frame_buf(cm) == NULL) {
av1_default_coef_probs(cm);
av1_setup_frame_contexts(cm);
}
if (q_cfg->aq_mode == VARIANCE_AQ) {
av1_vaq_frame_setup(cpi);
} else if (q_cfg->aq_mode == COMPLEXITY_AQ) {
av1_setup_in_frame_q_adj(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;
#if CONFIG_COLLECT_COMPONENT_TIMING
start_timing(cpi, av1_encode_frame_time);
#endif
if (!frame_is_intra_only(cm)) {
av1_pick_and_set_high_precision_mv(cpi, q);
if (loop_count > 0 &&
cm->features.allow_high_precision_mv != last_loop_allow_hp) {
gm_info->search_done = 0;
}
last_loop_allow_hp = cm->features.allow_high_precision_mv;
}
av1_encode_frame(cpi);
if (!cpi->do_frame_data_update) do_mv_stats_collection = 0;
if (cpi->mv_stats.valid && do_mv_stats_collection) av1_zero(cpi->mv_stats);
if (cpi->sf.hl_sf.high_precision_mv_usage == LAST_MV_DATA &&
av1_frame_allows_smart_mv(cpi) && do_mv_stats_collection) {
av1_collect_mv_stats(cpi, q);
}
#if CONFIG_COLLECT_COMPONENT_TIMING
end_timing(cpi, av1_encode_frame_time);
#endif
#if CONFIG_BITRATE_ACCURACY || CONFIG_RD_COMMAND
const int do_dummy_pack = 1;
#else
const int do_dummy_pack =
(cpi->sf.hl_sf.recode_loop >= ALLOW_RECODE_KFARFGF &&
oxcf->rc_cfg.mode != AOM_Q) ||
oxcf->rc_cfg.min_cr > 0;
#endif
if (do_dummy_pack) {
av1_finalize_encoded_frame(cpi);
int largest_tile_id = 0;
rc->coefficient_size = 0;
if (av1_pack_bitstream(cpi, dest, dest_size, size, &largest_tile_id) !=
AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
}
rc->projected_frame_size = (int)(*size) << 3;
#if CONFIG_RD_COMMAND
PSNR_STATS psnr;
aom_calc_psnr(cpi->source, &cpi->common.cur_frame->buf, &psnr);
printf("q %d rdmult %d rate %d dist %" PRIu64 "\n", q, cpi->rd.RDMULT,
rc->projected_frame_size, psnr.sse[0]);
++rd_command->frame_index;
if (rd_command->frame_index == rd_command->frame_count) {
return AOM_CODEC_ERROR;
}
#endif
#if CONFIG_RATECTRL_LOG && CONFIG_THREE_PASS && CONFIG_BITRATE_ACCURACY
if (oxcf->pass == AOM_RC_THIRD_PASS) {
int frame_coding_idx =
av1_vbr_rc_frame_coding_idx(&cpi->vbr_rc_info, cpi->gf_frame_index);
rc_log_frame_entropy(&cpi->rc_log, frame_coding_idx,
rc->projected_frame_size, rc->coefficient_size);
}
#endif
}
#if CONFIG_TUNE_VMAF
if (oxcf->tune_cfg.tuning >= AOM_TUNE_VMAF_WITH_PREPROCESSING &&
oxcf->tune_cfg.tuning <= AOM_TUNE_VMAF_NEG_MAX_GAIN) {
q = cpi->vmaf_info.original_qindex;
}
#endif
if (allow_recode) {
recode_loop_update_q(cpi, &loop, &q, &q_low, &q_high, top_index,
bottom_index, &undershoot_seen, &overshoot_seen,
&low_cr_seen, loop_count);
}
#if CONFIG_TUNE_BUTTERAUGLI
if (loop_count == 0 && oxcf->tune_cfg.tuning == AOM_TUNE_BUTTERAUGLI) {
loop = 1;
av1_setup_butteraugli_rdmult_and_restore_source(cpi, 0.4);
}
#endif
if (cpi->use_ducky_encode) {
loop = 0;
}
#if CONFIG_BITRATE_ACCURACY || CONFIG_RD_COMMAND
loop = 0;
#endif
if (loop) {
++loop_count;
cpi->num_frame_recode =
(cpi->num_frame_recode < (NUM_RECODES_PER_FRAME - 1))
? (cpi->num_frame_recode + 1)
: (NUM_RECODES_PER_FRAME - 1);
#if CONFIG_INTERNAL_STATS
++cpi->frame_recode_hits;
#endif
}
#if CONFIG_COLLECT_COMPONENT_TIMING
if (loop) printf("\n Recoding:");
#endif
} while (loop);
return AOM_CODEC_OK;
}
#endif
static void set_grain_syn_params(AV1_COMMON *cm) { … }
static int encode_with_recode_loop_and_filter(AV1_COMP *cpi, size_t *size,
uint8_t *dest, size_t dest_size,
int64_t *sse, int64_t *rate,
int *largest_tile_id) { … }
static int encode_with_and_without_superres(AV1_COMP *cpi, size_t *size,
uint8_t *dest, size_t dest_size,
int *largest_tile_id) { … }
static inline int selective_disable_cdf_rtc(const AV1_COMP *cpi) { … }
#if !CONFIG_REALTIME_ONLY
static void subtract_stats(FIRSTPASS_STATS *section,
const FIRSTPASS_STATS *frame) {
section->frame -= frame->frame;
section->weight -= frame->weight;
section->intra_error -= frame->intra_error;
section->frame_avg_wavelet_energy -= frame->frame_avg_wavelet_energy;
section->coded_error -= frame->coded_error;
section->sr_coded_error -= frame->sr_coded_error;
section->pcnt_inter -= frame->pcnt_inter;
section->pcnt_motion -= frame->pcnt_motion;
section->pcnt_second_ref -= frame->pcnt_second_ref;
section->pcnt_neutral -= frame->pcnt_neutral;
section->intra_skip_pct -= frame->intra_skip_pct;
section->inactive_zone_rows -= frame->inactive_zone_rows;
section->inactive_zone_cols -= frame->inactive_zone_cols;
section->MVr -= frame->MVr;
section->mvr_abs -= frame->mvr_abs;
section->MVc -= frame->MVc;
section->mvc_abs -= frame->mvc_abs;
section->MVrv -= frame->MVrv;
section->MVcv -= frame->MVcv;
section->mv_in_out_count -= frame->mv_in_out_count;
section->new_mv_count -= frame->new_mv_count;
section->count -= frame->count;
section->duration -= frame->duration;
}
static void calculate_frame_avg_haar_energy(AV1_COMP *cpi) {
TWO_PASS *const twopass = &cpi->ppi->twopass;
const FIRSTPASS_STATS *const total_stats =
twopass->stats_buf_ctx->total_stats;
if (is_one_pass_rt_params(cpi) ||
(cpi->oxcf.q_cfg.deltaq_mode != DELTA_Q_PERCEPTUAL) ||
(is_fp_wavelet_energy_invalid(total_stats) == 0))
return;
const int num_mbs = (cpi->oxcf.resize_cfg.resize_mode != RESIZE_NONE)
? cpi->initial_mbs
: cpi->common.mi_params.MBs;
const YV12_BUFFER_CONFIG *const unfiltered_source = cpi->unfiltered_source;
const uint8_t *const src = unfiltered_source->y_buffer;
const int hbd = unfiltered_source->flags & YV12_FLAG_HIGHBITDEPTH;
const int stride = unfiltered_source->y_stride;
const BLOCK_SIZE fp_block_size =
get_fp_block_size(cpi->is_screen_content_type);
const int fp_block_size_width = block_size_wide[fp_block_size];
const int fp_block_size_height = block_size_high[fp_block_size];
const int num_unit_cols =
get_num_blocks(unfiltered_source->y_crop_width, fp_block_size_width);
const int num_unit_rows =
get_num_blocks(unfiltered_source->y_crop_height, fp_block_size_height);
const int num_8x8_cols = num_unit_cols * (fp_block_size_width / 8);
const int num_8x8_rows = num_unit_rows * (fp_block_size_height / 8);
int64_t frame_avg_wavelet_energy = av1_haar_ac_sad_mxn_uint8_input(
src, stride, hbd, num_8x8_rows, num_8x8_cols);
cpi->twopass_frame.frame_avg_haar_energy =
log1p((double)frame_avg_wavelet_energy / num_mbs);
}
#endif
static int encode_frame_to_data_rate(AV1_COMP *cpi, size_t *size, uint8_t *dest,
size_t dest_size) { … }
int av1_encode(AV1_COMP *const cpi, uint8_t *const dest, size_t dest_size,
const EncodeFrameInput *const frame_input,
const EncodeFrameParams *const frame_params,
EncodeFrameResults *const frame_results) { … }
#if CONFIG_DENOISE
static int apply_denoise_2d(AV1_COMP *cpi, const YV12_BUFFER_CONFIG *sd,
int block_size, float noise_level,
int64_t time_stamp, int64_t end_time) { … }
#endif
int av1_receive_raw_frame(AV1_COMP *cpi, aom_enc_frame_flags_t frame_flags,
const YV12_BUFFER_CONFIG *sd, int64_t time_stamp,
int64_t end_time) { … }
#if CONFIG_ENTROPY_STATS
void print_entropy_stats(AV1_PRIMARY *const ppi) {
if (!ppi->cpi) return;
if (ppi->cpi->oxcf.pass != 1 &&
ppi->cpi->common.current_frame.frame_number > 0) {
fprintf(stderr, "Writing counts.stt\n");
FILE *f = fopen("counts.stt", "wb");
fwrite(&ppi->aggregate_fc, sizeof(ppi->aggregate_fc), 1, f);
fclose(f);
}
}
#endif
#if CONFIG_INTERNAL_STATS
static void adjust_image_stat(double y, double u, double v, double all,
ImageStat *s) {
s->stat[STAT_Y] += y;
s->stat[STAT_U] += u;
s->stat[STAT_V] += v;
s->stat[STAT_ALL] += all;
s->worst = AOMMIN(s->worst, all);
}
static void compute_internal_stats(AV1_COMP *cpi, int frame_bytes) {
AV1_PRIMARY *const ppi = cpi->ppi;
AV1_COMMON *const cm = &cpi->common;
double samples = 0.0;
const uint32_t in_bit_depth = cpi->oxcf.input_cfg.input_bit_depth;
const uint32_t bit_depth = cpi->td.mb.e_mbd.bd;
if (cpi->ppi->use_svc &&
cpi->svc.spatial_layer_id < cpi->svc.number_spatial_layers - 1)
return;
#if CONFIG_INTER_STATS_ONLY
if (cm->current_frame.frame_type == KEY_FRAME) return;
#endif
cpi->bytes += frame_bytes;
if (cm->show_frame) {
const YV12_BUFFER_CONFIG *orig = cpi->source;
const YV12_BUFFER_CONFIG *recon = &cpi->common.cur_frame->buf;
double y, u, v, frame_all;
ppi->count[0]++;
ppi->count[1]++;
if (cpi->ppi->b_calculate_psnr) {
PSNR_STATS psnr;
double weight[2] = { 0.0, 0.0 };
double frame_ssim2[2] = { 0.0, 0.0 };
#if CONFIG_AV1_HIGHBITDEPTH
aom_calc_highbd_psnr(orig, recon, &psnr, bit_depth, in_bit_depth);
#else
aom_calc_psnr(orig, recon, &psnr);
#endif
adjust_image_stat(psnr.psnr[1], psnr.psnr[2], psnr.psnr[3], psnr.psnr[0],
&(ppi->psnr[0]));
ppi->total_sq_error[0] += psnr.sse[0];
ppi->total_samples[0] += psnr.samples[0];
samples = psnr.samples[0];
aom_calc_ssim(orig, recon, bit_depth, in_bit_depth,
cm->seq_params->use_highbitdepth, weight, frame_ssim2);
ppi->worst_ssim = AOMMIN(ppi->worst_ssim, frame_ssim2[0]);
ppi->summed_quality += frame_ssim2[0] * weight[0];
ppi->summed_weights += weight[0];
#if CONFIG_AV1_HIGHBITDEPTH
if ((cpi->source->flags & YV12_FLAG_HIGHBITDEPTH) &&
(in_bit_depth < bit_depth)) {
adjust_image_stat(psnr.psnr_hbd[1], psnr.psnr_hbd[2], psnr.psnr_hbd[3],
psnr.psnr_hbd[0], &ppi->psnr[1]);
ppi->total_sq_error[1] += psnr.sse_hbd[0];
ppi->total_samples[1] += psnr.samples_hbd[0];
ppi->worst_ssim_hbd = AOMMIN(ppi->worst_ssim_hbd, frame_ssim2[1]);
ppi->summed_quality_hbd += frame_ssim2[1] * weight[1];
ppi->summed_weights_hbd += weight[1];
}
#endif
#if 0
{
FILE *f = fopen("q_used.stt", "a");
double y2 = psnr.psnr[1];
double u2 = psnr.psnr[2];
double v2 = psnr.psnr[3];
double frame_psnr2 = psnr.psnr[0];
fprintf(f, "%5d : Y%f7.3:U%f7.3:V%f7.3:F%f7.3:S%7.3f\n",
cm->current_frame.frame_number, y2, u2, v2,
frame_psnr2, frame_ssim2);
fclose(f);
}
#endif
}
if (ppi->b_calculate_blockiness) {
if (!cm->seq_params->use_highbitdepth) {
const double frame_blockiness =
av1_get_blockiness(orig->y_buffer, orig->y_stride, recon->y_buffer,
recon->y_stride, orig->y_width, orig->y_height);
ppi->worst_blockiness = AOMMAX(ppi->worst_blockiness, frame_blockiness);
ppi->total_blockiness += frame_blockiness;
}
if (ppi->b_calculate_consistency) {
if (!cm->seq_params->use_highbitdepth) {
const double this_inconsistency = aom_get_ssim_metrics(
orig->y_buffer, orig->y_stride, recon->y_buffer, recon->y_stride,
orig->y_width, orig->y_height, ppi->ssim_vars, &ppi->metrics, 1);
const double peak = (double)((1 << in_bit_depth) - 1);
const double consistency =
aom_sse_to_psnr(samples, peak, ppi->total_inconsistency);
if (consistency > 0.0)
ppi->worst_consistency =
AOMMIN(ppi->worst_consistency, consistency);
ppi->total_inconsistency += this_inconsistency;
}
}
}
frame_all =
aom_calc_fastssim(orig, recon, &y, &u, &v, bit_depth, in_bit_depth);
adjust_image_stat(y, u, v, frame_all, &ppi->fastssim);
frame_all = aom_psnrhvs(orig, recon, &y, &u, &v, bit_depth, in_bit_depth);
adjust_image_stat(y, u, v, frame_all, &ppi->psnrhvs);
}
}
void print_internal_stats(AV1_PRIMARY *ppi) {
if (!ppi->cpi) return;
AV1_COMP *const cpi = ppi->cpi;
if (ppi->cpi->oxcf.pass != 1 &&
ppi->cpi->common.current_frame.frame_number > 0) {
char headings[512] = { 0 };
char results[512] = { 0 };
FILE *f = fopen("opsnr.stt", "a");
double time_encoded =
(cpi->time_stamps.prev_ts_end - cpi->time_stamps.first_ts_start) /
10000000.000;
double total_encode_time =
(ppi->total_time_receive_data + ppi->total_time_compress_data) /
1000.000;
const double dr =
(double)ppi->total_bytes * (double)8 / (double)1000 / time_encoded;
const double peak =
(double)((1 << ppi->cpi->oxcf.input_cfg.input_bit_depth) - 1);
const double target_rate =
(double)ppi->cpi->oxcf.rc_cfg.target_bandwidth / 1000;
const double rate_err = ((100.0 * (dr - target_rate)) / target_rate);
if (ppi->b_calculate_psnr) {
const double total_psnr = aom_sse_to_psnr(
(double)ppi->total_samples[0], peak, (double)ppi->total_sq_error[0]);
const double total_ssim =
100 * pow(ppi->summed_quality / ppi->summed_weights, 8.0);
snprintf(headings, sizeof(headings),
"Bitrate\tAVGPsnr\tGLBPsnr\tAVPsnrP\tGLPsnrP\t"
"AOMSSIM\tVPSSIMP\tFASTSIM\tPSNRHVS\t"
"WstPsnr\tWstSsim\tWstFast\tWstHVS\t"
"AVPsrnY\tAPsnrCb\tAPsnrCr");
snprintf(results, sizeof(results),
"%7.2f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t"
"%7.3f\t%7.3f\t%7.3f\t%7.3f\t"
"%7.3f\t%7.3f\t%7.3f\t%7.3f\t"
"%7.3f\t%7.3f\t%7.3f",
dr, ppi->psnr[0].stat[STAT_ALL] / ppi->count[0], total_psnr,
ppi->psnr[0].stat[STAT_ALL] / ppi->count[0], total_psnr,
total_ssim, total_ssim,
ppi->fastssim.stat[STAT_ALL] / ppi->count[0],
ppi->psnrhvs.stat[STAT_ALL] / ppi->count[0], ppi->psnr[0].worst,
ppi->worst_ssim, ppi->fastssim.worst, ppi->psnrhvs.worst,
ppi->psnr[0].stat[STAT_Y] / ppi->count[0],
ppi->psnr[0].stat[STAT_U] / ppi->count[0],
ppi->psnr[0].stat[STAT_V] / ppi->count[0]);
if (ppi->b_calculate_blockiness) {
SNPRINT(headings, "\t Block\tWstBlck");
SNPRINT2(results, "\t%7.3f", ppi->total_blockiness / ppi->count[0]);
SNPRINT2(results, "\t%7.3f", ppi->worst_blockiness);
}
if (ppi->b_calculate_consistency) {
double consistency =
aom_sse_to_psnr((double)ppi->total_samples[0], peak,
(double)ppi->total_inconsistency);
SNPRINT(headings, "\tConsist\tWstCons");
SNPRINT2(results, "\t%7.3f", consistency);
SNPRINT2(results, "\t%7.3f", ppi->worst_consistency);
}
SNPRINT(headings, "\t Time\tRcErr\tAbsErr");
SNPRINT2(results, "\t%8.0f", total_encode_time);
SNPRINT2(results, " %7.2f", rate_err);
SNPRINT2(results, " %7.2f", fabs(rate_err));
SNPRINT(headings, "\tAPsnr611");
SNPRINT2(results, " %7.3f",
(6 * ppi->psnr[0].stat[STAT_Y] + ppi->psnr[0].stat[STAT_U] +
ppi->psnr[0].stat[STAT_V]) /
(ppi->count[0] * 8));
#if CONFIG_AV1_HIGHBITDEPTH
const uint32_t in_bit_depth = ppi->cpi->oxcf.input_cfg.input_bit_depth;
const uint32_t bit_depth = ppi->seq_params.bit_depth;
if ((ppi->total_samples[1] > 0) && (in_bit_depth < bit_depth)) {
const double peak_hbd = (double)((1 << bit_depth) - 1);
const double total_psnr_hbd =
aom_sse_to_psnr((double)ppi->total_samples[1], peak_hbd,
(double)ppi->total_sq_error[1]);
const double total_ssim_hbd =
100 * pow(ppi->summed_quality_hbd / ppi->summed_weights_hbd, 8.0);
SNPRINT(headings,
"\t AVGPsnrH GLBPsnrH AVPsnrPH GLPsnrPH"
" AVPsnrYH APsnrCbH APsnrCrH WstPsnrH"
" AOMSSIMH VPSSIMPH WstSsimH");
SNPRINT2(results, "\t%7.3f",
ppi->psnr[1].stat[STAT_ALL] / ppi->count[1]);
SNPRINT2(results, " %7.3f", total_psnr_hbd);
SNPRINT2(results, " %7.3f",
ppi->psnr[1].stat[STAT_ALL] / ppi->count[1]);
SNPRINT2(results, " %7.3f", total_psnr_hbd);
SNPRINT2(results, " %7.3f", ppi->psnr[1].stat[STAT_Y] / ppi->count[1]);
SNPRINT2(results, " %7.3f", ppi->psnr[1].stat[STAT_U] / ppi->count[1]);
SNPRINT2(results, " %7.3f", ppi->psnr[1].stat[STAT_V] / ppi->count[1]);
SNPRINT2(results, " %7.3f", ppi->psnr[1].worst);
SNPRINT2(results, " %7.3f", total_ssim_hbd);
SNPRINT2(results, " %7.3f", total_ssim_hbd);
SNPRINT2(results, " %7.3f", ppi->worst_ssim_hbd);
}
#endif
fprintf(f, "%s\n", headings);
fprintf(f, "%s\n", results);
}
fclose(f);
aom_free(ppi->ssim_vars);
ppi->ssim_vars = NULL;
}
}
#endif
static inline void update_keyframe_counters(AV1_COMP *cpi) { … }
static inline void update_frames_till_gf_update(AV1_COMP *cpi) { … }
static inline void update_gf_group_index(AV1_COMP *cpi) { … }
static void update_fb_of_context_type(const AV1_COMP *const cpi,
int *const fb_of_context_type) { … }
static void update_rc_counts(AV1_COMP *cpi) { … }
static void update_end_of_frame_stats(AV1_COMP *cpi) { … }
static inline void update_gm_stats(AV1_COMP *cpi) { … }
void av1_post_encode_updates(AV1_COMP *const cpi,
const AV1_COMP_DATA *const cpi_data) { … }
int av1_get_compressed_data(AV1_COMP *cpi, AV1_COMP_DATA *const cpi_data) { … }
static void scale_references_fpmt(AV1_COMP *cpi, int *ref_buffers_used_map) { … }
static void increment_scaled_ref_counts_fpmt(BufferPool *buffer_pool,
int ref_buffers_used_map) { … }
void av1_release_scaled_references_fpmt(AV1_COMP *cpi) { … }
void av1_decrement_ref_counts_fpmt(BufferPool *buffer_pool,
int ref_buffers_used_map) { … }
void av1_init_sc_decisions(AV1_PRIMARY *const ppi) { … }
AV1_COMP *av1_get_parallel_frame_enc_data(AV1_PRIMARY *const ppi,
AV1_COMP_DATA *const first_cpi_data) { … }
int av1_init_parallel_frame_context(const AV1_COMP_DATA *const first_cpi_data,
AV1_PRIMARY *const ppi,
int *ref_buffers_used_map) { … }
int av1_get_preview_raw_frame(AV1_COMP *cpi, YV12_BUFFER_CONFIG *dest) { … }
int av1_get_last_show_frame(AV1_COMP *cpi, YV12_BUFFER_CONFIG *frame) { … }
aom_codec_err_t av1_copy_new_frame_enc(AV1_COMMON *cm,
YV12_BUFFER_CONFIG *new_frame,
YV12_BUFFER_CONFIG *sd) { … }
int av1_set_internal_size(AV1EncoderConfig *const oxcf,
ResizePendingParams *resize_pending_params,
AOM_SCALING_MODE horiz_mode,
AOM_SCALING_MODE vert_mode) { … }
int av1_get_quantizer(AV1_COMP *cpi) { … }
int av1_convert_sect5obus_to_annexb(uint8_t *buffer, size_t *frame_size) { … }
static void rtc_set_updates_ref_frame_config(
ExtRefreshFrameFlagsInfo *const ext_refresh_frame_flags,
RTC_REF *const rtc_ref) { … }
static int rtc_set_references_external_ref_frame_config(AV1_COMP *cpi) { … }
void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) { … }
aom_fixed_buf_t *av1_get_global_headers(AV1_PRIMARY *ppi) { … }