[x265] [PATCH SCC 05/09] Added sao, deblock and temporal-mvp support and disable weight prediction

Anusuya Kumarasamy anusuya.kumarasamy at multicorewareinc.com
Wed Aug 7 17:21:51 UTC 2024


>From 4101dcf0f15686578b0c981de3df296d91a3ae8f Mon Sep 17 00:00:00 2001
From: AnusuyaKumarasamy <anusuya.kumarasamy at multicorewareinc.com>
Date: Fri, 19 Jul 2024 16:52:58 +0530
Subject: [PATCH 5/9] Added sao, deblock and temporal-mvp support and disable
 weight prediction

---
 source/common/cudata.cpp        |  8 ++---
 source/common/deblock.cpp       |  4 +--
 source/common/frame.cpp         | 55 ++++++++++++++++++++-------------
 source/common/frame.h           |  2 +-
 source/common/framedata.h       |  2 +-
 source/common/param.cpp         |  7 ++++-
 source/common/predict.cpp       | 50 +++++++++++++++++++++++-------
 source/common/slice.h           |  2 ++
 source/encoder/analysis.cpp     | 24 ++++++++------
 source/encoder/dpb.cpp          | 19 +++++++++---
 source/encoder/encoder.cpp      | 20 ++++++------
 source/encoder/entropy.cpp      |  4 +--
 source/encoder/frameencoder.cpp |  8 ++---
 source/encoder/framefilter.cpp  | 14 ++++-----
 source/encoder/level.cpp        |  9 +++---
 source/encoder/sao.cpp          | 10 +++---
 source/encoder/search.cpp       | 39 ++++++++++++++---------
 17 files changed, 173 insertions(+), 104 deletions(-)

diff --git a/source/common/cudata.cpp b/source/common/cudata.cpp
index a671df113..23f95288e 100644
--- a/source/common/cudata.cpp
+++ b/source/common/cudata.cpp
@@ -1595,7 +1595,7 @@ uint32_t CUData::getInterMergeCandidates(uint32_t
absPartIdx, uint32_t puIdx, MV
                 return maxNumMergeCand;
         }
     }
-    if (m_slice->m_sps->bTemporalMVPEnabled)
+    if (m_slice->m_bTemporalMvp)
     {
         uint32_t partIdxRB = deriveRightBottomIdx(puIdx);
         MV colmv;
@@ -1822,9 +1822,9 @@ int CUData::getPMV(InterNeighbourMV* neighbours,
uint32_t picList, uint32_t refI
     // Get the collocated candidate. At this step, either the first
candidate
     // was found or its value is 0.
 #if ENABLE_MULTIVIEW
-    if (m_slice->m_param->numViews > 1)
+    if (m_slice->m_param->numViews > 1 || !!m_slice->m_param->bEnableSCC)
     {
-        if (m_slice->m_sps->bTemporalMVPEnabled && num < 2)
+        if (m_slice->m_bTemporalMvp && num < 2)
         {
             int refId = refIdx;
             uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;
@@ -1915,7 +1915,7 @@ void CUData::getNeighbourMV(uint32_t puIdx, uint32_t
absPartIdx, InterNeighbourM
     getInterNeighbourMV(neighbours + MD_ABOVE,      partIdxRT, MD_ABOVE);
     getInterNeighbourMV(neighbours + MD_ABOVE_LEFT, partIdxLT,
MD_ABOVE_LEFT);

-    if (m_slice->m_sps->bTemporalMVPEnabled &&
!(m_slice->m_param->numViews > 1))
+    if (m_slice->m_bTemporalMvp && !(!!m_slice->m_param->bEnableSCC ||
m_slice->m_param->numViews > 1))
     {
         uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;
         uint32_t partIdxRB = deriveRightBottomIdx(puIdx);
diff --git a/source/common/deblock.cpp b/source/common/deblock.cpp
index 15ca361b2..0f9bc02dd 100644
--- a/source/common/deblock.cpp
+++ b/source/common/deblock.cpp
@@ -316,7 +316,7 @@ static inline void pelFilterLuma(pixel* src, intptr_t
srcStep, intptr_t offset,

 void Deblock::edgeFilterLuma(const CUData* cuQ, uint32_t absPartIdx,
uint32_t depth, int32_t dir, int32_t edge, const uint8_t blockStrength[])
 {
-    PicYuv* reconPic = cuQ->m_encData->m_reconPic;
+    PicYuv* reconPic = cuQ->m_encData->m_reconPic[0];
     pixel* src = reconPic->getLumaAddr(cuQ->m_cuAddr, absPartIdx);
     intptr_t stride = reconPic->m_stride;
     const PPS* pps = cuQ->m_slice->m_pps;
@@ -429,7 +429,7 @@ void Deblock::edgeFilterChroma(const CUData* cuQ,
uint32_t absPartIdx, uint32_t
                 : ((g_zscanToPelY[absPartIdx] + edge * UNIT_SIZE) >>
cuQ->m_vChromaShift)) % DEBLOCK_SMALLEST_BLOCK == 0,
                "invalid edge\n");

-    PicYuv* reconPic = cuQ->m_encData->m_reconPic;
+    PicYuv* reconPic = cuQ->m_encData->m_reconPic[0];
     intptr_t stride = reconPic->m_strideC;
     intptr_t srcOffset = reconPic->getChromaAddrOffset(cuQ->m_cuAddr,
absPartIdx);
     bool bCheckNoFilter = pps->bTransquantBypassEnabled;
diff --git a/source/common/frame.cpp b/source/common/frame.cpp
index c40093dba..6140021aa 100644
--- a/source/common/frame.cpp
+++ b/source/common/frame.cpp
@@ -37,7 +37,8 @@ Frame::Frame()
     m_reconColCount = NULL;
     m_countRefEncoders = 0;
     m_encData = NULL;
-    m_reconPic = NULL;
+    for (int i = 0; i < 2; i++)
+        m_reconPic[i] = NULL;
     m_quantOffsets = NULL;
     m_next = NULL;
     m_prev = NULL;
@@ -204,29 +205,35 @@ fail:
 bool Frame::allocEncodeData(x265_param *param, const SPS& sps)
 {
     m_encData = new FrameData;
-    m_reconPic = new PicYuv;
     m_param = param;
-    m_encData->m_reconPic = m_reconPic;
-    bool ok = m_encData->create(*param, sps, m_fencPic->m_picCsp) &&
m_reconPic->create(param);
+    for (int i = 0; i < !!m_param->bEnableSCC + 1; i++)
+    {
+        m_reconPic[i] = new PicYuv;
+        m_encData->m_reconPic[i] = m_reconPic[i];
+    }
+    bool ok = m_encData->create(*param, sps, m_fencPic->m_picCsp) &&
m_reconPic[0]->create(param) && (!!param->bEnableSCC ? (!!param->bEnableSCC
&& m_reconPic[1]->create(param)) : 1);
     if (ok)
     {
-        /* initialize right border of m_reconpicYuv as SAO may read beyond
the
+        /* initialize right border of m_reconPicYuv as SAO may read beyond
the
          * end of the picture accessing uninitialized pixels */
         int maxHeight = sps.numCuInHeight * param->maxCUSize;
-        memset(m_reconPic->m_picOrg[0], 0, sizeof(pixel)*
m_reconPic->m_stride * maxHeight);
-
-        /* use pre-calculated cu/pu offsets cached in the SPS structure */
-        m_reconPic->m_cuOffsetY = sps.cuOffsetY;
-        m_reconPic->m_buOffsetY = sps.buOffsetY;
+        memset(m_reconPic[0]->m_picOrg[0], 0, sizeof(pixel)*
m_reconPic[0]->m_stride * maxHeight);

-        if (param->internalCsp != X265_CSP_I400)
+        for (int i = 0; i < !!m_param->bEnableSCC + 1; i++)
         {
-            memset(m_reconPic->m_picOrg[1], 0, sizeof(pixel) *
m_reconPic->m_strideC * (maxHeight >> m_reconPic->m_vChromaShift));
-            memset(m_reconPic->m_picOrg[2], 0, sizeof(pixel) *
m_reconPic->m_strideC * (maxHeight >> m_reconPic->m_vChromaShift));
-
             /* use pre-calculated cu/pu offsets cached in the SPS
structure */
-            m_reconPic->m_cuOffsetC = sps.cuOffsetC;
-            m_reconPic->m_buOffsetC = sps.buOffsetC;
+            m_reconPic[i]->m_cuOffsetY = sps.cuOffsetY;
+            m_reconPic[i]->m_buOffsetY = sps.buOffsetY;
+
+            if (param->internalCsp != X265_CSP_I400)
+            {
+                memset(m_reconPic[i]->m_picOrg[1], 0, sizeof(pixel) *
m_reconPic[i]->m_strideC * (maxHeight >> m_reconPic[i]->m_vChromaShift));
+                memset(m_reconPic[i]->m_picOrg[2], 0, sizeof(pixel) *
m_reconPic[i]->m_strideC * (maxHeight >> m_reconPic[i]->m_vChromaShift));
+
+                /* use pre-calculated cu/pu offsets cached in the SPS
structure */
+                m_reconPic[i]->m_cuOffsetC = sps.cuOffsetC;
+                m_reconPic[i]->m_buOffsetC = sps.buOffsetC;
+            }
         }
     }
     return ok;
@@ -236,7 +243,9 @@ bool Frame::allocEncodeData(x265_param *param, const
SPS& sps)
 void Frame::reinit(const SPS& sps)
 {
     m_bChromaExtended = false;
-    m_reconPic = m_encData->m_reconPic;
+    m_reconPic[0] = m_encData->m_reconPic[0];
+    if (!!m_param->bEnableSCC)
+        m_reconPic[1] = m_encData->m_reconPic[1];
     m_encData->reinit(sps);
 }

@@ -306,11 +315,15 @@ void Frame::destroy()
         X265_FREE(m_isSubSampled);
     }

-    if (m_reconPic)
+    int numVersion = !!m_param->bEnableSCC ? 2 : 1;
+    for (int i = 0; i < numVersion; i++)
     {
-        m_reconPic->destroy();
-        delete m_reconPic;
-        m_reconPic = NULL;
+        if (m_reconPic[i])
+        {
+            m_reconPic[i]->destroy();
+            delete m_reconPic[i];
+            m_reconPic[i] = NULL;
+        }
     }

     if (m_reconRowFlag)
diff --git a/source/common/frame.h b/source/common/frame.h
index 4ddd8bd46..4e6a4beed 100644
--- a/source/common/frame.h
+++ b/source/common/frame.h
@@ -81,7 +81,7 @@ public:
     /* These two items will be NULL until the Frame begins to be encoded,
at which point
      * it will be assigned a FrameData instance, which comes with a
reconstructed image PicYuv */
     FrameData*             m_encData;
-    PicYuv*                m_reconPic;
+    PicYuv*                m_reconPic[2];

     /* Data associated with x265_picture */
     PicYuv*                m_fencPic;
diff --git a/source/common/framedata.h b/source/common/framedata.h
index 611664ca5..66a00696c 100644
--- a/source/common/framedata.h
+++ b/source/common/framedata.h
@@ -115,7 +115,7 @@ public:
     const x265_param* m_param;

     FrameData*     m_freeListNext;
-    PicYuv*        m_reconPic;
+    PicYuv*        m_reconPic[2];
     bool           m_bHasReferences;   /* used during DPB/RPS updates */
     int            m_frameEncoderID;   /* the ID of the FrameEncoder
encoding this frame */
     JobProvider*   m_jobProvider;
diff --git a/source/common/param.cpp b/source/common/param.cpp
index 2f4f8084d..bbf33dae9 100755
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -1476,7 +1476,12 @@ int x265_param_parse(x265_param* p, const char*
name, const char* value)
             p->numViews = atoi(value);
         }
 #endif
-        OPT("scc") p->bEnableSCC = atoi(value);
+        OPT("scc")
+        {
+            p->bEnableSCC = atoi(value);
+            if (p->bEnableSCC)
+                p->bEnableWeightedPred = false;
+        }
         else
             return X265_PARAM_BAD_NAME;
     }
diff --git a/source/common/predict.cpp b/source/common/predict.cpp
index a32bd05f7..e6fc478e3 100644
--- a/source/common/predict.cpp
+++ b/source/common/predict.cpp
@@ -112,10 +112,20 @@ void Predict::motionCompensation(const CUData& cu,
const PredictionUnit& pu, Yuv
         }
         else
         {
-            if (bLuma)
-                predInterLumaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
-            if (bChroma)
-                predInterChromaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+            if (!!cu.m_slice->m_param->bEnableSCC && refIdx0 ==
(cu.m_slice->m_numRefIdx[0] - 1))
+            {
+                if (bLuma)
+                    predInterLumaPixel(pu, predYuv,
*cu.m_slice->m_refFrameList[0][refIdx0]->m_reconPic[1], mv0);
+                if (bChroma)
+                    predInterChromaPixel(pu, predYuv,
*cu.m_slice->m_refFrameList[0][refIdx0]->m_reconPic[1], mv0);
+            }
+            else
+            {
+                if (bLuma)
+                    predInterLumaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+                if (bChroma)
+                    predInterChromaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+            }
         }
     }
     else
@@ -174,12 +184,18 @@ void Predict::motionCompensation(const CUData& cu,
const PredictionUnit& pu, Yuv

             if (bLuma)
             {
-                predInterLumaShort(pu, m_predShortYuv[0],
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+                if (!!cu.m_slice->m_param->bEnableSCC && refIdx0 ==
(cu.m_slice->m_numRefIdx[0] - 1))
+                    predInterLumaShort(pu, m_predShortYuv[0],
*cu.m_slice->m_refFrameList[0][refIdx0]->m_reconPic[1], mv0);
+                else
+                    predInterLumaShort(pu, m_predShortYuv[0],
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
                 predInterLumaShort(pu, m_predShortYuv[1],
*cu.m_slice->m_refReconPicList[1][refIdx1], mv1);
             }
             if (bChroma)
             {
-                predInterChromaShort(pu, m_predShortYuv[0],
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+                if (!!cu.m_slice->m_param->bEnableSCC && refIdx0 ==
(cu.m_slice->m_numRefIdx[0] - 1))
+                    predInterChromaShort(pu, m_predShortYuv[0],
*cu.m_slice->m_refFrameList[0][refIdx0]->m_reconPic[1], mv0);
+                else
+                    predInterChromaShort(pu, m_predShortYuv[0],
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
                 predInterChromaShort(pu, m_predShortYuv[1],
*cu.m_slice->m_refReconPicList[1][refIdx1], mv1);
             }

@@ -206,10 +222,20 @@ void Predict::motionCompensation(const CUData& cu,
const PredictionUnit& pu, Yuv
             }
             else
             {
-                if (bLuma)
-                    predInterLumaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
-                if (bChroma)
-                    predInterChromaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+                if (!!cu.m_slice->m_param->bEnableSCC && refIdx0 ==
(cu.m_slice->m_numRefIdx[0] - 1))
+                {
+                    if (bLuma)
+                        predInterLumaPixel(pu, predYuv,
*cu.m_slice->m_refFrameList[0][refIdx0]->m_reconPic[1], mv0);
+                    if (bChroma)
+                        predInterChromaPixel(pu, predYuv,
*cu.m_slice->m_refFrameList[0][refIdx0]->m_reconPic[1], mv0);
+                }
+                else
+                {
+                    if (bLuma)
+                        predInterLumaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+                    if (bChroma)
+                        predInterChromaPixel(pu, predYuv,
*cu.m_slice->m_refReconPicList[0][refIdx0], mv0);
+                }
             }
         }
         else
@@ -602,7 +628,7 @@ void Predict::initAdiPattern(const CUData& cu, const
CUGeom& cuGeom, uint32_t pu
     int tuSize = 1 << intraNeighbors.log2TrSize;
     int tuSize2 = tuSize << 1;

-    PicYuv* reconPic = cu.m_encData->m_reconPic;
+    PicYuv* reconPic = cu.m_encData->m_reconPic[0];
     pixel* adiOrigin = reconPic->getLumaAddr(cu.m_cuAddr,
cuGeom.absPartIdx + puAbsPartIdx);
     intptr_t picStride = reconPic->m_stride;

@@ -651,7 +677,7 @@ void Predict::initAdiPattern(const CUData& cu, const
CUGeom& cuGeom, uint32_t pu

 void Predict::initAdiPatternChroma(const CUData& cu, const CUGeom& cuGeom,
uint32_t puAbsPartIdx, const IntraNeighbors& intraNeighbors, uint32_t
chromaId)
 {
-    PicYuv* reconPic = cu.m_encData->m_reconPic;
+    PicYuv* reconPic = cu.m_encData->m_reconPic[0];
     const pixel* adiOrigin = reconPic->getChromaAddr(chromaId,
cu.m_cuAddr, cuGeom.absPartIdx + puAbsPartIdx);
     intptr_t picStride = reconPic->m_strideC;

diff --git a/source/common/slice.h b/source/common/slice.h
index 2f8872473..57ef1afee 100644
--- a/source/common/slice.h
+++ b/source/common/slice.h
@@ -405,6 +405,7 @@ public:

     Frame*      m_lastEncPic;
     bool        m_bLMvdL1Zero;
+    bool        m_bTemporalMvp;

     Slice()
     {
@@ -421,6 +422,7 @@ public:
         m_rpsIdx = -1;
         m_chromaQpOffset[0] = m_chromaQpOffset[1] = 0;
         m_fieldNum = 0;
+        m_bTemporalMvp = false;
     }

     void disableWeights();
diff --git a/source/encoder/analysis.cpp b/source/encoder/analysis.cpp
index 4bbfcbfe3..789069c4c 100644
--- a/source/encoder/analysis.cpp
+++ b/source/encoder/analysis.cpp
@@ -271,7 +271,7 @@ Mode& Analysis::compressCTU(CUData& ctu, Frame& frame,
const CUGeom& cuGeom, con
         {
             /* In RD Level 0/1, copy source pixels into the reconstructed
block so
              * they are available for intra predictions */
-            m_modeDepth[0].fencYuv.copyToPicYuv(*m_frame->m_reconPic,
ctu.m_cuAddr, 0);
+            m_modeDepth[0].fencYuv.copyToPicYuv(*m_frame->m_reconPic[0],
ctu.m_cuAddr, 0);

             compressInterCU_rd0_4(ctu, cuGeom, qp);

@@ -508,7 +508,7 @@ void Analysis::qprdRefine(const CUData& parentCTU,
const CUGeom& cuGeom, int32_t

     /* Copy best data to encData CTU and recon */
     md.bestMode->cu.copyToPic(depth);
-    md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic,
parentCTU.m_cuAddr, cuGeom.absPartIdx);
+    md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic[0],
parentCTU.m_cuAddr, cuGeom.absPartIdx);
 }

 uint64_t Analysis::compressIntraCU(const CUData& parentCTU, const CUGeom&
cuGeom, int32_t qp)
@@ -816,7 +816,10 @@ uint64_t Analysis::compressIntraCU(const CUData&
parentCTU, const CUGeom& cuGeom
     /* Copy best data to encData CTU and recon */
     md.bestMode->cu.copyToPic(depth);
     if (md.bestMode != &md.pred[PRED_SPLIT])
-        md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic,
parentCTU.m_cuAddr, cuGeom.absPartIdx);
+    {
+        for (int i = 0; i < !!m_param->bEnableSCC + 1; i++)
+            md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic[i],
parentCTU.m_cuAddr, cuGeom.absPartIdx);
+    }

     return md.bestMode->rdCost;
 }
@@ -1292,7 +1295,7 @@ uint32_t Analysis::compressInterCU_dist(const CUData&
parentCTU, const CUGeom& c

     /* Copy best data to encData CTU and recon */
     md.bestMode->cu.copyToPic(depth);
-    md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic, cuAddr,
cuGeom.absPartIdx);
+    md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic[0], cuAddr,
cuGeom.absPartIdx);

     return refMask;
 }
@@ -1310,14 +1313,14 @@ SplitData Analysis::compressInterCU_rd0_4(const
CUData& parentCTU, const CUGeom&
     if (m_param->searchMethod == X265_SEA)
     {
         int numPredDir = m_slice->isInterP() ? 1 : 2;
-        int offset =
(int)(m_frame->m_reconPic->m_cuOffsetY[parentCTU.m_cuAddr] +
m_frame->m_reconPic->m_buOffsetY[cuGeom.absPartIdx]);
+        int offset =
(int)(m_frame->m_reconPic[0]->m_cuOffsetY[parentCTU.m_cuAddr] +
m_frame->m_reconPic[0]->m_buOffsetY[cuGeom.absPartIdx]);
         for (int list = 0; list < numPredDir; list++)
             for (int i = 0; i <
m_frame->m_encData->m_slice->m_numRefIdx[list]; i++)
                 for (int planes = 0; planes < INTEGRAL_PLANE_NUM; planes++)
                     m_modeDepth[depth].fencYuv.m_integral[list][i][planes]
=
m_frame->m_encData->m_slice->m_refFrameList[list][i]->m_encData->m_meIntegral[planes]
+ offset;
     }

-    PicYuv& reconPic = *m_frame->m_reconPic;
+    PicYuv& reconPic = *m_frame->m_reconPic[0];
     SplitData splitCUData;

     bool bHEVCBlockAnalysis = (m_param->bAnalysisType == AVC_INFO &&
cuGeom.numPartitions > 16);
@@ -2026,7 +2029,7 @@ SplitData Analysis::compressInterCU_rd5_6(const
CUData& parentCTU, const CUGeom&
     if (m_param->searchMethod == X265_SEA)
     {
         int numPredDir = m_slice->isInterP() ? 1 : 2;
-        int offset =
(int)(m_frame->m_reconPic->m_cuOffsetY[parentCTU.m_cuAddr] +
m_frame->m_reconPic->m_buOffsetY[cuGeom.absPartIdx]);
+        int offset =
(int)(m_frame->m_reconPic[0]->m_cuOffsetY[parentCTU.m_cuAddr] +
m_frame->m_reconPic[0]->m_buOffsetY[cuGeom.absPartIdx]);
         for (int list = 0; list < numPredDir; list++)
             for (int i = 0; i <
m_frame->m_encData->m_slice->m_numRefIdx[list]; i++)
                 for (int planes = 0; planes < INTEGRAL_PLANE_NUM; planes++)
@@ -2708,7 +2711,8 @@ SplitData Analysis::compressInterCU_rd5_6(const
CUData& parentCTU, const CUGeom&

         /* Copy best data to encData CTU and recon */
         md.bestMode->cu.copyToPic(depth);
-        md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic,
parentCTU.m_cuAddr, cuGeom.absPartIdx);
+        for (int i = 0; i < !!m_param->bEnableSCC + 1; i++)
+            md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic[i],
parentCTU.m_cuAddr, cuGeom.absPartIdx);
     }
     else
     {
@@ -2994,7 +2998,7 @@ void Analysis::recodeCU(const CUData& parentCTU,
const CUGeom& cuGeom, int32_t q

         /* Copy best data to encData CTU and recon */
         md.bestMode->cu.copyToPic(depth);
-        md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic,
parentCTU.m_cuAddr, cuGeom.absPartIdx);
+        md.bestMode->reconYuv.copyToPicYuv(*m_frame->m_reconPic[0],
parentCTU.m_cuAddr, cuGeom.absPartIdx);
     }
     if (m_param->bDynamicRefine && bDecidedDepth)
         trainCU(parentCTU, cuGeom, *md.bestMode, td);
@@ -3580,7 +3584,7 @@ void Analysis::checkBidir2Nx2N(Mode& inter2Nx2N,
Mode& bidir2Nx2N, const CUGeom&
 {
     CUData& cu = bidir2Nx2N.cu;

-    if (cu.isBipredRestriction() || inter2Nx2N.bestME[0][0].cost ==
MAX_UINT || inter2Nx2N.bestME[0][1].cost == MAX_UINT)
+    if ((cu.is8x8BipredRestriction(inter2Nx2N.bestME[0][0].mv,
inter2Nx2N.bestME[0][1].mv, inter2Nx2N.bestME[0][0].ref,
inter2Nx2N.bestME[0][1].ref) ? (cu.m_cuDepth[0] == 3) :
cu.isBipredRestriction()) || inter2Nx2N.bestME[0][0].cost == MAX_UINT ||
inter2Nx2N.bestME[0][1].cost == MAX_UINT)
     {
         bidir2Nx2N.sa8dCost = MAX_INT64;
         bidir2Nx2N.rdCost = MAX_INT64;
diff --git a/source/encoder/dpb.cpp b/source/encoder/dpb.cpp
index d957008eb..8ef1f7abe 100644
--- a/source/encoder/dpb.cpp
+++ b/source/encoder/dpb.cpp
@@ -53,8 +53,8 @@ DPB::~DPB()
         FrameData* next = m_frameDataFreeList->m_freeListNext;
         m_frameDataFreeList->destroy();

-        m_frameDataFreeList->m_reconPic->destroy();
-        delete m_frameDataFreeList->m_reconPic;
+        m_frameDataFreeList->m_reconPic[0]->destroy();
+        delete m_frameDataFreeList->m_reconPic[0];

         delete m_frameDataFreeList;
         m_frameDataFreeList = next;
@@ -132,7 +132,8 @@ void DPB::recycleUnreferenced()
                 curFrame->m_prevCtuInfoChange = NULL;
             }
             curFrame->m_encData = NULL;
-            curFrame->m_reconPic = NULL;
+            for (int i = 0; i < !!curFrame->m_param->bEnableSCC + 1; i++)
+                curFrame->m_reconPic[i] = NULL;
         }
     }
 }
@@ -206,7 +207,8 @@ void DPB::prepareEncode(Frame *newFrame)
     // Do decoding refresh marking if any
     decodingRefreshMarking(pocCurr, slice->m_nalUnitType, layer);

-    computeRPS(pocCurr, newFrame->m_tempLayer, slice->isIRAP(),
&slice->m_rps, slice->m_sps->maxDecPicBuffering[newFrame->m_tempLayer],
layer);
+    uint32_t maxDecBuffer =
(slice->m_sps->maxDecPicBuffering[newFrame->m_tempLayer] >= 8 &&
slice->m_param->bEnableSCC) ? 7 :
slice->m_sps->maxDecPicBuffering[newFrame->m_tempLayer];
+    computeRPS(pocCurr, newFrame->m_tempLayer, slice->isIRAP(),
&slice->m_rps, maxDecBuffer, layer);
     bool isTSAPic = ((slice->m_nalUnitType == 2) || (slice->m_nalUnitType
== 3)) ? true : false;
     // Mark pictures in m_piclist as unreferenced if they are not included
in RPS
     applyReferencePictureSet(&slice->m_rps, pocCurr,
newFrame->m_tempLayer, isTSAPic, layer);
@@ -367,6 +369,15 @@ void DPB::prepareEncode(Frame *newFrame)
         slice->m_bLMvdL1Zero = false;
     }

+    if (!slice->isIntra() && slice->m_param->bEnableTemporalMvp)
+    {
+        const Frame* colPic = slice->m_refFrameList[slice->isInterB() &&
!slice->m_colFromL0Flag][slice->m_colRefIdx];
+        if (colPic->m_poc == slice->m_poc)
+            slice->m_bTemporalMvp = false;
+        else
+            slice->m_bTemporalMvp = true;
+    }
+
     // Disable Loopfilter in bound area, because we will do
slice-parallelism in future
     slice->m_sLFaseFlag = (newFrame->m_param->maxSlices > 1) ? false :
((SLFASE_CONSTANT & (1 << (pocCurr % 31))) > 0);

diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
index f4782f55d..4043342c1 100644
--- a/source/encoder/encoder.cpp
+++ b/source/encoder/encoder.cpp
@@ -624,7 +624,7 @@ int Encoder::getRefFrameList(PicYuv** l0, PicYuv** l1,
int sliceType, int poc, i
         {
             for (int j = 0; j <
framePtr->m_encData->m_slice->m_numRefIdx[0]; j++)    // check only for
--ref=n number of frames.
             {
-                if (framePtr->m_encData->m_slice->m_refFrameList[0][j] &&
framePtr->m_encData->m_slice->m_refFrameList[0][j]->m_reconPic != NULL)
+                if (framePtr->m_encData->m_slice->m_refFrameList[0][j] &&
framePtr->m_encData->m_slice->m_refFrameList[0][j]->m_reconPic[0] != NULL)
                 {
                     int l0POC =
framePtr->m_encData->m_slice->m_refFrameList[0][j]->m_poc;
                     pocL0[j] = l0POC;
@@ -634,19 +634,19 @@ int Encoder::getRefFrameList(PicYuv** l0, PicYuv**
l1, int sliceType, int poc, i
                         while (l0Fp->m_reconRowFlag[l0Fp->m_numRows -
1].get() == 0)
                             l0Fp->m_reconRowFlag[l0Fp->m_numRows -
1].waitForChange(0); /* If recon is not ready, current frame encoder has to
wait. */
                     }
-                    l0[j] = l0Fp->m_reconPic;
+                    l0[j] = l0Fp->m_reconPic[0];
                 }
             }
             for (int j = 0; j <
framePtr->m_encData->m_slice->m_numRefIdx[1]; j++)    // check only for
--ref=n number of frames.
             {
-                if (framePtr->m_encData->m_slice->m_refFrameList[1][j] &&
framePtr->m_encData->m_slice->m_refFrameList[1][j]->m_reconPic != NULL)
+                if (framePtr->m_encData->m_slice->m_refFrameList[1][j] &&
framePtr->m_encData->m_slice->m_refFrameList[1][j]->m_reconPic[0] != NULL)
                 {
                     int l1POC =
framePtr->m_encData->m_slice->m_refFrameList[1][j]->m_poc;
                     pocL1[j] = l1POC;
                     Frame* l1Fp = m_dpb->m_picList.getPOC(l1POC, 0);
                     while (l1Fp->m_reconRowFlag[l1Fp->m_numRows - 1].get()
== 0)
                         l1Fp->m_reconRowFlag[l1Fp->m_numRows -
1].waitForChange(0); /* If recon is not ready, current frame encoder has to
wait. */
-                    l1[j] = l1Fp->m_reconPic;
+                    l1[j] = l1Fp->m_reconPic[0];
                 }
             }
         }
@@ -1974,7 +1974,7 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
                     x265_free_analysis_data(m_param,
&outFrame->m_analysisData);
                 if (pic_out[sLayer])
                 {
-                    PicYuv* recpic = outFrame->m_reconPic;
+                    PicYuv* recpic = outFrame->m_reconPic[0];
                     pic_out[sLayer]->poc = slice->m_poc;
                     pic_out[sLayer]->bitDepth = X265_DEPTH;
                     pic_out[sLayer]->userData = outFrame->m_userData;
@@ -2330,15 +2330,15 @@ int Encoder::encode(const x265_picture* pic_in,
x265_picture** pic_out)
             {
                 int padX = m_param->maxCUSize + 32;
                 int padY = m_param->maxCUSize + 16;
-                uint32_t numCuInHeight =
(frameEnc[0]->m_encData->m_reconPic->m_picHeight + m_param->maxCUSize - 1)
/ m_param->maxCUSize;
+                uint32_t numCuInHeight =
(frameEnc[0]->m_encData->m_reconPic[0]->m_picHeight + m_param->maxCUSize -
1) / m_param->maxCUSize;
                 int maxHeight = numCuInHeight * m_param->maxCUSize;
                 for (int i = 0; i < INTEGRAL_PLANE_NUM; i++)
                 {
-                    frameEnc[0]->m_encData->m_meBuffer[i] =
X265_MALLOC(uint32_t, frameEnc[0]->m_reconPic->m_stride * (maxHeight + (2 *
padY)));
+                    frameEnc[0]->m_encData->m_meBuffer[i] =
X265_MALLOC(uint32_t, frameEnc[0]->m_reconPic[0]->m_stride * (maxHeight +
(2 * padY)));
                     if (frameEnc[0]->m_encData->m_meBuffer[i])
                     {
-                        memset(frameEnc[0]->m_encData->m_meBuffer[i], 0,
sizeof(uint32_t)* frameEnc[0]->m_reconPic->m_stride * (maxHeight + (2 *
padY)));
-                        frameEnc[0]->m_encData->m_meIntegral[i] =
frameEnc[0]->m_encData->m_meBuffer[i] +
frameEnc[0]->m_encData->m_reconPic->m_stride * padY + padX;
+                        memset(frameEnc[0]->m_encData->m_meBuffer[i], 0,
sizeof(uint32_t)* frameEnc[0]->m_reconPic[0]->m_stride * (maxHeight + (2 *
padY)));
+                        frameEnc[0]->m_encData->m_meIntegral[i] =
frameEnc[0]->m_encData->m_meBuffer[i] +
frameEnc[0]->m_encData->m_reconPic[0]->m_stride * padY + padX;
                     }
                     else
                         x265_log(m_param, X265_LOG_ERROR, "SEA motion
search: POC %d Integral buffer[%d] unallocated\n", frameEnc[0]->m_poc, i);
@@ -3072,7 +3072,7 @@ void Encoder::fetchStats(x265_stats *stats, size_t
statsSizeBytes, int layer)

 void Encoder::finishFrameStats(Frame* curFrame, FrameEncoder *curEncoder,
x265_frame_stats* frameStats, int inPoc, int layer)
 {
-    PicYuv* reconPic = curFrame->m_reconPic;
+    PicYuv* reconPic = curFrame->m_reconPic[0];
     uint64_t bits = curEncoder->m_accessUnitBits[layer];

     //===== calculate PSNR =====
diff --git a/source/encoder/entropy.cpp b/source/encoder/entropy.cpp
index 2ec93ab6a..22408e6f3 100644
--- a/source/encoder/entropy.cpp
+++ b/source/encoder/entropy.cpp
@@ -997,7 +997,7 @@ void Entropy::codeSliceHeader(const Slice& slice,
FrameData& encData, uint32_t s
         }

         if (slice.m_sps->bTemporalMVPEnabled)
-            WRITE_FLAG(1, "slice_temporal_mvp_enable_flag");
+            WRITE_FLAG(slice.m_bTemporalMvp,
"slice_temporal_mvp_enable_flag");
     }
     const SAOParam *saoParam = encData.m_saoParam;
     if (slice.m_bUseSao)
@@ -1039,7 +1039,7 @@ void Entropy::codeSliceHeader(const Slice& slice,
FrameData& encData, uint32_t s
     if (slice.isInterB())
         WRITE_FLAG(slice.m_bLMvdL1Zero, "mvd_l1_zero_flag");

-    if (slice.m_sps->bTemporalMVPEnabled)
+    if (slice.m_bTemporalMvp)
     {
         if (slice.m_sliceType == B_SLICE)
             WRITE_FLAG(slice.m_colFromL0Flag, "collocated_from_l0_flag");
diff --git a/source/encoder/frameencoder.cpp
b/source/encoder/frameencoder.cpp
index 0ee3e9a2e..286eb520a 100644
--- a/source/encoder/frameencoder.cpp
+++ b/source/encoder/frameencoder.cpp
@@ -591,7 +591,7 @@ void FrameEncoder::compressFrame(int layer)
             WeightParam *w = NULL;
             if ((bUseWeightP || bUseWeightB) &&
slice->m_weightPredTable[l][ref][0].wtPresent)
                 w = slice->m_weightPredTable[l][ref];
-            slice->m_refReconPicList[l][ref] =
slice->m_refFrameList[l][ref]->m_reconPic;
+            slice->m_refReconPicList[l][ref] =
slice->m_refFrameList[l][ref]->m_reconPic[0];
             m_mref[l][ref].init(slice->m_refReconPicList[l][ref], w,
*m_param);
         }
         if (m_param->analysisSave && (bUseWeightP || bUseWeightB))
@@ -988,7 +988,7 @@ void FrameEncoder::compressFrame(int layer)

     if (m_param->maxSlices > 1)
     {
-        PicYuv *reconPic = m_frame[layer]->m_reconPic;
+        PicYuv *reconPic = m_frame[layer]->m_reconPic[0];
         uint32_t height = reconPic->m_picHeight;
         initDecodedPictureHashSEI(0, 0, height, layer);
     }
@@ -1252,7 +1252,7 @@ void FrameEncoder::compressFrame(int layer)

 void FrameEncoder::initDecodedPictureHashSEI(int row, int cuAddr, int
height, int layer)
 {
-    PicYuv *reconPic = m_frame[layer]->m_reconPic;
+    PicYuv *reconPic = m_frame[layer]->m_reconPic[0];
     uint32_t width = reconPic->m_picWidth;
     intptr_t stride = reconPic->m_stride;
     uint32_t maxCUHeight = m_param->maxCUSize;
@@ -2263,7 +2263,7 @@ void
FrameEncoder::readModel(FilmGrainCharacteristics* m_filmGrain, FILE* filmgr
 void FrameEncoder::vmafFrameLevelScore()
 {
     PicYuv *fenc = m_frame->m_fencPic;
-    PicYuv *recon = m_frame->m_reconPic;
+    PicYuv *recon = m_frame->m_reconPic[0];

     x265_vmaf_framedata *vmafframedata =
(x265_vmaf_framedata*)x265_malloc(sizeof(x265_vmaf_framedata));
     if (!vmafframedata)
diff --git a/source/encoder/framefilter.cpp b/source/encoder/framefilter.cpp
index da01d0ceb..344ac738d 100644
--- a/source/encoder/framefilter.cpp
+++ b/source/encoder/framefilter.cpp
@@ -256,7 +256,7 @@ static void restoreOrigLosslessYuv(const CUData* cu,
Frame& frame, uint32_t absP
     const int size = cu->m_log2CUSize[absPartIdx] - 2;
     const uint32_t cuAddr = cu->m_cuAddr;

-    PicYuv* reconPic = frame.m_reconPic;
+    PicYuv* reconPic = frame.m_reconPic[0];
     PicYuv* fencPic  = frame.m_fencPic;

     pixel* dst = reconPic->getLumaAddr(cuAddr, absPartIdx);
@@ -337,7 +337,7 @@ void
FrameFilter::ParallelFilter::processSaoCTU(SAOParam *saoParam, int col)

         uint32_t cuAddr = m_rowAddr + col;
         const CUData* ctu = m_encData->getPicCTU(cuAddr);
-        assert(m_frameFilter->m_frame->m_reconPic ==
m_encData->m_reconPic);
+        assert(m_frameFilter->m_frame->m_reconPic[0] ==
m_encData->m_reconPic[0]);
         origCUSampleRestoration(ctu, cuGeoms[ctuGeomMap[cuAddr]],
*m_frameFilter->m_frame);
     }
 }
@@ -352,7 +352,7 @@ void FrameFilter::ParallelFilter::processPostCu(int
col) const
     if ((col != 0) & (col != m_frameFilter->m_numCols - 1) & (m_row != 0)
& (m_row != m_frameFilter->m_numRows - 1))
         return;

-    PicYuv *reconPic = m_frameFilter->m_frame->m_reconPic;
+    PicYuv *reconPic = m_frameFilter->m_frame->m_reconPic[0];
     const uint32_t lineStartCUAddr = m_rowAddr + col;
     const int realH = getCUHeight();
     const int realW = m_frameFilter->getCUWidth(col);
@@ -441,7 +441,7 @@ void FrameFilter::ParallelFilter::processTasks(int
/*workerThreadId*/)
     SAOParam* saoParam = m_encData->m_saoParam;
     const CUGeom* cuGeoms = m_frameFilter->m_frameEncoder->m_cuGeoms;
     const uint32_t* ctuGeomMap =
m_frameFilter->m_frameEncoder->m_ctuGeomMap;
-    PicYuv* reconPic = m_encData->m_reconPic;
+    PicYuv* reconPic = m_encData->m_reconPic[0];
     const int colStart = m_lastCol.get();
     const int numCols = m_frameFilter->m_numCols;
     // TODO: Waiting previous row finish or simple clip on it?
@@ -653,7 +653,7 @@ void FrameFilter::processRow(int row, int layer)

 void FrameFilter::processPostRow(int row, int layer)
 {
-    PicYuv *reconPic = m_frame->m_reconPic;
+    PicYuv *reconPic = m_frame->m_reconPic[0];
     const uint32_t numCols =
m_frame->m_encData->m_slice->m_sps->numCuInWidth;
     const uint32_t lineStartCUAddr = row * numCols;

@@ -737,7 +737,7 @@ void FrameFilter::computeMEIntegral(int row)
             }
         }

-        int stride = (int)m_frame->m_reconPic->m_stride;
+        int stride = (int)m_frame->m_reconPic[0]->m_stride;
         int padX = m_param->maxCUSize + 32;
         int padY = m_param->maxCUSize + 16;
         int numCuInHeight =
m_frame->m_encData->m_slice->m_sps->numCuInHeight;
@@ -763,7 +763,7 @@ void FrameFilter::computeMEIntegral(int row)

         for (int y = startRow; y < height; y++)
         {
-            pixel    *pix = m_frame->m_reconPic->m_picOrg[0] + y * stride
- padX;
+            pixel    *pix = m_frame->m_reconPic[0]->m_picOrg[0] + y *
stride - padX;
             uint32_t *sum32x32 = m_frame->m_encData->m_meIntegral[0] + (y
+ 1) * stride - padX;
             uint32_t *sum32x24 = m_frame->m_encData->m_meIntegral[1] + (y
+ 1) * stride - padX;
             uint32_t *sum32x8 = m_frame->m_encData->m_meIntegral[2] + (y +
1) * stride - padX;
diff --git a/source/encoder/level.cpp b/source/encoder/level.cpp
index b5af25b4f..84f407702 100644
--- a/source/encoder/level.cpp
+++ b/source/encoder/level.cpp
@@ -178,7 +178,7 @@ void determineLevel(const x265_param &param, VPS& vps)
     uint32_t samplesPerSec = (uint32_t)(lumaSamples *
((double)param.fpsNum / param.fpsDenom));
     uint32_t bitrate = param.rc.vbvMaxBitrate ? param.rc.vbvMaxBitrate :
param.rc.bitrate;

-    const uint32_t MaxDpbPicBuf = 6;
+    const uint32_t MaxDpbPicBuf = !!param.bEnableSCC ? 7 : 6;
     vps.ptl.levelIdc = Level::NONE;
     vps.ptl.tierFlag = Level::MAIN;

@@ -388,7 +388,7 @@ bool enforceLevel(x265_param& param, VPS& vps)
     for (uint32_t i = 0; i < vps.maxTempSubLayers; i++)
     {
         vps.numReorderPics[i] = (i == 0) ? ((param.bBPyramid &&
param.bframes > 1) ? 2 : !!param.bframes) : i;
-        vps.maxDecPicBuffering[i] = X265_MIN(MAX_NUM_REF,
X265_MAX(vps.numReorderPics[i] + 2, (uint32_t)param.maxNumReferences) + 1);
+        vps.maxDecPicBuffering[i] = X265_MIN(MAX_NUM_REF,
X265_MAX(vps.numReorderPics[i] + 2, (uint32_t)param.maxNumReferences) + 1)
+ !!param.bEnableSCC;
     }

     if (!!param.bEnableTemporalSubLayers)
@@ -504,7 +504,7 @@ bool enforceLevel(x265_param& param, VPS& vps)
     }

     /* The value of sps_max_dec_pic_buffering_minus1[ HighestTid ] + 1
shall be less than or equal to MaxDpbSize */
-    const uint32_t MaxDpbPicBuf = 6;
+    const uint32_t MaxDpbPicBuf = !!param.bEnableSCC ? 7 : 6;
     uint32_t maxDpbSize = MaxDpbPicBuf;
     if (!param.uhdBluray) /* Do not change MaxDpbPicBuf for UHD-Bluray */
     {
@@ -519,8 +519,7 @@ bool enforceLevel(x265_param& param, VPS& vps)
     int savedRefCount = param.maxNumReferences;
     while (vps.maxDecPicBuffering[vps.maxTempSubLayers - 1] > maxDpbSize
&& param.maxNumReferences > 1)
     {
-        param.maxNumReferences--;
-        vps.maxDecPicBuffering[vps.maxTempSubLayers - 1] =
X265_MIN(MAX_NUM_REF, X265_MAX(vps.numReorderPics[vps.maxTempSubLayers - 1]
+ 1, (uint32_t)param.maxNumReferences) + 1);
+        vps.maxDecPicBuffering[vps.maxTempSubLayers - 1] =
X265_MIN(MAX_NUM_REF, X265_MAX(vps.numReorderPics[vps.maxTempSubLayers - 1]
+ 1, (uint32_t)param.maxNumReferences) + 1 + !!param.bEnableSCC);
     }
     if (param.maxNumReferences != savedRefCount)
         x265_log(&param, X265_LOG_WARNING, "Lowering max references to %d
to meet level requirement\n", param.maxNumReferences);
diff --git a/source/encoder/sao.cpp b/source/encoder/sao.cpp
index 105ec79de..329f36ccf 100644
--- a/source/encoder/sao.cpp
+++ b/source/encoder/sao.cpp
@@ -267,7 +267,7 @@ void SAO::startSlice(Frame* frame, Entropy& initState)
 // CTU-based SAO process without slice granularity
 void SAO::applyPixelOffsets(int addr, int typeIdx, int plane)
 {
-    PicYuv* reconPic = m_frame->m_reconPic;
+    PicYuv* reconPic = m_frame->m_reconPic[0];
     pixel* rec = reconPic->getPlaneAddr(plane, addr);
     intptr_t stride = plane ? reconPic->m_strideC : reconPic->m_stride;
     uint32_t picWidth  = m_param->sourceWidth;
@@ -565,7 +565,7 @@ void SAO::applyPixelOffsets(int addr, int typeIdx, int
plane)
 /* Process SAO unit */
 void SAO::generateLumaOffsets(SaoCtuParam* ctuParam, int idxY, int idxX)
 {
-    PicYuv* reconPic = m_frame->m_reconPic;
+    PicYuv* reconPic = m_frame->m_reconPic[0];
     intptr_t stride = reconPic->m_stride;
     int ctuWidth = m_param->maxCUSize;
     int ctuHeight = m_param->maxCUSize;
@@ -625,7 +625,7 @@ void SAO::generateLumaOffsets(SaoCtuParam* ctuParam,
int idxY, int idxX)
 /* Process SAO unit (Chroma only) */
 void SAO::generateChromaOffsets(SaoCtuParam* ctuParam[3], int idxY, int
idxX)
 {
-    PicYuv* reconPic = m_frame->m_reconPic;
+    PicYuv* reconPic = m_frame->m_reconPic[0];
     intptr_t stride = reconPic->m_strideC;
     int ctuWidth  = m_param->maxCUSize;
     int ctuHeight = m_param->maxCUSize;
@@ -729,7 +729,7 @@ void SAO::generateChromaOffsets(SaoCtuParam*
ctuParam[3], int idxY, int idxX)
 void SAO::calcSaoStatsCTU(int addr, int plane)
 {
     Slice* slice = m_frame->m_encData->m_slice;
-    const PicYuv* reconPic = m_frame->m_reconPic;
+    const PicYuv* reconPic = m_frame->m_reconPic[0];
     const CUData* cu = m_frame->m_encData->getPicCTU(addr);
     const pixel* fenc0 = m_frame->m_fencPic->getPlaneAddr(plane, addr);
     const pixel* rec0  = reconPic->getPlaneAddr(plane, addr);
@@ -916,7 +916,7 @@ void SAO::calcSaoStatsCu_BeforeDblk(Frame* frame, int
idxX, int idxY)

     int x, y;
     const CUData* cu = frame->m_encData->getPicCTU(addr);
-    const PicYuv* reconPic = m_frame->m_reconPic;
+    const PicYuv* reconPic = m_frame->m_reconPic[0];
     const pixel* fenc;
     const pixel* rec;
     intptr_t stride = reconPic->m_stride;
diff --git a/source/encoder/search.cpp b/source/encoder/search.cpp
index ba220eaa6..3a5c54ffa 100644
--- a/source/encoder/search.cpp
+++ b/source/encoder/search.cpp
@@ -497,7 +497,7 @@ void Search::codeIntraLumaQT(Mode& mode, const CUGeom&
cuGeom, uint32_t tuDepth,
     }

     // set reconstruction for next intra prediction blocks if full TU
prediction won
-    PicYuv*  reconPic = m_frame->m_reconPic;
+    PicYuv*  reconPic = m_frame->m_reconPic[0];
     pixel*   picReconY = reconPic->getLumaAddr(cu.m_cuAddr,
cuGeom.absPartIdx + absPartIdx);
     intptr_t picStride = reconPic->m_stride;
     primitives.cu[sizeIdx].copy_pp(picReconY, picStride, reconQt,
reconQtStride);
@@ -673,7 +673,7 @@ void Search::codeIntraLumaTSkip(Mode& mode, const
CUGeom& cuGeom, uint32_t tuDep
     }

     // set reconstruction for next intra prediction blocks
-    PicYuv*  reconPic = m_frame->m_reconPic;
+    PicYuv*  reconPic = m_frame->m_reconPic[0];
     pixel*   picReconY = reconPic->getLumaAddr(cu.m_cuAddr,
cuGeom.absPartIdx + absPartIdx);
     intptr_t picStride = reconPic->m_stride;
     primitives.cu[sizeIdx].copy_pp(picReconY, picStride, reconQt,
reconQtStride);
@@ -724,7 +724,7 @@ void Search::residualTransformQuantIntra(Mode& mode,
const CUGeom& cuGeom, uint3
         uint32_t sizeIdx   = log2TrSize - 2;
         primitives.cu[sizeIdx].calcresidual[stride % 64 == 0](fenc, pred,
residual, stride);

-        PicYuv*  reconPic = m_frame->m_reconPic;
+        PicYuv*  reconPic = m_frame->m_reconPic[0];
         pixel*   picReconY = reconPic->getLumaAddr(cu.m_cuAddr,
cuGeom.absPartIdx + absPartIdx);
         intptr_t picStride = reconPic->m_stride;

@@ -888,7 +888,7 @@ void Search::codeIntraChromaQt(Mode& mode, const
CUGeom& cuGeom, uint32_t tuDept
             coeff_t* coeffC        = m_rqt[qtLayer].coeffRQT[chromaId] +
coeffOffsetC;
             pixel*   reconQt       =
m_rqt[qtLayer].reconQtYuv.getChromaAddr(chromaId, absPartIdxC);
             uint32_t reconQtStride = m_rqt[qtLayer].reconQtYuv.m_csize;
-            PicYuv*  reconPic = m_frame->m_reconPic;
+            PicYuv*  reconPic = m_frame->m_reconPic[0];
             pixel*   picReconC = reconPic->getChromaAddr(chromaId,
cu.m_cuAddr, cuGeom.absPartIdx + absPartIdxC);
             intptr_t picStride = reconPic->m_strideC;

@@ -1079,7 +1079,7 @@ void Search::codeIntraChromaTSkip(Mode& mode, const
CUGeom& cuGeom, uint32_t tuD
             cu.setCbfPartRange(bCbf << tuDepth, ttype, absPartIdxC,
tuIterator.absPartIdxStep);
             cu.setTransformSkipPartRange(bTSkip, ttype, absPartIdxC,
tuIterator.absPartIdxStep);

-            PicYuv*  reconPic = m_frame->m_reconPic;
+            PicYuv*  reconPic = m_frame->m_reconPic[0];
             pixel*   reconPicC = reconPic->getChromaAddr(chromaId,
cu.m_cuAddr, cuGeom.absPartIdx + absPartIdxC);
             intptr_t picStride = reconPic->m_strideC;
             primitives.cu[sizeIdxC].copy_pp(reconPicC, picStride, reconQt,
reconQtStride);
@@ -1186,7 +1186,7 @@ void Search::residualQTIntraChroma(Mode& mode, const
CUGeom& cuGeom, uint32_t ab
             int16_t* residual = resiYuv.getChromaAddr(chromaId,
absPartIdxC);
             uint32_t coeffOffsetC  = absPartIdxC << (LOG2_UNIT_SIZE * 2 -
(m_hChromaShift + m_vChromaShift));
             coeff_t* coeffC        = cu.m_trCoeff[ttype] + coeffOffsetC;
-            PicYuv*  reconPic = m_frame->m_reconPic;
+            PicYuv*  reconPic = m_frame->m_reconPic[0];
             pixel*   picReconC = reconPic->getChromaAddr(chromaId,
cu.m_cuAddr, cuGeom.absPartIdx + absPartIdxC);
             intptr_t picStride = reconPic->m_strideC;

@@ -1285,6 +1285,9 @@ void Search::checkIntra(Mode& intraMode, const
CUGeom& cuGeom, PartSize partSize

     updateModeCost(intraMode);
     checkDQP(intraMode, cuGeom);
+
+    if (!!m_param->bEnableSCC)
+        intraMode.reconYuv.copyToPicYuv(*m_frame->m_reconPic[1],
cu.m_cuAddr, cuGeom.absPartIdx);
 }

 /* Note that this function does not save the best intra prediction, it must
@@ -1672,7 +1675,7 @@ sse_t Search::estIntraPredQT(Mode &intraMode, const
CUGeom& cuGeom, const uint32
              * output recon picture, so it cannot proceed in parallel with
anything else when doing INTRA_NXN. Also
              * it is not updating m_rdContexts[depth].cur for the later
PUs which I suspect is slightly wrong. I think
              * that the contexts should be tracked through each PU */
-            PicYuv*  reconPic = m_frame->m_reconPic;
+            PicYuv*  reconPic = m_frame->m_reconPic[0];
             pixel*   dst       = reconPic->getLumaAddr(cu.m_cuAddr,
cuGeom.absPartIdx + absPartIdx);
             uint32_t dststride = reconPic->m_stride;
             const pixel*   src = reconYuv->getLumaAddr(absPartIdx);
@@ -1845,7 +1848,7 @@ sse_t Search::estIntraPredChromaQT(Mode &intraMode,
const CUGeom& cuGeom)
         if (!tuIterator.isLastSection())
         {
             uint32_t zorder    = cuGeom.absPartIdx + absPartIdxC;
-            PicYuv*  reconPic  = m_frame->m_reconPic;
+            PicYuv*  reconPic  = m_frame->m_reconPic[0];
             uint32_t dststride = reconPic->m_strideC;
             const pixel* src;
             pixel* dst;
@@ -2008,7 +2011,10 @@ int Search::selectMVP(const CUData& cu, const
PredictionUnit& pu, const MV amvp[
                 continue;
         }
         cu.clipMv(mvCand);
-        predInterLumaPixel(pu, tmpPredYuv,
*m_slice->m_refReconPicList[list][ref], mvCand);
+        if (!!m_slice->m_param->bEnableSCC && !list && ref ==
m_slice->m_numRefIdx[0] - 1)
+            predInterLumaPixel(pu, tmpPredYuv,
*m_slice->m_refFrameList[list][ref]->m_reconPic[1], mvCand);
+        else
+            predInterLumaPixel(pu, tmpPredYuv,
*m_slice->m_refReconPicList[list][ref], mvCand);
         costs[i] = m_me.bufSAD(tmpPredYuv.getLumaAddr(pu.puAbsPartIdx),
tmpPredYuv.m_size);
     }

@@ -2263,7 +2269,7 @@ void Search::predInterSearch(Mode& interMode, const
CUGeom& cuGeom, bool bChroma
                     int puX = puIdx & 1;
                     int puY = puIdx >> 1;
                     for (int planes = 0; planes < INTEGRAL_PLANE_NUM;
planes++)
-                        m_me.integral[planes] =
interMode.fencYuv->m_integral[list][ref][planes] + puX * pu.width + puY *
pu.height * m_slice->m_refFrameList[list][ref]->m_reconPic->m_stride;
+                        m_me.integral[planes] =
interMode.fencYuv->m_integral[list][ref][planes] + puX * pu.width + puY *
pu.height * m_slice->m_refFrameList[list][ref]->m_reconPic[0]->m_stride;
                 }
                 setSearchRange(cu, mvp, m_param->searchRange, mvmin,
mvmax);
                 MV mvpIn = mvp;
@@ -2432,7 +2438,7 @@ void Search::predInterSearch(Mode& interMode, const
CUGeom& cuGeom, bool bChroma
                         int puX = puIdx & 1;
                         int puY = puIdx >> 1;
                         for (int planes = 0; planes < INTEGRAL_PLANE_NUM;
planes++)
-                            m_me.integral[planes] =
interMode.fencYuv->m_integral[list][ref][planes] + puX * pu.width + puY *
pu.height * m_slice->m_refFrameList[list][ref]->m_reconPic->m_stride;
+                            m_me.integral[planes] =
interMode.fencYuv->m_integral[list][ref][planes] + puX * pu.width + puY *
pu.height * m_slice->m_refFrameList[list][ref]->m_reconPic[0]->m_stride;
                     }
                     m_vertRestriction =
cu.m_slice->m_refPOCList[list][ref] == cu.m_slice->m_poc;
                     setSearchRange(cu, mvp, m_param->searchRange, mvmin,
mvmax);
@@ -2731,12 +2737,12 @@ int Search::intraBCSearchMVChromaRefine(Mode&
intraBCMode,

         for (uint32_t ch = TEXT_CHROMA_U; ch < MAX_NUM_COMPONENT; ch++)
         {
-            ref = m_slice->m_refFrameList[0][m_slice->m_numRefIdx[0] -
1]->m_reconPic->getChromaAddr(ch, cu.m_cuAddr, cu.m_absIdxInCTU +
partOffset);
+            ref = m_slice->m_refFrameList[0][m_slice->m_numRefIdx[0] -
1]->m_reconPic[1]->getChromaAddr(ch, cu.m_cuAddr, cu.m_absIdxInCTU +
partOffset);

             picOrg = intraBCMode.fencYuv->getChromaAddr(ch, partOffset);
             orgStride = intraBCMode.fencYuv->m_csize;

-            refStride = m_frame->m_reconPic->m_strideC;
+            refStride = m_frame->m_reconPic[1]->m_strideC;

             width = roiWidth >> m_hChromaShift;
             height = roiHeight >> m_vChromaShift;
@@ -3545,8 +3551,8 @@ void Search::intraBlockCopyEstimate(Mode&
intraBCMode, const CUGeom& cuGeom, int
     assert(nPSH == roiHeight);

     int ref = m_slice->m_numRefIdx[0] - 1;
-    pixel* refY =
m_slice->m_refFrameList[0][ref]->m_reconPic->getLumaAddr(cu.m_cuAddr,
cu.m_absIdxInCTU + partAddr);
-    int  strideY = m_slice->m_refFrameList[0][ref]->m_reconPic->m_stride;
+    pixel* refY =
m_slice->m_refFrameList[0][ref]->m_reconPic[1]->getLumaAddr(cu.m_cuAddr,
cu.m_absIdxInCTU + partAddr);
+    int  strideY =
m_slice->m_refFrameList[0][ref]->m_reconPic[1]->m_stride;

     setIntraSearchRange(intraBCMode, mvPred, puIdx, roiWidth, roiHeight,
searchRangeLT, searchRangeRB);

@@ -4769,6 +4775,9 @@ void Search::encodeResAndCalcRdInterCU(Mode&
interMode, const CUGeom& cuGeom)
     cu.m_distortion[0] = interMode.distortion;
     updateModeCost(interMode);
     checkDQP(interMode, cuGeom);
+
+    if (!!m_param->bEnableSCC)
+        interMode.reconYuv.copyToPicYuv(*m_frame->m_reconPic[1],
cu.m_cuAddr, cuGeom.absPartIdx);
 }

 void Search::residualTransformQuantInter(Mode& mode, const CUGeom& cuGeom,
uint32_t absPartIdx, uint32_t tuDepth, const uint32_t depthRange[2])
-- 
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240807/7a0053ab/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0005-Added-sao-deblock-and-temporal-mvp-support-and-disab.patch
Type: application/octet-stream
Size: 49054 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240807/7a0053ab/attachment-0001.obj>


More information about the x265-devel mailing list