<div dir="ltr">From 120d31502652ba9e5eccbf4627be2094b2cb2e92 Mon Sep 17 00:00:00 2001<br>From: Kirithika <<a href="mailto:kirithika@multicorewareinc.com">kirithika@multicorewareinc.com</a>><br>Date: Fri, 12 Jul 2024 16:03:28 +0530<br>Subject: [PATCH 05/10] This commit does the following things:<br><br>1.Extend the encoding and reconstruction support for multiview<br>2.Add support for reference picture set construction<br><br>---<br> source/abrEncApp.cpp            | 25 ++++------<br> source/common/param.cpp         |  3 ++<br> source/common/picyuv.h          |  2 +-<br> source/common/slice.cpp         | 60 +++++++++++++++++++++++-<br> source/common/slice.h           | 11 ++---<br> source/encoder/api.cpp          |  6 +--<br> source/encoder/dpb.cpp          |  7 +++<br> source/encoder/encoder.cpp      | 82 +++++++++++++++++++++------------<br> source/encoder/encoder.h        | 10 ++--<br> source/encoder/frameencoder.cpp | 14 +++---<br> source/encoder/frameencoder.h   | 36 +++++++--------<br> source/encoder/search.cpp       |  6 ++-<br> source/x265.h                   |  6 +++<br> source/x265cli.cpp              | 13 +++---<br> source/x265cli.h                |  4 +-<br> 15 files changed, 190 insertions(+), 95 deletions(-)<br><br>diff --git a/source/abrEncApp.cpp b/source/abrEncApp.cpp<br>index 6874c4d74..b14db5900 100644<br>--- a/source/abrEncApp.cpp<br>+++ b/source/abrEncApp.cpp<br>@@ -594,15 +594,10 @@ ret:<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>-#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>+            x265_picture* pic_recon[MAX_LAYERS];<br>+            x265_picture pic_out[MAX_LAYERS];<br>+<br>+            for (int i = 0; i < m_param->numLayers; i++)<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>@@ -818,10 +813,10 @@ ret:<br>                         copyInfo(analysisInfo);<br>                     }<br> <br>-                    for (int i = 0; i < m_param->numScalableLayers; i++)<br>+                    for (int layer = 0; layer < m_param->numLayers; layer++)<br>                     {<br>-                        if (numEncoded && pic_recon[i] && m_cliopt.recon[i])<br>-                            m_cliopt.recon[i]->writePicture(pic_out[i]);<br>+                        if (numEncoded && pic_recon[layer] && m_cliopt.recon[layer])<br>+                            m_cliopt.recon[layer]->writePicture(pic_out[layer]);<br>                     }<br>                     if (nal)<br>                     {<br>@@ -856,10 +851,10 @@ ret:<br>                     copyInfo(analysisInfo);<br>                 }<br> <br>-                for (int i = 0; i < m_param->numScalableLayers; i++)<br>+                for (int layer = 0; layer < m_param->numLayers; layer++)<br>                 {<br>-                    if (numEncoded && pic_recon[i] && m_cliopt.recon[i])<br>-                        m_cliopt.recon[i]->writePicture(pic_out[i]);<br>+                    if (numEncoded && pic_recon[layer] && m_cliopt.recon[layer])<br>+                        m_cliopt.recon[layer]->writePicture(pic_out[layer]);<br>                 }<br>                 if (nal)<br>                 {<br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index c2efb11cf..8b7d268d2 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -406,6 +406,8 @@ void x265_param_default(x265_param* param)<br> <br>     /* Multi-View Encoding*/<br>     param->numViews = 1;<br>+<br>+    param->numLayers = 1;<br> }<br> <br> int x265_param_default_preset(x265_param* param, const char* preset, const char* tune)<br>@@ -2916,6 +2918,7 @@ void x265_copy_params(x265_param* dst, x265_param* src)<br> #if ENABLE_MULTIVIEW<br>     dst->numViews = src->numViews;<br> #endif<br>+    dst->numLayers = src->numLayers;<br> <br>     if (src->videoSignalTypePreset) dst->videoSignalTypePreset = strdup(src->videoSignalTypePreset);<br>     else dst->videoSignalTypePreset = NULL;<br>diff --git a/source/common/picyuv.h b/source/common/picyuv.h<br>index ec9ff69c2..89d843f38 100644<br>--- a/source/common/picyuv.h<br>+++ b/source/common/picyuv.h<br>@@ -83,7 +83,7 @@ public:<br>     void  destroy();<br>     int   getLumaBufLen(uint32_t picWidth, uint32_t picHeight, uint32_t picCsp);<br> <br>-    void  copyFromPicture(const x265_picture&, const x265_param& param, int padx, int pady, bool isBase);<br>+    void  copyFromPicture(const x265_picture&, const x265_param& param, int padx, int pady, bool isBase = true);<br>     void  copyFromFrame(PicYuv* source);<br> <br>     intptr_t getChromaAddrOffset(uint32_t ctuAddr, uint32_t absPartIdx) const { return m_cuOffsetC[ctuAddr] + m_buOffsetC[absPartIdx]; }<br>diff --git a/source/common/slice.cpp b/source/common/slice.cpp<br>index dd257b48d..7f62695ee 100644<br>--- a/source/common/slice.cpp<br>+++ b/source/common/slice.cpp<br>@@ -29,7 +29,31 @@<br> <br> using namespace X265_NS;<br> <br>-void Slice::setRefPicList(PicList& picList, int sLayerId)<br>+#if ENABLE_MULTIVIEW<br>+void Slice::createInterLayerReferencePictureSet(PicList& picList, PicList& refPicSetInterLayer0, PicList& refPicSetInterLayer1)<br>+{<br>+<br>+    for (int i = 0; i < 1; i++)<br>+    {<br>+        int layerIdRef = 0;// getRefPicLayerId(i);<br>+        Frame* refPic = picList.getPOC(m_poc, 0);<br>+        int viewIdCur = 0;<br>+        int viewIdZero = 1;<br>+        int viewIdRef = 1;<br>+<br>+        if ((viewIdCur <= viewIdZero && viewIdCur <= viewIdRef) || (viewIdCur >= viewIdZero && viewIdCur >= viewIdRef))<br>+        {<br>+            refPicSetInterLayer0.pushBackSubDPB(*refPic);<br>+        }<br>+        else<br>+        {<br>+            refPicSetInterLayer1.pushBackSubDPB(*refPic);<br>+        }<br>+    }<br>+}<br>+#endif<br>+<br>+void Slice::setRefPicList(PicList& picList, PicList& refPicSetInterLayer0, PicList& refPicSetInterLayer1, int sLayerId)<br> {<br>     if (m_sliceType == I_SLICE)<br>     {<br>@@ -75,18 +99,34 @@ void Slice::setRefPicList(PicList& picList, int sLayerId)<br>     // ref_pic_list_init<br>     Frame* rpsCurrList0[MAX_NUM_REF + 1];<br>     Frame* rpsCurrList1[MAX_NUM_REF + 1];<br>+#if ENABLE_MULTIVIEW<br>+    int numPocTotalCurr = numPocStCurr0 + numPocStCurr1 + numPocLtCurr + refPicSetInterLayer0.size() + refPicSetInterLayer1.size();<br>+#else<br>     int numPocTotalCurr = numPocStCurr0 + numPocStCurr1 + numPocLtCurr;<br>+#endif<br> <br>     int cIdx = 0;<br>     for (i = 0; i < numPocStCurr0; i++, cIdx++)<br>         rpsCurrList0[cIdx] = refPicSetStCurr0[i];<br> <br>+#if ENABLE_MULTIVIEW<br>+    if (m_param->numViews > 1)<br>+        for (i = 0; i < refPicSetInterLayer0.size(); i++, cIdx++)<br>+            rpsCurrList0[cIdx] = refPicSetInterLayer0.getPOC(m_poc, 0);<br>+#endif<br>+<br>     for (i = 0; i < numPocStCurr1; i++, cIdx++)<br>         rpsCurrList0[cIdx] = refPicSetStCurr1[i];<br> <br>     for (i = 0; i < numPocLtCurr; i++, cIdx++)<br>         rpsCurrList0[cIdx] = refPicSetLtCurr[i];<br> <br>+#if ENABLE_MULTIVIEW<br>+    if (m_param->numViews > 1)<br>+        for (i = 0; i < refPicSetInterLayer1.size(); i++, cIdx++)<br>+            rpsCurrList0[cIdx] = refPicSetInterLayer1.getPOC(m_poc, 0);<br>+#endif<br>+<br>     X265_CHECK(cIdx == numPocTotalCurr, "RPS index check fail\n");<br> <br>     if (m_sliceType == B_SLICE)<br>@@ -95,12 +135,24 @@ void Slice::setRefPicList(PicList& picList, int sLayerId)<br>         for (i = 0; i < numPocStCurr1; i++, cIdx++)<br>             rpsCurrList1[cIdx] = refPicSetStCurr1[i];<br> <br>+#if ENABLE_MULTIVIEW<br>+        if (m_param->numViews > 1)<br>+            for (i = 0; i < refPicSetInterLayer1.size(); i++, cIdx++)<br>+                rpsCurrList1[cIdx] = refPicSetInterLayer1.getPOC(m_poc, 0);<br>+#endif<br>+<br>         for (i = 0; i < numPocStCurr0; i++, cIdx++)<br>             rpsCurrList1[cIdx] = refPicSetStCurr0[i];<br> <br>         for (i = 0; i < numPocLtCurr; i++, cIdx++)<br>             rpsCurrList1[cIdx] = refPicSetLtCurr[i];<br> <br>+#if ENABLE_MULTIVIEW<br>+        if (m_param->numViews > 1)<br>+            for (i = 0; i < refPicSetInterLayer0.size(); i++, cIdx++)<br>+                rpsCurrList1[cIdx] = refPicSetInterLayer0.getPOC(m_poc, 0);<br>+#endif<br>+<br>         X265_CHECK(cIdx == numPocTotalCurr, "RPS index check fail\n");<br>     }<br> <br>@@ -109,6 +161,9 @@ void Slice::setRefPicList(PicList& picList, int sLayerId)<br>         cIdx = rIdx % numPocTotalCurr;<br>         X265_CHECK(cIdx >= 0 && cIdx < numPocTotalCurr, "RPS index check fail\n");<br>         m_refFrameList[0][rIdx] = rpsCurrList0[cIdx];<br>+#if ENABLE_MULTIVIEW<br>+        m_refFrameList[0][rIdx] = rpsCurrList0[cIdx];<br>+#endif<br>     }<br> <br>     if (m_sliceType != B_SLICE)<br>@@ -123,6 +178,9 @@ void Slice::setRefPicList(PicList& picList, int sLayerId)<br>             cIdx = rIdx % numPocTotalCurr;<br>             X265_CHECK(cIdx >= 0 && cIdx < numPocTotalCurr, "RPS index check fail\n");<br>             m_refFrameList[1][rIdx] = rpsCurrList1[cIdx];<br>+#if ENABLE_MULTIVIEW<br>+            m_refFrameList[1][rIdx] = rpsCurrList1[cIdx];<br>+#endif<br>         }<br>     }<br> <br>diff --git a/source/common/slice.h b/source/common/slice.h<br>index 9a05840a0..90009ae7f 100644<br>--- a/source/common/slice.h<br>+++ b/source/common/slice.h<br>@@ -109,11 +109,7 @@ namespace Level {<br> <br> struct ProfileTierLevel<br> {<br>-#if ENABLE_MULTIVIEW<br>-    int      profileIdc[MAX_VIEWS];<br>-#else<br>-    int      profileIdc[MAX_SCALABLE_LAYERS];<br>-#endif<br>+    int      profileIdc[MAX_LAYERS];<br>     int      levelIdc;<br>     uint32_t minCrForLevel;<br>     uint32_t maxLumaSrForLevel;<br>@@ -425,7 +421,10 @@ public:<br> <br>     void disableWeights();<br> <br>-    void setRefPicList(PicList& picList, int sLayerId);<br>+    void setRefPicList(PicList& picList, PicList& refPicSetInterLayer0, PicList& refPicSetInterLayer1, int viewId);<br>+#if ENABLE_MULTIVIEW<br>+    void createInterLayerReferencePictureSet(PicList& picList, PicList& refPicSetInterLayer0, PicList& refPicSetInterLayer1);<br>+#endif<br> <br>     bool getRapPicFlag() const<br>     {<br>diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp<br>index 88bc25550..96baf56c9 100644<br>--- a/source/encoder/api.cpp<br>+++ b/source/encoder/api.cpp<br>@@ -603,7 +603,7 @@ fail:<br> <br>     if (numEncoded && encoder->m_param->csvLogLevel && encoder->m_outputCount >= encoder->m_latestParam->chunkStart)<br>     {<br>-        for (int layer = 0; layer < encoder->m_param->numScalableLayers; layer++)<br>+        for (int layer = 0; layer < encoder->m_param->numLayers; layer++)<br>             x265_csvlog_frame(encoder->m_param, pic_out[layer]);<br>     }<br> <br>@@ -656,10 +656,10 @@ void x265_encoder_log(x265_encoder* enc, int argc, char **argv)<br>     if (enc)<br>     {<br>         Encoder *encoder = static_cast<Encoder*>(enc);<br>-        x265_stats stats[MAX_SCALABLE_LAYERS];<br>+        x265_stats stats[MAX_LAYERS];<br>         int padx = encoder->m_sps.conformanceWindow.rightOffset;<br>         int pady = encoder->m_sps.conformanceWindow.bottomOffset;<br>-        for (int layer = 0; layer < encoder->m_param->numScalableLayers; layer++)<br>+        for (int layer = 0; layer < encoder->m_param->numLayers; layer++)<br>         {<br>             encoder->fetchStats(stats, sizeof(stats[layer]), layer);<br>             x265_csvlog_encode(encoder->m_param, &stats[0], padx, pady, argc, argv);<br>diff --git a/source/encoder/dpb.cpp b/source/encoder/dpb.cpp<br>index bce49b500..3b4934df5 100644<br>--- a/source/encoder/dpb.cpp<br>+++ b/source/encoder/dpb.cpp<br>@@ -328,6 +328,13 @@ void DPB::computeRPS(int curPoc, int tempId, bool isRAP, RPS * rps, unsigned int<br>         {<br>             if ((!m_bTemporalSublayer || (iterPic->m_tempLayer <= tempId)) && ((m_lastIDR >= curPoc) || (m_lastIDR <= iterPic->m_poc)))<br>             {<br>+#if ENABLE_MULTIVIEW<br>+                    if (layer && numNeg == iterPic->m_param->maxNumReferences - 1 && (iterPic->m_poc - curPoc) < 0)<br>+                    {<br>+                        iterPic = iterPic->m_next;<br>+                        continue;<br>+                    }<br>+#endif<br>                     rps->poc[poci] = iterPic->m_poc;<br>                     rps->deltaPOC[poci] = rps->poc[poci] - curPoc;<br>                     (rps->deltaPOC[poci] < 0) ? numNeg++ : numPos++;<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index ef152f2ae..8a1ed9d88 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -149,7 +149,7 @@ Encoder::Encoder()<br>     m_rpsInSpsCount = 0;<br>     m_cB = 1.0;<br>     m_cR = 1.0;<br>-    for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)<br>+    for (int i = 0; i < MAX_LAYERS; i++)<br>         m_exportedPic[i] = NULL;<br>     for (int i = 0; i < X265_MAX_FRAME_THREADS; i++)<br>         m_frameEncoder[i] = NULL;<br>@@ -862,7 +862,7 @@ void Encoder::destroy()<br>         X265_FREE(m_rdCost);<br>         X265_FREE(m_trainingCount);<br>     }<br>-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+    for (int layer = 0; layer < m_param->numLayers; layer++)<br>     {<br>         if (m_exportedPic[layer])<br>         {<br>@@ -1488,7 +1488,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>         if (!m_param->bUseAnalysisFile && m_param->analysisSave)<br>             x265_free_analysis_data(m_param, &m_exportedPic[0]->m_analysisData);<br> <br>-        for (int i = 0; i < m_param->numScalableLayers; i++)<br>+        for (int i = 0; i < m_param->numLayers; i++)<br>         {<br>             ATOMIC_DEC(&m_exportedPic[i]->m_countRefEncoders);<br>             m_exportedPic[i] = NULL;<br>@@ -1587,19 +1587,18 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<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>-        for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>-#endif<br>+        Frame* inFrame[MAX_LAYERS];<br>+        for (int layer = 0; layer < m_param->numLayers; layer++)<br>         {<br>             if (m_dpb->m_freeList.empty())<br>             {<br>                 inFrame[layer] = new Frame;<br>                 inFrame[layer]->m_encodeStartTime = x265_mdate();<br>+#if ENABLE_MULTIVIEW<br>+                inFrame[layer]->m_viewId = layer;<br>+#else<br>                 inFrame[layer]->m_sLayerId = layer;<br>+#endif<br>                 inFrame[layer]->m_valid = false;<br>                 if (inFrame[layer]->create(p, inputPic[layer]->quantOffsets))<br>                 {<br>@@ -1670,10 +1669,43 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br> #endif<br>                 inFrame[layer]->m_valid = false;<br>                 inFrame[layer]->m_lowres.bKeyframe = false;<br>+#if ENABLE_MULTIVIEW<br>+                //Destroy interlayer References<br>+                //TODO Move this to end(after compress frame)<br>+                if (inFrame[layer]->refPicSetInterLayer0.size())<br>+                {<br>+                    Frame* iterFrame = inFrame[layer]->refPicSetInterLayer0.first();<br>+<br>+                    while (iterFrame)<br>+                    {<br>+                        Frame* curFrame = iterFrame;<br>+                        iterFrame = iterFrame->m_nextSubDPB;<br>+                        inFrame[layer]->refPicSetInterLayer0.removeSubDPB(*curFrame);<br>+                        iterFrame = inFrame[layer]->refPicSetInterLayer0.first();<br>+                    }<br>+                }<br>+<br>+                if (inFrame[layer]->refPicSetInterLayer1.size())<br>+                {<br>+                    Frame* iterFrame = inFrame[layer]->refPicSetInterLayer1.first();<br>+<br>+                    while (iterFrame)<br>+                    {<br>+                        Frame* curFrame = iterFrame;<br>+                        iterFrame = iterFrame->m_nextSubDPB;<br>+                        inFrame[layer]->refPicSetInterLayer1.removeSubDPB(*curFrame);<br>+                        iterFrame = inFrame[layer]->refPicSetInterLayer1.first();<br>+                    }<br>+                }<br>+#endif<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> <br>             inFrame[layer]->m_poc = (!layer) ? (++m_pocLast) : m_pocLast;<br>             inFrame[layer]->m_userData = inputPic[0]->userData;<br>@@ -1919,7 +1951,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>      * input picture before returning so the order must be reversed. This do/while() loop allows<br>      * us to alternate the order of the calls without ugly code replication */<br>     Frame** outFrames = { NULL };<br>-    Frame* frameEnc[MAX_SCALABLE_LAYERS] = { NULL };<br>+    Frame* frameEnc[MAX_LAYERS] = { NULL };<br>     int pass = 0;<br>     do<br>     {<br>@@ -1930,7 +1962,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>             outFrames = curEncoder->getEncodedPicture(m_nalList);<br>         if (outFrames)<br>         {<br>-            for (int sLayer = 0; sLayer < m_param->numScalableLayers; sLayer++)<br>+            for (int sLayer = 0; sLayer < m_param->numLayers; sLayer++)<br>             {<br>                 Frame* outFrame = *(outFrames + sLayer);<br>                 Slice* slice = outFrame->m_encData->m_slice;<br>@@ -2163,7 +2195,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>                 m_outputCount++;<br>                 if (m_param->chunkEnd == m_outputCount)<br>                     m_numDelayedPic = 0;<br>-                else if (outFrame->m_sLayerId == m_param->bEnableAlpha)<br>+                else if (sLayer == m_param->numLayers -1)<br>                     m_numDelayedPic--;<br> <br>                 ret = 1;<br>@@ -2176,10 +2208,10 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>             frameEnc[0] = m_lookahead->getDecidedPicture();<br>         if (frameEnc[0] && !pass && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd)))<br>         {<br>+<br> #if ENABLE_ALPHA || ENABLE_MULTIVIEW<br>             //Pop non base view pictures from DPB piclist<br>-            int numLayers = m_param->numViews > 1 ? m_param->numViews : (m_param->numScalableLayers > 1) ? m_param->numScalableLayers : 1;<br>-            for (int layer = 1; layer < numLayers; layer++)<br>+            for (int layer = 1; layer < m_param->numLayers; layer++)<br>             {<br>                 Frame* currentFrame = m_dpb->m_picList.getPOC(frameEnc[0]->m_poc, layer);<br>                 frameEnc[layer] = m_dpb->m_picList.removeFrame(*currentFrame);<br>@@ -2254,7 +2286,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>             curEncoder->m_reconfigure = m_reconfigure;<br> <br>             /* give this frame a FrameData instance before encoding */<br>-            for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+            for (int layer = 0; layer < m_param->numLayers; layer++)<br>             {<br>                 if (m_dpb->m_frameDataFreeList)<br>                 {<br>@@ -2385,7 +2417,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>                 }<br>             }<br>             /* determine references, setup RPS, etc */<br>-            for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+            for (int layer = 0; layer < m_param->numLayers; layer++)<br>                 m_dpb->prepareEncode(frameEnc[layer]);<br> <br>             if (m_param->bEnableTemporalFilter)<br>@@ -2407,7 +2439,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture** pic_out)<br>                 m_origPicBuffer->setOrigPicList(frameEnc[0], m_pocLast);<br>             }<br> <br>-            for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+            for (int layer = 0; layer < m_param->numLayers; layer++)<br>             {<br>                 if (!!m_param->selectiveSAO)<br>                 {<br>@@ -2762,7 +2794,7 @@ void Encoder::printSummary()<br>     if (m_param->logLevel < X265_LOG_INFO)<br>         return;<br> <br>-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+    for (int layer = 0; layer < m_param->numLayers; layer++)<br>     {<br>         char buffer[200];<br>         if (m_analyzeI[layer].m_numPics)<br>@@ -3316,11 +3348,7 @@ void Encoder::getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs)<br>     bs.writeByteAlignment();<br>     list.serialize(NAL_UNIT_VPS, bs);<br> <br>-#if ENABLE_MULTIVIEW<br>-    for (int layer = 0; layer < m_param->numViews; layer++)<br>-#else<br>-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>-#endif<br>+    for (int layer = 0; layer < m_param->numLayers; layer++)<br>     {<br>         bs.resetBits();<br>         sbacCoder.codeSPS(m_sps, m_scalingList, m_vps.ptl, layer);<br>@@ -3328,11 +3356,7 @@ void Encoder::getStreamHeaders(NALList& list, Entropy& sbacCoder, Bitstream& bs)<br>         list.serialize(NAL_UNIT_SPS, bs, layer);<br>     }<br> <br>-#if ENABLE_MULTIVIEW<br>-    for (int layer = 0; layer < m_param->numViews; layer++)<br>-#else<br>-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>-#endif<br>+    for (int layer = 0; layer < m_param->numLayers; layer++)<br>     {<br>         bs.resetBits();<br>         sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1), m_iPPSQpMinus26, layer);<br>diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h<br>index 58709e92e..1dbb41596 100644<br>--- a/source/encoder/encoder.h<br>+++ b/source/encoder/encoder.h<br>@@ -202,7 +202,7 @@ public:<br>     ThreadPool*        m_threadPool;<br>     FrameEncoder*      m_frameEncoder[X265_MAX_FRAME_THREADS];<br>     DPB*               m_dpb;<br>-    Frame*             m_exportedPic[MAX_SCALABLE_LAYERS];<br>+    Frame*             m_exportedPic[MAX_LAYERS];<br>     FILE*              m_analysisFileIn;<br>     FILE*              m_analysisFileOut;<br>     FILE*              m_naluFile;<br>@@ -217,10 +217,10 @@ public:<br> <br>     bool               m_externalFlush;<br>     /* Collect statistics globally */<br>-    EncStats           m_analyzeAll[MAX_SCALABLE_LAYERS];<br>-    EncStats           m_analyzeI[MAX_SCALABLE_LAYERS];<br>-    EncStats           m_analyzeP[MAX_SCALABLE_LAYERS];<br>-    EncStats           m_analyzeB[MAX_SCALABLE_LAYERS];<br>+    EncStats           m_analyzeAll[MAX_LAYERS];<br>+    EncStats           m_analyzeI[MAX_LAYERS];<br>+    EncStats           m_analyzeP[MAX_LAYERS];<br>+    EncStats           m_analyzeB[MAX_LAYERS];<br>     VPS                m_vps;<br>     SPS                m_sps;<br>     PPS                m_pps;<br>diff --git a/source/encoder/frameencoder.cpp b/source/encoder/frameencoder.cpp<br>index 1aab82b77..97d033fb6 100644<br>--- a/source/encoder/frameencoder.cpp<br>+++ b/source/encoder/frameencoder.cpp<br>@@ -58,7 +58,7 @@ FrameEncoder::FrameEncoder()<br>     m_ctuGeomMap = NULL;<br>     m_localTldIdx = 0;<br>     memset(&m_rce, 0, sizeof(RateControlEntry));<br>-    for (int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)<br>+    for (int layer = 0; layer < MAX_LAYERS; layer++)<br>     {<br>         m_prevOutputTime[layer] = x265_mdate();<br>         m_slicetypeWaitTime[layer] = 0;<br>@@ -220,8 +220,8 @@ bool FrameEncoder::init(Encoder *top, int numRows, int numCols)<br>             ok &= !!m_frameEncTF->createRefPicInfo(&m_mcstfRefList[i], m_param);<br>     }<br> <br>-    m_retFrameBuffer = X265_MALLOC(Frame*, m_param->numScalableLayers);<br>-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+    m_retFrameBuffer = X265_MALLOC(Frame*, m_param->numLayers);<br>+    for (int layer = 0; layer < m_param->numLayers; layer++)<br>         m_retFrameBuffer[layer] = NULL;<br>     return ok;<br> }<br>@@ -289,9 +289,9 @@ bool FrameEncoder::initializeGeoms()<br>     return true;<br> }<br> <br>-bool FrameEncoder::startCompressFrame(Frame* curFrame[MAX_SCALABLE_LAYERS])<br>+bool FrameEncoder::startCompressFrame(Frame* curFrame[MAX_LAYERS])<br> {<br>-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)<br>+    for (int layer = 0; layer < m_param->numLayers; layer++)<br>     {<br>         m_slicetypeWaitTime[layer] = x265_mdate() - m_prevOutputTime[layer];<br>         m_frame[layer] = curFrame[layer];<br>@@ -374,7 +374,7 @@ void FrameEncoder::threadMain()<br>                 m_frame[0]->m_copyMVType.wait();<br>         }<br> <br>-        for(int layer = 0; layer < m_param->numScalableLayers; layer ++)<br>+        for (int layer = 0; layer < m_param->numLayers; layer++)<br>             compressFrame(layer);<br>         m_done.trigger(); /* FrameEncoder::getEncodedPicture() blocks for this event */<br>         m_enable.wait();<br>@@ -2282,7 +2282,7 @@ Frame** FrameEncoder::getEncodedPicture(NALList& output)<br>         /* block here until worker thread completes */<br>         m_done.wait();<br> <br>-        for (int i = 0; i < m_param->numScalableLayers; i++)<br>+        for (int i = 0; i < m_param->numLayers; i++)<br>         {<br>             m_retFrameBuffer[i] = m_frame[i];<br>             m_frame[i] = NULL;<br>diff --git a/source/encoder/frameencoder.h b/source/encoder/frameencoder.h<br>index 6253cbd84..ebc6e57c5 100644<br>--- a/source/encoder/frameencoder.h<br>+++ b/source/encoder/frameencoder.h<br>@@ -156,7 +156,7 @@ public:<br>     void destroy();<br> <br>     /* triggers encode of a new frame by the worker thread */<br>-    bool startCompressFrame(Frame* curFrame[MAX_SCALABLE_LAYERS]);<br>+    bool startCompressFrame(Frame* curFrame[MAX_LAYERS]);<br> <br>     /* blocks until worker thread is done, returns access unit */<br>     Frame **getEncodedPicture(NALList& list);<br>@@ -190,34 +190,34 @@ public:<br>     RateControlEntry         m_rce;<br>     SEIDecodedPictureHash    m_seiReconPictureDigest;<br> <br>-    uint64_t                 m_SSDY[MAX_SCALABLE_LAYERS];<br>-    uint64_t                 m_SSDU[MAX_SCALABLE_LAYERS];<br>-    uint64_t                 m_SSDV[MAX_SCALABLE_LAYERS];<br>-    double                   m_ssim[MAX_SCALABLE_LAYERS];<br>-    uint64_t                 m_accessUnitBits[MAX_SCALABLE_LAYERS];<br>-    uint32_t                 m_ssimCnt[MAX_SCALABLE_LAYERS];<br>+    uint64_t                 m_SSDY[MAX_LAYERS];<br>+    uint64_t                 m_SSDU[MAX_LAYERS];<br>+    uint64_t                 m_SSDV[MAX_LAYERS];<br>+    double                   m_ssim[MAX_LAYERS];<br>+    uint64_t                 m_accessUnitBits[MAX_LAYERS];<br>+    uint32_t                 m_ssimCnt[MAX_LAYERS];<br> <br>     volatile int             m_activeWorkerCount;        // count of workers currently encoding or filtering CTUs<br>     volatile int             m_totalActiveWorkerCount;   // sum of m_activeWorkerCount sampled at end of each CTU<br>     volatile int             m_activeWorkerCountSamples; // count of times m_activeWorkerCount was sampled (think vbv restarts)<br>     volatile int             m_countRowBlocks;           // count of workers forced to abandon a row because of top dependency<br>-    int64_t                  m_startCompressTime[MAX_SCALABLE_LAYERS];        // timestamp when frame encoder is given a frame<br>-    int64_t                  m_row0WaitTime[MAX_SCALABLE_LAYERS];             // timestamp when row 0 is allowed to start<br>-    int64_t                  m_allRowsAvailableTime[MAX_SCALABLE_LAYERS];     // timestamp when all reference dependencies are resolved<br>-    int64_t                  m_endCompressTime[MAX_SCALABLE_LAYERS];          // timestamp after all CTUs are compressed<br>-    int64_t                  m_endFrameTime[MAX_SCALABLE_LAYERS];             // timestamp after RCEnd, NR updates, etc<br>-    int64_t                  m_stallStartTime[MAX_SCALABLE_LAYERS];           // timestamp when worker count becomes 0<br>-    int64_t                  m_prevOutputTime[MAX_SCALABLE_LAYERS];           // timestamp when prev frame was retrieved by API thread<br>-    int64_t                  m_slicetypeWaitTime[MAX_SCALABLE_LAYERS];        // total elapsed time waiting for decided frame<br>-    int64_t                  m_totalWorkerElapsedTime[MAX_SCALABLE_LAYERS];   // total elapsed time spent by worker threads processing CTUs<br>-    int64_t                  m_totalNoWorkerTime[MAX_SCALABLE_LAYERS];        // total elapsed time without any active worker threads<br>+    int64_t                  m_startCompressTime[MAX_LAYERS];        // timestamp when frame encoder is given a frame<br>+    int64_t                  m_row0WaitTime[MAX_LAYERS];             // timestamp when row 0 is allowed to start<br>+    int64_t                  m_allRowsAvailableTime[MAX_LAYERS];     // timestamp when all reference dependencies are resolved<br>+    int64_t                  m_endCompressTime[MAX_LAYERS];          // timestamp after all CTUs are compressed<br>+    int64_t                  m_endFrameTime[MAX_LAYERS];             // timestamp after RCEnd, NR updates, etc<br>+    int64_t                  m_stallStartTime[MAX_LAYERS];           // timestamp when worker count becomes 0<br>+    int64_t                  m_prevOutputTime[MAX_LAYERS];           // timestamp when prev frame was retrieved by API thread<br>+    int64_t                  m_slicetypeWaitTime[MAX_LAYERS];        // total elapsed time waiting for decided frame<br>+    int64_t                  m_totalWorkerElapsedTime[MAX_LAYERS];   // total elapsed time spent by worker threads processing CTUs<br>+    int64_t                  m_totalNoWorkerTime[MAX_LAYERS];        // total elapsed time without any active worker threads<br> #if DETAILED_CU_STATS<br>     CUStats                  m_cuStats;<br> #endif<br> <br>     Encoder*                 m_top;<br>     x265_param*              m_param;<br>-    Frame*                   m_frame[MAX_SCALABLE_LAYERS];<br>+    Frame*                   m_frame[MAX_LAYERS];<br>     Frame**                  m_retFrameBuffer;<br>     NoiseReduction*          m_nr;<br>     ThreadLocalData*         m_tld; /* for --no-wpp */<br>diff --git a/source/encoder/search.cpp b/source/encoder/search.cpp<br>index 001115782..3218f4a24 100644<br>--- a/source/encoder/search.cpp<br>+++ b/source/encoder/search.cpp<br>@@ -2102,7 +2102,8 @@ void Search::singleMotionEstimation(Search& master, Mode& interMode, const Predi<br>     if (!m_param->analysisSave && !m_param->analysisLoad) /* Prevents load/save outputs from diverging if lowresMV is not available */<br>     {<br>         MV lmv = getLowresMV(interMode.cu, pu, list, ref);<br>-        if (lmv.notZero() && !m_frame->m_sLayerId)<br>+        int layer = m_param->numViews > 1 ? m_frame->m_viewId : (m_param->numScalableLayers > 1) ? m_frame->m_sLayerId : 0;<br>+        if (lmv.notZero() && !layer)<br>             mvc[numMvc++] = lmv;<br>         if (m_param->bEnableHME)<br>             mvp_lowres = lmv;<br>@@ -2413,7 +2414,8 @@ void Search::predInterSearch(Mode& interMode, const CUGeom& cuGeom, bool bChroma<br>                     if (!m_param->analysisSave && !m_param->analysisLoad) /* Prevents load/save outputs from diverging when lowresMV is not available */<br>                     {<br>                         MV lmv = getLowresMV(cu, pu, list, ref);<br>-                        if (lmv.notZero() && !m_frame->m_sLayerId)<br>+                        int layer = m_param->numViews > 1 ? m_frame->m_viewId : (m_param->numScalableLayers > 1) ? m_frame->m_sLayerId : 0;<br>+                        if (lmv.notZero() && !layer)<br>                             mvc[numMvc++] = lmv;<br>                         if (m_param->bEnableHME)<br>                             mvp_lowres = lmv;<br>diff --git a/source/x265.h b/source/x265.h<br>index 091696e03..49880d0f3 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -643,6 +643,10 @@ typedef enum<br> #define MAX_SCALABLE_LAYERS     1<br> #endif<br> <br>+#if ENABLE_ALPHA || ENABLE_MULTIVIEW<br>+#define MAX_LAYERS              2<br>+#endif<br>+<br> #define X265_IPRATIO_STRENGTH   1.43<br> <br> typedef struct x265_cli_csp<br>@@ -2296,6 +2300,8 @@ typedef struct x265_param<br> <br>     /*Multi View Encoding*/<br>     int      numViews;<br>+<br>+    int      numLayers;<br> } x265_param;<br> <br> /* x265_param_alloc:<br>diff --git a/source/x265cli.cpp b/source/x265cli.cpp<br>index b2b357beb..cd42a3bfa 100755<br>--- a/source/x265cli.cpp<br>+++ b/source/x265cli.cpp<br>@@ -429,7 +429,7 @@ namespace X265_NS {<br>                 input[i]->release();<br>             input[i] = NULL;<br>         }<br>-        for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)<br>+        for (int i = 0; i < MAX_LAYERS; i++)<br>         {<br>             if (recon[i])<br>                 recon[i]->release();<br>@@ -595,7 +595,7 @@ namespace X265_NS {<br>         {<br>             inputfn[view] = X265_MALLOC(char, sizeof(char) * 1024);<br>         }<br>-        const char* reconfn[MAX_SCALABLE_LAYERS] = { NULL };<br>+        const char* reconfn[MAX_LAYERS] = { NULL };<br>         const char *outputfn = NULL;<br>         const char *preset = NULL;<br>         const char *tune = NULL;<br>@@ -831,6 +831,7 @@ namespace X265_NS {<br>             }<br>         }<br> #endif<br>+        param->numLayers = param->numViews > 1 ? param->numViews : (param->numScalableLayers > 1) ? param->numScalableLayers : 1;<br>         if (!outputfn)<br>         {<br>             x265_log(param, X265_LOG_ERROR, "input or output file not specified, try --help for help\n");<br>@@ -967,13 +968,13 @@ namespace X265_NS {<br>         {<br>             if (reconFileBitDepth == 0)<br>                 reconFileBitDepth = param->internalBitDepth;<br>-#if ENABLE_ALPHA<br>-            if (param->bEnableAlpha)<br>+#if ENABLE_ALPHA || ENABLE_MULTIVIEW<br>+            if (param->bEnableAlpha || param->numViews > 1)<br>             {<br>                 char* temp = new char[strlen(reconfn[0])];<br>                 strcpy(temp, reconfn[0]);<br>                 const char* token = strtok(temp, ".");<br>-                for (int view = 0; view < param->numScalableLayers; view++)<br>+                for (int view = 0; view < param->numLayers; view++)<br>                 {<br>                     char* buf = new char[strlen(temp) + 7];<br>                     sprintf(buf, "%s-%d.yuv", token, view);<br>@@ -981,7 +982,7 @@ namespace X265_NS {<br>                 }<br>             }<br> #endif<br>-            for (int i = 0; i < param->numScalableLayers; i++)<br>+            for (int i = 0; i < param->numLayers; 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>diff --git a/source/x265cli.h b/source/x265cli.h<br>index 0613c81e5..49a88d084 100644<br>--- a/source/x265cli.h<br>+++ b/source/x265cli.h<br>@@ -401,7 +401,7 @@ static const struct option long_options[] =<br>     struct CLIOptions<br>     {<br>         InputFile* input[MAX_VIEWS];<br>-        ReconFile* recon[MAX_SCALABLE_LAYERS];<br>+        ReconFile* recon[MAX_LAYERS];<br>         OutputFile* output;<br>         FILE*       qpfile;<br>         FILE*       zoneFile;<br>@@ -443,7 +443,7 @@ static const struct option long_options[] =<br>         {<br>             for (int i = 0; i < MAX_VIEWS; i++)<br>                 input[i] = NULL;<br>-            for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)<br>+            for (int i = 0; i < MAX_LAYERS; i++)<br>                 recon[i] = NULL;<br>             output = NULL;<br>             qpfile = NULL;<br>-- <br>2.36.0.windows.1<br><br></div>