1 /*****************************************************************************
2 * Copyright (C) 2013 x265 project
3 *
4 * Authors: Steve Borho <steve@borho.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
19 *
20 * This program is also available under a commercial proprietary license.
21 * For more information, contact us at license @ x265.com.
22 *****************************************************************************/
23
24 #if _MSC_VER
25 #pragma warning(disable: 4127) // conditional expression is constant, yes I know
26 #endif
27
28 #include "x265.h"
29 #include "x265-extras.h"
30 #include "x265cli.h"
31
32 #include "common.h"
33 #include "input/input.h"
34 #include "output/output.h"
35 #include "output/reconplay.h"
36
37 #include "param.h"
38 #include "cpu.h"
39
40 #if HAVE_VLD
41 /* Visual Leak Detector */
42 #include <vld.h>
43 #endif
44
45 #include <signal.h>
46 #include <errno.h>
47 #include <fcntl.h>
48
49 #include <string>
50 #include <ostream>
51 #include <fstream>
52 #include <queue>
53
54 #define CONSOLE_TITLE_SIZE 200
55 #ifdef _WIN32
56 #include <windows.h>
57 static char orgConsoleTitle[CONSOLE_TITLE_SIZE] = "";
58 #else
59 #define GetConsoleTitle(t, n)
60 #define SetConsoleTitle(t)
61 #define SetThreadExecutionState(es)
62 #endif
63
64 using namespace X265_NS;
65
66 /* Ctrl-C handler */
67 static volatile sig_atomic_t b_ctrl_c /* = 0 */;
sigint_handler(int)68 static void sigint_handler(int)
69 {
70 b_ctrl_c = 1;
71 }
72
73 struct CLIOptions
74 {
75 InputFile* input;
76 ReconFile* recon;
77 OutputFile* output;
78 FILE* qpfile;
79 FILE* csvfpt;
80 const char* csvfn;
81 const char* reconPlayCmd;
82 const x265_api* api;
83 x265_param* param;
84 bool bProgress;
85 bool bForceY4m;
86 bool bDither;
87 int csvLogLevel;
88 uint32_t seek; // number of frames to skip from the beginning
89 uint32_t framesToBeEncoded; // number of frames to encode
90 uint64_t totalbytes;
91 int64_t startTime;
92 int64_t prevUpdateTime;
93
94 /* in microseconds */
95 static const int UPDATE_INTERVAL = 250000;
96
CLIOptionsCLIOptions97 CLIOptions()
98 {
99 input = NULL;
100 recon = NULL;
101 output = NULL;
102 qpfile = NULL;
103 csvfpt = NULL;
104 csvfn = NULL;
105 reconPlayCmd = NULL;
106 api = NULL;
107 param = NULL;
108 framesToBeEncoded = seek = 0;
109 totalbytes = 0;
110 bProgress = true;
111 bForceY4m = false;
112 startTime = x265_mdate();
113 prevUpdateTime = 0;
114 bDither = false;
115 csvLogLevel = 0;
116 }
117
118 void destroy();
119 void printStatus(uint32_t frameNum);
120 bool parse(int argc, char **argv);
121 bool parseQPFile(x265_picture &pic_org);
122 };
123
destroy()124 void CLIOptions::destroy()
125 {
126 if (input)
127 input->release();
128 input = NULL;
129 if (recon)
130 recon->release();
131 recon = NULL;
132 if (qpfile)
133 fclose(qpfile);
134 qpfile = NULL;
135 if (csvfpt)
136 fclose(csvfpt);
137 csvfpt = NULL;
138 if (output)
139 output->release();
140 output = NULL;
141 }
142
printStatus(uint32_t frameNum)143 void CLIOptions::printStatus(uint32_t frameNum)
144 {
145 char buf[200];
146 int64_t time = x265_mdate();
147
148 if (!bProgress || !frameNum || (prevUpdateTime && time - prevUpdateTime < UPDATE_INTERVAL))
149 return;
150
151 int64_t elapsed = time - startTime;
152 double fps = elapsed > 0 ? frameNum * 1000000. / elapsed : 0;
153 float bitrate = 0.008f * totalbytes * (param->fpsNum / param->fpsDenom) / ((float)frameNum);
154 if (framesToBeEncoded)
155 {
156 int eta = (int)(elapsed * (framesToBeEncoded - frameNum) / ((int64_t)frameNum * 1000000));
157 sprintf(buf, "x265 [%.1f%%] %d/%d frames, %.2f fps, %.2f kb/s, eta %d:%02d:%02d",
158 100. * frameNum / framesToBeEncoded, frameNum, framesToBeEncoded, fps, bitrate,
159 eta / 3600, (eta / 60) % 60, eta % 60);
160 }
161 else
162 sprintf(buf, "x265 %d frames: %.2f fps, %.2f kb/s", frameNum, fps, bitrate);
163
164 fprintf(stderr, "%s \r", buf + 5);
165 SetConsoleTitle(buf);
166 fflush(stderr); // needed in windows
167 prevUpdateTime = time;
168 }
169
parse(int argc,char ** argv)170 bool CLIOptions::parse(int argc, char **argv)
171 {
172 bool bError = false;
173 int bShowHelp = false;
174 int inputBitDepth = 8;
175 int outputBitDepth = 0;
176 int reconFileBitDepth = 0;
177 const char *inputfn = NULL;
178 const char *reconfn = NULL;
179 const char *outputfn = NULL;
180 const char *preset = NULL;
181 const char *tune = NULL;
182 const char *profile = NULL;
183
184 if (argc <= 1)
185 {
186 x265_log(NULL, X265_LOG_ERROR, "No input file. Run x265 --help for a list of options.\n");
187 return true;
188 }
189
190 /* Presets are applied before all other options. */
191 for (optind = 0;; )
192 {
193 int c = getopt_long(argc, argv, short_options, long_options, NULL);
194 if (c == -1)
195 break;
196 else if (c == 'p')
197 preset = optarg;
198 else if (c == 't')
199 tune = optarg;
200 else if (c == 'D')
201 outputBitDepth = atoi(optarg);
202 else if (c == 'P')
203 profile = optarg;
204 else if (c == '?')
205 bShowHelp = true;
206 }
207
208 if (!outputBitDepth && profile)
209 {
210 /* try to derive the output bit depth from the requested profile */
211 if (strstr(profile, "10"))
212 outputBitDepth = 10;
213 else if (strstr(profile, "12"))
214 outputBitDepth = 12;
215 else
216 outputBitDepth = 8;
217 }
218
219 api = x265_api_get(outputBitDepth);
220 if (!api)
221 {
222 x265_log(NULL, X265_LOG_WARNING, "falling back to default bit-depth\n");
223 api = x265_api_get(0);
224 }
225
226 param = api->param_alloc();
227 if (!param)
228 {
229 x265_log(NULL, X265_LOG_ERROR, "param alloc failed\n");
230 return true;
231 }
232
233 if (api->param_default_preset(param, preset, tune) < 0)
234 {
235 x265_log(NULL, X265_LOG_ERROR, "preset or tune unrecognized\n");
236 return true;
237 }
238
239 if (bShowHelp)
240 {
241 printVersion(param, api);
242 showHelp(param);
243 }
244
245 for (optind = 0;; )
246 {
247 int long_options_index = -1;
248 int c = getopt_long(argc, argv, short_options, long_options, &long_options_index);
249 if (c == -1)
250 break;
251
252 switch (c)
253 {
254 case 'h':
255 printVersion(param, api);
256 showHelp(param);
257 break;
258
259 case 'V':
260 printVersion(param, api);
261 x265_report_simd(param);
262 exit(0);
263
264 default:
265 if (long_options_index < 0 && c > 0)
266 {
267 for (size_t i = 0; i < sizeof(long_options) / sizeof(long_options[0]); i++)
268 {
269 if (long_options[i].val == c)
270 {
271 long_options_index = (int)i;
272 break;
273 }
274 }
275
276 if (long_options_index < 0)
277 {
278 /* getopt_long might have already printed an error message */
279 if (c != 63)
280 x265_log(NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);
281 return true;
282 }
283 }
284 if (long_options_index < 0)
285 {
286 x265_log(NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c);
287 return true;
288 }
289 #define OPT(longname) \
290 else if (!strcmp(long_options[long_options_index].name, longname))
291 #define OPT2(name1, name2) \
292 else if (!strcmp(long_options[long_options_index].name, name1) || \
293 !strcmp(long_options[long_options_index].name, name2))
294
295 if (0) ;
296 OPT2("frame-skip", "seek") this->seek = (uint32_t)x265_atoi(optarg, bError);
297 OPT("frames") this->framesToBeEncoded = (uint32_t)x265_atoi(optarg, bError);
298 OPT("csv") this->csvfn = optarg;
299 OPT("csv-log-level") this->csvLogLevel = x265_atoi(optarg, bError);
300 OPT("no-progress") this->bProgress = false;
301 OPT("output") outputfn = optarg;
302 OPT("input") inputfn = optarg;
303 OPT("recon") reconfn = optarg;
304 OPT("input-depth") inputBitDepth = (uint32_t)x265_atoi(optarg, bError);
305 OPT("dither") this->bDither = true;
306 OPT("recon-depth") reconFileBitDepth = (uint32_t)x265_atoi(optarg, bError);
307 OPT("y4m") this->bForceY4m = true;
308 OPT("profile") /* handled above */;
309 OPT("preset") /* handled above */;
310 OPT("tune") /* handled above */;
311 OPT("output-depth") /* handled above */;
312 OPT("recon-y4m-exec") reconPlayCmd = optarg;
313 OPT("qpfile")
314 {
315 this->qpfile = fopen(optarg, "rb");
316 if (!this->qpfile)
317 {
318 x265_log(param, X265_LOG_ERROR, "%s qpfile not found or error in opening qp file\n", optarg);
319 return false;
320 }
321 }
322 else
323 bError |= !!api->param_parse(param, long_options[long_options_index].name, optarg);
324
325 if (bError)
326 {
327 const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind - 2];
328 x265_log(NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg);
329 return true;
330 }
331 #undef OPT
332 }
333 }
334
335 if (optind < argc && !inputfn)
336 inputfn = argv[optind++];
337 if (optind < argc && !outputfn)
338 outputfn = argv[optind++];
339 if (optind < argc)
340 {
341 x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]);
342 return true;
343 }
344
345 if (argc <= 1)
346 {
347 api->param_default(param);
348 printVersion(param, api);
349 showHelp(param);
350 }
351
352 if (!inputfn || !outputfn)
353 {
354 x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");
355 return true;
356 }
357
358 if (param->internalBitDepth != api->bit_depth)
359 {
360 x265_log(param, X265_LOG_ERROR, "Only bit depths of %d are supported in this build\n", api->bit_depth);
361 return true;
362 }
363
364 InputFileInfo info;
365 info.filename = inputfn;
366 info.depth = inputBitDepth;
367 info.csp = param->internalCsp;
368 info.width = param->sourceWidth;
369 info.height = param->sourceHeight;
370 info.fpsNum = param->fpsNum;
371 info.fpsDenom = param->fpsDenom;
372 info.sarWidth = param->vui.sarWidth;
373 info.sarHeight = param->vui.sarHeight;
374 info.skipFrames = seek;
375 info.frameCount = 0;
376 getParamAspectRatio(param, info.sarWidth, info.sarHeight);
377
378 this->input = InputFile::open(info, this->bForceY4m);
379 if (!this->input || this->input->isFail())
380 {
381 x265_log(param, X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn);
382 return true;
383 }
384
385 if (info.depth < 8 || info.depth > 16)
386 {
387 x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);
388 return true;
389 }
390
391 /* Unconditionally accept height/width/csp from file info */
392 param->sourceWidth = info.width;
393 param->sourceHeight = info.height;
394 param->internalCsp = info.csp;
395
396 /* Accept fps and sar from file info if not specified by user */
397 if (param->fpsDenom == 0 || param->fpsNum == 0)
398 {
399 param->fpsDenom = info.fpsDenom;
400 param->fpsNum = info.fpsNum;
401 }
402 if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)
403 setParamAspectRatio(param, info.sarWidth, info.sarHeight);
404 if (this->framesToBeEncoded == 0 && info.frameCount > (int)seek)
405 this->framesToBeEncoded = info.frameCount - seek;
406 param->totalFrames = this->framesToBeEncoded;
407
408 /* Force CFR until we have support for VFR */
409 info.timebaseNum = param->fpsDenom;
410 info.timebaseDenom = param->fpsNum;
411
412 if (api->param_apply_profile(param, profile))
413 return true;
414
415 if (param->logLevel >= X265_LOG_INFO)
416 {
417 char buf[128];
418 int p = sprintf(buf, "%dx%d fps %d/%d %sp%d", param->sourceWidth, param->sourceHeight,
419 param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info.depth);
420
421 int width, height;
422 getParamAspectRatio(param, width, height);
423 if (width && height)
424 p += sprintf(buf + p, " sar %d:%d", width, height);
425
426 if (framesToBeEncoded <= 0 || info.frameCount <= 0)
427 strcpy(buf + p, " unknown frame count");
428 else
429 sprintf(buf + p, " frames %u - %d of %d", this->seek, this->seek + this->framesToBeEncoded - 1, info.frameCount);
430
431 general_log(param, input->getName(), X265_LOG_INFO, "%s\n", buf);
432 }
433
434 this->input->startReader();
435
436 if (reconfn)
437 {
438 if (reconFileBitDepth == 0)
439 reconFileBitDepth = param->internalBitDepth;
440 this->recon = ReconFile::open(reconfn, param->sourceWidth, param->sourceHeight, reconFileBitDepth,
441 param->fpsNum, param->fpsDenom, param->internalCsp);
442 if (this->recon->isFail())
443 {
444 x265_log(param, X265_LOG_WARNING, "unable to write reconstructed outputs file\n");
445 this->recon->release();
446 this->recon = 0;
447 }
448 else
449 general_log(param, this->recon->getName(), X265_LOG_INFO,
450 "reconstructed images %dx%d fps %d/%d %s\n",
451 param->sourceWidth, param->sourceHeight, param->fpsNum, param->fpsDenom,
452 x265_source_csp_names[param->internalCsp]);
453 }
454
455 this->output = OutputFile::open(outputfn, info);
456 if (this->output->isFail())
457 {
458 x265_log(param, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);
459 return true;
460 }
461 general_log(param, this->output->getName(), X265_LOG_INFO, "output file: %s\n", outputfn);
462 return false;
463 }
464
parseQPFile(x265_picture & pic_org)465 bool CLIOptions::parseQPFile(x265_picture &pic_org)
466 {
467 int32_t num = -1, qp, ret;
468 char type;
469 uint32_t filePos;
470 pic_org.forceqp = 0;
471 pic_org.sliceType = X265_TYPE_AUTO;
472 while (num < pic_org.poc)
473 {
474 filePos = ftell(qpfile);
475 qp = -1;
476 ret = fscanf(qpfile, "%d %c%*[ \t]%d\n", &num, &type, &qp);
477
478 if (num > pic_org.poc || ret == EOF)
479 {
480 fseek(qpfile, filePos, SEEK_SET);
481 break;
482 }
483 if (num < pic_org.poc && ret >= 2)
484 continue;
485 if (ret == 3 && qp >= 0)
486 pic_org.forceqp = qp + 1;
487 if (type == 'I') pic_org.sliceType = X265_TYPE_IDR;
488 else if (type == 'i') pic_org.sliceType = X265_TYPE_I;
489 else if (type == 'P') pic_org.sliceType = X265_TYPE_P;
490 else if (type == 'B') pic_org.sliceType = X265_TYPE_BREF;
491 else if (type == 'b') pic_org.sliceType = X265_TYPE_B;
492 else ret = 0;
493 if (ret < 2 || qp < -1 || qp > 51)
494 return 0;
495 }
496 return 1;
497 }
498
499 /* CLI return codes:
500 *
501 * 0 - encode successful
502 * 1 - unable to parse command line
503 * 2 - unable to open encoder
504 * 3 - unable to generate stream headers
505 * 4 - encoder abort
506 * 5 - unable to open csv file */
507
main(int argc,char ** argv)508 int main(int argc, char **argv)
509 {
510 #if HAVE_VLD
511 // This uses Microsoft's proprietary WCHAR type, but this only builds on Windows to start with
512 VLDSetReportOptions(VLD_OPT_REPORT_TO_DEBUGGER | VLD_OPT_REPORT_TO_FILE, L"x265_leaks.txt");
513 #endif
514 PROFILE_INIT();
515 THREAD_NAME("API", 0);
516
517 GetConsoleTitle(orgConsoleTitle, CONSOLE_TITLE_SIZE);
518 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_AWAYMODE_REQUIRED);
519
520 ReconPlay* reconPlay = NULL;
521 CLIOptions cliopt;
522
523 if (cliopt.parse(argc, argv))
524 {
525 cliopt.destroy();
526 if (cliopt.api)
527 cliopt.api->param_free(cliopt.param);
528 exit(1);
529 }
530
531 x265_param* param = cliopt.param;
532 const x265_api* api = cliopt.api;
533
534 /* This allows muxers to modify bitstream format */
535 cliopt.output->setParam(param);
536
537 if (cliopt.reconPlayCmd)
538 reconPlay = new ReconPlay(cliopt.reconPlayCmd, *param);
539
540 /* note: we could try to acquire a different libx265 API here based on
541 * the profile found during option parsing, but it must be done before
542 * opening an encoder */
543
544 x265_encoder *encoder = api->encoder_open(param);
545 if (!encoder)
546 {
547 x265_log(param, X265_LOG_ERROR, "failed to open encoder\n");
548 cliopt.destroy();
549 api->param_free(param);
550 api->cleanup();
551 exit(2);
552 }
553
554 /* get the encoder parameters post-initialization */
555 api->encoder_parameters(encoder, param);
556
557 if (cliopt.csvfn)
558 {
559 cliopt.csvfpt = x265_csvlog_open(*api, *param, cliopt.csvfn, cliopt.csvLogLevel);
560 if (!cliopt.csvfpt)
561 {
562 x265_log(param, X265_LOG_ERROR, "Unable to open CSV log file <%s>, aborting\n", cliopt.csvfn);
563 cliopt.destroy();
564 if (cliopt.api)
565 cliopt.api->param_free(cliopt.param);
566 exit(5);
567 }
568 }
569
570 /* Control-C handler */
571 if (signal(SIGINT, sigint_handler) == SIG_ERR)
572 x265_log(param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s\n", strerror(errno));
573
574 x265_picture pic_orig, pic_out;
575 x265_picture *pic_in = &pic_orig;
576 /* Allocate recon picture if analysisMode is enabled */
577 std::priority_queue<int64_t>* pts_queue = cliopt.output->needPTS() ? new std::priority_queue<int64_t>() : NULL;
578 x265_picture *pic_recon = (cliopt.recon || !!param->analysisMode || pts_queue || reconPlay || cliopt.csvLogLevel) ? &pic_out : NULL;
579 uint32_t inFrameCount = 0;
580 uint32_t outFrameCount = 0;
581 x265_nal *p_nal;
582 x265_stats stats;
583 uint32_t nal;
584 int16_t *errorBuf = NULL;
585 int ret = 0;
586
587 if (!param->bRepeatHeaders)
588 {
589 if (api->encoder_headers(encoder, &p_nal, &nal) < 0)
590 {
591 x265_log(param, X265_LOG_ERROR, "Failure generating stream headers\n");
592 ret = 3;
593 goto fail;
594 }
595 else
596 cliopt.totalbytes += cliopt.output->writeHeaders(p_nal, nal);
597 }
598
599 api->picture_init(param, pic_in);
600
601 if (cliopt.bDither)
602 {
603 errorBuf = X265_MALLOC(int16_t, param->sourceWidth + 1);
604 if (errorBuf)
605 memset(errorBuf, 0, (param->sourceWidth + 1) * sizeof(int16_t));
606 else
607 cliopt.bDither = false;
608 }
609
610 // main encoder loop
611 while (pic_in && !b_ctrl_c)
612 {
613 pic_orig.poc = inFrameCount;
614 if (cliopt.qpfile)
615 {
616 if (!cliopt.parseQPFile(pic_orig))
617 {
618 x265_log(NULL, X265_LOG_ERROR, "can't parse qpfile for frame %d\n", pic_in->poc);
619 fclose(cliopt.qpfile);
620 cliopt.qpfile = NULL;
621 }
622 }
623
624 if (cliopt.framesToBeEncoded && inFrameCount >= cliopt.framesToBeEncoded)
625 pic_in = NULL;
626 else if (cliopt.input->readPicture(pic_orig))
627 inFrameCount++;
628 else
629 pic_in = NULL;
630
631 if (pic_in)
632 {
633 if (pic_in->bitDepth > param->internalBitDepth && cliopt.bDither)
634 {
635 x265_dither_image(*api, *pic_in, param->sourceWidth, param->sourceHeight, errorBuf, param->internalBitDepth);
636 pic_in->bitDepth = param->internalBitDepth;
637 }
638 /* Overwrite PTS */
639 pic_in->pts = pic_in->poc;
640 }
641
642 int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, pic_in, pic_recon);
643 if (numEncoded < 0)
644 {
645 b_ctrl_c = 1;
646 ret = 4;
647 break;
648 }
649
650 if (reconPlay && numEncoded)
651 reconPlay->writePicture(*pic_recon);
652
653 outFrameCount += numEncoded;
654
655 if (numEncoded && pic_recon && cliopt.recon)
656 cliopt.recon->writePicture(pic_out);
657 if (nal)
658 {
659 cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
660 if (pts_queue)
661 {
662 pts_queue->push(-pic_out.pts);
663 if (pts_queue->size() > 2)
664 pts_queue->pop();
665 }
666 }
667
668 cliopt.printStatus(outFrameCount);
669 if (numEncoded && cliopt.csvLogLevel)
670 x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
671 }
672
673 /* Flush the encoder */
674 while (!b_ctrl_c)
675 {
676 int numEncoded = api->encoder_encode(encoder, &p_nal, &nal, NULL, pic_recon);
677 if (numEncoded < 0)
678 {
679 ret = 4;
680 break;
681 }
682
683 if (reconPlay && numEncoded)
684 reconPlay->writePicture(*pic_recon);
685
686 outFrameCount += numEncoded;
687 if (numEncoded && pic_recon && cliopt.recon)
688 cliopt.recon->writePicture(pic_out);
689 if (nal)
690 {
691 cliopt.totalbytes += cliopt.output->writeFrame(p_nal, nal, pic_out);
692 if (pts_queue)
693 {
694 pts_queue->push(-pic_out.pts);
695 if (pts_queue->size() > 2)
696 pts_queue->pop();
697 }
698 }
699
700 cliopt.printStatus(outFrameCount);
701 if (numEncoded && cliopt.csvLogLevel)
702 x265_csvlog_frame(cliopt.csvfpt, *param, *pic_recon, cliopt.csvLogLevel);
703
704 if (!numEncoded)
705 break;
706 }
707
708 /* clear progress report */
709 if (cliopt.bProgress)
710 fprintf(stderr, "%*s\r", 80, " ");
711
712 fail:
713
714 delete reconPlay;
715
716 api->encoder_get_stats(encoder, &stats, sizeof(stats));
717 if (cliopt.csvfpt && !b_ctrl_c)
718 x265_csvlog_encode(cliopt.csvfpt, *api, *param, stats, cliopt.csvLogLevel, argc, argv);
719 api->encoder_close(encoder);
720
721 int64_t second_largest_pts = 0;
722 int64_t largest_pts = 0;
723 if (pts_queue && pts_queue->size() >= 2)
724 {
725 second_largest_pts = -pts_queue->top();
726 pts_queue->pop();
727 largest_pts = -pts_queue->top();
728 pts_queue->pop();
729 delete pts_queue;
730 pts_queue = NULL;
731 }
732 cliopt.output->closeFile(largest_pts, second_largest_pts);
733
734 if (b_ctrl_c)
735 general_log(param, NULL, X265_LOG_INFO, "aborted at input frame %d, output frame %d\n",
736 cliopt.seek + inFrameCount, stats.encodedPictureCount);
737
738 api->cleanup(); /* Free library singletons */
739
740 cliopt.destroy();
741
742 api->param_free(param);
743
744 X265_FREE(errorBuf);
745
746 SetConsoleTitle(orgConsoleTitle);
747 SetThreadExecutionState(ES_CONTINUOUS);
748
749 #if HAVE_VLD
750 assert(VLDReportLeaks() == 0);
751 #endif
752
753 return ret;
754 }
755