<div dir="ltr">From dba87b3da6bea98ce677bc7be006b928c9d7f8d0 Mon Sep 17 00:00:00 2001<br>From: Kirithika <<a href="mailto:kirithika@multicorewareinc.com" target="_blank">kirithika@multicorewareinc.com</a>><br>Date: Wed, 10 Jul 2024 16:06:01 +0530<br>Subject: [PATCH] Add compile time configuration and support for parsing<br> multiview config file<br><br>---<br> doc/reST/cli.rst        |  30 +++++++<br> source/CMakeLists.txt   |   7 +-<br> source/common/param.cpp |  21 +++++<br> source/x265.h           |   9 ++<br> source/x265cli.cpp      | 176 ++++++++++++++++++++++++++++++++++++++--<br> source/x265cli.h        |  13 +++<br> 6 files changed, 249 insertions(+), 7 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index 4d5ac1a15..298ee334a 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -2893,4 +2893,34 @@ Alpha Encode Options<br> <br> **CLI_ONLY**<br> <br>+Multiview Encode Options<br>+===================<br>+<br>+ Enable multiview encoding support in x265.This option can be enabled<br>+ only when ENABLE_MULTIVIEW is set during the make of x265.<br>+<br>+.. option:: --num-views <integer><br>+      Specify the number of views in the multiview input video.<br>+<br>+.. option:: --format <integer><br>+  Specify the format of the input video<br>+         0 : Two separate input videos<br>+        1 : One input video with both views in left and right format<br>+         2 : One input video with both views in top and bottom format<br>+<br>+.. option:: --multiview-config <filename><br>+   File containing the configurations to enable multiview encoding.<br>+<br>+  Sample config file::<br>+<br>+              --num-views 2<br>+                --format    0<br>+              --input     multiview-input-01.yuv<br>+         --input     multiview-input-02.yuv<br>+<br>+      Other input parameters such as input-csp/input-depth/input-res/fps must be configured through<br>+        normal CLI and is expected to be same for all views<br>+<br>+**CLI_ONLY**<br>+<br> .. vim: noet<br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index 2dcac3dc6..f25bc8b84 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -31,7 +31,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 210)<br>+set(X265_BUILD 211)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" target="_blank">x265.def.in</a>"<br>                "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in" target="_blank">x265_config.h.in</a>"<br>@@ -600,6 +600,11 @@ if(ENABLE_ALPHA)<br>     add_definitions(-DENABLE_ALPHA)<br> endif()<br> <br>+option(ENABLE_MULTIVIEW "Enable Multi-view encoding in HEVC" OFF)<br>+if(ENABLE_MULTIVIEW)<br>+    add_definitions(-DENABLE_MULTIVIEW)<br>+endif()<br>+<br> add_subdirectory(encoder)<br> add_subdirectory(common)<br> <br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index dec6ff6c9..c2efb11cf 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -403,6 +403,9 @@ void x265_param_default(x265_param* param)<br>     /* Film grain characteristics model filename */<br>     param->filmGrain = NULL;<br>     param->bEnableSBRC = 0;<br>+<br>+    /* Multi-View Encoding*/<br>+    param->numViews = 1;<br> }<br> <br> int x265_param_default_preset(x265_param* param, const char* preset, const char* tune)<br>@@ -1457,6 +1460,12 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>                 p->numScalableLayers = 2;<br>             }<br>         }<br>+#endif<br>+#if ENABLE_MULTIVIEW<br>+        OPT("num-views")<br>+        {<br>+            p->numViews = atoi(value);<br>+        }<br> #endif<br>         else<br>             return X265_PARAM_BAD_NAME;<br>@@ -1935,6 +1944,9 @@ int x265_check_params(x265_param* param)<br>         CHECK((param->internalCsp != X265_CSP_I420), "Alpha encode supported only with i420a colorspace");<br>         CHECK((param->rc.rateControlMode != X265_RC_CQP), "Alpha encode supported only with CQP mode");<br>     }<br>+#endif<br>+#if ENABLE_MULTIVIEW<br>+    CHECK((param->numViews > 2), "Multi-View Encoding currently support only 2 views");<br> #endif<br>     return check_failed;<br> }<br>@@ -2103,6 +2115,9 @@ void x265_print_params(x265_param* param)<br> #if ENABLE_ALPHA<br>     TOOLOPT(param->numScalableLayers > 1, "alpha");<br> #endif<br>+#if ENABLE_MULTIVIEW<br>+    TOOLOPT(param->numViews > 1, "multi-view");<br>+#endif<br> #if ENABLE_HDR10_PLUS<br>     TOOLOPT(param->toneMapFile != NULL, "dhdr10-info");<br> #endif<br>@@ -2369,6 +2384,9 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br>     BOOL(p->bEnableTemporalFilter, "mcstf");<br> #if ENABLE_ALPHA<br>     BOOL(p->bEnableAlpha, "alpha");<br>+#endif<br>+#if ENABLE_MULTIVIEW<br>+    s += sprintf(s, " num-views=%d", p->numViews);<br> #endif<br>     BOOL(p->bEnableSBRC, "sbrc");<br> #undef BOOL<br>@@ -2895,6 +2913,9 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br>     dst->bEnableAlpha = src->bEnableAlpha;<br>     dst->numScalableLayers = src->numScalableLayers;<br> #endif<br>+#if ENABLE_MULTIVIEW<br>+    dst->numViews = src->numViews;<br>+#endif<br> <br>     if (src->videoSignalTypePreset) dst->videoSignalTypePreset = strdup(src->videoSignalTypePreset);<br>     else dst->videoSignalTypePreset = NULL;<br>diff --git a/source/x265.h b/source/x265.h<br>index 084f7cd64..baf18e4fc 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -626,6 +626,12 @@ typedef enum<br> #define X265_MAX_GOP_LENGTH 16<br> #define MAX_T_LAYERS 7<br> <br>+#if ENABLE_MULTIVIEW<br>+#define MAX_VIEWS 2<br>+#else<br>+#define MAX_VIEWS 1<br>+#endif<br>+<br> #if ENABLE_ALPHA<br> #define MAX_SCALABLE_LAYERS     2<br> #define MAX_VPS_NUM_SCALABILITY_TYPES     16<br>@@ -2284,6 +2290,9 @@ typedef struct x265_param<br>     /*Alpha channel encoding*/<br>     int      bEnableAlpha;<br>     int      numScalableLayers;<br>+<br>+    /*Multi View Encoding*/<br>+    int      numViews;<br> } x265_param;<br> <br> /* x265_param_alloc:<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index 1ba0a5877..86e1d9bd8 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -377,6 +377,10 @@ namespace X265_NS {<br> #if ENABLE_ALPHA<br>         H0("   --alpha                       Enable alpha channel support. Default %d\n", param->bEnableAlpha);<br> #endif<br>+#if ENABLE_MULTIVIEW<br>+        H0("   --num-views                   Number of Views for Multiview Encoding. Default %d\n", param->numViews);<br>+        H0("   --multiview-config            Configuration file for Multiview Encoding\n");<br>+#endif<br> #ifdef SVT_HEVC<br>         H0("   --[no]svt                     Enable SVT HEVC encoder %s\n", OPT(param->bEnableSvtHevc));<br>         H0("   --[no-]svt-hme                Enable Hierarchial motion estimation(HME) in SVT HEVC encoder \n");<br>@@ -583,7 +587,11 @@ namespace X265_NS {<br>         int inputBitDepth = 8;<br>         int outputBitDepth = 0;<br>         int reconFileBitDepth = 0;<br>-        const char *inputfn = NULL;<br>+        char* inputfn[MAX_VIEWS] = { NULL };<br>+        for (int view = 0; view < MAX_VIEWS; view++)<br>+        {<br>+            inputfn[view] = X265_MALLOC(char, sizeof(char) * 1024);<br>+        }<br>         const char* reconfn[MAX_SCALABLE_LAYERS] = { NULL };<br>         const char *outputfn = NULL;<br>         const char *preset = NULL;<br>@@ -723,7 +731,7 @@ namespace X265_NS {<br>                 OPT("frames") this->framesToBeEncoded = (uint32_t)x265_atoi(optarg, bError);<br>                 OPT("no-progress") this->bProgress = false;<br>                 OPT("output") outputfn = optarg;<br>-                OPT("input") inputfn = optarg;<br>+                OPT("input") inputfn[0] = optarg;<br>                 OPT("recon") reconfn[0] = optarg;<br>                 OPT("input-depth") inputBitDepth = (uint32_t)x265_atoi(optarg, bError);<br>                 OPT("dither") this->bDither = true;<br>@@ -756,6 +764,14 @@ namespace X265_NS {<br>                     if (!this->scenecutAwareQpConfig)<br>                         x265_log_file(param, X265_LOG_ERROR, "%s scenecut aware qp config file not found or error in opening config file\n", optarg);<br>                 }<br>+#if ENABLE_MULTIVIEW<br>+                OPT("multiview-config")<br>+                {<br>+                    this->multiViewConfig = x265_fopen(optarg, "rb");<br>+                    if (!this->multiViewConfig)<br>+                        x265_log_file(param, X265_LOG_ERROR, "%s Multiview config file not found or error in opening config file\n", optarg);<br>+                }<br>+#endif<br>                 OPT("zonefile")<br>                 {<br>                     this->zoneFile = x265_fopen(optarg, "rb");<br>@@ -782,8 +798,10 @@ namespace X265_NS {<br>             }<br>         }<br> <br>-        if (optind < argc && !inputfn)<br>-            inputfn = argv[optind++];<br>+#if !ENABLE_MULTIVIEW<br>+        if (optind < argc && !inputfn[0])<br>+            inputfn[0] = argv[optind++];<br>+#endif<br>         if (optind < argc && !outputfn)<br>             outputfn = argv[optind++];<br>         if (optind < argc)<br>@@ -799,7 +817,18 @@ namespace X265_NS {<br>             showHelp(param);<br>         }<br> <br>-        if (!inputfn || !outputfn)<br>+#if ENABLE_MULTIVIEW<br>+        if (this->multiViewConfig)<br>+        {<br>+            if (!this->parseMultiViewConfig(inputfn))<br>+            {<br>+                x265_log(NULL, X265_LOG_ERROR, "Unable to parse multiview config file \n");<br>+                fclose(this->multiViewConfig);<br>+                this->multiViewConfig = NULL;<br>+            }<br>+        }<br>+#endif<br>+        if (!inputfn[0] || !outputfn)<br>         {<br>             x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");<br>             return true;<br>@@ -824,7 +853,7 @@ namespace X265_NS {<br> #endif<br> <br>         InputFileInfo info;<br>-        info.filename = inputfn;<br>+        info.filename = inputfn[0];<br>         info.depth = inputBitDepth;<br>         info.csp = param->internalCsp;<br>         info.width = param->sourceWidth;<br>@@ -1250,6 +1279,141 @@ namespace X265_NS {<br>         return false;<br>     }<br> <br>+#if ENABLE_MULTIVIEW<br>+    bool CLIOptions::parseMultiViewConfig(char** fn)<br>+    {<br>+        char line[256];<br>+        char* argLine;<br>+        rewind(multiViewConfig);<br>+        int linenum = 0;<br>+        int numInput = 0;<br>+        while (fgets(line, sizeof(line), multiViewConfig))<br>+        {<br>+            if (*line == '#' || (strcmp(line, "\r\n") == 0))<br>+                continue;<br>+            int index = (int)strcspn(line, "\r\n");<br>+            line[index] = '\0';<br>+            argLine = line;<br>+            while (isspace((unsigned char)*argLine)) argLine++;<br>+            char* start = strchr(argLine, '-');<br>+            int argCount = 0;<br>+            char** args = (char**)malloc(256 * sizeof(char*));<br>+            //Adding a dummy string to avoid file parsing error<br>+            args[argCount++] = (char*)"x265";<br>+            char* token = strtok(start, " ");<br>+            while (token)<br>+            {<br>+                args[argCount++] = token;<br>+                token = strtok(NULL, " ");<br>+                while (token && strchr(token, '"'))<br>+                {<br>+                    token = strchr(token, '"');<br>+                    token = strtok(token, "\"");<br>+                }<br>+            }<br>+            args[argCount] = NULL;<br>+            bool bError = false;<br>+            bool bInvalid = false;<br>+            for (optind = 0;;)<br>+            {<br>+                int long_options_index = -1;<br>+                int c = getopt_long(argCount, args, short_options, long_options, &long_options_index);<br>+                if (c == -1)<br>+                    break;<br>+                if (long_options_index < 0 && c > 0)<br>+                {<br>+                    for (size_t i = 0; i < sizeof(long_options) / sizeof(long_options[0]); i++)<br>+                    {<br>+                        if (long_options[i].val == c)<br>+                        {<br>+                            long_options_index = (int)i;<br>+                            break;<br>+                        }<br>+                    }<br>+                    if (long_options_index < 0)<br>+                    {<br>+                        /* getopt_long might have already printed an error message */<br>+                        if (c != 63)<br>+                            x265_log(NULL, X265_LOG_WARNING, "internal error: short option '%c' has no long option\n", c);<br>+                        bInvalid = true;<br>+                        break;<br>+                    }<br>+                }<br>+                if (long_options_index < 0)<br>+                {<br>+                    x265_log(NULL, X265_LOG_WARNING, "short option '%c' unrecognized\n", c);<br>+                    bInvalid = true;<br>+                    break;<br>+                }<br>+                char nameBuf[64];<br>+                const char* name = long_options[long_options_index].name;<br>+                if (!name)<br>+                    bError = true;<br>+                else<br>+                {<br>+                    // skip -- prefix if provided<br>+                    if (name[0] == '-' && name[1] == '-')<br>+                        name += 2;<br>+                    // s/_/-/g<br>+                    if (strlen(name) + 1 < sizeof(nameBuf) && strchr(name, '_'))<br>+                    {<br>+                        char* ch;<br>+                        strcpy(nameBuf, name);<br>+                        while ((ch = strchr(nameBuf, '_')) != 0)<br>+                            *ch = '-';<br>+                        name = nameBuf;<br>+                    }<br>+                    if (!optarg)<br>+                        optarg = "true";<br>+                    else if (optarg[0] == '=')<br>+                        optarg++;<br>+#define OPT(STR) else if (!strcmp(name, STR))<br>+                    if (0);<br>+                    OPT("num-views") param->numViews = x265_atoi(optarg, bError);<br>+                    if (param->numViews > 1)<br>+                    {<br>+                        if (0);<br>+                        OPT("input")<br>+                        {<br>+                            strcpy(fn[numInput++], optarg);<br>+                        }<br>+<br>+                    }<br>+#undef OPT<br>+                }<br>+                if (bError)<br>+                {<br>+                    const char* optname = long_options_index > 0 ? long_options[long_options_index].name : args[optind - 2];<br>+                    x265_log(NULL, X265_LOG_ERROR, "invalid argument: %s = %s\n", optname, optarg);<br>+                    bInvalid = true;<br>+                    break;<br>+                }<br>+            }<br>+            if (optind < argCount)<br>+            {<br>+                x265_log(param, X265_LOG_WARNING, "extra unused command arguments given <%s>\n", args[optind]);<br>+                bInvalid = true;<br>+            }<br>+            if (bInvalid)<br>+            {<br>+                if (api)<br>+                    api->param_free(param);<br>+                exit(1);<br>+            }<br>+            linenum++;<br>+        }<br>+        if (numInput != param->numViews)<br>+        {<br>+            x265_log(NULL, X265_LOG_WARNING, "Input file missing for given number of views<%d>\n", param->numViews);<br>+            if (api)<br>+                api->param_free(param);<br>+            exit(1);<br>+        }<br>+        return 1;<br>+    }<br>+<br>+#endif<br>+<br> #ifdef __cplusplus<br> }<br> #endif<br>\ No newline at end of file<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 7abf91eb8..0fdad9cf3 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -361,6 +361,10 @@ static const struct option long_options[] =<br> #if ENABLE_ALPHA<br>     { "alpha",                 no_argument, NULL, 0 },<br> #endif<br>+#if ENABLE_MULTIVIEW<br>+    { "num-views", required_argument, NULL, 0 },<br>+    { "multiview-config", required_argument, NULL, 0 },<br>+#endif<br> #ifdef SVT_HEVC<br>     { "svt",     no_argument, NULL, 0 },<br>     { "no-svt",  no_argument, NULL, 0 },<br>@@ -403,6 +407,9 @@ static const struct option long_options[] =<br>         FILE*       zoneFile;<br>         FILE*    dolbyVisionRpu;    /* File containing Dolby Vision BL RPU metadata */<br>         FILE*    scenecutAwareQpConfig; /* File containing scenecut aware frame quantization related CLI options */<br>+#if ENABLE_MULTIVIEW<br>+        FILE* multiViewConfig; /* File containing multi-view related CLI options */<br>+#endif<br>         const char* reconPlayCmd;<br>         const x265_api* api;<br>         x265_param* param;<br>@@ -442,6 +449,9 @@ static const struct option long_options[] =<br>             zoneFile = NULL;<br>             dolbyVisionRpu = NULL;<br>             scenecutAwareQpConfig = NULL;<br>+#if ENABLE_MULTIVIEW<br>+            multiViewConfig = NULL;<br>+#endif<br>             reconPlayCmd = NULL;<br>             api = NULL;<br>             param = NULL;<br>@@ -474,6 +484,9 @@ static const struct option long_options[] =<br>         int rpuParser(x265_picture * pic);<br>         bool parseScenecutAwareQpConfig();<br>         bool parseScenecutAwareQpParam(int argc, char **argv, x265_param* globalParam);<br>+#if ENABLE_MULTIVIEW<br>+        bool parseMultiViewConfig(char** fn);<br>+#endif<br>     };<br> #ifdef __cplusplus<br> }<br>-- <br>2.36.0.windows.1<br><br></div>