/*
进行宏块树计算
宏块树针对帧内不同宏块被后续帧参考的不同程度而相应自适应的设置qp
所以只针对参考帧来设置,即IDR/I/P/Bref,不针对B
b_intra 表示是否是一个关键帧起始的lookahead队列
num_frames 表示lookahead队列里有多少帧
过程:
1.计算mb_tree帧组的平均帧率时间average_duration
2.将lookahead队列中的所有帧,一段一段向前迭代进行计算,即每cur_nonb B ... B ... B last_nonb为一段
1.得到last_nonb以cur_nonb为前向参考的satd
2.计算剩余的B帧
·若使用Bref
1.取最中间帧作为Bref,计算其以cur_nonb前向参考,last_nonb后向参考的satd
2.计算Bref B ... B last_nonb之间的B帧,以Bref前向参考,last_nonb后向参考的satd
计算他们的propagate_cost,并将其瓜分到参考帧Bref和last_nonb的propagate_cost中
3.计算cur_nonb B ... B Bref之间的B帧,以cur_nonb前向参考,Bref后向参考的satd
计算他们的propagate_cost,并将其瓜分到参考帧cur_nonb和Bref的propagate_cost中
4.计算Bref的propagate_cost,并将其瓜分到参考帧cur_nonb和last_nonb的propagate_cost中,同时变现Bref的propagate_cost为qp_offset
·若不使用Bref
1.计算cur_nonb B ... B last_nonb之间的B帧,以cur_nonb前向参考,last_nonb后向参考的satd
计算他们的propagate_cost,并将其瓜分到参考帧cur_nonb和last_nonb的propagate_cost中
3.计算last_nonb的propagate_cost,并将其瓜分到参考帧cur_nonb的propagate_cost中,同时变现last_nonb的propagate_cost为qp_offset
3.将循环体内还未变现的第一个nonb的propagate_cost变现为qp_offset
*/
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;
int last_nonb, cur_nonb = 1;
int bframes = 0;
x264_emms();
//计算该mb_tree帧组的average_duration
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;
//若lookahead队列是以关键帧起始,则计算第0帧的satd
if( b_intra )
slicetype_frame_cost( h, a, frames, 0, 0, 0 );
//一直向前寻找第一个非B帧
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) );
}
/*
对lookahead队列一组一组进行mb_tree分析,计算他们的propagate_cost
并将他们的propagate_cost变现为qp_offset
每一组 nonb B B ... B nonb => cur_nonb B B ... B nonb
lookahead队列:
nonb ...... nonb ... nonb ... nonb ...
round1: cur_nonb last_nonb
round2: cur_nonb last_nonb
...
roundn: cur_nonb last_nonb
*/
while( i-- > idx )
{
//寻找非B帧,即 cur_nonb B B ... B B last_nonb
cur_nonb = i;
while( IS_X264_TYPE_B( frames[cur_nonb]->i_type ) && cur_nonb > 0 )
cur_nonb--;
if( cur_nonb < idx )
break;
//得到last_nonb以当cur_nonb为前向参考时的所有satd,并记录下来
slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, last_nonb );
//初始化cur_nonb的i_propagate_cost
memset( frames[cur_nonb]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
//计算cur_nonb与last_nonb之间的B帧数量
bframes = last_nonb - cur_nonb - 1;
if( h->param.i_bframe_pyramid && bframes > 1 ) //若允许B帧作为参考帧,且连续B帧个数>1
{
//求最中间帧middle
int middle = (bframes + 1)/2 + cur_nonb;
//得到middle以当前帧为前向参考,上一个非B帧为后向参考 时的所有satd
slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, middle );
//初始化middle的i_propagate_cost为0
memset( frames[middle]->i_propagate_cost, 0, h->mb.i_mb_count * sizeof(uint16_t) );
while( i > cur_nonb ) //遍历所有cur_nonb和last_nonb之间的B帧
{
/*得到前向参考和后向参考帧,即
cur_nonb ... midle ... last_nonb */
int p0 = i > middle ? middle : cur_nonb;
int p1 = i < middle ? middle : last_nonb;
if( i != middle )
{ //计算当前B帧以p0为前向参考,p1为后向参考的satd
slicetype_frame_cost( h, a, frames, p0, p1, i );
//计算当前B帧的propagate_cost,并将其瓜分到参考帧p0和p1的propagate_cost中
macroblock_tree_propagate( h, frames, average_duration, p0, p1, i, 0 );
}
i--;
}
/*计算middle帧的propagate_cost,将其瓜分到参考帧cur_nonb和last_nonb中
并将其propagate_cost变现成qp_offset */
macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, middle, 1 );
}
else
{
while( i > cur_nonb ) //遍历cur_nonb和last_nonb之间的所有B帧
{
//计算当前B帧以cur_nonb前向参考,last_nonb后向参考的satd
slicetype_frame_cost( h, a, frames, cur_nonb, last_nonb, i );
//计算当前B帧的propagate_cost,并将其瓜分到参考帧cur_nonb和last_nonb中
macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, i, 0 );
i--;
}
}
/* 计算last_nonb的propagate_cost,将其瓜分到参考帧cur_nonb中
并将其propagate_cost变现成qp_offset */
macroblock_tree_propagate( h, frames, average_duration, cur_nonb, last_nonb, last_nonb, 1 );
//迭代last_nonb和cur_nonb
last_nonb = cur_nonb;
} //end of while
//若不使用码控lookahead,不懂为什么要这样做
if( !h->param.rc.i_lookahead )
{
//计算last_nonb做为P帧,以frame[0]为前向参考的satd
slicetype_frame_cost( h, a, frames, 0, last_nonb, last_nonb );
//将last_nonb的propagate_cost瓜分到frame[0]中
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 );
}
/* 将队列中第一个nonb的propagate_cost变现成qp_offset
因为前面的循环未能变现第一个nonb帧 */
macroblock_tree_finish( h, frames[last_nonb], average_duration, last_nonb );
//变现last_nonb+(bframes+1)/2??不懂,之前在循环体内不是已经变现了么?
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 );
}
码控-macroblock_tree()
最新推荐文章于 2023-01-18 09:35:07 发布