<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-e2445db1a8.css">
<div class="htmledit_views">
x265探索与研究(六):main()函数
x265源码的入口函数是main(),本文分析main()的主要功能。首先给出main()函数的功能及其代码结构;其次给出main()函数源码以及分析;最后给出main()函数中的主要功能函数的具体功能。
1、main()函数的功能及其代码结构
main()函数的主要功能是解析参数并进行编码的一些准备工作,调用了如下几个重要的函数:
(1)cliopt.parse()函数:解析参数
(2)api->encoder_open()函数:打开编码器配置
(3)api->encoder_headers()函数:设置NAL相关信息
(4)api->encoder_encode()函数:进入编码函数
(5)api->encoder_close()函数:结束编码并进行总结
注:encoder_open()函数、encoder_headers()函数、encoder_encode()函数与encoder_close()函数均位于api.app中。
对应的函数关系图如下图所示:
2、main()函数源码以及分析
main()函数的源码分析如下代码中的注释,代码如下:
-
/*=============================================================*/
-
/*
-
====== Analysed by: RuiDong Fang
-
====== Csdn Blog: http://blog.csdn.net/frd2009041510
-
====== Date: 2016.04.10
-
====== Funtion: x265的入口main()函数
-
*/
-
/*=============================================================*/
-
/* CLI return codes:
-
*
-
* 0 - encode successful
-
* 1 - unable to parse command line
-
* 2 - unable to open encoder
-
* 3 - unable to generate stream headers
-
* 4 - encoder abort
-
* 5 - unable to open csv file
-
*
-
*/
-
int main(int argc, char **argv) //主函数入口
-
{
-
#if HAVE_VLD
-
// This uses Microsoft's proprietary WCHAR type, but this only builds on Windows to start with
-
VLDSetReportOptions(VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE,
L"x265_leaks.txt");
-
#endif
-
PROFILE_INIT();
-
THREAD_NAME(
"API",
0);
-
-
GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);
//获取控制台窗口
-
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
-
-
ReconPlay* reconPlay =
NULL;
-
CLIOptions cliopt;
-
-
if (cliopt.parse(argc, argv))
//==========分析参数,对编码器的参数进行设定,打开文件
-
{
-
cliopt.destroy();
-
if (cliopt.api)
-
cliopt.api->param_free(cliopt.param);
-
exit(
1);
-
}
-
-
x265_param* param = cliopt.param;
-
const x265_api* api = cliopt.api;
-
-
/* This allows muxers to modify bitstream format */
-
cliopt.output->setParam(param);
-
-
if (cliopt.reconPlayCmd)
-
reconPlay =
new ReconPlay(cliopt.reconPlayCmd, *param);
-
-
/* note: we could try to acquire a different libx265 API here based on
-
* the profile found during option parsing, but it must be done before
-
* opening an encoder */
-
-
x265_encoder *encoder = api->encoder_open(param);
//==========encoder_open()函数,打印编码器配置
-
if (!encoder)
//若打不开编码器配置,提示错误
-
{
-
x265_log(param, X265_LOG_ERROR,
"failed to open encoder\n");
-
cliopt.destroy();
-
api->param_free(param);
-
api->cleanup();
-
exit(
2);
-
}
-
-
/* get the encoder parameters post-initialization */
-
api->encoder_parameters(encoder, param);
-
-
if (cliopt.csvfn)
-
{
-
cliopt.csvfpt = x265_csvlog_open(*api, *param, cliopt.csvfn, cliopt.csvLogLevel);
-
if (!cliopt.csvfpt)
-
{
-
x265_log(param, X265_LOG_ERROR,
"Unable to open CSV log file <%s>, aborting\n", cliopt.csvfn);
-
cliopt.destroy();
-
if (cliopt.api)
-
cliopt.api->param_free(cliopt.param);
-
exit(
5);
-
}
-
}
-
-
/* Control-C handler */
-
//当键入Ctrl-C的时候,当前执行程序调用指针函数sigint_handler 执行完后,再返回原来执行的地方接着往下走。
-
if (signal(SIGINT, sigint_handler) == SIG_ERR)
-
x265_log(param, X265_LOG_ERROR,
"Unable to register CTRL+C handler: %s\n", strerror(errno));
-
-
x265_picture pic_orig, pic_out;
//定义x265的输入pic_orig和输出pic_out
-
x265_picture *pic_in = &pic_orig;
//获取x265的输入pic_orig的地址
-
-
/* Allocate recon picture if analysisMode is enabled */
-
std::priority_queue<
int64_t>* pts_queue = cliopt.output->needPTS() ?
new
std::priority_queue<
int64_t>() :
NULL;
-
x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode || pts_queue || reconPlay || cliopt.csvLogLevel) ? &pic_out :
NULL;
-
-
uint32_t inFrameCount =
0;
//输入的帧数
-
uint32_t outFrameCount =
0;
//输出的帧数
-
-
x265_nal *p_nal;
-
x265_stats stats;
-
uint32_t nal;
-
int16_t *errorBuf =
NULL;
-
int ret =
0;
-
-
if (!param->bRepeatHeaders)
-
{
-
if (api->encoder_headers(encoder, &p_nal, &nal) <
0)
//==========encoder_headers函数
-
{
-
x265_log(param, X265_LOG_ERROR,
"Failure generating stream headers\n");
-
ret =
3;
-
goto fail;
-
}
-
else
-
cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
-
}
-
-
api->picture_init(param, pic_in);
-
-
if (cliopt.bDither)
-
{
-
errorBuf = X265_MALLOC(
int16_t, param->sourceWidth +
1);
-
if (errorBuf)
-
memset(errorBuf,
0, (param->sourceWidth +
1) *
sizeof(
int16_t));
-
else
-
cliopt.bDither =
false;
-
}
-
-
// main encoder loop(编码主循环)
-
while (pic_in && !b_ctrl_c)
-
{
-
pic_orig.poc = inFrameCount;
-
if (cliopt.qpfile)
-
{
-
if (!cliopt.parseQPFile(pic_orig))
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"can't parse qpfile for frame %d\n", pic_in->poc);
-
fclose(cliopt.qpfile);
-
cliopt.qpfile =
NULL;
-
}
-
}
-
-
//当输入帧将要全部编码且输入的帧数大于或等于将要编码的帧数
-
if (cliopt.framesToBeEncoded && inFrameCount >= cliopt.framesToBeEncoded)
-
pic_in =
NULL;
-
else
if (cliopt.input->readPicture(pic_orig))
//每读入一帧
-
inFrameCount++;
//输入的帧数自加1
-
else
-
pic_in =
NULL;
-
-
if (pic_in)
-
{
-
if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)
-
{
-
x265_dither_image(*api, *pic_in, cliopt.input->getWidth(), cliopt.input->getHeight(), errorBuf, param->internalBitDepth);
-
pic_in->bitDepth = param->internalBitDepth;
-
}
-
/* Overwrite PTS */
-
pic_in->pts = pic_in->poc;
-
}
-
//进行编码的入口函数,读入24帧后才开始编码
-
int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon);
//==========encoder_encode()函数,numEncoded是将要编码的帧数
-
if (numEncoded <
0)
-
{
-
b_ctrl_c =
1;
-
ret =
4;
-
break;
-
}
-
-
if (reconPlay && numEncoded)
-
reconPlay->writePicture(*pic_recon);
-
-
outFrameCount += numEncoded;
-
-
if (numEncoded && pic_recon && cliopt.recon)
-
cliopt.recon->writePicture(pic_out);
-
if (nal)
-
{
-
cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
-
if (pts_queue)
-
{
-
pts_queue->push(-pic_out.pts);
-
if (pts_queue->size() >
2)
-
pts_queue->pop();
-
}
-
}
-
-
cliopt.printStatus(outFrameCount);
//打印编码帧的具体信息
-
if (numEncoded && cliopt.csvLogLevel)
-
x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
-
}
-
-
/* Flush the encoder */
-
/*功能:前面读入24帧后才开始编码,此处其实就是处理对应的倒数的24帧,将其存储*/
-
while (!b_ctrl_c)
//退出上一个大循环后且没有按下Ctrl+C,代码继续执行
-
{
-
//==========encoder_encode()函数
-
int numEncoded = api->encoder_encode(encoder, &p_nal, &nal,
NULL, pic_recon);
-
if (numEncoded <
0)
-
{
-
ret =
4;
-
break;
-
}
-
-
if (reconPlay && numEncoded)
-
reconPlay->writePicture(*pic_recon);
-
-
outFrameCount += numEncoded;
-
if (numEncoded && pic_recon && cliopt.recon)
-
cliopt.recon->writePicture(pic_out);
-
if (nal)
-
{
-
cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
-
if (pts_queue)
-
{
-
pts_queue->push(-pic_out.pts);
-
if (pts_queue->size() >
2)
-
pts_queue->pop();
-
}
-
}
-
-
cliopt.printStatus(outFrameCount);
-
if (numEncoded && cliopt.csvLogLevel)
-
x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
-
-
if (!numEncoded)
-
break;
-
}
-
-
/* clear progress report */
-
if (cliopt.bProgress)
-
fprintf(
stderr,
"%*s\r",
80,
" ");
-
-
fail:
-
-
delete reconPlay;
-
-
api->encoder_get_stats(encoder, &stats,
sizeof(stats));
-
if (cliopt.csvfpt && !b_ctrl_c)
-
x265_csvlog_encode(cliopt.csvfpt, *api, *param, stats, cliopt.csvLogLevel, argc, argv);
-
api->encoder_close(encoder);
//==========encoder_close()函数
-
-
int64_t second_largest_pts =
0;
-
int64_t largest_pts =
0;
-
if (pts_queue && pts_queue->size() >=
2)
-
{
-
second_largest_pts = -pts_queue->top();
-
pts_queue->pop();
-
largest_pts = -pts_queue->top();
-
pts_queue->pop();
-
delete pts_queue;
-
pts_queue =
NULL;
-
}
-
cliopt.output->closeFile(largest_pts, second_largest_pts);
-
-
if (b_ctrl_c)
//按下Ctrl+C,直接退出
-
general_log(param,
NULL, X265_LOG_INFO,
"aborted at input frame %d, output frame %d\n",
-
cliopt.seek + inFrameCount, stats.encodedPictureCount);
-
-
api->cleanup();
/* Free library singletons */
-
-
cliopt.destroy();
-
-
api->param_free(param);
-
-
X265_FREE(errorBuf);
-
-
SetConsoleTitle(orgConsoleTitle);
//设置控制窗口标题
-
SetThreadExecutionState(ES_CONTINUOUS);
-
-
#if HAVE_VLD
-
assert(VLDReportLeaks() ==
0);
-
#endif
-
-
return ret;
-
}
3、main()函数中的部分功能函数的具体功能
3.1、GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);
GetConsoleTitle的主要功能是获取控制台窗口,其中orgConsoleTitle指向一个缓冲区指针以接收包含标题的字符串;CONSOLE_TITLE_SIZE)是由orgConsoleTitle指向的缓冲区大小。如果函数成功,则返回值是以字符为单位的长度控制台窗口的标题;如果该函数失败,则返回值为零。要获取错误信息,可以调用GetLastError 。
3.2、cliopt.parse(argc, argv)
cliopt.parse(argc, argv)的主要功能是分析参数,直接调用x265.cpp中的bool CLIOptions::parse(int argc, char **argv)函数,该函数会打印输入视频的分辨率、帧率、视频格式、所要编码的帧数目以及输出文件名称等,如下图所示:
对应的代码如下:
-
bool CLIOptions::parse(
int argc,
char **argv)
-
{
-
bool bError =
false;
-
int bShowHelp =
false;
-
int inputBitDepth =
8;
-
int outputBitDepth =
0;
-
int reconFileBitDepth =
0;
-
const
char *inputfn =
NULL;
-
const
char *reconfn =
NULL;
-
const
char *outputfn =
NULL;
-
const
char *preset =
NULL;
-
const
char *tune =
NULL;
-
const
char *profile =
NULL;
-
-
if (argc <=
1)
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"No input file. Run x265 --help for a list of options.\n");
-
return
true;
-
}
-
-
/* Presets are applied before all other options. */
-
for (optind =
0;; )
-
{
-
int c = getopt_long(argc, argv, short_options, long_options,
NULL);
-
if (c ==
-1)
-
break;
-
else
if (c ==
'p')
-
preset = optarg;
-
else
if (c ==
't')
-
tune = optarg;
-
else
if (c ==
'D')
-
outputBitDepth = atoi(optarg);
-
else
if (c ==
'P')
-
profile = optarg;
-
else
if (c ==
'?')
-
bShowHelp =
true;
-
}
-
-
if (!outputBitDepth && profile)
-
{
-
/* try to derive the output bit depth from the requested profile */
-
if (
strstr(profile,
"10"))
-
outputBitDepth =
10;
-
else
if (
strstr(profile,
"12"))
-
outputBitDepth =
12;
-
else
-
outputBitDepth =
8;
-
}
-
-
api = x265_api_get(outputBitDepth);
-
if (!api)
-
{
-
x265_log(
NULL, X265_LOG_WARNING,
"falling back to default bit-depth\n");
-
api = x265_api_get(
0);
-
}
-
-
param = api->param_alloc();
-
if (!param)
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"param alloc failed\n");
-
return
true;
-
}
-
-
if (api->param_default_preset(param, preset, tune) <
0)
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"preset or tune unrecognized\n");
-
return
true;
-
}
-
-
if (bShowHelp)
-
{
-
printVersion(param, api);
-
showHelp(param);
-
}
-
-
for (optind =
0;; )
-
{
-
int long_options_index =
-1;
-
int c = getopt_long(argc, argv, short_options, long_options, &long_options_index);
-
if (c ==
-1)
-
break;
-
-
switch (c)
-
{
-
case
'h':
-
printVersion(param, api);
-
showHelp(param);
-
break;
-
-
case
'V':
-
printVersion(param, api);
-
x265_report_simd(param);
-
exit(
0);
-
-
default:
-
if (long_options_index <
0 && c >
0)
-
{
-
for (
size_t i =
0; i <
sizeof(long_options) /
sizeof(long_options[
0]); i++)
-
{
-
if (long_options[i].val == c)
-
{
-
long_options_index = (
int)i;
-
break;
-
}
-
}
-
-
if (long_options_index <
0)
-
{
-
/* getopt_long might have already printed an error message */
-
if (c !=
63)
-
x265_log(
NULL, X265_LOG_WARNING,
"internal error: short option '%c' has no long option\n", c);
-
return
true;
-
}
-
}
-
if (long_options_index <
0)
-
{
-
x265_log(
NULL, X265_LOG_WARNING,
"short option '%c' unrecognized\n", c);
-
return
true;
-
}
-
#define OPT(longname) \
-
else
if (!strcmp(long_options[long_options_index].name, longname))
-
#define OPT2(name1, name2) \
-
else if (!strcmp(long_options[long_options_index].name, name1) || \
-
!strcmp(long_options[long_options_index].name, name2))
-
-
if (
0) ;
-
OPT2(
"frame-skip",
"seek")
this->seek = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"frames")
this->framesToBeEncoded = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"csv")
this->csvfn = optarg;
-
OPT(
"csv-log-level")
this->csvLogLevel = x265_atoi(optarg, bError);
-
OPT(
"no-progress")
this->bProgress =
false;
-
OPT(
"output") outputfn = optarg;
-
OPT(
"input") inputfn = optarg;
-
OPT(
"recon") reconfn = optarg;
-
OPT(
"input-depth") inputBitDepth = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"dither")
this->bDither =
true;
-
OPT(
"recon-depth") reconFileBitDepth = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"y4m")
this->bForceY4m =
true;
-
OPT(
"profile")
/* handled above */;
-
OPT(
"preset")
/* handled above */;
-
OPT(
"tune")
/* handled above */;
-
OPT(
"output-depth")
/* handled above */;
-
OPT(
"recon-y4m-exec") reconPlayCmd = optarg;
-
OPT(
"qpfile")
-
{
-
this->qpfile = fopen(optarg,
"rb");
-
if (!
this->qpfile)
-
{
-
x265_log(param, X265_LOG_ERROR,
"%s qpfile not found or error in opening qp file\n", optarg);
-
return
false;
-
}
-
}
-
else
-
bError |= !!api->param_parse(param, long_options[long_options_index].name, optarg);
-
-
if (bError)
-
{
-
const
char *name = long_options_index >
0 ? long_options[long_options_index].name : argv[optind -
2];
-
x265_log(
NULL, X265_LOG_ERROR,
"invalid argument: %s = %s\n", name, optarg);
-
return
true;
-
}
-
#undef OPT
-
}
-
}
-
-
if (optind < argc && !inputfn)
-
inputfn = argv[optind++];
-
if (optind < argc && !outputfn)
-
outputfn = argv[optind++];
-
if (optind < argc)
-
{
-
x265_log(param, X265_LOG_WARNING,
"extra unused command arguments given <%s>\n", argv[optind]);
-
return
true;
-
}
-
-
if (argc <=
1)
-
{
-
api->param_default(param);
-
printVersion(param, api);
-
showHelp(param);
-
}
-
-
if (!inputfn || !outputfn)
-
{
-
x265_log(param, X265_LOG_ERROR,
"input or output file not specified, try --help for help\n");
-
return
true;
-
}
-
-
if (param->internalBitDepth != api->bit_depth)
-
{
-
x265_log(param, X265_LOG_ERROR,
"Only bit depths of %d are supported in this build\n", api->bit_depth);
-
return
true;
-
}
-
-
InputFileInfo info;
-
info.filename = inputfn;
-
info.depth = inputBitDepth;
-
info.csp = param->internalCsp;
-
info.width = param->sourceWidth;
-
info.height = param->sourceHeight;
-
info.fpsNum = param->fpsNum;
-
info.fpsDenom = param->fpsDenom;
-
info.sarWidth = param->vui.sarWidth;
-
info.sarHeight = param->vui.sarHeight;
-
info.skipFrames = seek;
-
info.frameCount =
0;
-
getParamAspectRatio(param, info.sarWidth, info.sarHeight);
-
-
this->input = InputFile::open(info,
this->bForceY4m);
-
if (!
this->input ||
this->input->isFail())
-
{
-
x265_log(param, X265_LOG_ERROR,
"unable to open input file <%s>\n", inputfn);
-
return
true;
-
}
-
-
if (info.depth <
8 || info.depth >
16)
-
{
-
x265_log(param, X265_LOG_ERROR,
"Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);
-
return
true;
-
}
-
-
/* Unconditionally accept height/width/csp from file info */
-
param->sourceWidth = info.width;
-
param->sourceHeight = info.height;
-
param->internalCsp = info.csp;
-
-
/* Accept fps and sar from file info if not specified by user */
-
if (param->fpsDenom ==
0 || param->fpsNum ==
0)
-
{
-
param->fpsDenom = info.fpsDenom;
-
param->fpsNum = info.fpsNum;
-
}
-
if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)
-
setParamAspectRatio(param, info.sarWidth, info.sarHeight);
-
if (
this->framesToBeEncoded ==
0 && info.frameCount > (
int)seek)
-
this->framesToBeEncoded = info.frameCount - seek;
-
param->totalFrames =
this->framesToBeEncoded;
-
-
/* Force CFR until we have support for VFR */
-
info.timebaseNum = param->fpsDenom;
-
info.timebaseDenom = param->fpsNum;
-
-
if (api->param_apply_profile(param, profile))
-
return
true;
-
-
if (param->logLevel >= X265_LOG_INFO)
-
{
-
char buf[
128];
-
int p =
sprintf(buf,
"%dx%d fps %d/%d %sp%d", param->sourceWidth, param->sourceHeight,
-
param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info.depth);
-
-
int width, height;
-
getParamAspectRatio(param, width, height);
-
if (width && height)
-
p +=
sprintf(buf + p,
" sar %d:%d", width, height);
-
-
if (framesToBeEncoded <=
0 || info.frameCount <=
0)
-
strcpy(buf + p,
" unknown frame count");
-
else
-
sprintf(buf + p,
" frames %u - %d of %d",
this->seek,
this->seek +
this->framesToBeEncoded -
1, info.frameCount);
-
-
general_log(param, input->getName(), X265_LOG_INFO,
"%s\n", buf);
-
}
-
-
this->input->startReader();
-
-
if (reconfn)
-
{
-
if (reconFileBitDepth ==
0)
-
reconFileBitDepth = param->internalBitDepth;
-
this->recon = ReconFile::open(reconfn, param->sourceWidth, param->sourceHeight, reconFileBitDepth,
-
param->fpsNum, param->fpsDenom, param->internalCsp);
-
if (
this->recon->isFail())
-
{
-
x265_log(param, X265_LOG_WARNING,
"unable to write reconstructed outputs file\n");
-
this->recon->release();
-
this->recon =
0;
-
}
-
else
-
general_log(param,
this->recon->getName(), X265_LOG_INFO,
-
"reconstructed images %dx%d fps %d/%d %s\n",
-
param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,
-
x265_source_csp_names[param->internalCsp]);
-
}
-
-
this->output = OutputFile::open(outputfn, info);
-
if (
this->output->isFail())
-
{
-
x265_log(param, X265_LOG_ERROR,
"failed to open output file <%s> for writing\n", outputfn);
-
return
true;
-
}
-
general_log(param,
this->output->getName(), X265_LOG_INFO,
"output file: %s\n", outputfn);
-
return
false;
//完成后返回false
-
}
3.3、encoder_open()函数
encoder_open(param)的主要功能是打印编码器的配置信息,直接调用api.cpp中的x265_encoder *x265_encoder_open(x265_param *p),该函数中调用了x265_print_params(param)用以打印编码器配置信息,如下图所示:
对应的代码如下:
-
x265_encoder *x265_encoder_open(x265_param *p)
-
{
-
if (!p)
-
return
NULL;
-
-
#if _MSC_VER
-
#pragma warning(disable: 4127) // conditional expression is constant, yes I know
-
#endif
-
-
#if HIGH_BIT_DEPTH
-
if (X265_DEPTH ==
12)
-
x265_log(p, X265_LOG_WARNING,
"Main12 is HIGHLY experimental, do not use!\n");
-
else
if (X265_DEPTH !=
10 && X265_DEPTH !=
12)
-
#
else
-
if (X265_DEPTH !=
8)
-
#endif
-
{
-
x265_log(p, X265_LOG_ERROR,
"Build error, internal bit depth mismatch\n");
-
return
NULL;
-
}
-
-
Encoder* encoder =
NULL;
-
x265_param* param = PARAM_NS::x265_param_alloc();
-
x265_param* latestParam = PARAM_NS::x265_param_alloc();
-
if (!param || !latestParam)
-
goto fail;
-
-
memcpy(param, p,
sizeof(x265_param));
-
x265_log(param, X265_LOG_INFO,
"HEVC encoder version %s\n", PFX(version_str));
-
x265_log(param, X265_LOG_INFO,
"build info %s\n", PFX(build_info_str));
-
-
x265_setup_primitives(param);
-
-
if (x265_check_params(param))
-
goto fail;
-
-
if (x265_set_globals(param))
-
goto fail;
-
-
encoder =
new Encoder;
-
if (!param->rc.bEnableSlowFirstPass)
-
PARAM_NS::x265_param_apply_fastfirstpass(param);
-
-
// may change params for auto-detect, etc
-
encoder->configure(param);
-
// may change rate control and CPB params
-
if (!enforceLevel(*param, encoder->m_vps))
-
goto fail;
-
-
// will detect and set profile/tier/level in VPS
-
determineLevel(*param, encoder->m_vps);
-
-
if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc == Profile::NONE)
-
{
-
x265_log(param, X265_LOG_INFO,
"non-conformant bitstreams not allowed (--allow-non-conformance)\n");
-
goto fail;
-
}
-
-
encoder->create();
-
encoder->m_latestParam = latestParam;
-
memcpy(latestParam, param,
sizeof(x265_param));
-
if (encoder->m_aborted)
-
goto fail;
-
-
x265_print_params(param);
//打印参数
-
return encoder;
-
-
fail:
-
delete encoder;
-
PARAM_NS::x265_param_free(param);
-
PARAM_NS::x265_param_free(latestParam);
-
return
NULL;
-
}
3.4、encoder_headers()函数
-
int x265_encoder_headers(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal)
-
{
-
if (pp_nal && enc)
-
{
-
Encoder *encoder =
static_cast<Encoder*>(enc);
-
Entropy sbacCoder;
-
Bitstream bs;
-
encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs);
//get Stream Headers
-
*pp_nal = &encoder->m_nalList.m_nal[
0];
-
if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
-
return encoder->m_nalList.m_occupancy;
-
}
-
-
return
-1;
-
}
3.5、encoder_encode()函数
-
int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture *pic_out)
-
{
-
if (!enc)
-
return
-1;
-
-
Encoder *encoder =
static_cast<Encoder*>(enc);
-
int numEncoded;
-
-
// While flushing, we cannot return 0 until the entire stream is flushed
-
do
-
{
-
numEncoded = encoder->encode(pic_in, pic_out);
//==========进入编码函数
-
}
-
while (numEncoded ==
0 && !pic_in && encoder->m_numDelayedPic);
-
-
// do not allow reuse of these buffers for more than one picture. The
-
// encoder now owns these analysisData buffers.
-
if (pic_in)
-
{
-
pic_in->analysisData.intraData =
NULL;
-
pic_in->analysisData.interData =
NULL;
-
}
-
-
if (pp_nal && numEncoded >
0)
-
{
-
*pp_nal = &encoder->m_nalList.m_nal[
0];
-
if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
-
}
-
else
if (pi_nal)
-
*pi_nal =
0;
-
-
return numEncoded;
-
}
3.6、encoder_close()函数
-
void x265_encoder_close(x265_encoder *enc)
-
{
-
if (enc)
-
{
-
Encoder *encoder =
static_cast<Encoder*>(enc);
-
-
encoder->stopJobs();
-
encoder->printSummary();
//==========打印总结信息
-
encoder->destroy();
-
delete encoder;
-
ATOMIC_DEC(&g_ctuSizeConfigured);
-
}
-
}
到这儿,main()函数的主要功能就分析完毕了。
转载出处:https://blog.csdn.net/FRD2009041510/article/details/51115455
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/ck_htmledit_views-e2445db1a8.css">
<div class="htmledit_views">
x265探索与研究(六):main()函数
x265源码的入口函数是main(),本文分析main()的主要功能。首先给出main()函数的功能及其代码结构;其次给出main()函数源码以及分析;最后给出main()函数中的主要功能函数的具体功能。
1、main()函数的功能及其代码结构
main()函数的主要功能是解析参数并进行编码的一些准备工作,调用了如下几个重要的函数:
(1)cliopt.parse()函数:解析参数
(2)api->encoder_open()函数:打开编码器配置
(3)api->encoder_headers()函数:设置NAL相关信息
(4)api->encoder_encode()函数:进入编码函数
(5)api->encoder_close()函数:结束编码并进行总结
注:encoder_open()函数、encoder_headers()函数、encoder_encode()函数与encoder_close()函数均位于api.app中。
对应的函数关系图如下图所示:
2、main()函数源码以及分析
main()函数的源码分析如下代码中的注释,代码如下:
-
/*=============================================================*/
-
/*
-
====== Analysed by: RuiDong Fang
-
====== Csdn Blog: http://blog.csdn.net/frd2009041510
-
====== Date: 2016.04.10
-
====== Funtion: x265的入口main()函数
-
*/
-
/*=============================================================*/
-
/* CLI return codes:
-
*
-
* 0 - encode successful
-
* 1 - unable to parse command line
-
* 2 - unable to open encoder
-
* 3 - unable to generate stream headers
-
* 4 - encoder abort
-
* 5 - unable to open csv file
-
*
-
*/
-
int main(int argc, char **argv) //主函数入口
-
{
-
#if HAVE_VLD
-
// This uses Microsoft's proprietary WCHAR type, but this only builds on Windows to start with
-
VLDSetReportOptions(VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE,
L"x265_leaks.txt");
-
#endif
-
PROFILE_INIT();
-
THREAD_NAME(
"API",
0);
-
-
GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);
//获取控制台窗口
-
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
-
-
ReconPlay* reconPlay =
NULL;
-
CLIOptions cliopt;
-
-
if (cliopt.parse(argc, argv))
//==========分析参数,对编码器的参数进行设定,打开文件
-
{
-
cliopt.destroy();
-
if (cliopt.api)
-
cliopt.api->param_free(cliopt.param);
-
exit(
1);
-
}
-
-
x265_param* param = cliopt.param;
-
const x265_api* api = cliopt.api;
-
-
/* This allows muxers to modify bitstream format */
-
cliopt.output->setParam(param);
-
-
if (cliopt.reconPlayCmd)
-
reconPlay =
new ReconPlay(cliopt.reconPlayCmd, *param);
-
-
/* note: we could try to acquire a different libx265 API here based on
-
* the profile found during option parsing, but it must be done before
-
* opening an encoder */
-
-
x265_encoder *encoder = api->encoder_open(param);
//==========encoder_open()函数,打印编码器配置
-
if (!encoder)
//若打不开编码器配置,提示错误
-
{
-
x265_log(param, X265_LOG_ERROR,
"failed to open encoder\n");
-
cliopt.destroy();
-
api->param_free(param);
-
api->cleanup();
-
exit(
2);
-
}
-
-
/* get the encoder parameters post-initialization */
-
api->encoder_parameters(encoder, param);
-
-
if (cliopt.csvfn)
-
{
-
cliopt.csvfpt = x265_csvlog_open(*api, *param, cliopt.csvfn, cliopt.csvLogLevel);
-
if (!cliopt.csvfpt)
-
{
-
x265_log(param, X265_LOG_ERROR,
"Unable to open CSV log file <%s>, aborting\n", cliopt.csvfn);
-
cliopt.destroy();
-
if (cliopt.api)
-
cliopt.api->param_free(cliopt.param);
-
exit(
5);
-
}
-
}
-
-
/* Control-C handler */
-
//当键入Ctrl-C的时候,当前执行程序调用指针函数sigint_handler 执行完后,再返回原来执行的地方接着往下走。
-
if (signal(SIGINT, sigint_handler) == SIG_ERR)
-
x265_log(param, X265_LOG_ERROR,
"Unable to register CTRL+C handler: %s\n", strerror(errno));
-
-
x265_picture pic_orig, pic_out;
//定义x265的输入pic_orig和输出pic_out
-
x265_picture *pic_in = &pic_orig;
//获取x265的输入pic_orig的地址
-
-
/* Allocate recon picture if analysisMode is enabled */
-
std::priority_queue<
int64_t>* pts_queue = cliopt.output->needPTS() ?
new
std::priority_queue<
int64_t>() :
NULL;
-
x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode || pts_queue || reconPlay || cliopt.csvLogLevel) ? &pic_out :
NULL;
-
-
uint32_t inFrameCount =
0;
//输入的帧数
-
uint32_t outFrameCount =
0;
//输出的帧数
-
-
x265_nal *p_nal;
-
x265_stats stats;
-
uint32_t nal;
-
int16_t *errorBuf =
NULL;
-
int ret =
0;
-
-
if (!param->bRepeatHeaders)
-
{
-
if (api->encoder_headers(encoder, &p_nal, &nal) <
0)
//==========encoder_headers函数
-
{
-
x265_log(param, X265_LOG_ERROR,
"Failure generating stream headers\n");
-
ret =
3;
-
goto fail;
-
}
-
else
-
cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
-
}
-
-
api->picture_init(param, pic_in);
-
-
if (cliopt.bDither)
-
{
-
errorBuf = X265_MALLOC(
int16_t, param->sourceWidth +
1);
-
if (errorBuf)
-
memset(errorBuf,
0, (param->sourceWidth +
1) *
sizeof(
int16_t));
-
else
-
cliopt.bDither =
false;
-
}
-
-
// main encoder loop(编码主循环)
-
while (pic_in && !b_ctrl_c)
-
{
-
pic_orig.poc = inFrameCount;
-
if (cliopt.qpfile)
-
{
-
if (!cliopt.parseQPFile(pic_orig))
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"can't parse qpfile for frame %d\n", pic_in->poc);
-
fclose(cliopt.qpfile);
-
cliopt.qpfile =
NULL;
-
}
-
}
-
-
//当输入帧将要全部编码且输入的帧数大于或等于将要编码的帧数
-
if (cliopt.framesToBeEncoded && inFrameCount >= cliopt.framesToBeEncoded)
-
pic_in =
NULL;
-
else
if (cliopt.input->readPicture(pic_orig))
//每读入一帧
-
inFrameCount++;
//输入的帧数自加1
-
else
-
pic_in =
NULL;
-
-
if (pic_in)
-
{
-
if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)
-
{
-
x265_dither_image(*api, *pic_in, cliopt.input->getWidth(), cliopt.input->getHeight(), errorBuf, param->internalBitDepth);
-
pic_in->bitDepth = param->internalBitDepth;
-
}
-
/* Overwrite PTS */
-
pic_in->pts = pic_in->poc;
-
}
-
//进行编码的入口函数,读入24帧后才开始编码
-
int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon);
//==========encoder_encode()函数,numEncoded是将要编码的帧数
-
if (numEncoded <
0)
-
{
-
b_ctrl_c =
1;
-
ret =
4;
-
break;
-
}
-
-
if (reconPlay && numEncoded)
-
reconPlay->writePicture(*pic_recon);
-
-
outFrameCount += numEncoded;
-
-
if (numEncoded && pic_recon && cliopt.recon)
-
cliopt.recon->writePicture(pic_out);
-
if (nal)
-
{
-
cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
-
if (pts_queue)
-
{
-
pts_queue->push(-pic_out.pts);
-
if (pts_queue->size() >
2)
-
pts_queue->pop();
-
}
-
}
-
-
cliopt.printStatus(outFrameCount);
//打印编码帧的具体信息
-
if (numEncoded && cliopt.csvLogLevel)
-
x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
-
}
-
-
/* Flush the encoder */
-
/*功能:前面读入24帧后才开始编码,此处其实就是处理对应的倒数的24帧,将其存储*/
-
while (!b_ctrl_c)
//退出上一个大循环后且没有按下Ctrl+C,代码继续执行
-
{
-
//==========encoder_encode()函数
-
int numEncoded = api->encoder_encode(encoder, &p_nal, &nal,
NULL, pic_recon);
-
if (numEncoded <
0)
-
{
-
ret =
4;
-
break;
-
}
-
-
if (reconPlay && numEncoded)
-
reconPlay->writePicture(*pic_recon);
-
-
outFrameCount += numEncoded;
-
if (numEncoded && pic_recon && cliopt.recon)
-
cliopt.recon->writePicture(pic_out);
-
if (nal)
-
{
-
cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
-
if (pts_queue)
-
{
-
pts_queue->push(-pic_out.pts);
-
if (pts_queue->size() >
2)
-
pts_queue->pop();
-
}
-
}
-
-
cliopt.printStatus(outFrameCount);
-
if (numEncoded && cliopt.csvLogLevel)
-
x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
-
-
if (!numEncoded)
-
break;
-
}
-
-
/* clear progress report */
-
if (cliopt.bProgress)
-
fprintf(
stderr,
"%*s\r",
80,
" ");
-
-
fail:
-
-
delete reconPlay;
-
-
api->encoder_get_stats(encoder, &stats,
sizeof(stats));
-
if (cliopt.csvfpt && !b_ctrl_c)
-
x265_csvlog_encode(cliopt.csvfpt, *api, *param, stats, cliopt.csvLogLevel, argc, argv);
-
api->encoder_close(encoder);
//==========encoder_close()函数
-
-
int64_t second_largest_pts =
0;
-
int64_t largest_pts =
0;
-
if (pts_queue && pts_queue->size() >=
2)
-
{
-
second_largest_pts = -pts_queue->top();
-
pts_queue->pop();
-
largest_pts = -pts_queue->top();
-
pts_queue->pop();
-
delete pts_queue;
-
pts_queue =
NULL;
-
}
-
cliopt.output->closeFile(largest_pts, second_largest_pts);
-
-
if (b_ctrl_c)
//按下Ctrl+C,直接退出
-
general_log(param,
NULL, X265_LOG_INFO,
"aborted at input frame %d, output frame %d\n",
-
cliopt.seek + inFrameCount, stats.encodedPictureCount);
-
-
api->cleanup();
/* Free library singletons */
-
-
cliopt.destroy();
-
-
api->param_free(param);
-
-
X265_FREE(errorBuf);
-
-
SetConsoleTitle(orgConsoleTitle);
//设置控制窗口标题
-
SetThreadExecutionState(ES_CONTINUOUS);
-
-
#if HAVE_VLD
-
assert(VLDReportLeaks() ==
0);
-
#endif
-
-
return ret;
-
}
3、main()函数中的部分功能函数的具体功能
3.1、GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);
GetConsoleTitle的主要功能是获取控制台窗口,其中orgConsoleTitle指向一个缓冲区指针以接收包含标题的字符串;CONSOLE_TITLE_SIZE)是由orgConsoleTitle指向的缓冲区大小。如果函数成功,则返回值是以字符为单位的长度控制台窗口的标题;如果该函数失败,则返回值为零。要获取错误信息,可以调用GetLastError 。
3.2、cliopt.parse(argc, argv)
cliopt.parse(argc, argv)的主要功能是分析参数,直接调用x265.cpp中的bool CLIOptions::parse(int argc, char **argv)函数,该函数会打印输入视频的分辨率、帧率、视频格式、所要编码的帧数目以及输出文件名称等,如下图所示:
对应的代码如下:
-
bool CLIOptions::parse(
int argc,
char **argv)
-
{
-
bool bError =
false;
-
int bShowHelp =
false;
-
int inputBitDepth =
8;
-
int outputBitDepth =
0;
-
int reconFileBitDepth =
0;
-
const
char *inputfn =
NULL;
-
const
char *reconfn =
NULL;
-
const
char *outputfn =
NULL;
-
const
char *preset =
NULL;
-
const
char *tune =
NULL;
-
const
char *profile =
NULL;
-
-
if (argc <=
1)
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"No input file. Run x265 --help for a list of options.\n");
-
return
true;
-
}
-
-
/* Presets are applied before all other options. */
-
for (optind =
0;; )
-
{
-
int c = getopt_long(argc, argv, short_options, long_options,
NULL);
-
if (c ==
-1)
-
break;
-
else
if (c ==
'p')
-
preset = optarg;
-
else
if (c ==
't')
-
tune = optarg;
-
else
if (c ==
'D')
-
outputBitDepth = atoi(optarg);
-
else
if (c ==
'P')
-
profile = optarg;
-
else
if (c ==
'?')
-
bShowHelp =
true;
-
}
-
-
if (!outputBitDepth && profile)
-
{
-
/* try to derive the output bit depth from the requested profile */
-
if (
strstr(profile,
"10"))
-
outputBitDepth =
10;
-
else
if (
strstr(profile,
"12"))
-
outputBitDepth =
12;
-
else
-
outputBitDepth =
8;
-
}
-
-
api = x265_api_get(outputBitDepth);
-
if (!api)
-
{
-
x265_log(
NULL, X265_LOG_WARNING,
"falling back to default bit-depth\n");
-
api = x265_api_get(
0);
-
}
-
-
param = api->param_alloc();
-
if (!param)
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"param alloc failed\n");
-
return
true;
-
}
-
-
if (api->param_default_preset(param, preset, tune) <
0)
-
{
-
x265_log(
NULL, X265_LOG_ERROR,
"preset or tune unrecognized\n");
-
return
true;
-
}
-
-
if (bShowHelp)
-
{
-
printVersion(param, api);
-
showHelp(param);
-
}
-
-
for (optind =
0;; )
-
{
-
int long_options_index =
-1;
-
int c = getopt_long(argc, argv, short_options, long_options, &long_options_index);
-
if (c ==
-1)
-
break;
-
-
switch (c)
-
{
-
case
'h':
-
printVersion(param, api);
-
showHelp(param);
-
break;
-
-
case
'V':
-
printVersion(param, api);
-
x265_report_simd(param);
-
exit(
0);
-
-
default:
-
if (long_options_index <
0 && c >
0)
-
{
-
for (
size_t i =
0; i <
sizeof(long_options) /
sizeof(long_options[
0]); i++)
-
{
-
if (long_options[i].val == c)
-
{
-
long_options_index = (
int)i;
-
break;
-
}
-
}
-
-
if (long_options_index <
0)
-
{
-
/* getopt_long might have already printed an error message */
-
if (c !=
63)
-
x265_log(
NULL, X265_LOG_WARNING,
"internal error: short option '%c' has no long option\n", c);
-
return
true;
-
}
-
}
-
if (long_options_index <
0)
-
{
-
x265_log(
NULL, X265_LOG_WARNING,
"short option '%c' unrecognized\n", c);
-
return
true;
-
}
-
#define OPT(longname) \
-
else
if (!strcmp(long_options[long_options_index].name, longname))
-
#define OPT2(name1, name2) \
-
else if (!strcmp(long_options[long_options_index].name, name1) || \
-
!strcmp(long_options[long_options_index].name, name2))
-
-
if (
0) ;
-
OPT2(
"frame-skip",
"seek")
this->seek = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"frames")
this->framesToBeEncoded = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"csv")
this->csvfn = optarg;
-
OPT(
"csv-log-level")
this->csvLogLevel = x265_atoi(optarg, bError);
-
OPT(
"no-progress")
this->bProgress =
false;
-
OPT(
"output") outputfn = optarg;
-
OPT(
"input") inputfn = optarg;
-
OPT(
"recon") reconfn = optarg;
-
OPT(
"input-depth") inputBitDepth = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"dither")
this->bDither =
true;
-
OPT(
"recon-depth") reconFileBitDepth = (
uint32_t)x265_atoi(optarg, bError);
-
OPT(
"y4m")
this->bForceY4m =
true;
-
OPT(
"profile")
/* handled above */;
-
OPT(
"preset")
/* handled above */;
-
OPT(
"tune")
/* handled above */;
-
OPT(
"output-depth")
/* handled above */;
-
OPT(
"recon-y4m-exec") reconPlayCmd = optarg;
-
OPT(
"qpfile")
-
{
-
this->qpfile = fopen(optarg,
"rb");
-
if (!
this->qpfile)
-
{
-
x265_log(param, X265_LOG_ERROR,
"%s qpfile not found or error in opening qp file\n", optarg);
-
return
false;
-
}
-
}
-
else
-
bError |= !!api->param_parse(param, long_options[long_options_index].name, optarg);
-
-
if (bError)
-
{
-
const
char *name = long_options_index >
0 ? long_options[long_options_index].name : argv[optind -
2];
-
x265_log(
NULL, X265_LOG_ERROR,
"invalid argument: %s = %s\n", name, optarg);
-
return
true;
-
}
-
#undef OPT
-
}
-
}
-
-
if (optind < argc && !inputfn)
-
inputfn = argv[optind++];
-
if (optind < argc && !outputfn)
-
outputfn = argv[optind++];
-
if (optind < argc)
-
{
-
x265_log(param, X265_LOG_WARNING,
"extra unused command arguments given <%s>\n", argv[optind]);
-
return
true;
-
}
-
-
if (argc <=
1)
-
{
-
api->param_default(param);
-
printVersion(param, api);
-
showHelp(param);
-
}
-
-
if (!inputfn || !outputfn)
-
{
-
x265_log(param, X265_LOG_ERROR,
"input or output file not specified, try --help for help\n");
-
return
true;
-
}
-
-
if (param->internalBitDepth != api->bit_depth)
-
{
-
x265_log(param, X265_LOG_ERROR,
"Only bit depths of %d are supported in this build\n", api->bit_depth);
-
return
true;
-
}
-
-
InputFileInfo info;
-
info.filename = inputfn;
-
info.depth = inputBitDepth;
-
info.csp = param->internalCsp;
-
info.width = param->sourceWidth;
-
info.height = param->sourceHeight;
-
info.fpsNum = param->fpsNum;
-
info.fpsDenom = param->fpsDenom;
-
info.sarWidth = param->vui.sarWidth;
-
info.sarHeight = param->vui.sarHeight;
-
info.skipFrames = seek;
-
info.frameCount =
0;
-
getParamAspectRatio(param, info.sarWidth, info.sarHeight);
-
-
this->input = InputFile::open(info,
this->bForceY4m);
-
if (!
this->input ||
this->input->isFail())
-
{
-
x265_log(param, X265_LOG_ERROR,
"unable to open input file <%s>\n", inputfn);
-
return
true;
-
}
-
-
if (info.depth <
8 || info.depth >
16)
-
{
-
x265_log(param, X265_LOG_ERROR,
"Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);
-
return
true;
-
}
-
-
/* Unconditionally accept height/width/csp from file info */
-
param->sourceWidth = info.width;
-
param->sourceHeight = info.height;
-
param->internalCsp = info.csp;
-
-
/* Accept fps and sar from file info if not specified by user */
-
if (param->fpsDenom ==
0 || param->fpsNum ==
0)
-
{
-
param->fpsDenom = info.fpsDenom;
-
param->fpsNum = info.fpsNum;
-
}
-
if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)
-
setParamAspectRatio(param, info.sarWidth, info.sarHeight);
-
if (
this->framesToBeEncoded ==
0 && info.frameCount > (
int)seek)
-
this->framesToBeEncoded = info.frameCount - seek;
-
param->totalFrames =
this->framesToBeEncoded;
-
-
/* Force CFR until we have support for VFR */
-
info.timebaseNum = param->fpsDenom;
-
info.timebaseDenom = param->fpsNum;
-
-
if (api->param_apply_profile(param, profile))
-
return
true;
-
-
if (param->logLevel >= X265_LOG_INFO)
-
{
-
char buf[
128];
-
int p =
sprintf(buf,
"%dx%d fps %d/%d %sp%d", param->sourceWidth, param->sourceHeight,
-
param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info.depth);
-
-
int width, height;
-
getParamAspectRatio(param, width, height);
-
if (width && height)
-
p +=
sprintf(buf + p,
" sar %d:%d", width, height);
-
-
if (framesToBeEncoded <=
0 || info.frameCount <=
0)
-
strcpy(buf + p,
" unknown frame count");
-
else
-
sprintf(buf + p,
" frames %u - %d of %d",
this->seek,
this->seek +
this->framesToBeEncoded -
1, info.frameCount);
-
-
general_log(param, input->getName(), X265_LOG_INFO,
"%s\n", buf);
-
}
-
-
this->input->startReader();
-
-
if (reconfn)
-
{
-
if (reconFileBitDepth ==
0)
-
reconFileBitDepth = param->internalBitDepth;
-
this->recon = ReconFile::open(reconfn, param->sourceWidth, param->sourceHeight, reconFileBitDepth,
-
param->fpsNum, param->fpsDenom, param->internalCsp);
-
if (
this->recon->isFail())
-
{
-
x265_log(param, X265_LOG_WARNING,
"unable to write reconstructed outputs file\n");
-
this->recon->release();
-
this->recon =
0;
-
}
-
else
-
general_log(param,
this->recon->getName(), X265_LOG_INFO,
-
"reconstructed images %dx%d fps %d/%d %s\n",
-
param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,
-
x265_source_csp_names[param->internalCsp]);
-
}
-
-
this->output = OutputFile::open(outputfn, info);
-
if (
this->output->isFail())
-
{
-
x265_log(param, X265_LOG_ERROR,
"failed to open output file <%s> for writing\n", outputfn);
-
return
true;
-
}
-
general_log(param,
this->output->getName(), X265_LOG_INFO,
"output file: %s\n", outputfn);
-
return
false;
//完成后返回false
-
}
3.3、encoder_open()函数
encoder_open(param)的主要功能是打印编码器的配置信息,直接调用api.cpp中的x265_encoder *x265_encoder_open(x265_param *p),该函数中调用了x265_print_params(param)用以打印编码器配置信息,如下图所示:
对应的代码如下:
-
x265_encoder *x265_encoder_open(x265_param *p)
-
{
-
if (!p)
-
return
NULL;
-
-
#if _MSC_VER
-
#pragma warning(disable: 4127) // conditional expression is constant, yes I know
-
#endif
-
-
#if HIGH_BIT_DEPTH
-
if (X265_DEPTH ==
12)
-
x265_log(p, X265_LOG_WARNING,
"Main12 is HIGHLY experimental, do not use!\n");
-
else
if (X265_DEPTH !=
10 && X265_DEPTH !=
12)
-
#
else
-
if (X265_DEPTH !=
8)
-
#endif
-
{
-
x265_log(p, X265_LOG_ERROR,
"Build error, internal bit depth mismatch\n");
-
return
NULL;
-
}
-
-
Encoder* encoder =
NULL;
-
x265_param* param = PARAM_NS::x265_param_alloc();
-
x265_param* latestParam = PARAM_NS::x265_param_alloc();
-
if (!param || !latestParam)
-
goto fail;
-
-
memcpy(param, p,
sizeof(x265_param));
-
x265_log(param, X265_LOG_INFO,
"HEVC encoder version %s\n", PFX(version_str));
-
x265_log(param, X265_LOG_INFO,
"build info %s\n", PFX(build_info_str));
-
-
x265_setup_primitives(param);
-
-
if (x265_check_params(param))
-
goto fail;
-
-
if (x265_set_globals(param))
-
goto fail;
-
-
encoder =
new Encoder;
-
if (!param->rc.bEnableSlowFirstPass)
-
PARAM_NS::x265_param_apply_fastfirstpass(param);
-
-
// may change params for auto-detect, etc
-
encoder->configure(param);
-
// may change rate control and CPB params
-
if (!enforceLevel(*param, encoder->m_vps))
-
goto fail;
-
-
// will detect and set profile/tier/level in VPS
-
determineLevel(*param, encoder->m_vps);
-
-
if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc == Profile::NONE)
-
{
-
x265_log(param, X265_LOG_INFO,
"non-conformant bitstreams not allowed (--allow-non-conformance)\n");
-
goto fail;
-
}
-
-
encoder->create();
-
encoder->m_latestParam = latestParam;
-
memcpy(latestParam, param,
sizeof(x265_param));
-
if (encoder->m_aborted)
-
goto fail;
-
-
x265_print_params(param);
//打印参数
-
return encoder;
-
-
fail:
-
delete encoder;
-
PARAM_NS::x265_param_free(param);
-
PARAM_NS::x265_param_free(latestParam);
-
return
NULL;
-
}
3.4、encoder_headers()函数
-
int x265_encoder_headers(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal)
-
{
-
if (pp_nal && enc)
-
{
-
Encoder *encoder =
static_cast<Encoder*>(enc);
-
Entropy sbacCoder;
-
Bitstream bs;
-
encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs);
//get Stream Headers
-
*pp_nal = &encoder->m_nalList.m_nal[
0];
-
if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
-
return encoder->m_nalList.m_occupancy;
-
}
-
-
return
-1;
-
}
3.5、encoder_encode()函数
-
int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture *pic_out)
-
{
-
if (!enc)
-
return
-1;
-
-
Encoder *encoder =
static_cast<Encoder*>(enc);
-
int numEncoded;
-
-
// While flushing, we cannot return 0 until the entire stream is flushed
-
do
-
{
-
numEncoded = encoder->encode(pic_in, pic_out);
//==========进入编码函数
-
}
-
while (numEncoded ==
0 && !pic_in && encoder->m_numDelayedPic);
-
-
// do not allow reuse of these buffers for more than one picture. The
-
// encoder now owns these analysisData buffers.
-
if (pic_in)
-
{
-
pic_in->analysisData.intraData =
NULL;
-
pic_in->analysisData.interData =
NULL;
-
}
-
-
if (pp_nal && numEncoded >
0)
-
{
-
*pp_nal = &encoder->m_nalList.m_nal[
0];
-
if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
-
}
-
else
if (pi_nal)
-
*pi_nal =
0;
-
-
return numEncoded;
-
}
3.6、encoder_close()函数
-
void x265_encoder_close(x265_encoder *enc)
-
{
-
if (enc)
-
{
-
Encoder *encoder =
static_cast<Encoder*>(enc);
-
-
encoder->stopJobs();
-
encoder->printSummary();
//==========打印总结信息
-
encoder->destroy();
-
delete encoder;
-
ATOMIC_DEC(&g_ctuSizeConfigured);
-
}
-
}
到这儿,main()函数的主要功能就分析完毕了。
转载出处:https://blog.csdn.net/FRD2009041510/article/details/51115455