# HG changeset patch # User Bhavna Hariharan <bha...@multicorewareinc.com> # Date 1544769275 -19800 # Fri Dec 14 12:04:35 2018 +0530 # Node ID d50593a06791dd9db6d17e5ca43955e306a4a4b4 # Parent 81373aab81dfe2e31a5ef353b1073d8bf1e22502 zone: add support to parse zone files
diff -r 81373aab81df -r d50593a06791 source/common/param.cpp --- a/source/common/param.cpp Thu Dec 13 10:55:15 2018 +0530 +++ b/source/common/param.cpp Fri Dec 14 12:04:35 2018 +0530 @@ -244,6 +244,7 @@ param->rc.complexityBlur = 20; param->rc.qblur = 0.5; param->rc.zoneCount = 0; + param->rc.zonefileCount = 0; param->rc.zones = NULL; param->rc.bEnableSlowFirstPass = 1; param->rc.bStrictCbr = 0; @@ -563,6 +564,104 @@ return x265_atoi(arg, bError); } +/* internal versions of string-to-int with additional error checking */ +#undef atoi +#undef atof +#define atoi(str) x265_atoi(str, bError) +#define atof(str) x265_atof(str, bError) +#define atobool(str) (x265_atobool(str, bError)) + +int x265_zone_param_parse(x265_param* p, const char* name, const char* value) +{ + bool bError = false; + char nameBuf[64]; + + if (!name) + return X265_PARAM_BAD_NAME; + + // skip -- prefix if provided + if (name[0] == '-' && name[1] == '-') + name += 2; + + // s/_/-/g + if (strlen(name) + 1 < sizeof(nameBuf) && strchr(name, '_')) + { + char *c; + strcpy(nameBuf, name); + while ((c = strchr(nameBuf, '_')) != 0) + *c = '-'; + + name = nameBuf; + } + + if (!strncmp(name, "no-", 3)) + { + name += 3; + value = !value || x265_atobool(value, bError) ? "false" : "true"; + } + else if (!strncmp(name, "no", 2)) + { + name += 2; + value = !value || x265_atobool(value, bError) ? "false" : "true"; + } + else if (!value) + value = "true"; + else if (value[0] == '=') + value++; + +#define OPT(STR) else if (!strcmp(name, STR)) +#define OPT2(STR1, STR2) else if (!strcmp(name, STR1) || !strcmp(name, STR2)) + + if (0); + OPT("ref") p->maxNumReferences = atoi(value); + OPT("fast-intra") p->bEnableFastIntra = atobool(value); + OPT("early-skip") p->bEnableEarlySkip = atobool(value); + OPT("rskip") p->bEnableRecursionSkip = atobool(value); + OPT("me")p->searchMethod = parseName(value, x265_motion_est_names, bError); + OPT("subme") p->subpelRefine = atoi(value); + OPT("merange") p->searchRange = atoi(value); + OPT("rect") p->bEnableRectInter = atobool(value); + OPT("amp") p->bEnableAMP = atobool(value); + OPT("max-merge") p->maxNumMergeCand = (uint32_t)atoi(value); + OPT("rd") p->rdLevel = atoi(value); + OPT2("rdoq", "rdoq-level") + { + int bval = atobool(value); + if (bError || bval) + { + bError = false; + p->rdoqLevel = atoi(value); + } + else + p->rdoqLevel = 0; + } + OPT("b-intra") p->bIntraInBFrames = atobool(value); + OPT("scaling-list") p->scalingLists = strdup(value); + OPT("aq-mode") p->rc.aqMode = atoi(value); + OPT("aq-strength") p->rc.aqStrength = atof(value); + OPT("nr-intra") p->noiseReductionIntra = atoi(value); + OPT("nr-inter") p->noiseReductionInter = atoi(value); + OPT("limit-modes") p->limitModes = atobool(value); + OPT("splitrd-skip") p->bEnableSplitRdSkip = atobool(value); + OPT("cu-lossless") p->bCULossless = atobool(value); + OPT("rd-refine") p->bEnableRdRefine = atobool(value); + OPT("limit-tu") p->limitTU = atoi(value); + OPT("tskip") p->bEnableTransformSkip = atobool(value); + OPT("tskip-fast") p->bEnableTSkipFast = atobool(value); + OPT("rdpenalty") p->rdPenalty = atoi(value); + OPT("dynamic-rd") p->dynamicRd = atof(value); + else + return X265_PARAM_BAD_NAME; + +#undef OPT +#undef OPT2 + + return bError ? X265_PARAM_BAD_VALUE : 0; +} + +#undef atobool +#undef atoi +#undef atof /* internal versions of string-to-int with additional error checking */ #undef atoi diff -r 81373aab81df -r d50593a06791 source/common/param.h --- a/source/common/param.h Thu Dec 13 10:55:15 2018 +0530 +++ b/source/common/param.h Fri Dec 14 12:04:35 2018 +0530 @@ -51,6 +51,7 @@ int x265_param_default_preset(x265_param *, const char *preset, const char *tune); int x265_param_apply_profile(x265_param *, const char *profile); int x265_param_parse(x265_param *p, const char *name, const char *value); +int x265_zone_param_parse(x265_param* p, const char* name, const char* value); #define PARAM_NS X265_NS #endif } diff -r 81373aab81df -r d50593a06791 source/encoder/api.cpp --- a/source/encoder/api.cpp Thu Dec 13 10:55:15 2018 +0530 +++ b/source/encoder/api.cpp Fri Dec 14 12:04:35 2018 +0530 @@ -673,9 +673,9 @@ #if ENABLE_LIBVMAF &x265_calculate_vmafscore, &x265_calculate_vmaf_framelevelscore, - &x265_vmaf_encoder_log + &x265_vmaf_encoder_log, #endif - + &PARAM_NS::x265_zone_param_parse }; typedef const x265_api* (*api_get_func)(int bitDepth); diff -r 81373aab81df -r d50593a06791 source/x265.cpp --- a/source/x265.cpp Thu Dec 13 10:55:15 2018 +0530 +++ b/source/x265.cpp Fri Dec 14 12:04:35 2018 +0530 @@ -74,6 +74,7 @@ ReconFile* recon; OutputFile* output; FILE* qpfile; + FILE* zoneFile; FILE* dolbyVisionRpu; /* File containing Dolby Vision BL RPU metadata */ const char* reconPlayCmd; const x265_api* api; @@ -97,6 +98,7 @@ recon = NULL; output = NULL; qpfile = NULL; + zoneFile = NULL; dolbyVisionRpu = NULL; reconPlayCmd = NULL; api = NULL; @@ -114,7 +116,9 @@ void destroy(); void printStatus(uint32_t frameNum); bool parse(int argc, char **argv); + bool parseZoneParam(int argc, char **argv, x265_param* globalParam, int zonefileCount); bool parseQPFile(x265_picture &pic_org); + bool parseZoneFile(); }; void CLIOptions::destroy() @@ -128,6 +132,9 @@ if (qpfile) fclose(qpfile); qpfile = NULL; + if (zoneFile) + fclose(zoneFile); + zoneFile = NULL; if (dolbyVisionRpu) fclose(dolbyVisionRpu); dolbyVisionRpu = NULL; @@ -163,6 +170,110 @@ prevUpdateTime = time; } +bool CLIOptions::parseZoneParam(int argc, char **argv, x265_param* globalParam, int zonefileCount) +{ + bool bError = false; + int bShowHelp = false; + int outputBitDepth = 0; + const char *profile = NULL; + + /* Presets are applied before all other options. */ + for (optind = 0;;) + { + int c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) + break; + else if (c == 'D') + outputBitDepth = atoi(optarg); + else if (c == 'P') + profile = optarg; + else if (c == '?') + bShowHelp = true; + } + + if (!outputBitDepth && profile) + { + /* try to derive the output bit depth from the requested profile */ + if (strstr(profile, "10")) + outputBitDepth = 10; + else if (strstr(profile, "12")) + outputBitDepth = 12; + else + outputBitDepth = 8; + } + + api = x265_api_get(outputBitDepth); + if (!api) + { + x265_log(NULL, X265_LOG_WARNING, "falling back to default bit-depth\n"); + api = x265_api_get(0); + } + + if (bShowHelp) + { + printVersion(globalParam, api); + showHelp(globalParam); + } + + globalParam->rc.zones[zonefileCount].zoneParam = api->param_alloc(); + if (!globalParam->rc.zones[zonefileCount].zoneParam) + { + x265_log(NULL, X265_LOG_ERROR, "param alloc failed\n"); + return true; + } + + memcpy(globalParam->rc.zones[zonefileCount].zoneParam, globalParam, sizeof(x265_param)); + + for (optind = 0;;) + { + int long_options_index = -1; + int c = getopt_long(argc, argv, short_options, long_options, &long_options_index); + if (c == -1) + break; + + if (long_options_index < 0 && c > 0) + { + for (size_t i = 0; i < sizeof(long_options) / sizeof(long_options[0]); i++) + { + if (long_options[i].val == c) + { + long_options_index = (int)i; + break; + } + } + + if (long_options_index < 0) + { + /* getopt_long might have already printed an error message */ + if (c != 63) + x265_log(NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c); + return true; + } + } + if (long_options_index < 0) + { + x265_log(NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c); + return true; + } + + bError |= !!api->zone_param_parse(globalParam->rc.zones[zonefileCount].zoneParam, long_options[long_options_index].name, optarg); + + if (bError) + { + const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind - 2]; + x265_log(NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg); + return true; + } + } + + if (optind < argc) + { + x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]); + return true; + } + return false; +} + bool CLIOptions::parse(int argc, char **argv) { bool bError = false; @@ -327,6 +438,12 @@ return true; } } + OPT("zonefile") + { + this->zoneFile = x265_fopen(optarg, "rb"); + if (!this->zoneFile) + x265_log_file(param, X265_LOG_ERROR, "%s zone file not found or error in opening zone file\n", optarg); + } OPT("fullhelp") { param->logLevel = X265_LOG_FULL; @@ -535,6 +652,59 @@ return 1; } +bool CLIOptions::parseZoneFile() +{ + char line[256]; + char* argLine; + param->rc.zonefileCount = 0; + + while (fgets(line, sizeof(line), zoneFile)) + { + if (!((*line == '#') || (strcmp(line, "\r\n") == 0))) + param->rc.zonefileCount++; + } + + rewind(zoneFile); + param->rc.zones = X265_MALLOC(x265_zone, param->rc.zonefileCount); + for (int i = 0; i < param->rc.zonefileCount; i++) + { + while (fgets(line, sizeof(line), zoneFile)) + { + if (*line == '#' || (strcmp(line, "\r\n") == 0)) + continue; + param->rc.zones[i].zoneParam = X265_MALLOC(x265_param, 1); + int index = (int)strcspn(line, "\r\n"); + line[index] = '\0'; + argLine = line; + while (isspace((unsigned char)*argLine)) argLine++; + char* start = strchr(argLine, ' '); + start++; + param->rc.zones[i].startFrame = atoi(argLine); + int argCount = 0; + char **args = (char**)malloc(256 * sizeof(char *)); + // Adding a dummy string to avoid file parsing error + args[argCount++] = (char *)"x265"; + char* token = strtok(start, " "); + while (token) + { + args[argCount++] = token; + token = strtok(NULL, " "); + } + args[argCount] = '\0'; + CLIOptions cliopt; + if (cliopt.parseZoneParam(argCount, args,param, i)) + { + cliopt.destroy(); + if (cliopt.api) + cliopt.api->param_free(cliopt.param); + exit(1); + } + break; + } + } + return 1; +} + #ifdef _WIN32 /* Copy of x264 code, which allows for Unicode characters in the command line. * Retrieve command line arguments as UTF-8. */ @@ -667,6 +837,16 @@ if (cliopt.reconPlayCmd) reconPlay = new ReconPlay(cliopt.reconPlayCmd, *param); + if (cliopt.zoneFile) + { + if (!cliopt.parseZoneFile()) + { + x265_log(NULL, X265_LOG_ERROR, "Unable to parse zonefile\n"); + fclose(cliopt.zoneFile); + cliopt.zoneFile = NULL; + } + } + /* note: we could try to acquire a different libx265 API here based on * the profile found during option parsing, but it must be done before * opening an encoder */ diff -r 81373aab81df -r d50593a06791 source/x265.h --- a/source/x265.h Thu Dec 13 10:55:15 2018 +0530 +++ b/source/x265.h Fri Dec 14 12:04:35 2018 +0530 @@ -654,6 +654,8 @@ static const char * const x265_interlace_names[] = { "prog", "tff", "bff", 0 }; static const char * const x265_analysis_names[] = { "off", "save", "load", 0 }; +struct x265_zone; +struct x265_param; /* Zones: override ratecontrol for specific sections of the video. * If zones overlap, whichever comes later in the list takes precedence. */ typedef struct x265_zone @@ -662,6 +664,7 @@ int bForceQp; /* whether to use qp vs bitrate factor */ int qp; float bitrateFactor; + x265_param* zoneParam; } x265_zone; /* data to calculate aggregate VMAF score */ @@ -1390,6 +1393,9 @@ int zoneCount; x265_zone* zones; + /* number of zones in zone-file*/ + int zonefileCount; + /* specify a text file which contains MAX_MAX_QP + 1 floating point * values to be copied into x265_lambda_tab and a second set of * MAX_MAX_QP + 1 floating point values for x265_lambda2_tab. All values @@ -1763,6 +1769,8 @@ #define X265_PARAM_BAD_VALUE (-2) int x265_param_parse(x265_param *p, const char *name, const char *value); +int x265_zone_param_parse(x265_param* p, const char* name, const char* value); + static const char * const x265_profile_names[] = { /* HEVC v1 */ "main", "main10", "mainstillpicture", /* alias */ "msp", @@ -2056,6 +2064,7 @@ double (*calculate_vmaf_framelevelscore)(x265_vmaf_framedata *); void (*vmaf_encoder_log)(x265_encoder*, int, char**, x265_param *, x265_vmaf_data *); #endif + int (*zone_param_parse)(x265_param*, const char*, const char*); /* add new pointers to the end, or increment X265_MAJOR_VERSION */ } x265_api; diff -r 81373aab81df -r d50593a06791 source/x265cli.h --- a/source/x265cli.h Thu Dec 13 10:55:15 2018 +0530 +++ b/source/x265cli.h Fri Dec 14 12:04:35 2018 +0530 @@ -242,6 +242,7 @@ { "no-info", no_argument, NULL, 0 }, { "zones", required_argument, NULL, 0 }, { "qpfile", required_argument, NULL, 0 }, + { "zonefile", required_argument, NULL, 0 }, { "lambda-file", required_argument, NULL, 0 }, { "b-intra", no_argument, NULL, 0 }, { "no-b-intra", no_argument, NULL, 0 },
# HG changeset patch # User Bhavna Hariharan <bha...@multicorewareinc.com> # Date 1544769275 -19800 # Fri Dec 14 12:04:35 2018 +0530 # Node ID d50593a06791dd9db6d17e5ca43955e306a4a4b4 # Parent 81373aab81dfe2e31a5ef353b1073d8bf1e22502 zone: add support to parse zone files diff -r 81373aab81df -r d50593a06791 source/common/param.cpp --- a/source/common/param.cpp Thu Dec 13 10:55:15 2018 +0530 +++ b/source/common/param.cpp Fri Dec 14 12:04:35 2018 +0530 @@ -244,6 +244,7 @@ param->rc.complexityBlur = 20; param->rc.qblur = 0.5; param->rc.zoneCount = 0; + param->rc.zonefileCount = 0; param->rc.zones = NULL; param->rc.bEnableSlowFirstPass = 1; param->rc.bStrictCbr = 0; @@ -563,6 +564,104 @@ return x265_atoi(arg, bError); } +/* internal versions of string-to-int with additional error checking */ +#undef atoi +#undef atof +#define atoi(str) x265_atoi(str, bError) +#define atof(str) x265_atof(str, bError) +#define atobool(str) (x265_atobool(str, bError)) + +int x265_zone_param_parse(x265_param* p, const char* name, const char* value) +{ + bool bError = false; + char nameBuf[64]; + + if (!name) + return X265_PARAM_BAD_NAME; + + // skip -- prefix if provided + if (name[0] == '-' && name[1] == '-') + name += 2; + + // s/_/-/g + if (strlen(name) + 1 < sizeof(nameBuf) && strchr(name, '_')) + { + char *c; + strcpy(nameBuf, name); + while ((c = strchr(nameBuf, '_')) != 0) + *c = '-'; + + name = nameBuf; + } + + if (!strncmp(name, "no-", 3)) + { + name += 3; + value = !value || x265_atobool(value, bError) ? "false" : "true"; + } + else if (!strncmp(name, "no", 2)) + { + name += 2; + value = !value || x265_atobool(value, bError) ? "false" : "true"; + } + else if (!value) + value = "true"; + else if (value[0] == '=') + value++; + +#define OPT(STR) else if (!strcmp(name, STR)) +#define OPT2(STR1, STR2) else if (!strcmp(name, STR1) || !strcmp(name, STR2)) + + if (0); + OPT("ref") p->maxNumReferences = atoi(value); + OPT("fast-intra") p->bEnableFastIntra = atobool(value); + OPT("early-skip") p->bEnableEarlySkip = atobool(value); + OPT("rskip") p->bEnableRecursionSkip = atobool(value); + OPT("me")p->searchMethod = parseName(value, x265_motion_est_names, bError); + OPT("subme") p->subpelRefine = atoi(value); + OPT("merange") p->searchRange = atoi(value); + OPT("rect") p->bEnableRectInter = atobool(value); + OPT("amp") p->bEnableAMP = atobool(value); + OPT("max-merge") p->maxNumMergeCand = (uint32_t)atoi(value); + OPT("rd") p->rdLevel = atoi(value); + OPT2("rdoq", "rdoq-level") + { + int bval = atobool(value); + if (bError || bval) + { + bError = false; + p->rdoqLevel = atoi(value); + } + else + p->rdoqLevel = 0; + } + OPT("b-intra") p->bIntraInBFrames = atobool(value); + OPT("scaling-list") p->scalingLists = strdup(value); + OPT("aq-mode") p->rc.aqMode = atoi(value); + OPT("aq-strength") p->rc.aqStrength = atof(value); + OPT("nr-intra") p->noiseReductionIntra = atoi(value); + OPT("nr-inter") p->noiseReductionInter = atoi(value); + OPT("limit-modes") p->limitModes = atobool(value); + OPT("splitrd-skip") p->bEnableSplitRdSkip = atobool(value); + OPT("cu-lossless") p->bCULossless = atobool(value); + OPT("rd-refine") p->bEnableRdRefine = atobool(value); + OPT("limit-tu") p->limitTU = atoi(value); + OPT("tskip") p->bEnableTransformSkip = atobool(value); + OPT("tskip-fast") p->bEnableTSkipFast = atobool(value); + OPT("rdpenalty") p->rdPenalty = atoi(value); + OPT("dynamic-rd") p->dynamicRd = atof(value); + else + return X265_PARAM_BAD_NAME; + +#undef OPT +#undef OPT2 + + return bError ? X265_PARAM_BAD_VALUE : 0; +} + +#undef atobool +#undef atoi +#undef atof /* internal versions of string-to-int with additional error checking */ #undef atoi diff -r 81373aab81df -r d50593a06791 source/common/param.h --- a/source/common/param.h Thu Dec 13 10:55:15 2018 +0530 +++ b/source/common/param.h Fri Dec 14 12:04:35 2018 +0530 @@ -51,6 +51,7 @@ int x265_param_default_preset(x265_param *, const char *preset, const char *tune); int x265_param_apply_profile(x265_param *, const char *profile); int x265_param_parse(x265_param *p, const char *name, const char *value); +int x265_zone_param_parse(x265_param* p, const char* name, const char* value); #define PARAM_NS X265_NS #endif } diff -r 81373aab81df -r d50593a06791 source/encoder/api.cpp --- a/source/encoder/api.cpp Thu Dec 13 10:55:15 2018 +0530 +++ b/source/encoder/api.cpp Fri Dec 14 12:04:35 2018 +0530 @@ -673,9 +673,9 @@ #if ENABLE_LIBVMAF &x265_calculate_vmafscore, &x265_calculate_vmaf_framelevelscore, - &x265_vmaf_encoder_log + &x265_vmaf_encoder_log, #endif - + &PARAM_NS::x265_zone_param_parse }; typedef const x265_api* (*api_get_func)(int bitDepth); diff -r 81373aab81df -r d50593a06791 source/x265.cpp --- a/source/x265.cpp Thu Dec 13 10:55:15 2018 +0530 +++ b/source/x265.cpp Fri Dec 14 12:04:35 2018 +0530 @@ -74,6 +74,7 @@ ReconFile* recon; OutputFile* output; FILE* qpfile; + FILE* zoneFile; FILE* dolbyVisionRpu; /* File containing Dolby Vision BL RPU metadata */ const char* reconPlayCmd; const x265_api* api; @@ -97,6 +98,7 @@ recon = NULL; output = NULL; qpfile = NULL; + zoneFile = NULL; dolbyVisionRpu = NULL; reconPlayCmd = NULL; api = NULL; @@ -114,7 +116,9 @@ void destroy(); void printStatus(uint32_t frameNum); bool parse(int argc, char **argv); + bool parseZoneParam(int argc, char **argv, x265_param* globalParam, int zonefileCount); bool parseQPFile(x265_picture &pic_org); + bool parseZoneFile(); }; void CLIOptions::destroy() @@ -128,6 +132,9 @@ if (qpfile) fclose(qpfile); qpfile = NULL; + if (zoneFile) + fclose(zoneFile); + zoneFile = NULL; if (dolbyVisionRpu) fclose(dolbyVisionRpu); dolbyVisionRpu = NULL; @@ -163,6 +170,110 @@ prevUpdateTime = time; } +bool CLIOptions::parseZoneParam(int argc, char **argv, x265_param* globalParam, int zonefileCount) +{ + bool bError = false; + int bShowHelp = false; + int outputBitDepth = 0; + const char *profile = NULL; + + /* Presets are applied before all other options. */ + for (optind = 0;;) + { + int c = getopt_long(argc, argv, short_options, long_options, NULL); + if (c == -1) + break; + else if (c == 'D') + outputBitDepth = atoi(optarg); + else if (c == 'P') + profile = optarg; + else if (c == '?') + bShowHelp = true; + } + + if (!outputBitDepth && profile) + { + /* try to derive the output bit depth from the requested profile */ + if (strstr(profile, "10")) + outputBitDepth = 10; + else if (strstr(profile, "12")) + outputBitDepth = 12; + else + outputBitDepth = 8; + } + + api = x265_api_get(outputBitDepth); + if (!api) + { + x265_log(NULL, X265_LOG_WARNING, "falling back to default bit-depth\n"); + api = x265_api_get(0); + } + + if (bShowHelp) + { + printVersion(globalParam, api); + showHelp(globalParam); + } + + globalParam->rc.zones[zonefileCount].zoneParam = api->param_alloc(); + if (!globalParam->rc.zones[zonefileCount].zoneParam) + { + x265_log(NULL, X265_LOG_ERROR, "param alloc failed\n"); + return true; + } + + memcpy(globalParam->rc.zones[zonefileCount].zoneParam, globalParam, sizeof(x265_param)); + + for (optind = 0;;) + { + int long_options_index = -1; + int c = getopt_long(argc, argv, short_options, long_options, &long_options_index); + if (c == -1) + break; + + if (long_options_index < 0 && c > 0) + { + for (size_t i = 0; i < sizeof(long_options) / sizeof(long_options[0]); i++) + { + if (long_options[i].val == c) + { + long_options_index = (int)i; + break; + } + } + + if (long_options_index < 0) + { + /* getopt_long might have already printed an error message */ + if (c != 63) + x265_log(NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c); + return true; + } + } + if (long_options_index < 0) + { + x265_log(NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c); + return true; + } + + bError |= !!api->zone_param_parse(globalParam->rc.zones[zonefileCount].zoneParam, long_options[long_options_index].name, optarg); + + if (bError) + { + const char *name = long_options_index > 0 ? long_options[long_options_index].name : argv[optind - 2]; + x265_log(NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", name, optarg); + return true; + } + } + + if (optind < argc) + { + x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", argv[optind]); + return true; + } + return false; +} + bool CLIOptions::parse(int argc, char **argv) { bool bError = false; @@ -327,6 +438,12 @@ return true; } } + OPT("zonefile") + { + this->zoneFile = x265_fopen(optarg, "rb"); + if (!this->zoneFile) + x265_log_file(param, X265_LOG_ERROR, "%s zone file not found or error in opening zone file\n", optarg); + } OPT("fullhelp") { param->logLevel = X265_LOG_FULL; @@ -535,6 +652,59 @@ return 1; } +bool CLIOptions::parseZoneFile() +{ + char line[256]; + char* argLine; + param->rc.zonefileCount = 0; + + while (fgets(line, sizeof(line), zoneFile)) + { + if (!((*line == '#') || (strcmp(line, "\r\n") == 0))) + param->rc.zonefileCount++; + } + + rewind(zoneFile); + param->rc.zones = X265_MALLOC(x265_zone, param->rc.zonefileCount); + for (int i = 0; i < param->rc.zonefileCount; i++) + { + while (fgets(line, sizeof(line), zoneFile)) + { + if (*line == '#' || (strcmp(line, "\r\n") == 0)) + continue; + param->rc.zones[i].zoneParam = X265_MALLOC(x265_param, 1); + int index = (int)strcspn(line, "\r\n"); + line[index] = '\0'; + argLine = line; + while (isspace((unsigned char)*argLine)) argLine++; + char* start = strchr(argLine, ' '); + start++; + param->rc.zones[i].startFrame = atoi(argLine); + int argCount = 0; + char **args = (char**)malloc(256 * sizeof(char *)); + // Adding a dummy string to avoid file parsing error + args[argCount++] = (char *)"x265"; + char* token = strtok(start, " "); + while (token) + { + args[argCount++] = token; + token = strtok(NULL, " "); + } + args[argCount] = '\0'; + CLIOptions cliopt; + if (cliopt.parseZoneParam(argCount, args,param, i)) + { + cliopt.destroy(); + if (cliopt.api) + cliopt.api->param_free(cliopt.param); + exit(1); + } + break; + } + } + return 1; +} + #ifdef _WIN32 /* Copy of x264 code, which allows for Unicode characters in the command line. * Retrieve command line arguments as UTF-8. */ @@ -667,6 +837,16 @@ if (cliopt.reconPlayCmd) reconPlay = new ReconPlay(cliopt.reconPlayCmd, *param); + if (cliopt.zoneFile) + { + if (!cliopt.parseZoneFile()) + { + x265_log(NULL, X265_LOG_ERROR, "Unable to parse zonefile\n"); + fclose(cliopt.zoneFile); + cliopt.zoneFile = NULL; + } + } + /* note: we could try to acquire a different libx265 API here based on * the profile found during option parsing, but it must be done before * opening an encoder */ diff -r 81373aab81df -r d50593a06791 source/x265.h --- a/source/x265.h Thu Dec 13 10:55:15 2018 +0530 +++ b/source/x265.h Fri Dec 14 12:04:35 2018 +0530 @@ -654,6 +654,8 @@ static const char * const x265_interlace_names[] = { "prog", "tff", "bff", 0 }; static const char * const x265_analysis_names[] = { "off", "save", "load", 0 }; +struct x265_zone; +struct x265_param; /* Zones: override ratecontrol for specific sections of the video. * If zones overlap, whichever comes later in the list takes precedence. */ typedef struct x265_zone @@ -662,6 +664,7 @@ int bForceQp; /* whether to use qp vs bitrate factor */ int qp; float bitrateFactor; + x265_param* zoneParam; } x265_zone; /* data to calculate aggregate VMAF score */ @@ -1390,6 +1393,9 @@ int zoneCount; x265_zone* zones; + /* number of zones in zone-file*/ + int zonefileCount; + /* specify a text file which contains MAX_MAX_QP + 1 floating point * values to be copied into x265_lambda_tab and a second set of * MAX_MAX_QP + 1 floating point values for x265_lambda2_tab. All values @@ -1763,6 +1769,8 @@ #define X265_PARAM_BAD_VALUE (-2) int x265_param_parse(x265_param *p, const char *name, const char *value); +int x265_zone_param_parse(x265_param* p, const char* name, const char* value); + static const char * const x265_profile_names[] = { /* HEVC v1 */ "main", "main10", "mainstillpicture", /* alias */ "msp", @@ -2056,6 +2064,7 @@ double (*calculate_vmaf_framelevelscore)(x265_vmaf_framedata *); void (*vmaf_encoder_log)(x265_encoder*, int, char**, x265_param *, x265_vmaf_data *); #endif + int (*zone_param_parse)(x265_param*, const char*, const char*); /* add new pointers to the end, or increment X265_MAJOR_VERSION */ } x265_api; diff -r 81373aab81df -r d50593a06791 source/x265cli.h --- a/source/x265cli.h Thu Dec 13 10:55:15 2018 +0530 +++ b/source/x265cli.h Fri Dec 14 12:04:35 2018 +0530 @@ -242,6 +242,7 @@ { "no-info", no_argument, NULL, 0 }, { "zones", required_argument, NULL, 0 }, { "qpfile", required_argument, NULL, 0 }, + { "zonefile", required_argument, NULL, 0 }, { "lambda-file", required_argument, NULL, 0 }, { "b-intra", no_argument, NULL, 0 }, { "no-b-intra", no_argument, NULL, 0 },
_______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel