[x265] [PATCH MV-HEVC 05/10] Add encoding and reconstruction support for multiview

Anusuya Kumarasamy anusuya.kumarasamy at multicorewareinc.com
Tue Aug 6 10:49:13 UTC 2024


>From 120d31502652ba9e5eccbf4627be2094b2cb2e92 Mon Sep 17 00:00:00 2001
From: Kirithika <kirithika at multicorewareinc.com>
Date: Fri, 12 Jul 2024 16:03:28 +0530
Subject: [PATCH 05/10] This commit does the following things:

1.Extend the encoding and reconstruction support for multiview
2.Add support for reference picture set construction

---
 source/abrEncApp.cpp            | 25 ++++------
 source/common/param.cpp         |  3 ++
 source/common/picyuv.h          |  2 +-
 source/common/slice.cpp         | 60 +++++++++++++++++++++++-
 source/common/slice.h           | 11 ++---
 source/encoder/api.cpp          |  6 +--
 source/encoder/dpb.cpp          |  7 +++
 source/encoder/encoder.cpp      | 82 +++++++++++++++++++++------------
 source/encoder/encoder.h        | 10 ++--
 source/encoder/frameencoder.cpp | 14 +++---
 source/encoder/frameencoder.h   | 36 +++++++--------
 source/encoder/search.cpp       |  6 ++-
 source/x265.h                   |  6 +++
 source/x265cli.cpp              | 13 +++---
 source/x265cli.h                |  4 +-
 15 files changed, 190 insertions(+), 95 deletions(-)

diff --git a/source/abrEncApp.cpp b/source/abrEncApp.cpp
index 6874c4d74..b14db5900 100644
--- a/source/abrEncApp.cpp
+++ b/source/abrEncApp.cpp
@@ -594,15 +594,10 @@ ret:
                 pic_in[view] = &pic_orig[view];
             /* Allocate recon picture if analysis save/load is enabled */
             std::priority_queue<int64_t>* pts_queue =
m_cliopt.output->needPTS() ? new std::priority_queue<int64_t>() : NULL;
-#if ENABLE_MULTIVIEW
-            x265_picture* pic_recon[MAX_VIEWS];
-            x265_picture pic_out[MAX_VIEWS];
-            for (int i = 0; i < m_param->numViews; i++)
-#else
-            x265_picture* pic_recon[MAX_SCALABLE_LAYERS];
-            x265_picture pic_out[MAX_SCALABLE_LAYERS];
-            for (int i = 0; i < m_param->numScalableLayers; i++)
-#endif
+            x265_picture* pic_recon[MAX_LAYERS];
+            x265_picture pic_out[MAX_LAYERS];
+
+            for (int i = 0; i < m_param->numLayers; i++)
                 pic_recon[i] = (m_cliopt.recon[i] || m_param->analysisSave
|| m_param->analysisLoad || pts_queue || reconPlay || m_param->csvLogLevel)
? &pic_out[i] : NULL;
             uint32_t inFrameCount = 0;
             uint32_t outFrameCount = 0;
@@ -818,10 +813,10 @@ ret:
                         copyInfo(analysisInfo);
                     }

-                    for (int i = 0; i < m_param->numScalableLayers; i++)
+                    for (int layer = 0; layer < m_param->numLayers;
layer++)
                     {
-                        if (numEncoded && pic_recon[i] &&
m_cliopt.recon[i])
-                            m_cliopt.recon[i]->writePicture(pic_out[i]);
+                        if (numEncoded && pic_recon[layer] &&
m_cliopt.recon[layer])
+
 m_cliopt.recon[layer]->writePicture(pic_out[layer]);
                     }
                     if (nal)
                     {
@@ -856,10 +851,10 @@ ret:
                     copyInfo(analysisInfo);
                 }

-                for (int i = 0; i < m_param->numScalableLayers; i++)
+                for (int layer = 0; layer < m_param->numLayers; layer++)
                 {
-                    if (numEncoded && pic_recon[i] && m_cliopt.recon[i])
-                        m_cliopt.recon[i]->writePicture(pic_out[i]);
+                    if (numEncoded && pic_recon[layer] &&
m_cliopt.recon[layer])
+
 m_cliopt.recon[layer]->writePicture(pic_out[layer]);
                 }
                 if (nal)
                 {
diff --git a/source/common/param.cpp b/source/common/param.cpp
index c2efb11cf..8b7d268d2 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -406,6 +406,8 @@ void x265_param_default(x265_param* param)

     /* Multi-View Encoding*/
     param->numViews = 1;
+
+    param->numLayers = 1;
 }

 int x265_param_default_preset(x265_param* param, const char* preset, const
char* tune)
@@ -2916,6 +2918,7 @@ void x265_copy_params(x265_param* dst, x265_param*
src)
 #if ENABLE_MULTIVIEW
     dst->numViews = src->numViews;
 #endif
+    dst->numLayers = src->numLayers;

     if (src->videoSignalTypePreset) dst->videoSignalTypePreset =
strdup(src->videoSignalTypePreset);
     else dst->videoSignalTypePreset = NULL;
diff --git a/source/common/picyuv.h b/source/common/picyuv.h
index ec9ff69c2..89d843f38 100644
--- a/source/common/picyuv.h
+++ b/source/common/picyuv.h
@@ -83,7 +83,7 @@ public:
     void  destroy();
     int   getLumaBufLen(uint32_t picWidth, uint32_t picHeight, uint32_t
picCsp);

-    void  copyFromPicture(const x265_picture&, const x265_param& param,
int padx, int pady, bool isBase);
+    void  copyFromPicture(const x265_picture&, const x265_param& param,
int padx, int pady, bool isBase = true);
     void  copyFromFrame(PicYuv* source);

     intptr_t getChromaAddrOffset(uint32_t ctuAddr, uint32_t absPartIdx)
const { return m_cuOffsetC[ctuAddr] + m_buOffsetC[absPartIdx]; }
diff --git a/source/common/slice.cpp b/source/common/slice.cpp
index dd257b48d..7f62695ee 100644
--- a/source/common/slice.cpp
+++ b/source/common/slice.cpp
@@ -29,7 +29,31 @@

 using namespace X265_NS;

-void Slice::setRefPicList(PicList& picList, int sLayerId)
+#if ENABLE_MULTIVIEW
+void Slice::createInterLayerReferencePictureSet(PicList& picList, PicList&
refPicSetInterLayer0, PicList& refPicSetInterLayer1)
+{
+
+    for (int i = 0; i < 1; i++)
+    {
+        int layerIdRef = 0;// getRefPicLayerId(i);
+        Frame* refPic = picList.getPOC(m_poc, 0);
+        int viewIdCur = 0;
+        int viewIdZero = 1;
+        int viewIdRef = 1;
+
+        if ((viewIdCur <= viewIdZero && viewIdCur <= viewIdRef) ||
(viewIdCur >= viewIdZero && viewIdCur >= viewIdRef))
+        {
+            refPicSetInterLayer0.pushBackSubDPB(*refPic);
+        }
+        else
+        {
+            refPicSetInterLayer1.pushBackSubDPB(*refPic);
+        }
+    }
+}
+#endif
+
+void Slice::setRefPicList(PicList& picList, PicList& refPicSetInterLayer0,
PicList& refPicSetInterLayer1, int sLayerId)
 {
     if (m_sliceType == I_SLICE)
     {
@@ -75,18 +99,34 @@ void Slice::setRefPicList(PicList& picList, int
sLayerId)
     // ref_pic_list_init
     Frame* rpsCurrList0[MAX_NUM_REF + 1];
     Frame* rpsCurrList1[MAX_NUM_REF + 1];
+#if ENABLE_MULTIVIEW
+    int numPocTotalCurr = numPocStCurr0 + numPocStCurr1 + numPocLtCurr +
refPicSetInterLayer0.size() + refPicSetInterLayer1.size();
+#else
     int numPocTotalCurr = numPocStCurr0 + numPocStCurr1 + numPocLtCurr;
+#endif

     int cIdx = 0;
     for (i = 0; i < numPocStCurr0; i++, cIdx++)
         rpsCurrList0[cIdx] = refPicSetStCurr0[i];

+#if ENABLE_MULTIVIEW
+    if (m_param->numViews > 1)
+        for (i = 0; i < refPicSetInterLayer0.size(); i++, cIdx++)
+            rpsCurrList0[cIdx] = refPicSetInterLayer0.getPOC(m_poc, 0);
+#endif
+
     for (i = 0; i < numPocStCurr1; i++, cIdx++)
         rpsCurrList0[cIdx] = refPicSetStCurr1[i];

     for (i = 0; i < numPocLtCurr; i++, cIdx++)
         rpsCurrList0[cIdx] = refPicSetLtCurr[i];

+#if ENABLE_MULTIVIEW
+    if (m_param->numViews > 1)
+        for (i = 0; i < refPicSetInterLayer1.size(); i++, cIdx++)
+            rpsCurrList0[cIdx] = refPicSetInterLayer1.getPOC(m_poc, 0);
+#endif
+
     X265_CHECK(cIdx == numPocTotalCurr, "RPS index check fail\n");

     if (m_sliceType == B_SLICE)
@@ -95,12 +135,24 @@ void Slice::setRefPicList(PicList& picList, int
sLayerId)
         for (i = 0; i < numPocStCurr1; i++, cIdx++)
             rpsCurrList1[cIdx] = refPicSetStCurr1[i];

+#if ENABLE_MULTIVIEW
+        if (m_param->numViews > 1)
+            for (i = 0; i < refPicSetInterLayer1.size(); i++, cIdx++)
+                rpsCurrList1[cIdx] = refPicSetInterLayer1.getPOC(m_poc, 0);
+#endif
+
         for (i = 0; i < numPocStCurr0; i++, cIdx++)
             rpsCurrList1[cIdx] = refPicSetStCurr0[i];

         for (i = 0; i < numPocLtCurr; i++, cIdx++)
             rpsCurrList1[cIdx] = refPicSetLtCurr[i];

+#if ENABLE_MULTIVIEW
+        if (m_param->numViews > 1)
+            for (i = 0; i < refPicSetInterLayer0.size(); i++, cIdx++)
+                rpsCurrList1[cIdx] = refPicSetInterLayer0.getPOC(m_poc, 0);
+#endif
+
         X265_CHECK(cIdx == numPocTotalCurr, "RPS index check fail\n");
     }

@@ -109,6 +161,9 @@ void Slice::setRefPicList(PicList& picList, int
sLayerId)
         cIdx = rIdx % numPocTotalCurr;
         X265_CHECK(cIdx >= 0 && cIdx < numPocTotalCurr, "RPS index check
fail\n");
         m_refFrameList[0][rIdx] = rpsCurrList0[cIdx];
+#if ENABLE_MULTIVIEW
+        m_refFrameList[0][rIdx] = rpsCurrList0[cIdx];
+#endif
     }

     if (m_sliceType != B_SLICE)
@@ -123,6 +178,9 @@ void Slice::setRefPicList(PicList& picList, int
sLayerId)
             cIdx = rIdx % numPocTotalCurr;
             X265_CHECK(cIdx >= 0 && cIdx < numPocTotalCurr, "RPS index
check fail\n");
             m_refFrameList[1][rIdx] = rpsCurrList1[cIdx];
+#if ENABLE_MULTIVIEW
+            m_refFrameList[1][rIdx] = rpsCurrList1[cIdx];
+#endif
         }
     }

diff --git a/source/common/slice.h b/source/common/slice.h
index 9a05840a0..90009ae7f 100644
--- a/source/common/slice.h
+++ b/source/common/slice.h
@@ -109,11 +109,7 @@ namespace Level {

 struct ProfileTierLevel
 {
-#if ENABLE_MULTIVIEW
-    int      profileIdc[MAX_VIEWS];
-#else
-    int      profileIdc[MAX_SCALABLE_LAYERS];
-#endif
+    int      profileIdc[MAX_LAYERS];
     int      levelIdc;
     uint32_t minCrForLevel;
     uint32_t maxLumaSrForLevel;
@@ -425,7 +421,10 @@ public:

     void disableWeights();

-    void setRefPicList(PicList& picList, int sLayerId);
+    void setRefPicList(PicList& picList, PicList& refPicSetInterLayer0,
PicList& refPicSetInterLayer1, int viewId);
+#if ENABLE_MULTIVIEW
+    void createInterLayerReferencePictureSet(PicList& picList, PicList&
refPicSetInterLayer0, PicList& refPicSetInterLayer1);
+#endif

     bool getRapPicFlag() const
     {
diff --git a/source/encoder/api.cpp b/source/encoder/api.cpp
index 88bc25550..96baf56c9 100644
--- a/source/encoder/api.cpp
+++ b/source/encoder/api.cpp
@@ -603,7 +603,7 @@ fail:

     if (numEncoded && encoder->m_param->csvLogLevel &&
encoder->m_outputCount >= encoder->m_latestParam->chunkStart)
     {
-        for (int layer = 0; layer < encoder->m_param->numScalableLayers;
layer++)
+        for (int layer = 0; layer < encoder->m_param->numLayers; layer++)
             x265_csvlog_frame(encoder->m_param, pic_out[layer]);
     }

@@ -656,10 +656,10 @@ void x265_encoder_log(x265_encoder* enc, int argc,
char **argv)
     if (enc)
     {
         Encoder *encoder = static_cast<Encoder*>(enc);
-        x265_stats stats[MAX_SCALABLE_LAYERS];
+        x265_stats stats[MAX_LAYERS];
         int padx = encoder->m_sps.conformanceWindow.rightOffset;
         int pady = encoder->m_sps.conformanceWindow.bottomOffset;
-        for (int layer = 0; layer < encoder->m_param->numScalableLayers;
layer++)
+        for (int layer = 0; layer < encoder->m_param->numLayers; layer++)
         {
             encoder->fetchStats(stats, sizeof(stats[layer]), layer);
             x265_csvlog_encode(encoder->m_param, &stats[0], padx, pady,
argc, argv);
diff --git a/source/encoder/dpb.cpp b/source/encoder/dpb.cpp
index bce49b500..3b4934df5 100644
--- a/source/encoder/dpb.cpp
+++ b/source/encoder/dpb.cpp
@@ -328,6 +328,13 @@ void DPB::computeRPS(int curPoc, int tempId, bool
isRAP, RPS * rps, unsigned int
         {
             if ((!m_bTemporalSublayer || (iterPic->m_tempLayer <= tempId))
&& ((m_lastIDR >= curPoc) || (m_lastIDR <= iterPic->m_poc)))
             {
+#if ENABLE_MULTIVIEW
+                    if (layer && numNeg ==
iterPic->m_param->maxNumReferences - 1 && (iterPic->m_poc - curPoc) < 0)
+                    {
+                        iterPic = iterPic->m_next;
+                        continue;
+                    }
+#endif
                     rps->poc[poci] = iterPic->m_poc;
                     rps->deltaPOC[poci] = rps->poc[poci] - curPoc;
                     (rps->deltaPOC[poci] < 0) ? numNeg++ : numPos++;
diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index ef152f2ae..8a1ed9d88 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -149,7 +149,7 @@ Encoder::Encoder()
     m_rpsInSpsCount = 0;
     m_cB = 1.0;
     m_cR = 1.0;
-    for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)
+    for (int i = 0; i < MAX_LAYERS; i++)
         m_exportedPic[i] = NULL;
     for (int i = 0; i < X265_MAX_FRAME_THREADS; i++)
         m_frameEncoder[i] = NULL;
@@ -862,7 +862,7 @@ void Encoder::destroy()
         X265_FREE(m_rdCost);
         X265_FREE(m_trainingCount);
     }
-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
+    for (int layer = 0; layer < m_param->numLayers; layer++)
     {
         if (m_exportedPic[layer])
         {
@@ -1488,7 +1488,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
         if (!m_param->bUseAnalysisFile && m_param->analysisSave)
             x265_free_analysis_data(m_param,
&m_exportedPic[0]->m_analysisData);

-        for (int i = 0; i < m_param->numScalableLayers; i++)
+        for (int i = 0; i < m_param->numLayers; i++)
         {
             ATOMIC_DEC(&m_exportedPic[i]->m_countRefEncoders);
             m_exportedPic[i] = NULL;
@@ -1587,19 +1587,18 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
         }

         x265_param* p = (m_reconfigure || m_reconfigureRc) ? m_latestParam
: m_param;
-#if ENABLE_MULTIVIEW
-        Frame* inFrame[MAX_VIEWS];
-        for (int layer = 0; layer < m_param->numViews; layer++)
-#else
-        Frame* inFrame[MAX_SCALABLE_LAYERS];
-        for (int layer = 0; layer < m_param->numScalableLayers; layer++)
-#endif
+        Frame* inFrame[MAX_LAYERS];
+        for (int layer = 0; layer < m_param->numLayers; layer++)
         {
             if (m_dpb->m_freeList.empty())
             {
                 inFrame[layer] = new Frame;
                 inFrame[layer]->m_encodeStartTime = x265_mdate();
+#if ENABLE_MULTIVIEW
+                inFrame[layer]->m_viewId = layer;
+#else
                 inFrame[layer]->m_sLayerId = layer;
+#endif
                 inFrame[layer]->m_valid = false;
                 if (inFrame[layer]->create(p,
inputPic[layer]->quantOffsets))
                 {
@@ -1670,10 +1669,43 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
 #endif
                 inFrame[layer]->m_valid = false;
                 inFrame[layer]->m_lowres.bKeyframe = false;
+#if ENABLE_MULTIVIEW
+                //Destroy interlayer References
+                //TODO Move this to end(after compress frame)
+                if (inFrame[layer]->refPicSetInterLayer0.size())
+                {
+                    Frame* iterFrame =
inFrame[layer]->refPicSetInterLayer0.first();
+
+                    while (iterFrame)
+                    {
+                        Frame* curFrame = iterFrame;
+                        iterFrame = iterFrame->m_nextSubDPB;
+
 inFrame[layer]->refPicSetInterLayer0.removeSubDPB(*curFrame);
+                        iterFrame =
inFrame[layer]->refPicSetInterLayer0.first();
+                    }
+                }
+
+                if (inFrame[layer]->refPicSetInterLayer1.size())
+                {
+                    Frame* iterFrame =
inFrame[layer]->refPicSetInterLayer1.first();
+
+                    while (iterFrame)
+                    {
+                        Frame* curFrame = iterFrame;
+                        iterFrame = iterFrame->m_nextSubDPB;
+
 inFrame[layer]->refPicSetInterLayer1.removeSubDPB(*curFrame);
+                        iterFrame =
inFrame[layer]->refPicSetInterLayer1.first();
+                    }
+                }
+#endif
             }

             /* Copy input picture into a Frame and PicYuv, send to
lookahead */
+#if ENABLE_ALPHA
             inFrame[layer]->m_fencPic->copyFromPicture(*inputPic[layer],
*m_param, m_sps.conformanceWindow.rightOffset,
m_sps.conformanceWindow.bottomOffset, !layer);
+#else
+            inFrame[layer]->m_fencPic->copyFromPicture(*inputPic[layer],
*m_param, m_sps.conformanceWindow.rightOffset,
m_sps.conformanceWindow.bottomOffset);
+#endif

             inFrame[layer]->m_poc = (!layer) ? (++m_pocLast) : m_pocLast;
             inFrame[layer]->m_userData = inputPic[0]->userData;
@@ -1919,7 +1951,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
      * input picture before returning so the order must be reversed. This
do/while() loop allows
      * us to alternate the order of the calls without ugly code
replication */
     Frame** outFrames = { NULL };
-    Frame* frameEnc[MAX_SCALABLE_LAYERS] = { NULL };
+    Frame* frameEnc[MAX_LAYERS] = { NULL };
     int pass = 0;
     do
     {
@@ -1930,7 +1962,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
             outFrames = curEncoder->getEncodedPicture(m_nalList);
         if (outFrames)
         {
-            for (int sLayer = 0; sLayer < m_param->numScalableLayers;
sLayer++)
+            for (int sLayer = 0; sLayer < m_param->numLayers; sLayer++)
             {
                 Frame* outFrame = *(outFrames + sLayer);
                 Slice* slice = outFrame->m_encData->m_slice;
@@ -2163,7 +2195,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                 m_outputCount++;
                 if (m_param->chunkEnd == m_outputCount)
                     m_numDelayedPic = 0;
-                else if (outFrame->m_sLayerId == m_param->bEnableAlpha)
+                else if (sLayer == m_param->numLayers -1)
                     m_numDelayedPic--;

                 ret = 1;
@@ -2176,10 +2208,10 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
             frameEnc[0] = m_lookahead->getDecidedPicture();
         if (frameEnc[0] && !pass && (!m_param->chunkEnd ||
(m_encodedFrameNum < m_param->chunkEnd)))
         {
+
 #if ENABLE_ALPHA || ENABLE_MULTIVIEW
             //Pop non base view pictures from DPB piclist
-            int numLayers = m_param->numViews > 1 ? m_param->numViews :
(m_param->numScalableLayers > 1) ? m_param->numScalableLayers : 1;
-            for (int layer = 1; layer < numLayers; layer++)
+            for (int layer = 1; layer < m_param->numLayers; layer++)
             {
                 Frame* currentFrame =
m_dpb->m_picList.getPOC(frameEnc[0]->m_poc, layer);
                 frameEnc[layer] =
m_dpb->m_picList.removeFrame(*currentFrame);
@@ -2254,7 +2286,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
             curEncoder->m_reconfigure = m_reconfigure;

             /* give this frame a FrameData instance before encoding */
-            for (int layer = 0; layer < m_param->numScalableLayers;
layer++)
+            for (int layer = 0; layer < m_param->numLayers; layer++)
             {
                 if (m_dpb->m_frameDataFreeList)
                 {
@@ -2385,7 +2417,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                 }
             }
             /* determine references, setup RPS, etc */
-            for (int layer = 0; layer < m_param->numScalableLayers;
layer++)
+            for (int layer = 0; layer < m_param->numLayers; layer++)
                 m_dpb->prepareEncode(frameEnc[layer]);

             if (m_param->bEnableTemporalFilter)
@@ -2407,7 +2439,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                 m_origPicBuffer->setOrigPicList(frameEnc[0], m_pocLast);
             }

-            for (int layer = 0; layer < m_param->numScalableLayers;
layer++)
+            for (int layer = 0; layer < m_param->numLayers; layer++)
             {
                 if (!!m_param->selectiveSAO)
                 {
@@ -2762,7 +2794,7 @@ void Encoder::printSummary()
     if (m_param->logLevel < X265_LOG_INFO)
         return;

-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
+    for (int layer = 0; layer < m_param->numLayers; layer++)
     {
         char buffer[200];
         if (m_analyzeI[layer].m_numPics)
@@ -3316,11 +3348,7 @@ void Encoder::getStreamHeaders(NALList& list,
Entropy& sbacCoder, Bitstream& bs)
     bs.writeByteAlignment();
     list.serialize(NAL_UNIT_VPS, bs);

-#if ENABLE_MULTIVIEW
-    for (int layer = 0; layer < m_param->numViews; layer++)
-#else
-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
-#endif
+    for (int layer = 0; layer < m_param->numLayers; layer++)
     {
         bs.resetBits();
         sbacCoder.codeSPS(m_sps, m_scalingList, m_vps.ptl, layer);
@@ -3328,11 +3356,7 @@ void Encoder::getStreamHeaders(NALList& list,
Entropy& sbacCoder, Bitstream& bs)
         list.serialize(NAL_UNIT_SPS, bs, layer);
     }

-#if ENABLE_MULTIVIEW
-    for (int layer = 0; layer < m_param->numViews; layer++)
-#else
-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
-#endif
+    for (int layer = 0; layer < m_param->numLayers; layer++)
     {
         bs.resetBits();
         sbacCoder.codePPS(m_pps, (m_param->maxSlices <= 1),
m_iPPSQpMinus26, layer);
diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h
index 58709e92e..1dbb41596 100644
--- a/source/encoder/encoder.h
+++ b/source/encoder/encoder.h
@@ -202,7 +202,7 @@ public:
     ThreadPool*        m_threadPool;
     FrameEncoder*      m_frameEncoder[X265_MAX_FRAME_THREADS];
     DPB*               m_dpb;
-    Frame*             m_exportedPic[MAX_SCALABLE_LAYERS];
+    Frame*             m_exportedPic[MAX_LAYERS];
     FILE*              m_analysisFileIn;
     FILE*              m_analysisFileOut;
     FILE*              m_naluFile;
@@ -217,10 +217,10 @@ public:

     bool               m_externalFlush;
     /* Collect statistics globally */
-    EncStats           m_analyzeAll[MAX_SCALABLE_LAYERS];
-    EncStats           m_analyzeI[MAX_SCALABLE_LAYERS];
-    EncStats           m_analyzeP[MAX_SCALABLE_LAYERS];
-    EncStats           m_analyzeB[MAX_SCALABLE_LAYERS];
+    EncStats           m_analyzeAll[MAX_LAYERS];
+    EncStats           m_analyzeI[MAX_LAYERS];
+    EncStats           m_analyzeP[MAX_LAYERS];
+    EncStats           m_analyzeB[MAX_LAYERS];
     VPS                m_vps;
     SPS                m_sps;
     PPS                m_pps;
diff --git a/source/encoder/frameencoder.cpp
b/source/encoder/frameencoder.cpp
index 1aab82b77..97d033fb6 100644
--- a/source/encoder/frameencoder.cpp
+++ b/source/encoder/frameencoder.cpp
@@ -58,7 +58,7 @@ FrameEncoder::FrameEncoder()
     m_ctuGeomMap = NULL;
     m_localTldIdx = 0;
     memset(&m_rce, 0, sizeof(RateControlEntry));
-    for (int layer = 0; layer < MAX_SCALABLE_LAYERS; layer++)
+    for (int layer = 0; layer < MAX_LAYERS; layer++)
     {
         m_prevOutputTime[layer] = x265_mdate();
         m_slicetypeWaitTime[layer] = 0;
@@ -220,8 +220,8 @@ bool FrameEncoder::init(Encoder *top, int numRows, int
numCols)
             ok &= !!m_frameEncTF->createRefPicInfo(&m_mcstfRefList[i],
m_param);
     }

-    m_retFrameBuffer = X265_MALLOC(Frame*, m_param->numScalableLayers);
-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
+    m_retFrameBuffer = X265_MALLOC(Frame*, m_param->numLayers);
+    for (int layer = 0; layer < m_param->numLayers; layer++)
         m_retFrameBuffer[layer] = NULL;
     return ok;
 }
@@ -289,9 +289,9 @@ bool FrameEncoder::initializeGeoms()
     return true;
 }

-bool FrameEncoder::startCompressFrame(Frame* curFrame[MAX_SCALABLE_LAYERS])
+bool FrameEncoder::startCompressFrame(Frame* curFrame[MAX_LAYERS])
 {
-    for (int layer = 0; layer < m_param->numScalableLayers; layer++)
+    for (int layer = 0; layer < m_param->numLayers; layer++)
     {
         m_slicetypeWaitTime[layer] = x265_mdate() -
m_prevOutputTime[layer];
         m_frame[layer] = curFrame[layer];
@@ -374,7 +374,7 @@ void FrameEncoder::threadMain()
                 m_frame[0]->m_copyMVType.wait();
         }

-        for(int layer = 0; layer < m_param->numScalableLayers; layer ++)
+        for (int layer = 0; layer < m_param->numLayers; layer++)
             compressFrame(layer);
         m_done.trigger(); /* FrameEncoder::getEncodedPicture() blocks for
this event */
         m_enable.wait();
@@ -2282,7 +2282,7 @@ Frame** FrameEncoder::getEncodedPicture(NALList&
output)
         /* block here until worker thread completes */
         m_done.wait();

-        for (int i = 0; i < m_param->numScalableLayers; i++)
+        for (int i = 0; i < m_param->numLayers; i++)
         {
             m_retFrameBuffer[i] = m_frame[i];
             m_frame[i] = NULL;
diff --git a/source/encoder/frameencoder.h b/source/encoder/frameencoder.h
index 6253cbd84..ebc6e57c5 100644
--- a/source/encoder/frameencoder.h
+++ b/source/encoder/frameencoder.h
@@ -156,7 +156,7 @@ public:
     void destroy();

     /* triggers encode of a new frame by the worker thread */
-    bool startCompressFrame(Frame* curFrame[MAX_SCALABLE_LAYERS]);
+    bool startCompressFrame(Frame* curFrame[MAX_LAYERS]);

     /* blocks until worker thread is done, returns access unit */
     Frame **getEncodedPicture(NALList& list);
@@ -190,34 +190,34 @@ public:
     RateControlEntry         m_rce;
     SEIDecodedPictureHash    m_seiReconPictureDigest;

-    uint64_t                 m_SSDY[MAX_SCALABLE_LAYERS];
-    uint64_t                 m_SSDU[MAX_SCALABLE_LAYERS];
-    uint64_t                 m_SSDV[MAX_SCALABLE_LAYERS];
-    double                   m_ssim[MAX_SCALABLE_LAYERS];
-    uint64_t                 m_accessUnitBits[MAX_SCALABLE_LAYERS];
-    uint32_t                 m_ssimCnt[MAX_SCALABLE_LAYERS];
+    uint64_t                 m_SSDY[MAX_LAYERS];
+    uint64_t                 m_SSDU[MAX_LAYERS];
+    uint64_t                 m_SSDV[MAX_LAYERS];
+    double                   m_ssim[MAX_LAYERS];
+    uint64_t                 m_accessUnitBits[MAX_LAYERS];
+    uint32_t                 m_ssimCnt[MAX_LAYERS];

     volatile int             m_activeWorkerCount;        // count of
workers currently encoding or filtering CTUs
     volatile int             m_totalActiveWorkerCount;   // sum of
m_activeWorkerCount sampled at end of each CTU
     volatile int             m_activeWorkerCountSamples; // count of times
m_activeWorkerCount was sampled (think vbv restarts)
     volatile int             m_countRowBlocks;           // count of
workers forced to abandon a row because of top dependency
-    int64_t                  m_startCompressTime[MAX_SCALABLE_LAYERS];
   // timestamp when frame encoder is given a frame
-    int64_t                  m_row0WaitTime[MAX_SCALABLE_LAYERS];
    // timestamp when row 0 is allowed to start
-    int64_t                  m_allRowsAvailableTime[MAX_SCALABLE_LAYERS];
    // timestamp when all reference dependencies are resolved
-    int64_t                  m_endCompressTime[MAX_SCALABLE_LAYERS];
   // timestamp after all CTUs are compressed
-    int64_t                  m_endFrameTime[MAX_SCALABLE_LAYERS];
    // timestamp after RCEnd, NR updates, etc
-    int64_t                  m_stallStartTime[MAX_SCALABLE_LAYERS];
    // timestamp when worker count becomes 0
-    int64_t                  m_prevOutputTime[MAX_SCALABLE_LAYERS];
    // timestamp when prev frame was retrieved by API thread
-    int64_t                  m_slicetypeWaitTime[MAX_SCALABLE_LAYERS];
   // total elapsed time waiting for decided frame
-    int64_t
 m_totalWorkerElapsedTime[MAX_SCALABLE_LAYERS];   // total elapsed time
spent by worker threads processing CTUs
-    int64_t                  m_totalNoWorkerTime[MAX_SCALABLE_LAYERS];
   // total elapsed time without any active worker threads
+    int64_t                  m_startCompressTime[MAX_LAYERS];        //
timestamp when frame encoder is given a frame
+    int64_t                  m_row0WaitTime[MAX_LAYERS];             //
timestamp when row 0 is allowed to start
+    int64_t                  m_allRowsAvailableTime[MAX_LAYERS];     //
timestamp when all reference dependencies are resolved
+    int64_t                  m_endCompressTime[MAX_LAYERS];          //
timestamp after all CTUs are compressed
+    int64_t                  m_endFrameTime[MAX_LAYERS];             //
timestamp after RCEnd, NR updates, etc
+    int64_t                  m_stallStartTime[MAX_LAYERS];           //
timestamp when worker count becomes 0
+    int64_t                  m_prevOutputTime[MAX_LAYERS];           //
timestamp when prev frame was retrieved by API thread
+    int64_t                  m_slicetypeWaitTime[MAX_LAYERS];        //
total elapsed time waiting for decided frame
+    int64_t                  m_totalWorkerElapsedTime[MAX_LAYERS];   //
total elapsed time spent by worker threads processing CTUs
+    int64_t                  m_totalNoWorkerTime[MAX_LAYERS];        //
total elapsed time without any active worker threads
 #if DETAILED_CU_STATS
     CUStats                  m_cuStats;
 #endif

     Encoder*                 m_top;
     x265_param*              m_param;
-    Frame*                   m_frame[MAX_SCALABLE_LAYERS];
+    Frame*                   m_frame[MAX_LAYERS];
     Frame**                  m_retFrameBuffer;
     NoiseReduction*          m_nr;
     ThreadLocalData*         m_tld; /* for --no-wpp */
diff --git a/source/encoder/search.cpp b/source/encoder/search.cpp
index 001115782..3218f4a24 100644
--- a/source/encoder/search.cpp
+++ b/source/encoder/search.cpp
@@ -2102,7 +2102,8 @@ void Search::singleMotionEstimation(Search& master,
Mode& interMode, const Predi
     if (!m_param->analysisSave && !m_param->analysisLoad) /* Prevents
load/save outputs from diverging if lowresMV is not available */
     {
         MV lmv = getLowresMV(interMode.cu, pu, list, ref);
-        if (lmv.notZero() && !m_frame->m_sLayerId)
+        int layer = m_param->numViews > 1 ? m_frame->m_viewId :
(m_param->numScalableLayers > 1) ? m_frame->m_sLayerId : 0;
+        if (lmv.notZero() && !layer)
             mvc[numMvc++] = lmv;
         if (m_param->bEnableHME)
             mvp_lowres = lmv;
@@ -2413,7 +2414,8 @@ void Search::predInterSearch(Mode& interMode, const
CUGeom& cuGeom, bool bChroma
                     if (!m_param->analysisSave && !m_param->analysisLoad)
/* Prevents load/save outputs from diverging when lowresMV is not available
*/
                     {
                         MV lmv = getLowresMV(cu, pu, list, ref);
-                        if (lmv.notZero() && !m_frame->m_sLayerId)
+                        int layer = m_param->numViews > 1 ?
m_frame->m_viewId : (m_param->numScalableLayers > 1) ? m_frame->m_sLayerId
: 0;
+                        if (lmv.notZero() && !layer)
                             mvc[numMvc++] = lmv;
                         if (m_param->bEnableHME)
                             mvp_lowres = lmv;
diff --git a/source/x265.h b/source/x265.h
index 091696e03..49880d0f3 100644
--- a/source/x265.h
+++ b/source/x265.h
@@ -643,6 +643,10 @@ typedef enum
 #define MAX_SCALABLE_LAYERS     1
 #endif

+#if ENABLE_ALPHA || ENABLE_MULTIVIEW
+#define MAX_LAYERS              2
+#endif
+
 #define X265_IPRATIO_STRENGTH   1.43

 typedef struct x265_cli_csp
@@ -2296,6 +2300,8 @@ typedef struct x265_param

     /*Multi View Encoding*/
     int      numViews;
+
+    int      numLayers;
 } x265_param;

 /* x265_param_alloc:
diff --git a/source/x265cli.cpp b/source/x265cli.cpp
index b2b357beb..cd42a3bfa 100755
--- a/source/x265cli.cpp
+++ b/source/x265cli.cpp
@@ -429,7 +429,7 @@ namespace X265_NS {
                 input[i]->release();
             input[i] = NULL;
         }
-        for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)
+        for (int i = 0; i < MAX_LAYERS; i++)
         {
             if (recon[i])
                 recon[i]->release();
@@ -595,7 +595,7 @@ namespace X265_NS {
         {
             inputfn[view] = X265_MALLOC(char, sizeof(char) * 1024);
         }
-        const char* reconfn[MAX_SCALABLE_LAYERS] = { NULL };
+        const char* reconfn[MAX_LAYERS] = { NULL };
         const char *outputfn = NULL;
         const char *preset = NULL;
         const char *tune = NULL;
@@ -831,6 +831,7 @@ namespace X265_NS {
             }
         }
 #endif
+        param->numLayers = param->numViews > 1 ? param->numViews :
(param->numScalableLayers > 1) ? param->numScalableLayers : 1;
         if (!outputfn)
         {
             x265_log(param, X265_LOG_ERROR, "input or output file not
specified, try --help for help\n");
@@ -967,13 +968,13 @@ namespace X265_NS {
         {
             if (reconFileBitDepth == 0)
                 reconFileBitDepth = param->internalBitDepth;
-#if ENABLE_ALPHA
-            if (param->bEnableAlpha)
+#if ENABLE_ALPHA || ENABLE_MULTIVIEW
+            if (param->bEnableAlpha || param->numViews > 1)
             {
                 char* temp = new char[strlen(reconfn[0])];
                 strcpy(temp, reconfn[0]);
                 const char* token = strtok(temp, ".");
-                for (int view = 0; view < param->numScalableLayers; view++)
+                for (int view = 0; view < param->numLayers; view++)
                 {
                     char* buf = new char[strlen(temp) + 7];
                     sprintf(buf, "%s-%d.yuv", token, view);
@@ -981,7 +982,7 @@ namespace X265_NS {
                 }
             }
 #endif
-            for (int i = 0; i < param->numScalableLayers; i++)
+            for (int i = 0; i < param->numLayers; i++)
             {
                 this->recon[i] = ReconFile::open(reconfn[i],
param->sourceWidth, param->sourceHeight, reconFileBitDepth,
                     param->fpsNum, param->fpsDenom, param->internalCsp,
param->sourceBitDepth);
diff --git a/source/x265cli.h b/source/x265cli.h
index 0613c81e5..49a88d084 100644
--- a/source/x265cli.h
+++ b/source/x265cli.h
@@ -401,7 +401,7 @@ static const struct option long_options[] =
     struct CLIOptions
     {
         InputFile* input[MAX_VIEWS];
-        ReconFile* recon[MAX_SCALABLE_LAYERS];
+        ReconFile* recon[MAX_LAYERS];
         OutputFile* output;
         FILE*       qpfile;
         FILE*       zoneFile;
@@ -443,7 +443,7 @@ static const struct option long_options[] =
         {
             for (int i = 0; i < MAX_VIEWS; i++)
                 input[i] = NULL;
-            for (int i = 0; i < MAX_SCALABLE_LAYERS; i++)
+            for (int i = 0; i < MAX_LAYERS; i++)
                 recon[i] = NULL;
             output = NULL;
             qpfile = NULL;
-- 
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/6182fdcc/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0005-This-commit-does-the-following-things-Extend-the-enc.patch
Type: application/octet-stream
Size: 34772 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/6182fdcc/attachment-0001.obj>


More information about the x265-devel mailing list