x264幀內預測

x264幀內預測


理論

    
1、宏塊大小是 16x16,每個宏塊包含一個 16x16 大小的亮度塊和兩個 8x8 的色度塊
2、亮度分量
    對於亮度分量而言,幀內預測只針對 16x16 的塊或者 4x4 的小塊,換句話說,對於亮度分量而言,進行幀內預測的時候,它只能被劃分爲 16x16(即不進行劃分)的塊,或者 4x4 的小塊。
    2.1、16x16 亮度塊
        有4種幀內預測模式:DC、H(水平模式)、V(垂直模式)、plane(平面模式)。對於的序號分別是:0、1、2、3.
    2.2、4x4 亮度塊
        有 9 種幀內預測模式:模式 0(垂直),模式 1(水平),模式 2(DC),模式3(45°),模式 4(135°),模式 5(116.6°),模式 6(153.4°),模式 7(63.4°),模式 8(26.6°)
    2.3、額外補充
        按照理論上,亮度分量只支持 16x16 和 4x4 的塊,但是後來增加了 8x8 的DCT,它要求提供 8x8 的幀內預測,因此,x264 提供了 8x8 塊的幀內預測。它的模式和 4x4 小塊的模式是一樣的。
3、色度分量對於色度分量,幀內預測只支持 8x8 的色度分量,也就是說宏塊對應的色度分量不用劃分,直接進行預測。它使用的預測方式和 16x16 的亮度塊一樣。
4、處理過程
    先計算宏塊下每個 4x4 小塊的最優模式,把所有 4x4 小塊的最優代價相加(假設爲 sum),然後計算 16x16 的塊的最優模式,與 sum 進行比較,決定使用哪一個作爲最優模式。



代碼


1、入口函數 x264_mb_analyse_intra
2、處理步驟
    2.1、進行 16x16 亮度塊的幀內預測
        (1)調用函數 predict_16x16_mode_available,選出 16x16 亮度塊可用的幀內模式(要根據鄰居塊是否存在來判別哪些模式可用)
        (2) 遍 歷 所 有 可 用 的 16x16 亮 度 塊 的 模 式 , 調 用 函 數 指 針predict_16x16[...]進行預測,然後計算 sad,最後選出 16x16 塊的最優模式
    2.2、進行 8x8 色度塊的幀內預測
        (1) 如 果 使 用 了 rdo 模 式 ( 可 以 由 用 戶 設 置 ), 那 麼 調 用x264_mb_analyse_intra_chroma 函數,進行下面處理:調用 predict_8x8chroma_mode_available 函數,選取 8x8 色度塊可用的幀內預測模式2)遍歷所有的 8x8 色度塊的預測模式,進行做魚操作,計算 sad,選出最優的模式
        (2)如果沒有使用 rdo 模式,那麼計算一些額外的 sad(相當於是 8x8色度塊的 sad),它們的模式應該和對應的 16x16 亮度塊的模式一樣,不用另外計算。
    2.3、進行 4x4 亮度塊的幀內預測,遍歷宏塊下所有的 4x4 小塊,對於每一個小塊,進行下面操作
        (1)調用 x264_mb_predict_intra4x4_mode 函數,得到一個從鄰居塊預測來的模式 pred_mode,用於後面 sad 的計算。
        (2)調用 predict_4x4_mode_available 函數,選取可用的 4x4 亮度塊的預測模式。
        (3)遍歷所有可用的預測模式,進行預測操作,選取最優的模式
        (4)對於最優的模式,調用 x264_mb_encode_i4x4,計算比特率
        (5)把所有的 4x4 小塊最優模式的代價相加,就得到了宏塊下 4x4 劃分的最優模式的代價
    2.4、如果有必要(使用 8x8 的 DCT 時),那麼進行 8x8 亮度塊的幀內預測
        (1)宏塊由 4 個 8x8 塊構成,因此要依次處理這 4 個塊。
        (2)對於每一個 8x8 可用的模式(由於 8x8 亮度預測模式和 4x4 的一樣,因此實際調用 predict_4x4_mode_available 函數來得到可用的預測模式),遍歷這些可用模式,進行 8x8 的預測操作,選出最優的模式,然後調用x264_mb_encode_i8x8 計算該最優模式的比特率。
        (3)累加宏塊下 8x8 小塊的最優代價,即爲 8x8 幀內預測模式的最優代價
3、具體代碼實現,抽取了幾個典型的函數作爲例子:

/* 幀內預測主函數 */
static void x264_mb_analyse_intra( x264_t *h, x264_mb_analysis_t *a, int i_cost_inter )
{
    const unsigned int flags = h->sh.i_type == SLICE_TYPE_I ? h->param.analyse.intra :
                                                              h->param.analyse.inter;
    const int i_stride = h->mb.pic.i_stride[0];
    uint8_t *p_src = h->mb.pic.p_fenc[0];
    uint8_t *p_dst = h->mb.pic.p_fdec[0];
    int
            f8_satd_rd_ratio = 0;
    int i, idx;
    int i_max;
    int predict_mode[9];
    const int i_satd_thresh = a->i_best_satd * 5/4 + a->i_lambda * 10;
    /*---------------- Try all mode and calculate their score ---------------*/
    /* 16x16 prediction selection */
    /* 16x16亮度 預測 */
    predict_16x16_mode_available( h->mb.i_neighbour, predict_mode, &i_max );
    for( i = 0; i < i_max; i++ )
    {
        int i_sad;
        int i_mode;
        i_mode = predict_mode[i];
        h->predict_16x16[i_mode]( p_dst, i_stride );
        i_sad = h->pixf.mbcmp[PIXEL_16x16]( p_dst, i_stride, p_src, i_stride ) +
                a->i_lambda * bs_size_ue( x264_mb_pred_mode16x16_fix[i_mode] );
        if( a->i_sad_i16x16 > i_sad )
        {
            a->i_predict16x16 = i_mode;
            a->i_sad_i16x16
        }
    }
    = i_sad;/* 8x8色度預測 */
    if( a->b_mbrd )
    {
        f8_satd_rd_ratio = ((unsigned)i_cost_inter << 8) / a->i_best_satd + 1;
        x264_mb_analyse_intra_chroma( h, a );
        if( h->mb.b_chroma_me )
            a->i_sad_i16x16 += a->i_sad_i8x8chroma;
        if( a->i_sad_i16x16 < i_satd_thresh )
        {
            h->mb.i_type = I_16x16;
            h->mb.i_intra16x16_pred_mode = a->i_predict16x16;
            a->i_sad_i16x16 = x264_rd_cost_mb( h, a->i_lambda2 );
        }
        else
            a->i_sad_i16x16 = a->i_sad_i16x16 * f8_satd_rd_ratio >> 8;
    }
    else
    {
        if( h->sh.i_type == SLICE_TYPE_B )
            /* cavlc mb type prefix */
            a->i_sad_i16x16 += a->i_lambda * i_mb_b_cost_table[I_16x16];
        if( a->b_fast_intra && a->i_sad_i16x16 > 2*i_cost_inter )
            return;
    }
    /* 4x4 prediction selection */
    /* 4x4亮度預測 */
    if( flags & X264_ANALYSE_I4x4 )
    {
        a->i_sad_i4x4 = 0;
        for( idx = 0; idx < 16; idx++ )
        {
            uint8_t *p_src_by;
            uint8_t *p_dst_by;
            int
                    i_best;
            int x, y;
            int i_pred_mode;
            i_pred_mode= x264_mb_predict_intra4x4_mode( h, idx );
            x = block_idx_x[idx];
            y = block_idx_y[idx];
            p_src_by = p_src + 4 * x + 4 * y * i_stride;
            p_dst_by = p_dst + 4 * x + 4 * y * i_stride;i_best = COST_MAX;
            predict_4x4_mode_available( h->mb.i_neighbour4[idx], predict_mode,
                                        &i_max );
            for( i = 0; i < i_max; i++ )
            {
                int i_sad;
                int i_mode;
                i_mode = predict_mode[i];
                h->predict_4x4[i_mode]( p_dst_by, i_stride );
                i_sad = h->pixf.mbcmp[PIXEL_4x4]( p_dst_by, i_stride,
                        p_src_by, i_stride )
                        + a->i_lambda * (i_pred_mode ==
                                         x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
                if( i_best > i_sad )
                {
                    a->i_predict4x4[x][y] = i_mode;
                    i_best = i_sad;
                }
            }
            a->i_sad_i4x4 += i_best;
            /* we need to encode this block now (for next ones) */
            h->predict_4x4[a->i_predict4x4[x][y]]( p_dst_by, i_stride );
            /* 計算該最優模式下的比特率 */
            x264_mb_encode_i4x4( h, idx, a->i_qp );
            h->mb.cache.intra4x4_pred_mode[x264_scan8[idx]] = a->i_predict4x4[x][y];
        }
        a->i_sad_i4x4 += a->i_lambda * 24;
        /* from JVT (SATD0) */
        if( a->b_mbrd )
        {
            if( h->mb.b_chroma_me )
                a->i_sad_i4x4 += a->i_sad_i8x8chroma;
            if( a->i_sad_i4x4 < i_satd_thresh )
            {
                h->mb.i_type = I_4x4;
                a->i_sad_i4x4 = x264_rd_cost_mb( h, a->i_lambda2 );
            }
            elsea->i_sad_i4x4 = a->i_sad_i4x4 * f8_satd_rd_ratio >> 8;
        }
        else
        {
            if( h->sh.i_type == SLICE_TYPE_B )
                a->i_sad_i4x4 += a->i_lambda * i_mb_b_cost_table[I_4x4];
        }
    }
    /* 8x8 prediction selection */
    /* 如果有必要,那麼進行8x8的亮度預測 */
    if( flags & X264_ANALYSE_I8x8 )
    {
        a->i_sad_i8x8 = 0;
        for( idx = 0; idx < 4; idx++ )
        {
            uint8_t *p_src_by;
            uint8_t *p_dst_by;
            int
                    i_best;
            int x, y;
            int i_pred_mode;
            i_pred_mode= x264_mb_predict_intra4x4_mode( h, 4*idx );
            x = idx&1;
            y = idx>>1;
            p_src_by = p_src + 8 * x + 8 * y * i_stride;
            p_dst_by = p_dst + 8 * x + 8 * y * i_stride;
            i_best = COST_MAX;
            predict_4x4_mode_available( h->mb.i_neighbour8[idx], predict_mode,
                                        &i_max );
            for( i = 0; i < i_max; i++ )
            {
                int i_sad;
                int i_mode;
                i_mode = predict_mode[i];
                h->predict_8x8[i_mode]( p_dst_by, i_stride, h->mb.i_neighbour );
                /* could use sa8d, but it doesn't seem worth the speed cost (without
mmx at least) */
                i_sad = h->pixf.mbcmp[PIXEL_8x8]( p_dst_by, i_stride,
                        p_src_by, i_stride )+ a->i_lambda * (i_pred_mode ==
                                                             x264_mb_pred_mode4x4_fix(i_mode) ? 1 : 4);
                if( i_best > i_sad )
                {
                    a->i_predict8x8[x][y] = i_mode;
                    i_best = i_sad;
                }
            }
            a->i_sad_i8x8 += i_best;
            /* we need to encode this block now (for next ones) */
            h->predict_8x8[a->i_predict8x8[x][y]]( p_dst_by, i_stride,
                                                   h->mb.i_neighbour );
            x264_mb_encode_i8x8( h, idx, a->i_qp );
            x264_macroblock_cache_intra8x8_pred( h, 2*x, 2*y, a->i_predict8x8[x][y] );
        }
        if( a->b_mbrd )
        {
            if( h->mb.b_chroma_me )
                a->i_sad_i8x8 += a->i_sad_i8x8chroma;
            if( a->i_sad_i8x8 < i_satd_thresh )
            {
                h->mb.i_type = I_8x8;
                a->i_sad_i8x8 = x264_rd_cost_mb( h, a->i_lambda2 );
            }
            else
                a->i_sad_i8x8 = a->i_sad_i8x8 * f8_satd_rd_ratio >> 8;
        }
        else
        {
            // FIXME some bias like in i4x4?
            if( h->sh.i_type == SLICE_TYPE_B )
                a->i_sad_i8x8 += a->i_lambda * i_mb_b_cost_table[I_8x8];
        }
    }
}
/* 選取 16x16 亮度塊,可用的幀內預測模式 */
static void predict_16x16_mode_available( unsigned int i_neighbour, int *mode, int
                                          *pi_count ){
    if( i_neighbour & MB_TOPLEFT )
    {
        /* top and left avaible */
        *mode++ = I_PRED_16x16_V;
        *mode++ = I_PRED_16x16_H;
        *mode++ = I_PRED_16x16_DC;
        *mode++ = I_PRED_16x16_P;
        *pi_count = 4;
    }
    else if( i_neighbour & MB_LEFT )
    {
        /* left available*/
        *mode++ = I_PRED_16x16_DC_LEFT;
        *mode++ = I_PRED_16x16_H;
        *pi_count = 2;
    }
    else if( i_neighbour & MB_TOP )
    {
        /* top available*/
        *mode++ = I_PRED_16x16_DC_TOP;
        *mode++ = I_PRED_16x16_V;
        *pi_count = 2;
    }
    else
    {
        /* none avaible */
        *mode = I_PRED_16x16_DC_128;
        *pi_count = 1;
    }
}
/* 從附近塊中預測出一個模式 pred_mode */
int x264_mb_predict_intra4x4_mode( x264_t *h, int idx )
{
    const int ma = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 1];
    const int mb = h->mb.cache.intra4x4_pred_mode[x264_scan8[idx] - 8];
    const int m = X264_MIN( x264_mb_pred_mode4x4_fix(ma),
                            x264_mb_pred_mode4x4_fix(mb) );
    if( m < 0 )
        return I_PRED_4x4_DC;
    return m;}
/* 4x4(8x8)亮度塊,可用的預測模式 */
static void predict_4x4_mode_available( unsigned int i_neighbour,
                                        int *mode, int *pi_count )
{
    /* FIXME even when b_tr == 0 there is some case where missing pixels
* are emulated and thus more mode are available TODO
* analysis and encode should be fixed too */
    int b_l = i_neighbour & MB_LEFT;
    int b_t = i_neighbour & MB_TOP;
    int b_tr = i_neighbour & MB_TOPRIGHT;
    if( b_l && b_t )
    {
        *mode++ = I_PRED_4x4_DC;
        *mode++ = I_PRED_4x4_H;
        *mode++ = I_PRED_4x4_V;
        *mode++ = I_PRED_4x4_DDR;
        *mode++ = I_PRED_4x4_VR;
        *mode++ = I_PRED_4x4_HD;
        *mode++ = I_PRED_4x4_HU;
        *pi_count = 7;
    }
    else if( b_l )
    {
        *mode++ = I_PRED_4x4_DC_LEFT;
        *mode++ = I_PRED_4x4_H;
        *mode++ = I_PRED_4x4_HU;
        *pi_count = 3;
    }
    else if( b_t )
    {
        *mode++ = I_PRED_4x4_DC_TOP;
        *mode++ = I_PRED_4x4_V;
        *pi_count = 2;
    }
    else
    {
        *mode++ = I_PRED_4x4_DC_128;
        *pi_count = 1;
    }
    if( b_t && b_tr ){
        *mode++ = I_PRED_4x4_DDL;
        *mode++ = I_PRED_4x4_VL;
        (*pi_count) += 2;
    }
}
/* 編碼/計算某個模式的比特率(爲了選取最優模式) */
void x264_mb_encode_i4x4( x264_t *h, int idx, int i_qscale )
{
    const int i_stride = h->mb.pic.i_stride[0];
    const int i_offset = 4 * block_idx_x[idx] + 4 * block_idx_y[idx] * i_stride;
    uint8_t *p_src = &h->mb.pic.p_fenc[0][i_offset];
    uint8_t *p_dst = &h->mb.pic.p_fdec[0][i_offset];
    int16_t dct4x4[4][4];
    if( h->mb.b_lossless )
    {
        sub_zigzag_4x4full( h->dct.block[idx].luma4x4, p_src, p_dst, i_stride );
        return;
    }
    h->dctf.sub4x4_dct( dct4x4, p_src, i_stride, p_dst, i_stride );
    quant_4x4( dct4x4, h->quant4_mf[CQM_4IY], i_qscale, 1 );
    scan_zigzag_4x4full( h->dct.block[idx].luma4x4, dct4x4 );
    x264_mb_dequant_4x4( dct4x4, h->dequant4_mf[CQM_4IY], i_qscale );
    /* output samples to fdec */
    h->dctf.add4x4_idct( p_dst, i_stride, dct4x4 );
}
/* 16x16 亮度塊水平預測 */
static void predict_16x16_h( uint8_t *src, int i_stride )
{
    int i,j;
    for( i = 0; i < 16; i++ )
    {
        uint8_t v;
        v = src[-1];
        for( j = 0; j < 16; j++ )
        {src[j] = v;
        }
        src += i_stride;
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章