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;
}