x264 - x264_reference_build_list

来源:互联网 发布:mac的输入法快捷键 编辑:程序博客网 时间:2024/06/12 04:53




static inline void x264_reference_build_list( x264_t *h, int i_poc )
{
    int b_ok;

    /* build ref list 0/1 */
    // 初始化 h->i_ref[0], h->i_ref[1]为0
    // h->i_ref[0]为参考帧队列ref[0]的索引
    // h->i_ref[1]为参考帧队列ref[1]的索引
   
    h->mb.pic.i_fref[0] = h->i_ref[0] = 0;
    h->mb.pic.i_fref[1] = h->i_ref[1] = 0;
   
   
    // 如果当前的slice类型为SLICE_TYPE_I, 则返回
    if( h->sh.i_type == SLICE_TYPE_I )
        return;

    for( int i = 0; h->frames.reference[i]; i++ )
    {
        // 如果帧被破坏, 则跳过继续
        if( h->frames.reference[i]->b_corrupt )
            continue;
        // 将参考帧队列中i_poc小于当前i_poc的帧
        // 放入参考帧队列ref[0];
        // 否则放入ref[1]中
        if( h->frames.reference[i]->i_poc < i_poc )
            h->fref[0][h->i_ref[0]++] = h->frames.reference[i];
        else if( h->frames.reference[i]->i_poc > i_poc )
            h->fref[1][h->i_ref[1]++] = h->frames.reference[i];
    }

    // 依据参考帧与当前帧的poc距离来排序参考帧
    // 排序参考帧, 并且获取各自参考帧列表的最近的参考帧
    // 这里先依据POC距离来排序参考帧列表
    // 然后在x264_reference_check_reorder中
    // list0 依据 i_frame_num 来确定是否重序,
    // list1 依然依据 poc 来确定是否重序
    // 在函数x264_reference_check_reorder中,
    // 设置重序标志,在x264_slice_header_init
    // 利用这两个标志来确定将是否需要重序的标志
    // 写进slice_header里,并通过x264_slice_write
    // 写进码流
    /* Order reference lists by distance from the current frame. */
    for( int list = 0; list < 2; list++ )
    {
        h->fref_nearest[list] = h->fref[list][0];
        do
        {
            b_ok = 1;
            for( int i = 0; i < h->i_ref[list] - 1; i++ )
            {
                // 参考帧队列0放的是前向参考帧,而参考帧队列1放的是后向参考帧
                // 前向参考帧列表按降序排列,而后向参考帧列表按升序排列
                if( list ? h->fref[list][i+1]->i_poc < h->fref_nearest[list]->i_poc
                         : h->fref[list][i+1]->i_poc > h->fref_nearest[list]->i_poc )
                    h->fref_nearest[list] = h->fref[list][i+1];
                if( x264_reference_distance( h, h->fref[list][i] ) > x264_reference_distance( h, h->fref[list][i+1] ) )
                {
                    // 如果参考帧i到待编码帧的距离 大于 参考帧i+1到待编码帧的距离
                    // 交换在参考帧列表里的两参考帧
                    XCHG( x264_frame_t*, h->fref[list][i], h->fref[list][i+1] );
                    b_ok = 0;
                    break;
                }
            }
        } while( !b_ok );
    }

    // h->sh.i_mmco_remove_from_end 在 x264_reference_hierarchy_reset
    // 函数中被设置 (h->sh.i_mmco_remove_from_end = X264_MAX( ref + 2 - h->frames.i_max_dpb, 0 );)
    // 标记清除参考帧列表0中的帧,从距离远的帧开始清除
    // 清除h->sh.i_mmco_remove_from_end个参考帧
    if( h->sh.i_mmco_remove_from_end )
        for( int i = h->i_ref[0]-1; i >= h->i_ref[0] - h->sh.i_mmco_remove_from_end; i-- )
        {
            int diff = h->i_frame_num - h->fref[0][i]->i_frame_num;
            h->sh.mmco[h->sh.i_mmco_command_count].i_poc = h->fref[0][i]->i_poc;
            h->sh.mmco[h->sh.i_mmco_command_count++].i_difference_of_pic_nums = diff;
        }

    // 检查参考帧列表是否需要重序
    x264_reference_check_reorder( h );

    // 设定list0, list1参考帧数目
    h->i_ref[1] = X264_MIN( h->i_ref[1], h->frames.i_max_ref1 );
    h->i_ref[0] = X264_MIN( h->i_ref[0], h->frames.i_max_ref0 );
    h->i_ref[0] = X264_MIN( h->i_ref[0], h->param.i_frame_reference ); // if reconfig() has lowered the limit

    /* For Blu-ray compliance, don't reference frames outside of the minigop. */
    if( IS_X264_TYPE_B( h->fenc->i_type ) && h->param.b_bluray_compat )
        h->i_ref[0] = X264_MIN( h->i_ref[0], IS_X264_TYPE_B( h->fref[0][0]->i_type ) + 1 );

    /* add duplicates */
    if( h->fenc->i_type == X264_TYPE_P )
    {
        int idx = -1;
        if( h->param.analyse.i_weighted_pred >= X264_WEIGHTP_SIMPLE )
        {
            x264_weight_t w[3];
            w[1].weightfn = w[2].weightfn = NULL;
            if( h->param.rc.b_stat_read )
                x264_ratecontrol_set_weights( h, h->fenc );

            if( !h->fenc->weight[0][0].weightfn )
            {
                h->fenc->weight[0][0].i_denom = 0;
                SET_WEIGHT( w[0], 1, 1, 0, -1 );
                idx = x264_weighted_reference_duplicate( h, 0, w );
            }
            else
            {
                if( h->fenc->weight[0][0].i_scale == 1<<h->fenc->weight[0][0].i_denom )
                {
                    SET_WEIGHT( h->fenc->weight[0][0], 1, 1, 0, h->fenc->weight[0][0].i_offset );
                }
                x264_weighted_reference_duplicate( h, 0, x264_weight_none );
                if( h->fenc->weight[0][0].i_offset > -128 )
                {
                    w[0] = h->fenc->weight[0][0];
                    w[0].i_offset--;
                    h->mc.weight_cache( h, &w[0] );
                    idx = x264_weighted_reference_duplicate( h, 0, w );
                }
            }
        }
        h->mb.ref_blind_dupe = idx;
    }

    assert( h->i_ref[0] + h->i_ref[1] <= X264_REF_MAX );
    // 将list0, list1参考帧数目保存在h->mb.pic.i_fref[0], [1]
    h->mb.pic.i_fref[0] = h->i_ref[0];
    h->mb.pic.i_fref[1] = h->i_ref[1];
}


static inline int x264_reference_distance( x264_t *h, x264_frame_t *frame )
{
    // 返回待编码帧和参考帧列表里帧的距离
    // 计算方法:待编码帧编码序号 与 参考帧编码序号 之差的绝对值
    if( h->param.i_frame_packing == 5 )
        return abs((h->fenc->i_frame&~1) - (frame->i_frame&~1)) +
                  ((h->fenc->i_frame&1) != (frame->i_frame&1));
    else
        return abs(h->fenc->i_frame - frame->i_frame);
}


0 0