[x265] [PATCH MV-HEVC 01/10] Add compile time configuration and support for parsing multiview config file

Anusuya Kumarasamy anusuya.kumarasamy at multicorewareinc.com
Tue Aug 6 10:42:11 UTC 2024


>From dba87b3da6bea98ce677bc7be006b928c9d7f8d0 Mon Sep 17 00:00:00 2001
From: Kirithika <kirithika at multicorewareinc.com>
Date: Wed, 10 Jul 2024 16:06:01 +0530
Subject: [PATCH] Add compile time configuration and support for parsing
 multiview config file

---
 doc/reST/cli.rst        |  30 +++++++
 source/CMakeLists.txt   |   7 +-
 source/common/param.cpp |  21 +++++
 source/x265.h           |   9 ++
 source/x265cli.cpp      | 176 ++++++++++++++++++++++++++++++++++++++--
 source/x265cli.h        |  13 +++
 6 files changed, 249 insertions(+), 7 deletions(-)

diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
index 4d5ac1a15..298ee334a 100755
--- a/doc/reST/cli.rst
+++ b/doc/reST/cli.rst
@@ -2893,4 +2893,34 @@ Alpha Encode Options

 **CLI_ONLY**

+Multiview Encode Options
+===================
+
+ Enable multiview encoding support in x265.This option can be enabled
+ only when ENABLE_MULTIVIEW is set during the make of x265.
+
+.. option:: --num-views <integer>
+ Specify the number of views in the multiview input video.
+
+.. option:: --format <integer>
+ Specify the format of the input video
+ 0 : Two separate input videos
+ 1 : One input video with both views in left and right format
+ 2 : One input video with both views in top and bottom format
+
+.. option:: --multiview-config <filename>
+ File containing the configurations to enable multiview encoding.
+
+ Sample config file::
+
+ --num-views 2
+ --format    0
+ --input     multiview-input-01.yuv
+ --input     multiview-input-02.yuv
+
+ Other input parameters such as input-csp/input-depth/input-res/fps must
be configured through
+ normal CLI and is expected to be same for all views
+
+**CLI_ONLY**
+
 .. vim: noet
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 2dcac3dc6..f25bc8b84 100755
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -31,7 +31,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)
 option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
 mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 210)
+set(X265_BUILD 211)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
@@ -600,6 +600,11 @@ if(ENABLE_ALPHA)
     add_definitions(-DENABLE_ALPHA)
 endif()

+option(ENABLE_MULTIVIEW "Enable Multi-view encoding in HEVC" OFF)
+if(ENABLE_MULTIVIEW)
+    add_definitions(-DENABLE_MULTIVIEW)
+endif()
+
 add_subdirectory(encoder)
 add_subdirectory(common)

diff --git a/source/common/param.cpp b/source/common/param.cpp
index dec6ff6c9..c2efb11cf 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -403,6 +403,9 @@ void x265_param_default(x265_param* param)
     /* Film grain characteristics model filename */
     param->filmGrain = NULL;
     param->bEnableSBRC = 0;
+
+    /* Multi-View Encoding*/
+    param->numViews = 1;
 }

 int x265_param_default_preset(x265_param* param, const char* preset, const
char* tune)
@@ -1457,6 +1460,12 @@ int x265_param_parse(x265_param* p, const char*
name, const char* value)
                 p->numScalableLayers = 2;
             }
         }
+#endif
+#if ENABLE_MULTIVIEW
+        OPT("num-views")
+        {
+            p->numViews = atoi(value);
+        }
 #endif
         else
             return X265_PARAM_BAD_NAME;
@@ -1935,6 +1944,9 @@ int x265_check_params(x265_param* param)
         CHECK((param->internalCsp != X265_CSP_I420), "Alpha encode
supported only with i420a colorspace");
         CHECK((param->rc.rateControlMode != X265_RC_CQP), "Alpha encode
supported only with CQP mode");
     }
+#endif
+#if ENABLE_MULTIVIEW
+    CHECK((param->numViews > 2), "Multi-View Encoding currently support
only 2 views");
 #endif
     return check_failed;
 }
@@ -2103,6 +2115,9 @@ void x265_print_params(x265_param* param)
 #if ENABLE_ALPHA
     TOOLOPT(param->numScalableLayers > 1, "alpha");
 #endif
+#if ENABLE_MULTIVIEW
+    TOOLOPT(param->numViews > 1, "multi-view");
+#endif
 #if ENABLE_HDR10_PLUS
     TOOLOPT(param->toneMapFile != NULL, "dhdr10-info");
 #endif
@@ -2369,6 +2384,9 @@ char *x265_param2string(x265_param* p, int padx, int
pady)
     BOOL(p->bEnableTemporalFilter, "mcstf");
 #if ENABLE_ALPHA
     BOOL(p->bEnableAlpha, "alpha");
+#endif
+#if ENABLE_MULTIVIEW
+    s += sprintf(s, " num-views=%d", p->numViews);
 #endif
     BOOL(p->bEnableSBRC, "sbrc");
 #undef BOOL
@@ -2895,6 +2913,9 @@ void x265_copy_params(x265_param* dst, x265_param*
src)
     dst->bEnableAlpha = src->bEnableAlpha;
     dst->numScalableLayers = src->numScalableLayers;
 #endif
+#if ENABLE_MULTIVIEW
+    dst->numViews = src->numViews;
+#endif

     if (src->videoSignalTypePreset) dst->videoSignalTypePreset =
strdup(src->videoSignalTypePreset);
     else dst->videoSignalTypePreset = NULL;
diff --git a/source/x265.h b/source/x265.h
index 084f7cd64..baf18e4fc 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -626,6 +626,12 @@ typedef enum
 #define X265_MAX_GOP_LENGTH 16
 #define MAX_T_LAYERS 7

+#if ENABLE_MULTIVIEW
+#define MAX_VIEWS 2
+#else
+#define MAX_VIEWS 1
+#endif
+
 #if ENABLE_ALPHA
 #define MAX_SCALABLE_LAYERS     2
 #define MAX_VPS_NUM_SCALABILITY_TYPES     16
@@ -2284,6 +2290,9 @@ typedef struct x265_param
     /*Alpha channel encoding*/
     int      bEnableAlpha;
     int      numScalableLayers;
+
+    /*Multi View Encoding*/
+    int      numViews;
 } x265_param;

 /* x265_param_alloc:
diff --git a/source/x265cli.cpp b/source/x265cli.cpp
index 1ba0a5877..86e1d9bd8 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -377,6 +377,10 @@ namespace X265_NS {
 #if ENABLE_ALPHA
         H0("   --alpha                       Enable alpha channel support.
Default %d\n", param->bEnableAlpha);
 #endif
+#if ENABLE_MULTIVIEW
+        H0("   --num-views                   Number of Views for Multiview
Encoding. Default %d\n", param->numViews);
+        H0("   --multiview-config            Configuration file for
Multiview Encoding\n");
+#endif
 #ifdef SVT_HEVC
         H0("   --[no]svt                     Enable SVT HEVC encoder
%s\n", OPT(param->bEnableSvtHevc));
         H0("   --[no-]svt-hme                Enable Hierarchial motion
estimation(HME) in SVT HEVC encoder \n");
@@ -583,7 +587,11 @@ namespace X265_NS {
         int inputBitDepth = 8;
         int outputBitDepth = 0;
         int reconFileBitDepth = 0;
-        const char *inputfn = NULL;
+        char* inputfn[MAX_VIEWS] = { NULL };
+        for (int view = 0; view < MAX_VIEWS; view++)
+        {
+            inputfn[view] = X265_MALLOC(char, sizeof(char) * 1024);
+        }
         const char* reconfn[MAX_SCALABLE_LAYERS] = { NULL };
         const char *outputfn = NULL;
         const char *preset = NULL;
@@ -723,7 +731,7 @@ namespace X265_NS {
                 OPT("frames") this->framesToBeEncoded =
(uint32_t)x265_atoi(optarg, bError);
                 OPT("no-progress") this->bProgress = false;
                 OPT("output") outputfn = optarg;
-                OPT("input") inputfn = optarg;
+                OPT("input") inputfn[0] = optarg;
                 OPT("recon") reconfn[0] = optarg;
                 OPT("input-depth") inputBitDepth =
(uint32_t)x265_atoi(optarg, bError);
                 OPT("dither") this->bDither = true;
@@ -756,6 +764,14 @@ namespace X265_NS {
                     if (!this->scenecutAwareQpConfig)
                         x265_log_file(param, X265_LOG_ERROR, "%s scenecut
aware qp config file not found or error in opening config file\n", optarg);
                 }
+#if ENABLE_MULTIVIEW
+                OPT("multiview-config")
+                {
+                    this->multiViewConfig = x265_fopen(optarg, "rb");
+                    if (!this->multiViewConfig)
+                        x265_log_file(param, X265_LOG_ERROR, "%s Multiview
config file not found or error in opening config file\n", optarg);
+                }
+#endif
                 OPT("zonefile")
                 {
                     this->zoneFile = x265_fopen(optarg, "rb");
@@ -782,8 +798,10 @@ namespace X265_NS {
             }
         }

-        if (optind < argc && !inputfn)
-            inputfn = argv[optind++];
+#if !ENABLE_MULTIVIEW
+        if (optind < argc && !inputfn[0])
+            inputfn[0] = argv[optind++];
+#endif
         if (optind < argc && !outputfn)
             outputfn = argv[optind++];
         if (optind < argc)
@@ -799,7 +817,18 @@ namespace X265_NS {
             showHelp(param);
         }

-        if (!inputfn || !outputfn)
+#if ENABLE_MULTIVIEW
+        if (this->multiViewConfig)
+        {
+            if (!this->parseMultiViewConfig(inputfn))
+            {
+                x265_log(NULL, X265_LOG_ERROR, "Unable to parse multiview
config file \n");
+                fclose(this->multiViewConfig);
+                this->multiViewConfig = NULL;
+            }
+        }
+#endif
+        if (!inputfn[0] || !outputfn)
         {
             x265_log(param, X265_LOG_ERROR, "input or output file not
specified, try --help for help\n");
             return true;
@@ -824,7 +853,7 @@ namespace X265_NS {
 #endif

         InputFileInfo info;
-        info.filename = inputfn;
+        info.filename = inputfn[0];
         info.depth = inputBitDepth;
         info.csp = param->internalCsp;
         info.width = param->sourceWidth;
@@ -1250,6 +1279,141 @@ namespace X265_NS {
         return false;
     }

+#if ENABLE_MULTIVIEW
+    bool CLIOptions::parseMultiViewConfig(char** fn)
+    {
+        char line[256];
+        char* argLine;
+        rewind(multiViewConfig);
+        int linenum = 0;
+        int numInput = 0;
+        while (fgets(line, sizeof(line), multiViewConfig))
+        {
+            if (*line == '#' || (strcmp(line, "\r\n") == 0))
+                continue;
+            int index = (int)strcspn(line, "\r\n");
+            line[index] = '\0';
+            argLine = line;
+            while (isspace((unsigned char)*argLine)) argLine++;
+            char* start = strchr(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, " ");
+                while (token && strchr(token, '"'))
+                {
+                    token = strchr(token, '"');
+                    token = strtok(token, "\"");
+                }
+            }
+            args[argCount] = NULL;
+            bool bError = false;
+            bool bInvalid = false;
+            for (optind = 0;;)
+            {
+                int long_options_index = -1;
+                int c = getopt_long(argCount, args, 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);
+                        bInvalid = true;
+                        break;
+                    }
+                }
+                if (long_options_index < 0)
+                {
+                    x265_log(NULL, X265_LOG_WARNING, "short option '%c'
unrecognized\n", c);
+                    bInvalid = true;
+                    break;
+                }
+                char nameBuf[64];
+                const char* name = long_options[long_options_index].name;
+                if (!name)
+                    bError = true;
+                else
+                {
+                    // skip -- prefix if provided
+                    if (name[0] == '-' && name[1] == '-')
+                        name += 2;
+                    // s/_/-/g
+                    if (strlen(name) + 1 < sizeof(nameBuf) && strchr(name,
'_'))
+                    {
+                        char* ch;
+                        strcpy(nameBuf, name);
+                        while ((ch = strchr(nameBuf, '_')) != 0)
+                            *ch = '-';
+                        name = nameBuf;
+                    }
+                    if (!optarg)
+                        optarg = "true";
+                    else if (optarg[0] == '=')
+                        optarg++;
+#define OPT(STR) else if (!strcmp(name, STR))
+                    if (0);
+                    OPT("num-views") param->numViews = x265_atoi(optarg,
bError);
+                    if (param->numViews > 1)
+                    {
+                        if (0);
+                        OPT("input")
+                        {
+                            strcpy(fn[numInput++], optarg);
+                        }
+
+                    }
+#undef OPT
+                }
+                if (bError)
+                {
+                    const char* optname = long_options_index > 0 ?
long_options[long_options_index].name : args[optind - 2];
+                    x265_log(NULL, X265_LOG_ERROR, "invalid argument: %s =
%s\n", optname, optarg);
+                    bInvalid = true;
+                    break;
+                }
+            }
+            if (optind < argCount)
+            {
+                x265_log(param, X265_LOG_WARNING, "extra unused command
arguments given <%s>\n", args[optind]);
+                bInvalid = true;
+            }
+            if (bInvalid)
+            {
+                if (api)
+                    api->param_free(param);
+                exit(1);
+            }
+            linenum++;
+        }
+        if (numInput != param->numViews)
+        {
+            x265_log(NULL, X265_LOG_WARNING, "Input file missing for given
number of views<%d>\n", param->numViews);
+            if (api)
+                api->param_free(param);
+            exit(1);
+        }
+        return 1;
+    }
+
+#endif
+
 #ifdef __cplusplus
 }
 #endif
\ No newline at end of file
diff --git a/source/x265cli.h b/source/x265cli.h
index 7abf91eb8..0fdad9cf3 100644
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -361,6 +361,10 @@ static const struct option long_options[] =
 #if ENABLE_ALPHA
     { "alpha",                 no_argument, NULL, 0 },
 #endif
+#if ENABLE_MULTIVIEW
+    { "num-views", required_argument, NULL, 0 },
+    { "multiview-config", required_argument, NULL, 0 },
+#endif
 #ifdef SVT_HEVC
     { "svt",     no_argument, NULL, 0 },
     { "no-svt",  no_argument, NULL, 0 },
@@ -403,6 +407,9 @@ static const struct option long_options[] =
         FILE*       zoneFile;
         FILE*    dolbyVisionRpu;    /* File containing Dolby Vision BL RPU
metadata */
         FILE*    scenecutAwareQpConfig; /* File containing scenecut aware
frame quantization related CLI options */
+#if ENABLE_MULTIVIEW
+        FILE* multiViewConfig; /* File containing multi-view related CLI
options */
+#endif
         const char* reconPlayCmd;
         const x265_api* api;
         x265_param* param;
@@ -442,6 +449,9 @@ static const struct option long_options[] =
             zoneFile = NULL;
             dolbyVisionRpu = NULL;
             scenecutAwareQpConfig = NULL;
+#if ENABLE_MULTIVIEW
+            multiViewConfig = NULL;
+#endif
             reconPlayCmd = NULL;
             api = NULL;
             param = NULL;
@@ -474,6 +484,9 @@ static const struct option long_options[] =
         int rpuParser(x265_picture * pic);
         bool parseScenecutAwareQpConfig();
         bool parseScenecutAwareQpParam(int argc, char **argv, x265_param*
globalParam);
+#if ENABLE_MULTIVIEW
+        bool parseMultiViewConfig(char** fn);
+#endif
     };
 #ifdef __cplusplus
 }
-- 
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/b682364c/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Add-compile-time-configuration-and-support-for-parsi.patch
Type: application/x-patch
Size: 16404 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/b682364c/attachment-0001.bin>


More information about the x265-devel mailing list