av1_encode没什么特别好说的,会把在av1_encode_strategy的参数(EncodeFrameInput和EncodeFrameParams)赋给结构体AV1_COMP和AV1_COMMON,对当前帧的数据进行初始化
AV1_COMP *const cpi
AV1_COMMON *const cm = &cpi->common;
CurrentFrame *const current_frame = &cm->current_frame;
这里可以看出,对于第一次编码和第二次编码,其所对应的下个函数是不同的。
if (cpi->oxcf.pass == 1) {
#if !CONFIG_REALTIME_ONLY
av1_first_pass(cpi, frame_input->ts_duration);
#endif
} else if (cpi->oxcf.pass == 0 || cpi->oxcf.pass == 2) {
if (encode_frame_to_data_rate(cpi, &frame_results->size, dest) !=
AOM_CODEC_OK) {
return AOM_CODEC_ERROR;
}
对于第一次编码,进入的函数av1_first_pass, 第一次编码的参考帧只有LAST和GOLDEN两种类型,为的是减少复杂度
const YV12_BUFFER_CONFIG *const lst_yv12 =
get_ref_frame_yv12_buf(cm, LAST_FRAME);
const YV12_BUFFER_CONFIG *gld_yv12 = get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
const YV12_BUFFER_CONFIG *alt_yv12 = NULL;
在第一次编码中,对于QP, 通过函数av1_find_qindex用二叉树的方法找到符合第一次编码的QP,块的是大小16×16
函数av1_set_quantizer:quantizer has to be reinitialized with av1_init_quantizer() if any delta_q changes.
av1_frame_init_quantizer初始化帧的量化器
在for (mb_row = 0; mb_row < cm->mb_rows; ++mb_row)开始循环
在循环内:把刚编码好的作为last frame,第0帧还要作为黄金帧,对块进行帧内和帧间的预测。
在函数末尾有可以保存第一次编码重建值的代码和对应的开关,方便对数据进行分析。
min_err是为了保证码率分配,这里跟块的数量成正比。
一系列运算的结果都存到 FIRSTPASS_STATS fps里, 并在完成一次编码后,赋给&twopass->total_stats
void av1_first_pass(AV1_COMP *cpi, const int64_t ts_duration) {
int mb_row, mb_col;
MACROBLOCK *const x = &cpi->td.mb;
AV1_COMMON *const cm = &cpi->common;
CurrentFrame *const current_frame = &cm->current_frame;
const SequenceHeader *const seq_params = &cm->seq_params;
const int num_planes = av1_num_planes(cm);
MACROBLOCKD *const xd = &x->e_mbd;
TileInfo tile;
struct macroblock_plane *const p = x->plane;
struct macroblockd_plane *const pd = xd->plane;
const PICK_MODE_CONTEXT *ctx =
&cpi->td.pc_root[MAX_MIB_SIZE_LOG2 - MIN_MIB_SIZE_LOG2]->none;
int i;
int recon_yoffset, src_yoffset, recon_uvoffset;
int64_t intra_error = 0;
int64_t frame_avg_wavelet_energy = 0;
int64_t coded_error = 0;
int64_t sr_coded_error = 0;
int64_t tr_coded_error = 0;
int sum_mvr = 0, sum_mvc = 0;
int sum_mvr_abs = 0, sum_mvc_abs = 0;
int64_t sum_mvrs = 0, sum_mvcs = 0;
int mvcount = 0;
int intercount = 0;
int second_ref_count = 0;
int third_ref_count = 0;
const int intrapenalty = INTRA_MODE_PENALTY;
double neutral_count;
int intra_skip_count = 0;
int image_data_start_row = INVALID_ROW;
int new_mv_count = 0;
int sum_in_vectors = 0;
MV lastmv = kZeroMv;
TWO_PASS *twopass = &cpi->twopass;
int recon_y_stride, src_y_stride, recon_uv_stride, uv_mb_height;
//重新定义了BUFFER,为了和第二次编码的区分开来,主要是LAST和GOLDEN
const YV12_BUFFER_CONFIG *const lst_yv12 =
get_ref_frame_yv12_buf(cm, LAST_FRAME);
const YV12_BUFFER_CONFIG *gld_yv12 = get_ref_frame_yv12_buf(cm, GOLDEN_FRAME);
const YV12_BUFFER_CONFIG *alt_yv12 = NULL;
const int alt_offset = 16 - (current_frame->frame_number % 16);
if (alt_offset < 16) {
const struct lookahead_entry *const alt_buf =
av1_lookahead_peek(cpi->lookahead, alt_offset);
if (alt_buf != NULL) {
alt_yv12 = &alt_buf->img;
}
}
YV12_BUFFER_CONFIG *const new_yv12 = &cm->cur_frame->buf;
double intra_factor;
double brightness_factor;
const int qindex = find_fp_qindex(seq_params->bit_depth);
const int mb_scale = mi_size_wide[BLOCK_16X16];
int *raw_motion_err_list;
int raw_motion_err_counts = 0;
CHECK_MEM_ERROR(
cm, raw_motion_err_list,
aom_calloc(cm->mb_rows * cm->mb_cols, sizeof(*raw_motion_err_list)));
// First pass code requires valid last and new frame buffers.
assert(new_yv12 != NULL);
assert(frame_is_intra_only(cm) || (lst_yv12 != NULL));
av1_setup_frame_size(cpi);
aom_clear_system_state();
xd->mi = cm->mi_grid_visible;
xd->mi[0] = cm->mi;
x->e_mbd.mi[0]->sb_type = BLOCK_16X16;
intra_factor = 0.0;
brightness_factor = 0.0;
neutral_count = 0.0;
// Do not use periodic key frames.
cpi->rc.frames_to_key = INT_MAX;
//QP的初始化,buffer的初始化等
av1_set_quantizer(cm, qindex);
av1_setup_block_planes(&x->e_mbd, seq_params->subsampling_x,
seq_params->subsampling_y, num_planes);
av1_setup_src_planes(x, cpi->source, 0, 0, num_planes,
x->e_mbd.mi[0]->sb_type);
av1_setup_dst_planes(xd->plane, seq_params->sb_size, new_yv12, 0, 0, 0,
num_planes);
//如果不是intra,就要从last_frame的buffer里读取数据来做预测,通常是原始帧
if (!frame_is_intra_only(cm)) {
av1_setup_pre_planes(xd, 0, lst_yv12, 0, 0, NULL, num_planes);
}
xd->mi = cm->mi_grid_visible;
xd->mi[0] = cm->mi;
// Don't store luma o