下面将开始分析x264编码的核心部分:x264_encoder_encode函数。 首先先看encode_frame函数:
static int encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic, int64_t *last_dts )
{
x264_picture_t pic_out; //编码后的图片
x264_nal_t *nal;
int i_nal;
int i_frame_size = 0; //帧的大小
//将待编码的一帧图片作为参数传进去,进行编码,再将编码后的图片传回来
i_frame_size = x264_encoder_encode( h, &nal, &i_nal, pic, &pic_out );
FAIL_IF_ERROR( i_frame_size < 0, "x264_encoder_encode failed\n" );
if( i_frame_size )
{
//将编码后的一帧图片输出
i_frame_size = cli_output.write_frame( hout, nal[0].p_payload, i_frame_size, &pic_out );
*last_dts = pic_out.i_dts; //跟新dts(编码顺序)
}
return i_frame_size;
}
下面将分析x264_encoder_encode函数:
/****************************************************************************
* x264_encoder_encode:
* XXX: i_poc : is the poc of the current given picture
* i_frame : is the number of the frame being coded
* ex: type frame poc
* I 0 2*0
* P 1 2*3
* B 2 2*1
* B 3 2*2
* P 4 2*6
* B 5 2*4
* B 6 2*5
****************************************************************************/
int x264_encoder_encode( x264_t *h,
x264_nal_t **pp_nal, int *pi_nal,
x264_picture_t *pic_in,
x264_picture_t *pic_out )
{
x264_t *thread_current, *thread_prev, *thread_oldest;
int i_nal_type, i_nal_ref_idc, i_global_qp;
int overhead = NALU_OVERHEAD;
#if HAVE_OPENCL
if( h->opencl.b_fatal_error )
return -1;
#endif
if( h->i_thread_frames > 1 )
{
thread_prev = h->thread[ h->i_thread_phase ];
h->i_thread_phase = (h->i_thread_phase + 1) % h->i_thread_frames;
thread_current = h->thread[ h->i_thread_phase ];
thread_oldest = h->thread[ (h->i_thread_phase + 1) % h->i_thread_frames ];
x264_thread_sync_context( thread_current, thread_prev );
x264_thread_sync_ratecontrol( thread_current, thread_prev, thread_oldest );
h = thread_current;
}
else
{
thread_current =
thread_oldest = h;
}
h->i_cpb_delay_pir_offset = h->i_cpb_delay_pir_offset_next;
/* no data out */
*pi_nal = 0;
*pp_nal = NULL;
/* ------------------- Setup new frame from picture -------------------- */
if( pic_in != NULL )
{
/* 1: Copy the picture to a frame and move it to a buffer */
//指针指向未编码的一帧空间
x264_frame_t *fenc = x264_frame_pop_unused( h, 0 );
if( !fenc )
return -1;
//将图片的信息拷贝到fenc中
if( x264_frame_copy_picture( h, fenc, pic_in ) < 0 )
return -1;
//如果宽高不是16的倍数,进行扩展
if( h->param.i_width != 16 * h->mb.i_mb_width ||
h->param.i_height != 16 * h->mb.i_mb_height )
x264_frame_expand_border_mod16( h, fenc );
//记录帧号
fenc->i_frame = h->frames.i_input++;
if( fenc->i_frame == 0 )
h->frames.i_first_pts = fenc->i_pts;
if( h->frames.i_bframe_delay && fenc->i_frame == h->frames.i_bframe_delay )
h->frames.i_bframe_delay_time = fenc->i_pts - h->frames.i_first_pts;
if( h->param.b_vfr_input && fenc->i_pts <= h->frames.i_largest_pts )
x264_log( h, X264_LOG_WARNING, "non-strictly-monotonic PTS\n" );
h->frames.i_second_largest_pts = h->frames.i_largest_pts;
h->frames.i_largest_pts = fenc->i_pts;
if( (fenc->i_pic_struct < PIC_STRUCT_AUTO) || (fenc->i_pic_struct > PIC_STRUCT_TRIPLE) )
fenc->i_pic_struct = PIC_STRUCT_AUTO;
if( fenc->i_pic_struct == PIC_STRUCT_AUTO )
{
#if HAVE_INTERLACED
int b_interlaced = fenc->param ? fenc->param->b_interlaced : h->param.b_interlaced;
#else
int b_interlaced = 0;
#endif
if( b_interlaced )
{
int b_tff = fenc->param ? fenc->param->b_tff : h->param.b_tff;
fenc->i_pic_struct = b_tff ? PIC_STRUCT_TOP_BOTTOM : PIC_STRUCT_BOTTOM_TOP;
}
else
fenc->i_pic_struct = PIC_STRUCT_PROGRESSIVE;
}
if( h->param.rc.b_mb_tree && h->param.rc.b_stat_read )
{