#include <stdint.h>
#include "av1/common/blockd.h"
#include "config/aom_config.h"
#include "config/aom_scale_rtcd.h"
#include "aom/aom_codec.h"
#include "aom/aom_encoder.h"
#if CONFIG_MISMATCH_DEBUG
#include "aom_util/debug_util.h"
#endif
#include "av1/common/av1_common_int.h"
#include "av1/common/reconinter.h"
#include "av1/encoder/encoder.h"
#include "av1/encoder/encode_strategy.h"
#include "av1/encoder/encodeframe.h"
#include "av1/encoder/encoder_alloc.h"
#include "av1/encoder/firstpass.h"
#include "av1/encoder/gop_structure.h"
#include "av1/encoder/pass2_strategy.h"
#include "av1/encoder/temporal_filter.h"
#if CONFIG_THREE_PASS
#include "av1/encoder/thirdpass.h"
#endif
#include "av1/encoder/tpl_model.h"
#if CONFIG_TUNE_VMAF
#include "av1/encoder/tune_vmaf.h"
#endif
#define TEMPORAL_FILTER_KEY_FRAME …
static inline void set_refresh_frame_flags(
RefreshFrameInfo *const refresh_frame, bool refresh_gf, bool refresh_bwdref,
bool refresh_arf) { … }
void av1_configure_buffer_updates(AV1_COMP *const cpi,
RefreshFrameInfo *const refresh_frame,
const FRAME_UPDATE_TYPE type,
const REFBUF_STATE refbuf_state,
int force_refresh_all) { … }
static void set_additional_frame_flags(const AV1_COMMON *const cm,
unsigned int *const frame_flags) { … }
static void set_ext_overrides(AV1_COMMON *const cm,
EncodeFrameParams *const frame_params,
ExternalFlags *const ext_flags) { … }
static int choose_primary_ref_frame(
AV1_COMP *const cpi, const EncodeFrameParams *const frame_params) { … }
static void adjust_frame_rate(AV1_COMP *cpi, int64_t ts_start, int64_t ts_end) { … }
int is_forced_keyframe_pending(struct lookahead_ctx *lookahead,
const int up_to_index,
const COMPRESSOR_STAGE compressor_stage) { … }
static struct lookahead_entry *choose_frame_source(
AV1_COMP *const cpi, int *const flush, int *pop_lookahead,
struct lookahead_entry **last_source, int *const show_frame) { … }
static int allow_show_existing(const AV1_COMP *const cpi,
unsigned int frame_flags) { … }
static void update_frame_flags(const AV1_COMMON *const cm,
const RefreshFrameInfo *const refresh_frame,
unsigned int *frame_flags) { … }
#define DUMP_REF_FRAME_IMAGES …
#if DUMP_REF_FRAME_IMAGES == 1
static int dump_one_image(AV1_COMMON *cm,
const YV12_BUFFER_CONFIG *const ref_buf,
char *file_name) {
int h;
FILE *f_ref = NULL;
if (ref_buf == NULL) {
printf("Frame data buffer is NULL.\n");
return AOM_CODEC_MEM_ERROR;
}
if ((f_ref = fopen(file_name, "wb")) == NULL) {
printf("Unable to open file %s to write.\n", file_name);
return AOM_CODEC_MEM_ERROR;
}
for (h = 0; h < cm->height; ++h) {
fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref);
}
for (h = 0; h < (cm->height >> 1); ++h) {
fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
f_ref);
}
for (h = 0; h < (cm->height >> 1); ++h) {
fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
f_ref);
}
fclose(f_ref);
return AOM_CODEC_OK;
}
static void dump_ref_frame_images(AV1_COMP *cpi) {
AV1_COMMON *const cm = &cpi->common;
MV_REFERENCE_FRAME ref_frame;
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
char file_name[256] = "";
snprintf(file_name, sizeof(file_name), "/tmp/enc_F%d_ref_%d.yuv",
cm->current_frame.frame_number, ref_frame);
dump_one_image(cm, get_ref_frame_yv12_buf(cpi, ref_frame), file_name);
}
}
#endif
int av1_get_refresh_ref_frame_map(int refresh_frame_flags) { … }
static int get_free_ref_map_index(RefFrameMapPair ref_map_pairs[REF_FRAMES]) { … }
static int get_refresh_idx(RefFrameMapPair ref_frame_map_pairs[REF_FRAMES],
int update_arf, GF_GROUP *gf_group, int gf_index,
int enable_refresh_skip, int cur_frame_disp) { … }
int av1_calc_refresh_idx_for_intnl_arf(
AV1_COMP *cpi, RefFrameMapPair ref_frame_map_pairs[REF_FRAMES],
int gf_index) { … }
int av1_get_refresh_frame_flags(
const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params,
FRAME_UPDATE_TYPE frame_update_type, int gf_index, int cur_disp_order,
RefFrameMapPair ref_frame_map_pairs[REF_FRAMES]) { … }
#if !CONFIG_REALTIME_ONLY
static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest,
size_t dest_size,
EncodeFrameInput *const frame_input,
const EncodeFrameParams *const frame_params,
EncodeFrameResults *const frame_results) {
#if CONFIG_COLLECT_COMPONENT_TIMING
if (cpi->oxcf.pass == 2) start_timing(cpi, denoise_and_encode_time);
#endif
const AV1EncoderConfig *const oxcf = &cpi->oxcf;
AV1_COMMON *const cm = &cpi->common;
GF_GROUP *const gf_group = &cpi->ppi->gf_group;
FRAME_UPDATE_TYPE update_type =
get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
const int is_second_arf =
av1_gop_is_second_arf(gf_group, cpi->gf_frame_index);
int apply_filtering =
av1_is_temporal_filter_on(oxcf) && !is_stat_generation_stage(cpi);
if (update_type != KF_UPDATE && update_type != ARF_UPDATE && !is_second_arf) {
apply_filtering = 0;
}
if (apply_filtering) {
if (frame_params->frame_type == KEY_FRAME) {
int allow_kf_filtering = oxcf->kf_cfg.enable_keyframe_filtering &&
!frame_params->show_existing_frame &&
!is_lossless_requested(&oxcf->rc_cfg);
if (allow_kf_filtering) {
double y_noise_level = 0.0;
av1_estimate_noise_level(
frame_input->source, &y_noise_level, AOM_PLANE_Y, AOM_PLANE_Y,
cm->seq_params->bit_depth, NOISE_ESTIMATION_EDGE_THRESHOLD);
apply_filtering = y_noise_level > 0;
} else {
apply_filtering = 0;
}
if (apply_filtering) {
av1_setup_past_independence(cm);
}
} else if (is_second_arf) {
apply_filtering = cpi->sf.hl_sf.second_alt_ref_filtering;
}
}
#if CONFIG_COLLECT_COMPONENT_TIMING
if (cpi->oxcf.pass == 2) start_timing(cpi, apply_filtering_time);
#endif
YV12_BUFFER_CONFIG *source_buffer = frame_input->source;
if (apply_filtering) {
int show_existing_alt_ref = 0;
FRAME_DIFF frame_diff;
int top_index = 0;
int bottom_index = 0;
const int q_index = av1_rc_pick_q_and_bounds(
cpi, cpi->oxcf.frm_dim_cfg.width, cpi->oxcf.frm_dim_cfg.height,
cpi->gf_frame_index, &bottom_index, &top_index);
cm->current_frame.frame_type = frame_params->frame_type;
if (update_type == KF_UPDATE || update_type == ARF_UPDATE) {
YV12_BUFFER_CONFIG *tf_buf = av1_tf_info_get_filtered_buf(
&cpi->ppi->tf_info, cpi->gf_frame_index, &frame_diff);
if (tf_buf != NULL) {
frame_input->source = tf_buf;
show_existing_alt_ref = av1_check_show_filtered_frame(
tf_buf, &frame_diff, q_index, cm->seq_params->bit_depth);
if (show_existing_alt_ref) {
cpi->common.showable_frame |= 1;
} else {
cpi->common.showable_frame = 0;
}
}
if (gf_group->frame_type[cpi->gf_frame_index] != KEY_FRAME) {
cpi->ppi->show_existing_alt_ref = show_existing_alt_ref;
}
}
if (is_second_arf) {
int ret = aom_realloc_frame_buffer(
&cpi->ppi->tf_info.tf_buf_second_arf, oxcf->frm_dim_cfg.width,
oxcf->frm_dim_cfg.height, cm->seq_params->subsampling_x,
cm->seq_params->subsampling_y, cm->seq_params->use_highbitdepth,
cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL,
NULL, cpi->alloc_pyramid, 0);
if (ret)
aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
"Failed to allocate tf_buf_second_arf");
YV12_BUFFER_CONFIG *tf_buf_second_arf =
&cpi->ppi->tf_info.tf_buf_second_arf;
const int arf_src_index = gf_group->arf_src_offset[cpi->gf_frame_index];
av1_temporal_filter(cpi, arf_src_index, cpi->gf_frame_index, &frame_diff,
tf_buf_second_arf);
show_existing_alt_ref = av1_check_show_filtered_frame(
tf_buf_second_arf, &frame_diff, q_index, cm->seq_params->bit_depth);
if (show_existing_alt_ref) {
aom_extend_frame_borders(tf_buf_second_arf, av1_num_planes(cm));
frame_input->source = tf_buf_second_arf;
}
cpi->common.showable_frame |= 1;
}
if (source_buffer->metadata &&
aom_copy_metadata_to_frame_buffer(frame_input->source,
source_buffer->metadata)) {
aom_internal_error(
cm->error, AOM_CODEC_MEM_ERROR,
"Failed to copy source metadata to the temporal filtered frame");
}
}
#if CONFIG_COLLECT_COMPONENT_TIMING
if (cpi->oxcf.pass == 2) end_timing(cpi, apply_filtering_time);
#endif
int set_mv_params = frame_params->frame_type == KEY_FRAME ||
update_type == ARF_UPDATE || update_type == GF_UPDATE;
cm->show_frame = frame_params->show_frame;
cm->current_frame.frame_type = frame_params->frame_type;
av1_set_frame_size(cpi, cm->width, cm->height);
if (set_mv_params) av1_set_mv_search_params(cpi);
#if CONFIG_RD_COMMAND
if (frame_params->frame_type == KEY_FRAME) {
char filepath[] = "rd_command.txt";
av1_read_rd_command(filepath, &cpi->rd_command);
}
#endif
if (cpi->gf_frame_index == 0 && !is_stat_generation_stage(cpi)) {
int allow_tpl =
oxcf->gf_cfg.lag_in_frames > 1 && oxcf->algo_cfg.enable_tpl_model;
if (gf_group->size > MAX_LENGTH_TPL_FRAME_STATS) {
allow_tpl = 0;
}
if (frame_params->frame_type != KEY_FRAME) {
allow_tpl =
allow_tpl && (update_type == ARF_UPDATE || update_type == GF_UPDATE ||
(cpi->use_ducky_encode &&
cpi->ducky_encode_info.frame_info.gop_mode ==
DUCKY_ENCODE_GOP_MODE_RCL));
}
if (allow_tpl) {
if (!cpi->skip_tpl_setup_stats) {
av1_tpl_preload_rc_estimate(cpi, frame_params);
av1_tpl_setup_stats(cpi, 0, frame_params);
#if CONFIG_BITRATE_ACCURACY && !CONFIG_THREE_PASS
assert(cpi->gf_frame_index == 0);
av1_vbr_rc_update_q_index_list(&cpi->vbr_rc_info, &cpi->ppi->tpl_data,
gf_group, cm->seq_params->bit_depth);
#endif
}
} else {
av1_init_tpl_stats(&cpi->ppi->tpl_data);
}
#if CONFIG_BITRATE_ACCURACY && CONFIG_THREE_PASS
if (cpi->oxcf.pass == AOM_RC_SECOND_PASS &&
cpi->second_pass_log_stream != NULL) {
TPL_INFO *tpl_info;
AOM_CHECK_MEM_ERROR(cm->error, tpl_info, aom_malloc(sizeof(*tpl_info)));
av1_pack_tpl_info(tpl_info, gf_group, &cpi->ppi->tpl_data);
av1_write_tpl_info(tpl_info, cpi->second_pass_log_stream,
cpi->common.error);
aom_free(tpl_info);
}
#endif
}
if (av1_encode(cpi, dest, dest_size, frame_input, frame_params,
frame_results) != AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
}
if (apply_filtering && is_psnr_calc_enabled(cpi)) {
cpi->source = av1_realloc_and_scale_if_required(
cm, source_buffer, &cpi->scaled_source, cm->features.interp_filter, 0,
false, true, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid);
cpi->unscaled_source = source_buffer;
}
#if CONFIG_COLLECT_COMPONENT_TIMING
if (cpi->oxcf.pass == 2) end_timing(cpi, denoise_and_encode_time);
#endif
return AOM_CODEC_OK;
}
#endif
RefBufMapData;
static int compare_map_idx_pair_asc(const void *a, const void *b) { … }
static int is_in_ref_map(RefBufMapData *map, int disp_order, int n_frames) { … }
static void add_ref_to_slot(RefBufMapData *ref, int *const remapped_ref_idx,
int frame) { … }
#define LOW_LEVEL_FRAMES_TR …
static void set_unmapped_ref(RefBufMapData *buffer_map, int n_bufs,
int n_min_level_refs, int min_level,
int cur_frame_disp) { … }
void av1_get_ref_frames(RefFrameMapPair ref_frame_map_pairs[REF_FRAMES],
int cur_frame_disp, const AV1_COMP *cpi, int gf_index,
int is_parallel_encode,
int remapped_ref_idx[REF_FRAMES]) { … }
int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
uint8_t *const dest, size_t dest_size,
unsigned int *frame_flags, int64_t *const time_stamp,
int64_t *const time_end,
const aom_rational64_t *const timestamp_ratio,
int *const pop_lookahead, int flush) { … }