<div dir="ltr">From c867087e91c890d96380b09b0033ab584a17f247 Mon Sep 17 00:00:00 2001<br>From: AnusuyaKumarasamy <<a href="mailto:anusuya.kumarasamy@multicorewareinc.com" target="_blank">anusuya.kumarasamy@multicorewareinc.com</a>><br>Date: Tue, 30 Jul 2024 15:29:14 +0530<br>Subject: [PATCH] Add support for parsing spatial video with side-by-side and<br> top-bottom format<br><br>---<br> source/abrEncApp.cpp       | 12 ++++++++----<br> source/common/param.cpp    |  5 +++++<br> source/common/picyuv.cpp   | 14 ++++++++++----<br> source/encoder/encoder.cpp |  6 +-----<br> source/input/input.cpp     |  4 ++--<br> source/input/input.h       |  2 +-<br> source/input/yuv.cpp       | 12 ++++++------<br> source/input/yuv.h         |  2 +-<br> source/x265.h              |  2 ++<br> source/x265cli.cpp         | 16 +++++++++-------<br> source/x265cli.h           |  1 +<br> 11 files changed, 46 insertions(+), 30 deletions(-)<br><br>diff --git a/source/abrEncApp.cpp b/source/abrEncApp.cpp<br>index b14db5900..3460dfe78 100644<br>--- a/source/abrEncApp.cpp<br>+++ b/source/abrEncApp.cpp<br>@@ -558,6 +558,7 @@ ret:<br>             pic->planes[1] = srcPic->planes[1];<br>             pic->planes[2] = srcPic->planes[2];<br>             pic->planes[3] = srcPic->planes[3];<br>+            pic->format = srcPic->format;<br>             if (isAbrLoad)<br>                 pic->analysisData = *analysisData;<br>             return true;<br>@@ -1150,9 +1151,10 @@ ret:<br>                 read = m_parentEnc->m_parent->m_picIdxReadCnt[m_id][writeIdx].waitForChange(read);<br>             }<br> <br>-            for (int view = 0; view < m_parentEnc->m_param->numViews; view++)<br>+            for (int view = 0; view < m_parentEnc->m_param->numViews - !!m_parentEnc->m_param->format; view++)<br>             {<br>                 x265_picture* dest = m_parentEnc->m_parent->m_inputPicBuffer[view][writeIdx];<br>+                src->format = m_parentEnc->m_param->format;<br>                 if (m_input[view]->readPicture(*src))<br>                 {<br>                     dest->poc = src->poc;<br>@@ -1169,20 +1171,22 @@ ret:<br>                     dest->stride[0] = src->stride[0];<br>                     dest->stride[1] = src->stride[1];<br>                     dest->stride[2] = src->stride[2];<br>+                    dest->format = src->format;<br> <br>                     if (!dest->planes[0])<br>                         dest->planes[0] = X265_MALLOC(char, dest->framesize);<br> <br>                     memcpy(dest->planes[0], src->planes[0], src->framesize * sizeof(char));<br>-                    dest->planes[1] = (char*)dest->planes[0] + src->stride[0] * src->height;<br>-                    dest->planes[2] = (char*)dest->planes[1] + src->stride[1] * (src->height >> x265_cli_csps[src->colorSpace].height[1]);<br>+                    int height = (src->height * (src->format == 2 ? 2 : 1));<br>+                    dest->planes[1] = (char*)dest->planes[0] + src->stride[0] * height;<br>+                    dest->planes[2] = (char*)dest->planes[1] + src->stride[1] * (height >> x265_cli_csps[src->colorSpace].height[1]);<br> #if ENABLE_ALPHA<br>                     if (m_parentEnc->m_param->numScalableLayers > 1)<br>                     {<br>                         dest->planes[3] = (char*)dest->planes[2] + src->stride[2] * (src->height >> x265_cli_csps[src->colorSpace].height[2]);<br>                     }<br> #endif<br>-                    if (view == m_parentEnc->m_param->numViews - 1)<br>+                    if (view == m_parentEnc->m_param->numViews - 1 - !!m_parentEnc->m_param->format)<br>                         m_parentEnc->m_parent->m_picWriteCnt[m_id].incr();<br>                 }<br>                 else<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index 8b7d268d2..c310a7b4c 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -406,6 +406,7 @@ void x265_param_default(x265_param* param)<br> <br>     /* Multi-View Encoding*/<br>     param->numViews = 1;<br>+    param->format = 1;<br> <br>     param->numLayers = 1;<br> }<br>@@ -1464,6 +1465,8 @@ int x265_param_parse(x265_param* p, const char* name, const char* value)<br>         }<br> #endif<br> #if ENABLE_MULTIVIEW<br>+        OPT("format")<br>+            p->format = atoi(value);<br>         OPT("num-views")<br>         {<br>             p->numViews = atoi(value);<br>@@ -2389,6 +2392,7 @@ char *x265_param2string(x265_param* p, int padx, int pady)<br> #endif<br> #if ENABLE_MULTIVIEW<br>     s += sprintf(s, " num-views=%d", p->numViews);<br>+    s += sprintf(s, " format=%d", p->format);<br> #endif<br>     BOOL(p->bEnableSBRC, "sbrc");<br> #undef BOOL<br>@@ -2917,6 +2921,7 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br> #endif<br> #if ENABLE_MULTIVIEW<br>     dst->numViews = src->numViews;<br>+    dst->format = src->format;<br> #endif<br>     dst->numLayers = src->numLayers;<br> <br>diff --git a/source/common/picyuv.cpp b/source/common/picyuv.cpp<br>index bd5690d3e..e4911b19a 100644<br>--- a/source/common/picyuv.cpp<br>+++ b/source/common/picyuv.cpp<br>@@ -321,10 +321,13 @@ void PicYuv::copyFromPicture(const x265_picture& pic, const x265_param& param, i<br> #else /* Case for (X265_DEPTH == 8) */<br>             // TODO: Does we need this path? may merge into above in future<br>         {<br>-            if (isBase)<br>+            if (isBase || param.numViews > 1)<br>             {<br>+                int offsetX, offsetY;<br>+                offsetX = (!isBase && pic.format == 1 ? width : 0);<br>+                offsetY = (!isBase && pic.format == 2 ? width * height : 0);<br>                 pixel *yPixel = m_picOrg[0];<br>-                uint8_t *yChar = (uint8_t*)pic.planes[0];<br>+                uint8_t* yChar = (uint8_t*)pic.planes[0] + offsetX + offsetY;<br> <br>                 for (int r = 0; r < height; r++)<br>                 {<br>@@ -336,11 +339,14 @@ void PicYuv::copyFromPicture(const x265_picture& pic, const x265_param& param, i<br> <br>                 if (param.internalCsp != X265_CSP_I400)<br>                 {<br>+                    offsetX = offsetX >> m_hChromaShift;<br>+                    offsetY = offsetY >> (m_hChromaShift * 2);<br>+<br>                     pixel *uPixel = m_picOrg[1];<br>                     pixel *vPixel = m_picOrg[2];<br> <br>-                    uint8_t *uChar = (uint8_t*)pic.planes[1];<br>-                    uint8_t *vChar = (uint8_t*)pic.planes[2];<br>+                    uint8_t* uChar = (uint8_t*)pic.planes[1] + offsetX + offsetY;<br>+                    uint8_t* vChar = (uint8_t*)pic.planes[2] + offsetX + offsetY;<br> <br>                     for (int r = 0; r < height >> m_vChromaShift; r++)<br>                     {<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 7f4e4b3eb..5fb822c8a 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -1701,11 +1701,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>             }<br> <br>             /* Copy input picture into a Frame and PicYuv, send to lookahead */<br>-#if ENABLE_ALPHA<br>-            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic[layer], *m_param, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset, !layer);<br>-#else<br>-            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic[layer], *m_param, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset);<br>-#endif<br>+            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic[!m_param->format ? layer : 0], *m_param, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset, !layer);<br> <br>             inFrame[layer]->m_poc = (!layer) ? (++m_pocLast) : m_pocLast;<br>             inFrame[layer]->m_userData = inputPic[0]->userData;<br>diff --git a/source/input/input.cpp b/source/input/input.cpp<br>index 889c0ba5e..43734c978 100644<br>--- a/source/input/input.cpp<br>+++ b/source/input/input.cpp<br>@@ -27,12 +27,12 @@<br> <br> using namespace X265_NS;<br> <br>-InputFile* InputFile::open(InputFileInfo& info, bool bForceY4m, bool alpha)<br>+InputFile* InputFile::open(InputFileInfo& info, bool bForceY4m, bool alpha, int format)<br> {<br>     const char * s = strrchr(info.filename, '.');<br> <br>     if (bForceY4m || (s && !strcmp(s, ".y4m")))<br>         return new Y4MInput(info, alpha);<br>     else<br>-        return new YUVInput(info, alpha);<br>+        return new YUVInput(info, alpha, format);<br> }<br>diff --git a/source/input/input.h b/source/input/input.h<br>index 96a5734c6..8836eb9bf 100644<br>--- a/source/input/input.h<br>+++ b/source/input/input.h<br>@@ -66,7 +66,7 @@ public:<br> <br>     InputFile()           {}<br> <br>-    static InputFile* open(InputFileInfo& info, bool bForceY4m, bool alpha);<br>+    static InputFile* open(InputFileInfo& info, bool bForceY4m, bool alpha, int format);<br> <br>     virtual void startReader() = 0;<br> <br>diff --git a/source/input/yuv.cpp b/source/input/yuv.cpp<br>index 878075ec8..65d696c48 100644<br>--- a/source/input/yuv.cpp<br>+++ b/source/input/yuv.cpp<br>@@ -40,7 +40,7 @@<br> using namespace X265_NS;<br> using namespace std;<br> <br>-YUVInput::YUVInput(InputFileInfo& info, bool alpha)<br>+YUVInput::YUVInput(InputFileInfo& info, bool alpha, int format)<br> {<br>     for (int i = 0; i < QUEUE_SIZE; i++)<br>         buf[i] = NULL;<br>@@ -57,8 +57,8 @@ YUVInput::YUVInput(InputFileInfo& info, bool alpha)<br>     framesize = 0;<br>     for (int i = 0; i < x265_cli_csps[colorSpace].planes + alphaAvailable; i++)<br>     {<br>-        uint32_t w = width >> x265_cli_csps[colorSpace].width[i];<br>-        uint32_t h = height >> x265_cli_csps[colorSpace].height[i];<br>+        int32_t w = (width * (format == 1 ? 2 : 1)) >> x265_cli_csps[colorSpace].width[i];<br>+        uint32_t h = (height * (format == 2 ? 2 : 1)) >> x265_cli_csps[colorSpace].height[i];<br>         framesize += w * h * pixelbytes;<br>     }<br> <br>@@ -206,12 +206,12 @@ bool YUVInput::readPicture(x265_picture& pic)<br>         pic.framesize = framesize;<br>         pic.height = height;<br>         pic.width = width;<br>-        pic.stride[0] = width * pixelbytes;<br>+        pic.stride[0] = width * pixelbytes * (pic.format == 1 ? 2 : 1);<br>         pic.stride[1] = pic.stride[0] >> x265_cli_csps[colorSpace].width[1];<br>         pic.stride[2] = pic.stride[0] >> x265_cli_csps[colorSpace].width[2];<br>         pic.planes[0] = buf[read % QUEUE_SIZE];<br>-        pic.planes[1] = (char*)pic.planes[0] + pic.stride[0] * height;<br>-        pic.planes[2] = (char*)pic.planes[1] + pic.stride[1] * (height >> x265_cli_csps[colorSpace].height[1]);<br>+        pic.planes[1] = (char*)pic.planes[0] + pic.stride[0] * (height * (pic.format == 2 ? 2 : 1));<br>+        pic.planes[2] = (char*)pic.planes[1] + pic.stride[1] * ((height * (pic.format == 2 ? 2 : 1)) >> x265_cli_csps[colorSpace].height[1]);<br> #if ENABLE_ALPHA<br>         if (alphaAvailable)<br>         {<br>diff --git a/source/input/yuv.h b/source/input/yuv.h<br>index 2c104a4cc..8cab97d74 100644<br>--- a/source/input/yuv.h<br>+++ b/source/input/yuv.h<br>@@ -63,7 +63,7 @@ protected:<br> <br> public:<br> <br>-    YUVInput(InputFileInfo& info, bool alpha);<br>+    YUVInput(InputFileInfo& info, bool alpha, int format);<br> <br>     virtual ~YUVInput();<br>     void release();<br>diff --git a/source/x265.h b/source/x265.h<br>index 1b685e3c1..fb06372af 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -494,6 +494,7 @@ typedef struct x265_picture<br>     int    width;<br> <br>     int   layerID;<br>+    int    format;<br> } x265_picture;<br> <br> typedef enum<br>@@ -2304,6 +2305,7 @@ typedef struct x265_param<br> <br>     /*Multi View Encoding*/<br>     int      numViews;<br>+    int      format;<br> <br>     int      numLayers;<br> } x265_param;<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index cd42a3bfa..c0c70b78b 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -379,6 +379,7 @@ namespace X265_NS {<br> #endif<br> #if ENABLE_MULTIVIEW<br>         H0("   --num-views                   Number of Views for Multiview Encoding. Default %d\n", param->numViews);<br>+        H0("   --format                      Format of the input video 0 : normal, 1 : side-by-side, 2 : over-under  Default %d\n", param->format);<br>         H0("   --multiview-config            Configuration file for Multiview Encoding\n");<br> #endif<br> #ifdef SVT_HEVC<br>@@ -864,7 +865,7 @@ namespace X265_NS {<br>         }<br> #endif<br>         InputFileInfo info[MAX_VIEWS];<br>-        for (int i = 0; i < param->numViews; i++)<br>+        for (int i = 0; i < param->numViews - !!param->format; i++)<br>         {<br>             info[i].filename = inputfn[i];<br>             info[i].depth = inputBitDepth;<br>@@ -879,7 +880,7 @@ namespace X265_NS {<br>             info[i].frameCount = 0;<br>             getParamAspectRatio(param, info[i].sarWidth, info[i].sarHeight);<br> <br>-            this->input[i] = InputFile::open(info[i], this->bForceY4m, param->numScalableLayers > 1);<br>+            this->input[i] = InputFile::open(info[i], this->bForceY4m, param->numScalableLayers > 1, param->format);<br>             if (!this->input[i] || this->input[i]->isFail())<br>             {<br>                 x265_log_file(param, X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn[i]);<br>@@ -957,11 +958,11 @@ namespace X265_NS {<br>             else<br>                 sprintf(buf + p, " frames %u - %d of %d", this->seek, this->seek + this->framesToBeEncoded - 1, info[0].frameCount);<br> <br>-            for (int view = 0; view < param->numViews; view++)<br>+            for (int view = 0; view < param->numViews - !!param->format; view++)<br>                 general_log(param, input[view]->getName(), X265_LOG_INFO, "%s\n", buf);<br>         }<br> <br>-        for (int view = 0; view < param->numViews; view++)<br>+        for (int view = 0; view < param->numViews - !!param->format; view++)<br>             this->input[view]->startReader();<br> <br>         if (reconfn[0])<br>@@ -982,7 +983,7 @@ namespace X265_NS {<br>                 }<br>             }<br> #endif<br>-            for (int i = 0; i < param->numLayers; i++)<br>+            for (int i = 0; i < param->numLayers - !!param->format; i++)<br>             {<br>                 this->recon[i] = ReconFile::open(reconfn[i], param->sourceWidth, param->sourceHeight, reconFileBitDepth,<br>                     param->fpsNum, param->fpsDenom, param->internalCsp, param->sourceBitDepth);<br>@@ -1387,6 +1388,7 @@ namespace X265_NS {<br> #define OPT(STR) else if (!strcmp(name, STR))<br>                     if (0);<br>                     OPT("num-views") param->numViews = x265_atoi(optarg, bError);<br>+                    OPT("format") param->format = x265_atoi(optarg, bError);<br>                     if (param->numViews > 1)<br>                     {<br>                         if (0);<br>@@ -1419,9 +1421,9 @@ namespace X265_NS {<br>             }<br>             linenum++;<br>         }<br>-        if (numInput != param->numViews)<br>+        if (numInput != (param->format ? 1 : param->numViews))<br>         {<br>-            x265_log(NULL, X265_LOG_WARNING, "Input file missing for given number of views<%d>\n", param->numViews);<br>+            x265_log(NULL, X265_LOG_WARNING, "Number of Input files does not match with the given format <%d>\n", param->format);<br>             if (api)<br>                 api->param_free(param);<br>             exit(1);<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 49a88d084..7ae9877d7 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -364,6 +364,7 @@ static const struct option long_options[] =<br> #if ENABLE_MULTIVIEW<br>     { "num-views", required_argument, NULL, 0 },<br>     { "multiview-config", required_argument, NULL, 0 },<br>+    { "format", required_argument, NULL, 0 },<br> #endif<br> #ifdef SVT_HEVC<br>     { "svt",     no_argument, NULL, 0 },<br>-- <br>2.36.0.windows.1<br><br></div>