<div dir="ltr">From bed3eac35256040e5003c794cec52ab33d75fa70 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: Wed, 10 Jul 2024 17:10:21 +0530<br>Subject: [PATCH] Add support to parse Multiview input file<br><br>---<br> source/abrEncApp.cpp       | 392 ++++++++++++++++++++++---------------<br> source/abrEncApp.h         |   6 +-<br> source/encoder/encoder.cpp |  56 +++---<br> source/x265cli.cpp         | 108 +++++-----<br> source/x265cli.h           |   5 +-<br> 5 files changed, 334 insertions(+), 233 deletions(-)<br><br>diff --git a/source/abrEncApp.cpp b/source/abrEncApp.cpp<br>index fc4262369..6874c4d74 100644<br>--- a/source/abrEncApp.cpp<br>+++ b/source/abrEncApp.cpp<br>@@ -76,7 +76,11 @@ namespace X265_NS {<br> <br>     bool AbrEncoder::allocBuffers()<br>     {<br>+#if ENABLE_MULTIVIEW<br>+        m_inputPicBuffer = X265_MALLOC(x265_picture**, MAX_VIEWS);<br>+#else<br>         m_inputPicBuffer = X265_MALLOC(x265_picture**, m_numEncodes);<br>+#endif<br>         m_analysisBuffer = X265_MALLOC(x265_analysis_data*, m_numEncodes);<br> <br>         m_picWriteCnt = new ThreadSafeInteger[m_numEncodes];<br>@@ -89,21 +93,48 @@ namespace X265_NS {<br>         m_analysisRead = X265_MALLOC(ThreadSafeInteger*, m_numEncodes);<br>         m_readFlag = X265_MALLOC(int*, m_numEncodes);<br> <br>-        for (uint8_t pass = 0; pass < m_numEncodes; pass++)<br>+#if ENABLE_MULTIVIEW<br>+        if (m_passEnc[0]->m_param->numViews > 1)<br>         {<br>-            m_inputPicBuffer[pass] = X265_MALLOC(x265_picture*, m_queueSize);<br>-            for (uint32_t idx = 0; idx < m_queueSize; idx++)<br>+            for (uint8_t pass = 0; pass < m_passEnc[0]->m_param->numViews; pass++)<br>             {<br>-                m_inputPicBuffer[pass][idx] = x265_picture_alloc();<br>-                x265_picture_init(m_passEnc[pass]->m_param, m_inputPicBuffer[pass][idx]);<br>+                m_inputPicBuffer[pass] = X265_MALLOC(x265_picture*, m_queueSize);<br>+                for (uint32_t idx = 0; idx < m_queueSize; idx++)<br>+                {<br>+                    m_inputPicBuffer[pass][idx] = x265_picture_alloc();<br>+                    x265_picture_init(m_passEnc[0]->m_param, m_inputPicBuffer[pass][idx]);<br>+                }<br>+                if (pass == 0)<br>+                {<br>+                    CHECKED_MALLOC_ZERO(m_analysisBuffer[pass], x265_analysis_data, m_queueSize);<br>+                    m_picIdxReadCnt[pass] = new ThreadSafeInteger[m_queueSize];<br>+                    m_analysisWrite[pass] = new ThreadSafeInteger[m_queueSize];<br>+                    m_analysisRead[pass] = new ThreadSafeInteger[m_queueSize];<br>+                    m_readFlag[pass] = X265_MALLOC(int, m_queueSize);<br>+                }<br>             }<br>+        }<br>+        else<br>+        {<br>+#endif<br>+            for (uint8_t pass = 0; pass < m_numEncodes; pass++)<br>+            {<br>+                m_inputPicBuffer[pass] = X265_MALLOC(x265_picture*, m_queueSize);<br>+                for (uint32_t idx = 0; idx < m_queueSize; idx++)<br>+                {<br>+                    m_inputPicBuffer[pass][idx] = x265_picture_alloc();<br>+                    x265_picture_init(m_passEnc[pass]->m_param, m_inputPicBuffer[pass][idx]);<br>+                }<br> <br>-            CHECKED_MALLOC_ZERO(m_analysisBuffer[pass], x265_analysis_data, m_queueSize);<br>-            m_picIdxReadCnt[pass] = new ThreadSafeInteger[m_queueSize];<br>-            m_analysisWrite[pass] = new ThreadSafeInteger[m_queueSize];<br>-            m_analysisRead[pass] = new ThreadSafeInteger[m_queueSize];<br>-            m_readFlag[pass] = X265_MALLOC(int, m_queueSize);<br>+                CHECKED_MALLOC_ZERO(m_analysisBuffer[pass], x265_analysis_data, m_queueSize);<br>+                m_picIdxReadCnt[pass] = new ThreadSafeInteger[m_queueSize];<br>+                m_analysisWrite[pass] = new ThreadSafeInteger[m_queueSize];<br>+                m_analysisRead[pass] = new ThreadSafeInteger[m_queueSize];<br>+                m_readFlag[pass] = X265_MALLOC(int, m_queueSize);<br>+            }<br>+#if ENABLE_MULTIVIEW<br>         }<br>+#endif<br>         return true;<br>     fail:<br>         return false;<br>@@ -112,15 +143,37 @@ namespace X265_NS {<br>     void AbrEncoder::destroy()<br>     {<br>         x265_cleanup(); /* Free library singletons */<br>-        for (uint8_t pass = 0; pass < m_numEncodes; pass++)<br>+#if ENABLE_MULTIVIEW<br>+        for (uint8_t pass = 0; pass < MAX_VIEWS; pass++)<br>         {<br>             for (uint32_t index = 0; index < m_queueSize; index++)<br>             {<br>                 X265_FREE(m_inputPicBuffer[pass][index]->planes[0]);<br>                 x265_picture_free(m_inputPicBuffer[pass][index]);<br>             }<br>+            X265_FREE(m_inputPicBuffer[pass]);<br> <br>+            if (pass == 0)<br>+            {<br>+                X265_FREE(m_analysisBuffer[pass]);<br>+                X265_FREE(m_readFlag[pass]);<br>+                delete[] m_picIdxReadCnt[pass];<br>+                delete[] m_analysisWrite[pass];<br>+                delete[] m_analysisRead[pass];<br>+                m_passEnc[pass]->destroy();<br>+                delete m_passEnc[pass];<br>+            }<br>+        }<br>+#else<br>+        for (uint8_t pass = 0; pass < m_numEncodes; pass++)<br>+        {<br>+            for (uint32_t index = 0; index < m_queueSize; index++)<br>+            {<br>+                X265_FREE(m_inputPicBuffer[pass][index]->planes[0]);<br>+                x265_picture_free(m_inputPicBuffer[pass][index]);<br>+            }<br>             X265_FREE(m_inputPicBuffer[pass]);<br>+<br>             X265_FREE(m_analysisBuffer[pass]);<br>             X265_FREE(m_readFlag[pass]);<br>             delete[] m_picIdxReadCnt[pass];<br>@@ -129,6 +182,7 @@ namespace X265_NS {<br>             m_passEnc[pass]->destroy();<br>             delete m_passEnc[pass];<br>         }<br>+#endif<br>         X265_FREE(m_inputPicBuffer);<br>         X265_FREE(m_analysisBuffer);<br>         X265_FREE(m_readFlag);<br>@@ -150,8 +204,11 @@ namespace X265_NS {<br>         m_id = id;<br>         m_cliopt = cliopt;<br>         m_parent = parent;<br>-        if(!(m_cliopt.enableScaler && m_id))<br>-            m_input = m_cliopt.input;<br>+        if (!(m_cliopt.enableScaler && m_id))<br>+        {<br>+            for (int view = 0; view < m_cliopt.param->numViews; view++)<br>+                m_input[view] = m_cliopt.input[view];<br>+        }<br>         m_param = cliopt.param;<br>         m_inputOver = false;<br>         m_lastIdx = -1;<br>@@ -403,7 +460,7 @@ ret:<br>     }<br> <br> <br>-    bool PassEncoder::readPicture(x265_picture *dstPic)<br>+    bool PassEncoder::readPicture(x265_picture* dstPic, int view)<br>     {<br>         /*Check and wait if there any input frames to read*/<br>         int ipread = m_parent->m_picReadCnt[m_id].get();<br>@@ -481,7 +538,7 @@ ret:<br>             }<br> <br> <br>-            x265_picture *srcPic = (x265_picture*)(m_parent->m_inputPicBuffer[m_id][readPos]);<br>+            x265_picture* srcPic = (m_param->numViews > 1) ? (x265_picture*)(m_parent->m_inputPicBuffer[view][readPos]) : (x265_picture*)(m_parent->m_inputPicBuffer[m_id][readPos]);<br> <br>             x265_picture *pic = (x265_picture*)(dstPic);<br>             pic->colorSpace = srcPic->colorSpace;<br>@@ -531,12 +588,21 @@ ret:<br>                 x265_log(m_param, X265_LOG_ERROR, "Unable to register CTRL+C handler: %s in %s\n",<br>                     strerror(errno), profileName);<br> <br>-            x265_picture pic_orig, pic_out[MAX_SCALABLE_LAYERS];<br>-            x265_picture *pic_in = &pic_orig;<br>+            x265_picture pic_orig[MAX_VIEWS];<br>+            x265_picture *pic_in[MAX_VIEWS];<br>+            for (int view = 0; view < m_param->numViews; view++)<br>+                pic_in[view] = &pic_orig[view];<br>             /* Allocate recon picture if analysis save/load is enabled */<br>             std::priority_queue<int64_t>* pts_queue = m_cliopt.output->needPTS() ? new std::priority_queue<int64_t>() : NULL;<br>-            x265_picture *pic_recon[MAX_SCALABLE_LAYERS];<br>-            for(int i = 0; i < m_param->numScalableLayers; i++)<br>+#if ENABLE_MULTIVIEW<br>+            x265_picture* pic_recon[MAX_VIEWS];<br>+            x265_picture pic_out[MAX_VIEWS];<br>+            for (int i = 0; i < m_param->numViews; i++)<br>+#else<br>+            x265_picture* pic_recon[MAX_SCALABLE_LAYERS];<br>+            x265_picture pic_out[MAX_SCALABLE_LAYERS];<br>+            for (int i = 0; i < m_param->numScalableLayers; i++)<br>+#endif<br>                 pic_recon[i] = (m_cliopt.recon[i] || m_param->analysisSave || m_param->analysisLoad || pts_queue || reconPlay || m_param->csvLogLevel) ? &pic_out[i] : NULL;<br>             uint32_t inFrameCount = 0;<br>             uint32_t outFrameCount = 0;<br>@@ -563,22 +629,25 @@ ret:<br>                     m_cliopt.totalbytes += m_cliopt.output->writeHeaders(p_nal, nal);<br>             }<br> <br>-            if (m_param->bField && m_param->interlaceMode)<br>+            for (int view = 0; view < m_param->numViews; view++)<br>             {<br>-                api->picture_init(m_param, &picField1);<br>-                api->picture_init(m_param, &picField2);<br>-                // return back the original height of input<br>-                m_param->sourceHeight *= 2;<br>-                api->picture_init(m_param, &pic_orig);<br>+                if (m_param->bField && m_param->interlaceMode)<br>+                {<br>+                    api->picture_init(m_param, &picField1);<br>+                    api->picture_init(m_param, &picField2);<br>+                    // return back the original height of input<br>+                    m_param->sourceHeight *= 2;<br>+                    api->picture_init(m_param, &pic_orig[view]);<br>+                }<br>+                else<br>+                    api->picture_init(m_param, &pic_orig[view]);<br>             }<br>-            else<br>-                api->picture_init(m_param, &pic_orig);<br> <br>             if (m_param->dolbyProfile && m_cliopt.dolbyVisionRpu)<br>             {<br>                 rpuPayload = X265_MALLOC(uint8_t, 1024);<br>-                pic_in->rpu.payload = rpuPayload;<br>-                if (pic_in->rpu.payload)<br>+                pic_in[0]->rpu.payload = rpuPayload;<br>+                if (pic_in[0]->rpu.payload)<br>                     bDolbyVisionRPU = true;<br>             }<br> <br>@@ -592,132 +661,134 @@ ret:<br>             }<br> <br>             // main encoder loop<br>-            while (pic_in && !b_ctrl_c)<br>+            while (pic_in[0] && !b_ctrl_c)<br>             {<br>-                pic_orig.poc = (m_param->bField && m_param->interlaceMode) ? inFrameCount * 2 : inFrameCount;<br>-                if (m_cliopt.qpfile)<br>+                for (int view = 0; view < m_param->numViews; view++)<br>                 {<br>-                    if (!m_cliopt.parseQPFile(pic_orig))<br>+                    pic_orig[view].poc = (m_param->bField && m_param->interlaceMode) ? inFrameCount * 2 : inFrameCount;<br>+                    if (m_cliopt.qpfile)<br>                     {<br>-                        x265_log(NULL, X265_LOG_ERROR, "can't parse qpfile for frame %d in %s\n",<br>-                            pic_in->poc, profileName);<br>-                        fclose(m_cliopt.qpfile);<br>-                        m_cliopt.qpfile = NULL;<br>-                    }<br>-                }<br>-<br>-                if (m_cliopt.framesToBeEncoded && inFrameCount >= m_cliopt.framesToBeEncoded)<br>-                    pic_in = NULL;<br>-                else if (readPicture(pic_in))<br>-                    inFrameCount++;<br>-                else<br>-                    pic_in = NULL;<br>-<br>-                if (pic_in)<br>-                {<br>-                    if (pic_in->bitDepth > m_param->internalBitDepth && m_cliopt.bDither)<br>-                    {<br>-                        x265_dither_image(pic_in, m_cliopt.input->getWidth(), m_cliopt.input->getHeight(), errorBuf, m_param->internalBitDepth);<br>-                        pic_in->bitDepth = m_param->internalBitDepth;<br>+                        if (!m_cliopt.parseQPFile(pic_orig[view]))<br>+                        {<br>+                            x265_log(NULL, X265_LOG_ERROR, "can't parse qpfile for frame %d in %s\n",<br>+                                pic_in[view]->poc, profileName);<br>+                            fclose(m_cliopt.qpfile);<br>+                            m_cliopt.qpfile = NULL;<br>+                        }<br>                     }<br>-                    /* Overwrite PTS */<br>-                    pic_in->pts = pic_in->poc;<br> <br>-                    // convert to field<br>-                    if (m_param->bField && m_param->interlaceMode)<br>+                    if (m_cliopt.framesToBeEncoded && inFrameCount >= m_cliopt.framesToBeEncoded)<br>+                        pic_in[view] = NULL;<br>+                    else if (readPicture(pic_in[view], view) && view == m_param->numViews - 1)<br>+                        inFrameCount++;<br>+                    else if (!pic_in[view])<br>+                        pic_in[view] = NULL;<br>+                    if (pic_in[view])<br>                     {<br>-                        int height = pic_in->height >> 1;<br>+                        if (pic_in[view]->bitDepth > m_param->internalBitDepth && m_cliopt.bDither)<br>+                        {<br>+                            x265_dither_image(pic_in[view], m_cliopt.input[view]->getWidth(), m_cliopt.input[view]->getHeight(), errorBuf, m_param->internalBitDepth);<br>+                            pic_in[view]->bitDepth = m_param->internalBitDepth;<br>+                        }<br>+                        /* Overwrite PTS */<br>+                        pic_in[view]->pts = pic_in[view]->poc;<br> <br>-                        int static bCreated = 0;<br>-                        if (bCreated == 0)<br>+                        // convert to field<br>+                        if (m_param->bField && m_param->interlaceMode)<br>                         {<br>-                            bCreated = 1;<br>-                            inputPicNum = 2;<br>-                            picField1.fieldNum = 1;<br>-                            picField2.fieldNum = 2;<br>-<br>-                            picField1.bitDepth = picField2.bitDepth = pic_in->bitDepth;<br>-                            picField1.colorSpace = picField2.colorSpace = pic_in->colorSpace;<br>-                            picField1.height = picField2.height = pic_in->height >> 1;<br>-                            picField1.framesize = picField2.framesize = pic_in->framesize >> 1;<br>-<br>-                            size_t fieldFrameSize = (size_t)pic_in->framesize >> 1;<br>-                            char* field1Buf = X265_MALLOC(char, fieldFrameSize);<br>-                            char* field2Buf = X265_MALLOC(char, fieldFrameSize);<br>-<br>-                            int stride = picField1.stride[0] = picField2.stride[0] = pic_in->stride[0];<br>-                            uint64_t framesize = stride * (height >> x265_cli_csps[pic_in->colorSpace].height[0]);<br>-                            picField1.planes[0] = field1Buf;<br>-                            picField2.planes[0] = field2Buf;<br>-                            for (int i = 1; i < x265_cli_csps[pic_in->colorSpace].planes; i++)<br>+                            int height = pic_in[view]->height >> 1;<br>+<br>+                            int static bCreated = 0;<br>+                            if (bCreated == 0)<br>                             {<br>-                                picField1.planes[i] = field1Buf + framesize;<br>-                                picField2.planes[i] = field2Buf + framesize;<br>+                                bCreated = 1;<br>+                                inputPicNum = 2;<br>+                                picField1.fieldNum = 1;<br>+                                picField2.fieldNum = 2;<br>+<br>+                                picField1.bitDepth = picField2.bitDepth = pic_in[view]->bitDepth;<br>+                                picField1.colorSpace = picField2.colorSpace = pic_in[view]->colorSpace;<br>+                                picField1.height = picField2.height = pic_in[view]->height >> 1;<br>+                                picField1.framesize = picField2.framesize = pic_in[view]->framesize >> 1;<br>+<br>+                                size_t fieldFrameSize = (size_t)pic_in[view]->framesize >> 1;<br>+                                char* field1Buf = X265_MALLOC(char, fieldFrameSize);<br>+                                char* field2Buf = X265_MALLOC(char, fieldFrameSize);<br>+<br>+                                int stride = picField1.stride[0] = picField2.stride[0] = pic_in[0]->stride[0];<br>+                                uint64_t framesize = stride * (height >> x265_cli_csps[pic_in[view]->colorSpace].height[0]);<br>+                                picField1.planes[0] = field1Buf;<br>+                                picField2.planes[0] = field2Buf;<br>+                                for (int i = 1; i < x265_cli_csps[pic_in[0]->colorSpace].planes; i++)<br>+                                {<br>+                                    picField1.planes[i] = field1Buf + framesize;<br>+                                    picField2.planes[i] = field2Buf + framesize;<br> <br>-                                stride = picField1.stride[i] = picField2.stride[i] = pic_in->stride[i];<br>-                                framesize += (stride * (height >> x265_cli_csps[pic_in->colorSpace].height[i]));<br>+                                    stride = picField1.stride[i] = picField2.stride[i] = pic_in[view]->stride[i];<br>+                                    framesize += (stride * (height >> x265_cli_csps[pic_in[view]->colorSpace].height[i]));<br>+                                }<br>+                                assert(framesize == picField1.framesize);<br>                             }<br>-                            assert(framesize == picField1.framesize);<br>-                        }<br> <br>-                        picField1.pts = picField1.poc = pic_in->poc;<br>-                        picField2.pts = picField2.poc = pic_in->poc + 1;<br>+                            picField1.pts = picField1.poc = pic_in[view]->poc;<br>+                            picField2.pts = picField2.poc = pic_in[view]->poc + 1;<br> <br>-                        picField1.userSEI = picField2.userSEI = pic_in->userSEI;<br>+                            picField1.userSEI = picField2.userSEI = pic_in[view]->userSEI;<br> <br>-                        //if (pic_in->userData)<br>-                        //{<br>-                        //    // Have to handle userData here<br>-                        //}<br>+                            //if (pic_in->userData)<br>+                            //{<br>+                            //    // Have to handle userData here<br>+                            //}<br> <br>-                        if (pic_in->framesize)<br>-                        {<br>-                            for (int i = 0; i < x265_cli_csps[pic_in->colorSpace].planes; i++)<br>+                            if (pic_in[view]->framesize)<br>                             {<br>-                                char* srcP1 = (char*)pic_in->planes[i];<br>-                                char* srcP2 = (char*)pic_in->planes[i] + pic_in->stride[i];<br>-                                char* p1 = (char*)picField1.planes[i];<br>-                                char* p2 = (char*)picField2.planes[i];<br>-<br>-                                int stride = picField1.stride[i];<br>-<br>-                                for (int y = 0; y < (height >> x265_cli_csps[pic_in->colorSpace].height[i]); y++)<br>+                                for (int i = 0; i < x265_cli_csps[pic_in[view]->colorSpace].planes; i++)<br>                                 {<br>-                                    memcpy(p1, srcP1, stride);<br>-                                    memcpy(p2, srcP2, stride);<br>-                                    srcP1 += 2 * stride;<br>-                                    srcP2 += 2 * stride;<br>-                                    p1 += stride;<br>-                                    p2 += stride;<br>+                                    char* srcP1 = (char*)pic_in[view]->planes[i];<br>+                                    char* srcP2 = (char*)pic_in[view]->planes[i] + pic_in[view]->stride[i];<br>+                                    char* p1 = (char*)picField1.planes[i];<br>+                                    char* p2 = (char*)picField2.planes[i];<br>+<br>+                                    int stride = picField1.stride[i];<br>+<br>+                                    for (int y = 0; y < (height >> x265_cli_csps[pic_in[view]->colorSpace].height[i]); y++)<br>+                                    {<br>+                                        memcpy(p1, srcP1, stride);<br>+                                        memcpy(p2, srcP2, stride);<br>+                                        srcP1 += 2 * stride;<br>+                                        srcP2 += 2 * stride;<br>+                                        p1 += stride;<br>+                                        p2 += stride;<br>+                                    }<br>                                 }<br>                             }<br>                         }<br>-                    }<br> <br>-                    if (bDolbyVisionRPU)<br>-                    {<br>-                        if (m_param->bField && m_param->interlaceMode)<br>+                        if (bDolbyVisionRPU)<br>                         {<br>-                            if (m_cliopt.rpuParser(&picField1) > 0)<br>-                                goto fail;<br>-                            if (m_cliopt.rpuParser(&picField2) > 0)<br>-                                goto fail;<br>-                        }<br>-                        else<br>-                        {<br>-                            if (m_cliopt.rpuParser(pic_in) > 0)<br>-                                goto fail;<br>+                            if (m_param->bField && m_param->interlaceMode)<br>+                            {<br>+                                if (m_cliopt.rpuParser(&picField1) > 0)<br>+                                    goto fail;<br>+                                if (m_cliopt.rpuParser(&picField2) > 0)<br>+                                    goto fail;<br>+                            }<br>+                            else<br>+                            {<br>+                                if (m_cliopt.rpuParser(pic_in[view]) > 0)<br>+                                    goto fail;<br>+                            }<br>                         }<br>                     }<br>                 }<br> <br>                 for (int inputNum = 0; inputNum < inputPicNum; inputNum++)<br>                 {<br>-                    x265_picture *picInput = NULL;<br>+                    x265_picture* picInput = NULL;<br>                     if (inputPicNum == 2)<br>                         picInput = pic_in ? (inputNum ? &picField2 : &picField1) : NULL;<br>                     else<br>-                        picInput = pic_in;<br>+                        picInput = *pic_in;<br> <br>                     int numEncoded = api->encoder_encode(m_encoder, &p_nal, &nal, picInput, pic_recon);<br> <br>@@ -1057,7 +1128,8 @@ ret:<br>     {<br>         m_parentEnc = parentEnc;<br>         m_id = id;<br>-        m_input = parentEnc->m_input;<br>+        for (int view = 0; view < MAX_VIEWS; view++)<br>+            m_input[view] = parentEnc->m_input[view];<br>     }<br> <br>     void Reader::threadMain()<br>@@ -1083,43 +1155,47 @@ ret:<br>                 read = m_parentEnc->m_parent->m_picIdxReadCnt[m_id][writeIdx].waitForChange(read);<br>             }<br> <br>-            x265_picture* dest = m_parentEnc->m_parent->m_inputPicBuffer[m_id][writeIdx];<br>-            if (m_input->readPicture(*src))<br>+            for (int view = 0; view < m_parentEnc->m_param->numViews; view++)<br>             {<br>-                dest->poc = src->poc;<br>-                dest->pts = src->pts;<br>-                dest->userSEI = src->userSEI;<br>-                dest->bitDepth = src->bitDepth;<br>-                dest->framesize = src->framesize;<br>-                dest->height = src->height;<br>-                dest->width = src->width;<br>-                dest->colorSpace = src->colorSpace;<br>-                dest->userSEI = src->userSEI;<br>-                dest->rpu.payload = src->rpu.payload;<br>-                dest->picStruct = src->picStruct;<br>-                dest->stride[0] = src->stride[0];<br>-                dest->stride[1] = src->stride[1];<br>-                dest->stride[2] = src->stride[2];<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>+                x265_picture* dest = m_parentEnc->m_parent->m_inputPicBuffer[view][writeIdx];<br>+                if (m_input[view]->readPicture(*src))<br>+                {<br>+                    dest->poc = src->poc;<br>+                    dest->pts = src->pts;<br>+                    dest->userSEI = src->userSEI;<br>+                    dest->bitDepth = src->bitDepth;<br>+                    dest->framesize = src->framesize;<br>+                    dest->height = src->height;<br>+                    dest->width = src->width;<br>+                    dest->colorSpace = src->colorSpace;<br>+                    dest->userSEI = src->userSEI;<br>+                    dest->rpu.payload = src->rpu.payload;<br>+                    dest->picStruct = src->picStruct;<br>+                    dest->stride[0] = src->stride[0];<br>+                    dest->stride[1] = src->stride[1];<br>+                    dest->stride[2] = src->stride[2];<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> #if ENABLE_ALPHA<br>-                if (m_parentEnc->m_param->bEnableAlpha)<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>+                        m_parentEnc->m_parent->m_picWriteCnt[m_id].incr();<br>+                }<br>+                else<br>                 {<br>-                    dest->planes[3] = (char*)dest->planes[2] + src->stride[2] * (src->height >> x265_cli_csps[src->colorSpace].height[2]);<br>+                    m_threadActive = false;<br>+                    m_parentEnc->m_inputOver = true;<br>+                    m_parentEnc->m_parent->m_picWriteCnt[m_id].poke();<br>                 }<br>-#endif<br>-                m_parentEnc->m_parent->m_picWriteCnt[m_id].incr();<br>-            }<br>-            else<br>-            {<br>-                m_threadActive = false;<br>-                m_parentEnc->m_inputOver = true;<br>-                m_parentEnc->m_parent->m_picWriteCnt[m_id].poke();<br>             }<br>         }<br>         x265_picture_free(src);<br>diff --git a/source/abrEncApp.h b/source/abrEncApp.h<br>index f7ff6d96d..43b202cc5 100644<br>--- a/source/abrEncApp.h<br>+++ b/source/abrEncApp.h<br>@@ -86,7 +86,7 @@ namespace X265_NS {<br>         x265_picture **m_outputRecon;<br> <br>         CLIOptions m_cliopt;<br>-        InputFile* m_input;<br>+        InputFile* m_input[MAX_VIEWS];<br>         const char* m_reconPlayCmd;<br>         FILE*    m_qpfile;<br>         FILE*    m_zoneFile;<br>@@ -102,7 +102,7 @@ namespace X265_NS {<br>         void startThreads();<br>         void copyInfo(x265_analysis_data *src);<br> <br>-        bool readPicture(x265_picture*);<br>+        bool readPicture(x265_picture*, int view);<br>         void destroy();<br> <br>     private:<br>@@ -142,7 +142,7 @@ namespace X265_NS {<br>     public:<br>         PassEncoder *m_parentEnc;<br>         int m_id;<br>-        InputFile* m_input;<br>+        InputFile* m_input[MAX_VIEWS];<br>         int m_threadActive;<br> <br>         Reader(int id, PassEncoder *parentEnc);<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index 88dd4b3fb..55248ff2a 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -1478,7 +1478,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>     if (m_aborted)<br>         return -1;<br> <br>-    const x265_picture* inputPic = NULL;<br>+    const x265_picture* inputPic[MAX_VIEWS] = { NULL };<br>     static int written = 0, read = 0;<br>     bool dontRead = false;<br>     bool dropflag = false;<br>@@ -1576,16 +1576,24 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br> <br>             if (read < written)<br>             {<br>-                inputPic = m_dupBuffer[0]->dupPic;<br>+                inputPic[0] = m_dupBuffer[0]->dupPic;<br>                 read++;<br>             }<br>         }<br>         else<br>-            inputPic = pic_in;<br>+        {<br>+            for (int view = 0; view < m_param->numViews; view++)<br>+                inputPic[view] = pic_in + view;<br>+        }<br> <br>+        x265_param* p = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;<br>+#if ENABLE_MULTIVIEW<br>+        Frame* inFrame[MAX_VIEWS];<br>+        for (int layer = 0; layer < m_param->numViews; layer++)<br>+#else<br>         Frame* inFrame[MAX_SCALABLE_LAYERS];<br>-        x265_param *p = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;<br>         for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+#endif<br>         {<br>             if (m_dpb->m_freeList.empty())<br>             {<br>@@ -1593,7 +1601,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>                 inFrame[layer]->m_encodeStartTime = x265_mdate();<br>                 inFrame[layer]->m_sLayerId = layer;<br>                 inFrame[layer]->m_valid = false;<br>-                if (inFrame[layer]->create(p, inputPic->quantOffsets))<br>+                if (inFrame[layer]->create(p, inputPic[layer]->quantOffsets))<br>                 {<br>                     /* the first PicYuv created is asked to generate the CU and block unit offset<br>                      * arrays which are then shared with all subsequent PicYuv (orig and recon)<br>@@ -1661,11 +1669,11 @@ 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>-            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic, *m_param, m_sps.conformanceWindow.rightOffset, m_sps.conformanceWindow.bottomOffset, !layer);<br>+            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic[layer], *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->userData;<br>-            inFrame[layer]->m_pts = inputPic->pts;<br>+            inFrame[layer]->m_userData = inputPic[0]->userData;<br>+            inFrame[layer]->m_pts = inputPic[0]->pts;<br> <br>             if ((m_param->bEnableSceneCutAwareQp & BACKWARD) && m_param->rc.bStatRead)<br>             {<br>@@ -1684,33 +1692,33 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>                 }<br>             }<br> <br>-            inFrame[layer]->m_forceqp = inputPic->forceqp;<br>+            inFrame[layer]->m_forceqp = inputPic[0]->forceqp;<br>             inFrame[layer]->m_param = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;<br>-            inFrame[layer]->m_picStruct = inputPic->picStruct;<br>+            inFrame[layer]->m_picStruct = inputPic[0]->picStruct;<br>             if (m_param->bField && m_param->interlaceMode)<br>-                inFrame[layer]->m_fieldNum = inputPic->fieldNum;<br>+                inFrame[layer]->m_fieldNum = inputPic[0]->fieldNum;<br> <br>             /* Encoder holds a reference count until stats collection is finished */<br>             ATOMIC_INC(&inFrame[layer]->m_countRefEncoders);<br>         }<br>-        copyUserSEIMessages(inFrame[0], inputPic);<br>+        copyUserSEIMessages(inFrame[0], inputPic[0]);<br> <br>         /*Copy Dolby Vision RPU from inputPic to frame*/<br>-        if (inputPic->rpu.payloadSize)<br>+        if (inputPic[0]->rpu.payloadSize)<br>         {<br>-            inFrame[0]->m_rpu.payloadSize = inputPic->rpu.payloadSize;<br>-            inFrame[0]->m_rpu.payload = new uint8_t[inputPic->rpu.payloadSize];<br>-            memcpy(inFrame[0]->m_rpu.payload, inputPic->rpu.payload, inputPic->rpu.payloadSize);<br>+            inFrame[0]->m_rpu.payloadSize = inputPic[0]->rpu.payloadSize;<br>+            inFrame[0]->m_rpu.payload = new uint8_t[inputPic[0]->rpu.payloadSize];<br>+            memcpy(inFrame[0]->m_rpu.payload, inputPic[0]->rpu.payload, inputPic[0]->rpu.payloadSize);<br>         }<br> <br>-        if (inputPic->quantOffsets != NULL)<br>+        if (inputPic[0]->quantOffsets != NULL)<br>         {<br>             int cuCount;<br>             if (m_param->rc.qgSize == 8)<br>                 cuCount = inFrame[0]->m_lowres.maxBlocksInRowFullRes * inFrame[0]->m_lowres.maxBlocksInColFullRes;<br>             else<br>                 cuCount = inFrame[0]->m_lowres.maxBlocksInRow * inFrame[0]->m_lowres.maxBlocksInCol;<br>-            memcpy(inFrame[0]->m_quantOffsets, inputPic->quantOffsets, cuCount * sizeof(float));<br>+            memcpy(inFrame[0]->m_quantOffsets, inputPic[0]->quantOffsets, cuCount * sizeof(float));<br>         }<br> <br>         if (m_pocLast == 0)<br>@@ -1730,7 +1738,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br> <br>         /* Use the frame types from the first pass, if available */<br>         int sliceType = (m_param->rc.bStatRead) ? m_rateControl->rateControlSliceType(inFrame[0]->m_poc) : X265_TYPE_AUTO;<br>-        inFrame[0]->m_lowres.sliceTypeReq = inputPic->sliceType;<br>+        inFrame[0]->m_lowres.sliceTypeReq = inputPic[0]->sliceType;<br> <br>         /* In analysisSave mode, x265_analysis_data is allocated in inputPic and inFrame points to this */<br>         /* Load analysis data before lookahead->addPicture, since sliceType has been decided */<br>@@ -1740,7 +1748,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>             static int paramBytes = CONF_OFFSET_BYTES;<br>             if (!inFrame[0]->m_poc && m_param->bAnalysisType != HEVC_INFO)<br>             {<br>-                x265_analysis_validate saveParam = inputPic->analysisData.saveParam;<br>+                x265_analysis_validate saveParam = inputPic[0]->analysisData.saveParam;<br>                 paramBytes += validateAnalysisData(&saveParam, 0);<br>                 if (paramBytes == -1)<br>                 {<br>@@ -1761,10 +1769,10 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>                 uint32_t outOfBoundaryLowresH = extendedHeight - m_param->sourceHeight / 2;<br>                 if (outOfBoundaryLowresH * 2 >= m_param->maxCUSize)<br>                     cuLocInFrame.skipHeight = true;<br>-                readAnalysisFile(&inFrame[0]->m_analysisData, inFrame[0]->m_poc, inputPic, paramBytes, cuLocInFrame);<br>+                readAnalysisFile(&inFrame[0]->m_analysisData, inFrame[0]->m_poc, inputPic[0], paramBytes, cuLocInFrame);<br>             }<br>             else<br>-                readAnalysisFile(&inFrame[0]->m_analysisData, inFrame[0]->m_poc, inputPic, paramBytes);<br>+                readAnalysisFile(&inFrame[0]->m_analysisData, inFrame[0]->m_poc, inputPic[0], paramBytes);<br>             inFrame[0]->m_poc = inFrame[0]->m_analysisData.poc;<br>             sliceType = inFrame[0]->m_analysisData.sliceType;<br>             inFrame[0]->m_lowres.bScenecut = !!inFrame[0]->m_analysisData.bScenecut;<br>@@ -1785,9 +1793,9 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>                 }<br>             }<br>         }<br>-        if (m_param->bUseRcStats && inputPic->rcData)<br>+        if (m_param->bUseRcStats && inputPic[0]->rcData)<br>         {<br>-            RcStats* rc = (RcStats*)inputPic->rcData;<br>+            RcStats* rc = (RcStats*)inputPic[0]->rcData;<br>             m_rateControl->m_accumPQp = rc->cumulativePQp;<br>             m_rateControl->m_accumPNorm = rc->cumulativePNorm;<br>             m_rateControl->m_isNextGop = true;<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index 86e1d9bd8..b2b357beb 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -423,9 +423,12 @@ namespace X265_NS {<br>             free(argString);<br>         }<br> <br>-        if (input)<br>-            input->release();<br>-        input = NULL;<br>+        for (int i = 0; i < MAX_VIEWS; i++)<br>+        {<br>+            if (input[i])<br>+                input[i]->release();<br>+            input[i] = NULL;<br>+        }<br>         for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)<br>         {<br>             if (recon[i])<br>@@ -828,9 +831,17 @@ namespace X265_NS {<br>             }<br>         }<br> #endif<br>-        if (!inputfn[0] || !outputfn)<br>+        if (!outputfn)<br>         {<br>             x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");<br>+            for (int view = 0; view < param->numViews; view++)<br>+            {<br>+                if (!inputfn[view])<br>+                {<br>+                    x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");<br>+                    return true;<br>+                }<br>+            }<br>             return true;<br>         }<br> <br>@@ -851,50 +862,53 @@ namespace X265_NS {<br>             svtParam->encoderBitDepth = inputBitDepth;<br>         }<br> #endif<br>-<br>-        InputFileInfo info;<br>-        info.filename = inputfn[0];<br>-        info.depth = inputBitDepth;<br>-        info.csp = param->internalCsp;<br>-        info.width = param->sourceWidth;<br>-        info.height = param->sourceHeight;<br>-        info.fpsNum = param->fpsNum;<br>-        info.fpsDenom = param->fpsDenom;<br>-        info.sarWidth = param->vui.sarWidth;<br>-        info.sarHeight = param->vui.sarHeight;<br>-        info.skipFrames = seek;<br>-        info.frameCount = 0;<br>-        getParamAspectRatio(param, info.sarWidth, info.sarHeight);<br>-<br>-        this->input = InputFile::open(info, this->bForceY4m, param->bEnableAlpha);<br>-        if (!this->input || this->input->isFail())<br>+        InputFileInfo info[MAX_VIEWS];<br>+        for (int i = 0; i < param->numViews; i++)<br>         {<br>-            x265_log_file(param, X265_LOG_ERROR, "unable to open input file <%s>\n", inputfn);<br>-            return true;<br>-        }<br>+            info[i].filename = inputfn[i];<br>+            info[i].depth = inputBitDepth;<br>+            info[i].csp = param->internalCsp;<br>+            info[i].width = param->sourceWidth;<br>+            info[i].height = param->sourceHeight;<br>+            info[i].fpsNum = param->fpsNum;<br>+            info[i].fpsDenom = param->fpsDenom;<br>+            info[i].sarWidth = param->vui.sarWidth;<br>+            info[i].sarHeight = param->vui.sarHeight;<br>+            info[i].skipFrames = seek;<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>+            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>+                return true;<br>+            }<br> <br>-        if (info.depth < 8 || info.depth > 16)<br>-        {<br>-            x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);<br>-            return true;<br>+            if (info[i].depth < 8 || info[i].depth > 16)<br>+            {<br>+                x265_log(param, X265_LOG_ERROR, "Input bit depth (%d) must be between 8 and 16\n", inputBitDepth);<br>+                return true;<br>+            }<br>         }<br> <br>+            //TODO:Validate info params of both the views to equal values<br>         /* Unconditionally accept height/width/csp/bitDepth from file info */<br>-        param->sourceWidth = info.width;<br>-        param->sourceHeight = info.height;<br>-        param->internalCsp = info.csp;<br>-        param->sourceBitDepth = info.depth;<br>+            param->sourceWidth = info[0].width;<br>+            param->sourceHeight = info[0].height;<br>+            param->internalCsp = info[0].csp;<br>+            param->sourceBitDepth = info[0].depth;<br> <br>         /* Accept fps and sar from file info if not specified by user */<br>         if (param->fpsDenom == 0 || param->fpsNum == 0)<br>         {<br>-            param->fpsDenom = info.fpsDenom;<br>-            param->fpsNum = info.fpsNum;<br>+            param->fpsDenom = info[0].fpsDenom;<br>+            param->fpsNum = info[0].fpsNum;<br>         }<br>-        if (!param->vui.aspectRatioIdc && info.sarWidth && info.sarHeight)<br>-            setParamAspectRatio(param, info.sarWidth, info.sarHeight);<br>-        if (this->framesToBeEncoded == 0 && info.frameCount > (int)seek)<br>-            this->framesToBeEncoded = info.frameCount - seek;<br>+        if (!param->vui.aspectRatioIdc && info[0].sarWidth && info[0].sarHeight)<br>+            setParamAspectRatio(param, info[0].sarWidth, info[0].sarHeight);<br>+        if (this->framesToBeEncoded == 0 && info[0].frameCount > (int)seek)<br>+            this->framesToBeEncoded = info[0].frameCount - seek;<br>         param->totalFrames = this->framesToBeEncoded;<br> <br> #ifdef SVT_HEVC<br>@@ -911,8 +925,8 @@ namespace X265_NS {<br> #endif<br> <br>         /* Force CFR until we have support for VFR */<br>-        info.timebaseNum = param->fpsDenom;<br>-        info.timebaseDenom = param->fpsNum;<br>+        info[0].timebaseNum = param->fpsDenom;<br>+        info[0].timebaseDenom = param->fpsNum;<br> <br>         if (param->bField && param->interlaceMode)<br>         {   // Field FPS<br>@@ -930,22 +944,24 @@ namespace X265_NS {<br>         {<br>             char buf[128];<br>             int p = sprintf(buf, "%dx%d fps %d/%d %sp%d", param->sourceWidth, param->sourceHeight,<br>-                param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info.depth);<br>+                param->fpsNum, param->fpsDenom, x265_source_csp_names[param->internalCsp], info[0].depth);<br> <br>             int width, height;<br>             getParamAspectRatio(param, width, height);<br>             if (width && height)<br>                 p += sprintf(buf + p, " sar %d:%d", width, height);<br> <br>-            if (framesToBeEncoded <= 0 || info.frameCount <= 0)<br>+            if (framesToBeEncoded <= 0 || info[0].frameCount <= 0)<br>                 strcpy(buf + p, " unknown frame count");<br>             else<br>-                sprintf(buf + p, " frames %u - %d of %d", this->seek, this->seek + this->framesToBeEncoded - 1, info.frameCount);<br>+                sprintf(buf + p, " frames %u - %d of %d", this->seek, this->seek + this->framesToBeEncoded - 1, info[0].frameCount);<br> <br>-            general_log(param, input->getName(), X265_LOG_INFO, "%s\n", buf);<br>+            for (int view = 0; view < param->numViews; view++)<br>+                general_log(param, input[view]->getName(), X265_LOG_INFO, "%s\n", buf);<br>         }<br> <br>-        this->input->startReader();<br>+        for (int view = 0; view < param->numViews; view++)<br>+            this->input[view]->startReader();<br> <br>         if (reconfn[0])<br>         {<br>@@ -1006,7 +1022,7 @@ namespace X265_NS {<br>             return true;<br>         }<br> #endif<br>-        this->output = OutputFile::open(outputfn, info);<br>+        this->output = OutputFile::open(outputfn, info[0]);<br>         if (this->output->isFail())<br>         {<br>             x265_log_file(param, X265_LOG_ERROR, "failed to open output file <%s> for writing\n", outputfn);<br>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 0fdad9cf3..0613c81e5 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -400,7 +400,7 @@ static const struct option long_options[] =<br> <br>     struct CLIOptions<br>     {<br>-        InputFile* input;<br>+        InputFile* input[MAX_VIEWS];<br>         ReconFile* recon[MAX_SCALABLE_LAYERS];<br>         OutputFile* output;<br>         FILE*       qpfile;<br>@@ -441,7 +441,8 @@ static const struct option long_options[] =<br>         static const int UPDATE_INTERVAL = 250000;<br>         CLIOptions()<br>         {<br>-            input = NULL;<br>+            for (int i = 0; i < MAX_VIEWS; i++)<br>+                input[i] = NULL;<br>             for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)<br>                 recon[i] = NULL;<br>             output = NULL;<br>-- <br>2.36.0.windows.1<br><br></div>