X264码率控制一(abr码率控制)

本文详细阐述了X264的码率控制模型,包括P帧和B帧的QP计算、图像复杂度的评估、qscale的计算方法,以及帧级多线程编码对ABR码率控制的影响。文中提供了关键参数的解释和计算代码实例。
摘要由CSDN通过智能技术生成

X264码率控制一(abr码率控制) 

X264码率控制二(vbv码率控制)

X264码率控制三(Mb-Tree介绍)

码率控制的代码流程图

码率控制的关键的结构体参数介绍图

一、x264码率控制模型

1、P帧下的QP和QSCALE计算公式

2、P帧下的QP和QSCALE计算代码

static inline float qp2qscale( float qp )
{
    return 0.85f * powf( 2.0f, ( qp - (12.0f + QP_BD_OFFSET) ) / 6.0f );
}
static inline float qscale2qp( float qscale )
{
    return (12.0f + QP_BD_OFFSET) + 6.0f * log2f( qscale/0.85f );
}

        x264先根据输入视频图像复杂度和目标码率计算qpscale,在根据qpscale来计算出帧级的qp;每一帧的qscale的计算都是按照P帧的类型计算的,然后根据实际的帧类型,来调整,比如I帧的qscale计算会通过f_ip_factor参数来调整,B帧通过f_pb_factor来调整。

二、图像复杂度计算

1、复杂度计算公式

2、复杂度计算的代码

        复杂度的计算代码在rate_estimate_qscale()函数中,如下:

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;

复杂度是历史帧的stad的值的平均。cplxsum乘上0.5以及cplxcount 乘上0.5都是历史帧的复杂度的权重为0.5,当前帧的复杂度权重为0.5;当前帧的复杂度保存在blurred_complexity 中以便后面qscale的计算。

三、根据复杂度计算qscale

1、qscale的计算公式

参数解释:

qcompress:由用户配置的参数默认0.6,取值范围(0,1);

blurred_complexity:历史图像的平均模糊复杂度;

wanted_bits_window:编码帧总的目标码率大小;

cplxr_sum:历史帧bits*qscale/rceq的累加和;

avgrc_qscale:根据 未经过aq所有宏块的平均QP 计算而来;

2、qscale的计算代码

qscale的计算代码在函数get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor, int frame_num)中;

//代码有删减
static double get_qscale(x264_t *h, ratecontrol_entry_t *rce, double rate_factor, int frame_num)
{
    double q;
    if( h->param.rc.b_mb_tree )//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 );
    }
    else
        q = pow( rce->blurred_complexity, 1 - rcc->qcompress );//根据复杂度估算出一个qscale


    {
        rcc->last_rceq = q;
        q /= rate_factor;//将qscale除上rate_factor,rate_factor=wanted_bits_window / cplxr_sum
        rcc->last_qscale = q;
    }

    return q;
}

rate_factor的计算是在rate_estimate_qscale()函数中,代码如下:

q = get_qscale( h, &rce, rcc->wanted_bits_window / rcc->cplxr_sum, h->fenc->i_frame );

其中rate_factor=rcc->wanted_bits_window / rcc->cplxr_sum;

wanted_bits_window:编码帧总的目标码率大小;cplxr_sum:历史帧bits*qscale/rceq的累加和;这两个参数是在x264_ratecontrol_end()函数中更新的,代码如下:

//代码有删减
//bits是编码后的实际bits
int x264_ratecontrol_end( x264_t *h, int bits, int *filler )
{
    if( rc->b_abr )
    {
        if( h->sh.i_type != SLICE_TYPE_B )
            rc->cplxr_sum += bits * qp2qscale( rc->qpa_rc ) / rc->last_rceq;
        else
        {
            /* Depends on the fact that B-frame's QP is an offset from the following P-frame's.
             * Not perfectly accurate with B-refs, but good enough. */
            rc->cplxr_sum += bits * qp2qscale( rc->qpa_rc ) / (rc->last_rceq * h->param.rc.f_pb_factor);//B帧cplxr_sum的计算需要乘上f_pb_factor)
        }
        rc->cplxr_sum *= rc->cbr_decay;
        rc->wanted_bits_window += h->fenc->f_duration * rc->bitrate;//累加当前帧的目标码率
        rc->wanted_bits_window *= rc->cbr_decay;
    }
}

        代码中的rc->qpa_rc 是当前帧中所有mb的qp的平均值,也即avgrc_qscale=qp2qscale( rc->qpa_rc )代码如下,

rc->qpa_rc += rc->qpm * h->mb.i_mb_width; rc->qpa_rc /= h->mb.i_mb_count;

四、qscale的码率溢出处理

 1、qscale的码率溢出计算;

        实际编码出来的predicted_bits 比目标编码wanted_bits的要大,则overflow大于1,即溢出,溢出处理就是增加qscale来提高qp进而降低编码bits; 实际编码出来的predicted_bits 比目标编码wanted_bits的要小,则overflow小于1,也即溢出,溢出处理就是减小qscale来减小qp进而提升编码bits。abr_buffer是用来控制溢出的容忍度,由外部api参数rate_tolerance和帧率来控制,abr_buffer越小溢出系数overflow和1.0的差异越大(比1大的越多,或者比1.0小的越多),溢出处理也越明显。

 2、qscale的码率溢出计算代码:

//代码有删减
static float rate_estimate_qscale( x264_t *h )
{
    int64_t total_bits = 8*(h->stat.i_frame_size[SLICE_TYPE_I]
                          + h->stat.i_frame_size[SLICE_TYPE_P]
                          + h->stat.i_frame_size[SLICE_TYPE_B])
                       - rcc->filler_bits_sum;//计算已经编码完整帧总的bits数
    double abr_buffer = 2 * rcc->rate_tolerance * rcc->bitrate;
    double predicted_bits = total_bits;
    int i_frame_done = h->i_frame;//已经编码的帧数
    double time_done = i_frame_done / rcc->fps;//根据已经编码的帧数计算出已经编码的时长
    wanted_bits = time_done * rcc->bitrate;//计算已经编码的帧的bits大小
    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;
    }
}

五、图像编码bits的预估

1、帧级编码bits的预测公式

        由上面的公式可以看出图像编码bits和satd成正比,即satd越大bits越大 图像bits和qscale成反比,即qscale越大bits越小(qscale越大QP也越大)。

2、帧级编码bits的预测代码

typedef struct
{
    float coeff_min;
    float coeff;
    float count;
    float decay;
    float offset;
} predictor_t;

static float predict_size( predictor_t *p, float q, float var )
{
    return (p->coeff*var + p->offset) / (q*p->count);
}

        帧级编码bits的预测函数predict_size()的调用代码如下:

x264_encoder_encode()        

        -->x264_ratecontrol_start()      

                -->rate_estimate_qscale()              

                        -->predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd )//I/P 帧

                        -->predict_size( rcc->pred_b_from_p, q, h->fref[1][h->i_ref[1]-1]->i_satd );//B帧编码大小预测,根据最近的的参考P帧的satd来预测

3、coeff、offset参数更新

        当编码完成后实际的编码bits和qscale、satd都是已知的则可以更新coeff、offset ;

satd=last_satd采用的是lows->statd qscale=qp2qscale( rcc->qpa_rc )//qpa_rc未经过aq所有宏块的平均QP;      

4、coeff、offset参数更新的代码

//bits为实际编码后的bits,var为satd,q为qscale
static void update_predictor( predictor_t *p, float q, float var, float bits )
{
    float range = 1.5;
    if( var < 10 )
        return;
    float old_coeff = p->coeff / p->count;
    float old_offset = p->offset / p->count;
    float new_coeff = X264_MAX( (bits*q - old_offset) / var, p->coeff_min );
    float new_coeff_clipped = x264_clip3f( new_coeff, old_coeff/range, old_coeff*range );
    float new_offset = bits*q - new_coeff_clipped * var;
    if( new_offset >= 0 )
        new_coeff = new_coeff_clipped;
    else
        new_offset = 0;
    p->count  *= p->decay;
    p->coeff  *= p->decay;
    p->offset *= p->decay;
    p->count  ++;
    p->coeff  += new_coeff;
    p->offset += new_offset;
}

当前帧编码完成后,会调用update_predictor()函数来更新预测参数;调用代码流程如下:

六、 帧级多线程编码对abr码率控制流程

1、帧级多线程码率控制介绍

        帧级多线程开启时候相临连续的几个帧同时编码,导致后面的帧(帧序号大的帧)在启动编码的时候前面的帧可能没有编码完成,则在码率控制过程需要用到的编码码率则为使用predict_size()函数预测出的码率。如下图示例,第三个P帧编码启动时候I帧和第一个P帧都编码完成了,第二个P帧还么编码完成,则第三个P帧的预测时候第二个P帧的编码bits使用的是预测出来的bits。

2、帧级多线程编码的代码

代码如下:

//代码有删减
static float rate_estimate_qscale( x264_t *h )
{
   int64_t total_bits = 8*(h->stat.i_frame_size[SLICE_TYPE_I]
                          + h->stat.i_frame_size[SLICE_TYPE_P]
                          + h->stat.i_frame_size[SLICE_TYPE_B])
                       - rcc->filler_bits_sum;
   double predicted_bits = total_bits;
   if( h->i_thread_frames > 1 )//帧级多线程开启
   {
       int j = rcc - h->thread[0]->rc;
       for( int i = 1; i < h->i_thread_frames; i++ )
       {
             x264_t *t = h->thread[(j+i) % h->i_thread_frames];
             double bits = t->rc->frame_size_planned;
             if( !t->b_thread_active )//b_thread_active为1表示线程编码未完成,0表示线程没有编码
                  continue;
             bits = X264_MAX(bits, t->rc->frame_size_estimated);
             predicted_bits += bits;
        }
    }

}

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FFmpeg的ABR是指自适应比特率(Adaptive Bitrate)编码。它允许根据网络条件和设备能力动态调整视频的比特率,以提供更好的观看体验。对于x264编码器,使用FFmpeg进行ABR编码的示例命令如下: ffmpeg -i <input> -c:v libx264 -b:v 1M -pass 1 -f null /dev/null ffmpeg -i <input> -c:v libx264 -b:v 1M -pass 2 <output>.mp4 而对于VP9编码器,使用FFmpeg进行ABR编码的示例命令如下: ffmpeg -i <input> -c:v libvpx-vp9 -b:v 1M -pass 1 -f null /dev/null ffmpeg -i <input> -c:v libvpx-vp9 -b:v 1M -pass 2 <output>.webm 这些命令中的`<input>`是输入文件的路径,`<output>`是输出文件的路径。通过使用两个pass,FFmpeg会先进行一次预处理,然后根据第一次编码的结果进行第二次编码来优化视频质量。其中,`-b:v 1M`表示目标比特率为1Mbps。这样,FFmpeg就可以根据设定的比特率进行自适应的编码,以适应不同的网络和设备情况。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [视频编码-码率控制CQP/CRF/ABR/CBR/VBV](https://blog.csdn.net/yinshipin007/article/details/125900485)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值