[x265] [PATCH MV-HEVC 06/10] Fix hash mismatch and temporal mvp issue

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


>From 9d58aa88fc522dede32a12cc5a66342a0c3ee298 Mon Sep 17 00:00:00 2001
From: AnusuyaKumarasamy <anusuya.kumarasamy at multicorewareinc.com>
Date: Fri, 12 Jul 2024 16:28:14 +0530
Subject: [PATCH] Fix hash mismatch and temporal mvp issue

---
 source/common/cudata.cpp    | 165 +++++++++++++++++++++++++++++-------
 source/common/cudata.h      |   4 +-
 source/encoder/analysis.cpp |   2 +-
 source/encoder/dpb.cpp      |  24 +++++-
 source/encoder/search.cpp   |   6 +-
 5 files changed, 165 insertions(+), 36 deletions(-)

diff --git a/source/common/cudata.cpp b/source/common/cudata.cpp
index 19281dee2..baa9be476 100644
--- a/source/common/cudata.cpp
+++ b/source/common/cudata.cpp
@@ -1712,28 +1712,61 @@ uint32_t CUData::getInterMergeCandidates(uint32_t
absPartIdx, uint32_t puIdx, MV
 }

 // Create the PMV list. Called for each reference index.
-int CUData::getPMV(InterNeighbourMV *neighbours, uint32_t picList,
uint32_t refIdx, MV* amvpCand, MV* pmv) const
+int CUData::getPMV(InterNeighbourMV* neighbours, uint32_t picList,
uint32_t refIdx, MV* amvpCand, MV* pmv, uint32_t puIdx, uint32_t
absPartIdx) const
 {
     MV directMV[MD_ABOVE_LEFT + 1];
     MV indirectMV[MD_ABOVE_LEFT + 1];
     bool validDirect[MD_ABOVE_LEFT + 1];
     bool validIndirect[MD_ABOVE_LEFT + 1];

-    // Left candidate.
-    validDirect[MD_BELOW_LEFT]  = getDirectPMV(directMV[MD_BELOW_LEFT],
neighbours + MD_BELOW_LEFT, picList, refIdx);
-    validDirect[MD_LEFT]        = getDirectPMV(directMV[MD_LEFT],
neighbours + MD_LEFT, picList, refIdx);
-    // Top candidate.
-    validDirect[MD_ABOVE_RIGHT] = getDirectPMV(directMV[MD_ABOVE_RIGHT],
neighbours + MD_ABOVE_RIGHT, picList, refIdx);
-    validDirect[MD_ABOVE]       = getDirectPMV(directMV[MD_ABOVE],
neighbours + MD_ABOVE, picList, refIdx);
-    validDirect[MD_ABOVE_LEFT]  = getDirectPMV(directMV[MD_ABOVE_LEFT],
neighbours + MD_ABOVE_LEFT, picList, refIdx);
-
-    // Left candidate.
-    validIndirect[MD_BELOW_LEFT]  =
getIndirectPMV(indirectMV[MD_BELOW_LEFT], neighbours + MD_BELOW_LEFT,
picList, refIdx);
-    validIndirect[MD_LEFT]        = getIndirectPMV(indirectMV[MD_LEFT],
neighbours + MD_LEFT, picList, refIdx);
-    // Top candidate.
-    validIndirect[MD_ABOVE_RIGHT] =
getIndirectPMV(indirectMV[MD_ABOVE_RIGHT], neighbours + MD_ABOVE_RIGHT,
picList, refIdx);
-    validIndirect[MD_ABOVE]       = getIndirectPMV(indirectMV[MD_ABOVE],
neighbours + MD_ABOVE, picList, refIdx);
-    validIndirect[MD_ABOVE_LEFT]  =
getIndirectPMV(indirectMV[MD_ABOVE_LEFT], neighbours + MD_ABOVE_LEFT,
picList, refIdx);
+#if ENABLE_MULTIVIEW
+    if (m_slice->m_param->numViews > 1)
+    {
+        // Left candidate.
+        if ((neighbours + MD_BELOW_LEFT)->isAvailable || (neighbours +
MD_LEFT)->isAvailable)
+        {
+            validIndirect[MD_ABOVE_RIGHT] = validIndirect[MD_ABOVE] =
validIndirect[MD_ABOVE_LEFT] = false;
+
+            validDirect[MD_BELOW_LEFT] =
getDirectPMV(directMV[MD_BELOW_LEFT], neighbours + MD_BELOW_LEFT, picList,
refIdx);
+            validDirect[MD_LEFT] = getDirectPMV(directMV[MD_LEFT],
neighbours + MD_LEFT, picList, refIdx);
+
+            validIndirect[MD_BELOW_LEFT] =
getIndirectPMV(indirectMV[MD_BELOW_LEFT], neighbours + MD_BELOW_LEFT,
picList, refIdx);
+            validIndirect[MD_LEFT] = getIndirectPMV(indirectMV[MD_LEFT],
neighbours + MD_LEFT, picList, refIdx);
+        }
+
+        // Top candidate.
+        validDirect[MD_ABOVE_RIGHT] =
getDirectPMV(directMV[MD_ABOVE_RIGHT], neighbours + MD_ABOVE_RIGHT,
picList, refIdx);
+        validDirect[MD_ABOVE] = getDirectPMV(directMV[MD_ABOVE],
neighbours + MD_ABOVE, picList, refIdx);
+        validDirect[MD_ABOVE_LEFT] = getDirectPMV(directMV[MD_ABOVE_LEFT],
neighbours + MD_ABOVE_LEFT, picList, refIdx);
+
+        // Top candidate.
+        if (!((neighbours + MD_BELOW_LEFT)->isAvailable || (neighbours +
MD_LEFT)->isAvailable))
+        {
+            validDirect[MD_BELOW_LEFT] = validDirect[MD_LEFT] =
validIndirect[MD_BELOW_LEFT] = validIndirect[MD_LEFT] = false;
+            validIndirect[MD_ABOVE_RIGHT] =
getIndirectPMV(indirectMV[MD_ABOVE_RIGHT], neighbours + MD_ABOVE_RIGHT,
picList, refIdx);
+            validIndirect[MD_ABOVE] = getIndirectPMV(indirectMV[MD_ABOVE],
neighbours + MD_ABOVE, picList, refIdx);
+            validIndirect[MD_ABOVE_LEFT] =
getIndirectPMV(indirectMV[MD_ABOVE_LEFT], neighbours + MD_ABOVE_LEFT,
picList, refIdx);
+        }
+    }
+    else
+#endif
+    {
+        // Left candidate.
+        validDirect[MD_BELOW_LEFT] = getDirectPMV(directMV[MD_BELOW_LEFT],
neighbours + MD_BELOW_LEFT, picList, refIdx);
+        validDirect[MD_LEFT] = getDirectPMV(directMV[MD_LEFT], neighbours
+ MD_LEFT, picList, refIdx);
+        // Top candidate.
+        validDirect[MD_ABOVE_RIGHT] =
getDirectPMV(directMV[MD_ABOVE_RIGHT], neighbours + MD_ABOVE_RIGHT,
picList, refIdx);
+        validDirect[MD_ABOVE] = getDirectPMV(directMV[MD_ABOVE],
neighbours + MD_ABOVE, picList, refIdx);
+        validDirect[MD_ABOVE_LEFT] = getDirectPMV(directMV[MD_ABOVE_LEFT],
neighbours + MD_ABOVE_LEFT, picList, refIdx);
+
+        // Left candidate.
+        validIndirect[MD_BELOW_LEFT] =
getIndirectPMV(indirectMV[MD_BELOW_LEFT], neighbours + MD_BELOW_LEFT,
picList, refIdx);
+        validIndirect[MD_LEFT] = getIndirectPMV(indirectMV[MD_LEFT],
neighbours + MD_LEFT, picList, refIdx);
+        // Top candidate.
+        validIndirect[MD_ABOVE_RIGHT] =
getIndirectPMV(indirectMV[MD_ABOVE_RIGHT], neighbours + MD_ABOVE_RIGHT,
picList, refIdx);
+        validIndirect[MD_ABOVE] = getIndirectPMV(indirectMV[MD_ABOVE],
neighbours + MD_ABOVE, picList, refIdx);
+        validIndirect[MD_ABOVE_LEFT] =
getIndirectPMV(indirectMV[MD_ABOVE_LEFT], neighbours + MD_ABOVE_LEFT,
picList, refIdx);
+    }

     int num = 0;
     // Left predictor search
@@ -1781,22 +1814,75 @@ 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 (m_slice->m_sps->bTemporalMVPEnabled && num < 2)
+#if ENABLE_MULTIVIEW
+    if (m_slice->m_param->numViews > 1)
+    {
+        if (m_slice->m_sps->bTemporalMVPEnabled && num < 2)
+        {
+            int refId = refIdx;
+            uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;
+            uint32_t partIdxRB = deriveRightBottomIdx(puIdx);
+            bool isValid;
+
+            // co-located RightBottom temporal predictor (H)
+            int ctuIdx = -1;
+
+            // image boundary check
+            if (m_encData->getPicCTU(m_cuAddr)->m_cuPelX +
g_zscanToPelX[partIdxRB] + UNIT_SIZE <
m_slice->m_sps->picWidthInLumaSamples &&
+                m_encData->getPicCTU(m_cuAddr)->m_cuPelY +
g_zscanToPelY[partIdxRB] + UNIT_SIZE <
m_slice->m_sps->picHeightInLumaSamples)
+            {
+                uint32_t absPartIdxRB = g_zscanToRaster[partIdxRB];
+                uint32_t numUnits = s_numPartInCUSize;
+                bool bNotLastCol = lessThanCol(absPartIdxRB, numUnits -
1); // is not at the last column of CTU
+                bool bNotLastRow = lessThanRow(absPartIdxRB, numUnits -
1); // is not at the last row    of CTU
+
+                if (bNotLastCol && bNotLastRow)
+                {
+                    absPartAddr = g_rasterToZscan[absPartIdxRB +
RASTER_SIZE + 1];
+                    ctuIdx = m_cuAddr;
+                }
+                else if (bNotLastCol)
+                    absPartAddr = g_rasterToZscan[(absPartIdxRB + 1) &
(numUnits - 1)];
+                else if (bNotLastRow)
+                {
+                    absPartAddr = g_rasterToZscan[absPartIdxRB +
RASTER_SIZE - numUnits + 1];
+                    ctuIdx = m_cuAddr + 1;
+                }
+                else // is the right bottom corner of CTU
+                    absPartAddr = 0;
+            }
+            if (ctuIdx >= 0 &&
getColMVP(neighbours[MD_COLLOCATED].mv[picList], refId, picList, ctuIdx,
absPartAddr))
+                pmv[numMvc++] = amvpCand[num++] =
neighbours[MD_COLLOCATED].mv[picList];
+            else
+            {
+                uint32_t partIdxCenter = deriveCenterIdx(puIdx);
+                uint32_t curCTUIdx = m_cuAddr;
+                if (getColMVP(neighbours[MD_COLLOCATED].mv[picList],
refId, picList, curCTUIdx, partIdxCenter))
+                    pmv[numMvc++] = amvpCand[num++] =
neighbours[MD_COLLOCATED].mv[picList];
+            }
+        }
+    }
+    else
+#endif
     {
-        int tempRefIdx = neighbours[MD_COLLOCATED].refIdx[picList];
-        if (tempRefIdx != -1)
+        if (m_slice->m_sps->bTemporalMVPEnabled && num < 2)
         {
-            uint32_t cuAddr = neighbours[MD_COLLOCATED].cuAddr[picList];
-            const Frame* colPic =
m_slice->m_refFrameList[m_slice->isInterB() &&
!m_slice->m_colFromL0Flag][m_slice->m_colRefIdx];
-            const CUData* colCU = colPic->m_encData->getPicCTU(cuAddr);
+            int tempRefIdx = neighbours[MD_COLLOCATED].refIdx[picList];
+            if (tempRefIdx != -1)
+            {
+                uint32_t cuAddr =
neighbours[MD_COLLOCATED].cuAddr[picList];
+                const Frame* colPic =
m_slice->m_refFrameList[m_slice->isInterB() &&
!m_slice->m_colFromL0Flag][m_slice->m_colRefIdx];
+                const CUData* colCU = colPic->m_encData->getPicCTU(cuAddr);

-            // Scale the vector
-            int colRefPOC = colCU->m_slice->m_refPOCList[tempRefIdx >>
4][tempRefIdx & 0xf];
-            int colPOC = colCU->m_slice->m_poc;
+                // Scale the vector
+                int colRefPOC = colCU->m_slice->m_refPOCList[tempRefIdx >>
4][tempRefIdx & 0xf];
+                int colPOC = colCU->m_slice->m_poc;

-            int curRefPOC = m_slice->m_refPOCList[picList][refIdx];
-            int curPOC = m_slice->m_poc;
-            pmv[numMvc++] = amvpCand[num++] =
scaleMvByPOCDist(neighbours[MD_COLLOCATED].mv[picList], curPOC, curRefPOC,
colPOC, colRefPOC);
+                int curRefPOC = m_slice->m_refPOCList[picList][refIdx];
+                int curPOC = m_slice->m_poc;
+
+                pmv[numMvc++] = amvpCand[num++] =
scaleMvByPOCDist(neighbours[MD_COLLOCATED].mv[picList], curPOC, curRefPOC,
colPOC, colRefPOC);
+            }
         }
     }

@@ -1822,7 +1908,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)
+    if (m_slice->m_sps->bTemporalMVPEnabled &&
!(m_slice->m_param->numViews > 1))
     {
         uint32_t absPartAddr = m_absIdxInCTU + absPartIdx;
         uint32_t partIdxRB = deriveRightBottomIdx(puIdx);
@@ -1895,6 +1981,7 @@ void CUData::getInterNeighbourMV(InterNeighbourMV
*neighbour, uint32_t partUnitI
         // Mark the PMV as unavailable.
         for (int i = 0; i < 2; i++)
             neighbour->refIdx[i] = -1;
+        neighbour->isAvailable = (tmpCU != NULL) && (tmpCU->isInter(idx));
         return;
     }

@@ -1905,6 +1992,7 @@ void CUData::getInterNeighbourMV(InterNeighbourMV
*neighbour, uint32_t partUnitI

         // Get the reference idx.
         neighbour->refIdx[i] = tmpCU->m_refIdx[i][idx];
+        neighbour->isAvailable = (tmpCU != NULL) && (tmpCU->isInter(idx));
     }
 }

@@ -1958,8 +2046,18 @@ bool CUData::getIndirectPMV(MV& outMV,
InterNeighbourMV *neighbours, uint32_t pi
             int neibRefPOC = m_slice->m_refPOCList[picList][partRefIdx];
             MV mvp = neighbours->mv[picList];

+#if ENABLE_MULTIVIEW
+            if ((curRefPOC == curPOC) == (neibRefPOC == curPOC))
+            {
+                if (curRefPOC == curPOC)
+                    outMV = mvp;
+                if (!(curRefPOC == curPOC))
+                    outMV = scaleMvByPOCDist(mvp, curPOC, curRefPOC,
neibPOC, neibRefPOC);
+#else
             outMV = scaleMvByPOCDist(mvp, curPOC, curRefPOC, neibPOC,
neibRefPOC);
+#endif
             return true;
+            }
         }
     }
     return false;
@@ -1995,7 +2093,16 @@ bool CUData::getColMVP(MV& outMV, int& outRefIdx,
int picList, int cuAddr, int p
     int curRefPOC = m_slice->m_refPOCList[picList][outRefIdx];
     int curPOC = m_slice->m_poc;

+#if ENABLE_MULTIVIEW
+    if ((colPOC == colRefPOC) != (curPOC == curRefPOC))
+        return false;
+    else if (curRefPOC == curPOC)
+        outMV = colmv;
+    else if (!(curRefPOC == curPOC))
+        outMV = scaleMvByPOCDist(colmv, curPOC, curRefPOC, colPOC,
colRefPOC);
+#else
     outMV = scaleMvByPOCDist(colmv, curPOC, curRefPOC, colPOC, colRefPOC);
+#endif;
     return true;
 }

diff --git a/source/common/cudata.h b/source/common/cudata.h
index 8397f0568..404e95714 100644
--- a/source/common/cudata.h
+++ b/source/common/cudata.h
@@ -107,6 +107,8 @@ struct InterNeighbourMV
     // Collocated right bottom CU addr.
     uint32_t cuAddr[2];

+    bool isAvailable;
+
     // For spatial prediction, this field contains the reference index
     // in each list (-1 if not available).
     //
@@ -272,7 +274,7 @@ public:
     int8_t   getRefQP(uint32_t currAbsIdxInCTU) const;
     uint32_t getInterMergeCandidates(uint32_t absPartIdx, uint32_t puIdx,
MVField (*candMvField)[2], uint8_t* candDir) const;
     void     clipMv(MV& outMV) const;
-    int      getPMV(InterNeighbourMV *neighbours, uint32_t reference_list,
uint32_t refIdx, MV* amvpCand, MV* pmv) const;
+    int      getPMV(InterNeighbourMV* neighbours, uint32_t reference_list,
uint32_t refIdx, MV* amvpCand, MV* pmv, uint32_t puIdx = 0, uint32_t
absPartIdx = 0) const;
     void     getNeighbourMV(uint32_t puIdx, uint32_t absPartIdx,
InterNeighbourMV* neighbours) const;
     void     getIntraTUQtDepthRange(uint32_t tuDepthRange[2], uint32_t
absPartIdx) const;
     void     getInterTUQtDepthRange(uint32_t tuDepthRange[2], uint32_t
absPartIdx) const;
diff --git a/source/encoder/analysis.cpp b/source/encoder/analysis.cpp
index aabf386ca..1f1984707 100644
--- a/source/encoder/analysis.cpp
+++ b/source/encoder/analysis.cpp
@@ -2501,7 +2501,7 @@ void Analysis::recodeCU(const CUData& parentCTU,
const CUGeom& cuGeom, int32_t q
                                 continue;
                             MV mvp;

-                            int numMvc =
mode.cu.getPMV(mode.interNeighbours, list, ref, mode.amvpCand[list][ref],
mvc);
+                            int numMvc =
mode.cu.getPMV(mode.interNeighbours, list, ref, mode.amvpCand[list][ref],
mvc, part, pu.puAbsPartIdx);
                             mvp =
mode.amvpCand[list][ref][mode.cu.m_mvpIdx[list][pu.puAbsPartIdx]];
                             if (m_param->interRefine == 1)
                             {
diff --git a/source/encoder/dpb.cpp b/source/encoder/dpb.cpp
index 3b4934df5..a187e6657 100644
--- a/source/encoder/dpb.cpp
+++ b/source/encoder/dpb.cpp
@@ -287,9 +287,29 @@ void DPB::prepareEncode(Frame *newFrame)
         /* TODO: the lookahead should be able to tell which reference
picture
          * had the least motion residual.  We should be able to use that
here to
          * select a colocation reference list and index */
-        slice->m_colFromL0Flag = false;
+
+        bool bLowDelay = true;
+        int  iCurrPOC = slice->m_poc;
+        int iRefIdx = 0;
+
+        for (iRefIdx = 0; iRefIdx < slice->m_numRefIdx[0] && bLowDelay;
iRefIdx++)
+        {
+            if (slice->m_refPOCList[0][iRefIdx] > iCurrPOC)
+            {
+                bLowDelay = false;
+            }
+        }
+        for (iRefIdx = 0; iRefIdx < slice->m_numRefIdx[1] && bLowDelay;
iRefIdx++)
+        {
+            if (slice->m_refPOCList[1][iRefIdx] > iCurrPOC)
+            {
+                bLowDelay = false;
+            }
+        }
+
+        slice->m_bCheckLDC = bLowDelay;
+        slice->m_colFromL0Flag = bLowDelay;
         slice->m_colRefIdx = 0;
-        slice->m_bCheckLDC = false;
     }
     else
     {
diff --git a/source/encoder/search.cpp b/source/encoder/search.cpp
index 3218f4a24..9dc5f90c5 100644
--- a/source/encoder/search.cpp
+++ b/source/encoder/search.cpp
@@ -2092,7 +2092,7 @@ void Search::singleMotionEstimation(Search& master,
Mode& interMode, const Predi

     // 12 mv candidates including lowresMV
     MV  mvc[(MD_ABOVE_LEFT + 1) * 2 + 2];
-    int numMvc = interMode.cu.getPMV(interMode.interNeighbours, list, ref,
interMode.amvpCand[list][ref], mvc);
+    int numMvc = interMode.cu.getPMV(interMode.interNeighbours, list, ref,
interMode.amvpCand[list][ref], mvc, 0, pu.puAbsPartIdx);

     const MV* amvp = interMode.amvpCand[list][ref];
     int mvpIdx = selectMVP(interMode.cu, pu, amvp, list, ref);
@@ -2246,7 +2246,7 @@ void Search::predInterSearch(Mode& interMode, const
CUGeom& cuGeom, bool bChroma
                 uint32_t bits = m_listSelBits[list] + MVP_IDX_BITS;
                 bits += getTUBits(ref, numRefIdx[list]);

-                int numMvc = cu.getPMV(interMode.interNeighbours, list,
ref, interMode.amvpCand[list][ref], mvc);
+                int numMvc = cu.getPMV(interMode.interNeighbours, list,
ref, interMode.amvpCand[list][ref], mvc, puIdx, pu.puAbsPartIdx);
                 const MV* amvp = interMode.amvpCand[list][ref];
                 int mvpIdx = selectMVP(cu, pu, amvp, list, ref);
                 MV mvmin, mvmax, outmv, mvp;
@@ -2404,7 +2404,7 @@ void Search::predInterSearch(Mode& interMode, const
CUGeom& cuGeom, bool bChroma
                     uint32_t bits = m_listSelBits[list] + MVP_IDX_BITS;
                     bits += getTUBits(ref, numRefIdx[list]);

-                    int numMvc = cu.getPMV(interMode.interNeighbours,
list, ref, interMode.amvpCand[list][ref], mvc);
+                    int numMvc = cu.getPMV(interMode.interNeighbours,
list, ref, interMode.amvpCand[list][ref], mvc, puIdx, pu.puAbsPartIdx);

                     const MV* amvp = interMode.amvpCand[list][ref];
                     int mvpIdx = selectMVP(cu, pu, amvp, list, ref);
-- 
2.36.0.windows.1
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/cfa7db82/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0006-Fix-hash-mismatch-and-temporal-mvp-issue.patch
Type: application/x-patch
Size: 18046 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240806/cfa7db82/attachment-0001.bin>


More information about the x265-devel mailing list