x264中的空闲帧,参考帧队列管理

先直接从更新参考帧的位置看起,这里的操作是最为复杂的地方

static inline int reference_update( x264_t *h )
{
    if( !h->fdec->b_kept_as_ref )//如果帧不被当做参考帧
    {
        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;
}

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值