x265探索与研究(六):main()函数

版权声明:本文为博主原创文章,转载请标注转载网址:http://blog.csdn.net/frd2009041510 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()函数中的主要功能函数的具体功能。

1main()函数的功能及其代码结构

        main()函数的主要功能是解析参数并进行编码的一些准备工作,调用了如下几个重要的函数:

1cliopt.parse()函数:解析参数

2api->encoder_open()函数:打开编码器配置

3api->encoder_headers()函数:设置NAL相关信息

4api->encoder_encode()函数:进入编码函数

5api->encoder_close()函数:结束编码并进行总结

注:encoder_open()函数、encoder_headers()函数、encoder_encode()函数与encoder_close()函数均位于api.app中。

        对应的函数关系图如下图所示:




2main()函数源码以及分析

        

        main()函数的源码分析如下代码中的注释,代码如下:


   
   
  1. /*=============================================================*/
  2. /*
  3. ====== Analysed by: RuiDong Fang
  4. ====== Csdn Blog: http://blog.csdn.net/frd2009041510
  5. ====== Date: 2016.04.10
  6. ====== Funtion: x265的入口main()函数
  7. */
  8. /*=============================================================*/
  9. /* CLI return codes:
  10. *
  11. * 0 - encode successful
  12. * 1 - unable to parse command line
  13. * 2 - unable to open encoder
  14. * 3 - unable to generate stream headers
  15. * 4 - encoder abort
  16. * 5 - unable to open csv file
  17. *
  18. */
  19. int main(int argc, char **argv) //主函数入口
  20. {
  21. #if HAVE_VLD
  22. // This uses Microsoft's proprietary WCHAR type, but this only builds on Windows to start with
  23. VLDSetReportOptions(VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE, L"x265_leaks.txt");
  24. #endif
  25. PROFILE_INIT();
  26. THREAD_NAME( "API", 0);
  27. GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE); //获取控制台窗口
  28. SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
  29. ReconPlay* reconPlay = NULL;
  30. CLIOptions cliopt;
  31. if (cliopt.parse(argc, argv)) //==========分析参数,对编码器的参数进行设定,打开文件
  32. {
  33. cliopt.destroy();
  34. if (cliopt.api)
  35. cliopt.api->param_free(cliopt.param);
  36. exit( 1);
  37. }
  38. x265_param* param = cliopt.param;
  39. const x265_api* api = cliopt.api;
  40. /* This allows muxers to modify bitstream format */
  41. cliopt.output->setParam(param);
  42. if (cliopt.reconPlayCmd)
  43. reconPlay = new ReconPlay(cliopt.reconPlayCmd, *param);
  44. /* note: we could try to acquire a different libx265 API here based on
  45. * the profile found during option parsing, but it must be done before
  46. * opening an encoder */
  47. x265_encoder *encoder = api->encoder_open(param); //==========encoder_open()函数,打印编码器配置
  48. if (!encoder) //若打不开编码器配置,提示错误
  49. {
  50. x265_log(param, X265_LOG_ERROR, "failed to open encoder\n");
  51. cliopt.destroy();
  52. api->param_free(param);
  53. api->cleanup();
  54. exit( 2);
  55. }
  56. /* get the encoder parameters post-initialization */
  57. api->encoder_parameters(encoder, param);
  58. if (cliopt.csvfn)
  59. {
  60. cliopt.csvfpt = x265_csvlog_open(*api, *param, cliopt.csvfn, cliopt.csvLogLevel);
  61. if (!cliopt.csvfpt)
  62. {
  63. x265_log(param, X265_LOG_ERROR, "Unable to open CSV log file <%s>, aborting\n", cliopt.csvfn);
  64. cliopt.destroy();
  65. if (cliopt.api)
  66. cliopt.api->param_free(cliopt.param);
  67. exit( 5);
  68. }
  69. }
  70. /* Control-C handler */
  71. //当键入Ctrl-C的时候,当前执行程序调用指针函数sigint_handler 执行完后,再返回原来执行的地方接着往下走。
  72. if (signal(SIGINT, sigint_handler) == SIG_ERR)
  73. x265_log(param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s\n", strerror(errno));
  74. x265_picture pic_orig, pic_out; //定义x265的输入pic_orig和输出pic_out
  75. x265_picture *pic_in = &pic_orig; //获取x265的输入pic_orig的地址
  76. /* Allocate recon picture if analysisMode is enabled */
  77. std::priority_queue< int64_t>* pts_queue = cliopt.output->needPTS() ? new std::priority_queue< int64_t>() : NULL;
  78. x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode || pts_queue || reconPlay || cliopt.csvLogLevel) ? &pic_out : NULL;
  79. uint32_t inFrameCount = 0; //输入的帧数
  80. uint32_t outFrameCount = 0; //输出的帧数
  81. x265_nal *p_nal;
  82. x265_stats stats;
  83. uint32_t nal;
  84. int16_t *errorBuf = NULL;
  85. int ret = 0;
  86. if (!param->bRepeatHeaders)
  87. {
  88. if (api->encoder_headers(encoder, &p_nal, &nal) < 0) //==========encoder_headers函数
  89. {
  90. x265_log(param, X265_LOG_ERROR, "Failure generating stream headers\n");
  91. ret = 3;
  92. goto fail;
  93. }
  94. else
  95. cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
  96. }
  97. api->picture_init(param, pic_in);
  98. if (cliopt.bDither)
  99. {
  100. errorBuf = X265_MALLOC( int16_t, param->sourceWidth + 1);
  101. if (errorBuf)
  102. memset(errorBuf, 0, (param->sourceWidth + 1) * sizeof( int16_t));
  103. else
  104. cliopt.bDither = false;
  105. }
  106. // main encoder loop(编码主循环)
  107. while (pic_in && !b_ctrl_c)
  108. {
  109. pic_orig.poc = inFrameCount;
  110. if (cliopt.qpfile)
  111. {
  112. if (!cliopt.parseQPFile(pic_orig))
  113. {
  114. x265_log( NULL, X265_LOG_ERROR, "can't parse qpfile for frame %d\n", pic_in->poc);
  115. fclose(cliopt.qpfile);
  116. cliopt.qpfile = NULL;
  117. }
  118. }
  119. //当输入帧将要全部编码且输入的帧数大于或等于将要编码的帧数
  120. if (cliopt.framesToBeEncoded && inFrameCount >= cliopt.framesToBeEncoded)
  121. pic_in = NULL;
  122. else if (cliopt.input->readPicture(pic_orig)) //每读入一帧
  123. inFrameCount++; //输入的帧数自加1
  124. else
  125. pic_in = NULL;
  126. if (pic_in)
  127. {
  128. if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)
  129. {
  130. x265_dither_image(*api, *pic_in, cliopt.input->getWidth(), cliopt.input->getHeight(), errorBuf, param->internalBitDepth);
  131. pic_in->bitDepth = param->internalBitDepth;
  132. }
  133. /* Overwrite PTS */
  134. pic_in->pts = pic_in->poc;
  135. }
  136. //进行编码的入口函数,读入24帧后才开始编码
  137. int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon); //==========encoder_encode()函数,numEncoded是将要编码的帧数
  138. if (numEncoded < 0)
  139. {
  140. b_ctrl_c = 1;
  141. ret = 4;
  142. break;
  143. }
  144. if (reconPlay && numEncoded)
  145. reconPlay->writePicture(*pic_recon);
  146. outFrameCount += numEncoded;
  147. if (numEncoded && pic_recon && cliopt.recon)
  148. cliopt.recon->writePicture(pic_out);
  149. if (nal)
  150. {
  151. cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
  152. if (pts_queue)
  153. {
  154. pts_queue->push(-pic_out.pts);
  155. if (pts_queue->size() > 2)
  156. pts_queue->pop();
  157. }
  158. }
  159. cliopt.printStatus(outFrameCount); //打印编码帧的具体信息
  160. if (numEncoded && cliopt.csvLogLevel)
  161. x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
  162. }
  163. /* Flush the encoder */
  164. /*功能:前面读入24帧后才开始编码,此处其实就是处理对应的倒数的24帧,将其存储*/
  165. while (!b_ctrl_c) //退出上一个大循环后且没有按下Ctrl+C,代码继续执行
  166. {
  167. //==========encoder_encode()函数
  168. int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, NULL, pic_recon);
  169. if (numEncoded < 0)
  170. {
  171. ret = 4;
  172. break;
  173. }
  174. if (reconPlay && numEncoded)
  175. reconPlay->writePicture(*pic_recon);
  176. outFrameCount += numEncoded;
  177. if (numEncoded && pic_recon && cliopt.recon)
  178. cliopt.recon->writePicture(pic_out);
  179. if (nal)
  180. {
  181. cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
  182. if (pts_queue)
  183. {
  184. pts_queue->push(-pic_out.pts);
  185. if (pts_queue->size() > 2)
  186. pts_queue->pop();
  187. }
  188. }
  189. cliopt.printStatus(outFrameCount);
  190. if (numEncoded && cliopt.csvLogLevel)
  191. x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
  192. if (!numEncoded)
  193. break;
  194. }
  195. /* clear progress report */
  196. if (cliopt.bProgress)
  197. fprintf( stderr, "%*s\r", 80, " ");
  198. fail:
  199. delete reconPlay;
  200. api->encoder_get_stats(encoder, &stats, sizeof(stats));
  201. if (cliopt.csvfpt && !b_ctrl_c)
  202. x265_csvlog_encode(cliopt.csvfpt, *api, *param, stats, cliopt.csvLogLevel, argc, argv);
  203. api->encoder_close(encoder); //==========encoder_close()函数
  204. int64_t second_largest_pts = 0;
  205. int64_t largest_pts = 0;
  206. if (pts_queue && pts_queue->size() >= 2)
  207. {
  208. second_largest_pts = -pts_queue->top();
  209. pts_queue->pop();
  210. largest_pts = -pts_queue->top();
  211. pts_queue->pop();
  212. delete pts_queue;
  213. pts_queue = NULL;
  214. }
  215. cliopt.output->closeFile(largest_pts, second_largest_pts);
  216. if (b_ctrl_c) //按下Ctrl+C,直接退出
  217. general_log(param, NULL, X265_LOG_INFO, "aborted at input frame %d, output frame %d\n",
  218. cliopt.seek + inFrameCount, stats.encodedPictureCount);
  219. api->cleanup(); /* Free library singletons */
  220. cliopt.destroy();
  221. api->param_free(param);
  222. X265_FREE(errorBuf);
  223. SetConsoleTitle(orgConsoleTitle); //设置控制窗口标题
  224. SetThreadExecutionState(ES_CONTINUOUS);
  225. #if HAVE_VLD
  226. assert(VLDReportLeaks() == 0);
  227. #endif
  228. return ret;
  229. }




3main()函数中的部分功能函数的具体功能

3.1GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);

        GetConsoleTitle的主要功能是获取控制台窗口,其中orgConsoleTitle指向一个缓冲区指针以接收包含标题的字符串;CONSOLE_TITLE_SIZE)是由orgConsoleTitle指向的缓冲区大小。如果函数成功,则返回值是以字符为单位的长度控制台窗口的标题;如果该函数失败,则返回值为零。要获取错误信息,可以调用GetLastError 。

3.2cliopt.parse(argc, argv)

        cliopt.parse(argc, argv)的主要功能是分析参数,直接调用x265.cpp中的bool CLIOptions::parse(int argc, char **argv)函数,该函数会打印输入视频的分辨率、帧率、视频格式、所要编码的帧数目以及输出文件名称等,如下图所示:

        对应的代码如下:


   
   
  1. bool CLIOptions::parse( int argc, char **argv)
  2. {
  3. bool bError = false;
  4. int bShowHelp = false;
  5. int inputBitDepth = 8;
  6. int outputBitDepth = 0;
  7. int reconFileBitDepth = 0;
  8. const char *inputfn = NULL;
  9. const char *reconfn = NULL;
  10. const char *outputfn = NULL;
  11. const char *preset = NULL;
  12. const char *tune = NULL;
  13. const char *profile = NULL;
  14. if (argc <= 1)
  15. {
  16. x265_log( NULL, X265_LOG_ERROR, "No input file. Run x265 --help for a list of options.\n");
  17. return true;
  18. }
  19. /* Presets are applied before all other options. */
  20. for (optind = 0;; )
  21. {
  22. int c = getopt_long(argc, argv, short_options, long_options, NULL);
  23. if (c == -1)
  24. break;
  25. else if (c == 'p')
  26. preset = optarg;
  27. else if (c == 't')
  28. tune = optarg;
  29. else if (c == 'D')
  30. outputBitDepth = atoi(optarg);
  31. else if (c == 'P')
  32. profile = optarg;
  33. else if (c == '?')
  34. bShowHelp = true;
  35. }
  36. if (!outputBitDepth && profile)
  37. {
  38. /* try to derive the output bit depth from the requested profile */
  39. if ( strstr(profile, "10"))
  40. outputBitDepth = 10;
  41. else if ( strstr(profile, "12"))
  42. outputBitDepth = 12;
  43. else
  44. outputBitDepth = 8;
  45. }
  46. api = x265_api_get(outputBitDepth);
  47. if (!api)
  48. {
  49. x265_log( NULL, X265_LOG_WARNING, "falling back to default bit-depth\n");
  50. api = x265_api_get( 0);
  51. }
  52. param = api->param_alloc();
  53. if (!param)
  54. {
  55. x265_log( NULL, X265_LOG_ERROR, "param alloc failed\n");
  56. return true;
  57. }
  58. if (api->param_default_preset(param, preset, tune) < 0)
  59. {
  60. x265_log( NULL, X265_LOG_ERROR, "preset or tune unrecognized\n");
  61. return true;
  62. }
  63. if (bShowHelp)
  64. {
  65. printVersion(param, api);
  66. showHelp(param);
  67. }
  68. for (optind = 0;; )
  69. {
  70. int long_options_index = -1;
  71. int c = getopt_long(argc, argv, short_options, long_options, &long_options_index);
  72. if (c == -1)
  73. break;
  74. switch (c)
  75. {
  76. case 'h':
  77. printVersion(param, api);
  78. showHelp(param);
  79. break;
  80. case 'V':
  81. printVersion(param, api);
  82. x265_report_simd(param);
  83. exit( 0);
  84. default:
  85. if (long_options_index < 0 && c > 0)
  86. {
  87. for ( size_t i = 0; i < sizeof(long_options) / sizeof(long_options[ 0]); i++)
  88. {
  89. if (long_options[i].val == c)
  90. {
  91. long_options_index = ( int)i;
  92. break;
  93. }
  94. }
  95. if (long_options_index < 0)
  96. {
  97. /* getopt_long might have already printed an error message */
  98. if (c != 63)
  99. x265_log( NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);
  100. return true;
  101. }
  102. }
  103. if (long_options_index < 0)
  104. {
  105. x265_log( NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c);
  106. return true;
  107. }
  108. #define OPT(longname) \
  109. else if (!strcmp(long_options[long_options_index].name, longname))
  110. #define OPT2(name1, name2) \
  111. else if (!strcmp(long_options[long_options_index].name, name1) || \
  112. !strcmp(long_options[long_options_index].name, name2))
  113. if ( 0) ;
  114. OPT2( "frame-skip", "seek") this->seek = ( uint32_t)x265_atoi(optarg, bError);
  115. OPT( "frames") this->framesToBeEncoded = ( uint32_t)x265_atoi(optarg, bError);
  116. OPT( "csv") this->csvfn = optarg;
  117. OPT( "csv-log-level") this->csvLogLevel = x265_atoi(optarg, bError);
  118. OPT( "no-progress") this->bProgress = false;
  119. OPT( "output") outputfn = optarg;
  120. OPT( "input") inputfn = optarg;
  121. OPT( "recon") reconfn = optarg;
  122. OPT( "input-depth") inputBitDepth = ( uint32_t)x265_atoi(optarg, bError);
  123. OPT( "dither") this->bDither = true;
  124. OPT( "recon-depth") reconFileBitDepth = ( uint32_t)x265_atoi(optarg, bError);
  125. OPT( "y4m") this->bForceY4m = true;
  126. OPT( "profile") /* handled above */;
  127. OPT( "preset") /* handled above */;
  128. OPT( "tune") /* handled above */;
  129. OPT( "output-depth") /* handled above */;
  130. OPT( "recon-y4m-exec") reconPlayCmd = optarg;
  131. OPT( "qpfile")
  132. {
  133. this->qpfile = fopen(optarg, "rb");
  134. if (! this->qpfile)
  135. {
  136. x265_log(param, X265_LOG_ERROR, "%s qpfile not found or error in opening qp file\n", optarg);
  137. return false;
  138. }
  139. }
  140. else
  141. bError |= !!api->param_parse(param, long_options[long_options_index].name, optarg);
  142. if (bError)
  143. {
  144. const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind - 2];
  145. x265_log( NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg);
  146. return true;
  147. }
  148. #undef OPT
  149. }
  150. }
  151. if (optind < argc && !inputfn)
  152. inputfn = argv[optind++];
  153. if (optind < argc && !outputfn)
  154. outputfn = argv[optind++];
  155. if (optind < argc)
  156. {
  157. x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]);
  158. return true;
  159. }
  160. if (argc <= 1)
  161. {
  162. api->param_default(param);
  163. printVersion(param, api);
  164. showHelp(param);
  165. }
  166. if (!inputfn || !outputfn)
  167. {
  168. x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");
  169. return true;
  170. }
  171. if (param->internalBitDepth != api->bit_depth)
  172. {
  173. x265_log(param, X265_LOG_ERROR, "Only bit depths of %d are supported in this build\n", api->bit_depth);
  174. return true;
  175. }
  176. InputFileInfo info;
  177. info.filename = inputfn;
  178. info.depth = inputBitDepth;
  179. info.csp = param->internalCsp;
  180. info.width = param->sourceWidth;
  181. info.height = param->sourceHeight;
  182. info.fpsNum = param->fpsNum;
  183. info.fpsDenom = param->fpsDenom;
  184. info.sarWidth = param->vui.sarWidth;
  185. info.sarHeight = param->vui.sarHeight;
  186. info.skipFrames = seek;
  187. info.frameCount = 0;
  188. getParamAspectRatio(param, info.sarWidth, info.sarHeight);
  189. this->input = InputFile::open(info, this->bForceY4m);
  190. if (! this->input || this->input->isFail())
  191. {
  192. x265_log(param, X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn);
  193. return true;
  194. }
  195. if (info.depth < 8 || info.depth > 16)
  196. {
  197. x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);
  198. return true;
  199. }
  200. /* Unconditionally accept height/width/csp from file info */
  201. param->sourceWidth = info.width;
  202. param->sourceHeight = info.height;
  203. param->internalCsp = info.csp;
  204. /* Accept fps and sar from file info if not specified by user */
  205. if (param->fpsDenom == 0 || param->fpsNum == 0)
  206. {
  207. param->fpsDenom = info.fpsDenom;
  208. param->fpsNum = info.fpsNum;
  209. }
  210. if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)
  211. setParamAspectRatio(param, info.sarWidth, info.sarHeight);
  212. if ( this->framesToBeEncoded == 0 && info.frameCount > ( int)seek)
  213. this->framesToBeEncoded = info.frameCount - seek;
  214. param->totalFrames = this->framesToBeEncoded;
  215. /* Force CFR until we have support for VFR */
  216. info.timebaseNum = param->fpsDenom;
  217. info.timebaseDenom = param->fpsNum;
  218. if (api->param_apply_profile(param, profile))
  219. return true;
  220. if (param->logLevel >= X265_LOG_INFO)
  221. {
  222. char buf[ 128];
  223. int p = sprintf(buf, "%dx%d fps %d/%d %sp%d", param->sourceWidth, param->sourceHeight,
  224. param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info.depth);
  225. int width, height;
  226. getParamAspectRatio(param, width, height);
  227. if (width && height)
  228. p += sprintf(buf + p, " sar %d:%d", width, height);
  229. if (framesToBeEncoded <= 0 || info.frameCount <= 0)
  230. strcpy(buf + p, " unknown frame count");
  231. else
  232. sprintf(buf + p, " frames %u - %d of %d", this->seek, this->seek + this->framesToBeEncoded - 1, info.frameCount);
  233. general_log(param, input->getName(), X265_LOG_INFO, "%s\n", buf);
  234. }
  235. this->input->startReader();
  236. if (reconfn)
  237. {
  238. if (reconFileBitDepth == 0)
  239. reconFileBitDepth = param->internalBitDepth;
  240. this->recon = ReconFile::open(reconfn, param->sourceWidth, param->sourceHeight, reconFileBitDepth,
  241. param->fpsNum, param->fpsDenom, param->internalCsp);
  242. if ( this->recon->isFail())
  243. {
  244. x265_log(param, X265_LOG_WARNING, "unable to write reconstructed outputs file\n");
  245. this->recon->release();
  246. this->recon = 0;
  247. }
  248. else
  249. general_log(param, this->recon->getName(), X265_LOG_INFO,
  250. "reconstructed images %dx%d fps %d/%d %s\n",
  251. param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,
  252. x265_source_csp_names[param->internalCsp]);
  253. }
  254. this->output = OutputFile::open(outputfn, info);
  255. if ( this->output->isFail())
  256. {
  257. x265_log(param, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);
  258. return true;
  259. }
  260. general_log(param, this->output->getName(), X265_LOG_INFO, "output file: %s\n", outputfn);
  261. return false; //完成后返回false
  262. }

3.3encoder_open()函数

        encoder_open(param)的主要功能是打印编码器的配置信息,直接调用api.cpp中的x265_encoder *x265_encoder_open(x265_param *p),该函数中调用了x265_print_params(param)用以打印编码器配置信息,如下图所示:




对应的代码如下:


   
   
  1. x265_encoder *x265_encoder_open(x265_param *p)
  2. {
  3. if (!p)
  4. return NULL;
  5. #if _MSC_VER
  6. #pragma warning(disable: 4127) // conditional expression is constant, yes I know
  7. #endif
  8. #if HIGH_BIT_DEPTH
  9. if (X265_DEPTH == 12)
  10. x265_log(p, X265_LOG_WARNING, "Main12 is HIGHLY experimental, do not use!\n");
  11. else if (X265_DEPTH != 10 && X265_DEPTH != 12)
  12. # else
  13. if (X265_DEPTH != 8)
  14. #endif
  15. {
  16. x265_log(p, X265_LOG_ERROR, "Build error, internal bit depth mismatch\n");
  17. return NULL;
  18. }
  19. Encoder* encoder = NULL;
  20. x265_param* param = PARAM_NS::x265_param_alloc();
  21. x265_param* latestParam = PARAM_NS::x265_param_alloc();
  22. if (!param || !latestParam)
  23. goto fail;
  24. memcpy(param, p, sizeof(x265_param));
  25. x265_log(param, X265_LOG_INFO, "HEVC encoder version %s\n", PFX(version_str));
  26. x265_log(param, X265_LOG_INFO, "build info %s\n", PFX(build_info_str));
  27. x265_setup_primitives(param);
  28. if (x265_check_params(param))
  29. goto fail;
  30. if (x265_set_globals(param))
  31. goto fail;
  32. encoder = new Encoder;
  33. if (!param->rc.bEnableSlowFirstPass)
  34. PARAM_NS::x265_param_apply_fastfirstpass(param);
  35. // may change params for auto-detect, etc
  36. encoder->configure(param);
  37. // may change rate control and CPB params
  38. if (!enforceLevel(*param, encoder->m_vps))
  39. goto fail;
  40. // will detect and set profile/tier/level in VPS
  41. determineLevel(*param, encoder->m_vps);
  42. if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc == Profile::NONE)
  43. {
  44. x265_log(param, X265_LOG_INFO, "non-conformant bitstreams not allowed (--allow-non-conformance)\n");
  45. goto fail;
  46. }
  47. encoder->create();
  48. encoder->m_latestParam = latestParam;
  49. memcpy(latestParam, param, sizeof(x265_param));
  50. if (encoder->m_aborted)
  51. goto fail;
  52. x265_print_params(param); //打印参数
  53. return encoder;
  54. fail:
  55. delete encoder;
  56. PARAM_NS::x265_param_free(param);
  57. PARAM_NS::x265_param_free(latestParam);
  58. return NULL;
  59. }


3.4encoder_headers()函数


   
   
  1. int x265_encoder_headers(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal)
  2. {
  3. if (pp_nal && enc)
  4. {
  5. Encoder *encoder = static_cast<Encoder*>(enc);
  6. Entropy sbacCoder;
  7. Bitstream bs;
  8. encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs); //get Stream Headers
  9. *pp_nal = &encoder->m_nalList.m_nal[ 0];
  10. if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
  11. return encoder->m_nalList.m_occupancy;
  12. }
  13. return -1;
  14. }


3.5encoder_encode()函数


   
   
  1. int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture *pic_out)
  2. {
  3. if (!enc)
  4. return -1;
  5. Encoder *encoder = static_cast<Encoder*>(enc);
  6. int numEncoded;
  7. // While flushing, we cannot return 0 until the entire stream is flushed
  8. do
  9. {
  10. numEncoded = encoder->encode(pic_in, pic_out); //==========进入编码函数
  11. }
  12. while (numEncoded == 0 && !pic_in && encoder->m_numDelayedPic);
  13. // do not allow reuse of these buffers for more than one picture. The
  14. // encoder now owns these analysisData buffers.
  15. if (pic_in)
  16. {
  17. pic_in->analysisData.intraData = NULL;
  18. pic_in->analysisData.interData = NULL;
  19. }
  20. if (pp_nal && numEncoded > 0)
  21. {
  22. *pp_nal = &encoder->m_nalList.m_nal[ 0];
  23. if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
  24. }
  25. else if (pi_nal)
  26. *pi_nal = 0;
  27. return numEncoded;
  28. }


3.6encoder_close()函数


   
   
  1. void x265_encoder_close(x265_encoder *enc)
  2. {
  3. if (enc)
  4. {
  5. Encoder *encoder = static_cast<Encoder*>(enc);
  6. encoder->stopJobs();
  7. encoder->printSummary(); //==========打印总结信息
  8. encoder->destroy();
  9. delete encoder;
  10. ATOMIC_DEC(&g_ctuSizeConfigured);
  11. }
  12. }

大笑到这儿,main()函数的主要功能就分析完毕了。


     转载出处:https://blog.csdn.net/FRD2009041510/article/details/51115455
版权声明:本文为博主原创文章,转载请标注转载网址:http://blog.csdn.net/frd2009041510 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()函数中的主要功能函数的具体功能。

1main()函数的功能及其代码结构

        main()函数的主要功能是解析参数并进行编码的一些准备工作,调用了如下几个重要的函数:

1cliopt.parse()函数:解析参数

2api->encoder_open()函数:打开编码器配置

3api->encoder_headers()函数:设置NAL相关信息

4api->encoder_encode()函数:进入编码函数

5api->encoder_close()函数:结束编码并进行总结

注:encoder_open()函数、encoder_headers()函数、encoder_encode()函数与encoder_close()函数均位于api.app中。

        对应的函数关系图如下图所示:




2main()函数源码以及分析

        

        main()函数的源码分析如下代码中的注释,代码如下:


 
 
  1. /*=============================================================*/
  2. /*
  3. ====== Analysed by: RuiDong Fang
  4. ====== Csdn Blog: http://blog.csdn.net/frd2009041510
  5. ====== Date: 2016.04.10
  6. ====== Funtion: x265的入口main()函数
  7. */
  8. /*=============================================================*/
  9. /* CLI return codes:
  10. *
  11. * 0 - encode successful
  12. * 1 - unable to parse command line
  13. * 2 - unable to open encoder
  14. * 3 - unable to generate stream headers
  15. * 4 - encoder abort
  16. * 5 - unable to open csv file
  17. *
  18. */
  19. int main(int argc, char **argv) //主函数入口
  20. {
  21. #if HAVE_VLD
  22. // This uses Microsoft's proprietary WCHAR type, but this only builds on Windows to start with
  23. VLDSetReportOptions(VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE, L"x265_leaks.txt");
  24. #endif
  25. PROFILE_INIT();
  26. THREAD_NAME( "API", 0);
  27. GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE); //获取控制台窗口
  28. SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
  29. ReconPlay* reconPlay = NULL;
  30. CLIOptions cliopt;
  31. if (cliopt.parse(argc, argv)) //==========分析参数,对编码器的参数进行设定,打开文件
  32. {
  33. cliopt.destroy();
  34. if (cliopt.api)
  35. cliopt.api->param_free(cliopt.param);
  36. exit( 1);
  37. }
  38. x265_param* param = cliopt.param;
  39. const x265_api* api = cliopt.api;
  40. /* This allows muxers to modify bitstream format */
  41. cliopt.output->setParam(param);
  42. if (cliopt.reconPlayCmd)
  43. reconPlay = new ReconPlay(cliopt.reconPlayCmd, *param);
  44. /* note: we could try to acquire a different libx265 API here based on
  45. * the profile found during option parsing, but it must be done before
  46. * opening an encoder */
  47. x265_encoder *encoder = api->encoder_open(param); //==========encoder_open()函数,打印编码器配置
  48. if (!encoder) //若打不开编码器配置,提示错误
  49. {
  50. x265_log(param, X265_LOG_ERROR, "failed to open encoder\n");
  51. cliopt.destroy();
  52. api->param_free(param);
  53. api->cleanup();
  54. exit( 2);
  55. }
  56. /* get the encoder parameters post-initialization */
  57. api->encoder_parameters(encoder, param);
  58. if (cliopt.csvfn)
  59. {
  60. cliopt.csvfpt = x265_csvlog_open(*api, *param, cliopt.csvfn, cliopt.csvLogLevel);
  61. if (!cliopt.csvfpt)
  62. {
  63. x265_log(param, X265_LOG_ERROR, "Unable to open CSV log file <%s>, aborting\n", cliopt.csvfn);
  64. cliopt.destroy();
  65. if (cliopt.api)
  66. cliopt.api->param_free(cliopt.param);
  67. exit( 5);
  68. }
  69. }
  70. /* Control-C handler */
  71. //当键入Ctrl-C的时候,当前执行程序调用指针函数sigint_handler 执行完后,再返回原来执行的地方接着往下走。
  72. if (signal(SIGINT, sigint_handler) == SIG_ERR)
  73. x265_log(param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s\n", strerror(errno));
  74. x265_picture pic_orig, pic_out; //定义x265的输入pic_orig和输出pic_out
  75. x265_picture *pic_in = &pic_orig; //获取x265的输入pic_orig的地址
  76. /* Allocate recon picture if analysisMode is enabled */
  77. std::priority_queue< int64_t>* pts_queue = cliopt.output->needPTS() ? new std::priority_queue< int64_t>() : NULL;
  78. x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode || pts_queue || reconPlay || cliopt.csvLogLevel) ? &pic_out : NULL;
  79. uint32_t inFrameCount = 0; //输入的帧数
  80. uint32_t outFrameCount = 0; //输出的帧数
  81. x265_nal *p_nal;
  82. x265_stats stats;
  83. uint32_t nal;
  84. int16_t *errorBuf = NULL;
  85. int ret = 0;
  86. if (!param->bRepeatHeaders)
  87. {
  88. if (api->encoder_headers(encoder, &p_nal, &nal) < 0) //==========encoder_headers函数
  89. {
  90. x265_log(param, X265_LOG_ERROR, "Failure generating stream headers\n");
  91. ret = 3;
  92. goto fail;
  93. }
  94. else
  95. cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
  96. }
  97. api->picture_init(param, pic_in);
  98. if (cliopt.bDither)
  99. {
  100. errorBuf = X265_MALLOC( int16_t, param->sourceWidth + 1);
  101. if (errorBuf)
  102. memset(errorBuf, 0, (param->sourceWidth + 1) * sizeof( int16_t));
  103. else
  104. cliopt.bDither = false;
  105. }
  106. // main encoder loop(编码主循环)
  107. while (pic_in && !b_ctrl_c)
  108. {
  109. pic_orig.poc = inFrameCount;
  110. if (cliopt.qpfile)
  111. {
  112. if (!cliopt.parseQPFile(pic_orig))
  113. {
  114. x265_log( NULL, X265_LOG_ERROR, "can't parse qpfile for frame %d\n", pic_in->poc);
  115. fclose(cliopt.qpfile);
  116. cliopt.qpfile = NULL;
  117. }
  118. }
  119. //当输入帧将要全部编码且输入的帧数大于或等于将要编码的帧数
  120. if (cliopt.framesToBeEncoded && inFrameCount >= cliopt.framesToBeEncoded)
  121. pic_in = NULL;
  122. else if (cliopt.input->readPicture(pic_orig)) //每读入一帧
  123. inFrameCount++; //输入的帧数自加1
  124. else
  125. pic_in = NULL;
  126. if (pic_in)
  127. {
  128. if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)
  129. {
  130. x265_dither_image(*api, *pic_in, cliopt.input->getWidth(), cliopt.input->getHeight(), errorBuf, param->internalBitDepth);
  131. pic_in->bitDepth = param->internalBitDepth;
  132. }
  133. /* Overwrite PTS */
  134. pic_in->pts = pic_in->poc;
  135. }
  136. //进行编码的入口函数,读入24帧后才开始编码
  137. int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon); //==========encoder_encode()函数,numEncoded是将要编码的帧数
  138. if (numEncoded < 0)
  139. {
  140. b_ctrl_c = 1;
  141. ret = 4;
  142. break;
  143. }
  144. if (reconPlay && numEncoded)
  145. reconPlay->writePicture(*pic_recon);
  146. outFrameCount += numEncoded;
  147. if (numEncoded && pic_recon && cliopt.recon)
  148. cliopt.recon->writePicture(pic_out);
  149. if (nal)
  150. {
  151. cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
  152. if (pts_queue)
  153. {
  154. pts_queue->push(-pic_out.pts);
  155. if (pts_queue->size() > 2)
  156. pts_queue->pop();
  157. }
  158. }
  159. cliopt.printStatus(outFrameCount); //打印编码帧的具体信息
  160. if (numEncoded && cliopt.csvLogLevel)
  161. x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
  162. }
  163. /* Flush the encoder */
  164. /*功能:前面读入24帧后才开始编码,此处其实就是处理对应的倒数的24帧,将其存储*/
  165. while (!b_ctrl_c) //退出上一个大循环后且没有按下Ctrl+C,代码继续执行
  166. {
  167. //==========encoder_encode()函数
  168. int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, NULL, pic_recon);
  169. if (numEncoded < 0)
  170. {
  171. ret = 4;
  172. break;
  173. }
  174. if (reconPlay && numEncoded)
  175. reconPlay->writePicture(*pic_recon);
  176. outFrameCount += numEncoded;
  177. if (numEncoded && pic_recon && cliopt.recon)
  178. cliopt.recon->writePicture(pic_out);
  179. if (nal)
  180. {
  181. cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
  182. if (pts_queue)
  183. {
  184. pts_queue->push(-pic_out.pts);
  185. if (pts_queue->size() > 2)
  186. pts_queue->pop();
  187. }
  188. }
  189. cliopt.printStatus(outFrameCount);
  190. if (numEncoded && cliopt.csvLogLevel)
  191. x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
  192. if (!numEncoded)
  193. break;
  194. }
  195. /* clear progress report */
  196. if (cliopt.bProgress)
  197. fprintf( stderr, "%*s\r", 80, " ");
  198. fail:
  199. delete reconPlay;
  200. api->encoder_get_stats(encoder, &stats, sizeof(stats));
  201. if (cliopt.csvfpt && !b_ctrl_c)
  202. x265_csvlog_encode(cliopt.csvfpt, *api, *param, stats, cliopt.csvLogLevel, argc, argv);
  203. api->encoder_close(encoder); //==========encoder_close()函数
  204. int64_t second_largest_pts = 0;
  205. int64_t largest_pts = 0;
  206. if (pts_queue && pts_queue->size() >= 2)
  207. {
  208. second_largest_pts = -pts_queue->top();
  209. pts_queue->pop();
  210. largest_pts = -pts_queue->top();
  211. pts_queue->pop();
  212. delete pts_queue;
  213. pts_queue = NULL;
  214. }
  215. cliopt.output->closeFile(largest_pts, second_largest_pts);
  216. if (b_ctrl_c) //按下Ctrl+C,直接退出
  217. general_log(param, NULL, X265_LOG_INFO, "aborted at input frame %d, output frame %d\n",
  218. cliopt.seek + inFrameCount, stats.encodedPictureCount);
  219. api->cleanup(); /* Free library singletons */
  220. cliopt.destroy();
  221. api->param_free(param);
  222. X265_FREE(errorBuf);
  223. SetConsoleTitle(orgConsoleTitle); //设置控制窗口标题
  224. SetThreadExecutionState(ES_CONTINUOUS);
  225. #if HAVE_VLD
  226. assert(VLDReportLeaks() == 0);
  227. #endif
  228. return ret;
  229. }




3main()函数中的部分功能函数的具体功能

3.1GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);

        GetConsoleTitle的主要功能是获取控制台窗口,其中orgConsoleTitle指向一个缓冲区指针以接收包含标题的字符串;CONSOLE_TITLE_SIZE)是由orgConsoleTitle指向的缓冲区大小。如果函数成功,则返回值是以字符为单位的长度控制台窗口的标题;如果该函数失败,则返回值为零。要获取错误信息,可以调用GetLastError 。

3.2cliopt.parse(argc, argv)

        cliopt.parse(argc, argv)的主要功能是分析参数,直接调用x265.cpp中的bool CLIOptions::parse(int argc, char **argv)函数,该函数会打印输入视频的分辨率、帧率、视频格式、所要编码的帧数目以及输出文件名称等,如下图所示:

        对应的代码如下:


 
 
  1. bool CLIOptions::parse( int argc, char **argv)
  2. {
  3. bool bError = false;
  4. int bShowHelp = false;
  5. int inputBitDepth = 8;
  6. int outputBitDepth = 0;
  7. int reconFileBitDepth = 0;
  8. const char *inputfn = NULL;
  9. const char *reconfn = NULL;
  10. const char *outputfn = NULL;
  11. const char *preset = NULL;
  12. const char *tune = NULL;
  13. const char *profile = NULL;
  14. if (argc <= 1)
  15. {
  16. x265_log( NULL, X265_LOG_ERROR, "No input file. Run x265 --help for a list of options.\n");
  17. return true;
  18. }
  19. /* Presets are applied before all other options. */
  20. for (optind = 0;; )
  21. {
  22. int c = getopt_long(argc, argv, short_options, long_options, NULL);
  23. if (c == -1)
  24. break;
  25. else if (c == 'p')
  26. preset = optarg;
  27. else if (c == 't')
  28. tune = optarg;
  29. else if (c == 'D')
  30. outputBitDepth = atoi(optarg);
  31. else if (c == 'P')
  32. profile = optarg;
  33. else if (c == '?')
  34. bShowHelp = true;
  35. }
  36. if (!outputBitDepth && profile)
  37. {
  38. /* try to derive the output bit depth from the requested profile */
  39. if ( strstr(profile, "10"))
  40. outputBitDepth = 10;
  41. else if ( strstr(profile, "12"))
  42. outputBitDepth = 12;
  43. else
  44. outputBitDepth = 8;
  45. }
  46. api = x265_api_get(outputBitDepth);
  47. if (!api)
  48. {
  49. x265_log( NULL, X265_LOG_WARNING, "falling back to default bit-depth\n");
  50. api = x265_api_get( 0);
  51. }
  52. param = api->param_alloc();
  53. if (!param)
  54. {
  55. x265_log( NULL, X265_LOG_ERROR, "param alloc failed\n");
  56. return true;
  57. }
  58. if (api->param_default_preset(param, preset, tune) < 0)
  59. {
  60. x265_log( NULL, X265_LOG_ERROR, "preset or tune unrecognized\n");
  61. return true;
  62. }
  63. if (bShowHelp)
  64. {
  65. printVersion(param, api);
  66. showHelp(param);
  67. }
  68. for (optind = 0;; )
  69. {
  70. int long_options_index = -1;
  71. int c = getopt_long(argc, argv, short_options, long_options, &long_options_index);
  72. if (c == -1)
  73. break;
  74. switch (c)
  75. {
  76. case 'h':
  77. printVersion(param, api);
  78. showHelp(param);
  79. break;
  80. case 'V':
  81. printVersion(param, api);
  82. x265_report_simd(param);
  83. exit( 0);
  84. default:
  85. if (long_options_index < 0 && c > 0)
  86. {
  87. for ( size_t i = 0; i < sizeof(long_options) / sizeof(long_options[ 0]); i++)
  88. {
  89. if (long_options[i].val == c)
  90. {
  91. long_options_index = ( int)i;
  92. break;
  93. }
  94. }
  95. if (long_options_index < 0)
  96. {
  97. /* getopt_long might have already printed an error message */
  98. if (c != 63)
  99. x265_log( NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);
  100. return true;
  101. }
  102. }
  103. if (long_options_index < 0)
  104. {
  105. x265_log( NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c);
  106. return true;
  107. }
  108. #define OPT(longname) \
  109. else if (!strcmp(long_options[long_options_index].name, longname))
  110. #define OPT2(name1, name2) \
  111. else if (!strcmp(long_options[long_options_index].name, name1) || \
  112. !strcmp(long_options[long_options_index].name, name2))
  113. if ( 0) ;
  114. OPT2( "frame-skip", "seek") this->seek = ( uint32_t)x265_atoi(optarg, bError);
  115. OPT( "frames") this->framesToBeEncoded = ( uint32_t)x265_atoi(optarg, bError);
  116. OPT( "csv") this->csvfn = optarg;
  117. OPT( "csv-log-level") this->csvLogLevel = x265_atoi(optarg, bError);
  118. OPT( "no-progress") this->bProgress = false;
  119. OPT( "output") outputfn = optarg;
  120. OPT( "input") inputfn = optarg;
  121. OPT( "recon") reconfn = optarg;
  122. OPT( "input-depth") inputBitDepth = ( uint32_t)x265_atoi(optarg, bError);
  123. OPT( "dither") this->bDither = true;
  124. OPT( "recon-depth") reconFileBitDepth = ( uint32_t)x265_atoi(optarg, bError);
  125. OPT( "y4m") this->bForceY4m = true;
  126. OPT( "profile") /* handled above */;
  127. OPT( "preset") /* handled above */;
  128. OPT( "tune") /* handled above */;
  129. OPT( "output-depth") /* handled above */;
  130. OPT( "recon-y4m-exec") reconPlayCmd = optarg;
  131. OPT( "qpfile")
  132. {
  133. this->qpfile = fopen(optarg, "rb");
  134. if (! this->qpfile)
  135. {
  136. x265_log(param, X265_LOG_ERROR, "%s qpfile not found or error in opening qp file\n", optarg);
  137. return false;
  138. }
  139. }
  140. else
  141. bError |= !!api->param_parse(param, long_options[long_options_index].name, optarg);
  142. if (bError)
  143. {
  144. const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind - 2];
  145. x265_log( NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg);
  146. return true;
  147. }
  148. #undef OPT
  149. }
  150. }
  151. if (optind < argc && !inputfn)
  152. inputfn = argv[optind++];
  153. if (optind < argc && !outputfn)
  154. outputfn = argv[optind++];
  155. if (optind < argc)
  156. {
  157. x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]);
  158. return true;
  159. }
  160. if (argc <= 1)
  161. {
  162. api->param_default(param);
  163. printVersion(param, api);
  164. showHelp(param);
  165. }
  166. if (!inputfn || !outputfn)
  167. {
  168. x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");
  169. return true;
  170. }
  171. if (param->internalBitDepth != api->bit_depth)
  172. {
  173. x265_log(param, X265_LOG_ERROR, "Only bit depths of %d are supported in this build\n", api->bit_depth);
  174. return true;
  175. }
  176. InputFileInfo info;
  177. info.filename = inputfn;
  178. info.depth = inputBitDepth;
  179. info.csp = param->internalCsp;
  180. info.width = param->sourceWidth;
  181. info.height = param->sourceHeight;
  182. info.fpsNum = param->fpsNum;
  183. info.fpsDenom = param->fpsDenom;
  184. info.sarWidth = param->vui.sarWidth;
  185. info.sarHeight = param->vui.sarHeight;
  186. info.skipFrames = seek;
  187. info.frameCount = 0;
  188. getParamAspectRatio(param, info.sarWidth, info.sarHeight);
  189. this->input = InputFile::open(info, this->bForceY4m);
  190. if (! this->input || this->input->isFail())
  191. {
  192. x265_log(param, X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn);
  193. return true;
  194. }
  195. if (info.depth < 8 || info.depth > 16)
  196. {
  197. x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);
  198. return true;
  199. }
  200. /* Unconditionally accept height/width/csp from file info */
  201. param->sourceWidth = info.width;
  202. param->sourceHeight = info.height;
  203. param->internalCsp = info.csp;
  204. /* Accept fps and sar from file info if not specified by user */
  205. if (param->fpsDenom == 0 || param->fpsNum == 0)
  206. {
  207. param->fpsDenom = info.fpsDenom;
  208. param->fpsNum = info.fpsNum;
  209. }
  210. if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)
  211. setParamAspectRatio(param, info.sarWidth, info.sarHeight);
  212. if ( this->framesToBeEncoded == 0 && info.frameCount > ( int)seek)
  213. this->framesToBeEncoded = info.frameCount - seek;
  214. param->totalFrames = this->framesToBeEncoded;
  215. /* Force CFR until we have support for VFR */
  216. info.timebaseNum = param->fpsDenom;
  217. info.timebaseDenom = param->fpsNum;
  218. if (api->param_apply_profile(param, profile))
  219. return true;
  220. if (param->logLevel >= X265_LOG_INFO)
  221. {
  222. char buf[ 128];
  223. int p = sprintf(buf, "%dx%d fps %d/%d %sp%d", param->sourceWidth, param->sourceHeight,
  224. param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info.depth);
  225. int width, height;
  226. getParamAspectRatio(param, width, height);
  227. if (width && height)
  228. p += sprintf(buf + p, " sar %d:%d", width, height);
  229. if (framesToBeEncoded <= 0 || info.frameCount <= 0)
  230. strcpy(buf + p, " unknown frame count");
  231. else
  232. sprintf(buf + p, " frames %u - %d of %d", this->seek, this->seek + this->framesToBeEncoded - 1, info.frameCount);
  233. general_log(param, input->getName(), X265_LOG_INFO, "%s\n", buf);
  234. }
  235. this->input->startReader();
  236. if (reconfn)
  237. {
  238. if (reconFileBitDepth == 0)
  239. reconFileBitDepth = param->internalBitDepth;
  240. this->recon = ReconFile::open(reconfn, param->sourceWidth, param->sourceHeight, reconFileBitDepth,
  241. param->fpsNum, param->fpsDenom, param->internalCsp);
  242. if ( this->recon->isFail())
  243. {
  244. x265_log(param, X265_LOG_WARNING, "unable to write reconstructed outputs file\n");
  245. this->recon->release();
  246. this->recon = 0;
  247. }
  248. else
  249. general_log(param, this->recon->getName(), X265_LOG_INFO,
  250. "reconstructed images %dx%d fps %d/%d %s\n",
  251. param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,
  252. x265_source_csp_names[param->internalCsp]);
  253. }
  254. this->output = OutputFile::open(outputfn, info);
  255. if ( this->output->isFail())
  256. {
  257. x265_log(param, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);
  258. return true;
  259. }
  260. general_log(param, this->output->getName(), X265_LOG_INFO, "output file: %s\n", outputfn);
  261. return false; //完成后返回false
  262. }

3.3encoder_open()函数

        encoder_open(param)的主要功能是打印编码器的配置信息,直接调用api.cpp中的x265_encoder *x265_encoder_open(x265_param *p),该函数中调用了x265_print_params(param)用以打印编码器配置信息,如下图所示:




对应的代码如下:


 
 
  1. x265_encoder *x265_encoder_open(x265_param *p)
  2. {
  3. if (!p)
  4. return NULL;
  5. #if _MSC_VER
  6. #pragma warning(disable: 4127) // conditional expression is constant, yes I know
  7. #endif
  8. #if HIGH_BIT_DEPTH
  9. if (X265_DEPTH == 12)
  10. x265_log(p, X265_LOG_WARNING, "Main12 is HIGHLY experimental, do not use!\n");
  11. else if (X265_DEPTH != 10 && X265_DEPTH != 12)
  12. # else
  13. if (X265_DEPTH != 8)
  14. #endif
  15. {
  16. x265_log(p, X265_LOG_ERROR, "Build error, internal bit depth mismatch\n");
  17. return NULL;
  18. }
  19. Encoder* encoder = NULL;
  20. x265_param* param = PARAM_NS::x265_param_alloc();
  21. x265_param* latestParam = PARAM_NS::x265_param_alloc();
  22. if (!param || !latestParam)
  23. goto fail;
  24. memcpy(param, p, sizeof(x265_param));
  25. x265_log(param, X265_LOG_INFO, "HEVC encoder version %s\n", PFX(version_str));
  26. x265_log(param, X265_LOG_INFO, "build info %s\n", PFX(build_info_str));
  27. x265_setup_primitives(param);
  28. if (x265_check_params(param))
  29. goto fail;
  30. if (x265_set_globals(param))
  31. goto fail;
  32. encoder = new Encoder;
  33. if (!param->rc.bEnableSlowFirstPass)
  34. PARAM_NS::x265_param_apply_fastfirstpass(param);
  35. // may change params for auto-detect, etc
  36. encoder->configure(param);
  37. // may change rate control and CPB params
  38. if (!enforceLevel(*param, encoder->m_vps))
  39. goto fail;
  40. // will detect and set profile/tier/level in VPS
  41. determineLevel(*param, encoder->m_vps);
  42. if (!param->bAllowNonConformance && encoder->m_vps.ptl.profileIdc == Profile::NONE)
  43. {
  44. x265_log(param, X265_LOG_INFO, "non-conformant bitstreams not allowed (--allow-non-conformance)\n");
  45. goto fail;
  46. }
  47. encoder->create();
  48. encoder->m_latestParam = latestParam;
  49. memcpy(latestParam, param, sizeof(x265_param));
  50. if (encoder->m_aborted)
  51. goto fail;
  52. x265_print_params(param); //打印参数
  53. return encoder;
  54. fail:
  55. delete encoder;
  56. PARAM_NS::x265_param_free(param);
  57. PARAM_NS::x265_param_free(latestParam);
  58. return NULL;
  59. }


3.4encoder_headers()函数


 
 
  1. int x265_encoder_headers(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal)
  2. {
  3. if (pp_nal && enc)
  4. {
  5. Encoder *encoder = static_cast<Encoder*>(enc);
  6. Entropy sbacCoder;
  7. Bitstream bs;
  8. encoder->getStreamHeaders(encoder->m_nalList, sbacCoder, bs); //get Stream Headers
  9. *pp_nal = &encoder->m_nalList.m_nal[ 0];
  10. if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
  11. return encoder->m_nalList.m_occupancy;
  12. }
  13. return -1;
  14. }


3.5encoder_encode()函数


 
 
  1. int x265_encoder_encode(x265_encoder *enc, x265_nal **pp_nal, uint32_t *pi_nal, x265_picture *pic_in, x265_picture *pic_out)
  2. {
  3. if (!enc)
  4. return -1;
  5. Encoder *encoder = static_cast<Encoder*>(enc);
  6. int numEncoded;
  7. // While flushing, we cannot return 0 until the entire stream is flushed
  8. do
  9. {
  10. numEncoded = encoder->encode(pic_in, pic_out); //==========进入编码函数
  11. }
  12. while (numEncoded == 0 && !pic_in && encoder->m_numDelayedPic);
  13. // do not allow reuse of these buffers for more than one picture. The
  14. // encoder now owns these analysisData buffers.
  15. if (pic_in)
  16. {
  17. pic_in->analysisData.intraData = NULL;
  18. pic_in->analysisData.interData = NULL;
  19. }
  20. if (pp_nal && numEncoded > 0)
  21. {
  22. *pp_nal = &encoder->m_nalList.m_nal[ 0];
  23. if (pi_nal) *pi_nal = encoder->m_nalList.m_numNal;
  24. }
  25. else if (pi_nal)
  26. *pi_nal = 0;
  27. return numEncoded;
  28. }


3.6encoder_close()函数


 
 
  1. void x265_encoder_close(x265_encoder *enc)
  2. {
  3. if (enc)
  4. {
  5. Encoder *encoder = static_cast<Encoder*>(enc);
  6. encoder->stopJobs();
  7. encoder->printSummary(); //==========打印总结信息
  8. encoder->destroy();
  9. delete encoder;
  10. ATOMIC_DEC(&g_ctuSizeConfigured);
  11. }
  12. }

大笑到这儿,main()函数的主要功能就分析完毕了。


     转载出处:https://blog.csdn.net/FRD2009041510/article/details/51115455

猜你喜欢

转载自blog.csdn.net/yanceyxin/article/details/82112722