2014-01-24 10:37:15 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* This file is part of Kvazaar HEVC encoder.
|
2014-02-21 13:00:20 +00:00
|
|
|
*
|
2015-02-23 11:18:48 +00:00
|
|
|
* Copyright (C) 2013-2015 Tampere University of Technology and others (see
|
2014-01-24 10:37:15 +00:00
|
|
|
* COPYING file).
|
|
|
|
*
|
2015-02-23 11:18:48 +00:00
|
|
|
* Kvazaar is free software: you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU Lesser General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2.1 of the License, or (at your
|
|
|
|
* option) any later version.
|
2014-01-24 10:37:15 +00:00
|
|
|
*
|
2015-02-23 11:18:48 +00:00
|
|
|
* Kvazaar is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
|
|
|
* more details.
|
2014-01-24 10:37:15 +00:00
|
|
|
*
|
2015-02-23 11:18:48 +00:00
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with Kvazaar. If not, see <http://www.gnu.org/licenses/>.
|
2014-01-24 10:37:15 +00:00
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* \file
|
2013-09-18 14:29:30 +00:00
|
|
|
*
|
2012-05-30 12:10:23 +00:00
|
|
|
*/
|
|
|
|
|
2014-01-31 12:32:41 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
/* The following two defines must be located before the inclusion of any system header files. */
|
|
|
|
#define WINVER 0x0500
|
|
|
|
#define _WIN32_WINNT 0x0500
|
|
|
|
#include <io.h> /* _setmode() */
|
|
|
|
#include <fcntl.h> /* _O_BINARY */
|
|
|
|
#endif
|
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2014-04-11 09:42:37 +00:00
|
|
|
#include <time.h>
|
2013-09-23 13:48:34 +00:00
|
|
|
|
2014-06-11 05:48:36 +00:00
|
|
|
#include "checkpoint.h"
|
2013-09-19 09:48:25 +00:00
|
|
|
#include "global.h"
|
|
|
|
#include "config.h"
|
2014-06-16 08:18:11 +00:00
|
|
|
#include "threads.h"
|
2013-09-19 09:48:25 +00:00
|
|
|
#include "encoder.h"
|
|
|
|
#include "cabac.h"
|
2014-06-05 12:54:58 +00:00
|
|
|
#include "image.h"
|
2013-09-19 09:48:25 +00:00
|
|
|
#include "transform.h"
|
2014-04-16 07:40:42 +00:00
|
|
|
#include "scalinglist.h"
|
2014-04-29 08:14:42 +00:00
|
|
|
#include "strategyselector.h"
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
/**
|
|
|
|
* \brief Program main function.
|
|
|
|
* \param argc Argument count from commandline
|
|
|
|
* \param argv Argument list
|
|
|
|
* \return Program exit state
|
2012-05-30 12:10:23 +00:00
|
|
|
*/
|
2013-09-19 09:48:25 +00:00
|
|
|
int main(int argc, char *argv[])
|
2014-02-21 13:00:20 +00:00
|
|
|
{
|
2015-03-04 11:30:26 +00:00
|
|
|
config_t *cfg = NULL; //!< Global configuration
|
2013-09-19 09:48:25 +00:00
|
|
|
FILE *input = NULL; //!< input file (YUV)
|
|
|
|
FILE *output = NULL; //!< output file (HEVC NAL stream)
|
2015-03-04 10:26:57 +00:00
|
|
|
encoder_control_t encoder;
|
2013-09-19 09:48:25 +00:00
|
|
|
double psnr[3] = { 0.0, 0.0, 0.0 };
|
2014-06-16 07:22:59 +00:00
|
|
|
uint32_t stat_frames = 0;
|
|
|
|
uint64_t curpos = 0;
|
2014-03-10 16:07:48 +00:00
|
|
|
FILE *recout = NULL; //!< reconstructed YUV output, --debug
|
2014-04-11 09:42:37 +00:00
|
|
|
clock_t start_time = clock();
|
2014-06-16 08:18:11 +00:00
|
|
|
clock_t encoding_start_cpu_time;
|
|
|
|
CLOCK_T encoding_start_real_time;
|
|
|
|
|
|
|
|
clock_t encoding_end_cpu_time;
|
|
|
|
CLOCK_T encoding_end_real_time;
|
2014-01-31 12:32:41 +00:00
|
|
|
|
2014-02-05 17:16:44 +00:00
|
|
|
// Stdin and stdout need to be binary for input and output to work.
|
|
|
|
// Stderr needs to be text mode to convert \n to \r\n in Windows.
|
2014-01-31 12:32:41 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
_setmode( _fileno( stdin ), _O_BINARY );
|
|
|
|
_setmode( _fileno( stdout ), _O_BINARY );
|
2014-02-05 17:16:44 +00:00
|
|
|
_setmode( _fileno( stderr ), _O_TEXT );
|
2014-01-31 12:32:41 +00:00
|
|
|
#endif
|
2014-06-11 05:48:36 +00:00
|
|
|
|
|
|
|
CHECKPOINTS_INIT();
|
2014-01-31 12:32:41 +00:00
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
// Handle configuration
|
|
|
|
cfg = config_alloc();
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
// If problem with configuration, print banner and shutdown
|
2014-01-31 18:34:50 +00:00
|
|
|
if (!cfg || !config_init(cfg) || !config_read(cfg,argc,argv)) {
|
2014-02-05 17:16:44 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"/***********************************************/\n"
|
2014-02-07 01:48:38 +00:00
|
|
|
" * Kvazaar HEVC Encoder v. " VERSION_STRING " *\n"
|
2014-02-05 17:16:44 +00:00
|
|
|
" * Tampere University of Technology 2014 *\n"
|
|
|
|
"/***********************************************/\n\n");
|
2014-02-21 13:00:20 +00:00
|
|
|
|
|
|
|
fprintf(stderr,
|
2014-02-05 17:16:44 +00:00
|
|
|
"Usage:\n"
|
2014-03-12 13:18:50 +00:00
|
|
|
"kvazaar -i <input> --input-res <width>x<height> -o <output>\n"
|
2014-02-06 19:45:37 +00:00
|
|
|
"\n"
|
2014-02-05 17:16:44 +00:00
|
|
|
"Optional parameters:\n"
|
2014-03-10 12:58:57 +00:00
|
|
|
" -n, --frames <integer> : Number of frames to code [all]\n"
|
|
|
|
" --seek <integer> : First frame to code [0]\n"
|
2014-03-10 13:53:23 +00:00
|
|
|
" --input-res <int>x<int> : Input resolution (width x height)\n"
|
2014-02-06 19:45:37 +00:00
|
|
|
" -q, --qp <integer> : Quantization Parameter [32]\n"
|
|
|
|
" -p, --period <integer> : Period of intra pictures [0]\n"
|
|
|
|
" 0: only first picture is intra\n"
|
|
|
|
" 1: all pictures are intra\n"
|
|
|
|
" 2-N: every Nth picture is intra\n"
|
2015-02-18 11:41:03 +00:00
|
|
|
" --vps-period <integer> : Specify how often the video parameter set is\n"
|
|
|
|
" re-sent. [0]\n"
|
|
|
|
" 0: only send VPS with the first frame\n"
|
|
|
|
" 1: send VPS with every intra frame\n"
|
|
|
|
" N: send VPS with every Nth intra frame\n"
|
2014-02-20 09:02:51 +00:00
|
|
|
" -r, --ref <integer> : Reference frames, range 1..15 [3]\n"
|
2014-02-06 19:45:37 +00:00
|
|
|
" --no-deblock : Disable deblocking filter\n"
|
|
|
|
" --deblock <beta:tc> : Deblocking filter parameters\n"
|
|
|
|
" beta and tc range is -6..6 [0:0]\n"
|
|
|
|
" --no-sao : Disable sample adaptive offset\n"
|
2014-04-02 11:41:40 +00:00
|
|
|
" --no-rdoq : Disable RDO quantization\n"
|
2015-01-24 18:10:21 +00:00
|
|
|
" --no-signhide : Disable sign hiding in quantization\n"
|
2014-04-07 11:36:01 +00:00
|
|
|
" --rd <integer> : Rate-Distortion Optimization level [1]\n"
|
|
|
|
" 0: no RDO\n"
|
|
|
|
" 1: estimated RDO\n"
|
|
|
|
" 2: full RDO\n"
|
2014-06-17 12:32:05 +00:00
|
|
|
" --full-intra-search : Try all intra modes.\n"
|
2015-03-19 16:48:10 +00:00
|
|
|
" --me <string> : Set integer motion estimation algorithm [\"hexbs\"]\n"
|
|
|
|
" \"hexbs\": Hexagon Based Search (faster)\n"
|
|
|
|
" \"tz\": Test Zone Search (better quality)\n"
|
2014-04-02 11:41:40 +00:00
|
|
|
" --no-transform-skip : Disable transform skip\n"
|
2014-02-06 22:35:15 +00:00
|
|
|
" --aud : Use access unit delimiters\n"
|
config: Add --cqmfile to use custom quantization matrices from a file.
The coefficients in a matrix are stored in up-right diagonal order.
The following indicates the default matrices specified in the spec.
INTRA4X4_LUMA
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16
INTRA4X4_CHROMAU
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16
INTRA4X4_CHROMAV
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16
INTER4X4_LUMA
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16
INTER4X4_CHROMAU
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16
INTER4X4_CHROMAV
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16,
16, 16, 16, 16
INTRA8X8_LUMA
16, 16, 16, 16, 17, 18, 21, 24,
16, 16, 16, 16, 17, 19, 22, 25,
16, 16, 17, 18, 20, 22, 25, 29,
16, 16, 18, 21, 24, 27, 31, 36,
17, 17, 20, 24, 30, 35, 41, 47,
18, 19, 22, 27, 35, 44, 54, 65,
21, 22, 25, 31, 41, 54, 70, 88,
24, 25, 29, 36, 47, 65, 88, 115
INTRA8X8_CHROMAU
16, 16, 16, 16, 17, 18, 21, 24,
16, 16, 16, 16, 17, 19, 22, 25,
16, 16, 17, 18, 20, 22, 25, 29,
16, 16, 18, 21, 24, 27, 31, 36,
17, 17, 20, 24, 30, 35, 41, 47,
18, 19, 22, 27, 35, 44, 54, 65,
21, 22, 25, 31, 41, 54, 70, 88,
24, 25, 29, 36, 47, 65, 88, 115
INTRA8X8_CHROMAV
16, 16, 16, 16, 17, 18, 21, 24,
16, 16, 16, 16, 17, 19, 22, 25,
16, 16, 17, 18, 20, 22, 25, 29,
16, 16, 18, 21, 24, 27, 31, 36,
17, 17, 20, 24, 30, 35, 41, 47,
18, 19, 22, 27, 35, 44, 54, 65,
21, 22, 25, 31, 41, 54, 70, 88,
24, 25, 29, 36, 47, 65, 88, 115
INTER8X8_LUMA
16, 16, 16, 16, 17, 18, 20, 24,
16, 16, 16, 17, 18, 20, 24, 25,
16, 16, 17, 18, 20, 24, 25, 28,
16, 17, 18, 20, 24, 25, 28, 33,
17, 18, 20, 24, 25, 28, 33, 41,
18, 20, 24, 25, 28, 33, 41, 54,
20, 24, 25, 28, 33, 41, 54, 71,
24, 25, 28, 33, 41, 54, 71, 91
INTER8X8_CHROMAU
16, 16, 16, 16, 17, 18, 20, 24,
16, 16, 16, 17, 18, 20, 24, 25,
16, 16, 17, 18, 20, 24, 25, 28,
16, 17, 18, 20, 24, 25, 28, 33,
17, 18, 20, 24, 25, 28, 33, 41,
18, 20, 24, 25, 28, 33, 41, 54,
20, 24, 25, 28, 33, 41, 54, 71,
24, 25, 28, 33, 41, 54, 71, 91
INTER8X8_CHROMAV
16, 16, 16, 16, 17, 18, 20, 24,
16, 16, 16, 17, 18, 20, 24, 25,
16, 16, 17, 18, 20, 24, 25, 28,
16, 17, 18, 20, 24, 25, 28, 33,
17, 18, 20, 24, 25, 28, 33, 41,
18, 20, 24, 25, 28, 33, 41, 54,
20, 24, 25, 28, 33, 41, 54, 71,
24, 25, 28, 33, 41, 54, 71, 91
INTRA16X16_LUMA
16, 16, 16, 16, 17, 18, 21, 24,
16, 16, 16, 16, 17, 19, 22, 25,
16, 16, 17, 18, 20, 22, 25, 29,
16, 16, 18, 21, 24, 27, 31, 36,
17, 17, 20, 24, 30, 35, 41, 47,
18, 19, 22, 27, 35, 44, 54, 65,
21, 22, 25, 31, 41, 54, 70, 88,
24, 25, 29, 36, 47, 65, 88, 115
INTRA16X16_CHROMAU
16, 16, 16, 16, 17, 18, 21, 24,
16, 16, 16, 16, 17, 19, 22, 25,
16, 16, 17, 18, 20, 22, 25, 29,
16, 16, 18, 21, 24, 27, 31, 36,
17, 17, 20, 24, 30, 35, 41, 47,
18, 19, 22, 27, 35, 44, 54, 65,
21, 22, 25, 31, 41, 54, 70, 88,
24, 25, 29, 36, 47, 65, 88, 115
INTRA16X16_CHROMAV
16, 16, 16, 16, 17, 18, 21, 24,
16, 16, 16, 16, 17, 19, 22, 25,
16, 16, 17, 18, 20, 22, 25, 29,
16, 16, 18, 21, 24, 27, 31, 36,
17, 17, 20, 24, 30, 35, 41, 47,
18, 19, 22, 27, 35, 44, 54, 65,
21, 22, 25, 31, 41, 54, 70, 88,
24, 25, 29, 36, 47, 65, 88, 115
INTER16X16_LUMA
16, 16, 16, 16, 17, 18, 20, 24,
16, 16, 16, 17, 18, 20, 24, 25,
16, 16, 17, 18, 20, 24, 25, 28,
16, 17, 18, 20, 24, 25, 28, 33,
17, 18, 20, 24, 25, 28, 33, 41,
18, 20, 24, 25, 28, 33, 41, 54,
20, 24, 25, 28, 33, 41, 54, 71,
24, 25, 28, 33, 41, 54, 71, 91
INTER16X16_CHROMAU
16, 16, 16, 16, 17, 18, 20, 24,
16, 16, 16, 17, 18, 20, 24, 25,
16, 16, 17, 18, 20, 24, 25, 28,
16, 17, 18, 20, 24, 25, 28, 33,
17, 18, 20, 24, 25, 28, 33, 41,
18, 20, 24, 25, 28, 33, 41, 54,
20, 24, 25, 28, 33, 41, 54, 71,
24, 25, 28, 33, 41, 54, 71, 91
INTER16X16_CHROMAV
16, 16, 16, 16, 17, 18, 20, 24,
16, 16, 16, 17, 18, 20, 24, 25,
16, 16, 17, 18, 20, 24, 25, 28,
16, 17, 18, 20, 24, 25, 28, 33,
17, 18, 20, 24, 25, 28, 33, 41,
18, 20, 24, 25, 28, 33, 41, 54,
20, 24, 25, 28, 33, 41, 54, 71,
24, 25, 28, 33, 41, 54, 71, 91
INTRA32X32_LUMA
16, 16, 16, 16, 17, 18, 21, 24,
16, 16, 16, 16, 17, 19, 22, 25,
16, 16, 17, 18, 20, 22, 25, 29,
16, 16, 18, 21, 24, 27, 31, 36,
17, 17, 20, 24, 30, 35, 41, 47,
18, 19, 22, 27, 35, 44, 54, 65,
21, 22, 25, 31, 41, 54, 70, 88,
24, 25, 29, 36, 47, 65, 88, 115
INTER32X32_LUMA
16, 16, 16, 16, 17, 18, 20, 24,
16, 16, 16, 17, 18, 20, 24, 25,
16, 16, 17, 18, 20, 24, 25, 28,
16, 17, 18, 20, 24, 25, 28, 33,
17, 18, 20, 24, 25, 28, 33, 41,
18, 20, 24, 25, 28, 33, 41, 54,
20, 24, 25, 28, 33, 41, 54, 71,
24, 25, 28, 33, 41, 54, 71, 91
INTRA16X16_LUMA_DC
16
INTRA16X16_CHROMAU_DC
16
INTRA16X16_CHROMAV_DC
16
INTER16X16_LUMA_DC
16
INTER16X16_CHROMAU_DC
16
INTER16X16_CHROMAV_DC
16
INTRA32X32_LUMA_DC
16
INTER32X32_LUMA_DC
16
2014-02-11 10:55:21 +00:00
|
|
|
" --cqmfile <string> : Custom Quantization Matrices from a file\n"
|
2014-03-12 15:58:43 +00:00
|
|
|
" --debug <string> : Output encoders reconstruction.\n"
|
2014-10-14 09:01:56 +00:00
|
|
|
" --cpuid <integer> : Disable runtime cpu optimizations with value 0.\n"
|
2014-11-20 12:59:04 +00:00
|
|
|
" --subme <integer> : Set fractional pixel motion estimation level [1].\n"
|
|
|
|
" 0: only integer motion estimation\n"
|
|
|
|
" 1: fractional pixel motion estimation enabled\n"
|
2015-01-12 08:59:28 +00:00
|
|
|
" --pu-depth-inter <int>-<int> : Range for sizes of inter prediction units to try.\n"
|
|
|
|
" 0: 64x64, 1: 32x32, 2: 16x16, 3: 8x8\n"
|
|
|
|
" --pu-depth-intra <int>-<int> : Range for sizes of intra prediction units to try.\n"
|
|
|
|
" 0: 64x64, 1: 32x32, 2: 16x16, 3: 8x8, 4: 4x4\n"
|
2014-02-06 19:45:37 +00:00
|
|
|
"\n"
|
|
|
|
" Video Usability Information:\n"
|
|
|
|
" --sar <width:height> : Specify Sample Aspect Ratio\n"
|
|
|
|
" --overscan <string> : Specify crop overscan setting [\"undef\"]\n"
|
|
|
|
" - undef, show, crop\n"
|
|
|
|
" --videoformat <string> : Specify video format [\"undef\"]\n"
|
|
|
|
" - component, pal, ntsc, secam, mac, undef\n"
|
2014-02-08 02:29:50 +00:00
|
|
|
" --range <string> : Specify color range [\"tv\"]\n"
|
|
|
|
" - tv, pc\n"
|
2014-02-06 19:45:37 +00:00
|
|
|
" --colorprim <string> : Specify color primaries [\"undef\"]\n"
|
|
|
|
" - undef, bt709, bt470m, bt470bg,\n"
|
|
|
|
" smpte170m, smpte240m, film, bt2020\n"
|
|
|
|
" --transfer <string> : Specify transfer characteristics [\"undef\"]\n"
|
|
|
|
" - undef, bt709, bt470m, bt470bg,\n"
|
|
|
|
" smpte170m, smpte240m, linear, log100,\n"
|
|
|
|
" log316, iec61966-2-4, bt1361e,\n"
|
|
|
|
" iec61966-2-1, bt2020-10, bt2020-12\n"
|
|
|
|
" --colormatrix <string> : Specify color matrix setting [\"undef\"]\n"
|
|
|
|
" - undef, bt709, fcc, bt470bg, smpte170m,\n"
|
|
|
|
" smpte240m, GBR, YCgCo, bt2020nc, bt2020c\n"
|
2014-03-10 13:53:23 +00:00
|
|
|
" --chromaloc <integer> : Specify chroma sample location (0 to 5) [0]\n"
|
2014-04-02 08:38:03 +00:00
|
|
|
"\n"
|
2015-01-12 08:59:28 +00:00
|
|
|
" Parallel processing:\n"
|
2014-06-04 12:23:27 +00:00
|
|
|
" --threads <integer> : Maximum number of threads to use.\n"
|
|
|
|
" Disable threads if set to 0.\n"
|
|
|
|
"\n"
|
2014-04-02 08:38:03 +00:00
|
|
|
" Tiles:\n"
|
2014-09-15 01:40:18 +00:00
|
|
|
" --tiles-width-split <string>|u<int> : \n"
|
2014-04-02 08:38:03 +00:00
|
|
|
" Specifies a comma separated list of pixel\n"
|
|
|
|
" positions of tiles columns separation coordinates.\n"
|
|
|
|
" Can also be u followed by and a single int n,\n"
|
|
|
|
" in which case it produces columns of uniform width.\n"
|
2014-09-15 01:40:18 +00:00
|
|
|
" --tiles-height-split <string>|u<int> : \n"
|
2014-04-02 08:38:03 +00:00
|
|
|
" Specifies a comma separated list of pixel\n"
|
|
|
|
" positions of tiles rows separation coordinates.\n"
|
|
|
|
" Can also be u followed by and a single int n,\n"
|
|
|
|
" in which case it produces rows of uniform height.\n"
|
2014-03-10 13:53:23 +00:00
|
|
|
"\n"
|
2014-05-05 13:17:22 +00:00
|
|
|
" Wpp:\n"
|
2014-09-15 01:40:18 +00:00
|
|
|
" --wpp : Enable wavefront parallel processing\n"
|
2014-11-17 00:19:25 +00:00
|
|
|
" --owf <integer>|auto : Number of parallel frames to process. 0 to disable.\n"
|
2014-05-05 13:17:22 +00:00
|
|
|
"\n"
|
|
|
|
" Slices:\n"
|
|
|
|
" --slice-addresses <string>|u<int>: \n"
|
|
|
|
" Specifies a comma separated list of LCU\n"
|
|
|
|
" positions in tile scan order of tile separations.\n"
|
|
|
|
" Can also be u followed by and a single int n,\n"
|
|
|
|
" in which case it produces uniform slice length.\n"
|
|
|
|
"\n"
|
2014-03-10 13:53:23 +00:00
|
|
|
" Deprecated parameters: (might be removed at some point)\n"
|
|
|
|
" Use --input-res:\n"
|
|
|
|
" -w, --width : Width of input in pixels\n"
|
|
|
|
" -h, --height : Height of input in pixels\n");
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-04-17 08:58:03 +00:00
|
|
|
goto exit_failure;
|
2013-09-19 09:48:25 +00:00
|
|
|
}
|
|
|
|
|
2014-03-10 15:49:54 +00:00
|
|
|
// Add dimensions to the reconstructions file name.
|
|
|
|
if (cfg->debug != NULL) {
|
|
|
|
char dim_str[50]; // log10(2^64) < 20, so this should suffice. I hate C.
|
|
|
|
size_t left_len, right_len;
|
|
|
|
sprintf(dim_str, "_%dx%d.yuv", cfg->width, cfg->height);
|
|
|
|
left_len = strlen(cfg->debug);
|
|
|
|
right_len = strlen(dim_str);
|
2014-04-04 08:39:25 +00:00
|
|
|
cfg->debug = realloc(cfg->debug, left_len + right_len + 1);
|
|
|
|
if (!cfg->debug) {
|
2014-04-04 04:31:54 +00:00
|
|
|
fprintf(stderr, "realloc failed!\n");
|
2014-04-17 08:58:03 +00:00
|
|
|
goto exit_failure;
|
2014-04-03 10:32:56 +00:00
|
|
|
}
|
2014-04-04 04:31:54 +00:00
|
|
|
strcpy(cfg->debug + left_len, dim_str);
|
2014-03-10 15:49:54 +00:00
|
|
|
}
|
|
|
|
|
2014-11-17 00:19:25 +00:00
|
|
|
if (cfg->owf == -1) {
|
2014-12-05 12:42:09 +00:00
|
|
|
if (!config_set_owf_auto(cfg)) {
|
|
|
|
goto exit_failure;
|
2014-11-17 00:19:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-10 13:53:23 +00:00
|
|
|
// Do more validation to make sure the parameters we have make sense.
|
|
|
|
if (!config_validate(cfg)) {
|
2014-04-17 08:58:03 +00:00
|
|
|
goto exit_failure;
|
2014-03-10 13:53:23 +00:00
|
|
|
}
|
|
|
|
|
2014-10-14 09:01:56 +00:00
|
|
|
//Initialize strategies
|
|
|
|
if (!strategyselector_init(cfg->cpuid)) {
|
|
|
|
fprintf(stderr, "Failed to initialize strategies.\n");
|
|
|
|
goto exit_failure;
|
|
|
|
}
|
|
|
|
|
2014-01-31 12:32:41 +00:00
|
|
|
// Check if the input file name is a dash, this means stdin
|
|
|
|
if (!strcmp(cfg->input, "-")) {
|
|
|
|
input = stdin;
|
|
|
|
} else {
|
|
|
|
// Otherwise we try to open the input file
|
|
|
|
input = fopen(cfg->input, "rb");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that input was opened correctly
|
2013-09-19 09:48:25 +00:00
|
|
|
if (input == NULL) {
|
|
|
|
fprintf(stderr, "Could not open input file, shutting down!\n");
|
2014-04-17 08:58:03 +00:00
|
|
|
goto exit_failure;
|
2013-09-19 09:48:25 +00:00
|
|
|
}
|
2014-02-21 13:00:20 +00:00
|
|
|
|
2014-11-13 09:45:53 +00:00
|
|
|
// Check if the output file name is a dash, this means stdout
|
|
|
|
if (!strcmp(cfg->output, "-")) {
|
|
|
|
output = stdout;
|
|
|
|
} else {
|
|
|
|
// Otherwise we try to open the output file
|
|
|
|
output = fopen(cfg->output, "wb");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that output was opened correctly
|
2013-09-19 09:48:25 +00:00
|
|
|
if (output == NULL) {
|
|
|
|
fprintf(stderr, "Could not open output file, shutting down!\n");
|
2014-04-17 08:58:03 +00:00
|
|
|
goto exit_failure;
|
2013-09-19 09:48:25 +00:00
|
|
|
}
|
|
|
|
|
2014-03-10 16:07:48 +00:00
|
|
|
if (cfg->debug != NULL) {
|
|
|
|
recout = fopen(cfg->debug, "wb");
|
|
|
|
if (recout == NULL) {
|
|
|
|
fprintf(stderr, "Could not open reconstruction file (%s), shutting down!\n", cfg->debug);
|
2014-04-17 08:58:03 +00:00
|
|
|
goto exit_failure;
|
2014-03-10 16:07:48 +00:00
|
|
|
}
|
|
|
|
}
|
2014-04-17 12:42:20 +00:00
|
|
|
|
|
|
|
//Allocate and init exp golomb table
|
|
|
|
if (!init_exp_golomb(4096*8)) {
|
|
|
|
fprintf(stderr, "Failed to allocate the exp golomb code table, shutting down!\n");
|
2014-04-17 08:58:03 +00:00
|
|
|
goto exit_failure;
|
2014-04-17 12:42:20 +00:00
|
|
|
}
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2015-03-03 10:22:09 +00:00
|
|
|
// GOP
|
|
|
|
cfg->gop_len = 8;
|
2015-03-20 08:22:53 +00:00
|
|
|
cfg->gop[0].poc_offset = 8; cfg->gop[0].qp_offset = 1; cfg->gop[0].layer = 1; cfg->gop[0].qp_factor = 0.442; cfg->gop[0].is_ref = 1;
|
|
|
|
cfg->gop[0].ref_pos_count = 0;
|
|
|
|
cfg->gop[0].ref_neg_count = 3; cfg->gop[0].ref_neg[0] = 8; cfg->gop[0].ref_neg[1] = 12; cfg->gop[0].ref_neg[2] = 16;
|
|
|
|
|
|
|
|
cfg->gop[1].poc_offset = 4; cfg->gop[1].qp_offset = 2; cfg->gop[1].layer = 2; cfg->gop[1].qp_factor = 0.3536; cfg->gop[1].is_ref = 1;
|
|
|
|
cfg->gop[1].ref_neg_count = 2; cfg->gop[1].ref_neg[0] = 4; cfg->gop[1].ref_neg[1] = 8;
|
|
|
|
cfg->gop[1].ref_pos_count = 1; cfg->gop[1].ref_pos[0] = 4;
|
|
|
|
|
|
|
|
cfg->gop[2].poc_offset = 2; cfg->gop[2].qp_offset = 3; cfg->gop[2].layer = 3; cfg->gop[2].qp_factor = 0.3536; cfg->gop[2].is_ref = 1;
|
|
|
|
cfg->gop[2].ref_neg_count = 2; cfg->gop[2].ref_neg[0] = 2; cfg->gop[2].ref_neg[1] = 6;
|
|
|
|
cfg->gop[2].ref_pos_count = 2; cfg->gop[2].ref_pos[0] = 2; cfg->gop[2].ref_pos[1] = 6;
|
|
|
|
|
|
|
|
cfg->gop[3].poc_offset = 1; cfg->gop[3].qp_offset = 4; cfg->gop[3].layer = 4; cfg->gop[3].qp_factor = 0.68; cfg->gop[3].is_ref = 0;
|
|
|
|
cfg->gop[3].ref_neg_count = 1; cfg->gop[3].ref_neg[0] = 1;
|
|
|
|
cfg->gop[3].ref_pos_count = 3; cfg->gop[3].ref_pos[0] = 1; cfg->gop[3].ref_pos[1] = 3; cfg->gop[3].ref_pos[2] = 7;
|
|
|
|
|
|
|
|
cfg->gop[4].poc_offset = 3; cfg->gop[4].qp_offset = 4; cfg->gop[4].layer = 4; cfg->gop[4].qp_factor = 0.68; cfg->gop[4].is_ref = 0;
|
|
|
|
cfg->gop[4].ref_neg_count = 2; cfg->gop[4].ref_neg[0] = 1; cfg->gop[4].ref_neg[1] = 3;
|
|
|
|
cfg->gop[4].ref_pos_count = 2; cfg->gop[4].ref_pos[0] = 1; cfg->gop[4].ref_pos[1] = 5;
|
|
|
|
|
|
|
|
cfg->gop[5].poc_offset = 6; cfg->gop[5].qp_offset = 3; cfg->gop[5].layer = 3; cfg->gop[5].qp_factor = 0.3536; cfg->gop[5].is_ref = 1;
|
|
|
|
cfg->gop[5].ref_neg_count = 2; cfg->gop[5].ref_neg[0] = 2; cfg->gop[5].ref_neg[1] = 6;
|
|
|
|
cfg->gop[5].ref_pos_count = 1; cfg->gop[5].ref_pos[0] = 2;
|
|
|
|
|
|
|
|
cfg->gop[6].poc_offset = 5; cfg->gop[6].qp_offset = 4; cfg->gop[6].layer = 4; cfg->gop[6].qp_factor = 0.68; cfg->gop[6].is_ref = 0;
|
|
|
|
cfg->gop[6].ref_neg_count = 2; cfg->gop[6].ref_neg[0] = 1; cfg->gop[6].ref_neg[1] = 5;
|
|
|
|
cfg->gop[6].ref_pos_count = 2; cfg->gop[6].ref_pos[0] = 1; cfg->gop[6].ref_pos[1] = 3;
|
|
|
|
|
2015-03-23 12:17:44 +00:00
|
|
|
cfg->gop[7].poc_offset = 7; cfg->gop[7].qp_offset = 4; cfg->gop[7].layer = 4; cfg->gop[7].qp_factor = 0.68; cfg->gop[7].is_ref = 0;
|
2015-03-20 08:22:53 +00:00
|
|
|
cfg->gop[7].ref_neg_count = 3; cfg->gop[7].ref_neg[0] = 1; cfg->gop[7].ref_neg[1] = 3; cfg->gop[7].ref_neg[2] = 7;
|
|
|
|
cfg->gop[7].ref_pos_count = 1; cfg->gop[7].ref_pos[0] = 1;
|
|
|
|
|
2015-03-03 10:22:09 +00:00
|
|
|
|
2014-04-17 12:42:20 +00:00
|
|
|
if (!encoder_control_init(&encoder, cfg)) {
|
|
|
|
goto exit_failure;
|
|
|
|
}
|
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
// Set output file
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.out.file = output;
|
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
// input init (TODO: read from commandline / config)
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.bitdepth = 8;
|
|
|
|
encoder.in.video_format = FORMAT_420;
|
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
// deblocking filter
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.deblock_enable = (int8_t)encoder.cfg->deblock_enable;
|
|
|
|
encoder.beta_offset_div2 = (int8_t)encoder.cfg->deblock_beta;
|
|
|
|
encoder.tc_offset_div2 = (int8_t)encoder.cfg->deblock_tc;
|
2013-09-19 09:48:25 +00:00
|
|
|
// SAO
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.sao_enable = (int8_t)encoder.cfg->sao_enable;
|
2014-04-07 11:36:01 +00:00
|
|
|
// RDO
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.rdoq_enable = (int8_t)encoder.cfg->rdoq_enable;
|
|
|
|
encoder.rdo = (int8_t)encoder.cfg->rdo;
|
2015-01-24 18:10:21 +00:00
|
|
|
encoder.sign_hiding = encoder.cfg->signhide_enable;
|
2014-06-17 12:32:05 +00:00
|
|
|
encoder.full_intra_search = (int8_t)encoder.cfg->full_intra_search;
|
2014-04-02 11:41:40 +00:00
|
|
|
// TR SKIP
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.trskip_enable = (int8_t)encoder.cfg->trskip_enable;
|
2014-05-30 14:19:41 +00:00
|
|
|
encoder.tr_depth_intra = (int8_t)encoder.cfg->tr_depth_intra;
|
2014-11-20 12:59:04 +00:00
|
|
|
// MOTION ESTIMATION
|
|
|
|
encoder.fme_level = (int8_t)encoder.cfg->fme_level;
|
2014-02-06 19:45:37 +00:00
|
|
|
// VUI
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.vui.sar_width = (int16_t)encoder.cfg->vui.sar_width;
|
|
|
|
encoder.vui.sar_height = (int16_t)encoder.cfg->vui.sar_height;
|
|
|
|
encoder.vui.overscan = encoder.cfg->vui.overscan;
|
|
|
|
encoder.vui.videoformat = encoder.cfg->vui.videoformat;
|
|
|
|
encoder.vui.fullrange = encoder.cfg->vui.fullrange;
|
|
|
|
encoder.vui.colorprim = encoder.cfg->vui.colorprim;
|
|
|
|
encoder.vui.transfer = encoder.cfg->vui.transfer;
|
|
|
|
encoder.vui.colormatrix = encoder.cfg->vui.colormatrix;
|
|
|
|
encoder.vui.chroma_loc = (int8_t)encoder.cfg->vui.chroma_loc;
|
2014-02-06 22:35:15 +00:00
|
|
|
// AUD
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.aud_enable = (int8_t)encoder.cfg->aud_enable;
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2015-02-18 11:41:03 +00:00
|
|
|
encoder.vps_period = encoder.cfg->vps_period * encoder.cfg->intra_period;
|
2015-01-22 11:13:23 +00:00
|
|
|
|
2014-04-22 11:50:24 +00:00
|
|
|
encoder.in.file = input;
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-04-11 13:50:59 +00:00
|
|
|
fprintf(stderr, "Input: %s, output: %s\n", cfg->input, cfg->output);
|
2014-04-11 13:55:08 +00:00
|
|
|
fprintf(stderr, " Video size: %dx%d (input=%dx%d)\n",
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder.in.width, encoder.in.height,
|
|
|
|
encoder.in.real_width, encoder.in.real_height);
|
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
//Now, do the real stuff
|
|
|
|
{
|
2015-03-04 10:25:42 +00:00
|
|
|
encoder_state_t *encoder_states = malloc((encoder.owf + 1) * sizeof(encoder_state_t));
|
2014-06-10 08:59:31 +00:00
|
|
|
if (encoder_states == NULL) {
|
|
|
|
fprintf(stderr, "Failed to allocate memory.");
|
|
|
|
goto exit_failure;
|
|
|
|
}
|
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
int i;
|
|
|
|
int current_encoder_state = 0;
|
|
|
|
for (i = 0; i <= encoder.owf; ++i) {
|
|
|
|
encoder_states[i].encoder_control = &encoder;
|
|
|
|
if (i > 0) {
|
|
|
|
encoder_states[i].previous_encoder_state = &encoder_states[i-1];
|
|
|
|
} else {
|
|
|
|
//i == 0, use last encoder as the previous one
|
|
|
|
encoder_states[i].previous_encoder_state = &encoder_states[encoder.owf];
|
2014-03-10 12:58:57 +00:00
|
|
|
}
|
2014-06-05 07:09:25 +00:00
|
|
|
if (!encoder_state_init(&encoder_states[i], NULL)) {
|
|
|
|
goto exit_failure;
|
2014-03-10 12:58:57 +00:00
|
|
|
}
|
2014-06-05 07:09:25 +00:00
|
|
|
encoder_states[i].global->QP = (int8_t)encoder.cfg->qp;
|
2014-03-10 12:58:57 +00:00
|
|
|
}
|
2014-06-05 07:09:25 +00:00
|
|
|
|
|
|
|
for (i = 0; i <= encoder.owf; ++i) {
|
|
|
|
encoder_state_match_children_of_previous_frame(&encoder_states[i]);
|
2014-02-04 10:50:39 +00:00
|
|
|
}
|
2014-04-17 12:42:20 +00:00
|
|
|
|
2014-06-13 09:58:12 +00:00
|
|
|
//Initial frame
|
|
|
|
encoder_states[current_encoder_state].global->frame = -1;
|
2014-06-05 07:09:25 +00:00
|
|
|
|
|
|
|
// Only the code that handles conformance window coding needs to know
|
|
|
|
// the real dimensions. As a quick fix for broken non-multiple of 8 videos,
|
|
|
|
// change the input values here to be the real values. For a real fix
|
|
|
|
// encoder.in probably needs to be merged into cfg.
|
|
|
|
// The real fix would be: never go dig in cfg
|
|
|
|
//cfg->width = encoder.in.width;
|
|
|
|
//cfg->height = encoder.in.height;
|
2014-06-16 08:18:11 +00:00
|
|
|
|
|
|
|
GET_TIME(&encoding_start_real_time);
|
|
|
|
encoding_start_cpu_time = clock();
|
2014-06-05 07:09:25 +00:00
|
|
|
|
2015-01-22 10:16:46 +00:00
|
|
|
uint64_t bitstream_length = 0;
|
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
// Start coding cycle while data on input and not on the last frame
|
2014-06-16 11:21:52 +00:00
|
|
|
while(!cfg->frames || encoder_states[current_encoder_state].global->frame < cfg->frames - 1) {
|
2014-06-05 07:09:25 +00:00
|
|
|
// Skip '--seek' frames before input.
|
|
|
|
// This block can be moved outside this while loop when there is a
|
|
|
|
// mechanism to skip the while loop on error.
|
|
|
|
if (encoder_states[current_encoder_state].global->frame == 0 && cfg->seek > 0) {
|
|
|
|
int frame_bytes = cfg->width * cfg->height * 3 / 2;
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
if (!strcmp(cfg->input, "-")) {
|
|
|
|
// Input is stdin.
|
|
|
|
int i;
|
|
|
|
for (i = 0; !error && i < cfg->seek; ++i) {
|
|
|
|
error = !read_one_frame(input, &encoder_states[current_encoder_state]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// input is a file. We hope. Proper detection is OS dependent.
|
|
|
|
error = fseek(input, cfg->seek * frame_bytes, SEEK_CUR);
|
|
|
|
}
|
|
|
|
if (error && !feof(input)) {
|
|
|
|
fprintf(stderr, "Failed to seek %d frames.\n", cfg->seek);
|
|
|
|
break;
|
|
|
|
}
|
2014-06-16 08:18:11 +00:00
|
|
|
GET_TIME(&encoding_start_real_time);
|
|
|
|
encoding_start_cpu_time = clock();
|
2014-03-19 11:23:41 +00:00
|
|
|
}
|
2014-06-11 05:48:36 +00:00
|
|
|
|
2014-06-16 07:22:59 +00:00
|
|
|
//Compute stats
|
2015-01-22 10:16:46 +00:00
|
|
|
encoder_compute_stats(&encoder_states[current_encoder_state], recout, &stat_frames, psnr, &bitstream_length);
|
2014-06-16 07:22:59 +00:00
|
|
|
|
2014-06-13 09:58:12 +00:00
|
|
|
//Clear encoder
|
|
|
|
encoder_next_frame(&encoder_states[current_encoder_state]);
|
|
|
|
|
2014-06-18 04:45:53 +00:00
|
|
|
//Abort if enough frames
|
|
|
|
if (cfg->frames && encoder_states[current_encoder_state].global->frame >= cfg->frames) {
|
|
|
|
//Ignore this frame, which is not valid...
|
|
|
|
encoder_states[current_encoder_state].stats_done = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-06-11 05:48:36 +00:00
|
|
|
CHECKPOINT_MARK("read source frame: %d", encoder_states[current_encoder_state].global->frame + cfg->seek);
|
2014-06-05 07:09:25 +00:00
|
|
|
|
|
|
|
// Read one frame from the input
|
|
|
|
if (!read_one_frame(input, &encoder_states[current_encoder_state])) {
|
|
|
|
if (!feof(input))
|
|
|
|
fprintf(stderr, "Failed to read a frame %d\n", encoder_states[current_encoder_state].global->frame);
|
2014-06-16 11:21:52 +00:00
|
|
|
|
|
|
|
//Ignore this frame, which is not valid...
|
|
|
|
encoder_states[current_encoder_state].stats_done = 1;
|
2014-06-05 07:09:25 +00:00
|
|
|
break;
|
2014-03-19 11:23:41 +00:00
|
|
|
}
|
2014-06-05 07:09:25 +00:00
|
|
|
|
|
|
|
// The actual coding happens here, after this function we have a coded frame
|
|
|
|
encode_one_frame(&encoder_states[current_encoder_state]);
|
|
|
|
|
2014-06-13 09:58:12 +00:00
|
|
|
//Switch to the next encoder
|
|
|
|
current_encoder_state = (current_encoder_state + 1) % (encoder.owf + 1);
|
2014-06-05 07:09:25 +00:00
|
|
|
}
|
2014-06-16 07:22:59 +00:00
|
|
|
|
|
|
|
//Compute stats for the remaining encoders
|
|
|
|
{
|
|
|
|
int first_enc = current_encoder_state;
|
|
|
|
do {
|
|
|
|
current_encoder_state = (current_encoder_state + 1) % (encoder.owf + 1);
|
2015-01-22 10:16:46 +00:00
|
|
|
encoder_compute_stats(&encoder_states[current_encoder_state], recout, &stat_frames, psnr, &bitstream_length);
|
2014-06-16 07:22:59 +00:00
|
|
|
} while (current_encoder_state != first_enc);
|
|
|
|
}
|
|
|
|
|
2014-06-16 08:18:11 +00:00
|
|
|
GET_TIME(&encoding_end_real_time);
|
|
|
|
encoding_end_cpu_time = clock();
|
|
|
|
|
2014-06-13 09:58:12 +00:00
|
|
|
threadqueue_flush(encoder.threadqueue);
|
|
|
|
|
2014-06-16 07:22:59 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
// Coding finished
|
|
|
|
fgetpos(output,(fpos_t*)&curpos);
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
// Print statistics of the coding
|
2015-01-22 10:16:46 +00:00
|
|
|
fprintf(stderr, " Processed %d frames, %10llu bits AVG PSNR: %2.4f %2.4f %2.4f\n",
|
2015-01-23 13:50:14 +00:00
|
|
|
stat_frames, (long long unsigned int)bitstream_length * 8,
|
2015-01-22 10:16:46 +00:00
|
|
|
psnr[0] / stat_frames, psnr[1] / stat_frames, psnr[2] / stat_frames);
|
2014-06-16 08:18:11 +00:00
|
|
|
fprintf(stderr, " Total CPU time: %.3f s.\n", ((float)(clock() - start_time)) / CLOCKS_PER_SEC);
|
|
|
|
|
|
|
|
{
|
2014-11-14 14:38:07 +00:00
|
|
|
double encoding_time = ( (double)(encoding_end_cpu_time - encoding_start_cpu_time) ) / (double) CLOCKS_PER_SEC;
|
2014-06-16 08:18:11 +00:00
|
|
|
double wall_time = CLOCK_T_AS_DOUBLE(encoding_end_real_time) - CLOCK_T_AS_DOUBLE(encoding_start_real_time);
|
2014-11-14 14:38:07 +00:00
|
|
|
fprintf(stderr, " Encoding time: %.3f s.\n", encoding_time);
|
|
|
|
fprintf(stderr, " Encoding wall time: %.3f s.\n", wall_time);
|
|
|
|
fprintf(stderr, " Encoding CPU usage: %.2f%%\n", encoding_time/wall_time*100.f);
|
|
|
|
fprintf(stderr, " FPS: %.2f\n", ((double)stat_frames)/wall_time);
|
2014-06-16 08:18:11 +00:00
|
|
|
}
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
fclose(input);
|
|
|
|
fclose(output);
|
|
|
|
if(recout != NULL) fclose(recout);
|
|
|
|
|
|
|
|
for (i = 0; i <= encoder.owf; ++i) {
|
|
|
|
encoder_state_finalize(&encoder_states[i]);
|
|
|
|
}
|
2014-06-10 08:59:31 +00:00
|
|
|
|
|
|
|
free(encoder_states);
|
2014-06-05 07:09:25 +00:00
|
|
|
}
|
2013-09-19 09:48:25 +00:00
|
|
|
|
|
|
|
// Deallocating
|
|
|
|
config_destroy(cfg);
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder_control_finalize(&encoder);
|
|
|
|
|
2014-04-04 08:04:24 +00:00
|
|
|
free_exp_golomb();
|
2014-04-29 08:14:42 +00:00
|
|
|
|
|
|
|
strategyselector_free();
|
2014-06-11 05:48:36 +00:00
|
|
|
|
|
|
|
CHECKPOINTS_FINALIZE();
|
2013-09-19 09:48:25 +00:00
|
|
|
|
|
|
|
return EXIT_SUCCESS;
|
2014-04-17 08:58:03 +00:00
|
|
|
|
|
|
|
exit_failure:
|
|
|
|
if (cfg) config_destroy(cfg);
|
|
|
|
if (input) fclose(input);
|
|
|
|
if (output) fclose(output);
|
|
|
|
if (recout) fclose(recout);
|
2014-04-29 08:14:42 +00:00
|
|
|
strategyselector_free();
|
2014-06-11 05:48:36 +00:00
|
|
|
CHECKPOINTS_FINALIZE();
|
2014-04-17 08:58:03 +00:00
|
|
|
return EXIT_FAILURE;
|
2013-09-19 09:48:25 +00:00
|
|
|
}
|