x264中关于编码帧存取lookahead的操作

编码帧的输入顺序是I B B B B P,设置4个B帧。
这里假设每次最多能缓存5帧图像,即lookahead的列表中能存5帧图像。编码的第一帧图像是I帧或者IDR帧,首先将第一帧图像存入h->lookahead->next->list中,它的size加1,接着依次存入四帧图像,它的size为5,此时h->lookahead->next->list中的图像是:

在这里插入图片描述
接着对列表中的图像进行依次编码,首先取索引为0的帧,确定帧类型为IDR帧,然后将此帧赋值给h->lookahead->last_nonb,具体操作如下:

h->lookahead->last_nonb=h->lookahead->next->list[0];

然后确定要移动的帧数shift_frames=1;
然后将这一帧移到另一个列表中,具体操作如下:

h->lookahead->ofbuf->list[0]=h->lookahead->next->list[0];

h->lookahead->ofbuf.size加1,h->lookahead->next.size减1,h->lookahead->next->list中后面的几帧依次向前移,
h->lookahead->next->list[i] = h->lookahead->next->list[i+1]
在这里插入图片描述
h->lookahead->next->list移动之后的情况

在这里插入图片描述
h->lookahead->ofbuf->list添加一帧之后的情况
然后又从h->lookahead->ofbuf->list中将这一帧取出存入到h->frames.current中
在这里插入图片描述
此时,h->frames.current中存入一帧,h->lookahead->ofbuf->list中为空。然后编码的时候从h->frames.current中取索引为0的帧作为当前编码帧。此时只有一帧,,不需要移动其他帧。
这一个IDR帧编码完后,又向h->lookahead->next->list中加入新的一帧,加到列表的最后,此时还是存5帧。
接着编码第二帧,第二帧一般是P帧。取第二帧之前要先确定这些帧的帧类型。
这些帧的类型是:
在这里插入图片描述
然后调整P帧B帧顺序,调整前:
在这里插入图片描述
调整后:
在这里插入图片描述
对其进行重新排序:
在这里插入图片描述
此时h->lookahead->next->list中的顺序就是重新排序后的顺序。
确定要移动的帧数shift_frames=5;
将h->lookahead->next->list中的5帧依次移到h->lookahead->ofbuf->list中,顺序保持不变,移动后h->lookahead->next的size为0,h->lookahead->ofbuf的size为5.
然后再将h->lookahead->ofbuf->list中的5帧依次移到h->frames.current中,顺序保持不变,移动后h->lookahead->ofbuf的size为0.
编码的时候是从h->frames.current中依次取,编完一帧,就将这帧从h->frames.current中移除,根据先入先出原则,所以总是取索引为0的帧。
当这些帧编码完后,又会重新存入5帧到h->lookahead->next->list中。重新执行这些操作。

代码如下:

int     x264_encoder_encode( x264_t *h,
                             x264_nal_t **pp_nal, int *pi_nal,
                             x264_picture_t *pic_in,
                             x264_picture_t *pic_out )
{

	.....
	x264_lookahead_put_frame( h, fenc );//将当前帧加入到lookahead->next->list中
	......
	if( !h->frames.current[0] )
        x264_lookahead_get_frames( h );//实现存入h->frames.current中
    h->fenc = x264_frame_shift( h->frames.current );//实现从h->frames.current中获取要编码的帧
    .....
}
void x264_lookahead_get_frames( x264_t *h )
{
    if( h->param.i_sync_lookahead )
    {   /* We have a lookahead thread, so get frames from there */
        x264_pthread_mutex_lock( &h->lookahead->ofbuf.mutex );
        while( !h->lookahead->ofbuf.i_size && h->lookahead->b_thread_active )
            x264_pthread_cond_wait( &h->lookahead->ofbuf.cv_fill, &h->lookahead->ofbuf.mutex );
        lookahead_encoder_shift( h );
        x264_pthread_mutex_unlock( &h->lookahead->ofbuf.mutex );
    }
    else
    {   /* We are not running a lookahead thread, so perform all the slicetype decide on the fly */

        if( h->frames.current[0] || !h->lookahead->next.i_size )
            return;

        x264_slicetype_decide( h );//确定slice类型
    
        lookahead_update_last_nonb( h, h->lookahead->next.list[0] );
        int shift_frames = h->lookahead->next.list[0]->i_bframes + 1;
        lookahead_shift( &h->lookahead->ofbuf, &h->lookahead->next, shift_frames );//将h->lookahead->next->list中的frame赋值给h->lookahead->ofbuf->list
       
        /* For MB-tree and VBV lookahead, we have to perform propagation analysis on I-frames too. */
        if( h->lookahead->b_analyse_keyframe && IS_X264_TYPE_I( h->lookahead->last_nonb->i_type ) )
            x264_slicetype_analyse( h, shift_frames );

        lookahead_encoder_shift( h );//将h->lookahead->ofbuf->list中的帧移动到h->frames.current中
    }
}

void x264_slicetype_decide( x264_t *h )
{
	......
	if( h->param.rc.b_stat_read )
    {
        /* Use the frame types from the first pass 二路编码之间使用第一次编码的帧类型*/
        for( int i = 0; i < h->lookahead->next.i_size; i++ )
            h->lookahead->next.list[i]->i_type =
                x264_ratecontrol_slice_type( h, h->lookahead->next.list[i]->i_frame );
    }
    else if( (h->param.i_bframe && h->param.i_bframe_adaptive)
             || h->param.i_scenecut_threshold
             || h->param.rc.b_mb_tree
             || (h->param.rc.i_vbv_buffer_size && h->param.rc.i_lookahead) )
        x264_slicetype_analyse( h, 0 );//帧类型分析
    ......
	/* insert a bref into the sequence */
    if( h->param.i_bframe_pyramid && bframes > 1 && !brefs )
    {
        h->lookahead->next.list[(bframes-1)/2]->i_type = X264_TYPE_BREF;//设置一个BREF帧
        brefs++;
    }
    .....
    if( bframes )
    {
        int idx_list[] = { brefs+1, 1 };
        for( int i = 0; i < bframes; i++ )//调整P帧B帧顺序
        {
            int idx = idx_list[h->lookahead->next.list[i]->i_type == X264_TYPE_BREF]++;
            frames[idx] = h->lookahead->next.list[i];
            frames[idx]->i_reordered_pts = h->lookahead->next.list[idx]->i_pts;
        }
        frames[0] = h->lookahead->next.list[bframes];
        frames[0]->i_reordered_pts = h->lookahead->next.list[0]->i_pts;
        memcpy( h->lookahead->next.list, frames, (bframes+1) * sizeof(x264_frame_t*) );//重排序
    }
    ......
}

PS:暂时理解这么多。

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值