一 作用
x264种的mbtree是为了通过参考关系,来调整lookahead中帧级别的cost,然后根据intra和inter cost换算出来新的qp_adj。得到qp_adj之后,就需要重新计算cost,调用的recaculateCost函数。
二 代码分析
传递残差计算
static void macroblock_tree( x264_t *h, x264_mb_analysis_t *a, x264_frame_t **frames, int num_frames, int b_intra )
{
int idx = !b_intra; //如果这是IDR帧,则会传递到IDR这里,如果是P,则不会传递给P帧。不跨minigop 传递
int last_nonb, cur_nonb = 1;
int bframes = 0;
x264_emms();
float total_duration = 0.0;
for( int j = 0; j <= num_frames; j++ )
total_duration += frames[j]->f_duration;
float average_duration = total_duration / (num_frames + 1);
int i = num_frames;
if( b_intra )
slicetype_frame_cost( h, a, frames, 0, 0, 0 );
while( i > 0 && IS_X264_TYPE_B( frames[i]->i_type ) )
i--;
last_nonb = i;
/* Lookaheadless MB-tree is not a theoretically distinct case; the same extrapolation could
* be applied to the end of a lookahead buffer of any size. However, it's most needed when
* lookahead=0, so that's what's currently implemented. */
if( !h->param.rc.i_lookahead )
{
if( b_intra )
{
memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
memcpy( frames[0]->f_qp_offset, frames[0]->f_qp_offset_aq, h->mb.i_mb_count * sizeof(float) );
return;
}
XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost );
memset( frames[0]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
}
else
{
if( last_nonb < idx )
return;
memset( frames[last_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
}
while( i-- > idx )
{
fprintf(stderr, "idx # %d i %d type %d\n", idx, i, frames[i]->i_type);
cur_nonb = i;
while( IS_X264_TYPE_B( frames[cur_nonb]->i_type ) && cur_nonb > 0 ) //倒推一个minigop
cur_nonb--;
if( cur_nonb < idx ) //到头了就结束
break;
slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, last_nonb );
memset( frames[cur_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
bframes = last_nonb - cur_nonb - 1;
if( h->param.i_bframe_pyramid && bframes > 1 ) //2层的B帧
{
int middle = (bframes + 1)/2 + cur_nonb;
slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, middle );
memset( frames[middle]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
while( i > cur_nonb ) // i比cur nonb大,还没有倒推到P帧,
{
int p0 = i > middle ? middle : cur_nonb; //x264编码出来的B帧结构 PbbbbBbbbbP cur_nonb是当前minigop最后一个P
int p1 = i < middle ? middle : last_nonb; //last_nonb 是最前面的P,
if( i != middle )
{
slicetype_frame_cost( h, a, frames, p0, p1, i ); //以帧为单位计算cost
macroblock_tree_propagate( h, frames, average_duration, p0, p1, i, 0 );
}
i--;
}//被参考的P帧,传递残差要进行下去。
macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, middle, 1 ); //中间的B帧参考的前后两个P帧
}
else
{
while( i > cur_nonb ) // 非参考B帧,清理帧本身的传递残差
{ //i是当前帧
slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, i );
macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, i, 0 );//这整个minigop 内的B帧,都是参考,最前面和最后的P帧
i--;
}
}
//普通的P帧传递残差传播, last_nonb 倒数第一个P帧, cur_nonb ,往前推进的P帧
macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, last_nonb, 1 ); //最后这个P帧,还要参考,前面的P帧
last_nonb = cur_nonb;
}
if( !h->param.rc.i_lookahead )
{
slicetype_frame_cost( h, a, frames, 0, last_nonb, last_nonb );
macroblock_tree_propagate( h, frames, average_duration, 0, last_nonb, last_nonb, 1 );
XCHG( uint16_t*, frames[last_nonb]->i_propagate_cost, frames[0]->i_propagate_cost );
}
macroblock_tree_finish( h, frames[last_nonb], average_duration, last_nonb );
if( h->param.i_bframe_pyramid && bframes > 1 && !h->param.rc.i_vbv_buffer_size )
macroblock_tree_finish( h, frames[last_nonb+(bframes+1)/2], average_duration, 0 );
}
重新调整cost
/* If MB-tree changes the quantizers, we need to recalculate the frame cost without
* re-running lookahead. */
static int slicetype_frame_cost_recalculate( x264_t *h, x264_frame_t **frames, int p0, int p1, int b )
{
int i_score = 0;
int *row_satd = frames[b]->i_row_satds[b-p0][p1-b];
float *qp_offset = IS_X264_TYPE_B(frames[b]->i_type) ? frames[b]->f_qp_offset_aq : frames[b]->f_qp_offset;
x264_emms();
for( h->mb.i_mb_y = h->mb.i_mb_height - 1; h->mb.i_mb_y >= 0; h->mb.i_mb_y-- )
{
row_satd[ h->mb.i_mb_y ] = 0;
for( h->mb.i_mb_x = h->mb.i_mb_width - 1; h->mb.i_mb_x >= 0; h->mb.i_mb_x-- )
{
int i_mb_xy = h->mb.i_mb_x + h->mb.i_mb_y*h->mb.i_mb_stride;
int i_mb_cost = frames[b]->lowres_costs[b-p0][p1-b][i_mb_xy] & LOWRES_COST_MASK;
float qp_adj = qp_offset[i_mb_xy];
i_mb_cost = (i_mb_cost * x264_exp2fix8(qp_adj) + 128) >> 8; //根据qp_adj和之前的到的cosT, 计算得到新的cost
row_satd[ h->mb.i_mb_y ] += i_mb_cost;
if( (h->mb.i_mb_y > 0 && h->mb.i_mb_y < h->mb.i_mb_height - 1 &&
h->mb.i_mb_x > 0 && h->mb.i_mb_x < h->mb.i_mb_width - 1) ||
h->mb.i_mb_width <= 2 || h->mb.i_mb_height <= 2 )
{
i_score += i_mb_cost;
}
}
}
return i_score;
}