From 74a2660897ea4a3a0bae71ae607bc6ddc049de40 Mon Sep 17 00:00:00 2001
From: jamesxxiu <xiaoyuxiu@kwai.com>
Date: Tue, 2 Apr 2019 10:03:53 -0700
Subject: [PATCH] JVET-N0334: MV Overflow Prevention

---
 source/Lib/CommonLib/ContextModelling.cpp | 11 +++++++
 source/Lib/CommonLib/InterPrediction.cpp  |  4 +++
 source/Lib/CommonLib/Mv.h                 | 13 ++++++++
 source/Lib/CommonLib/TypeDef.h            |  2 ++
 source/Lib/CommonLib/UnitTools.cpp        | 37 +++++++++++++++++++++++
 source/Lib/CommonLib/UnitTools.h          |  3 ++
 source/Lib/DecoderLib/DecCu.cpp           | 10 ++++++
 source/Lib/EncoderLib/EncCu.cpp           | 28 +++++++++++++++++
 8 files changed, 108 insertions(+)

diff --git a/source/Lib/CommonLib/ContextModelling.cpp b/source/Lib/CommonLib/ContextModelling.cpp
index 823198497..2a1eefb20 100644
--- a/source/Lib/CommonLib/ContextModelling.cpp
+++ b/source/Lib/CommonLib/ContextModelling.cpp
@@ -524,5 +524,16 @@ void MergeCtx::setMmvdMergeCandiInfo(PredictionUnit& pu, int candIdx)
 
   pu.cu->GBiIdx = (interDirNeighbours[fPosBaseIdx] == 3) ? GBiIdx[fPosBaseIdx] : GBI_DEFAULT;
 
+#if JVET_N0334_MVCLIPPING
+  for (int refList = 0; refList < 2; refList++)
+  {
+    if (pu.refIdx[refList] >= 0)
+    {
+      pu.mv[refList].clipToStorageBitDepth();
+    }
+  }
+#endif
+
+
   PU::restrictBiPredMergeCandsOne(pu);
 }
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 1967564ce..aea57502c 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -1767,6 +1767,10 @@ void InterPrediction::xProcessDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvDst, con
 
         subPu.mv[0] = mergeMv[REF_PIC_LIST_0] + pu.mvdL0SubPu[num];
         subPu.mv[1] = mergeMv[REF_PIC_LIST_1] - pu.mvdL0SubPu[num];
+#if JVET_N0334_MVCLIPPING
+        subPu.mv[0].clipToStorageBitDepth();
+        subPu.mv[1].clipToStorageBitDepth();
+#endif
         m_cYuvRefBuffSubCuDMVRL0 = m_cYuvRefBuffDMVRL0.subBuf(UnitAreaRelative(pu, subPu));
         m_cYuvRefBuffSubCuDMVRL1 = m_cYuvRefBuffDMVRL1.subBuf(UnitAreaRelative(pu, subPu));
         xFinalPaddedMCForDMVR(subPu, srcPred0, srcPred1, m_cYuvRefBuffSubCuDMVRL0, m_cYuvRefBuffSubCuDMVRL1, bioApplied, mergeMv);
diff --git a/source/Lib/CommonLib/Mv.h b/source/Lib/CommonLib/Mv.h
index 51d08d682..dcb77eb16 100644
--- a/source/Lib/CommonLib/Mv.h
+++ b/source/Lib/CommonLib/Mv.h
@@ -61,6 +61,10 @@ class Mv
 {
 private:
   static const MvPrecision m_amvrPrecision[3];
+#if JVET_N0334_MVCLIPPING
+  static const int mvClipPeriod = (1 << 18);
+  static const int halMvClipPeriod = (1 << 17);
+#endif
 
 public:
   int   hor;     ///< horizontal component of motion vector
@@ -213,6 +217,15 @@ public:
     hor = Clip3( -(1 << 17), (1 << 17) - 1, hor );
     ver = Clip3( -(1 << 17), (1 << 17) - 1, ver );
   }
+#if JVET_N0334_MVCLIPPING
+  void mvCliptoStorageBitDepth()  // periodic clipping
+  {
+    hor = (hor + mvClipPeriod) & (mvClipPeriod - 1);
+    hor = (hor >= halMvClipPeriod) ? (hor - mvClipPeriod) : hor;
+    ver = (ver + mvClipPeriod) & (mvClipPeriod - 1);
+    ver = (ver >= halMvClipPeriod) ? (ver - mvClipPeriod) : ver;
+  }
+#endif
 };// END CLASS DEFINITION MV
 
 namespace std
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 80270fd95..512a2540c 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,8 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_N0334_MVCLIPPING                             1  // prevention of MV stroage overflow and alignment with spec of MV/CPMV modular for AMVP mode
+
 #define JVET_N0477_LMCS_CLEANUP                           1
 #define JVET_N0220_LMCS_SIMPLIFICATION                    1
 
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 534ec8017..6ac8d767a 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -87,6 +87,10 @@ void CS::setRefinedMotionField(CodingStructure &cs)
             subPu.mv[1] = pu.mv[1];
             subPu.mv[REF_PIC_LIST_0] += pu.mvdL0SubPu[num];
             subPu.mv[REF_PIC_LIST_1] -= pu.mvdL0SubPu[num];
+#if JVET_N0334_MVCLIPPING
+            subPu.mv[REF_PIC_LIST_0].clipToStorageBitDepth();
+            subPu.mv[REF_PIC_LIST_1].clipToStorageBitDepth();
+#endif
             pu.mvdL0SubPu[num].setZero();
             num++;
             PU::spanMotionInfo(subPu);
@@ -3182,16 +3186,25 @@ void PU::getAffineControlPointCand( const PredictionUnit &pu, MotionInfo mi[4],
       case 1: // 1 : LT, RT, RB
         cMv[l][2].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][1].hor;
         cMv[l][2].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][1].ver;
+#if JVET_N0334_MVCLIPPING
+        cMv[l][2].clipToStorageBitDepth();
+#endif
         break;
 
       case 2: // 2 : LT, LB, RB
         cMv[l][1].hor = cMv[l][3].hor + cMv[l][0].hor - cMv[l][2].hor;
         cMv[l][1].ver = cMv[l][3].ver + cMv[l][0].ver - cMv[l][2].ver;
+#if JVET_N0334_MVCLIPPING
+        cMv[l][1].clipToStorageBitDepth();
+#endif
         break;
 
       case 3: // 3 : RT, LB, RB
         cMv[l][0].hor = cMv[l][1].hor + cMv[l][2].hor - cMv[l][3].hor;
         cMv[l][0].ver = cMv[l][1].ver + cMv[l][2].ver - cMv[l][3].ver;
+#if JVET_N0334_MVCLIPPING
+        cMv[l][0].clipToStorageBitDepth();
+#endif
         break;
 
       case 4: // 4 : LT, RT
@@ -3202,6 +3215,9 @@ void PU::getAffineControlPointCand( const PredictionUnit &pu, MotionInfo mi[4],
         vy = (cMv[l][0].ver << shift) - ((cMv[l][2].hor - cMv[l][0].hor) << shiftHtoW);
         roundAffineMv( vx, vy, shift );
         cMv[l][1].set( vx, vy );
+#if JVET_N0334_MVCLIPPING
+        cMv[l][1].clipToStorageBitDepth();
+#endif
         break;
 
       default:
@@ -3625,7 +3641,11 @@ void PU::setAllAffineMvField( PredictionUnit &pu, MvField *mvField, RefPicList e
   pu.refIdx[eRefList] = mvField[0].refIdx;
 }
 
+#if JVET_N0334_MVCLIPPING
+void PU::setAllAffineMv(PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList, bool setHighPrec, bool clipCPMVs)
+#else
 void PU::setAllAffineMv( PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList, bool setHighPrec)
+#endif
 {
   int width  = pu.Y().width;
   int shift = MAX_CU_DEPTH;
@@ -3635,6 +3655,17 @@ void PU::setAllAffineMv( PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPi
     affRT.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
     affLB.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
   }
+#if JVET_N0334_MVCLIPPING
+  if (clipCPMVs)
+  {
+    affLT.mvCliptoStorageBitDepth();
+    affRT.mvCliptoStorageBitDepth();
+    if (pu.cu->affineType == AFFINEMODEL_6PARAM)
+    {
+      affLB.mvCliptoStorageBitDepth();
+    }
+  }
+#endif
   int deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY;
   deltaMvHorX = (affRT - affLT).getHor() << (shift - g_aucLog2[width]);
   deltaMvHorY = (affRT - affLT).getVer() << (shift - g_aucLog2[width]);
@@ -4039,6 +4070,9 @@ void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interP
       pu.mvpIdx[0] = mvp_idx;
       pu.mv    [0] = amvpInfo.mvCand[mvp_idx] + pu.mvd[0];
       pu.mv[0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
+#if JVET_N0334_MVCLIPPING
+      pu.mv[0].mvCliptoStorageBitDepth();
+#endif
     }
 
     if (pu.interDir != 1 /* PRED_L0 */)
@@ -4054,6 +4088,9 @@ void PU::applyImv( PredictionUnit& pu, MergeCtx &mrgCtx, InterPrediction *interP
       pu.mvpIdx[1] = mvp_idx;
       pu.mv    [1] = amvpInfo.mvCand[mvp_idx] + pu.mvd[1];
       pu.mv[1].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
+#if JVET_N0334_MVCLIPPING
+      pu.mv[1].mvCliptoStorageBitDepth();
+#endif
     }
   }
   else
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 344bac8fb..c2c3387d6 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -160,6 +160,9 @@ namespace PU
   void setAllAffineMvField            (      PredictionUnit &pu, MvField *mvField, RefPicList eRefList );
   void setAllAffineMv                 (      PredictionUnit &pu, Mv affLT, Mv affRT, Mv affLB, RefPicList eRefList
     , bool setHighPrec = false
+#if JVET_N0334_MVCLIPPING
+    , bool clipCPMVs = false
+#endif
   );
   bool getInterMergeSubPuMvpCand(const PredictionUnit &pu, MergeCtx &mrgCtx, bool& LICFlag, const int count
     , int mmvdList
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 30ee7bbb1..d4b9c5863 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -745,7 +745,11 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
                   mvLB.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL );
                 }
               }
+#if JVET_N0334_MVCLIPPING
+              PU::setAllAffineMv(pu, mvLT, mvRT, mvLB, eRefList, false, true);
+#else
               PU::setAllAffineMv( pu, mvLT, mvRT, mvLB, eRefList );
+#endif
             }
           }
         }
@@ -761,6 +765,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
             mvd <<= 2;
           pu.mv[REF_PIC_LIST_0] = amvpInfo.mvCand[pu.mvpIdx[REF_PIC_LIST_0]] + mvd;
           pu.mv[REF_PIC_LIST_0].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
+#if JVET_N0334_MVCLIPPING
+          pu.mv[REF_PIC_LIST_0].mvCliptoStorageBitDepth();
+#endif
         }
         else
         {
@@ -774,6 +781,9 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
               pu.mvpNum [eRefList] = amvpInfo.numCand;
               pu.mv[eRefList] = amvpInfo.mvCand[pu.mvpIdx[eRefList]] + pu.mvd[eRefList];
               pu.mv[eRefList].changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
+#if JVET_N0334_MVCLIPPING
+              pu.mv[eRefList].mvCliptoStorageBitDepth();
+#endif
             }
           }
         }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 51f0e9386..7b78b3708 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -3784,6 +3784,34 @@ void EncCu::xEncodeInterResidual(   CodingStructure *&tempCS
       }
     }
   }
+#if JVET_N0334_MVCLIPPING
+  // avoid MV exceeding 18-bit dynamic range
+  const int maxMv = 1 << 17;
+  if (!cu->affine && !pu.mergeFlag)
+  {
+    if ( (pu.refIdx[0] >= 0 && (pu.mv[0].getAbsHor() >= maxMv || pu.mv[0].getAbsVer() >= maxMv))
+      || (pu.refIdx[1] >= 0 && (pu.mv[1].getAbsHor() >= maxMv || pu.mv[1].getAbsVer() >= maxMv)))
+    {
+      return;
+    }
+  }
+  if (cu->affine && !pu.mergeFlag)
+  {
+    for (int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
+    {
+      if (pu.refIdx[refList] >= 0)
+      {
+        for (int ctrlP = 1 + (cu->affineType == AFFINEMODEL_6PARAM); ctrlP >= 0; ctrlP--)
+        {
+          if (pu.mvAffi[refList][ctrlP].getAbsHor() >= maxMv || pu.mvAffi[refList][ctrlP].getAbsVer() >= maxMv)
+          {
+            return;
+          }
+        }
+      }
+    }
+  }
+#endif
   const bool mtsAllowed = tempCS->sps->getUseInterMTS() && CU::isInter( *cu ) && partitioner.currArea().lwidth() <= MTS_INTER_MAX_CU_SIZE && partitioner.currArea().lheight() <= MTS_INTER_MAX_CU_SIZE;
   uint8_t sbtAllowed = cu->checkAllowedSbt();
   uint8_t numRDOTried = 0;
-- 
GitLab