diff --git a/cmake/CMakeBuild/bin/pyhhi/__init__.pyc b/cmake/CMakeBuild/bin/pyhhi/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..cde6cada74dfa8f81e6b2224df0edabf75d754f8
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/__init__.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/__init__.pyc b/cmake/CMakeBuild/bin/pyhhi/build/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..f93098d45cd975f3c40b1c545c4538d9443e50ef
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/__init__.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/app/__init__.pyc b/cmake/CMakeBuild/bin/pyhhi/build/app/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..aae725b6e2216d20f01a4ef68a0d82508032d423
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/app/__init__.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/app/cmk.pyc b/cmake/CMakeBuild/bin/pyhhi/build/app/cmk.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4346bb6eb002aa92f8c6890ccca123c874de6c68
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/app/cmk.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/cmkfnd.pyc b/cmake/CMakeBuild/bin/pyhhi/build/cmkfnd.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..e5b791b883732da774be809d26b4184660e79ac7
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/cmkfnd.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/cmksupp.pyc b/cmake/CMakeBuild/bin/pyhhi/build/cmksupp.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..7fa3750f0dba19655d62061f57dc628cf836dabf
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/cmksupp.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/common/__init__.pyc b/cmake/CMakeBuild/bin/pyhhi/build/common/__init__.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..d5fc6976798ba15db1f1066481f2feb7f9c75959
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/common/__init__.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/common/bldtools.pyc b/cmake/CMakeBuild/bin/pyhhi/build/common/bldtools.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..c27b7273fb8f5986f5fbb8d711430d544c67d5d9
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/common/bldtools.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/common/cmbldver.pyc b/cmake/CMakeBuild/bin/pyhhi/build/common/cmbldver.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..ae1c9c223ffe227c0819bcb9e8eb437591857ec9
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/common/cmbldver.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/common/error.pyc b/cmake/CMakeBuild/bin/pyhhi/build/common/error.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..5c206770122f234037123152ecb12bc9d39b3991
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/common/error.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/common/system.pyc b/cmake/CMakeBuild/bin/pyhhi/build/common/system.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..2f03cdc0f704dd8e5324592bda42e80ef253dea6
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/common/system.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/common/util.pyc b/cmake/CMakeBuild/bin/pyhhi/build/common/util.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9681ad0bd5db345a2a5a36d29fb3b250364b21b6
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/common/util.pyc differ
diff --git a/cmake/CMakeBuild/bin/pyhhi/build/common/ver.pyc b/cmake/CMakeBuild/bin/pyhhi/build/common/ver.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..0c0615f71febf28ce8bd3c68433486d54cf860cd
Binary files /dev/null and b/cmake/CMakeBuild/bin/pyhhi/build/common/ver.pyc differ
diff --git a/enc.bit b/enc.bit
new file mode 100644
index 0000000000000000000000000000000000000000..38b6a9dcd19461ad04583bb7104989f05d76bf8d
Binary files /dev/null and b/enc.bit differ
diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp
index c72a3e938bff37029a212213c08cb35a5eb26878..04dac8b388b6667c600f37482c92619f48239b75 100644
--- a/source/App/DecoderApp/DecAppCfg.cpp
+++ b/source/App/DecoderApp/DecAppCfg.cpp
@@ -111,6 +111,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
                                                                                    "\t1: enable bit statistic\n"
                                                                                    "\t2: enable tool statistic\n"
                                                                                    "\t3: enable bit and tool statistic\n")
+#endif
+#if JVET_M0445_MCTS_DEC_CHECK
+  ("MCTSCheck",                m_mctsCheck,                           false,       "If enabled, the decoder checks for violations of mc_exact_sample_value_match_flag in Temporal MCTS ")
 #endif
   ;
 
@@ -148,6 +151,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
   }
 #endif
 
+#if JVET_M0445_MCTS_DEC_CHECK
+  g_mctsDecCheckEnabled = m_mctsCheck;
+#endif
   // Chroma output bit-depth
   if( m_outputBitDepth[CHANNEL_TYPE_LUMA] != 0 && m_outputBitDepth[CHANNEL_TYPE_CHROMA] == 0 )
   {
@@ -230,6 +236,9 @@ DecAppCfg::DecAppCfg()
 , m_bClipOutputVideoToRec709Range(false)
 , m_packedYUVMode(false)
 , m_statMode(0)
+#if JVET_M0445_MCTS_DEC_CHECK
+, m_mctsCheck(false)
+#endif
 {
   for (uint32_t channelTypeIndex = 0; channelTypeIndex < MAX_NUM_CHANNEL_TYPE; channelTypeIndex++)
   {
diff --git a/source/App/DecoderApp/DecAppCfg.h b/source/App/DecoderApp/DecAppCfg.h
index 8674f99e816bcaf180b608e2a6e92ab6c13ff322..029ad15ebd4847fafc14c10503c4eaa6ddae05cd 100644
--- a/source/App/DecoderApp/DecAppCfg.h
+++ b/source/App/DecoderApp/DecAppCfg.h
@@ -73,6 +73,9 @@ protected:
   bool          m_packedYUVMode;                      ///< If true, output 10-bit and 12-bit YUV data as 5-byte and 3-byte (respectively) packed YUV data
   std::string   m_cacheCfgFile;                       ///< Config file of cache model
   int           m_statMode;                           ///< Config statistic mode (0 - bit stat, 1 - tool stat, 3 - both)
+#if JVET_M0445_MCTS_DEC_CHECK
+  bool          m_mctsCheck;
+#endif
 
 public:
   DecAppCfg();
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 53d2b214bb3c21a5d90dfb32e8b86b51a895551b..a38a1174f8f581354335161834968ec88d28b1f2 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -435,6 +435,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setSOPDescriptionSEIEnabled                          ( m_SOPDescriptionSEIEnabled );
   m_cEncLib.setScalableNestingSEIEnabled                         ( m_scalableNestingSEIEnabled );
   m_cEncLib.setTMCTSSEIEnabled                                   ( m_tmctsSEIEnabled );
+#if JVET_M0445_MCTS
+  m_cEncLib.setMCTSEncConstraint                                 ( m_MCTSEncConstraint);
+#endif
   m_cEncLib.setTimeCodeSEIEnabled                                ( m_timeCodeSEIEnabled );
   m_cEncLib.setNumberOfTimeSets                                  ( m_timeCodeSEINumTs );
   for(int i = 0; i < m_timeCodeSEINumTs; i++)
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index b6b2e470f22766f1519232163bf11431d15162be..a4b20c5cfd4e474d57b682f13555ffff596e1255 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1296,6 +1296,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
 #endif
   ("SEIGreenMetadataType",                            m_greenMetadataType,                                  0u, "Value for the green_metadata_type specifies the type of metadata that is present in the SEI message. If green_metadata_type is 1, then metadata enabling quality recovery after low-power encoding is present")
   ("SEIXSDMetricType",                                m_xsdMetricType,                                      0u, "Value for the xsd_metric_type indicates the type of the objective quality metric. PSNR is the only type currently supported")
+#if JVET_M0445_MCTS
+  ("MCTSEncConstraint",                               m_MCTSEncConstraint,                               false, "For MCTS, constrain motion vectors at tile boundaries")
+#endif
 #if ENABLE_TRACING
   ("TraceChannelsList",                               bTracingChannelsList,                              false, "List all available tracing channels")
   ("TraceRule",                                       sTracingRule,                               string( "" ), "Tracing rule (ex: \"D_CABAC:poc==8\" or \"D_REC_CB_LUMA:poc==8\")")
@@ -2840,6 +2843,30 @@ bool EncAppCfg::xCheckParameter()
 #endif
   }
 
+#if JVET_M0445_MCTS
+  g_mctsEncConstraint = m_MCTSEncConstraint;
+  if ((m_MCTSEncConstraint) && (m_bLFCrossTileBoundaryFlag))
+  {
+    printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling filtering across tile boundaries!\n");
+    m_bLFCrossTileBoundaryFlag = false;
+  }
+  if ((m_MCTSEncConstraint) && (m_TMVPModeId))
+  {
+    printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling TMVP!\n");
+    m_TMVPModeId = 0;
+  }
+
+  if ((m_MCTSEncConstraint) && ( m_alf ))
+  {
+    printf("Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling ALF!\n");
+    m_alf = false;
+  }
+  if( ( m_MCTSEncConstraint ) && ( m_BIO ) )
+  {
+    printf( "Warning: Constrained Encoding for Motion Constrained Tile Sets (MCTS) is enabled. Disabling BIO!\n" );
+    m_BIO = false;
+  }
+#endif
 
   if (m_toneMappingInfoSEIEnabled)
   {
@@ -3137,6 +3164,9 @@ void EncAppCfg::xPrintParameter()
   {
     msg( VERBOSE, "A=%d ", m_sliceSegmentArgument);
   }
+#endif
+#if JVET_M0445_MCTS
+  msg( VERBOSE, "Tiles:%dx%d ", m_numTileColumnsMinus1 + 1, m_numTileRowsMinus1 + 1 );
 #endif
   msg( VERBOSE, "CIP:%d ", m_bUseConstrainedIntraPred);
   msg( VERBOSE, "SAO:%d ", (m_bUseSAO)?(1):(0));
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index b4b3705ecfe8cc449df2e9eab2498165211cb371..09f665f46e179f0121e8457ce05b1ad11d60e463 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -465,6 +465,10 @@ protected:
   uint32_t      m_greenMetadataType;
   uint32_t      m_xsdMetricType;
 
+#if JVET_M0445_MCTS
+  bool      m_MCTSEncConstraint;
+#endif
+
   // weighted prediction
   bool      m_useWeightedPred;                    ///< Use of weighted prediction in P slices
   bool      m_useWeightedBiPred;                  ///< Use of bi-directional weighted prediction in B slices
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index 473d844c98a0b024bc37dab51e6684a192f0233e..62493a2f8d5716bd0a710b48f56e39993e1de35d 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -39,6 +39,9 @@
 
 #include "Buffer.h"
 #include "UnitTools.h"
+#if JVET_M0445_MCTS
+#include "MCTS.h"
+#endif
 
 #include <memory.h>
 #include <algorithm>
@@ -1447,10 +1450,27 @@ void InterPrediction::motionCompensation4Triangle( CodingUnit &cu, MergeCtx &tri
     PU::spanMotionInfo( pu );
     motionCompensation( pu, tmpTriangleBuf );
 
+#if JVET_M0445_MCTS_DEC_CHECK
+    {
+      if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) )
+      {
+        printf( "DECODER_TRIANGLE_PU: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
+      }
+    }
+#endif
+  
     triangleMrgCtx.setMergeInfo( pu, candIdx1 );
     PU::spanMotionInfo( pu );
     motionCompensation( pu, predBuf );
 
+#if JVET_M0445_MCTS_DEC_CHECK
+    {
+      if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) )
+      {
+        printf( "DECODER_TRIANGLE_PU: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
+      }
+    }
+#endif
 #if JVET_M0328_KEEP_ONE_WEIGHT_GROUP
     weightedTriangleBlk( pu, splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, tmpTriangleBuf, predBuf );
 #else
diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h
index 3be7081794d6505d02b79839fd46dd94072caa14..6e6dcc1f60ad669321b89694376e6fab42f509b6 100644
--- a/source/Lib/CommonLib/Picture.h
+++ b/source/Lib/CommonLib/Picture.h
@@ -49,6 +49,9 @@
 #if JVET_M0253_HASH_ME
 #include "Hash.h"
 #endif
+#if JVET_M0445_MCTS
+#include "MCTS.h"
+#endif
 #include <deque>
 
 #if ENABLE_WPP_PARALLELISM || ENABLE_SPLIT_PARALLELISM
@@ -286,6 +289,9 @@ public:
 
 #if HEVC_TILES_WPP
   TileMap*     tileMap;
+#endif
+#if JVET_M0445_MCTS
+  MCTSInfo     mctsInfo;
 #endif
   std::vector<AQpLayer*> aqlayer;
 
diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp
index d2e45089664850f87bf095c792926f52eb326c4b..e9e873d575c1c508741ee2351f3d43b199f2ae69 100644
--- a/source/Lib/CommonLib/Rom.cpp
+++ b/source/Lib/CommonLib/Rom.cpp
@@ -51,6 +51,12 @@
 #if ENABLE_TRACING
 CDTrace *g_trace_ctx = NULL;
 #endif
+#if JVET_M0445_MCTS
+bool g_mctsEncConstraint = false;
+#endif
+#if JVET_M0445_MCTS_DEC_CHECK
+bool g_mctsDecCheckEnabled = false;
+#endif
 
 
 //! \ingroup CommonLib
diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h
index f7b795621be0edde887cd2700663a8f2a8a2a60b..712092901f2f49b669ca00230b956e07e6a174ff 100644
--- a/source/Lib/CommonLib/Rom.h
+++ b/source/Lib/CommonLib/Rom.h
@@ -262,5 +262,12 @@ extern const uint8_t g_triangleCombination[TRIANGLE_MAX_NUM_CANDS][3];
 extern const uint8_t g_triangleIdxBins[TRIANGLE_MAX_NUM_CANDS];
 #endif
 
+#if JVET_M0445_MCTS
+extern bool g_mctsEncConstraint;
+#endif
+#if JVET_M0445_MCTS_DEC_CHECK
+extern bool g_mctsDecCheckEnabled;
+#endif
+
 #endif  //__TCOMROM__
 
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 6c591033bf365a4da7343a2afcbdf4ecda1562be..28061f9604c4c1d5a9fbe9a5543a57895f71502b 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,10 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_M0445_MCTS                                   1 // Motion constrained tile sets
+#if JVET_M0445_MCTS
+#define JVET_M0445_MCTS_DEC_CHECK                         1 // Check at decoder side the MCTS restrictions
+#endif
 #define JCTVC_Y0038_PARAMS                                1
 
 #define JVET_M0600_RATE_CTRL                              1 //frame level bit allocation by qdf
@@ -261,6 +265,15 @@ typedef std::pair<int, int>  TrCost;
 #define HEVC_TILES_WPP                                    1
 #endif
 
+#if JVET_M0445_MCTS
+#ifndef HEVC_TILES_WPP 
+#define HEVC_TILES_WPP                                    1
+#endif
+#if !HEVC_TILES_WPP
+#error JVET_M0445_MCTS_NEEDS_TILES_ENABLED
+#endif
+#endif
+
 #define KEEP_PRED_AND_RESI_SIGNALS                        0
 
 
diff --git a/source/Lib/CommonLib/dtrace_buffer.h b/source/Lib/CommonLib/dtrace_buffer.h
index 3d4712b33bd27e2a2a4380d100d8ed325a9ce39a..f5fcbdf61a542990ed952845786472b1e40d6077 100644
--- a/source/Lib/CommonLib/dtrace_buffer.h
+++ b/source/Lib/CommonLib/dtrace_buffer.h
@@ -165,6 +165,25 @@ inline void dtraceCCRC( CDTrace *trace_ctx, DTRACE_CHANNEL channel, const Coding
       calcCheckSum( pelBuf, cs.sps->getBitDepth ( toChannelType(compId) )));
 }
 
+inline void dtraceMotField( CDTrace *trace_ctx, const PredictionUnit& pu )
+{
+  DTRACE( trace_ctx, D_MOT_FIELD, "PU %d,%d @ %d,%d\n", pu.lwidth(), pu.lheight(), pu.lx(), pu.ly() );
+  const CMotionBuf mb = pu.getMotionBuf();
+  for( uint32_t listIdx = 0; listIdx < 2; listIdx++ )
+  {
+    RefPicList eListIdx = RefPicList( listIdx );
+    for( int y = 0, i = 0; y < pu.lheight(); y += 4 )
+    {
+      for( int x = 0; x < pu.lwidth(); x += 4, i++ )
+      {
+        const MotionInfo &mi = mb.at( x >> 2, y >> 2 );
+        DTRACE( trace_ctx, D_MOT_FIELD, "%d,%d:%d  ", mi.mv[eListIdx].getHor(), mi.mv[eListIdx].getVer(), mi.refIdx[eListIdx] );
+      }
+      DTRACE( trace_ctx, D_MOT_FIELD, "\n" );
+    }
+    DTRACE( trace_ctx, D_MOT_FIELD, "\n" );
+  }
+}
 
 #define DTRACE_PEL_BUF(...)              dtracePelBuf( __VA_ARGS__ )
 #define DTRACE_COEFF_BUF(...)            dtraceCoeffBuf( __VA_ARGS__ )
@@ -175,6 +194,7 @@ inline void dtraceCCRC( CDTrace *trace_ctx, DTRACE_CHANNEL channel, const Coding
 #define DTRACE_UNIT_COMP(...)            dtraceUnitComp( __VA_ARGS__ )
 #define DTRACE_CRC(...)                  dtraceCRC( __VA_ARGS__ )
 #define DTRACE_CCRC(...)                 dtraceCCRC( __VA_ARGS__ )
+#define DTRACE_MOT_FIELD(...)            dtraceMotField( __VA_ARGS__ )
 
 #else
 
@@ -187,6 +207,7 @@ inline void dtraceCCRC( CDTrace *trace_ctx, DTRACE_CHANNEL channel, const Coding
 #define DTRACE_UNIT_COMP(...)
 #define DTRACE_CRC(...)
 #define DTRACE_CCRC(...)
+#define DTRACE_MOT_FIELD(...)
 
 #endif
 
diff --git a/source/Lib/CommonLib/dtrace_next.h b/source/Lib/CommonLib/dtrace_next.h
index 2aa746d8a139c8854ae62924de8a90738aa7a6d1..23e7ef98e15808b98b6ef11b03b101b055da8ce0 100644
--- a/source/Lib/CommonLib/dtrace_next.h
+++ b/source/Lib/CommonLib/dtrace_next.h
@@ -141,6 +141,7 @@ enum DTRACE_CHANNEL
   D_RDOQ_MORE,
   D_RDOQ_COST,
   D_TMP,
+  D_MOT_FIELD,
   D_CRC
 #if K0149_BLOCK_STATISTICS
   ,
@@ -242,6 +243,7 @@ inline CDTrace* tracing_init( std::string& sTracingFile, std::string& sTracingRu
     _CNL_DEF( D_RDOQ_MORE ),
     _CNL_DEF( D_RDOQ_COST ),
     _CNL_DEF( D_TMP ),
+    _CNL_DEF( D_MOT_FIELD ),
     _CNL_DEF( D_CRC )
   #if K0149_BLOCK_STATISTICS
     ,
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 723ccb3dce81f83f8625567717bd644f5bf7eccb..9d6b2a035dc959857c69c8efcb469cdc40be783c 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -905,6 +905,15 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         PU::spanMotionInfo( pu, mrgCtx );
       }
     }
+#if JVET_M0445_MCTS_DEC_CHECK
+    if( !cu.triangle )
+    {
+      if( g_mctsDecCheckEnabled && !MCTSHelper::checkMvBufferForMCTSConstraint( pu, true ) )
+      {
+        printf( "DECODER: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
+      }
+    }
+#endif
   }
 }
 //! \}
diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp
index 5e12acbcfcc5ef91dfe4c63995acfb24eada8ac4..b365dd7e042435fcaee8b904e82eedcccb756228 100644
--- a/source/Lib/DecoderLib/DecSlice.cpp
+++ b/source/Lib/DecoderLib/DecSlice.cpp
@@ -235,6 +235,12 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream )
       cs.slice->resetMotionLUTs();
     }
 
+#if JVET_M0445_MCTS_DEC_CHECK
+    if( !cs.slice->isIntra() )
+    {
+      pic->mctsInfo.init( &cs, getCtuAddr( ctuArea.lumaPos(), *( cs.pcv ) ) );
+    }
+#endif
 #if JVET_M0055_DEBUG_CTU
 
     if( ctuRsAddr == debugCTU )
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 84faf6062336fdfae584bffb0d3432723aaabd80..64db89dfbe06b25a5fc26ea45f2bb655e14b1c19 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -478,6 +478,9 @@ protected:
   bool      m_SOPDescriptionSEIEnabled;
   bool      m_scalableNestingSEIEnabled;
   bool      m_tmctsSEIEnabled;
+#if JVET_M0445_MCTS
+  bool      m_MCTSEncConstraint;
+#endif
   bool      m_timeCodeSEIEnabled;
   int       m_timeCodeSEINumTs;
   SEITimeSet   m_timeSetArray[MAX_TIMECODE_SEI_SETS];
@@ -1278,6 +1281,10 @@ public:
   bool  getScalableNestingSEIEnabled() const                         { return m_scalableNestingSEIEnabled; }
   void  setTMCTSSEIEnabled(bool b)                                   { m_tmctsSEIEnabled = b; }
   bool  getTMCTSSEIEnabled()                                         { return m_tmctsSEIEnabled; }
+#if JVET_M0445_MCTS
+  void  setMCTSEncConstraint(bool b)                                 { m_MCTSEncConstraint = b; }
+  bool  getMCTSEncConstraint()                                       { return m_MCTSEncConstraint; }
+#endif
   void  setTimeCodeSEIEnabled(bool b)                                { m_timeCodeSEIEnabled = b; }
   bool  getTimeCodeSEIEnabled()                                      { return m_timeCodeSEIEnabled; }
   void  setNumberOfTimeSets(int value)                               { m_timeCodeSEINumTs = value; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 55fdef4db785a19724d8f19190f8feaad6950448..2f294c1694d82ccb68fb8239e521f0e1655665c7 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -44,6 +44,9 @@
 #include "CommonLib/dtrace_codingstruct.h"
 #include "CommonLib/Picture.h"
 #include "CommonLib/UnitTools.h"
+#if JVET_M0445_MCTS
+#include "MCTS.h"
+#endif
 
 
 #include "CommonLib/dtrace_buffer.h"
@@ -2612,6 +2615,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       }
       PU::spanMotionInfo( pu, mergeCtx );
 
+#if JVET_M0445_MCTS 
+      if( m_pcEncCfg->getMCTSEncConstraint() && ( !( MCTSHelper::checkMvBufferForMCTSConstraint( pu ) ) ) )
+      {
+        // Do not use this mode
+        tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+        continue;
+      }
+#endif
       if( mrgTempBufSet )
       {
 #if JVET_M0147_DMVR
@@ -2697,7 +2708,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 
       if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip && !pu.mhIntraFlag)
       {
+#if JVET_M0445_MCTS
+        bestIsSkip = !bestCS->cus.empty() && bestCS->getCU( partitioner.chType )->rootCbf == 0;
+#else
         bestIsSkip = bestCS->getCU( partitioner.chType )->rootCbf == 0;
+#endif
       }
       tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
     }// end loop uiMrgHADIdx
@@ -2807,6 +2822,14 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
       triangleMrgCtx.setMergeInfo( pu, mergeCand );
       PU::spanMotionInfo( pu, triangleMrgCtx );
 
+#if JVET_M0445_MCTS
+      if( m_pcEncCfg->getMCTSEncConstraint() && ( !( MCTSHelper::checkMvBufferForMCTSConstraint( pu ) ) ) )
+      {
+        // Do not use this mode
+        tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+        return;
+      }
+#endif      
       m_pcInterSearch->motionCompensation( pu, triangleBuffer[mergeCand] );
     }
   }
@@ -3012,6 +3035,14 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
         PU::spanTriangleMotionInfo(pu, triangleMrgCtx, mergeCand, splitDir, candIdx0, candIdx1 );
 #endif
 
+#if JVET_M0445_MCTS
+        if( m_pcEncCfg->getMCTSEncConstraint() && ( !( MCTSHelper::checkMvBufferForMCTSConstraint( *cu.firstPU ) ) ) )
+        {
+          // Do not use this mode
+          tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+          return;
+        }
+#endif
         if( tempBufSet )
         {
           tempCS->getPredBuf().copyFrom( triangleWeightedBuffer[mergeCand] );
@@ -3293,6 +3324,14 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
         PU::spanMotionInfo( pu );
       }
 
+#if JVET_M0445_MCTS
+      if( m_pcEncCfg->getMCTSEncConstraint() && ( !( MCTSHelper::checkMvBufferForMCTSConstraint( *cu.firstPU ) ) ) )
+      {
+        // Do not use this mode
+        tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+        return;
+      }
+#endif
       if ( mrgTempBufSet )
       {
         tempCS->getPredBuf().copyFrom( acMergeBuffer[uiMergeCand] );
@@ -4228,6 +4267,14 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be
 #endif
   }
 
+#if JVET_M0445_MCTS 
+  if( m_pcEncCfg->getMCTSEncConstraint() && ( ( cu.firstPU->refIdx[L0] < 0 && cu.firstPU->refIdx[L1] < 0 ) || ( !( MCTSHelper::checkMvBufferForMCTSConstraint( *cu.firstPU ) ) ) ) )
+  {
+    // Do not use this mode
+    tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+    continue;
+  }
+#endif
   if( testGbi && gbiIdx == GBI_DEFAULT ) // Enabled GBi but the search results is uni.
   {
     tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 6dd2b484302b4bd7c4a41556e14d1c79f38d8ccb..775413103b4db2af56a0ee732bacd93e33130c36 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -1492,9 +1492,13 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
     if (cs.sps->getIBCMode() && !cuECtx.bestTU)
 #endif
       return true;
+ #if !JVET_M0445_MCTS
     CHECK( !slice.isIntra() && !cuECtx.bestTU, "No possible non-intra encoding for a P- or B-slice found" );
 
     if( !( slice.isIRAP() || bestMode.type == ETM_INTRA ||
+#else
+    if( !( slice.isIRAP() || bestMode.type == ETM_INTRA || !cuECtx.bestTU ||
+#endif
 #if JVET_M0483_IBC
       ((!m_pcEncCfg->getDisableIntraPUsInInterSlices()) && (!relatedCU.isInter || !relatedCU.isIBC) && (
 #else
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index a9d137a9fc0801ee4677e5f3f982b2ac8d36cc6e..ed3246256d25cd7e9d0f644fb8b8d03d04335384 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -1663,6 +1663,12 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
       m_pcCuEncoder->setDecCuReshaperInEncCU(m_pcLib->getReshaper(), pcSlice->getSPS()->getChromaFormatIdc());
     }
 #endif
+#if JVET_M0445_MCTS
+    if( !cs.slice->isIntra() && pCfg->getMCTSEncConstraint() )
+    {
+      pcPic->mctsInfo.init( &cs, ctuRsAddr );
+    }
+#endif
 
 #if JVET_M0055_DEBUG_CTU
   if (pCfg->getSwitchPOC() != pcPic->poc || ctuRsAddr >= pCfg->getDebugCTU())
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index b4fe070d4f7dfb0ae90019bb0512d7f8d990561f..a21dcc20e30b66309f139112c66dc66b069cc297 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -45,6 +45,9 @@
 #include "CommonLib/UnitTools.h"
 #include "CommonLib/dtrace_next.h"
 #include "CommonLib/dtrace_buffer.h"
+#if JVET_M0445_MCTS
+#include "CommonLib/MCTS.h"
+#endif
 
 #include "EncModeCtrl.h"
 #include "EncLib.h"
@@ -1945,7 +1948,11 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
   AMVPInfo     aacAMVPInfo[2][33];
 
   int          iRefIdx[2]={0,0}; //If un-initialized, may cause SEGV in bi-directional prediction iterative stage.
+#if JVET_M0445_MCTS
+  int          iRefIdxBi[2] = { -1, -1 };
+#else
   int          iRefIdxBi[2];
+#endif
 
   uint32_t         uiMbBits[3] = {1, 1, 0};
 
@@ -2149,6 +2156,9 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
         && (cu.slice->getCheckLDC() || gbiIdx == GBI_DEFAULT || !m_affineModeSelected || !m_pcEncCfg->getUseGBiFast())
         )
       {
+#if JVET_M0445_MCTS
+        bool doBiPred = true;
+#endif
         cMvBi[0] = cMv[0];
         cMvBi[1] = cMv[1];
         iRefIdxBi[0] = iRefIdx[0];
@@ -2172,6 +2182,21 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
           pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1];
           pu.mvpIdx[REF_PIC_LIST_1] = bestBiPMvpL1;
 
+#if JVET_M0445_MCTS
+            if( m_pcEncCfg->getMCTSEncConstraint() )
+            {
+              Mv restrictedMv = pu.mv[REF_PIC_LIST_1];
+              Area curTileAreaRestricted;
+              curTileAreaRestricted = pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu );
+              MCTSHelper::clipMvToArea( restrictedMv, pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+              // If sub-pel filter samples are not inside of allowed area
+              if( restrictedMv != pu.mv[REF_PIC_LIST_1] )
+              {
+                uiCostBi = std::numeric_limits<Distortion>::max();
+                doBiPred = false;
+              }
+            }
+#endif
           PelUnitBuf predBufTmp = m_tmpPredStorage[REF_PIC_LIST_1].getBuf( UnitAreaRelative(cu, pu) );
           motionCompensation( pu, predBufTmp, REF_PIC_LIST_1 );
 
@@ -2200,6 +2225,10 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
           uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
         }
 
+#if JVET_M0445_MCTS
+        if( doBiPred )
+        {
+#endif
         // 4-times iteration (default)
         int iNumIter = 4;
 
@@ -2330,6 +2359,9 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
             break;
           }
         } // for loop-iter
+#if JVET_M0445_MCTS
+        }
+#endif
         cu.refIdxBi[0] = iRefIdxBi[0];
         cu.refIdxBi[1] = iRefIdxBi[1];
 
@@ -2425,6 +2457,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
           symCost += m_pcRdCost->getCost(bits);
           cTarMvField.setMvField(cCurMvField.mv.getSymmvdMv(cMvPredSym[curRefList], cMvPredSym[tarRefList]), refIdxTar);
 
+#if JVET_M0445_MCTS
+          if( m_pcEncCfg->getMCTSEncConstraint() )
+          {
+            if( !( MCTSHelper::checkMvForMCTSConstraint( pu, cCurMvField.mv ) && MCTSHelper::checkMvForMCTSConstraint( pu, cTarMvField.mv ) ) )
+              symCost = std::numeric_limits<Distortion>::max();
+          }
+#endif
           // save results
           if ( symCost < uiCostBi )
           {
@@ -2648,6 +2687,15 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
         uiAffineCost += m_pcRdCost->getCost( 1 ); // add one bit for affine_type
       }
 
+#if JVET_M0445_MCTS
+      if( uiAffineCost < uiHevcCost )
+      {
+        if( m_pcEncCfg->getMCTSEncConstraint() && !MCTSHelper::checkMvBufferForMCTSConstraint( pu ) )
+        {
+          uiAffineCost = std::numeric_limits<Distortion>::max();
+        }
+      }
+#endif
       if ( uiHevcCost <= uiAffineCost )
       {
         // set hevc me result
@@ -3086,6 +3134,20 @@ void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Ref
   // sub-pel refinement for sub-pel resolution
   if( pu.cu->imv == 0 )
   {
+#if JVET_M0445_MCTS
+    if( m_pcEncCfg->getMCTSEncConstraint() )
+    {
+      Area curTileAreaSubPelRestricted = pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu );
+      Area targetArea = pu.cu->Y();
+      targetArea.repositionTo( targetArea.offset( rcMv.getHor(), rcMv.getVer() ) );
+      // If sub-pel filter samples are not inside of allowed area
+      // Variant 1: clip full-pel vector, do sub-pel refinement for clipped MV
+      if( !curTileAreaSubPelRestricted.contains( targetArea ) )
+      {
+        MCTSHelper::clipMvToArea( rcMv, pu.cu->Y(), curTileAreaSubPelRestricted, *pu.cs->sps, 0 );
+      }
+    }
+#endif
     xPatternSearchFracDIF( pu, eRefPicList, iRefIdxPred, cStruct, rcMv, cMvHalf, cMvQter, ruiCost );
     m_pcRdCost->setCostScale( 0 );
     rcMv <<= 2;
@@ -3121,12 +3183,29 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu,
   Mv mvTL(cFPMvPred.getHor() - (iSrchRng << iMvShift), cFPMvPred.getVer() - (iSrchRng << iMvShift));
   Mv mvBR(cFPMvPred.getHor() + (iSrchRng << iMvShift), cFPMvPred.getVer() + (iSrchRng << iMvShift));
 
+#if JVET_M0445_MCTS
+  if (m_pcEncCfg->getMCTSEncConstraint())
+  {
+    MCTSHelper::clipMvToArea( mvTL, pu.Y(), pu.cs->picture->mctsInfo.getTileArea(), *pu.cs->sps );
+    MCTSHelper::clipMvToArea( mvBR, pu.Y(), pu.cs->picture->mctsInfo.getTileArea(), *pu.cs->sps );
+  }
+  else
+  {
+    xClipMv( mvTL, pu.cu->lumaPos(),
+            pu.cu->lumaSize(),
+            *pu.cs->sps );
+    xClipMv( mvBR, pu.cu->lumaPos(),
+            pu.cu->lumaSize(),
+            *pu.cs->sps );
+  }
+#else
   xClipMv( mvTL, pu.cu->lumaPos(),
           pu.cu->lumaSize(),
           *pu.cs->sps );
   xClipMv( mvBR, pu.cu->lumaPos(),
           pu.cu->lumaSize(),
           *pu.cs->sps );
+#endif
 
   mvTL.divideByPowerOf2( iMvShift );
   mvBR.divideByPowerOf2( iMvShift );
@@ -3270,6 +3349,13 @@ void InterSearch::xTZSearch( const PredictionUnit& pu,
 
   int iSearchRange = m_iSearchRange;
   rcMv.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
+#if JVET_M0445_MCTS
+  if( m_pcEncCfg->getMCTSEncConstraint() )
+  {
+    MCTSHelper::clipMvToArea( rcMv, pu.Y(), pu.cs->picture->mctsInfo.getTileArea(), *pu.cs->sps );
+  }
+  else
+#endif
   clipMv( rcMv, pu.cu->lumaPos(),
           pu.cu->lumaSize(),
           *pu.cs->sps );
@@ -3306,6 +3392,13 @@ void InterSearch::xTZSearch( const PredictionUnit& pu,
   {
     Mv integerMv2Nx2NPred = *pIntegerMv2Nx2NPred;
     integerMv2Nx2NPred.changePrecision(MV_PRECISION_INT, MV_PRECISION_INTERNAL);
+#if JVET_M0445_MCTS
+    if( m_pcEncCfg->getMCTSEncConstraint() )
+    {
+      MCTSHelper::clipMvToArea( integerMv2Nx2NPred, pu.Y(), pu.cs->picture->mctsInfo.getTileArea(), *pu.cs->sps );
+    }
+    else
+#endif
     clipMv( integerMv2Nx2NPred, pu.cu->lumaPos(),
             pu.cu->lumaSize(),
             *pu.cs->sps );
@@ -3758,14 +3851,37 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct&
       cTestMv[iMVPIdx] += cBaseMvd[iMVPIdx];
       cTestMv[iMVPIdx] += amvpInfo.mvCand[iMVPIdx];
 
+#if JVET_M0445_MCTS
+      // MCTS and IMV
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        Mv cTestMVRestr = cTestMv[iMVPIdx];
+        cTestMVRestr.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL );
+        MCTSHelper::clipMvToArea( cTestMVRestr, pu.cu->Y(), pu.cs->picture->mctsInfo.getTileAreaIntPelRestricted( pu ), *pu.cs->sps );
+        cTestMVRestr.changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER );
+
+        if( cTestMVRestr != cTestMv[iMVPIdx] )
+        {
+          // Skip this IMV pos, cause clipping affects IMV scaling
+          continue;
+        }
+      }
+#endif
       if ( iMVPIdx == 0 || cTestMv[0] != cTestMv[1])
       {
         Mv cTempMV = cTestMv[iMVPIdx];
+#if JVET_M0445_MCTS
+        if( !m_pcEncCfg->getMCTSEncConstraint() )
+        {
+#endif
         cTempMV.changePrecision(MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL);
         clipMv(cTempMV, pu.cu->lumaPos(),
                pu.cu->lumaSize(),
                sps);
         cTempMV.changePrecision(MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER);
+#if JVET_M0445_MCTS
+        }
+#endif
         m_cDistParam.cur.buf = cStruct.piRefY  + cStruct.iRefStride * (cTempMV.getVer() >>  2) + (cTempMV.getHor() >> 2);
         uiDist = uiSATD = (Distortion) (m_cDistParam.distFunc( m_cDistParam ) * fWeight);
       }
@@ -3788,6 +3904,13 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct&
       }
     }
   }
+#if JVET_M0445_MCTS
+  if( uiBestDist == std::numeric_limits<Distortion>::max() )
+  {
+    ruiCost = std::numeric_limits<Distortion>::max();
+    return;
+  }
+#endif
 
   rcMv = cBestMv;
   rcMvPred = amvpInfo.mvCand[iBestMVPIdx];
@@ -3961,6 +4084,13 @@ Distortion InterSearch::xSymmeticRefineMvSearch( PredictionUnit &pu, PelUnitBuf&
       MvField mvCand = mvCurCenter, mvPair;
       mvCand.mv += mvOffset;
 
+#if JVET_M0445_MCTS
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        if( !( MCTSHelper::checkMvForMCTSConstraint( pu, mvCand.mv ) ) )
+          continue; // Skip this this pos
+      }
+#endif
       // get MVD cost
       m_pcRdCost->setPredictor( rcMvCurPred );
       m_pcRdCost->setCostScale( 0 );
@@ -3970,6 +4100,13 @@ Distortion InterSearch::xSymmeticRefineMvSearch( PredictionUnit &pu, PelUnitBuf&
       // get MVD pair and set target MV
       mvPair.refIdx = rTarMvField.refIdx;
       mvPair.mv.set( rcMvTarPred.hor - (mvCand.mv.hor - rcMvCurPred.hor), rcMvTarPred.ver - (mvCand.mv.ver - rcMvCurPred.ver) );
+#if JVET_M0445_MCTS
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        if( !( MCTSHelper::checkMvForMCTSConstraint( pu, mvPair.mv ) ) )
+          continue; // Skip this this pos
+      }
+#endif
       uiCost += xGetSymmetricCost( pu, origBuf, eRefPicList, mvCand, mvPair, gbiIdx );
       if ( uiCost < uiMinCost )
       {
@@ -4515,6 +4652,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
     ::memcpy( aaiMvpIdxBi, aaiMvpIdx, sizeof(aaiMvpIdx) );
 
     uint32_t uiMotBits[2];
+#if JVET_M0445_MCTS
+    bool doBiPred = true;
+#endif
 
     if ( slice.getMvdL1ZeroFlag() ) // GPB, list 1 only use Mvp
     {
@@ -4531,6 +4671,27 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
       ::memcpy( cMvTemp[1][bestBiPRefIdxL1],   pcMvTemp, sizeof(Mv)*3 );
       iRefIdxBi[1] = bestBiPRefIdxL1;
 
+#if JVET_M0445_MCTS
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        Area curTileAreaRestricted;
+        curTileAreaRestricted = pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu );
+        for( int i = 0; i < mvNum; i++ )
+        {
+          Mv restrictedMv = pcMvTemp[i];
+          restrictedMv.changePrecision( MV_PRECISION_QUARTER, MV_PRECISION_INTERNAL );
+          MCTSHelper::clipMvToArea( restrictedMv, pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+          restrictedMv.changePrecision( MV_PRECISION_INTERNAL, MV_PRECISION_QUARTER );
+
+          // If sub-pel filter samples are not inside of allowed area
+          if( restrictedMv != pcMvTemp[i] )
+          {
+            uiCostBi = std::numeric_limits<Distortion>::max();
+            doBiPred = false;
+          }
+        }
+      }
+#endif
       // Get list1 prediction block
       PU::setAllAffineMv( pu, cMvBi[1][0], cMvBi[1][1], cMvBi[1][2], REF_PIC_LIST_1
 #if JVET_M0246_AFFINE_AMVR
@@ -4566,6 +4727,10 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
       uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
     }
 
+#if JVET_M0445_MCTS
+    if( doBiPred )
+    {
+#endif
     // 4-times iteration (default)
     int iNumIter = 4;
     // fast encoder setting or GPB: only one iteration
@@ -4713,6 +4878,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
         break;
       }
     } // for loop-iter
+#if JVET_M0445_MCTS
+    }
+#endif
   } // if (B_SLICE)
 
   pu.mv    [REF_PIC_LIST_0] = Mv();
@@ -5094,6 +5262,19 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu,
   uint32_t uiBitsBest = 0;
 
   // do motion compensation with origin mv
+#if JVET_M0445_MCTS
+  if( m_pcEncCfg->getMCTSEncConstraint() )
+  {
+    Area curTileAreaRestricted = pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu );
+    MCTSHelper::clipMvToArea( acMvTemp[0], pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+    MCTSHelper::clipMvToArea( acMvTemp[1], pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+    if( pu.cu->affineType == AFFINEMODEL_6PARAM )
+    {
+      MCTSHelper::clipMvToArea( acMvTemp[2], pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+    }
+  }
+  else
+#endif
   clipMv( acMvTemp[0], pu.cu->lumaPos(),
           pu.cu->lumaSize(),
           *pu.cs->sps );
@@ -5336,6 +5517,20 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu,
       {
         acMvTemp[i].roundToPrecision( MV_PRECISION_INTERNAL, MV_PRECISION_INT );
       }
+#endif
+#if JVET_M0445_MCTS
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        MCTSHelper::clipMvToArea( acMvTemp[i], pu.cu->Y(), pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu ), *pu.cs->sps );
+      }
+      else
+#endif
+#if JVET_M0445_MCTS
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        MCTSHelper::clipMvToArea( acMvTemp[i], pu.cu->Y(), pu.cs->picture->mctsInfo.getTileAreaSubPelRestricted( pu ), *pu.cs->sps );
+      }
+      else
 #endif
       clipMv(acMvTemp[i], pu.cu->lumaPos(),
              pu.cu->lumaSize(),
diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp
index 485a25e8e5ae6f97a7e6c85d8d88eba78c6f86b9..6ecc3e20810d7afe759c770fd7e68a9a380b8ae9 100644
--- a/source/Lib/EncoderLib/SEIEncoder.cpp
+++ b/source/Lib/EncoderLib/SEIEncoder.cpp
@@ -359,6 +359,18 @@ void SEIEncoder::initSEITempMotionConstrainedTileSets (SEITempMotionConstrainedT
 
   if(pps->getTilesEnabledFlag())
   {
+#if JVET_M0445_MCTS
+    if (m_pcCfg->getMCTSEncConstraint())
+    {
+      sei->m_mc_all_tiles_exact_sample_value_match_flag = true;
+      sei->m_each_tile_one_tile_set_flag = true;
+      sei->m_limited_tile_set_display_flag = false;
+      sei->m_max_mcs_tier_level_idc_present_flag = false;
+      sei->setNumberOfTileSets(0);
+    }
+    else
+    {
+#endif
     sei->m_mc_all_tiles_exact_sample_value_match_flag = false;
     sei->m_each_tile_one_tile_set_flag                = false;
     sei->m_limited_tile_set_display_flag              = false;
@@ -379,6 +391,9 @@ void SEIEncoder::initSEITempMotionConstrainedTileSets (SEITempMotionConstrainedT
       sei->tileSetData(i).m_mcts_tier_level_idc_present_flag = false;
     }
   }
+#if JVET_M0445_MCTS
+  }
+#endif
   else
   {
     CHECK(!(!"Tile is not enabled"), "Unspecified error");