编码帧的输入顺序是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:暂时理解这么多。