av1代码学习8---av1_encode_frame()
2020-06-23 本文已影响0人
青吟乐
1,函数功能
主要进行参考帧相关设置后进行编码调用encode_frame_internal(cpi)进行编码
2,代码学习
void av1_encode_frame(AV1_COMP *cpi) {
AV1_COMMON *const cm = &cpi->common;
CurrentFrame *const current_frame = &cm->current_frame;
const int num_planes = av1_num_planes(cm);
// Indicates whether or not to use a default reduced set for ext-tx
// rather than the potential full set of 16 transforms
cm->reduced_tx_set_used = cpi->oxcf.reduced_tx_type_set;
// Make sure segment_id is no larger than last_active_segid.
if (cm->seg.enabled && cm->seg.update_map) {
const int mi_rows = cm->mi_rows;
const int mi_cols = cm->mi_cols;
const int last_active_segid = cm->seg.last_active_segid;
uint8_t *map = cpi->segmentation_map;
for (int mi_row = 0; mi_row < mi_rows; ++mi_row) {
for (int mi_col = 0; mi_col < mi_cols; ++mi_col) {
map[mi_col] = AOMMIN(map[mi_col], last_active_segid);
}
map += mi_cols;
}
}
av1_setup_frame_buf_refs(cm);//参考帧
enforce_max_ref_frames(cpi);//强制参考帧引用数
set_rel_frame_dist(cpi);//设置参考帧w.r.t.与当前帧的相对距离
av1_setup_frame_sign_bias(cm);//设置标志位偏移量
#if CHECK_PRECOMPUTED_REF_FRAME_MAP
GF_GROUP *gf_group = &cpi->gf_group;
// TODO(yuec): The check is disabled on OVERLAY frames for now, because info
// in cpi->gf_group has been refreshed for the next GOP when the check is
// performed for OVERLAY frames. Since we have not support inter-GOP ref
// frame map computation, the precomputed ref map for an OVERLAY frame is all
// -1 at this point (although it is meaning before gf_group is refreshed).
if (!frame_is_intra_only(cm) && gf_group->index != 0) {
const RefCntBuffer *const golden_buf = get_ref_frame_buf(cm, GOLDEN_FRAME);
if (golden_buf) {
const int golden_order_hint = golden_buf->order_hint;
for (int ref = LAST_FRAME; ref < EXTREF_FRAME; ++ref) {
const RefCntBuffer *const buf = get_ref_frame_buf(cm, ref);
const int ref_disp_idx_precomputed =
gf_group->ref_frame_disp_idx[gf_group->index][ref - LAST_FRAME];
(void)ref_disp_idx_precomputed;
if (buf != NULL) {
const int ref_disp_idx =
get_relative_dist(&cm->seq_params.order_hint_info,
buf->order_hint, golden_order_hint);
if (ref_disp_idx >= 0)
assert(ref_disp_idx == ref_disp_idx_precomputed);
else
assert(ref_disp_idx_precomputed == -1);
} else {
assert(ref_disp_idx_precomputed == -1);
}
}
}
}
#endif
#if CONFIG_MISMATCH_DEBUG
mismatch_reset_frame(num_planes);
#else
(void)num_planes;
#endif
if (cpi->sf.frame_parameter_update) {//s帧,帧级编码参数
int i;
RD_OPT *const rd_opt = &cpi->rd;
RD_COUNTS *const rdc = &cpi->td.rd_counts;
// This code does a single RD pass over the whole frame assuming
// either compound, single or hybrid prediction as per whatever has
// worked best for that type of frame in the past.
// It also predicts whether another coding mode would have worked
// better than this coding mode. If that is the case, it remembers
// that for subsequent frames.
// It does the same analysis for transform size selection also.
//这段代码在整个帧上执行一次RD传递,假设根据过去对该类型帧最有效的方法进行复合、单一或混合预测。
//它还预测了另一种编码模式是否比这种编码模式工作得更好。
//如果是这样的话,它会记住后面的帧。它对变换大小的选择也做同样的分析。
// TODO(zoeliu): To investigate whether a frame_type other than
// INTRA/ALTREF/GOLDEN/LAST needs to be specified seperately.
const MV_REFERENCE_FRAME frame_type = get_frame_type(cpi);
int64_t *const mode_thrs = rd_opt->prediction_type_threshes[frame_type];
const int is_alt_ref = frame_type == ALTREF_FRAME;
/* prediction (compound, single or hybrid) mode selection */
// NOTE: "is_alt_ref" is true only for OVERLAY/INTNL_OVERLAY frames
/*预测模式选择*/
if (is_alt_ref || frame_is_intra_only(cm))//只帧内单独预测,否则就要进行选择
current_frame->reference_mode = SINGLE_REFERENCE;
else
current_frame->reference_mode = REFERENCE_MODE_SELECT;
cm->interp_filter = SWITCHABLE;
if (cm->large_scale_tile) cm->interp_filter = EIGHTTAP_REGULAR;
cm->switchable_motion_mode = 1;//运动模式选择1
rdc->compound_ref_used_flag = 0;//字面意思:复合参考帧使用标志?
rdc->skip_mode_used_flag = 0;//跳过某些模式的标志
encode_frame_internal(cpi);//编码入口
for (i = 0; i < REFERENCE_MODES; ++i)
mode_thrs[i] = (mode_thrs[i] + rdc->comp_pred_diff[i] / cm->MBs) / 2;
//参考模式
if (current_frame->reference_mode == REFERENCE_MODE_SELECT) {
// Use a flag that includes 4x4 blocks
if (rdc->compound_ref_used_flag == 0) {
current_frame->reference_mode = SINGLE_REFERENCE;
#if CONFIG_ENTROPY_STATS
av1_zero(cpi->td.counts->comp_inter);
#endif // CONFIG_ENTROPY_STATS
}
}
// Re-check on the skip mode status as reference mode may have been changed.
// 重新检查跳过模式状态,因为参考模式可能已更改。
SkipModeInfo *const skip_mode_info = ¤t_frame->skip_mode_info;
if (frame_is_intra_only(cm) ||
current_frame->reference_mode == SINGLE_REFERENCE) {
skip_mode_info->skip_mode_allowed = 0;
skip_mode_info->skip_mode_flag = 0;
}
if (skip_mode_info->skip_mode_flag && rdc->skip_mode_used_flag == 0)
skip_mode_info->skip_mode_flag = 0;
if (!cm->large_scale_tile) {
if (cm->tx_mode == TX_MODE_SELECT && cpi->td.mb.txb_split_count == 0)
cm->tx_mode = TX_MODE_LARGEST;
}
} else {
encode_frame_internal(cpi);
}
}