x264.c之static int Encode( x264_param_t *param, cli_opt_t *opt ) 函数的原型声明:
-
- static int Encode( x264_param_t *param, cli_opt_t *opt )
复制代码
static,是静态函数,网上搜了一段介绍:
在C中static有了第二种含义:用来表示不能被其它文件访问的全局变量和函数。, 但为了限制全局变量/函数的作用域, 函数或变量前加static使得函数成为静态函数。但此处“static”的含义不是指存储方式,而是指对函数的作用域仅局限于本文件(所以又称内部函数)。注意此时, 对于外部(全局)变量, 不论是否有static限制, 它的存储区域都是在静态存储区, 生存期都是全局的. 此时的static只是起作用域限制作用, 限定作用域在本模块(文件)内部.
使用内部函数的好处是:不同的人编写不同的函数时,不用担心自己定义的函数,是否会与其它文件中的函数同名。
函数的返回类型是int,在函数最后,返回了0:
函数接受两个参数:
- x264_param_t *param, cli_opt_t *opt
复制代码
都是自定义结构体的指针,对于这类比较庞大的变量来说,一般都是按地址传递的,所以用了指针类型。 x264_param_t在x264.h里定义,cli_opt_t在x264.c里定义,因为前一个结构体太长,不往这儿放了,只放出第二个来
- typedef struct
- {
- /* (CPU 标志位)*/
- unsigned int cpu;
- int i_threads;
- /* 视频属性 */
- int i_width; /* 宽度*/
- int i_height; /* 高度*/
- int i_csp; /* 色彩空间参数 */
- int i_level_idc; /* level值的设置 */
- int i_frame_total; /* 编码帧的总数, 默认 0 */
- ... ...
-
-
- /* Muxing parameters */
- int b_aud;
- int b_repeat_headers; /* */
- int i_sps_id; /* SPS and PPS id number */
- } x264_param_t;
-
-
- typedef struct {
- int b_progress; //用来控制是否显示编码进度的一个东西。取值为0,1
- int i_seek; //表示开始从哪一帧编码
- hnd_t hin; //
- hnd_t hout; //
- FILE *qpfile; //
- } cli_opt_t; /* 此结构体是记录一些与编码关系较小的设置信息的 */
复制代码
函数体的开始,定义了一些变量,有内置类型,也有自定义的结构体对象
-
- x264_t *h;
- x264_picture_t pic;
- int i_frame, i_frame_total;
- int64_t i_start, i_end; //从i_start开始编码,直到i_end结束
- int64_t i_file;
- int i_frame_size;
- int i_progress;
复制代码
x264_t也是一个很庞大的结构体: 在common.h里定义:
- struct x264_t
- {
- /* encoder parameters ( 编码器参数 )*/
- x264_param_t param;
-
- x264_t *thread[X264_SLICE_MAX];
-
- ... ...
-
- /* vlc table for decoding purpose only */
- x264_vlc_table_t *x264_coeff_token_lookup[5];
- x264_vlc_table_t *x264_level_prefix_lookup;
- x264_vlc_table_t *x264_total_zeros_lookup[15];
- x264_vlc_table_t *x264_total_zeros_dc_lookup[3];
- x264_vlc_table_t *x264_run_before_lookup[7];
- #if VISUALIZE
- struct visualize_t *visualize;
- #endif
- };
复制代码
x264_picture_t的定义相对来说简单些(在x264.h):
- typedef struct
- {
- int i_type;
- int i_qpplus1;
- int64_t i_pts;
-
- x264_image_t img;
- } x264_picture_t;
- 这里前三个都是普通的类型,第4个字段是结构体对象x264_image_t
-
- typedef struct
- {
- int i_csp;
- int i_plane;
- int i_stride[4];
- uint8_t *plane[4];
- } x264_image_t;
-
- 我们也可以把它合起来看,效果是一样的,把它看成是有7个字段的结构体:
-
- typedef struct
- {
- int i_type;
- int i_qpplus1;
- int64_t i_pts;
-
- int i_csp;
- int i_plane;
- int i_stride[4];
- uint8_t *plane[4];
- } x264_picture_t;
-
- 或者换一种方法来描述:
-
- typedef struct
- {
- int i_type;
- int i_qpplus1;
- int64_t i_pts;
-
- //x264_image_t img;
- typedef struct
- {
- int i_csp;
- int i_plane;
- int i_stride[4];
- uint8_t *plane[4];
- } x264_image_t;
-
- } x264_picture_t;
-
- 这种好象叫结构体的嵌套,当然原来的那种和这两种意思一样,但是实际效果在某些方面是有区别的。具体怎么样我也说不大清。
复制代码
开始的其它几个变量就都是普通的类型了,具体的作用,从变量的名称上能看出个大概来。 i_frame--统计已编码的总帧数 i_frame_total-----总共有多少帧要编码(可能会小于视频文件的总帧数) i_start------起始帧(比如,从第101帧开始编码) i_end------结束帧(比如,比如,从第101帧开始编码,到第200帧结束,文件可能一共有几万帧)
-
- i_frame_total = p_get_frame_total( opt->hin );
复制代码
赋值号左边是变量,i_frame_total,右边是函数p_get_frame_total,提供的参数是opt->hin,而opt 是调用Encode函数必须提供的第2个参数, 根据一般的命名规则看,这个hin应该是一个句柄,实际上它是指向一个YUV文件的指针,也就不难理解,赋值号右侧是提供一个文件句柄,它就可以获取到这个文件一共有多少帧。 实际上,x264是要编码,我们需要的是编码多少帧,并不在意文件总共有多少帧,即使用到,也是一个过渡。 上面提到,i_frame_total----是总共有多少帧要编码,当然还没有确认,只是大概的判断是这么个意思。 至于p_get_frame_total的具体实现,定位到这段代码:
- int (*p_open_infile)( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param );
复制代码
怎么看都觉得别扭,先不深究了
- i_frame_total -= opt->i_seek;
复制代码
这个是用到了C++的复合运算符,改写成最普通的式子:
-
- i_frame_total = i_frame_total - opt->i_seek;
复制代码
int i_seek; //表示开始从哪一帧编码,文件的总帧数 - 开始编码的起始帧数,这个结果还不是要编码的总帧数,因为要编码的最后一帧不一定是文件的最后一帧。
-
- if( ( i_frame_total == 0 || param->i_frame_total < i_frame_total ) && param->i_frame_total > 0 )
- i_frame_total = param->i_frame_total;
复制代码
这句进行了一个判断,用到了逻辑或(||)和逻辑与(&&)操作符,判断的结果如果为真(在C++中非0即为真,比如2也代表真) 那么就进行赋值操作,说白了,就是为了保证这个i_frame_total是一个合情合理的数,不要整出个没意义的来。 但是这几个i_frame_total让人有点迷糊,因为跨度太远了,前面的这个param->i_frame_total 是怎么得到的有点忘了,只是记的处理命令行参数时,有个解析命令行的过程,估计是那个时候填充这个字段的,还得回去翻翻。 在main函数中,调用了函数x264_param_default( ¶m );进行参数初始化,但是在这个函数里并没有针对i_frame_total初始化或者赋值(应该叫赋值吧,定义后再指定值应该是叫赋值)。 也就是说,调用x264_param_default( ¶m );后,i_frame_total实际是int型的默认值:0; 随后还有一个命令行的解析,调用的语句为:
-
- Parse( argc, argv, ¶m, &opt )
复制代码
在Parse里涉及到了i_frame_total:
-
-
- ... ...
-
- #define OPT_FRAMES 256
- ... ...
- case OPT_FRAMES:
- param->i_frame_total = atoi( optarg );
- break;
复制代码
从这儿也只是看出进行了字段填充,也看不出什么来,还得涉及到命令行的格式和解析,我记的命令行参数的实现,是把参数作为一个字符串来处理,收到后再用代码进行分析,从而实现命令的分情况处理。 在源码中,Parse函数内部调用了下面一条语句:
- 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的实现在“extras/getopt.c”文件中,
- /*
- * getopt_long --
- * Parse argc/argv argument vector.
- */
- int
- getopt_long(nargc, nargv, options, long_options, idx)
- int nargc;
- char * const *nargv;
- const char *options;
- const struct option *long_options;
- int *idx;
- {
- int retval;
- _DIAGASSERT(nargv != NULL);
- _DIAGASSERT(options != NULL);
- _DIAGASSERT(long_options != NULL);
- /* idx may be NULL */
- if ((retval = getopt_internal(nargc, nargv, options)) == -2) {
- char *current_argv, *has_equal;
- size_t current_argv_len;
- int i, match;
- current_argv = place;
- match = -1;
- optind++;
- place = EMSG;
- if (*current_argv == '\0') { /* found "--" */
- /*
- * We found an option (--), so if we skipped
- * non-options, we have to permute.
- */
- if (nonopt_end != -1) {
- permute_args(nonopt_start, nonopt_end,
- optind, nargv);
- optind -= nonopt_end - nonopt_start;
- }
- nonopt_start = nonopt_end = -1;
- return -1;
- }
- if ((has_equal = strchr(current_argv, '=')) != NULL) {
- /* argument found (--option=arg) */
- current_argv_len = has_equal - current_argv;
- has_equal++;
- } else
- current_argv_len = strlen(current_argv);
- for (i = 0; long_options[i].name; i++) {
- /* find matching long option */
- if (strncmp(current_argv, long_options[i].name,
- current_argv_len))
- continue;
- if (strlen(long_options[i].name) ==
- (unsigned)current_argv_len) {
- /* exact match */
- match = i;
- break;
- }
- if (match == -1) /* partial match */
- match = i;
- else {
- /* ambiguous abbreviation */
- if (PRINT_ERROR)
- warnx(ambig, (int)current_argv_len,
- current_argv);
- optopt = 0;
- return BADCH;
- }
- }
- if (match != -1) { /* option found */
- if (long_options[match].has_arg == no_argument
- && has_equal) {
- if (PRINT_ERROR)
- warnx(noarg, (int)current_argv_len,
- current_argv);
- /*
- * XXX: GNU sets optopt to val regardless of
- * flag
- */
- if (long_options[match].flag == NULL)
- optopt = long_options[match].val;
- else
- optopt = 0;
- return BADARG;
- }
- if (long_options[match].has_arg == required_argument ||
- long_options[match].has_arg == optional_argument) {
- if (has_equal)
- optarg = has_equal;
- else if (long_options[match].has_arg ==
- required_argument) {
- /*
- * optional argument doesn't use
- * next nargv
- */
- optarg = nargv[optind++];
- }
- }
- if ((long_options[match].has_arg == required_argument)
- && (optarg == NULL)) {
- /*
- * Missing argument; leading ':'
- * indicates no error should be generated
- */
- if (PRINT_ERROR)
- warnx(recargstring, current_argv);
- /*
- * XXX: GNU sets optopt to val regardless
- * of flag
- */
- if (long_options[match].flag == NULL)
- optopt = long_options[match].val;
- else
- optopt = 0;
- --optind;
- return BADARG;
- }
- } else { /* unknown option */
- if (PRINT_ERROR)
- warnx(illoptstring, current_argv);
- optopt = 0;
- return BADCH;
- }
- if (long_options[match].flag) {
- *long_options[match].flag = long_options[match].val;
- retval = 0;
- } else
- retval = long_options[match].val;
- if (idx)
- *idx = match;
- }
- return retval;
- }
复制代码
当然,上面这个函数有点扯远了,因为这段代码隐藏的比较深,所以先记在这儿,在代码中定位的时候只能定位到一个extern声明。 因为在Linux下,这个函数好象是系统带的,网上说windows下没有这个函数,得自己实现,所以多看了一眼。 大概的可以判断,param->i_frame_total最开始存的是命令行里输入的要编码的总帧数,比如我只编码视频中间的一截,可以指定编码100帧,而一个视频文件可能够播一个小时,当然远远不止这100帧。 当然,也有可能一个文件只有100帧,但是命令行中输出了500帧,这就是错误的了,指定编的总帧数超出了实际的物理帧数。 就需要在代码中判断,如果超范围了,就指定为一个最大的物理范围,即文件的总帧数,更确切的说,是文件的总帧数减去起始的帧余下的帧范围。 这样折腾只是为了多了解一下代码,其实不看代码也能猜想到该是什么意思。
在命令行输入从哪帧开始编码,一共编码多少帧解析命令行时,把用户的输入保存下来进行判断,确定要编码的总帧数是一个合理的范围 文件的总帧数-开始帧数,就是这个范围的上限,如果超出这个上限,就用这个上限,如果没超出,就用命令行的输入值 当然还有个情况,开始帧可能也会超出文件的总帧数,也需要判断 |
- if( ( h = x264_encoder_open( param ) ) == NULL )
复制代码
打开一个编码器,同时判断是否打开成功,左边是赋值语句,接收打开编码器返回的值,右边是比较判断,如果为NULL,说明打开失败 该函数的实现在“encoder/encoder.c”中:
- /****************************************************************************
- * x264_encoder_open:
- ****************************************************************************/
- x264_t *x264_encoder_open ( x264_param_t *param )
- {
- x264_t *h = x264_malloc( sizeof( x264_t ) ); /* 分配空间并进行初始化,x264_malloc( )在common.c中 */
- int i;
- memset( h, 0, sizeof( x264_t ) ); /* */
- /* Create a copy of param */
- memcpy( &h->param, param, sizeof( x264_param_t ) ); /* */
- if( x264_validate_parameters( h ) < 0 ) /* 函数x264_validate_parameters( h )在encoder.c中,功能为判断参数是否有效,并对不合适的参数进行修改 */
- {
- x264_free( h ); /* */
- return NULL;
- }
- if( h->param.psz_cqm_file ) /* */
- if( x264_cqm_parse_file( h, h->param.psz_cqm_file ) < 0 ) /* */
- {
- x264_free( h );
- return NULL;
- }
- if( h->param.rc.psz_stat_out ) /* */
- h->param.rc.psz_stat_out = strdup( h->param.rc.psz_stat_out ); /* */
- if( h->param.rc.psz_stat_in ) /* */
- h->param.rc.psz_stat_in = strdup( h->param.rc.psz_stat_in ); /* */
- if( h->param.rc.psz_rc_eq ) /* */
- h->param.rc.psz_rc_eq = strdup( h->param.rc.psz_rc_eq ); /* */
- /* VUI */
- if( h->param.vui.i_sar_width > 0 && h->param.vui.i_sar_height > 0 ) /* */
- {
- int i_w = param->vui.i_sar_width; /* */
- int i_h = param->vui.i_sar_height;
- x264_reduce_fraction( &i_w, &i_h ); /* */
- while( i_w > 65535 || i_h > 65535 )
- {
- i_w /= 2;
- i_h /= 2;
- }
- h->param.vui.i_sar_width = 0;
- h->param.vui.i_sar_height = 0;
- if( i_w == 0 || i_h == 0 )
- {
- x264_log( h, X264_LOG_WARNING, "cannot create valid sample aspect ratio\n" ); /* */
- }
- else
- {
- x264_log( h, X264_LOG_INFO, "using SAR=%d/%d\n", i_w, i_h ); /* */
- h->param.vui.i_sar_width = i_w;
- h->param.vui.i_sar_height = i_h;
- }
- }
- x264_reduce_fraction( &h->param.i_fps_num, &h->param.i_fps_den ); /* */
-
- ... ...
- return h;
- }
复制代码
这个函数很复杂,先不理会它的内部了,从后续的过程看,它只是进行了一些准备工作,并没有实际进行编码,因为后面有一个是对每一帧编码的循环过程。
- if( ( h = x264_encoder_open( param ) ) == NULL )
- {
- fprintf( stderr, "x264 [error]: x264_encoder_open failed\n" );
- p_close_infile( opt->hin );
- p_close_outfile( opt->hout );
- return -1;
- }
复制代码
判断创建编码器失败的话就关闭打开的输入和输出文件,并返回-1
- if( p_set_outfile_param( opt->hout, param ) )
- {
- fprintf( stderr, "x264 [error]: can't set outfile param\n" );
- p_close_infile( opt->hin );
- p_close_outfile( opt->hout );
- return -1;
- }
复制代码
设置输出文件参数,如果失败的话,仍然是输出出错提示并关闭输入文件和输出文件,来看看这三个函数 p_set_outfile_param p_close_infile p_close_outfile
- [code]static int (*p_open_outfile)( char *psz_filename, hnd_t *p_handle );
- static int (*p_set_outfile_param)( hnd_t handle, x264_param_t *p_param );
- static int (*p_close_outfile)( hnd_t handle );
复制代码
int (*p_open_infile)( char *psz_filename, hnd_t *p_handle, x264_param_t *p_param ); int (*p_close_infile)( hnd_t handle ); [/code] 这是在x264.c里声明的函数原型。 奇怪的是怎么也搜不到具体的实现代码。
该函数的声明是在common/common.h中
- int64_t x264_mdate( void );
复制代码
该函数的实现代码是在common/mdate.c中
-
- int64_t x264_mdate( void )
- {
- #if !(defined(_MSC_VER) || defined(__MINGW32__))
- struct timeval tv_date;
- gettimeofday( &tv_date, NULL );
- return( (int64_t) tv_date.tv_sec * 1000000 + (int64_t) tv_date.tv_usec );
- #else
- struct _timeb tb;
- _ftime(&tb);
- return ((int64_t)tb.time * (1000) + (int64_t)tb.millitm) * (1000);
- #endif
- }
复制代码
大略的意思是返回当前时间,用毫秒表示的,不是很清楚,反正是开始编码的时间,后面会再取到一个结束时间,然后求差,来计算编码速度。就这么个意思。 上面这个函数呢,没看懂,只能大略的这样理解了。 接下来,是个for循环,实质性的编码就在这儿展开,它循环的取每一帧,然后调用某个函数进行编码,如此反复,直到完成工作或者出错。
-
/* (循环编码每一帧) Encode frames */ - for( i_frame = 0, i_file = 0, i_progress = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); )
- {
- if( p_read_frame( &pic, opt->hin, i_frame + opt->i_seek ) )/* 读入第i_frame帧,从起始帧算,而不是视频的第0帧 */
- break;
- pic.i_pts = (int64_t)i_frame * param->i_fps_den;
- if( opt->qpfile )
- parse_qpfile( opt, &pic, i_frame + opt->i_seek );
- else
- {
- /* Do not force any parameters */
- pic.i_type = X264_TYPE_AUTO;
- pic.i_qpplus1 = 0;
- }
- i_file += Encode_frame( h, opt->hout, &pic );
- i_frame++;//已编码的帧数统计(递增1)
- /* 更新状态提示 update status line (up to 1000 times per input file) */
- if( opt->b_progress && param->i_log_level < X264_LOG_DEBUG &&
- ( i_frame_total ? i_frame * 1000 / i_frame_total > i_progress
- : i_frame % 10 == 0 ) )
- {
- int64_t i_elapsed = x264_mdate() - i_start;
- double fps = i_elapsed > 0 ? i_frame * 1000000. / i_elapsed : 0;
- if( i_frame_total )
- {
- int eta = i_elapsed * (i_frame_total - i_frame) / ((int64_t)i_frame * 1000000);
- i_progress = i_frame * 1000 / i_frame_total;
- fprintf( stderr, "encoded frames: %d/%d (%.1f%%), %.2f fps, eta %d:%02d:%02d \r", /* 状态提示 */
- i_frame, i_frame_total, (float)i_progress / 10, fps,
- eta/3600, (eta/60)%60, eta%60 );
- }
- else
- fprintf( stderr, "encoded frames: %d, %.2f fps \r", i_frame, fps ); /* 状态提示,共编码了... */
- fflush( stderr ); // needed in windows
- }
- }
复制代码
一开始就试过命令行执行x264.exe,给定一个输入文件和一个输出文件,最后编码输出,把编码的结果会输出到给定的输出文件。 所以在这个循环中,某一步中肯定会有一个写文件的动作,当然,可能不是在这段中直接用到,可能是调用的某个函数中也是有可能的。
-
- for( i_frame = 0, i_file = 0, i_progress = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); )
复制代码
平常见的都是
-
- for (int i = 0; i<100;i++)
- {
- ... ...
- }
复制代码
这样的循环语句,这儿怎么是这样子。
- for( i_frame = 0, i_file = 0, i_progress = 0; b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); )
复制代码
这个语句的意思是: 进入for循环时, 第一步:执行三个变量的赋值, i_frame = 0, i_file = 0, i_progress = 0; 第二步:判断是否退出循环的条件为b_ctrl_c == 0 && (i_frame < i_frame_total || i_frame_total == 0); 第三步:平时的递增省略了,由for函数体内的语句人为的进行递增操作。
-
- if( p_read_frame( &pic, opt->hin, i_frame + opt->i_seek ) ) /* 读入第i_frame帧,从起始帧算,而不是视频的第0帧 */
- break;
复制代码
该函数的声明在x264.c
- int (*p_read_frame)( x264_picture_t *p_pic, hnd_t handle, int i_frame );
复制代码
第1个参数为结构体的指针,读到的像素值将填充它,第2个参数是句柄,指定读哪个文件,第3个参数指定读哪一帧,其中第3个参数帧序号是递增的,递增的实现在后面的一句语句:
至于if后的break;因为p_read_frame的类型是int,当返回值非0时退出for循环,所以当读取帧内容正确的时候,它返回的应该是0,因为现在还没找到它的具体的实现代码,所以这样判断一下了。
-
- pic.i_pts = (int64_t)i_frame * param->i_fps_den;
复制代码
这句是什么意思啊????
如果opt->qpfile非0,那么执行后续的语句,这个qpfile是结构体cli_opt_t的字段之一:
- typedef struct {
- int b_progress; //用来控制是否显示编码进度的一个东西。取值为0,1
- int i_seek; //表示开始从哪一帧编码
- hnd_t hin; //Hin 指向输入yuv文件的指针 //void *在C语言里空指针是有几个特性的,他是一个一般化指针,可以指向任何一种类型,但却不能解引用,需要解引用的时候,需要进行强制转换。采用空指针的策略,应该是为了声明变量的简便和统一。
- hnd_t hout; //Hout 指向编码过后生成的文件的指针
- FILE *qpfile; //Qpfile 是一个指向文件类型的指针,他是文本文件,其每一行的格式是framenum frametype QP,用于强制指定某些帧或者全部帧的帧类型和QP(quant param量化参数)的值
- } cli_opt_t; /* 此结构体是记录一些与编码关系较小的设置信息的 */
复制代码
这个qpfile指的这个文件是什么意思,不是说那个yuv文件吗,另外还有一个文件????
-
- pic.i_type = X264_TYPE_AUTO;
- pic.i_qpplus1 = 0;//I_qpplus1 :此参数减1代表当前画面的量化参数值
复制代码
其中的i_qpplus1,此参数减1代表当前画面的量化参数值,那么当前画面的量化参数值是-1?真的是负数?
-
- i_file += Encode_frame( h, opt->hout, &pic );
复制代码
这是真正的调用这个函数对这一帧进行编码,该函数的第二个参数,看样子是指向输出文件,第三个参数里,存储着待编码的原始数据,当然还有其它一些相关的字段,第一个参数是一个结构。 该函数的原型声明及实现:
-
- static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic )
- {
- x264_picture_t pic_out;
- x264_nal_t *nal;
- int i_nal, i;
- int i_file = 0;
- if( x264_encoder_encode( h, &nal, &i_nal, pic, &pic_out ) < 0 )
- {
- fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" );
- }
- for( i = 0; i < i_nal; i++ )
- {
- int i_size;
- int i_data;
- i_data = DATA_MAX;
- if( ( i_size = x264_nal_encode( data, &i_data, 1, &nal[i] ) ) > 0 )
- {
- i_file += p_write_nalu( hout, data, i_size );
- }
- else if( i_size < 0 )
- {
- fprintf( stderr, "x264 [error]: need to increase buffer size (size=%d)\n", -i_size );
- }
- }
- if (i_nal)
- p_set_eop( hout, &pic_out );
- return i_file;
- }
复制代码
这个先不深究,因为大概看了一下,看一明白,继续
- /* Flush delayed(延迟) B-frames */
- do {
- i_file +=
- i_frame_size = Encode_frame( h, opt->hout, NULL );//上面调用的是i_file += Encode_frame( h, opt->hout, &pic );
- } while( i_frame_size );
复制代码
这里面又循环调用了 Encode_frame( h, opt->hout, NULL );,前面刚刚循环过,两次的差别只是最后一个参数
- i_file += Encode_frame( h, opt->hout, &pic );
-
- i_file +=
- i_frame_size = Encode_frame( h, opt->hout, NULL );
复制代码
第1个一开始认为是对帧进行了编码,那第二次调呢,又是做什么,糊涂了。 至于后面的代码,就是进行一些状态的提示。并关闭输入和输出文件。因为这是main函数调用的最后一步了。 这个函数里有好几个地方不懂,用特殊颜色标出来了,以后慢慢找答案吧。 再去转一个文件,看看状态提示什么的。 x264_picture_clean的实现代码在common/common.c中
-
- void x264_picture_clean( x264_picture_t *pic )
- {
- x264_free( pic->img.plane[0] );
- /* just to be safe */
- memset( pic, 0, sizeof( x264_picture_t ) );
- }
复制代码
memset是把一块内存设为某个值,这里全设置成了0。这是为了防止下次再用这块内存的时候忘了初始化,上次的结果会带到下次。不会描述了,就那么个意思,比如下次定义了一个变量,本来应该是NULL或者0,但是未初始化它,本来不应该是其它值的,结果这块内存上次用完未还原,结果新定义的变量可能就不是NULL或者为0,而是一个意想不到的值,这个值和上次使用完时的状态有关。是个不确定的值。
- void x264_free( void *p )
- {
- if( p )
- {
- #if defined( HAVE_MALLOC_H ) || defined( SYS_MACOSX )
- free( p );
- #else
- free( *( ( ( void **) p ) - 1 ) );
- #endif
- }
- }
复制代码
关闭编码器,前面有个对应的函数调用,是打开编码器
-
- if( ( h = x264_encoder_open( param ) ) == NULL )
- ... ...
- x264_encoder_close( h );
复制代码
x264_encoder_close在encoder/encoder.c中实现,也是非常的复杂。 |