天天看點

x264源碼解析:碼率控制之mbtree - propagate 計算流程碼率控制系列

碼率控制系列

  • 碼率控制之ABR

    碼率控制之ABR 使用指南與分析

  • 碼率控制之MBTree

    宏塊樹 mbtree 使用指南與源碼分析

    x264源碼解析:碼率控制之mbtree — — – x264_macroblock_tree

    x264源碼解析:lookahead之frametype — x264_slicetype_path (Viterbi算法)

    x264源碼解析:lookahead之md/mv — — x264_slicetype_frame_cost

    x264源碼解析:lookahead之cost計算基礎 x264_slicetype_mb_cost等

    x264源碼解析:碼率控制之mbtree — — – propagate 計算流程【本文】

    x264源碼解析:碼率控制之mbtree — — – qp調整

  • 碼率控制之AQ

    [x264/x265] Adaptive Quantization 使用指南

    x264源碼解析:碼率控制之adaptive quantization

    x265源碼解析:碼率控制之adaptive quantization【待補充】

  • 碼率控制之VBV

    x264源碼解析:碼率控制之VBV 幀級

    x264源碼解析:碼率控制之VBV 宏塊級

propagate 是影響反向傳播

//! cost傳播
static void x264_macroblock_tree_propagate( x264_t *h, x264_frame_t **frames, float average_duration, int p0, int p1, int b, int referenced )
{
    uint16_t *ref_costs[] = {frames[p0]->i_propagate_cost,frames[p1]->i_propagate_cost};     ///<
    int dist_scale_factor = ( ((b-p0) << ) + ((p1-p0) >> ) ) / (p1-p0);
    int i_bipred_weight = h->param.analyse.b_weighted_bipred ?  - (dist_scale_factor>>) : ;
    int16_t (*mvs[])[] = { frames[b]->lowres_mvs[][b-p0-], frames[b]->lowres_mvs[][p1-b-] };
    int bipred_weights[] = {i_bipred_weight,  - i_bipred_weight};
    int16_t *buf = h->scratch_buffer;
    uint16_t *propagate_cost = frames[b]->i_propagate_cost;         ///< curF propagate cost
    uint16_t *lowres_costs = frames[b]->lowres_costs[b-p0][p1-b];   ///< curF cost

    x264_emms();
    float fps_factor = CLIP_DURATION(frames[b]->f_duration) / (CLIP_DURATION(average_duration) * f) * MBTREE_PRECISION;

    /* For non-reffed frames the source costs are always zero, so just memset one row and re-use it. */
    if( !referenced )
        memset( frames[b]->i_propagate_cost, , h->mb.i_mb_width * sizeof(uint16_t) );

    for( h->mb.i_mb_y = ; h->mb.i_mb_y < h->mb.i_mb_height; h->mb.i_mb_y++ )
    {
        int mb_index = h->mb.i_mb_y*h->mb.i_mb_stride;
        h->mc.mbtree_propagate_cost( buf, propagate_cost,
            frames[b]->i_intra_cost+mb_index, lowres_costs+mb_index,
            frames[b]->i_inv_qscale_factor+mb_index, &fps_factor, h->mb.i_mb_width );
        if( referenced )
            propagate_cost += h->mb.i_mb_width;

        h->mc.mbtree_propagate_list( h, ref_costs[], &mvs[][mb_index], buf, &lowres_costs[mb_index],
                                     bipred_weights[], h->mb.i_mb_y, h->mb.i_mb_width,  );      ///< propagate_amount加到L0參考幀上
        if( b != p1 )                                            
        {
            h->mc.mbtree_propagate_list( h, ref_costs[], &mvs[][mb_index], buf, &lowres_costs[mb_index],
                                         bipred_weights[], h->mb.i_mb_y, h->mb.i_mb_width,  );  ///< L1
        }
    }

    if( h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead && referenced )
        x264_macroblock_tree_finish( h, frames[b], average_duration, b == p1 ? b - p0 :  );
}
           
//! 計算propagate_amount
/* Estimate the total amount of influence on future quality that could be had if we
 * were to improve the reference samples used to inter predict any given macroblock. */
static void mbtree_propagate_cost( int16_t *dst, uint16_t *propagate_in, uint16_t *intra_costs,
                                   uint16_t *inter_costs, uint16_t *inv_qscales, float *fps_factor, int len )
{
    float fps = *fps_factor;
    for( int i = ; i < len; i++ )      ///< row
    {
        int intra_cost = intra_costs[i];
        int inter_cost = X264_MIN(intra_costs[i], inter_costs[i] & LOWRES_COST_MASK);
        float propagate_intra  = intra_cost * inv_qscales[i];
        float propagate_amount = propagate_in[i] + propagate_intra*fps;
        float propagate_num    = intra_cost - inter_cost;
        float propagate_denom  = intra_cost;
        dst[i] = X264_MIN((int)(propagate_amount * propagate_num / propagate_denom + ), );
    }
}
           

propagate_num/propagate_denom = 1 - inter cost/intra cost =

propagate_fraction

propagate_amount

=(intra_cost+propagate_in) * propagate_fraction

//! propagate_amount算入參考幀propagate_in
static void mbtree_propagate_list( x264_t *h, uint16_t *ref_costs, int16_t (*mvs)[],
                                   int16_t *propagate_amount, uint16_t *lowres_costs,
                                   int bipred_weight, int mb_y, int len, int list )
{
    unsigned stride = h->mb.i_mb_stride;
    unsigned width = h->mb.i_mb_width;
    unsigned height = h->mb.i_mb_height;

    for( unsigned i = ; i < len; i++ )     ///< row
    {
        int lists_used = lowres_costs[i]>>LOWRES_COST_SHIFT;

        if( !(lists_used & ( << list)) )
            continue;

        int listamount = propagate_amount[i];
        /* Apply bipred weighting. */
        if( lists_used ==  )
            listamount = (listamount * bipred_weight + ) >> ;

        /* Early termination for simple case of mv0. */
        if( !M32( mvs[i] ) )
        {
            MC_CLIP_ADD( ref_costs[mb_y*stride + i], listamount );
            continue;
        }

        int x = mvs[i][];
        int y = mvs[i][];
        unsigned mbx = (x>>)+i;
        unsigned mby = (y>>)+mb_y;
        unsigned idx0 = mbx + mby * stride;
        unsigned idx2 = idx0 + stride;
        x &= ;
        y &= ;
        int idx0weight = (-y)*(-x);         ///< mv計算位置,再計算參考宏塊權值
        int idx1weight = (-y)*x;
        int idx2weight = y*(-x);
        int idx3weight = y*x;
        idx0weight = (idx0weight * listamount + ) >> ;
        idx1weight = (idx1weight * listamount + ) >> ;
        idx2weight = (idx2weight * listamount + ) >> ;
        idx3weight = (idx3weight * listamount + ) >> ;

        if( mbx < width- && mby < height- )   ///< 影響4個宏塊
        {
            MC_CLIP_ADD( ref_costs[idx0+], idx0weight );
            MC_CLIP_ADD( ref_costs[idx0+], idx1weight );
            MC_CLIP_ADD( ref_costs[idx2+], idx2weight );
            MC_CLIP_ADD( ref_costs[idx2+], idx3weight );
        }
        else
        {
            /* Note: this takes advantage of unsigned representation to
             * catch negative mbx/mby. */
            if( mby < height )
            {
                if( mbx < width )
                    MC_CLIP_ADD( ref_costs[idx0+], idx0weight );
                if( mbx+ < width )
                    MC_CLIP_ADD( ref_costs[idx0+], idx1weight );
            }
            if( mby+ < height )
            {
                if( mbx < width )
                    MC_CLIP_ADD( ref_costs[idx2+], idx2weight );
                if( mbx+ < width )
                    MC_CLIP_ADD( ref_costs[idx2+], idx3weight );
            }
        }
    }
}