Merge branch 'options'

This commit is contained in:
Ari Koivula 2014-02-07 14:21:26 +02:00
commit 903484387f
7 changed files with 348 additions and 50 deletions

View file

@ -14,16 +14,38 @@ meant to be user configurable later.
Usage:
hevc_encoder -i <input> -w <width> -h <height> -o <output>
Optional parameters:
-n, --frames <integer> : number of frames to code [all]
-q, --qp <integer> : Quantization Parameter [32]
-p, --period <integer> : Period of intra pictures [0]
0: only first picture is intra
1: all pictures are intra
2-N: every Nth picture is intra
--no-deblock : Disable deblocking filter
--deblock <beta:tc> : Deblocking filter parameters
beta and tc range is -6..6 [0:0]
--no-sao : Disable sample adaptive offset
-n, --frames <integer> : number of frames to code [all]
-q, --qp <integer> : Quantization Parameter [32]
-p, --period <integer> : Period of intra pictures [0]
0: only first picture is intra
1: all pictures are intra
2-N: every Nth picture is intra
--no-deblock : Disable deblocking filter
--deblock <beta:tc> : Deblocking filter parameters
beta and tc range is -6..6 [0:0]
--no-sao : Disable sample adaptive offset
--aud : Use access unit delimiters
Video Usability Information:
--sar <width:height> : Specify Sample Aspect Ratio
--overscan <string> : Specify crop overscan setting ["undef"]
- undef, show, crop
--videoformat <string> : Specify video format ["undef"]
- component, pal, ntsc, secam, mac, undef
--range <string> : Specify color range ["off"]
- off, on
--colorprim <string> : Specify color primaries ["undef"]
- undef, bt709, bt470m, bt470bg,
smpte170m, smpte240m, film, bt2020
--transfer <string> : Specify transfer characteristics ["undef"]
- undef, bt709, bt470m, bt470bg,
smpte170m, smpte240m, linear, log100,
log316, iec61966-2-4, bt1361e,
iec61966-2-1, bt2020-10, bt2020-12
--colormatrix <string> : Specify color matrix setting ["undef"]
- undef, bt709, fcc, bt470bg, smpte170m,
smpte240m, GBR, YCgCo, bt2020nc, bt2020c
--chromaloc <integer> : Specify chroma sample location (0 to 5) [0]
Example:

View file

@ -52,18 +52,28 @@ config *config_alloc()
*/
int config_init(config *cfg)
{
cfg->input = NULL;
cfg->output = NULL;
cfg->debug = NULL;
cfg->frames = 0;
cfg->width = 320;
cfg->height = 240;
cfg->qp = 32;
cfg->intra_period = 0;
cfg->deblock_enable = 1;
cfg->deblock_beta = 0;
cfg->deblock_tc = 0;
cfg->sao_enable = 1;
cfg->input = NULL;
cfg->output = NULL;
cfg->debug = NULL;
cfg->frames = 0;
cfg->width = 320;
cfg->height = 240;
cfg->qp = 32;
cfg->intra_period = 0;
cfg->deblock_enable = 1;
cfg->deblock_beta = 0;
cfg->deblock_tc = 0;
cfg->sao_enable = 1;
cfg->vui.sar_width = 0;
cfg->vui.sar_height = 0;
cfg->vui.overscan = 0; /* undef */
cfg->vui.videoformat = 5; /* undef */
cfg->vui.fullrange = 0; /* limited range */
cfg->vui.colorprim = 2; /* undef */
cfg->vui.transfer = 2; /* undef */
cfg->vui.colormatrix = 2; /* undef */
cfg->vui.chroma_loc = 0; /* left center */
cfg->aud_enable = 0;
return 1;
}
@ -115,9 +125,33 @@ static int atobool(const char *str)
return 0;
}
static int config_parse(config *cfg, const char *name, const char *value)
static int parse_enum(const char *arg, const char * const *names, int8_t *dst)
{
int i;
for (i = 0; names[i]; i++)
if (!strcmp(arg, names[i])) {
*dst = i;
return 1;
}
return 0;
}
static int config_parse(config *cfg, const char *name, const char *value)
{
static const char * const overscan_names[] = { "undef", "show", "crop", NULL };
static const char * const videoformat_names[] = { "component", "pal", "ntsc", "secam", "mac", "undef", NULL };
static const char * const fullrange_names[] = { "off", "on", NULL };
static const char * const colorprim_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m",
"smpte240m", "film", "bt2020", NULL };
static const char * const transfer_names[] = { "", "bt709", "undef", "", "bt470m", "bt470bg", "smpte170m",
"smpte240m", "linear", "log100", "log316", "iec61966-2-4",
"bt1361e", "iec61966-2-1", "bt2020-10", "bt2020-12", NULL };
static const char * const colormatrix_names[] = { "GBR", "bt709", "undef", "", "fcc", "bt470bg", "smpte170m",
"smpte240m", "YCgCo", "bt2020nc", "bt2020c", NULL };
int i;
int error = 0;
if (!name)
return 0;
@ -171,11 +205,40 @@ static int config_parse(config *cfg, const char *name, const char *value)
}
OPT("sao")
cfg->sao_enable = atobool(value);
OPT("sar") {
int sar_width, sar_height;
if (2 == sscanf(value, "%d:%d", &sar_width, &sar_height)) {
cfg->vui.sar_width = sar_width;
cfg->vui.sar_height = sar_height;
} else
error = 1;
}
OPT("overscan")
error = !parse_enum(value, overscan_names, &cfg->vui.overscan);
OPT("videoformat")
error = !parse_enum(value, videoformat_names, &cfg->vui.videoformat);
OPT("fullrange")
error = !parse_enum(value, fullrange_names, &cfg->vui.fullrange);
OPT("colorprim")
error = !parse_enum(value, colorprim_names, &cfg->vui.colorprim);
OPT("transfer")
error = !parse_enum(value, transfer_names, &cfg->vui.transfer);
OPT("colormatrix")
error = !parse_enum(value, colormatrix_names, &cfg->vui.colormatrix);
OPT("chromaloc") {
cfg->vui.chroma_loc = atoi(value);
if (cfg->vui.chroma_loc < 0 || cfg->vui.chroma_loc > 5) {
fprintf(stderr, "--chromaloc parameter out of range [0..5], set to 0\n");
cfg->vui.chroma_loc = 0;
}
}
OPT("aud")
cfg->aud_enable = atobool(value);
else
return 0;
#undef OPT
return 1;
return error ? 0 : 1;
}
/**
@ -205,6 +268,15 @@ int config_read(config *cfg,int argc, char *argv[])
{ "no-deblock", no_argument, NULL, 0 },
{ "deblock", required_argument, NULL, 0 },
{ "no-sao", no_argument, NULL, 0 },
{ "sar", required_argument, NULL, 0 },
{ "overscan", required_argument, NULL, 0 },
{ "videoformat", required_argument, NULL, 0 },
{ "range", required_argument, NULL, 0 },
{ "colorprim", required_argument, NULL, 0 },
{ "transfer", required_argument, NULL, 0 },
{ "colormatrix", required_argument, NULL, 0 },
{ "chromaloc", required_argument, NULL, 0 },
{ "aud", no_argument, NULL, 0 },
{0, 0, 0, 0}
};

View file

@ -45,6 +45,19 @@ typedef struct
int8_t sao_enable; /*!< \brief Flag to enable sample adaptive offset filter */
int8_t deblock_beta; /*!< \brief (deblocking) beta offset (div 2), range -6...6 */
int8_t deblock_tc; /*!< \brief (deblocking) tc offset (div 2), range -6...6 */
struct
{
int16_t sar_width; /*!< \brief the horizontal size of the sample aspect ratio (in arbitrary units) */
int16_t sar_height; /*!< \brief the vertical size of the sample aspect ratio (in the same arbitrary units as sar_width). */
int8_t overscan; /*!< \brief Crop overscan setting */
int8_t videoformat; /*!< \brief Video format */
int8_t fullrange; /*!< \brief Flag to indicate full-range */
int8_t colorprim; /*!< \brief Color primaries */
int8_t transfer; /*!< \brief Transfer characteristics */
int8_t colormatrix; /*!< \brief Color matrix coefficients */
int8_t chroma_loc; /*!< \brief Chroma sample location */
} vui;
int8_t aud_enable; /*!< \brief Flag to use access unit delimiters */
} config;
/* Function definitions */

View file

@ -82,24 +82,47 @@ int main(int argc, char *argv[])
if (!cfg || !config_init(cfg) || !config_read(cfg,argc,argv)) {
fprintf(stderr,
"/***********************************************/\n"
" * Kvazaar HEVC Encoder v. " VERSION_STRING "*\n"
" * Kvazaar HEVC Encoder v. " VERSION_STRING " *\n"
" * Tampere University of Technology 2014 *\n"
"/***********************************************/\n\n");
fprintf(stderr,
"Usage:\n"
"hevc_encoder -i <input> -w <width> -h <height> -o <output>\n"
"\n"
"Optional parameters:\n"
" -n, --frames <integer> : number of frames to code [all]\n"
" -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"
" --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");
" -n, --frames <integer> : number of frames to code [all]\n"
" -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"
" --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"
" --aud : Use access unit delimiters\n"
"\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"
" --range <string> : Specify color range [\"off\"]\n"
" - off, on\n"
" --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"
" --chromaloc <integer> : Specify chroma sample location (0 to 5) [0]\n");
if (cfg)
config_destroy(cfg);
@ -167,6 +190,18 @@ int main(int argc, char *argv[])
encoder->tc_offset_div2 = encoder->cfg->deblock_tc;
// SAO
encoder->sao_enable = encoder->cfg->sao_enable;
// VUI
encoder->vui.sar_width = encoder->cfg->vui.sar_width;
encoder->vui.sar_height = 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 = encoder->cfg->vui.chroma_loc;
// AUD
encoder->aud_enable = encoder->cfg->aud_enable;
init_encoder_input(&encoder->in, input, cfg->width, cfg->height);

View file

@ -47,6 +47,7 @@ uint32_t* g_sig_last_scan[3][7];
/* Local functions. */
static void add_checksum(encoder_control* encoder);
static void encode_VUI(encoder_control* encoder);
void init_sig_last_scan(uint32_t *buff_d, uint32_t *buff_h, uint32_t *buff_v,
int32_t width, int32_t height)
@ -366,7 +367,17 @@ void init_encoder_input(encoder_input *input, FILE *inputfile,
input->height);
}
#endif
}
}
static void write_aud(encoder_control* encoder)
{
encode_access_unit_delimiter(encoder);
bitstream_align(encoder->stream);
bitstream_flush(encoder->stream);
nal_write(encoder->output, encoder->stream->buffer,
encoder->stream->buffer_pos, 0, AUD_NUT, 0, 1);
bitstream_clear_buffer(encoder->stream);
}
void encode_one_frame(encoder_control* encoder)
{
@ -383,6 +394,13 @@ void encode_one_frame(encoder_control* encoder)
(encoder->cfg->intra_period != 1 || encoder->frame % 2 == 0 ) ) ) {
encoder->poc = 0;
encoder->in.cur_pic->slicetype = SLICE_I;
encoder->in.cur_pic->type = NAL_IDR_W_RADL;
// Access Unit Delimiter (AUD)
if (encoder->aud_enable)
write_aud(encoder);
// Video Parameter Set (VPS)
encode_vid_parameter_set(encoder);
bitstream_align(encoder->stream);
@ -407,10 +425,17 @@ void encode_one_frame(encoder_control* encoder)
encoder->stream->buffer_pos, 0, NAL_PPS_NUT, 0, 1);
bitstream_clear_buffer(encoder->stream);
if (encoder->frame == 0) {
encode_prefix_sei_version(encoder);
bitstream_align(encoder->stream);
bitstream_flush(encoder->stream);
nal_write(encoder->output, encoder->stream->buffer,
encoder->stream->buffer_pos, 0, PREFIX_SEI_NUT, 0, 0);
bitstream_clear_buffer(encoder->stream);
}
// First slice is IDR
cabac_start(&cabac);
encoder->in.cur_pic->slicetype = SLICE_I;
encoder->in.cur_pic->type = NAL_IDR_W_RADL;
scalinglist_process();
search_slice_data(encoder);
@ -424,10 +449,15 @@ void encode_one_frame(encoder_control* encoder)
encoder->stream->buffer_pos, 0, NAL_IDR_W_RADL, 0, 0);
bitstream_clear_buffer(encoder->stream);
} else {
cabac_start(&cabac);
// When intra period == 1, all pictures are intra
encoder->in.cur_pic->slicetype = encoder->cfg->intra_period==1 ? SLICE_I : SLICE_P;
encoder->in.cur_pic->type = NAL_TRAIL_R;
// Access Unit Delimiter (AUD)
if (encoder->aud_enable)
write_aud(encoder);
cabac_start(&cabac);
scalinglist_process();
search_slice_data(encoder);
@ -438,7 +468,7 @@ void encode_one_frame(encoder_control* encoder)
bitstream_align(encoder->stream);
bitstream_flush(encoder->stream);
nal_write(encoder->output, encoder->stream->buffer,
encoder->stream->buffer_pos, 0, NAL_TRAIL_R, 0, 1);
encoder->stream->buffer_pos, 0, NAL_TRAIL_R, 0, encoder->aud_enable ? 0 : 1);
bitstream_clear_buffer(encoder->stream);
}
@ -557,6 +587,60 @@ static void add_checksum(encoder_control* encoder)
bitstream_clear_buffer(encoder->stream);
}
void encode_access_unit_delimiter(encoder_control* encoder)
{
uint8_t pic_type = encoder->in.cur_pic->slicetype == SLICE_I ? 0
: encoder->in.cur_pic->slicetype == SLICE_P ? 1
: 2;
WRITE_U(encoder->stream, pic_type, 3, "pic_type");
}
void encode_prefix_sei_version(encoder_control* encoder)
{
#define STR_BUF_LEN 1000
int i, length;
char buf[STR_BUF_LEN] = { 0 };
char *s = buf + 16;
config *cfg = encoder->cfg;
// random uuid_iso_iec_11578 generated with www.famkruithof.net/uuid/uuidgen
static const uint8_t uuid[16] = {
0x32, 0xfe, 0x46, 0x6c, 0x98, 0x41, 0x42, 0x69,
0xae, 0x35, 0x6a, 0x91, 0x54, 0x9e, 0xf3, 0xf1
};
memcpy(buf, uuid, 16);
// user_data_payload_byte
s += sprintf(s, "Kvazaar HEVC Encoder v. " VERSION_STRING " - "
"Copyleft 2012-2014 - http://ultravideo.cs.tut.fi/ - options:");
s += sprintf(s, " %dx%d", cfg->width, cfg->height);
s += sprintf(s, " deblock=%d:%d:%d", cfg->deblock_enable,
cfg->deblock_beta, cfg->deblock_tc);
s += sprintf(s, " sao=%d", cfg->sao_enable);
s += sprintf(s, " intra_period=%d", cfg->intra_period);
s += sprintf(s, " qp=%d", cfg->qp);
length = (int)(s - buf + 1); // length, +1 for \0
// Assert this so that in the future if the message gets longer, we remember
// to increase the buf len. Divide by 2 for margin.
assert(length < STR_BUF_LEN / 2);
// payloadType = 5 -> user_data_unregistered
WRITE_U(encoder->stream, 5, 8, "last_payload_type_byte");
// payloadSize
for (i = 0; i <= length - 255; i += 255)
WRITE_U(encoder->stream, 255, 8, "ff_byte");
WRITE_U(encoder->stream, length - i, 8, "last_payload_size_byte");
for (i = 0; i < length; i++)
WRITE_U(encoder->stream, ((uint8_t *)buf)[i], 8, "sei_payload");
#undef STR_BUF_LEN
}
void encode_pic_parameter_set(encoder_control* encoder)
{
#ifdef _DEBUG
@ -751,10 +835,9 @@ void encode_seq_parameter_set(encoder_control* encoder)
WRITE_U(encoder->stream, ENABLE_TEMPORAL_MVP, 1,
"sps_temporal_mvp_enable_flag");
WRITE_U(encoder->stream, 0, 1, "sps_strong_intra_smoothing_enable_flag");
WRITE_U(encoder->stream, 0, 1, "vui_parameters_present_flag");
WRITE_U(encoder->stream, 1, 1, "vui_parameters_present_flag");
//TODO: VUI?
//encode_VUI(encoder);
encode_VUI(encoder);
WRITE_U(encoder->stream, 0, 1, "sps_extension_flag");
}
@ -794,27 +877,82 @@ void encode_vid_parameter_set(encoder_control* encoder)
WRITE_U(encoder->stream, 0, 1, "vps_extension_flag");
}
void encode_VUI(encoder_control* encoder)
static void encode_VUI(encoder_control* encoder)
{
#ifdef _DEBUG
printf("=========== VUI Set ID: 0 ===========\n");
#endif
WRITE_U(encoder->stream, 0, 1, "aspect_ratio_info_present_flag");
if (encoder->vui.sar_width > 0 && encoder->vui.sar_height > 0) {
int i;
static const struct
{
uint8_t width;
uint8_t height;
uint8_t idc;
} sar[] = {
// aspect_ratio_idc = 0 -> unspecified
{ 1, 1, 1 }, { 12, 11, 2 }, { 10, 11, 3 }, { 16, 11, 4 },
{ 40, 33, 5 }, { 24, 11, 6 }, { 20, 11, 7 }, { 32, 11, 8 },
{ 80, 33, 9 }, { 18, 11, 10}, { 15, 11, 11}, { 64, 33, 12},
{160, 99, 13}, { 4, 3, 14}, { 3, 2, 15}, { 2, 1, 16},
// aspect_ratio_idc = [17..254] -> reserved
{ 0, 0, 255 }
};
for (i = 0; sar[i].idc != 255; i++)
if (sar[i].width == encoder->vui.sar_width &&
sar[i].height == encoder->vui.sar_height)
break;
WRITE_U(encoder->stream, 1, 1, "aspect_ratio_info_present_flag");
WRITE_U(encoder->stream, sar[i].idc, 8, "aspect_ratio_idc");
if (sar[i].idc == 255) {
// EXTENDED_SAR
WRITE_U(encoder->stream, encoder->vui.sar_width, 16, "sar_width");
WRITE_U(encoder->stream, encoder->vui.sar_height, 16, "sar_height");
}
} else
WRITE_U(encoder->stream, 0, 1, "aspect_ratio_info_present_flag");
//IF aspect ratio info
//ENDIF
WRITE_U(encoder->stream, 0, 1, "overscan_info_present_flag");
if (encoder->vui.overscan > 0) {
WRITE_U(encoder->stream, 1, 1, "overscan_info_present_flag");
WRITE_U(encoder->stream, encoder->vui.overscan - 1, 1, "overscan_appropriate_flag");
} else
WRITE_U(encoder->stream, 0, 1, "overscan_info_present_flag");
//IF overscan info
//ENDIF
WRITE_U(encoder->stream, 0, 1, "video_signal_type_present_flag");
if (encoder->vui.videoformat != 5 || encoder->vui.fullrange ||
encoder->vui.colorprim != 2 || encoder->vui.transfer != 2 ||
encoder->vui.colormatrix != 2) {
WRITE_U(encoder->stream, 1, 1, "video_signal_type_present_flag");
WRITE_U(encoder->stream, encoder->vui.videoformat, 3, "video_format");
WRITE_U(encoder->stream, encoder->vui.fullrange, 1, "video_full_range_flag");
if (encoder->vui.colorprim != 2 || encoder->vui.transfer != 2 ||
encoder->vui.colormatrix != 2) {
WRITE_U(encoder->stream, 1, 1, "colour_description_present_flag");
WRITE_U(encoder->stream, encoder->vui.colorprim, 8, "colour_primaries");
WRITE_U(encoder->stream, encoder->vui.transfer, 8, "transfer_characteristics");
WRITE_U(encoder->stream, encoder->vui.colormatrix, 8, "matrix_coeffs");
} else
WRITE_U(encoder->stream, 0, 1, "colour_description_present_flag");
} else
WRITE_U(encoder->stream, 0, 1, "video_signal_type_present_flag");
//IF video type
//ENDIF
WRITE_U(encoder->stream, 0, 1, "chroma_loc_info_present_flag");
if (encoder->vui.chroma_loc > 0) {
WRITE_U(encoder->stream, 1, 1, "chroma_loc_info_present_flag");
WRITE_UE(encoder->stream, encoder->vui.chroma_loc, "chroma_sample_loc_type_top_field");
WRITE_UE(encoder->stream, encoder->vui.chroma_loc, "chroma_sample_loc_type_bottom_field");
} else
WRITE_U(encoder->stream, 0, 1, "chroma_loc_info_present_flag");
//IF chroma loc info
//ENDIF

View file

@ -78,6 +78,22 @@ typedef struct
int8_t sao_enable; // \brief Flag to enable sample adaptive offset filter
int8_t beta_offset_div2; // \brief (deblocking) beta offset (div 2), range -6...6
int8_t tc_offset_div2; // \brief (deblocking)tc offset (div 2), range -6...6
/* VUI */
struct
{
int16_t sar_width;
int16_t sar_height;
int8_t overscan;
int8_t videoformat;
int8_t fullrange;
int8_t colorprim;
int8_t transfer;
int8_t colormatrix;
int8_t chroma_loc;
} vui;
int8_t aud_enable;
} encoder_control;
void init_tables(void);
@ -94,6 +110,8 @@ void encode_pic_parameter_set(encoder_control *encoder);
void encode_vid_parameter_set(encoder_control *encoder);
void encode_slice_data(encoder_control *encoder);
void encode_slice_header(encoder_control *encoder);
void encode_access_unit_delimiter(encoder_control* encoder);
void encode_prefix_sei_version(encoder_control* encoder);
void encode_coding_tree(encoder_control *encoder, uint16_t x_ctb,
uint16_t y_ctb, uint8_t depth);
void encode_last_significant_xy(encoder_control *encoder, uint8_t lastpos_x,

View file

@ -22,7 +22,7 @@
/*
* \file
* \brief Header that is included in every other header.
´*
*
* This file contains global constants that can be referred to from any header
* or source file. It also contains some helper macros and includes stdint.h
* so that any file can refer to integer types with exact widths.
@ -109,7 +109,7 @@ typedef int16_t coefficient;
//#define SIGN3(x) ((x) > 0) ? +1 : ((x) == 0 ? 0 : -1)
#define SIGN3(x) (((x) > 0) - ((x) < 0))
#define VERSION_STRING "0.2.3 "
#define VERSION_STRING "0.2.3"
#define VERSION 0.2
//#define VERBOSE 1