diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 69e1c5b811b30b8752a604b49226e5fa2f664aab..2d5d737f1fd1668bcdca59f9fa83ab728dabd989 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -798,6 +798,47 @@ void InterPrediction::xPredInterBlk ( const ComponentID& compID, const Predictio
   }
 }
 
+#if JVET_N0068_AFFINE_MEM_BW
+bool InterPrediction::isSubblockVectorSpreadOverLimit( int a, int b, int c, int d, int predType ) 
+{
+  int s4 = ( 4 << 11 );
+  int filterTap = 6;
+
+  if ( predType == 3 )
+  {
+    int refBlkWidth  = std::max( std::max( 0, 4 * a + s4 ), std::max( 4 * c, 4 * a + 4 * c + s4 ) ) - std::min( std::min( 0, 4 * a + s4 ), std::min( 4 * c, 4 * a + 4 * c + s4 ) );
+    int refBlkHeight = std::max( std::max( 0, 4 * b ), std::max( 4 * d + s4, 4 * b + 4 * d + s4 ) ) - std::min( std::min( 0, 4 * b ), std::min( 4 * d + s4, 4 * b + 4 * d + s4 ) );
+    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
+    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
+
+    if ( refBlkWidth * refBlkHeight > ( filterTap + 9 ) * ( filterTap + 9 ) )
+    {
+      return true;
+    }
+  }
+  else
+  {
+    int refBlkWidth  = std::max( 0, 4 * a + s4 ) - std::min( 0, 4 * a + s4 );
+    int refBlkHeight = std::max( 0, 4 * b ) - std::min( 0, 4 * b );
+    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
+    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
+    if ( refBlkWidth * refBlkHeight > ( filterTap + 9 ) * ( filterTap + 5 ) )
+    {
+      return true;
+    }
+
+    refBlkWidth  = std::max( 0, 4 * c ) - std::min( 0, 4 * c );
+    refBlkHeight = std::max( 0, 4 * d + s4 ) - std::min( 0, 4 * d + s4 );
+    refBlkWidth  = ( refBlkWidth >> 11 ) + filterTap + 3;
+    refBlkHeight = ( refBlkHeight >> 11 ) + filterTap + 3;
+    if ( refBlkWidth * refBlkHeight > ( filterTap + 5 ) * ( filterTap + 9 ) )
+    {
+      return true;
+    }
+  }
+  return false;
+}
+#endif
 void InterPrediction::xPredAffineBlk( const ComponentID& compID, const PredictionUnit& pu, const Picture* refPic, const Mv* _mv, PelUnitBuf& dstPic, const bool& bi, const ClpRng& clpRng )
 {
   if ( (pu.cu->affineType == AFFINEMODEL_6PARAM && _mv[0] == _mv[1] && _mv[0] == _mv[2])
@@ -873,6 +914,13 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio
   const int vFilterSize = isLuma(compID) ? NTAPS_LUMA : NTAPS_CHROMA;
 
   const int shift = iBit - 4 + MV_FRACTIONAL_BITS_INTERNAL;
+#if JVET_N0068_AFFINE_MEM_BW
+  bool subblkMVSpreadOverLimit = false;
+  if ( isSubblockVectorSpreadOverLimit( iDMvHorX, iDMvHorY, iDMvVerX, iDMvVerY, pu.interDir ) )
+  {
+    subblkMVSpreadOverLimit = true;
+  }
+#endif
 
 
   // get prediction block by block
@@ -888,9 +936,20 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio
       if(compID == COMPONENT_Y)
 #endif //JVET_N0671_AFFINE
       {
-        iMvScaleTmpHor = iMvScaleHor + iDMvHorX * (iHalfBW + w) + iDMvVerX * (iHalfBH + h);
-        iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (iHalfBW + w) + iDMvVerY * (iHalfBH + h);
-
+#if JVET_N0068_AFFINE_MEM_BW
+        if ( !subblkMVSpreadOverLimit )
+        {
+#endif
+          iMvScaleTmpHor = iMvScaleHor + iDMvHorX * (iHalfBW + w) + iDMvVerX * (iHalfBH + h);
+          iMvScaleTmpVer = iMvScaleVer + iDMvHorY * (iHalfBW + w) + iDMvVerY * (iHalfBH + h);
+#if JVET_N0068_AFFINE_MEM_BW
+        }
+        else
+        {
+          iMvScaleTmpHor = iMvScaleHor + iDMvHorX * ( cxWidth >> 1 ) + iDMvVerX * ( cxHeight >> 1 );
+          iMvScaleTmpVer = iMvScaleVer + iDMvHorY * ( cxWidth >> 1 ) + iDMvVerY * ( cxHeight >> 1 );
+        }
+#endif
         roundAffineMv(iMvScaleTmpHor, iMvScaleTmpVer, shift);
         Mv tmpMv(iMvScaleTmpHor, iMvScaleTmpVer);
         tmpMv.clipToStorageBitDepth();
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index 760e2268a27fb1831f5bc10f15e0592f6d3791b7..5130f46f8a5f76edbb1b5a33d1bc192594f5c0c8 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -190,6 +190,9 @@ public:
 #if ENABLE_SPLIT_PARALLELISM
   int     getShareState() const { return m_shareState; }
 #endif
+#if JVET_N0068_AFFINE_MEM_BW
+  bool isSubblockVectorSpreadOverLimit( int a, int b, int c, int d, int predType );
+#endif
 };
 
 //! \}
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 63bd3f0f85c4cf54f759057a2b27ab2769dd233a..90dce7152866f1e8e27d27f2194b062dbdbf0c7b 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,8 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_N0068_AFFINE_MEM_BW                          1 // memory bandwidth reduction for affine mode
+
 #define JVET_N0308_MAX_CU_SIZE_FOR_ISP                    1
 
 #define JVET_N0280_RESIDUAL_CODING_TS                     1
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 3bab928cf55e03ebdefcb2d3a4c77929d5648118..9d343da3cccb3b16f26ffc67d7a851e3b34b3cd8 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -4032,14 +4032,30 @@ void PU::setAllAffineMv( PredictionUnit& pu, Mv affLT, Mv affRT, Mv affLB, RefPi
 
   MotionBuf mb = pu.getMotionBuf();
   int mvScaleTmpHor, mvScaleTmpVer;
-
+#if JVET_N0068_AFFINE_MEM_BW
+  bool subblkMVSpreadOverLimit = false;
+  InterPrediction temp;
+  subblkMVSpreadOverLimit = temp.isSubblockVectorSpreadOverLimit( deltaMvHorX, deltaMvHorY, deltaMvVerX, deltaMvVerY, pu.interDir );
+#endif
   for ( int h = 0; h < pu.Y().height; h += blockHeight )
   {
     for ( int w = 0; w < pu.Y().width; w += blockWidth )
     {
-      mvScaleTmpHor = mvScaleHor + deltaMvHorX * (halfBW + w) + deltaMvVerX * (halfBH + h);
-      mvScaleTmpVer = mvScaleVer + deltaMvHorY * (halfBW + w) + deltaMvVerY * (halfBH + h);
+#if JVET_N0068_AFFINE_MEM_BW
+      if ( !subblkMVSpreadOverLimit )
+      {
+#endif
+        mvScaleTmpHor = mvScaleHor + deltaMvHorX * (halfBW + w) + deltaMvVerX * (halfBH + h);
+        mvScaleTmpVer = mvScaleVer + deltaMvHorY * (halfBW + w) + deltaMvVerY * (halfBH + h);
 
+#if JVET_N0068_AFFINE_MEM_BW
+      }
+      else
+      {
+        mvScaleTmpHor = mvScaleHor + deltaMvHorX * ( pu.Y().width >> 1 ) + deltaMvVerX * ( pu.Y().height >> 1 );
+        mvScaleTmpVer = mvScaleVer + deltaMvHorY * ( pu.Y().width >> 1 ) + deltaMvVerY * ( pu.Y().height >> 1 );
+      }
+#endif
       roundAffineMv( mvScaleTmpHor, mvScaleTmpVer, shift );
       Mv curMv(mvScaleTmpHor, mvScaleTmpVer);
       curMv.clipToStorageBitDepth();
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index af871b34e8c07ac79f4d44957391c7768a07a756..59e74f97b3c7aa574bb10f420160c2fa1e50029e 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -4306,7 +4306,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
   for ( int iRefList = 0; iRefList < iNumPredDir; iRefList++ )
   {
     RefPicList  eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 );
-
+#if JVET_N0068_AFFINE_MEM_BW
+    pu.interDir = ( iRefList ? 2 : 1 );
+#endif
     for (int iRefIdxTemp = 0; iRefIdxTemp < slice.getNumRefIdx(eRefPicList); iRefIdxTemp++)
     {
       // Get RefIdx bits
@@ -4645,7 +4647,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
   if ( slice.isInterB() && !PU::isBipredRestriction(pu) )
   {
 	  tryBipred = 1;
-
+#if JVET_N0068_AFFINE_MEM_BW
+    pu.interDir = 3;
+#endif
     // Set as best list0 and list1
     iRefIdxBi[0] = iRefIdx[0];
     iRefIdxBi[1] = iRefIdx[1];
@@ -4901,7 +4905,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
   {
     lastMode = 2;
     affineCost = uiCostBi;
-
+#if JVET_N0068_AFFINE_MEM_BW
+    pu.interDir = 3;
+#endif
     PU::setAllAffineMv( pu, cMvBi[0][0], cMvBi[0][1], cMvBi[0][2], REF_PIC_LIST_0
       , changeToHighPrec
     );
@@ -4922,7 +4928,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
       }
     }
 
+#if !JVET_N0068_AFFINE_MEM_BW
     pu.interDir = 3;
+#endif
 
     pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdxBi[0][iRefIdxBi[0]];
     pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdxBi[0]];
@@ -4933,7 +4941,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
   {
     lastMode = 0;
     affineCost = uiCost[0];
-
+#if JVET_N0068_AFFINE_MEM_BW
+    pu.interDir = 1;
+#endif
     PU::setAllAffineMv( pu, aacMv[0][0], aacMv[0][1], aacMv[0][2], REF_PIC_LIST_0
       , changeToHighPrec
     );
@@ -4947,8 +4957,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
         pu.mvdAffi[0][verIdx] = pu.mvdAffi[0][verIdx] - pu.mvdAffi[0][0];
       }
     }
-
+#if !JVET_N0068_AFFINE_MEM_BW
     pu.interDir = 1;
+#endif
 
     pu.mvpIdx[REF_PIC_LIST_0] = aaiMvpIdx[0][iRefIdx[0]];
     pu.mvpNum[REF_PIC_LIST_0] = aaiMvpNum[0][iRefIdx[0]];
@@ -4957,7 +4968,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
   {
     lastMode = 1;
     affineCost = uiCost[1];
-
+#if JVET_N0068_AFFINE_MEM_BW
+    pu.interDir = 2;
+#endif
     PU::setAllAffineMv( pu, aacMv[1][0], aacMv[1][1], aacMv[1][2], REF_PIC_LIST_1
       , changeToHighPrec
     );
@@ -4971,8 +4984,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
         pu.mvdAffi[1][verIdx] = pu.mvdAffi[1][verIdx] - pu.mvdAffi[1][0];
       }
     }
-
+#if !JVET_N0068_AFFINE_MEM_BW
     pu.interDir = 2;
+#endif
 
     pu.mvpIdx[REF_PIC_LIST_1] = aaiMvpIdx[1][iRefIdx[1]];
     pu.mvpNum[REF_PIC_LIST_1] = aaiMvpNum[1][iRefIdx[1]];