x264源码分析之帧类型选择

x264片类型和帧类型选择代码分析,以IDR P B B P B B P B B P B B P B B I P B B P B B P…。观察发现,I帧前一帧是B,后一帧是P帧,

 /* ------------------- Select slice type and frame --------------------- */
    if( h->i_frame % (h->param.i_iframe * h->param.i_idrframe) == 0 )//此时为IDR帧,i_iframe:I帧之间的帧间隔;i_idrframe:每个几个I帧存在一个IDR帧
    {
        i_nal_type    = NAL_SLICE_IDR;//IDR帧
        i_nal_ref_idc = NAL_PRIORITY_HIGHEST;//,优先级最高位3
        i_slice_type = SLICE_TYPE_I;//片类型为I,一共5种类型,P,B,I,SP,SI

        /* we encode the given frame */
        h->picture    = pic;

        /* null poc */
        h->i_poc       = 0;
        h->fdec->i_poc = 0;

        /* null frame */
        h->i_frame_num = 0;

        /* reset ref pictures */
        x264_reference_reset( h );
    }
    else
    {
        /* TODO detect scene changes and switch to I slice */

        if( h->param.i_bframe > 0 )//如果有B帧,那么会使用到bframe_current,frame_next,frame_unused
        {
            x264_frame_t *frame;

            /* TODO avoid always doing x264_encoder_frame_put_from_picture */
            /* TODO implement adaptive B frame patern (not fixed one)*/

            /* put the current picture in frame_next */
            frame = x264_encoder_frame_put_from_picture( h, h->frame_next, pic );//将新的pic复制到frame,然后将frame放入frame_next队列尾部
            frame->i_poc = h->i_poc;//poc为显示顺序,偶数

            /* get the frame to be encoded */
            if( h->bframe_current[0] )//如果bframe_current有数据,证明需要编码B帧,B帧会放入bframe_current队列,后续的代码会向bframe_current队列放入待编码的B帧
            {
                frame = x264_encoder_frame_get( h->bframe_current );//从bframe_current 队列获取frame进行后续的编码操作
                i_slice_type = SLICE_TYPE_B;
            }
            else if( h->frame_next[h->param.i_bframe] == NULL )//只有开始的前i_bframe帧会跑进去
            {
                /* not enough b-frame yet */
                frame = NULL;
                i_slice_type = -1;
            }
            else
            {
                int i_mod = h->i_frame % h->param.i_iframe;//判断是否为I帧,如果为I帧,下一帧编码帧肯定为P帧

                if( i_mod == 0 )
                {
                    i_slice_type = SLICE_TYPE_I;
                    frame = x264_encoder_frame_get( h->frame_next );
                }
                else //bframe_current中没有帧,证明B帧已经编码完成,完成一个B B P,接下来是新一个B B P循环,先将B B放入bframe_current,然后编码P帧
                {
                    int i;

                    for( i = 0; i < h->param.i_bframe; i++ )
                    {
                        h->bframe_current[i] = x264_encoder_frame_get( h->frame_next );//连续取i_bframe(编码时连续B帧个数)帧放入bframe_current
                    }
                    frame = x264_encoder_frame_get( h->frame_next );//B帧参考与P帧,P帧要比B帧先编码;因此上面先将B帧放入bframe_current队列,编码P帧,然后才能编码B帧

                    i_slice_type = SLICE_TYPE_P;
                }
            }

            if( frame )
            {
                h->picture = &picture_tmp;
                for( i = 0; i < frame->i_plane; i++ )
                {
                    h->picture->i_stride[i] = frame->i_stride[i];
                    h->picture->plane[i] = frame->plane[i];
                }
                h->fdec->i_poc = frame->i_poc;

                x264_encoder_frame_put( h->frame_unused, frame );   /* it's ok to do it now */,选出来的frame会被放入frame_unused队列的尾部,用于内存的重复利用
            }
            else
            {
                h->picture = NULL;
            }
        }
        else //如果没有B帧,逻辑比较简单
        {
            i_slice_type = h->i_frame % h->param.i_iframe == 0 ? SLICE_TYPE_I : SLICE_TYPE_P;

            /* we encode the given frame */
            h->picture     = pic;
            h->fdec->i_poc = h->i_poc;  /* low delay */
        }

        i_nal_type    = NAL_SLICE;
        if( i_slice_type == SLICE_TYPE_I || i_slice_type == SLICE_TYPE_P )
        {
            i_nal_ref_idc = NAL_PRIORITY_HIGH;  /* Not completely true but for now it is (as all I/P are kept as ref)*/
        }
        else /* if( i_slice_type == SLICE_TYPE_B ) */
        {
            i_nal_ref_idc = NAL_PRIORITY_DISPOSABLE;
        }
    }




static x264_frame_t *x264_encoder_frame_put_from_picture( x264_t *h, x264_frame_t *buffer[X264_BFRAME_MAX], x264_picture_t *picture )
{
    int i;
    x264_frame_t *frame;

    /* get an unused bframe */
    frame = h->frame_unused[0];//frame_unused:在初始化编码器时,会提前分配好i_bframe个帧的内存,放在frame_unused
    for( i = 0; i < X264_BFRAME_MAX; i++ )//从frame_unused中提取一个frame
    {
        h->frame_unused[i] = h->frame_unused[i+1];
    }
    h->frame_unused[X264_BFRAME_MAX] = NULL;

    /* copy the picture in it */
    x264_frame_copy_picture( frame, picture );//将picture的内容复制到frame,picture中包含每一个图片的实际数据,frame初始化时为空,此时将有效数据复制到frame,且重复利用内存

    /* put the frame in buffer */
    x264_encoder_frame_put( buffer, frame );//将获取到的frame放入buffer队列尾部

    buffer[i] = frame;//i=X264_BFRAME_MAX
    return frame;
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值