[x265] [PATCH 1 of 2] zone: add support to parse zone files

bhavna at multicorewareinc.com bhavna at multicorewareinc.com
Thu Dec 20 12:03:38 CET 2018


# HG changeset patch
# User Bhavna Hariharan <bhavna at multicorewareinc.com>
# Date 1544769275 -19800
#      Fri Dec 14 12:04:35 2018 +0530
# Node ID 592b83c9068d7f402c85394fcf113b767b58f08d
# Parent  1f44f1f1623d677c80469e713ed642f6673af91d
zone: add support to parse zone files

diff -r 1f44f1f1623d -r 592b83c9068d doc/reST/cli.rst
--- a/doc/reST/cli.rst	Mon Dec 17 16:49:08 2018 +0530
+++ b/doc/reST/cli.rst	Fri Dec 14 12:04:35 2018 +0530
@@ -1826,6 +1826,20 @@
 
 	If zones overlap, whichever comes later in the list takes precedence.
 	Default none
+	
+	
+.. option:: --zonefile <filename>
+
+	Specify a text file which contains the boundaries of the zones where 
+	each of zones are configurable. The format of each line is:
+
+	<frame number> <options to be configured>
+
+	The frame number indicates the beginning of a zone. The options 
+	following this is applied until another zone begins. The reconfigurable 
+	options can be spcified as --<feature name> <feature value>
+	
+	**CLI ONLY**
 
 Quantization Options
 ====================
diff -r 1f44f1f1623d -r 592b83c9068d source/common/param.cpp
--- a/source/common/param.cpp	Mon Dec 17 16:49:08 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;
@@ -564,6 +565,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 1f44f1f1623d -r 592b83c9068d source/common/param.h
--- a/source/common/param.h	Mon Dec 17 16:49:08 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 1f44f1f1623d -r 592b83c9068d source/encoder/api.cpp
--- a/source/encoder/api.cpp	Mon Dec 17 16:49:08 2018 +0530
+++ b/source/encoder/api.cpp	Fri Dec 14 12:04:35 2018 +0530
@@ -674,9 +674,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 1f44f1f1623d -r 592b83c9068d source/x265.cpp
--- a/source/x265.cpp	Mon Dec 17 16:49:08 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 1f44f1f1623d -r 592b83c9068d source/x265.h
--- a/source/x265.h	Mon Dec 17 16:49:08 2018 +0530
+++ b/source/x265.h	Fri Dec 14 12:04:35 2018 +0530
@@ -659,6 +659,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
@@ -667,6 +669,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 */
@@ -1395,6 +1398,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
@@ -1773,6 +1779,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",
@@ -2066,6 +2074,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 1f44f1f1623d -r 592b83c9068d source/x265cli.h
--- a/source/x265cli.h	Mon Dec 17 16:49:08 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 },
@@ -541,6 +542,7 @@
     H1("                                   where <option> is either\n");
     H1("                                       q=<integer> (force QP)\n");
     H1("                                   or  b=<float> (bitrate multiplier)\n");
+    H0("   --zonefile <filename>         Zone file containing the zone boundaries and the parameters to be reconfigured.\n");
     H1("   --lambda-file <string>        Specify a file containing replacement values for the lambda tables\n");
     H1("                                 MAX_MAX_QP+1 floats for lambda table, then again for lambda2 table\n");
     H1("                                 Blank lines and lines starting with hash(#) are ignored\n");
-------------- next part --------------
A non-text attachment was scrubbed...
Name: x265-clean-1.patch
Type: text/x-patch
Size: 16488 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20181220/96893e53/attachment-0001.bin>


More information about the x265-devel mailing list