1、x264程序框架流程分析
(1) 进入x264.c 的int main( int argc, char **argv ) 函数
main 函数中主要有以下三个主要的步骤,分别调用了3个函数。
第一步、对编码器进行参数设定。函数实现如下:
x264_param_default( x264_param_t *param );此函数在common.c中定义,完成一个x264_param_t 结构体的初始化。
第二步、分析参数,读入运行参数完成文件打开。函数实现如下:
Parse( argc, argv, x264_param_t *param, &opt );此函数在 x264.c 中定义。
VC的运行参数我们可以设置: “-o out.264 football.yuv 352x288”
则具体到Parse函数,其输入的参数 argc == 5 ,这个数值大小等于要放下下面的 argv所需要的二维数组的行数。参数argc和argv在进入main 函数之前就已经确定了。
argv 为字符串char **的类型的,相当于一个二维数组,其具体内容如下:
argv[0][] == “F:\x264-snapshot-20070331-2245\build\win32\bin\x264.exe”
argv[1][] == “-o”
argv[2][] == “out.264”
argv[3][] == “football.yuv”
argv[4][] == “352x288”
第三步、开始编码。函数实现如下:
Encode( x264_param_t *param, &opt ); 此函数在 x264.c 中定义。
(2) static int Parse( int argc, char **argv, x264_param_t *param, cli_opt_t *opt )
分析参数,读入运行参数。
其中比较重要的语句是
int c = getopt_long( argc, argv, "8A:B:b:f:hI:i:m:o:p:q:r:t:Vvw",
long_options, &long_options_index);
getopt_long()解析入口地址的向量,最后int c 得到的是 运行参数(“-o out.264 football.yuv 352x288”)中前面“-o”中“o”的ASCII值 即 c = 111 。这个getopt_long函数的实现在官方网站上下的程序中没有实现,需要自己来写。
Parse 在解析了入口地址后,用下面的语句打开文件
p_open_infile( psz_filename, &opt->hin, param )
{
yuv_input_t *h = malloc(sizeof(yuv_input_t));
h->width = p_param->i_width;
h->height = p_param->i_height;
h->next_frame = 0;
if( !strcmp(psz_filename, "-") )
h->fh = stdin;
else
h->fh = fopen(psz_filename, "rb");
if( h->fh == NULL )
return -1;
*p_handle = (hnd_t)h;
return 0;
}
这样就在下面Encode函数中一开始,得到总的编码帧数,调用这个函数
int get_frame_total_yuv( hnd_t handle )
{
yuv_input_t *h = handle;
int i_frame_total = 0;
if( !fseek( h->fh, 0, SEEK_END ) )
{
uint64_t i_size = ftell( h->fh );//得到文件的大小。
fseek( h->fh, 0, SEEK_SET );
i_frame_total = (int)(i_size / ( h->width * h->height * 3 / 2 ));
//计算总的帧数
/// 这里乘以1.5是因为一个编码单位是一个亮度块加2个色度块,大小上等于1.5个亮度块
}
return i_frame_total;
}
(3) static int Encode( x264_param_t *param, cli_opt_t *opt )
前面都是读取默认参数,如果设置了参数的话,可以修改 param的。编码的主要部分还是在这个函数里面进行调用。
Encode 函数主要分为以下几步:
第一步、读取输入文件的总帧数,存放在 param->i_frame_total。
第二步、调用 h = x264_encoder_open( param ) 函数对不正确的264_t结构体(h的类型是264_t * )参数进行修改,并对各结构体参数、编码、预测等需要的参数进行初始化。
第三步、构造一个图像帧的初始化空间。
x264_picture_alloc( &pic, X264_CSP_I420, param->i_width, param->i_height );
第四步、利用下面一个for循环,开始一帧一帧进行编码。
for( i_frame = 0, i_file = 0, i_progress = 0;
b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); )
在这个for循环中,
读取 p_read_frame( &pic, opt->hin, i_frame + opt->i_seek )
编码并保存 i_file += Encode_frame( h, opt->hout, &pic );
(4) static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic )
这个函数主要是调用了 x264_encoder_encode( h, &nal, &i_nal, pic, &pic_out ) 来实现编码。这个函数也是x264的核心部分了