1 av1的环路滤波组成
首先从整体上说,环路滤波器的目的是消除(或至少减少)编码后产生的块效应后,将重建图像送入参考列表用于帧内预测和帧间预测。
av1的环路滤波主要包含3个部分: loopfilter,cdef和restoration这三个部分的大致作用如下:
loopfilter:对边缘信息进行处理
cdef:通过整块的方差抑制噪声
restoration:进行自我导向滤波或者维纳滤波提升质量
首先看loopfilter的代码,分析在代码的注释中
底层代码主要看三个滤波的部分,这三个部分在loopfilter_frame函数之后之后给出
static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
/*环路滤波是一个闭环,这里的cpi和cm都不会传入到解码端
**AV1_COMMON保存的是编码解码都会使用到的参数和函数
**AV1_COMP保存的是滤波时候用到的大量标志位等信息
*/
const int num_planes = av1_num_planes(cm);
MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
/*print out qindex 用于输出qindex,不需要的话可以注释掉*/
int qindex = cpi->td.mb.qindex;
printf("\norder:%d, qindex:%d", cm->current_frame.order_hint, qindex);
assert(IMPLIES(is_lossless_requested(&cpi->oxcf),
cm->coded_lossless && cm->all_lossless));
const int use_loopfilter = !cm->coded_lossless && !cm->large_scale_tile;
const int use_cdef = cm->seq_params.enable_cdef && !cm->coded_lossless &&
!cm->large_scale_tile;
const int use_restoration = cm->seq_params.enable_restoration &&
!cm->all_lossless && !cm->large_scale_tile;
struct loopfilter *lf = &cm->lf;
#if CONFIG_COLLECT_COMPONENT_TIMING
start_timing(cpi, loop_filter_time);
#endif
if (use_loopfilter) {//选择滤波强度,av1里面一共有四个等级0123
aom_clear_system_state();
av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick);
} else {
lf->filter_level[0] = 0;
lf->filter_level[1] = 0;
}
if (lf->filter_level[0] || lf->filter_level[1]) {
if (cpi->num_workers > 1)//多线程loopfilter使用_mt
av1_loop_filter_frame_mt(&cm->cur_frame->buf, cm, xd, 0, num_planes, 0,
#if CONFIG_LPF_MASK
0,
#endif
cpi->workers, cpi->num_workers,
&cpi->lf_row_sync);
else
av1_loop_filter_frame(&cm->cur_frame->buf, cm, xd,
#if CONFIG_LPF_MASK
0,
#endif
0, num_planes, 0);//单线程滤波
// 1, num_planes, 0);
}
cdef_restoration_frame(cpi, cm, xd, use_restoration, use_cdef);//进行cdef和restoration
首先看av1_loop_filter_frame
这个函数,这里就不给出最底层的计算方法了,我的水平也改动不了
,先大概了解一下loopfilter的工作就好
static void loop_filter_rows(YV12_BUFFER_CONFIG *frame_buffer, AV1_COMMON *cm,
MACROBLOCKD *xd, int start, int stop,
#if CONFIG_LPF_MASK
int is_decoding,
#endif
int plane_start, int plane_end) {
struct macroblockd_plane *pd = xd->plane;
const int col_start = 0;
const int col_end = cm->mi_cols;
int mi_row, mi_col;
int plane;
//滤波强度
for (plane = plane_start; plane < plane_end; plane++) {
if (plane == 0 && !(cm->lf.filter_level[0]) && !(cm->lf.filter_level[1]))
break;
else if (plane == 1 && !(cm->lf.filter_level_u))
continue;
else if (plane == 2 && !(cm->lf.filter_level_v))
continue;
if (cm->lf.combine_vert_horz_lf) {
// filter all vertical and horizontal edges in every 128x128 super block
//每个128x128的块过滤水平和垂直边缘
for (mi_row = start; mi_row < stop; mi_row += MAX_MIB_SIZE) {
for (mi_col = col_start; mi_col < col_end; mi_col += MAX_MIB_SIZE) {
// filter vertical edges处理垂直边缘
av1_setup_dst_planes(pd, cm->seq_params.sb_size, frame_buffer, mi_row,
mi_col, plane, plane + 1);
av1_filter_block_plane_vert(cm, xd, plane, &pd[plane], mi_row,
mi_col);
// filter horizontal edges处理水平边缘
if (mi_col - MAX_MIB_SIZE >= 0) {
av1_setup_dst_planes(pd, cm->seq_params.sb_size, frame_buffer,
mi_row, mi_col - MAX_MIB_SIZE, plane,
plane + 1);
av1_filter_block_plane_horz(cm, xd, plane, &pd[plane], mi_row,
mi_col - MAX_MIB_SIZE);
}
}
// filter horizontal edges
av1_setup_dst_planes(pd, cm->seq_params.sb_size, frame_buffer, mi_row,
mi_col - MAX_MIB_SIZE, plane, plane + 1);
av1_filter_block_plane_horz(cm, xd, plane, &pd[plane], mi_row,
mi_col - MAX_MIB_SIZE);
}
} else {
// filter all vertical edges in every 128x128 super block
for (mi_row = start; mi_row < stop; mi_row += MAX_MIB_SIZE) {
for (mi_col = col_start; mi_col < col_end; mi_col += MAX_MIB_SIZE) {
av1_setup_dst_planes(pd, cm->seq_params.sb_size, frame_buffer, mi_row,
mi_col, plane, plane + 1);
av1_filter_block_plane_vert(cm, xd, plane, &pd[plane], mi_row,
mi_col);
}
}
// filter all horizontal edges in every 128x128 super block
for (mi_row = start; mi_row < stop; mi_row += MAX_MIB_SIZE) {
for (mi_col = col_start; mi_col < col_end; mi_col += MAX_MIB_SIZE) {
av1_setup_dst_planes(pd, cm->seq_params.sb_size, frame_buffer, mi_row,
mi_col, plane, plane + 1);
av1_filter_block_plane_horz(cm, xd, plane, &pd[plane], mi_row,
mi_col);
}
}
}
}
}
然后是cdef和restoration函数
static void cdef_restoration_frame(AV1_COMP *cpi, AV1_COMMON *cm,
MACROBLOCKD *xd, int use_restoration,
int use_cdef) {
if (use_restoration)
av1_loop_restoration_save_boundary_lines(&cm->cur_frame->buf, cm, 0);
if (use_cdef) {
#if CONFIG_COLLECT_COMPONENT_TIMING
start_timing(cpi, cdef_time);
#endif
// Find CDEF parameters
av1_cdef_search(&cm->cur_frame->buf, cpi->source, cm, xd,
cpi->sf.cdef_pick_method, cpi->td.mb.rdmult);
// Apply the filter函数入口
av1_cdef_frame(&cm->cur_frame->buf, cm, xd);
#if CONFIG_COLLECT_COMPONENT_TIMING
end_timing(cpi, cdef_time);
#endif
} else {
cm->cdef_info.cdef_bits = 0;
cm->cdef_info.cdef_strengths[0] = 0;
cm->cdef_info.nb_cdef_strengths = 1;
cm->cdef_info.cdef_uv_strengths[0] = 0;
}
superres_post_encode(cpi);
#if CONFIG_COLLECT_COMPONENT_TIMING
start_timing(cpi, loop_restoration_time);
#endif
if (use_restoration) {
av1_loop_restoration_save_boundary_lines(&cm->cur_frame->buf, cm, 1);
av1_pick_filter_restoration(cpi->source, cpi);
if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
if (cpi->num_workers > 1)//restoration函数入口
av1_loop_restoration_filter_frame_mt(&cm->cur_frame->buf, cm, 0,
cpi->workers, cpi->num_workers,
&cpi->lr_row_sync, &cpi->lr_ctxt);
else
av1_loop_restoration_filter_frame(&cm->cur_frame->buf, cm, 0,
&cpi->lr_ctxt);
}
} else {
cm->rst_info[0].frame_restoration_type = RESTORE_NONE;
cm->rst_info[1].frame_restoration_type = RESTORE_NONE;
cm->rst_info[2].frame_restoration_type = RESTORE_NONE;
}
#if CONFIG_COLLECT_COMPONENT_TIMING
end_timing(cpi, loop_restoration_time);
#endif
}
网友评论