qcomp参数对h264编码的码率控制主要有两方面,1 帧qscale计算 2 宏块qp调整
1 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 )
{
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 );
}
} //目前我们都是开了宏块树码率控制的,宏块树记录了宏块间的参考关系,1 被参考多的宏块qp减小,反之增大。
这里q = pow( BASE_FRAME_DURATION / CLIP_DURATION(rce->i_duration * timescale), 1 - h->param.rc.f_qcompress ); 显然这个是个固定值,即qcomp一定的情况下,qscale固定了。
else条件中,q = pow( rce->blurred_complexity, 1 - rcc->qcompress ); blurred 是本帧所有的宏块satd带权和。
这里仅仅是初始的帧的qscale值。
后面还会通过clip_qscale,调整帧的qscale值,这个函数尝试左右浮动qscale求得最合适的值。
2 宏块级的影响
static void macroblock_tree_finish( x264_t *h, x264_frame_t *frame, float average_duration, int ref0_distance )
{
int fps_factor = round( CLIP_DURATION(average_duration) / CLIP_DURATION(frame->f_duration) * 256 / MBTREE_PRECISION );
float weightdelta = 0.0;
if( ref0_distance && frame->f_weighted_cost_delta[ref0_distance-1] > 0 )
weightdelta = (1.0 - frame->f_weighted_cost_delta[ref0_distance-1]);
/* Allow the strength to be adjusted via qcompress, since the two
* concepts are very similar. */
float strength = 5.0f * (1.0f - h->param.rc.f_qcompress); //宏块码率控制中,宏块树的强度和qcomp成相反的关系,qcomp大,宏块树作用小。
for( int mb_index = 0; mb_index < h->mb.i_mb_count; mb_index++ )
{
int intra_cost = (frame->i_intra_cost[mb_index] * frame->i_inv_qscale_factor[mb_index] + 128) >> 8;
if( intra_cost )
{
int propagate_cost = (frame->i_propagate_cost[mb_index] * fps_factor + 128) >> 8;
float log2_ratio = x264_log2(intra_cost + propagate_cost) - x264_log2(intra_cost) + weightdelta;
frame->f_qp_offset[mb_index] = frame->f_qp_offset_aq[mb_index] - strength * log2_ratio;
}
}
// 宏块树作用小,qp_offset调整幅度越大。
}从这个函数可有看出来,strength决定了宏块的cost对最终的qp_offset的影响,如果strength越大,则影响越大。这里qcomp和strength是反的关系,所以qcomp越小,宏块cost对最终的影响越大,qp_offset值越小。
int x264_ratecontrol_mb_qp( x264_t *h )
{
x264_emms();
float qp = h->rc->qpm;
if( h->param.rc.i_aq_mode )
{
/* MB-tree currently doesn't adjust quantizers in unreferenced frames. */
float qp_offset = h->fdec->b_kept_as_ref ? h->fenc->f_qp_offset[h->mb.i_mb_xy] : h->fenc->f_qp_offset_aq[h->mb.i_mb_xy];
/* Scale AQ's effect towards zero in emergency mode. */
if( qp > QP_MAX_SPEC )
qp_offset *= (QP_MAX - qp) / (QP_MAX - QP_MAX_SPEC);
qp += qp_offset;
}
return x264_clip3( qp + 0.5f, h->param.rc.i_qp_min, h->param.rc.i_qp_max );
}
在宏块qp调整中,qp_offset 直接对应的qcomp调节的值。
然后通过一定比例计算出调整的delta_qp值,得到最终的qp值。这里说明,qcomp越小,qp_offset 作为负值也越小,即绝对值越大。和当前qp相加后的结果越小,也就是说qcomp越小,qp会伴随cost大小变化幅度越大。失真就越小。
总的来说,就是qcomp会强调cost大的宏块。