2014-01-24 10:37:15 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* This file is part of Kvazaar HEVC encoder.
|
2014-02-21 13:00:20 +00:00
|
|
|
*
|
|
|
|
* Copyright (C) 2013-2014 Tampere University of Technology and others (see
|
2014-01-24 10:37:15 +00:00
|
|
|
* COPYING file).
|
|
|
|
*
|
|
|
|
* Kvazaar is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as published
|
|
|
|
* by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Kvazaar. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* \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
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
#include "global.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "encoder.h"
|
|
|
|
#include "cabac.h"
|
|
|
|
#include "picture.h"
|
|
|
|
#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
|
|
|
{
|
2013-09-19 09:48:25 +00:00
|
|
|
config *cfg = NULL; //!< Global configuration
|
|
|
|
FILE *input = NULL; //!< input file (YUV)
|
|
|
|
FILE *output = NULL; //!< output file (HEVC NAL stream)
|
2014-04-17 12:42:20 +00:00
|
|
|
encoder_control encoder;
|
2014-06-05 07:09:25 +00:00
|
|
|
//encoder_state encoder_state;
|
2014-04-17 12:42:20 +00:00
|
|
|
picture *cur_pic;
|
2013-09-19 09:48:25 +00:00
|
|
|
double psnr[3] = { 0.0, 0.0, 0.0 };
|
2013-11-12 10:04:54 +00:00
|
|
|
uint64_t curpos = 0;
|
|
|
|
uint64_t lastpos = 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-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-04-29 08:14:42 +00:00
|
|
|
//Initialize strategies
|
|
|
|
if (!strategyselector_init()) {
|
|
|
|
fprintf(stderr, "Failed to initialize strategies.\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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"
|
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"
|
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-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-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"
|
2014-06-04 12:23:27 +00:00
|
|
|
" Parallel processing :\n"
|
|
|
|
" --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"
|
|
|
|
" --tiles-width-split <string>|u<int>: \n"
|
|
|
|
" 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"
|
|
|
|
" --tiles-height-split <string>|u<int>: \n"
|
|
|
|
" 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"
|
|
|
|
" --wpp: Enable wavefront parallel processing\n"
|
|
|
|
"\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-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-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
|
|
|
|
2013-09-19 09:48:25 +00:00
|
|
|
// Open output file and check that it was opened correctly
|
|
|
|
output = fopen(cfg->output, "wb");
|
|
|
|
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
|
|
|
|
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;
|
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-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
|
|
|
|
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
|
|
|
|
{
|
|
|
|
encoder_state encoder_states[encoder.owf + 1];
|
|
|
|
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-05 07:09:25 +00:00
|
|
|
encoder_states[current_encoder_state].global->frame = 0;
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
// Start coding cycle while data on input and not on the last frame
|
|
|
|
while(!cfg->frames || encoder_states[current_encoder_state].global->frame < cfg->frames) {
|
|
|
|
int32_t diff;
|
|
|
|
double temp_psnr[3];
|
|
|
|
|
|
|
|
// 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-03-19 11:23:41 +00:00
|
|
|
}
|
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);
|
|
|
|
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]);
|
|
|
|
|
|
|
|
cur_pic = encoder_states[current_encoder_state].tile->cur_pic;
|
|
|
|
|
|
|
|
if (cfg->debug != NULL) {
|
|
|
|
// Write reconstructed frame out.
|
|
|
|
// Use conformance-window dimensions instead of internal ones.
|
|
|
|
const int width = cur_pic->width;
|
|
|
|
const int out_width = encoder.in.real_width;
|
|
|
|
const int out_height = encoder.in.real_height;
|
|
|
|
int y;
|
|
|
|
const pixel *y_rec = cur_pic->y_recdata;
|
|
|
|
const pixel *u_rec = cur_pic->u_recdata;
|
|
|
|
const pixel *v_rec = cur_pic->v_recdata;
|
|
|
|
|
|
|
|
for (y = 0; y < out_height; ++y) {
|
|
|
|
fwrite(&y_rec[y * width], sizeof(*y_rec), out_width, recout);
|
|
|
|
}
|
|
|
|
for (y = 0; y < out_height / 2; ++y) {
|
|
|
|
fwrite(&u_rec[y * width / 2], sizeof(*u_rec), out_width / 2, recout);
|
|
|
|
}
|
|
|
|
for (y = 0; y < out_height / 2; ++y) {
|
|
|
|
fwrite(&v_rec[y * width / 2], sizeof(*v_rec), out_width / 2, recout);
|
|
|
|
}
|
2014-03-19 11:23:41 +00:00
|
|
|
}
|
2012-05-30 12:10:23 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
// Calculate the bytes pushed to output for this frame
|
|
|
|
fgetpos(output,(fpos_t*)&curpos);
|
|
|
|
diff = (int32_t)(curpos-lastpos);
|
|
|
|
lastpos = curpos;
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
// PSNR calculations
|
|
|
|
temp_psnr[0] = image_psnr(cur_pic->y_data, cur_pic->y_recdata, cfg->width, cfg->height);
|
|
|
|
temp_psnr[1] = image_psnr(cur_pic->u_data, cur_pic->u_recdata, cfg->width>>1, cfg->height>>1);
|
|
|
|
temp_psnr[2] = image_psnr(cur_pic->v_data, cur_pic->v_recdata, cfg->width>>1, cfg->height>>1);
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
fprintf(stderr, "POC %4d (%c-frame) %10d bits PSNR: %2.4f %2.4f %2.4f\n", encoder_states[current_encoder_state].global->frame,
|
|
|
|
"BPI"[encoder_states[current_encoder_state].global->slicetype%3], diff<<3,
|
|
|
|
temp_psnr[0], temp_psnr[1], temp_psnr[2]);
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
// Increment total PSNR
|
|
|
|
psnr[0] += temp_psnr[0];
|
|
|
|
psnr[1] += temp_psnr[1];
|
|
|
|
psnr[2] += temp_psnr[2];
|
2013-09-19 09:48:25 +00:00
|
|
|
|
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
// TODO: add more than one reference
|
2013-09-19 09:48:25 +00:00
|
|
|
|
2014-06-05 07:09:25 +00:00
|
|
|
encoder_next_frame(&encoder_states[current_encoder_state]);
|
|
|
|
}
|
|
|
|
// 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
|
|
|
|
fprintf(stderr, " Processed %d frames, %10llu bits AVG PSNR: %2.4f %2.4f %2.4f\n", encoder_states[current_encoder_state].global->frame, (long long unsigned int) curpos<<3,
|
|
|
|
psnr[0] / encoder_states[current_encoder_state].global->frame, psnr[1] / encoder_states[current_encoder_state].global->frame, psnr[2] / encoder_states[current_encoder_state].global->frame);
|
|
|
|
fprintf(stderr, " Total time: %.3f s.\n", ((float)(clock() - start_time)) / CLOCKS_PER_SEC);
|
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]);
|
|
|
|
}
|
|
|
|
}
|
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();
|
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-04-17 08:58:03 +00:00
|
|
|
return EXIT_FAILURE;
|
2013-09-19 09:48:25 +00:00
|
|
|
}
|