x264中關於編碼幀存取lookahead的操作
技術標籤:x264
編碼幀的輸入順序是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幀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:暫時理解這麼多。