x264 码率控制:ABR模式
2017-07-21 17:15
344 查看
前段时间看了一下x264 码率控制部分,在这里简要分析一下x264的ABR模式相关代码,有不对的地方欢迎指正。
因为ABR模式在控制过程中会产生较大的码率波动,进而导致图像质量不稳定,同时在Http Adaptive Streaming中,也会导致视频segment大小不稳定,在接收端产生卡顿。所以ABR模式一般配合vbv使用,使用vbv buffer来限制码率的波动。
ABR模式的流程图如下:
ABR会在帧级、行级和宏块级去调整qscale(QP)。帧级和行级调整的目的主要有两个:1,总码率逼近目标码率;2,vbvbuffer不会overflow或者underflow,即码流大小稳定。宏块级的调整主要是Adaptive Quantization(AQ)和MB-tree,前者作用于空域,根据宏块的平滑程度调整qscale,后者作用于时域,根据宏块被后续帧参考的多少来决定其重要性,继而调整qscale。
和码率控制相关的函数可以参见
zhanghui_cuc x264源码分析与应用示
4000
例(二)——码率控制 http://blog.csdn.net/nonmarking/article/details/50737198
qscale的初始化和调整过程主要在 rate_estimate_qscale( )函数中完成,我们先从这个函数开始看起。
rate_estimate_qscale( )
可以看到,ABR模式下,qscale的初值由get_qscale函数计算得出,然后在不开启vbv的情况下,根据(predicted_bits- wanted_bits)来调整qscale;在开启vbv的情况下,使用clip_qscale( ),根据vbv buffer的状态来调整qscale.
get_qscale( )
get_qscale( )函数用于计算qscale的初值,在MB-tree默认开启的情况下,不再使用模糊复杂度公式计算qscale,而是会根据fps计算出一个固定值,然后通过rate_factor进行调整。
q /=rate_factor;
rate_factor的更新是在x264_ratecontrol_end( ),公式如下
rate_factor=rcc->wanted_bits_window / rcc->cplxr_sum;
rc->cplxr_sum+= bits * qp2qscale( rc->qpa_rc ) / rc->last_rceq;
rc->wanted_bits_window+= h->fenc->f_duration * rc->bitrate;
bits是每一帧的实际比特数,rc->qpa_rc是最后帧级和行级调整完后的qp, rc->last_rceq上面求出的qscale初值。rc->wanted_bits_window是当前目标比特数。
由以上公式可以看到,rate_factor由两个比值决定:
目标比特数/实际比特数,比值越大→rate_factor越大→qscale和QP越小。
上一帧调整前qscale/上一帧调整后qscale,这个比值一般处于(0,1),比值越小说明上一帧调整幅度越大→rate_factor越小→qscale和QP越大。
clip_qscale( )
clip_qscale( )通过预测当前qscale下未来n帧的大小来估计vbv的状态,如果vbv buffer将overflow,则增大qscale;如果buffer将会underflow,则减小qscale。
在帧级调整完QP后,编码每个MB时,Adaptive Quantization和MB-tree会使用qp_offset对QP进行调整,这一步由函数x264_ratecontrol_mb_qp()实现。
AQ产生的qp_offset在函数x264_adaptive_quant_frame( )中,根据宏块的AC系数来调整qp_offset,相比于DC系数是图像的低频成分,反映了像素值的平均大小,AC系数是图像的高频成分,反映了图像的复杂程度。如果AC系数越低,则认为该宏块越平滑,其QP越小,如果AC系数越大,该宏块越复杂,则增大其QP。
MB-tree产生的offset在x264_macroblock_tree_finish( )中,如果一个宏块被后面的帧参考越多,则认为其重要性越高,则减小该宏块的QP,给该宏块分配更多码率,反之增大QP,MB-tree相关算法具体参见http://blog.csdn.net/zhoudegui88/article/details/73017216
每编码完一行后,会利用预测模型对当前帧大小进行预测,然后根据VBV buffer fill 对QP进行微调。这一步是在x264_ratecontrol_mb()中进行。
x264_ratecontrol_mb( )
编完一帧后,会在x264_ratecontrol_end()计算该帧的一些数据 如各种宏块类型的数量、平均QP、写入stat file(2 pass),更新VBV buffer状态和上面提到的rate factor。
参考内容:
UnderstandingRate Control Modes (x264, x265)
http://slhck.info/video/2017/03/01/rate-control.html
x264源码分析与应用示例(二)——码率控制
http://blog.csdn.net/nonmarking/article/details/50737198
x264 自适应量化模式 (AQ Adaptive Quantization) 初探
http://blog.csdn.net/ljb_wh/article/details/15815063
X264码率控制总结2——x264码率控制方法概述
http://blog.csdn.net/chenchong_219/article/details/43941641
因为ABR模式在控制过程中会产生较大的码率波动,进而导致图像质量不稳定,同时在Http Adaptive Streaming中,也会导致视频segment大小不稳定,在接收端产生卡顿。所以ABR模式一般配合vbv使用,使用vbv buffer来限制码率的波动。
ABR模式的流程图如下:
ABR会在帧级、行级和宏块级去调整qscale(QP)。帧级和行级调整的目的主要有两个:1,总码率逼近目标码率;2,vbvbuffer不会overflow或者underflow,即码流大小稳定。宏块级的调整主要是Adaptive Quantization(AQ)和MB-tree,前者作用于空域,根据宏块的平滑程度调整qscale,后者作用于时域,根据宏块被后续帧参考的多少来决定其重要性,继而调整qscale。
和码率控制相关的函数可以参见
zhanghui_cuc x264源码分析与应用示
4000
例(二)——码率控制 http://blog.csdn.net/nonmarking/article/details/50737198
qscale的初始化和调整过程主要在 rate_estimate_qscale( )函数中完成,我们先从这个函数开始看起。
rate_estimate_qscale( )
static float rate_estimate_qscale( x264_t *h ) { float q; x264_ratecontrol_t *rcc = h->rc; ratecontrol_entry_t rce = {0}; int pict_type = h->sh.i_type; int64_t total_bits = 8*(h->stat.i_frame_size[SLICE_TYPE_I] //total bits已编码比特数 + h->stat.i_frame_size[SLICE_TYPE_P] + h->stat.i_frame_size[SLICE_TYPE_B]) - rcc->filler_bits_sum; //编码完成帧的filler data大小(不计入视频大小) if( rcc->b_2pass ) { rce = *rcc->rce; if( pict_type != rce.pict_type ) { x264_log( h, X264_LOG_ERROR, "slice=%c but 2pass stats say %c\n", slice_type_to_char[pict_type], slice_type_to_char[rce.pict_type] ); } } if( pict_type == SLICE_TYPE_B ) { /* B-frames don't have independent ratecontrol, but rather get the * average QP of the two adjacent P-frames + an offset */ //B帧的QP由两个相邻的P帧的QP计算而来 int i0 = IS_X264_TYPE_I(h->fref_nearest[0]->i_type); int i1 = IS_X264_TYPE_I(h->fref_nearest[1]->i_type); int dt0 = abs(h->fenc->i_poc - h->fref_nearest[0]->i_poc); int dt1 = abs(h->fenc->i_poc - h->fref_nearest[1]->i_poc); float q0 = h->fref_nearest[0]->f_qp_avg_rc; float q1 = h->fref_nearest[1]->f_qp_avg_rc; if( h->fref_nearest[0]->i_type == X264_TYPE_BREF ) q0 -= rcc->pb_offset/2; if( h->fref_nearest[1]->i_type == X264_TYPE_BREF ) q1 -= rcc->pb_offset/2; if( i0 && i1 ) q = (q0 + q1) / 2 + rcc->ip_offset; else if( i0 ) q = q1; else if( i1 ) q = q0; else q = (q0*dt1 + q1*dt0) / (dt0 + dt1); if( h->fenc->b_kept_as_ref ) q += rcc->pb_offset/2; else q += rcc->pb_offset; rcc->qp_novbv = q; q = qp2qscale( q ); if( rcc->b_2pass ) rcc->frame_size_planned = qscale2bits( &rce, q ); else rcc->frame_size_planned = predict_size( rcc->pred_b_from_p, q, h->fref[1][h->i_ref[1]-1]->i_satd ); /* Limit planned size by MinCR */ if( rcc->b_vbv ) rcc->frame_size_planned = X264_MIN( rcc->frame_size_planned, rcc->frame_size_maximum ); h->rc->frame_size_estimated = rcc->frame_size_planned; /* For row SATDs */ if( rcc->b_vbv ) rcc->last_satd = x264_rc_analyse_slice( h ); //根据mb-tree的结果重新计算frame SATD cost,计算每一行的SATD cost return q; } else { double abr_buffer = 2 * rcc->rate_tolerance * rcc->bitrate;//abr缓存,用于控制实际码流大小和目标大小的差值 double predicted_bits = total_bits; if( h->i_thread_frames > 1 ) //预测当前线程中的编码帧大小 { int j = h->rc - 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 ) continue; bits = X264_MAX(bits, t->rc->frame_size_estimated); predicted_bits += bits; //已编码码流大小+线程中编码帧的大小 } } if( rcc->b_2pass ) //2pass部分暂时跳过 { double lmin = rcc->lmin[pict_type]; double lmax = rcc->lmax[pict_type]; double diff; /* Adjust ABR buffer based on distance to the end of the video. */ if( rcc->num_entries > h->i_frame ) { double final_bits = rcc->entry_out[rcc->num_entries-1]->expected_bits; double video_pos = rce.expected_bits / final_bits; double scale_factor = sqrt( (1 - video_pos) * rcc->num_entries ); abr_buffer *= 0.5 * X264_MAX( scale_factor, 0.5 ); } diff = predicted_bits - rce.expected_bits; q = rce.new_qscale; q /= x264_clip3f((abr_buffer - diff) / abr_buffer, .5, 2); if( h->i_frame >= rcc->fps && rcc->expected_bits_sum >= 1 ) { /* Adjust quant based on the difference between * achieved and expected bitrate so far */ double cur_time = (double)h->i_frame / rcc->num_entries; double w = x264_clip3f( cur_time*100, 0.0, 1.0 ); q *= pow( (double)total_bits / rcc->expected_bits_sum, w ); } rcc->qp_novbv = qscale2qp( q ); if( rcc->b_vbv ) { /* Do not overflow vbv */ double expected_size = qscale2bits( &rce, q ); double expected_vbv = rcc->buffer_fill + rcc->buffer_rate - expected_size; double expected_fullness = rce.expected_vbv / rcc->buffer_size; double qmax = q*(2 - expected_fullness); double size_constraint = 1 + expected_fullness; qmax = X264_MAX( qmax, rce.new_qscale ); if( expected_fullness < .05 ) qmax = lmax; qmax = X264_MIN(qmax, lmax); while( ((expected_vbv < rce.expected_vbv/size_constraint) && (q < qmax)) || ((expected_vbv < 0) && (q < lmax))) { q *= 1.05; expected_size = qscale2bits(&rce, q); expected_vbv = rcc->buffer_fill + rcc->buffer_rate - expected_size; } rcc->last_satd = x264_rc_analyse_slice( h ); } q = x264_clip3f( q, lmin, lmax ); } else /* 1pass ABR */ { /* Calculate the quantizer which would have produced the desired * average bitrate if it had been applied to all frames so far. * Then modulate that quant based on the current frame's complexity * relative to the average complexity so far (using the 2pass RCEQ). * Then bias the quant up or down if total size so far was far from * the target. * Result: Depending on the value of rate_tolerance, there is a * tradeoff between quality and bitrate precision. But at large * tolerances, the bit distribution approaches that of 2pass. */ double wanted_bits, overflow = 1; rcc->last_satd = x264_rc_analyse_slice( h ); //根据mb-tree的结果重新计算frame SATD cost,计算每一行的SATD cost 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; //旧版x264所用的复杂度公式 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 );//计算每一帧的qscale初值并根据rate_factor调整 /* 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 ) //不开启vbv时会增加一次调整 { // 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 ) ); //abr_buffer:用来控制实际比特数跟目标比特数的差值 overflow = x264_clip3f( 1.0 + (predicted_bits - wanted_bits) / abr_buffer, .5, 2 ); q *= overflow; //根据差值调整qscale } } } if( pict_type == SLICE_TYPE_I && h->param.i_keyint_max > 1 /* should test _next_ pict type, but that isn't decided yet */ && rcc->last_non_b_pict_type != SLICE_TYPE_I ) { q = qp2qscale( rcc->accum_p_qp / rcc->accum_p_norm ); q /= fabs( h->param.rc.f_ip_factor ); } else if( h->i_frame > 0 ) { if( h->param.rc.i_rc_method != X264_RC_CRF ) { /* Asymmetric clipping, because symmetric would prevent * overflow control in areas of rapidly oscillating complexity */ double lmin = rcc->last_qscale_for[pict_type] / rcc->lstep; double lmax = rcc->last_qscale_for[pict_type] * rcc->lstep; if( overflow > 1.1 && h->i_frame > 3 ) lmax *= rcc->lstep; else if( overflow < 0.9 ) lmin /= rcc->lstep; q = x264_clip3f(q, lmin, lmax); } } else if( h->param.rc.i_rc_method == X264_RC_CRF && rcc->qcompress != 1 ) { q = qp2qscale( ABR_INIT_QP ) / fabs( h->param.rc.f_ip_factor ); } rcc->qp_novbv = qscale2qp( q ); //FIXME use get_diff_limited_q() ? q = clip_qscale( h, pict_type, q ); //根据vbv buffer的状态调整qscale } rcc->last_qscale_for[pict_type] = rcc->last_qscale = q; if( !(rcc->b_2pass && !rcc->b_vbv) && h->fenc->i_frame == 0 ) rcc->last_qscale_for[SLICE_TYPE_P] = q * fabs( h->param.rc.f_ip_factor ); if( rcc->b_2pass ) rcc->frame_size_planned = qscale2bits( &rce, q ); else rcc->frame_size_planned = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); /* Always use up the whole VBV in this case. */ if( rcc->single_frame_vbv ) rcc->frame_size_planned = rcc->buffer_rate; /* Limit planned size by MinCR */ if( rcc->b_vbv ) rcc->frame_size_planned = X264_MIN( rcc->frame_size_planned, rcc->frame_size_maximum ); h->rc->frame_size_estimated = rcc->frame_size_planned; //size-estimated在当前帧编码完后会更新成实际编码大小 return q; } }
可以看到,ABR模式下,qscale的初值由get_qscale函数计算得出,然后在不开启vbv的情况下,根据(predicted_bits- wanted_bits)来调整qscale;在开启vbv的情况下,使用clip_qscale( ),根据vbv buffer的状态来调整qscale.
get_qscale( )
get_qscale( )函数用于计算qscale的初值,在MB-tree默认开启的情况下,不再使用模糊复杂度公式计算qscale,而是会根据fps计算出一个固定值,然后通过rate_factor进行调整。
q /=rate_factor;
rate_factor的更新是在x264_ratecontrol_end( ),公式如下
rate_factor=rcc->wanted_bits_window / rcc->cplxr_sum;
rc->cplxr_sum+= bits * qp2qscale( rc->qpa_rc ) / rc->last_rceq;
rc->wanted_bits_window+= h->fenc->f_duration * rc->bitrate;
bits是每一帧的实际比特数,rc->qpa_rc是最后帧级和行级调整完后的qp, rc->last_rceq上面求出的qscale初值。rc->wanted_bits_window是当前目标比特数。
由以上公式可以看到,rate_factor由两个比值决定:
目标比特数/实际比特数,比值越大→rate_factor越大→qscale和QP越小。
上一帧调整前qscale/上一帧调整后qscale,这个比值一般处于(0,1),比值越小说明上一帧调整幅度越大→rate_factor越小→qscale和QP越大。
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 ) //在新版本x264中mb-tree默认开启,所以不使用传统的复杂度公式来计算qscale,而是通过fps计算出一个固定值 { 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 ); //fps越大 底数越大 //BASE_FRAME_DURATION=0.04 即fps=25,rce->i_duration * timescale编码所用的1/fps } 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; //根据rate_factor调整qp初值 rcc->last_qscale = q; } if( zone ) { if( zone->b_force_qp ) q = qp2qscale( zone->i_qp ); else q /= zone->f_bitrate_factor; } return q; }
clip_qscale( )
clip_qscale( )通过预测当前qscale下未来n帧的大小来估计vbv的状态,如果vbv buffer将overflow,则增大qscale;如果buffer将会underflow,则减小qscale。
static double clip_qscale( x264_t *h, int pict_type, double q ) { x264_ratecontrol_t *rcc = h->rc; double lmin = rcc->lmin[pict_type]; double lmax = rcc->lmax[pict_type]; if( rcc->rate_factor_max_increment ) lmax = X264_MIN( lmax, qp2qscale( rcc->qp_novbv + rcc->rate_factor_max_increment ) ); double q0 = q; /* B-frames are not directly subject to VBV, * since they are controlled by the P-frames' QPs. */ if( rcc->b_vbv && rcc->last_satd > 0 ) { double fenc_cpb_duration = (double)h->fenc->i_cpb_duration * h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale; /* Lookahead VBV: raise the quantizer as necessary such that no frames in * the lookahead overflow and suc ca72 h that the buffer is in a reasonable state * by the end of the lookahead. */ if( h->param.rc.i_lookahead ) { int terminate = 0; /* Avoid an infinite loop. */ for( int iterations = 0; iterations < 1000 && terminate != 3; iterations++ ) { double frame_q[3]; double cur_bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); double buffer_fill_cur = rcc->buffer_fill - cur_bits; double target_fill; double total_duration = 0; double last_duration = fenc_cpb_duration; frame_q[0] = h->sh.i_type == SLICE_TYPE_I ? q * h->param.rc.f_ip_factor : q; frame_q[1] = frame_q[0] * h->param.rc.f_pb_factor; frame_q[2] = frame_q[0] / h->param.rc.f_ip_factor; /* Loop over the planned future frames. */ for( int j = 0; buffer_fill_cur >= 0 && buffer_fill_cur <= rcc->buffer_size; j++ ) //向前预测n帧大小,一般情况下等于lookahead的数量 { total_duration += last_duration; buffer_fill_cur += rcc->vbv_max_rate * last_duration; int i_type = h->fenc->i_planned_type[j]; int i_satd = h->fenc->i_planned_satd[j]; if( i_type == X264_TYPE_AUTO ) //一直预测到类型为AUTO的帧 break; i_type = IS_X264_TYPE_I( i_type ) ? SLICE_TYPE_I : IS_X264_TYPE_B( i_type ) ? SLICE_TYPE_B : SLICE_TYPE_P; cur_bits = predict_size( &rcc->pred[i_type], frame_q[i_type], i_satd ); //使用线性模型预测未来帧大小 buffer_fill_cur -= cur_bits; last_duration = h->fenc->f_planned_cpb_duration[j]; } /* Try to get to get the buffer at least 50% filled, but don't set an impossible goal. */ 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 ) //buffer_fill_cur是buffer剩余空间,如果剩余空间过小,增大qscale { 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 ) //如果剩余空间过大,减小qscale { q /= 1.01; terminate |= 2; continue; } break; } } /* Fallback to old purely-reactive algorithm: no lookahead. */ else { if( ( pict_type == SLICE_TYPE_P || ( pict_type == SLICE_TYPE_I && rcc->last_non_b_pict_type == SLICE_TYPE_I ) ) && rcc->buffer_fill/rcc->buffer_size < 0.5 ) { q /= x264_clip3f( 2.0*rcc->buffer_fill/rcc->buffer_size, 0.5, 1.0 ); } /* Now a hard threshold to make sure the frame fits in VBV. * This one is mostly for I-frames. */ double bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); /* For small VBVs, allow the frame to use up the entire VBV. */ double max_fill_factor = h->param.rc.i_vbv_buffer_size >= 5*h->param.rc.i_vbv_max_bitrate / rcc->fps ? 2 : 1; /* For single-frame VBVs, request that the frame use up the entire VBV. */ double min_fill_factor = rcc->single_frame_vbv ? 1 : 2; if( bits > rcc->buffer_fill/max_fill_factor ) { double qf = x264_clip3f( rcc->buffer_fill/(max_fill_factor*bits), 0.2, 1.0 ); q /= qf; bits *= qf; } if( bits < rcc->buffer_rate/min_fill_factor ) { double qf = x264_clip3f( bits*min_fill_factor/rcc->buffer_rate, 0.001, 1.0 ); q *= qf; } q = X264_MAX( q0, q ); } /* Check B-frame complexity, and use up any bits that would * overflow before the next P-frame. */ if( h->sh.i_type == SLICE_TYPE_P && !rcc->single_frame_vbv ) { int nb = rcc->bframes; double bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); double pbbits = bits; double bbits = predict_size( rcc->pred_b_from_p, q * h->param.rc.f_pb_factor, rcc->last_satd ); double space; double bframe_cpb_duration = 0; double minigop_cpb_duration; for( int i = 0; i < nb; i++ ) bframe_cpb_duration += h->fenc->f_planned_cpb_duration[i]; if( bbits * nb > bframe_cpb_duration * rcc->vbv_max_rate ) nb = 0; pbbits += nb * bbits; minigop_cpb_duration = bframe_cpb_duration + fenc_cpb_duration; space = rcc->buffer_fill + minigop_cpb_duration*rcc->vbv_max_rate - rcc->buffer_size; if( pbbits < space ) { q *= X264_MAX( pbbits / space, bits / (0.5 * rcc->buffer_size) ); } q = X264_MAX( q0/2, q ); } /* Apply MinCR and buffer fill restrictions */ double bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd ); double frame_size_maximum = X264_MIN( rcc->frame_size_maximum, X264_MAX( rcc->buffer_fill, 0.001 ) ); if( bits > frame_size_maximum ) q *= bits / frame_size_maximum; if( !rcc->b_vbv_min_rate ) q = X264_MAX( q0, q ); } if( lmin==lmax ) return lmin; else if( rcc->b_2pass ) { double min2 = log( lmin ); double max2 = log( lmax ); q = (log(q) - min2)/(max2-min2) - 0.5; q = 1.0/(1.0 + exp( -4*q )); q = q*(max2-min2) + min2; return exp( q ); } else return x264_clip3f( q, lmin, lmax ); }
在帧级调整完QP后,编码每个MB时,Adaptive Quantization和MB-tree会使用qp_offset对QP进行调整,这一步由函数x264_ratecontrol_mb_qp()实现。
AQ产生的qp_offset在函数x264_adaptive_quant_frame( )中,根据宏块的AC系数来调整qp_offset,相比于DC系数是图像的低频成分,反映了像素值的平均大小,AC系数是图像的高频成分,反映了图像的复杂程度。如果AC系数越低,则认为该宏块越平滑,其QP越小,如果AC系数越大,该宏块越复杂,则增大其QP。
MB-tree产生的offset在x264_macroblock_tree_finish( )中,如果一个宏块被后面的帧参考越多,则认为其重要性越高,则减小该宏块的QP,给该宏块分配更多码率,反之增大QP,MB-tree相关算法具体参见http://blog.csdn.net/zhoudegui88/article/details/73017216
每编码完一行后,会利用预测模型对当前帧大小进行预测,然后根据VBV buffer fill 对QP进行微调。这一步是在x264_ratecontrol_mb()中进行。
x264_ratecontrol_mb( )
int x264_ratecontrol_mb( x264_t *h, int bits ) { x264_ratecontrol_t *rc = h->rc; const int y = h->mb.i_mb_y; //行数 h->fdec->i_row_bits[y] += bits; rc->qpa_aq += h->mb.i_qp; //qpa_ap 自适应量化后的qp均值,即加上qpoffset后的qp值 if( h->mb.i_mb_x != h->mb.i_mb_width - 1 ) //没到行尾,返回 return 0; x264_emms(); rc->qpa_rc += rc->qpm * h->mb.i_mb_width; //qpm estimal_qsale的结果 自适应量化前的qp均值 if( !rc->b_vbv ) return 0; float qscale = qp2qscale( rc->qpm ); h->fdec->f_row_qp[y] = rc->qpm; h->fdec->f_row_qscale[y] = qscale; update_predictor( &rc->row_pred[0], qscale, h->fdec->i_row_satd[y], h->fdec->i_row_bits[y] ); //模型系数的更新 if( h->sh.i_type != SLICE_TYPE_I && rc->qpm < h->fref[0][0]->f_row_qp[y] ) update_predictor( &rc->row_pred[1], qscale, h->fdec->i_row_satds[0][0][y], h->fdec->i_row_bits[y] ); /* update ratecontrol per-mbpair in MBAFF */ if( SLICE_MBAFF && !(y&1) ) return 0; /* FIXME: We don't currently support the case where there's a slice * boundary in between. */ int can_reencode_row = h->sh.i_first_mb <= ((h->mb.i_mb_y - SLICE_MBAFF) * h->mb.i_mb_stride); /* tweak quality based on difference from predicted size */ float prev_row_qp = h->fdec->f_row_qp[y]; float qp_absolute_max = h->param.rc.i_qp_max; if( rc->rate_factor_max_increment ) qp_absolute_max = X264_MIN( qp_absolute_max, rc->qp_novbv + rc->rate_factor_max_increment ); float qp_max = X264_MIN( prev_row_qp + h->param.rc.i_qp_step, qp_absolute_max ); float qp_min = X264_MAX( prev_row_qp - h->param.rc.i_qp_step, h->param.rc.i_qp_min ); float step_size = 0.5f; float slice_size_planned = h->param.b_sliced_threads ? rc->slice_size_planned : rc->frame_size_planned; float bits_so_far = row_bits_so_far( h, y ); float max_frame_error = x264_clip3f( 1.0 / h->mb.i_mb_height, 0.05, 0.25 ); float max_frame_size = rc->frame_size_maximum - rc->frame_size_maximum * max_frame_error; max_frame_size = X264_MIN( max_frame_size, rc->buffer_fill - rc->buffer_rate * max_frame_error ); float size_of_other_slices = 0; if( h->param.b_sliced_threads ) { float size_of_other_slices_planned = 0; for( int i = 0; i < h->param.i_threads; i++ ) if( h != h->thread[i] ) { size_of_other_slices += h->thread[i]->rc->frame_size_estimated; size_of_other_slices_planned += h->thread[i]->rc->slice_size_planned; } float weight = rc->slice_size_planned / rc->frame_size_planned; size_of_other_slices = (size_of_other_slices - size_of_other_slices_planned) * weight + size_of_other_slices_planned; } if( y < h->i_threadslice_end-1 ) //如果不是当前帧的最后一行 { /* B-frames shouldn't use lower QP than their reference frames. */ if( h->sh.i_type == SLICE_TYPE_B ) { qp_min = X264_MAX( qp_min, X264_MAX( h->fref[0][0]->f_row_qp[y+1], h->fref[1][0]->f_row_qp[y+1] ) ); rc->qpm = X264_MAX( rc->qpm, qp_min ); } float buffer_left_planned = rc->buffer_fill - rc->frame_size_planned; buffer_left_planned = X264_MAX( buffer_left_planned, 0.f ); /* More threads means we have to be more cautious in letting ratecontrol use up extra bits. */ float rc_tol = buffer_left_planned / h->param.i_threads * rc->rate_tolerance; float b1 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices; float trust_coeff = x264_clip3f( bits_so_far / slice_size_planned, 0.0, 1.0 ); /* Don't increase the row QPs until a sufficent amount of the bits of the frame have been processed, in case a flat */ /* area at the top of the frame was measured inaccurately. */ if( trust_coeff < 0.05f ) qp_max = qp_absolute_max = prev_row_qp; if( h->sh.i_type != SLICE_TYPE_I ) rc_tol *= 0.5f; if( !rc->b_vbv_min_rate ) qp_min = X264_MAX( qp_min, rc->qp_novbv ); while( rc->qpm < qp_max //根据与预测值的差距还有VBV buffer的状态调整qpm && ((b1 > rc->frame_size_planned + rc_tol) || (b1 > rc->frame_size_planned && rc->qpm < rc->qp_novbv) || (b1 > rc->buffer_fill - buffer_left_planned * 0.5f)) ) //预测大小超出 增大qpm { rc->qpm += step_size; b1 = bits_so_far + predict_row_size_to_end( h, y, rc->qpm ) + size_of_other_slices; } float b_max = b1 + ((rc->buffer_fill - rc->buffer_size + rc7->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)) ) { 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; } h->rc->frame_size_estimated = b1 - size_of_other_slices; // /* If the current row was large enough to cause a large QP jump, try re-encoding it. */ if( rc->qpm > qp_max && prev_row_qp < qp_max && can_reencode_row ) //如果调整后QP超出范围,重编当前行 { /* Bump QP to halfway in between... close enough. */ rc->qpm = x264_clip3f( (prev_row_qp + rc->qpm)*0.5f, prev_row_qp + 1.0f, qp_max ); rc->qpa_rc = rc->qpa_rc_prev; rc->qpa_aq = rc->qpa_aq_prev; h->fdec->i_row_bits[y] = 0; h->fdec->i_row_bits[y-SLICE_MBAFF] = 0; return -1; } } else { h->rc->frame_size_estimated = bits_so_far; //用来参与更新下一帧的vbv plan /* Last-ditch attempt: if the last row of the frame underflowed the VBV, * try again. */ if( rc->qpm < qp_max && can_reencode_row //如果overflow,重编最后一行 && (h->rc->frame_size_estimated + size_of_other_slices > X264_MIN( rc->frame_size_maximum, rc->buffer_fill )) ) { rc->qpm = qp_max; rc->qpa_rc = rc->qpa_rc_prev; rc->qpa_aq = rc->qpa_aq_prev; h->fdec->i_row_bits[y] = 0; h->fdec->i_row_bits[y-SLICE_MBAFF] = 0; return -1; } } rc->qpa_rc_prev = rc->qpa_rc; rc->qpa_aq_prev = rc->qpa_aq; return 0; }
编完一帧后,会在x264_ratecontrol_end()计算该帧的一些数据 如各种宏块类型的数量、平均QP、写入stat file(2 pass),更新VBV buffer状态和上面提到的rate factor。
参考内容:
UnderstandingRate Control Modes (x264, x265)
http://slhck.info/video/2017/03/01/rate-control.html
x264源码分析与应用示例(二)——码率控制
http://blog.csdn.net/nonmarking/article/details/50737198
x264 自适应量化模式 (AQ Adaptive Quantization) 初探
http://blog.csdn.net/ljb_wh/article/details/15815063
X264码率控制总结2——x264码率控制方法概述
http://blog.csdn.net/chenchong_219/article/details/43941641
相关文章推荐
- X264码率控制总结1——ABR,CQP,CRF
- X264码率控制总结1——ABR,CQP,CRF
- X264码率控制总结1——ABR,CQP,CRF
- X264码率控制总结1——ABR,CQP,CRF
- X264码率控制总结1——ABR,CQP,CRF
- X264码率控制总结1——ABR,CQP,CRF
- X264码率控制总结1——ABR,CQP,CRF
- X264码率控制总结1——ABR,CQP,CRF
- 理解X264的码率控制模式
- x264的五种码率控制及其命令
- X264码率控制流程分析
- x264源码分析与应用示例(二)——码率控制
- x264基于经验和感觉的码率控制策略
- x264基于经验和感觉的码率控制策略
- x264编码指南——码率控制
- X264码率控制流程分析 (转)
- x264码率控制方法介绍
- X264码率控制总结
- x264码率控制参数详解
- X264码率控制流程分析