美文网首页
(二十三)x264_frame_deblock_row滤波函数

(二十三)x264_frame_deblock_row滤波函数

作者: 奔向火星005 | 来源:发表于2018-09-26 16:04 被阅读0次

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)。这个暂时不分析,有时间再补上。

相关文章

网友评论

      本文标题:(二十三)x264_frame_deblock_row滤波函数

      本文链接:https://www.haomeiwen.com/subject/hbzdoftx.html