码控-macroblock_tree()

/*
	进行宏块树计算
	宏块树针对帧内不同宏块被后续帧参考的不同程度而相应自适应的设置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 );
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值