美文网首页
(二十三)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