x264码率控制(一)

本文讲解一下x264大体的码率控制流程

码率控制分为帧级别的码率控制和宏块级别的。

帧级别的码率控制代码逻辑流程:

x264_encoder_encode()->

      x264_ratecontrol_start()-->

            rate_estimate_qscale() //传入帧的时候,先做一次帧级别的码率调控

/*根据帧复杂度,计算一个初步的帧初始qp*/

double wanted_bits, overflow = 1;

            rcc->last_satd = x264_rc_analyse_slice( h );
            rcc->short_term_cplxsum *= 0.5;
            rcc->short_term_cplxcount *= 0.5;
            rcc->short_term_cplxsum += rcc->last_satd / (CLIP_DURATION(h->fenc->f_duration) / BASE_FRAME_DURATION);
            rcc->short_term_cplxcount ++;

            rce.tex_bits = rcc->last_satd;
            rce.blurred_complexity = rcc->short_term_cplxsum / rcc->short_term_cplxcount;
            rce.mv_bits = 0;
            rce.p_count = rcc->nmb;
            rce.i_count = 0;
            rce.s_count = 0;
            rce.qscale = 1;
            rce.pict_type = pict_type;
            rce.i_duration = h->fenc->i_duration;

            if( h->param.rc.i_rc_method == X264_RC_CRF )
            {
                q = get_qscale( h, &rce, rcc->rate_factor_constant, h->fenc->i_frame );
            }
            else
            {
                q = get_qscale( h, &rce, rcc->wanted_bits_window / rcc->cplxr_sum, h->fenc->i_frame );

                /* ABR code can potentially be counterproductive in CBR, so just don't bother.
                 * Don't run it if the frame complexity is zero either. */
                if( !rcc->b_vbv_min_rate && rcc->last_satd )
                {
                    // FIXME is it simpler to keep track of wanted_bits in ratecontrol_end?
                    int i_frame_done = h->i_frame;
                    double time_done = i_frame_done / rcc->fps;
                    if( h->param.b_vfr_input && i_frame_done > 0 )
                        time_done = ((double)(h->fenc->i_reordered_pts - h->i_reordered_pts_delay)) * h->param.i_timebase_num / h->param.i_timebase_den;
                    wanted_bits = time_done * rcc->bitrate;
                    if( wanted_bits > 0 )
                    {
                        abr_buffer *= X264_MAX( 1, sqrt( time_done ) );
                        overflow = x264_clip3f( 1.0 + (predicted_bits - wanted_bits) / abr_buffer, .5, 2 );
                        q *= overflow;
                    }
                }
            }

//

static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor, int frame_num)
{
    x264_ratecontrol_t *rcc= h->rc;
    x264_zone_t *zone = get_zone( h, frame_num );
    double q;
    if( h->param.rc.b_mb_tree )
    {//CRF模式下,mb_tree基本都是开着的,
        double timescale = (double)h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
        q = pow( BASE_FRAME_DURATION / CLIP_DURATION(rce->i_duration * timescale), 1 - h->param.rc.f_qcompress );

//计算得到当前帧的初始qp值,这里并没有根据当前帧的复杂度信息来计算,因为后面还有枚举调整的过程,所以这里就简化了。
    }
    else
        q = pow( rce->blurred_complexity, 1 - rcc->qcompress );

    // avoid NaN's in the rc_eq
    if( !isfinite(q) || rce->tex_bits + rce->mv_bits == 0 )
        q = rcc->last_qscale_for[rce->pict_type];
    else
    {
        rcc->last_rceq = q;
        q /= rate_factor;
        rcc->last_qscale = q;
    }

    if( zone )
    {
        if( zone->b_force_qp )
            q = qp2qscale( zone->i_qp );
        else
            q /= zone->f_bitrate_factor;
    }

    return q;
}

//得到初始帧qp之后,枚举qp值,找到合适的当前帧的qp值。

static double clip_qscale( x264_t *h, int pict_type, double q )

target_fill = X264_MIN( rcc->buffer_fill + total_duration * rcc->vbv_max_rate * 0.5, rcc->buffer_size * 0.5 );
if( buffer_fill_cur < target_fill )
{
       q *= 1.01;
       terminate |= 1;
       continue;
}
/* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */

target_fill = x264_clip3f( rcc->buffer_fill - total_duration * rcc->vbv_max_rate * 0.5, rcc->buffer_size * 0.8, rcc->buffer_size );
if( rcc->b_vbv_min_rate && buffer_fill_cur > target_fill )
{
        q /= 1.01;
        terminate |= 2;
        continue;
 }

这里通过参数设置的maxrate和maxbuf大小,调整当前帧的qp值。这里得到的是qscale值,

static inline float qscale2qp( float qscale )
{
    return (12.0f + QP_BD_OFFSET) + 6.0f * log2f( qscale/0.85f );
}// 通过上面函数,将qscale转换为qp值,12.0 6.0 0.85均为经验系数

 

二 实际编码的时候宏块级别的qp调整

代码调用逻辑

slice_write()-->

        x264_macroblock_analyse( h );// 宏块分析

        /* encode this macroblock -> be careful it can change the mb type to P_SKIP if needed */
reencode:
        x264_macroblock_encode( h );//宏块编码

        x264_ratecontrol_mb(); //宏块qp 值选择

        /*根据帧最大码率,和buffer大小,以及一些因子参数计算出当前宏块能消耗的最大bits*/

        float b_max = b1 + ((rc->buffer_fill - rc->buffer_size + rc->buffer_rate) * 0.90f - b1) * trust_coeff;
        rc->qpm -= step_size;
        float b2 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices;
        while( rc->qpm > qp_min && rc->qpm < prev_row_qp
               && (rc->qpm > h->fdec->f_row_qp[0] || rc->single_frame_vbv)
               && (b2 < max_frame_size)
               && ((b2 < rc->frame_size_planned * 0.8f) || (b2 < b_max)) )
        {// 通过最大bits和当前宏块预测消耗的bits 进行比较,并做调整
            b1 = b2;
            rc->qpm -= step_size;
            b2 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices;
        }
        rc->qpm += step_size;

        /* avoid VBV underflow or MinCR violation */
        while( rc->qpm < qp_absolute_max && (b1 > max_frame_size) )
        {
            rc->qpm += step_size;
            b1 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices;
        }

// 上面是通过计算对当前宏块的qp值进行调大/或者调小,找到合适当前宏块的qp值。
 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值