先直接从更新参考帧的位置看起,这里的操作是最为复杂的地方
static inline int reference_update( x264_t *h )
{
if( !h->fdec->b_kept_as_ref )//如果B帧不被当做参考帧
{
if( h->i_thread_frames > 1 )
{
x264_frame_push_unused( h, h->fdec );
h->fdec = x264_frame_pop_unused( h, 1 );
if( !h->fdec )
return -1;
}
return 0;
}
/* apply mmco from previous frame. 将参考帧poc映射,后续再细琢磨*/
for( int i = 0; i < h->sh.i_mmco_command_count; i++ )
for( int j = 0; h->frames.reference[j]; j++ )
{
if( h->frames.reference[j]->i_poc == h->sh.mmco[i].i_poc )
{
x264_frame_push_unused( h, x264_frame_shift( &h->frames.reference[j] ) );//
}
}
/* move frame in the buffer */
x264_frame_push( h->frames.reference, h->fdec );//插入重建帧,当成参考帧
if( h->frames.reference[h->sps->i_num_ref_frames] )//如果参考序列满了,则要删掉最前的那个参考帧,然后把参考帧序列挪动一下位置
{
x264_frame_push_unused( h, x264_frame_shift( h->frames.reference ) );//把新的帧查到最前面
}
h->fdec = x264_frame_pop_unused( h, 1 );//取出一个空余的帧节点,下一次重建帧使用这个存储数据
if( !h->fdec )
return -1;
return 0;
}
void x264_frame_push( x264_frame_t **list, x264_frame_t *frame )//上面调用这个函数向参考帧中插入一个frame,
{
int i = 0;
while( list[i] ) i++;//找到一个空闲的frame
list[i] = frame;//把要插入的frame地址赋值过去
}
//如何理解这句话
x264_frame_push_unused( h, x264_frame_shift( h->frames.reference ) );//把新的帧查到最前面
先看x264_frame_shift
x264_frame_t *x264_frame_shift( x264_frame_t **list )
{
x264_frame_t *frame = list[0];
int i;
for( i = 0; list[i]; i++ )
list[i] = list[i+1];
assert(frame);
return frame;//顺序性的取帧,一个线程取一个
}
把位置0的frame取出来,后面的依次向前挪动一个位置。因为reference[0]是最老的一个参考帧,这里存满了,要删掉一个最老的
//如何删掉这个最老的参考帧,i_reference_count 被参考的次数
void x264_frame_push_unused( x264_t *h, x264_frame_t *frame )
{
assert( frame->i_reference_count > 0 );
frame->i_reference_count--;//有多少个线程把这个帧当成参考帧,清空一个,这个帧的i_reference_count 就 --
if( frame->i_reference_count == 0 )//已经没有线程引用这个帧当做参考帧了
x264_frame_push( h->frames.unused[frame->b_fdec], frame );//把空闲的frame 回收
}
//每个线程都有自己的x264_t 上下文,每调用依次这个函数,frame被引用的次数减1,直到为0,这个时候frame就可以被释放了,释放不是释放内存,而是吧frame重新回收到上下文的unused队列,供下次使用。
因此调用x264_frame_push(unused,frame);
void x264_frame_push( x264_frame_t **list, x264_frame_t *frame )//在unused数组中找到一个空闲的frame位置,把要释放的frame填进去就好。
{
int i = 0;
while( list[i] ) i++;
list[i] = frame;
}
那么这里释放了,后面如何使用的呢?
x264_frame_t *x264_frame_pop( x264_frame_t **list )//弹出最近的一个参考帧
{
x264_frame_t *frame;
int i = 0;
assert( list[0] );
while( list[i+1] ) i++;
frame = list[i];
list[i] = NULL;
return frame;
}
x264_frame_t *x264_frame_pop_unused( x264_t *h, int b_fdec )
{
x264_frame_t *frame;
if( h->frames.unused[b_fdec][0] )
frame = x264_frame_pop( h->frames.unused[b_fdec] );//从unused中pop一个地址不为空的frame出来。前面释放的时候,frame地址呗这里回收了,现在pop再次利用
else
frame = frame_new( h, b_fdec );
if( !frame )
return NULL;
frame->b_last_minigop_bframe = 0;
frame->i_reference_count = 1;
frame->b_intra_calculated = 0;
frame->b_scenecut = 1;
frame->b_keyframe = 0;
frame->b_corrupt = 0;
frame->i_slice_count = h->param.b_sliced_threads ? h->param.i_threads : 1;
memset( frame->weight, 0, sizeof(frame->weight) );
memset( frame->f_weighted_cost_delta, 0, sizeof(frame->f_weighted_cost_delta) );
return frame;
}