x264中的decimate_score

孤街浪徒 提交于 2019-12-16 22:28:19

 为了减少残差系数使用的编码比特,x264中使用了一种方法--decimation。原话是这样子的:

Writing the 16 CBFs in an i16x16 block is quite costly, so decimation can save many bits. More useful with CAVLC, but still useful with CABAC. 中心思想是如果一个16x16块的非零残差系数个数很少且最大绝对值不超过1(用一个score来衡量),直接将其所有4x4块的残差系数置为0,这样子就不要为该16x16块发送16个cbf;

对于亮度,如果是8x8块,则score<4时,将残差系数全置为0;

                    如果是16x16块,则score<6时,将残差系数全置为0;

对于色度,则score<7时,将残差系数全置为0;

该技术一般用于帧间宏块,总共在下面几个函数应用:

x264_mb_encode_i16x16;

x264_macroblock_encode_p8x8_internal;

x264_macroblock_probe_skip_internal;

x264_macroblock_encode_internal;

x264_mb_encode_chroma_internal;

以x264_mb_encode_i16x16为例来看看:

static void x264_mb_encode_i16x16( x264_t *h, int p, int i_qp )

{

    pixel *p_src = h->mb.pic.p_fenc[p];

    pixel *p_dst = h->mb.pic.p_fdec[p];

 

    ALIGNED_ARRAY_N( dctcoef, dct4x4,[16],[16] );

    ALIGNED_ARRAY_N( dctcoef, dct_dc4x4,[16] );

 

    int nz, block_cbp = 0;

    int decimate_score = h->mb.b_dct_decimate ? 0 : 9;//I帧设置为9,p帧设置为0;

    int i_quant_cat = p ? CQM_4IC : CQM_4IY;

    int i_mode = h->mb.i_intra16x16_pred_mode;

 

    if( h->mb.b_lossless )

        x264_predict_lossless_16x16( h, p, i_mode );

    else

        h->predict_16x16[i_mode]( h->mb.pic.p_fdec[p] );

 

    if( h->mb.b_lossless )

    {

        for( int i = 0; i < 16; i++ )

        {

            int oe = block_idx_xy_fenc[i];

            int od = block_idx_xy_fdec[i];

            nz = h->zigzagf.sub_4x4ac( h->dct.luma4x4[16*p+i], p_src+oe, p_dst+od, &dct_dc4x4[block_idx_yx_1d[i]] );

            h->mb.cache.non_zero_count[x264_scan8[16*p+i]] = nz;

            block_cbp |= nz;

        }

        h->mb.i_cbp_luma |= block_cbp * 0xf;

        h->mb.cache.non_zero_count[x264_scan8[LUMA_DC+p]] = array_non_zero( dct_dc4x4, 16 );

        h->zigzagf.scan_4x4( h->dct.luma16x16_dc[p], dct_dc4x4 );

        return;

    }

 

    CLEAR_16x16_NNZ( p );

 

    h->dctf.sub16x16_dct( dct4x4, p_src, p_dst );//对所有16x16残差系数进行dct变换;

 

    if( h->mb.b_noise_reduction )

        for( int idx = 0; idx < 16; idx++ )

            h->quantf.denoise_dct( dct4x4[idx], h->nr_residual_sum[0], h->nr_offset[0], 16 );

 

    for( int idx = 0; idx < 16; idx++ )//将每个4x4小块的dc系数置0;

    {

        dct_dc4x4[block_idx_xy_1d[idx]] = dct4x4[idx][0];

        dct4x4[idx][0] = 0;

    }

 

    if( h->mb.b_trellis )

    {

        for( int idx = 0; idx < 16; idx++ )

            if( x264_quant_4x4_trellis( h, dct4x4[idx], i_quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_AC][p], 1, !!p, idx ) )

            {

                block_cbp = 0xf;

                h->zigzagf.scan_4x4( h->dct.luma4x4[16*p+idx], dct4x4[idx] );

                h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[i_quant_cat], i_qp );

                if( decimate_score < 6 ) decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16*p+idx] );

                h->mb.cache.non_zero_count[x264_scan8[16*p+idx]] = 1;

            }

    }

    else

    {

        for( int i8x8 = 0; i8x8 < 4; i8x8++ )//遍历4个8x8块;

        {

            nz = h->quantf.quant_4x4x4( &dct4x4[i8x8*4], h->quant4_mf[i_quant_cat][i_qp], h->quant4_bias[i_quant_cat][i_qp] );//量化,并且返回每个4x4小块是否有非零系数;

            if( nz )

            {

                block_cbp = 0xf;

                FOREACH_BIT( idx, i8x8*4, nz )//遍历每个有非零系数的4x4小块;

                {

                    h->zigzagf.scan_4x4( h->dct.luma4x4[16*p+idx], dct4x4[idx] );//扫描;

                    h->quantf.dequant_4x4( dct4x4[idx], h->dequant4_mf[i_quant_cat], i_qp );//反量化;

                    if( decimate_score < 6 ) decimate_score += h->quantf.decimate_score15( h->dct.luma4x4[16*p+idx] );//对扫描后的残差系数计算score;

                    h->mb.cache.non_zero_count[x264_scan8[16*p+idx]] = 1;

                }

            }

        }

    }

 

    /* Writing the 16 CBFs in an i16x16 block is quite costly, so decimation can save many bits. */

    /* More useful with CAVLC, but still useful with CABAC. */

    if( decimate_score < 6 )//如果score<6,则将该16x16块的残差系数这是为全0;

    {

        CLEAR_16x16_NNZ( p );

        block_cbp = 0;

    }

    else

        h->mb.i_cbp_luma |= block_cbp;

 

    h->dctf.dct4x4dc( dct_dc4x4 );//对dc系数做dct变换;

    if( h->mb.b_trellis )

        nz = x264_quant_luma_dc_trellis( h, dct_dc4x4, i_quant_cat, i_qp, ctx_cat_plane[DCT_LUMA_DC][p], 1, LUMA_DC+p );

    else

        nz = h->quantf.quant_4x4_dc( dct_dc4x4, h->quant4_mf[i_quant_cat][i_qp][0]>>1, h->quant4_bias[i_quant_cat][i_qp][0]<<1 );//对dc系数做量化;

 

    h->mb.cache.non_zero_count[x264_scan8[LUMA_DC+p]] = nz;

    if( nz )//如果dc残差系数中有非零系数

    {

        h->zigzagf.scan_4x4( h->dct.luma16x16_dc[p], dct_dc4x4 );//扫描

 

        /* output samples to fdec */

        h->dctf.idct4x4dc( dct_dc4x4 );//反变换;

        h->quantf.dequant_4x4_dc( dct_dc4x4, h->dequant4_mf[i_quant_cat], i_qp );  /* XXX not inversed *///反量化

        if( block_cbp )//存在非零系数,则把dc系数赋值回去,否则dc系数就是0;

            for( int i = 0; i < 16; i++ )

                dct4x4[i][0] = dct_dc4x4[block_idx_xy_1d[i]];

    }

 

    /* put pixels to fdec */

    if( block_cbp )//如果存在非零系数,则对残差系数反变换然后加到预测值上得到重建值;(如果score<6,则永远不会满足该条件)

        h->dctf.add16x16_idct( p_dst, dct4x4 );

    else if( nz )  //如果dc系数中存在非零系数,则将dc系数反变换然后加到预值上得到重建值;

        h->dctf.add16x16_idct_dc( p_dst, dct_dc4x4 );

      //否则的话重建值直接等于预测值;

}

其他函数应该类似;

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!