x264_frame_deblock_row对一行宏块进行去块效应滤波处理,源码如下:
void x264_frame_deblock_row( x264_t *h, int mb_y )
{
int b_interlaced = SLICE_MBAFF; //是否隔行扫描
int a = h->sh.i_alpha_c0_offset - QP_BD_OFFSET;
int b = h->sh.i_beta_offset - QP_BD_OFFSET;
int qp_thresh = 15 - X264_MIN( a, b ) - X264_MAX( 0, h->pps->i_chroma_qp_index_offset );
int stridey = h->fdec->i_stride[0];
int strideuv = h->fdec->i_stride[1];
int chroma444 = CHROMA444;
int chroma_height = 16 >> CHROMA_V_SHIFT;
intptr_t uvdiff = chroma444 ? h->fdec->plane[2] - h->fdec->plane[1] : 1;
for( int mb_x = 0; mb_x < h->mb.i_mb_width; mb_x += (~b_interlaced | mb_y)&1, mb_y ^= b_interlaced ) //遍历一行中的每个宏块
{
x264_prefetch_fenc( h, h->fdec, mb_x, mb_y );
//主要是判断该宏块是否在原图像最左边或最上边,设置MB_LEFT和MB_TOP标志
x264_macroblock_cache_load_neighbours_deblock( h, mb_x, mb_y );
int mb_xy = h->mb.i_mb_xy;
int transform_8x8 = h->mb.mb_transform_size[mb_xy];
int intra_cur = IS_INTRA( h->mb.type[mb_xy] );
uint8_t (*bs)[8][4] = h->deblock_strength[mb_y&1][h->param.b_sliced_threads?mb_xy:mb_x];
pixel *pixy = h->fdec->plane[0] + 16*mb_y*stridey + 16*mb_x;
pixel *pixuv = h->fdec->plane[1] + chroma_height*mb_y*strideuv + 16*mb_x;
if( mb_y & MB_INTERLACED ) //隔行扫描,忽略
{
pixy -= 15*stridey;
pixuv -= (chroma_height-1)*strideuv;
}
int stride2y = stridey << MB_INTERLACED;
int stride2uv = strideuv << MB_INTERLACED;
int qp = h->mb.qp[mb_xy];
int qpc = h->chroma_qp_table[qp];
int first_edge_only = (h->mb.partition[mb_xy] == D_16x16 && !h->mb.cbp[mb_xy] && !intra_cur) || qp <= qp_thresh;
#define FILTER( intra, dir, edge, qp, chroma_qp )\
do\
{\
if( !(edge & 1) || !transform_8x8 )\
{\
deblock_edge##intra( h, pixy + 4*edge*(dir?stride2y:1),\
stride2y, bs[dir][edge], qp, a, b, 0,\
h->loopf.deblock_luma##intra[dir] );\
if( CHROMA_FORMAT == CHROMA_444 )\
{\
deblock_edge##intra( h, pixuv + 4*edge*(dir?stride2uv:1),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\
h->loopf.deblock_luma##intra[dir] );\
deblock_edge##intra( h, pixuv + uvdiff + 4*edge*(dir?stride2uv:1),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 0,\
h->loopf.deblock_luma##intra[dir] );\
}\
else if( CHROMA_FORMAT == CHROMA_420 && !(edge & 1) )\
{\
deblock_edge##intra( h, pixuv + edge*(dir?2*stride2uv:4),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\
h->loopf.deblock_chroma##intra[dir] );\
}\
}\
if( CHROMA_FORMAT == CHROMA_422 && (dir || !(edge & 1)) )\
{\
deblock_edge##intra( h, pixuv + edge*(dir?4*stride2uv:4),\
stride2uv, bs[dir][edge], chroma_qp, a, b, 1,\
h->loopf.deblock_chroma##intra[dir] );\
}\
} while( 0 )
if( h->mb.i_neighbour & MB_LEFT ) //如果是原图像最左边的宏块,是不需要滤波的,不会进去
{
if( b_interlaced && h->mb.field[h->mb.i_mb_left_xy[0]] != MB_INTERLACED ) //隔行扫描,忽略
{
//忽略
}
else //逐行扫描
{
int qpl = h->mb.qp[h->mb.i_mb_xy-1];
int qp_left = (qp + qpl + 1) >> 1;
int qpc_left = (qpc + h->chroma_qp_table[qpl] + 1) >> 1;
int intra_left = IS_INTRA( h->mb.type[h->mb.i_mb_xy-1] );
int intra_deblock = intra_cur || intra_left; //帧内编码,或者是宏块边缘
/* Any MB that was coded, or that analysis decided to skip, has quality commensurate with its QP.
* But if deblocking affects neighboring MBs that were force-skipped, blur might accumulate there.
* So reset their effective QP to max, to indicate that lack of guarantee. */
if( h->fdec->mb_info && M32( bs[0][0] ) )
{
#define RESET_EFFECTIVE_QP(xy) h->fdec->effective_qp[xy] |= 0xff * !!(h->fdec->mb_info[xy] & X264_MBINFO_CONSTANT);
RESET_EFFECTIVE_QP(mb_xy);
RESET_EFFECTIVE_QP(h->mb.i_mb_left_xy[0]);
}
if( intra_deblock ) //帧内编码,或者是宏块边缘,需要用强滤波(Bs==4)
FILTER( _intra, 0, 0, qp_left, qpc_left ); //1.对一个宏块最左边的像素滤波
else
FILTER( , 0, 0, qp_left, qpc_left );
}
}
if( !first_edge_only )
{
FILTER( , 0, 1, qp, qpc ); //2.第1列4x4块和第2列4x4块之间的边界滤波
FILTER( , 0, 2, qp, qpc ); //3.第2列4x4块和第3列4x4块...
FILTER( , 0, 3, qp, qpc ); //4.第3列4x4块和第4列4x4块...
}
if( h->mb.i_neighbour & MB_TOP ) //原图像最上方的宏块,是不需要滤波的,不会进去
{
if( b_interlaced && !(mb_y&1) && !MB_INTERLACED && h->mb.field[h->mb.i_mb_top_xy] ) //隔行扫描,忽略
{
//....
}
else //逐行扫描
{
int qpt = h->mb.qp[h->mb.i_mb_top_xy];
int qp_top = (qp + qpt + 1) >> 1;
int qpc_top = (qpc + h->chroma_qp_table[qpt] + 1) >> 1;
int intra_top = IS_INTRA( h->mb.type[h->mb.i_mb_top_xy] );
int intra_deblock = intra_cur || intra_top;
/* This edge has been modified, reset effective qp to max. */
if( h->fdec->mb_info && M32( bs[1][0] ) )
{
RESET_EFFECTIVE_QP(mb_xy);
RESET_EFFECTIVE_QP(h->mb.i_mb_top_xy);
}
if( (!b_interlaced || (!MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy])) && intra_deblock )
{
FILTER( _intra, 1, 0, qp_top, qpc_top );
}
else
{
if( intra_deblock )
M32( bs[1][0] ) = 0x03030303;
FILTER( , 1, 0, qp_top, qpc_top ); //5.对一个宏块最上方的像素滤波
}
}
}
if( !first_edge_only )
{
FILTER( , 1, 1, qp, qpc ); //6.第1行4x4块和第2行4x4块之间的边界滤波
FILTER( , 1, 2, qp, qpc ); //7.第2行4x4块和第3行4x4块之间的边界滤波
FILTER( , 1, 3, qp, qpc ); //8.第3行4x4块和第4行4x4块之间的边界滤波
}
#undef FILTER
}
}
从源码中可看出,x264_frame_deblock_row函数主要是对一行宏块进行滤波,for循环从左到右遍历一行中的每一个宏块。我们只分析逐行扫描情况,隔行扫描忽略。
第一步首先会调用x264_macroblock_cache_load_neighbours_deblock函数,它主要是判断一个宏块是否处于原图像的最左方或最上方,因为图像最左方和最上方的像素是不需要进行去块滤波的。x264_macroblock_cache_load_neighbours_deblock代码如下:
static ALWAYS_INLINE void x264_macroblock_cache_load_neighbours_deblock( x264_t *h, int mb_x, int mb_y )
{
//是否在一个slice的边界进行去块滤波
//h->sh.i_disable_deblocking_filter_idc等于2时,表示它只有在同一个slice才会去块滤波
int deblock_on_slice_edges = h->sh.i_disable_deblocking_filter_idc != 2;
h->mb.i_neighbour = 0;
h->mb.i_mb_xy = mb_y * h->mb.i_mb_stride + mb_x; //一维坐标
h->mb.b_interlaced = PARAM_INTERLACED && h->mb.field[h->mb.i_mb_xy]; //一直都是0
h->mb.i_mb_top_y = mb_y - (1 << MB_INTERLACED); //=mb_y - 1, 宏块上方y坐标
h->mb.i_mb_top_xy = mb_x + h->mb.i_mb_stride*h->mb.i_mb_top_y; //一维坐标
h->mb.i_mb_left_xy[1] =
h->mb.i_mb_left_xy[0] = h->mb.i_mb_xy - 1; //坐标为-1,宏块左边坐标
if( SLICE_MBAFF ) //隔行扫描,忽略
{
if( mb_y&1 )
{
if( mb_x && h->mb.field[h->mb.i_mb_xy - 1] != MB_INTERLACED )
h->mb.i_mb_left_xy[0] -= h->mb.i_mb_stride;
}
else
{
if( h->mb.i_mb_top_xy >= 0 && MB_INTERLACED && !h->mb.field[h->mb.i_mb_top_xy] )
{
h->mb.i_mb_top_xy += h->mb.i_mb_stride;
h->mb.i_mb_top_y++;
}
if( mb_x && h->mb.field[h->mb.i_mb_xy - 1] != MB_INTERLACED )
h->mb.i_mb_left_xy[1] += h->mb.i_mb_stride;
}
}
if( mb_x > 0 && (deblock_on_slice_edges ||
h->mb.slice_table[h->mb.i_mb_left_xy[0]] == h->mb.slice_table[h->mb.i_mb_xy]) )
h->mb.i_neighbour |= MB_LEFT; //mb_x==0时,说明是图像最左边的宏块
if( mb_y > MB_INTERLACED && (deblock_on_slice_edges
|| h->mb.slice_table[h->mb.i_mb_top_xy] == h->mb.slice_table[h->mb.i_mb_xy]) )
h->mb.i_neighbour |= MB_TOP; //mb_y==0时,说明是图像最上边的宏块
}
回到x264_frame_deblock_row函数,for循环中对每个宏块进行滤波,每个宏块是16x16宏块,因一个16x16宏块中有16个4x4块,需要对每两个4x4宏块的边界进行滤波,我在注释中对每个边界做了1~8的注释,对应下图:
filter02.png
FILTER是一个宏,执行具体的滤波操作,它主要调用deblock_edge(普通滤波,Bs=1,2,3)或deblock_edge_intra(强滤波,Bs=4)。这个暂时不分析,有时间再补上。
网友评论