From beb39fd3530e03a4b1e7b5275f95b4ed2112f265 Mon Sep 17 00:00:00 2001
From: Philippe Hanhart <philippe.hanhart@interdigital.com>
Date: Wed, 28 Nov 2018 11:23:16 -0800
Subject: [PATCH] JVET-L0231 Horizontal wrap-around motion compensation for
 inter prediction

---
 source/App/EncoderApp/EncApp.cpp         |   5 ++
 source/App/EncoderApp/EncAppCfg.cpp      |  23 +++++
 source/App/EncoderApp/EncAppCfg.h        |   5 ++
 source/Lib/CommonLib/InterPrediction.cpp |  57 +++++++++++--
 source/Lib/CommonLib/Mv.cpp              |  17 +++-
 source/Lib/CommonLib/Mv.h                |   6 +-
 source/Lib/CommonLib/Picture.cpp         |  30 +++++--
 source/Lib/CommonLib/Slice.cpp           |   4 +
 source/Lib/CommonLib/Slice.h             |  11 +++
 source/Lib/CommonLib/TypeDef.h           |   2 +
 source/Lib/DecoderLib/VLCReader.cpp      |   8 ++
 source/Lib/EncoderLib/EncCfg.h           |  12 +++
 source/Lib/EncoderLib/EncLib.cpp         |   5 ++
 source/Lib/EncoderLib/InterSearch.cpp    | 102 +++++++++++++++++++----
 source/Lib/EncoderLib/VLCWriter.cpp      |   8 ++
 15 files changed, 264 insertions(+), 31 deletions(-)

diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index f48428987..d4857b50d 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -275,6 +275,11 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setCPRFastMethod                                     ( m_CPRFastMethod );
 #endif    
 
+#if JVET_L0231_WRAPAROUND
+  m_cEncLib.setUseWraparound                                     ( m_Wraparound );
+  m_cEncLib.setWraparoundOffset                                  ( m_WraparoundOffset );
+#endif
+
   // ADD_NEW_TOOL : (encoder app) add setting of tool enabling flags and associated parameters here
 
   m_cEncLib.setMaxCUWidth                                        ( m_uiCTUSize );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 89356829f..924bdb3d9 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -879,6 +879,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ( "CPRFastMethod",                                  m_CPRFastMethod,                                     6u, "Fast methods for CPR")
 #endif
 
+#if JVET_L0231_WRAPAROUND
+  ("Wraparound",                                      m_Wraparound,                                     false, "Enable horizontal wrap-around motion compensation for inter prediction (0:off, 1:on)  [default: off]")
+  ("WraparoundOffset",                                m_WraparoundOffset,                                  0u, "Offset in luma samples used for computing the horizontal wrap-around position")
+#endif
+
   // ADD_NEW_TOOL : (encoder app) add parsing parameters here
 
   ("LCTUFast",                                        m_useFastLCTU,                                    false, "Fast methods for large CTU")
@@ -1959,6 +1964,9 @@ bool EncAppCfg::xCheckParameter()
 #endif
 #if JVET_L0124_L0208_TRIANGLE
     xConfirmPara( m_Triangle, "Triangle is only allowed with NEXT profile" );
+#endif
+#if JVET_L0231_WRAPAROUND
+    xConfirmPara( m_Wraparound, "Horizontal wrap-around motion compensation for inter prediction is only allowed with NEXT profile" );
 #endif
     // ADD_NEW_TOOL : (parameter check) add a check for next tools here
   }
@@ -1983,6 +1991,14 @@ bool EncAppCfg::xCheckParameter()
     xConfirmPara(m_Affine && !m_highPrecisionMv, "Affine is not yet implemented for HighPrecMv off.");
 #endif
 
+#if JVET_L0231_WRAPAROUND
+    if( m_Wraparound )
+    {
+      xConfirmPara(m_WraparoundOffset == 0, "Wrap-around offset must be greater than 0");
+      xConfirmPara(m_WraparoundOffset > m_iSourceWidth, "Wrap-around offset must not be greater than the source picture width");
+      xConfirmPara(m_WraparoundOffset % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Wrap-around offset must be an integer multiple of the specified chroma subsampling");
+    }
+#endif
   }
 
 #if ENABLE_SPLIT_PARALLELISM
@@ -3164,6 +3180,13 @@ void EncAppCfg::xPrintParameter()
   }
 #if JVET_L0293_CPR
     msg(VERBOSE, "CPR:%d ", m_CPRMode);
+#endif
+#if JVET_L0231_WRAPAROUND
+  msg( VERBOSE, "Wraparound:%d ", m_Wraparound);
+  if( m_Wraparound )
+  {
+    msg( VERBOSE, "WraparoundOffset:%d ", m_WraparoundOffset );
+  }
 #endif
   // ADD_NEW_TOOL (add some output indicating the usage of tools)
 
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index bd140d91d..226a9369a 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -257,6 +257,11 @@ protected:
   unsigned  m_CPRFastMethod;
 #endif    
   
+#if JVET_L0231_WRAPAROUND
+  bool      m_Wraparound;
+  unsigned  m_WraparoundOffset;
+#endif
+
   // ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here
 
   unsigned  m_uiMaxCUWidth;                                   ///< max. CU width in pixel
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 959ba16d6..e57de7d12 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -460,7 +460,11 @@ void InterPrediction::xPredInterUni(const PredictionUnit& pu, const RefPicList&
     mv[0] = pu.mv[eRefPicList];
   }
   if ( !pu.cu->affine )
-  clipMv(mv[0], pu.cu->lumaPos(), sps);
+  clipMv(mv[0], pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+         pu.cu->lumaSize(),
+#endif
+         sps);
 
 
   for( uint32_t comp = COMPONENT_Y; comp < pcYuvPred.bufs.size() && comp <= m_maxCompIDToPred; comp++ )
@@ -727,7 +731,11 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio
     )
   {
     Mv mvTemp = _mv[0];
-    clipMv( mvTemp, pu.cu->lumaPos(), *pu.cs->sps );
+    clipMv( mvTemp, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+            pu.cu->lumaSize(),
+#endif
+            *pu.cs->sps );
     xPredInterBlk( compID, pu, refPic, mvTemp, dstPic, bi, clpRng
 #if JVET_L0256_BIO
                   , false
@@ -822,10 +830,25 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio
         roundAffineMv(iMvScaleTmpHor, iMvScaleTmpVer, shift);
 
         // clip and scale
-        iMvScaleTmpHor = std::min<int>(iHorMax, std::max<int>(iHorMin, iMvScaleTmpHor));
-        iMvScaleTmpVer = std::min<int>(iVerMax, std::max<int>(iVerMin, iMvScaleTmpVer));
+#if JVET_L0231_WRAPAROUND
+        if (sps.getSpsNext().getUseWraparound())
+        {
+          m_storedMv[h / AFFINE_MIN_BLOCK_SIZE * MVBUFFER_SIZE + w / AFFINE_MIN_BLOCK_SIZE].set(iMvScaleTmpHor, iMvScaleTmpVer);
+          Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
+          clipMv(tmpMv, Position(pu.Y().x + w, pu.Y().y + h), Size(blockWidth, blockHeight), sps);
+          iMvScaleTmpHor = tmpMv.getHor();
+          iMvScaleTmpVer = tmpMv.getVer();
+        }
+        else
+        {
+#endif
+          iMvScaleTmpHor = std::min<int>(iHorMax, std::max<int>(iHorMin, iMvScaleTmpHor));
+          iMvScaleTmpVer = std::min<int>(iVerMax, std::max<int>(iVerMin, iMvScaleTmpVer));
 
-        m_storedMv[h / AFFINE_MIN_BLOCK_SIZE * MVBUFFER_SIZE + w / AFFINE_MIN_BLOCK_SIZE].set(iMvScaleTmpHor, iMvScaleTmpVer);
+          m_storedMv[h / AFFINE_MIN_BLOCK_SIZE * MVBUFFER_SIZE + w / AFFINE_MIN_BLOCK_SIZE].set(iMvScaleTmpHor, iMvScaleTmpVer);
+#if JVET_L0231_WRAPAROUND
+        }
+#endif
       }
       else
       {
@@ -835,6 +858,12 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio
           m_storedMv[((h << iScaleY) / AFFINE_MIN_BLOCK_SIZE + 1)* MVBUFFER_SIZE + ((w << iScaleX) / AFFINE_MIN_BLOCK_SIZE + 1)] +
           Mv(2, 2));
         curMv.set(curMv.getHor() >> 2, curMv.getVer() >> 2);     
+#if JVET_L0231_WRAPAROUND
+        if (sps.getSpsNext().getUseWraparound())
+        {
+          clipMv(curMv, Position(pu.Y().x + (w << iScaleX), pu.Y().y + (h << iScaleY)), Size(blockWidth << iScaleX, blockHeight << iScaleY), sps);
+        }
+#endif
         iMvScaleTmpHor = curMv.hor;
         iMvScaleTmpVer = curMv.ver;
       }
@@ -844,8 +873,22 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio
       roundAffineMv( iMvScaleTmpHor, iMvScaleTmpVer, shift );
 
       // clip and scale
-      iMvScaleTmpHor = std::min<int>( iHorMax, std::max<int>( iHorMin, iMvScaleTmpHor ) );
-      iMvScaleTmpVer = std::min<int>( iVerMax, std::max<int>( iVerMin, iMvScaleTmpVer ) );
+#if JVET_L0231_WRAPAROUND
+      if (sps.getSpsNext().getUseWraparound())
+      {
+        Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
+        clipMv(tmpMv, Position(pu.Y().x + (w << iScaleX), pu.Y().y + (h << iScaleY)), Size(blockWidth << iScaleX, blockHeight << iScaleY), sps);
+        iMvScaleTmpHor = tmpMv.getHor();
+        iMvScaleTmpVer = tmpMv.getVer();
+      }
+      else
+      {
+#endif
+        iMvScaleTmpHor = std::min<int>( iHorMax, std::max<int>( iHorMin, iMvScaleTmpHor ) );
+        iMvScaleTmpVer = std::min<int>( iVerMax, std::max<int>( iVerMin, iMvScaleTmpVer ) );
+#if JVET_L0231_WRAPAROUND
+      }
+#endif
 #endif
       // get the MV in high precision
       int xFrac, yFrac, xInt, yInt;
diff --git a/source/Lib/CommonLib/Mv.cpp b/source/Lib/CommonLib/Mv.cpp
index 6e91ad386..aa46498ad 100644
--- a/source/Lib/CommonLib/Mv.cpp
+++ b/source/Lib/CommonLib/Mv.cpp
@@ -63,7 +63,11 @@ void roundAffineMv( int& mvx, int& mvy, int nShift )
   mvy = mvy >= 0 ? (mvy + nOffset) >> nShift : -((-mvy + nOffset) >> nShift);
 }
 
-void clipMv( Mv& rcMv, const Position& pos, const SPS& sps )
+void clipMv( Mv& rcMv, const Position& pos,
+#if JVET_L0231_WRAPAROUND
+             const struct Size& size,
+#endif
+             const SPS& sps )
 {
 #if !REMOVE_MV_ADAPT_PREC
   int iMvShift = 2 + (rcMv.highPrec ? VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE : 0);
@@ -80,6 +84,17 @@ void clipMv( Mv& rcMv, const Position& pos, const SPS& sps )
   int iVerMax = ( sps.getPicHeightInLumaSamples() + iOffset - ( int ) pos.y - 1 ) << iMvShift;
   int iVerMin = ( -( int ) sps.getMaxCUHeight()   - iOffset - ( int ) pos.y + 1 ) << iMvShift;
 
+#if JVET_L0231_WRAPAROUND
+  if( sps.getSpsNext().getUseWraparound() )
+  {
+    int iHorMax = ( sps.getPicWidthInLumaSamples() + sps.getMaxCUWidth() - size.width + iOffset - ( int ) pos.x - 1 ) << iMvShift;
+    int iHorMin = ( -( int ) sps.getMaxCUWidth()                                      - iOffset - ( int ) pos.x + 1 ) << iMvShift;
+    rcMv.setHor( std::min( iHorMax, std::max( iHorMin, rcMv.getHor() ) ) );
+    rcMv.setVer( std::min( iVerMax, std::max( iVerMin, rcMv.getVer() ) ) );
+    return;
+  }
+#endif
+
   rcMv.setHor( std::min( iHorMax, std::max( iHorMin, rcMv.getHor() ) ) );
   rcMv.setVer( std::min( iVerMax, std::max( iVerMin, rcMv.getVer() ) ) );
 }
diff --git a/source/Lib/CommonLib/Mv.h b/source/Lib/CommonLib/Mv.h
index c86c4354f..a1525ddc7 100644
--- a/source/Lib/CommonLib/Mv.h
+++ b/source/Lib/CommonLib/Mv.h
@@ -287,7 +287,11 @@ namespace std
 };
 #endif
 void roundMV( Mv& rcMv, unsigned imvShift );
-void clipMv ( Mv& rcMv, const struct Position& pos, const class SPS& sps );
+void clipMv ( Mv& rcMv, const struct Position& pos, 
+#if JVET_L0231_WRAPAROUND
+              const struct Size& size,
+#endif
+              const class SPS& sps );
 
 void roundAffineMv( int& mvx, int& mvy, int nShift );
 
diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp
index dad3fc9cb..78b614a9a 100644
--- a/source/Lib/CommonLib/Picture.cpp
+++ b/source/Lib/CommonLib/Picture.cpp
@@ -1004,15 +1004,35 @@ void Picture::extendPicBorder()
 
     Pel*  pi = piTxt;
     // do left and right margins
-    for (int y = 0; y < p.height; y++)
+#if JVET_L0231_WRAPAROUND
+    if (cs->sps->getSpsNext().getUseWraparound())
     {
-      for (int x = 0; x < xmargin; x++ )
+      int xoffset = cs->sps->getSpsNext().getWraparoundOffset() >> getComponentScaleX( compID, cs->area.chromaFormat );
+      for (int y = 0; y < p.height; y++)
       {
-        pi[ -xmargin + x ] = pi[0];
-        pi[  p.width + x ] = pi[p.width-1];
+        for (int x = 0; x < xmargin; x++ )
+        {
+          pi[ -xmargin + x ] = pi[ -xmargin + x + xoffset ];
+          pi[  p.width + x ] = pi[  p.width + x - xoffset ];
+        }
+        pi += p.stride;
       }
-      pi += p.stride;
     }
+    else
+    {
+#endif
+      for (int y = 0; y < p.height; y++)
+      {
+        for (int x = 0; x < xmargin; x++ )
+        {
+          pi[ -xmargin + x ] = pi[0];
+          pi[  p.width + x ] = pi[p.width-1];
+        }
+        pi += p.stride;
+      }
+#if JVET_L0231_WRAPAROUND
+    }
+#endif
 
     // pi is now the (0,height) (bottom left of image within bigger picture
     pi -= (p.stride + xmargin);
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 0f77bcbfc..a6a6d3b95 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -1829,6 +1829,10 @@ SPSNext::SPSNext( SPS& sps )
     , m_compositeRefEnabled     ( false )
 #if JVET_L0293_CPR
   , m_CPRMode                   ( 0 )
+#endif
+#if JVET_L0231_WRAPAROUND
+  , m_Wraparound                ( false )
+  , m_WraparoundOffset          ( 0 )
 #endif
   // ADD_NEW_TOOL : (sps extension) add tool enabling flags here (with "false" as default values)
 {
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index c54d840c0..0d5f1bec7 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -868,6 +868,11 @@ private:
   unsigned    m_CPRMode;
 #endif
 
+#if JVET_L0231_WRAPAROUND
+  bool        m_Wraparound;
+  unsigned    m_WraparoundOffset;
+#endif
+
   // ADD_NEW_TOOL : (sps extension) add tool enabling flags and associated parameters here
 
 public:
@@ -989,6 +994,12 @@ public:
 #if JVET_L0293_CPR
   void      setCPRMode            (unsigned CPRMode)                                { m_CPRMode = CPRMode; }
   unsigned  getCPRMode            ()                                      const     { return m_CPRMode; }
+#endif
+#if JVET_L0231_WRAPAROUND
+  void      setUseWraparound      ( bool b )                                        { m_Wraparound = b; }
+  bool      getUseWraparound      ()                                      const     { return m_Wraparound; }
+  void      setWraparoundOffset   ( unsigned offset )                               { m_WraparoundOffset = offset; }
+  unsigned  getWraparoundOffset   ()                                      const     { return m_WraparoundOffset; }
 #endif
   // ADD_NEW_TOOL : (sps extension) add access functions for tool enabling flags and associated parameters here
 
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 9f4077909..b1043bf31 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,8 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_L0231_WRAPAROUND                             1 // Wrap-around MC
+
 #define TRAINED_CABAC_INIT_TABLES                         1 // Trained values for VTM3
 #define JVET_L0410_TC_TAB                                 1 // Change TC table for QP 51-63
 
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index a72c94c67..f5c83a27e 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -930,6 +930,14 @@ void HLSyntaxReader::parseSPSNext( SPSNext& spsNext, const bool usePCM )
     }
   }
 #endif
+
+#if JVET_L0231_WRAPAROUND
+  READ_FLAG( symbol, "ref_wraparound_enabled_flag" );               spsNext.setUseWraparound( symbol != 0 );
+  if( spsNext.getUseWraparound() )
+  {
+    READ_UVLC( symbol, "ref_wraparound_offset" );                   spsNext.setWraparoundOffset( symbol );
+  }
+#endif
   // ADD_NEW_TOOL : (sps extension parser) read tool enabling flags and associated parameters here
 }
 
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 60709f112..1ce03c6ec 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -239,6 +239,11 @@ protected:
   unsigned  m_CPRFastMethod;
 #endif    
   
+#if JVET_L0231_WRAPAROUND
+  bool      m_Wraparound;
+  unsigned  m_WraparoundOffset;
+#endif
+
   // ADD_NEW_TOOL : (encoder lib) add tool enabling flags and associated parameters here
 
   bool      m_useFastLCTU;
@@ -732,6 +737,13 @@ public:
   unsigned  getCPRFastMethod                ()         const { return m_CPRFastMethod; }
 #endif  
 
+#if JVET_L0231_WRAPAROUND
+  void      setUseWraparound                ( bool b )       { m_Wraparound = b; }
+  bool      getUseWraparound                ()         const { return m_Wraparound; }
+  void      setWraparoundOffset             ( unsigned u )   { m_WraparoundOffset = u; }
+  unsigned  getWraparoundOffset             ()         const { return m_WraparoundOffset; }
+#endif
+
   // ADD_NEW_TOOL : (encoder lib) add access functions here
 
 
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index e57939ac7..8a102ef7c 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -882,6 +882,11 @@ void EncLib::xInitSPS(SPS &sps)
 #if JVET_L0293_CPR
   sps.getSpsNext().setCPRMode               ( m_CPRMode );
 #endif 
+
+#if JVET_L0231_WRAPAROUND
+  sps.getSpsNext().setUseWraparound         ( m_Wraparound );
+  sps.getSpsNext().setWraparoundOffset      ( m_WraparoundOffset );
+#endif
   // ADD_NEW_TOOL : (encoder lib) set tool enabling flags and associated parameters here
 
   int minCUSize =  sps.getMaxCUWidth() >> sps.getLog2DiffMaxMinCodingBlockSize();
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 0ff695df8..44f0b1d07 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -1270,8 +1270,16 @@ void InterSearch::xSetIntraSearchRange(PredictionUnit& pu, int iRoiWidth, int iR
 
   rcMvSrchRngLT <<= 2;
   rcMvSrchRngRB <<= 2;
-  clipMv(rcMvSrchRngLT, pu.cu->lumaPos(), sps);
-  clipMv(rcMvSrchRngRB, pu.cu->lumaPos(), sps);
+  clipMv(rcMvSrchRngLT, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+         pu.cu->lumaSize(),
+#endif
+         sps);
+  clipMv(rcMvSrchRngRB, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+         pu.cu->lumaSize(),
+#endif
+         sps);
   rcMvSrchRngLT >>= 2;
   rcMvSrchRngRB >>= 2;
 }
@@ -2328,7 +2336,11 @@ Distortion InterSearch::xGetTemplateCost( const PredictionUnit& pu,
   cMvCand.hor = cMvCand.hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
   cMvCand.ver = cMvCand.ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
 #endif
-  clipMv( cMvCand, pu.cu->lumaPos(), *pu.cs->sps );
+  clipMv( cMvCand, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
 
 
   // prediction pattern
@@ -2566,7 +2578,11 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu,
   cFPMvPred.hor = cFPMvPred.hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
   cFPMvPred.ver = cFPMvPred.ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
 #endif
-  clipMv( cFPMvPred, pu.cu->lumaPos(), *pu.cs->sps );
+  clipMv( cFPMvPred, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
 
 #if !REMOVE_MV_ADAPT_PREC
   Mv mvTL(cFPMvPred.getHor() - (iSrchRng << iMvShift), cFPMvPred.getVer() - (iSrchRng << iMvShift), cFPMvPred.highPrec);
@@ -2576,8 +2592,16 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu,
   Mv mvBR(cFPMvPred.getHor() + (iSrchRng << iMvShift), cFPMvPred.getVer() + (iSrchRng << iMvShift));
 #endif
 
-  clipMv( mvTL, pu.cu->lumaPos(), *pu.cs->sps );
-  clipMv( mvBR, pu.cu->lumaPos(), *pu.cs->sps );
+  clipMv( mvTL, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
+  clipMv( mvBR, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
 
   mvTL.divideByPowerOf2( iMvShift );
   mvBR.divideByPowerOf2( iMvShift );
@@ -2727,7 +2751,11 @@ void InterSearch::xTZSearch( const PredictionUnit& pu,
   rcMv.hor = rcMv.hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
   rcMv.ver = rcMv.ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
 #endif
-  clipMv( rcMv, pu.cu->lumaPos(), *pu.cs->sps );
+  clipMv( rcMv, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
 #if REMOVE_MV_ADAPT_PREC
   rcMv.hor = rcMv.hor >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
   rcMv.ver = rcMv.ver >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
@@ -2768,7 +2796,11 @@ void InterSearch::xTZSearch( const PredictionUnit& pu,
     integerMv2Nx2NPred.hor = integerMv2Nx2NPred.hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
     integerMv2Nx2NPred.ver = integerMv2Nx2NPred.ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
 #endif
-    clipMv( integerMv2Nx2NPred, pu.cu->lumaPos(), *pu.cs->sps );
+    clipMv( integerMv2Nx2NPred, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+            pu.cu->lumaSize(),
+#endif
+            *pu.cs->sps );
 #if REMOVE_MV_ADAPT_PREC
     integerMv2Nx2NPred.hor = integerMv2Nx2NPred.hor >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
     integerMv2Nx2NPred.ver = integerMv2Nx2NPred.ver >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
@@ -3005,7 +3037,11 @@ void InterSearch::xTZSearchSelective( const PredictionUnit& pu,
   rcMv.hor = rcMv.hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
   rcMv.ver = rcMv.ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
 #endif
-  clipMv( rcMv, pu.cu->lumaPos(), *pu.cs->sps );
+  clipMv( rcMv, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
 #if REMOVE_MV_ADAPT_PREC
   rcMv.hor = rcMv.hor >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
   rcMv.ver = rcMv.ver >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
@@ -3040,7 +3076,11 @@ void InterSearch::xTZSearchSelective( const PredictionUnit& pu,
     integerMv2Nx2NPred.hor = integerMv2Nx2NPred.hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
     integerMv2Nx2NPred.ver = integerMv2Nx2NPred.ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
 #endif
-    clipMv( integerMv2Nx2NPred, pu.cu->lumaPos(), *pu.cs->sps );
+    clipMv( integerMv2Nx2NPred, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+            pu.cu->lumaSize(),
+#endif
+            *pu.cs->sps );
 #if REMOVE_MV_ADAPT_PREC
     integerMv2Nx2NPred.hor = integerMv2Nx2NPred.hor >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
     integerMv2Nx2NPred.ver = integerMv2Nx2NPred.ver >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
@@ -3191,7 +3231,11 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct&
         cTempMV.hor = cTempMV.hor << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
         cTempMV.ver = cTempMV.ver << VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
 #endif
-        clipMv(cTempMV, pu.cu->lumaPos(), sps);
+        clipMv(cTempMV, pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+               pu.cu->lumaSize(),
+#endif
+               sps);
 #if REMOVE_MV_ADAPT_PREC
         cTempMV.hor = cTempMV.hor >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
         cTempMV.ver = cTempMV.ver >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
@@ -3458,13 +3502,21 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
           vy = mvScaleVer + dMvHorY * (pu.Y().x - mvInfo->x) + dMvVerY * (pu.Y().y - mvInfo->y);
           roundAffineMv(vx, vy, shift);
           mvTmp[0] = Mv(vx, vy);
-          clipMv(mvTmp[0], pu.cu->lumaPos(), *pu.cs->sps);
+          clipMv(mvTmp[0], pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+                 pu.cu->lumaSize(),
+#endif
+                 *pu.cs->sps);
           mvTmp[0].roundMV2SignalPrecision();
           vx = mvScaleHor + dMvHorX * (pu.Y().x + pu.Y().width - mvInfo->x) + dMvVerX * (pu.Y().y - mvInfo->y);
           vy = mvScaleVer + dMvHorY * (pu.Y().x + pu.Y().width - mvInfo->x) + dMvVerY * (pu.Y().y - mvInfo->y);
           roundAffineMv(vx, vy, shift);
           mvTmp[1] = Mv(vx, vy);
-          clipMv(mvTmp[1], pu.cu->lumaPos(), *pu.cs->sps);
+          clipMv(mvTmp[1], pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+                 pu.cu->lumaSize(),
+#endif
+                 *pu.cs->sps);
           mvTmp[1].roundMV2SignalPrecision();
 #if REMOVE_MV_ADAPT_PREC
           mvTmp[0].hor = mvTmp[0].hor >> VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
@@ -4245,11 +4297,23 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu,
   uint32_t uiBitsBest = 0;
 
   // do motion compensation with origin mv
-  clipMv( acMvTemp[0], pu.cu->lumaPos(), *pu.cs->sps );
-  clipMv( acMvTemp[1], pu.cu->lumaPos(), *pu.cs->sps );
+  clipMv( acMvTemp[0], pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
+  clipMv( acMvTemp[1], pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+          pu.cu->lumaSize(),
+#endif
+          *pu.cs->sps );
   if ( pu.cu->affineType == AFFINEMODEL_6PARAM )
   {
-    clipMv( acMvTemp[2], pu.cu->lumaPos(), *pu.cs->sps );
+    clipMv( acMvTemp[2], pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+            pu.cu->lumaSize(),
+#endif
+            *pu.cs->sps );
   }
   xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cs->slice->clpRng( COMPONENT_Y ) );
 
@@ -4422,7 +4486,11 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu,
       acMvTemp[i].hor = Clip3( -32768, 32767, acMvTemp[i].hor );
       acMvTemp[i].ver = Clip3( -32768, 32767, acMvTemp[i].ver );
       acMvTemp[i].roundMV2SignalPrecision();
-      clipMv(acMvTemp[i], pu.cu->lumaPos(), *pu.cs->sps);
+      clipMv(acMvTemp[i], pu.cu->lumaPos(),
+#if JVET_L0231_WRAPAROUND
+             pu.cu->lumaSize(),
+#endif
+             *pu.cs->sps);
     }
     xPredAffineBlk( COMPONENT_Y, pu, refPic, acMvTemp, predBuf, false, pu.cu->slice->clpRng( COMPONENT_Y ) );
 
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index dbb3dd213..1c7f05de6 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -640,6 +640,14 @@ void HLSWriter::codeSPSNext( const SPSNext& spsNext, const bool usePCM )
     }
   }
 #endif
+
+#if JVET_L0231_WRAPAROUND
+  WRITE_FLAG( spsNext.getUseWraparound() ? 1 : 0,                                               "ref_wraparound_enabled_flag" );
+  if( spsNext.getUseWraparound() )
+  {
+    WRITE_UVLC( spsNext.getWraparoundOffset(),                                                  "ref_wraparound_offset" );
+  }
+#endif
   // ADD_NEW_TOOL : (sps extension writer) write tool enabling flags and associated parameters here
 }
 
-- 
GitLab