From eee3d81519d949e912e75d3155d6c72eabaf1f11 Mon Sep 17 00:00:00 2001
From: Valeri George <valeri.george@hhi.fraunhofer.de>
Date: Sun, 13 Jan 2019 11:52:50 +0100
Subject: [PATCH 72/72] My squashed commits

---
 cfg/encoder_lowdelay_vtm_tiles.cfg         | 156 ++++++++++++++++++
 cfg/encoder_randomaccess_vtm_tiles.cfg     | 171 ++++++++++++++++++++
 source/App/DecoderApp/DecApp.cpp           |   8 +-
 source/App/DecoderApp/DecAppCfg.cpp        |  10 ++
 source/App/DecoderApp/DecAppCfg.h          |   3 +
 source/App/DecoderApp/decmain.cpp          |   6 +
 source/App/EncoderApp/EncApp.cpp           |   3 +
 source/App/EncoderApp/EncAppCfg.cpp        |  27 ++++
 source/App/EncoderApp/EncAppCfg.h          |   4 +
 source/App/EncoderApp/encmain.cpp          |   3 +
 source/Lib/CommonLib/CodingStructure.cpp   |   8 +
 source/Lib/CommonLib/CodingStructure.h     |  11 +-
 source/Lib/CommonLib/CprHashMap.cpp        |   2 +-
 source/Lib/CommonLib/InterPrediction.cpp   | 245 ++++++++++++++++++++++++++++-
 source/Lib/CommonLib/InterPrediction.h     |  65 ++++++++
 source/Lib/CommonLib/Mv.cpp                |  15 ++
 source/Lib/CommonLib/Mv.h                  |   3 +
 source/Lib/CommonLib/Picture.cpp           |  98 ++++++++++++
 source/Lib/CommonLib/Picture.h             |  12 +-
 source/Lib/CommonLib/Rom.cpp               |   9 ++
 source/Lib/CommonLib/Rom.h                 |  10 ++
 source/Lib/CommonLib/Slice.h               |  14 ++
 source/Lib/CommonLib/TypeDef.h             |  13 ++
 source/Lib/CommonLib/Unit.cpp              |  12 ++
 source/Lib/CommonLib/Unit.h                |   8 +
 source/Lib/CommonLib/UnitTools.cpp         |  60 ++++++-
 source/Lib/CommonLib/UnitTools.h           |   7 +
 source/Lib/CommonLib/dtrace.h              |  50 ++++++
 source/Lib/CommonLib/dtrace_codingstruct.h | 181 +++++++++++++++++++++
 source/Lib/CommonLib/dtrace_next.h         |  17 +-
 source/Lib/DecoderLib/CABACReader.cpp      |  46 +++++-
 source/Lib/DecoderLib/DecCu.cpp            |  11 ++
 source/Lib/DecoderLib/DecLib.cpp           |   4 +
 source/Lib/DecoderLib/DecSlice.cpp         |   8 +-
 source/Lib/DecoderLib/VLCReader.cpp        |   1 +
 source/Lib/EncoderLib/CABACWriter.cpp      |   7 +-
 source/Lib/EncoderLib/EncCfg.h             |   7 +
 source/Lib/EncoderLib/EncCu.cpp            |  62 +++++++-
 source/Lib/EncoderLib/EncGOP.cpp           |   1 -
 source/Lib/EncoderLib/EncLib.cpp           |   4 +
 source/Lib/EncoderLib/EncModeCtrl.cpp      |   9 ++
 source/Lib/EncoderLib/EncSlice.cpp         |   9 ++
 source/Lib/EncoderLib/InterSearch.cpp      | 211 +++++++++++++++++++++++--
 source/Lib/EncoderLib/InterSearch.h        |   4 +
 source/Lib/EncoderLib/SEIEncoder.cpp       |  16 ++
 45 files changed, 1590 insertions(+), 41 deletions(-)
 create mode 100644 cfg/encoder_lowdelay_vtm_tiles.cfg
 create mode 100644 cfg/encoder_randomaccess_vtm_tiles.cfg

diff --git a/cfg/encoder_lowdelay_vtm_tiles.cfg b/cfg/encoder_lowdelay_vtm_tiles.cfg
new file mode 100644
index 0000000..bc25915
--- /dev/null
+++ b/cfg/encoder_lowdelay_vtm_tiles.cfg
@@ -0,0 +1,156 @@
+#======== File I/O =====================
+BitstreamFile                 : str.bin
+ReconFile                     : rec.yuv
+
+#======== Profile ================
+Profile                       : next
+
+#======== Unit definition ================
+MaxCUWidth                    : 64          # Maximum coding unit width in pixel
+MaxCUHeight                   : 64          # Maximum coding unit height in pixel
+MaxPartitionDepth             : 4           # Maximum coding unit depth
+# obsoleted by TULog2MaxSize
+#QuadtreeTULog2MinSize         : 2           # Log2 of minimum transform size for
+#                                            # quadtree-based TU coding (2...6)
+QuadtreeTUMaxDepthInter       : 3
+QuadtreeTUMaxDepthIntra       : 3
+
+#======== Coding Structure =============
+IntraPeriod                   : -1          # Period of I-Frame ( -1 = only first)
+DecodingRefreshType           : 0           # Random Accesss 0:none, 1:CRA, 2:IDR, 3:Recovery Point SEI
+GOPSize                       : 4           # GOP Size (number of B slice = GOPSize-1)
+
+IntraQPOffset                 : -1
+LambdaFromQpEnable            : 1           # see JCTVC-X0038 for suitable parameters for IntraQPOffset, QPoffset, QPOffsetModelOff, QPOffsetModelScale when enabled
+#        Type POC QPoffset QPOffsetModelOff QPOffsetModelScale CbQPoffset CrQPoffset QPfactor tcOffsetDiv2 betaOffsetDiv2 temporal_id #ref_pics_active #ref_pics reference pictures     predict deltaRPS #ref_idcs reference idcs
+Frame1:  B    1   5       -6.5                      0.2590         0          0          1.0      0            0               0           4                4         -1 -5 -9 -13       0
+Frame2:  B    2   4       -6.5                      0.2590         0          0          1.0      0            0               0           4                4         -1 -2 -6 -10       1      -1       5         1 1 1 0 1
+Frame3:  B    3   5       -6.5                      0.2590         0          0          1.0      0            0               0           4                4         -1 -3 -7 -11       1      -1       5         0 1 1 1 1
+Frame4:  B    4   1        0.0                      0.0            0          0          1.0      0            0               0           4                4         -1 -4 -8 -12       1      -1       5         0 1 1 1 1
+
+#=========== Motion Search =============
+FastSearch                    : 1           # 0:Full search  1:TZ search
+SearchRange                   : 64          # (0: Search range is a Full frame)
+BipredSearchRange             : 4           # Search range for bi-prediction refinement
+HadamardME                    : 1           # Use of hadamard measure for fractional ME
+FEN                           : 1           # Fast encoder decision
+FDM                           : 1           # Fast Decision for Merge RD cost
+
+#======== Quantization =============
+QP                            : 32          # Quantization parameter(0-51)
+MaxDeltaQP                    : 0           # CU-based multi-QP optimization
+MaxCuDQPDepth                 : 0           # Max depth of a minimum CuDQP for sub-LCU-level delta QP
+DeltaQpRD                     : 0           # Slice-based multi-QP optimization
+RDOQ                          : 1           # RDOQ
+RDOQTS                        : 1           # RDOQ for transform skip
+
+#=========== Deblock Filter ============
+LoopFilterOffsetInPPS         : 1           # Dbl params: 0=varying params in SliceHeader, param = base_param + GOP_offset_param; 1 (default) =constant params in PPS, param = base_param)
+LoopFilterDisable             : 0           # Disable deblocking filter (0=Filter, 1=No Filter)
+LoopFilterBetaOffset_div2     : 0           # base_param: -6 ~ 6
+LoopFilterTcOffset_div2       : 0           # base_param: -6 ~ 6
+DeblockingFilterMetric        : 0           # blockiness metric (automatically configures deblocking parameters in bitstream). Applies slice-level loop filter offsets (LoopFilterOffsetInPPS and LoopFilterDisable must be 0)
+
+#=========== Misc. ============
+InternalBitDepth              : 10          # codec operating bit-depth
+
+#=========== Coding Tools =================
+SAO                           : 1           # Sample adaptive offset  (0: OFF, 1: ON)
+AMP                           : 1           # Asymmetric motion partitions (0: OFF, 1: ON)
+TransformSkip                 : 1           # Transform skipping (0: OFF, 1: ON)
+TransformSkipFast             : 1           # Fast Transform skipping (0: OFF, 1: ON)
+SAOLcuBoundary                : 0           # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON)
+
+#============ Slices ================
+SliceMode                : 0                # 0: Disable all slice options.
+                                            # 1: Enforce maximum number of LCU in an slice,
+                                            # 2: Enforce maximum number of bytes in an 'slice'
+                                            # 3: Enforce maximum number of tiles in a slice
+SliceArgument            : 1500             # Argument for 'SliceMode'.
+                                            # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice.
+                                            # If SliceMode==2 it represents max. bytes per slice.
+                                            # If SliceMode==3 it represents max. tiles per slice.
+
+LFCrossSliceBoundaryFlag : 1                # In-loop filtering, including ALF and DB, is across or not across slice boundary.
+                                            # 0:not across, 1: across
+
+#============ PCM ================
+PCMEnabledFlag                      : 0                # 0: No PCM mode
+PCMLog2MaxSize                      : 5                # Log2 of maximum PCM block size.
+PCMLog2MinSize                      : 3                # Log2 of minimum PCM block size.
+PCMInputBitDepthFlag                : 1                # 0: PCM bit-depth is internal bit-depth. 1: PCM bit-depth is input bit-depth.
+PCMFilterDisableFlag                : 0                # 0: Enable loop filtering on I_PCM samples. 1: Disable loop filtering on I_PCM samples.
+
+#============ Tiles ================
+TileUniformSpacing                  : 1                # 0: the column boundaries are indicated by TileColumnWidth array, the row boundaries are indicated by TileRowHeight array
+                                                       # 1: the column and row boundaries are distributed uniformly
+NumTileColumnsMinus1                : 1                # Number of tile columns in a picture minus 1
+TileColumnWidthArray                : 2 3              # Array containing tile column width values in units of CTU (from left to right in picture)
+NumTileRowsMinus1                   : 1                # Number of tile rows in a picture minus 1
+TileRowHeightArray                  : 2                # Array containing tile row height values in units of CTU (from top to bottom in picture)
+
+LFCrossTileBoundaryFlag             : 0                # In-loop filtering is across or not across tile boundary.
+                                                       # 0:not across, 1: across
+
+#MCTSEncConstraint                   : 1
+
+#============ Lossless ================
+TransquantBypassEnable     : 0                         # Value of PPS flag.
+CUTransquantBypassFlagForce: 0                         # Force transquant bypass mode, when transquant_bypass_enable_flag is enabled
+
+#============ Rate Control ======================
+RateControl                         : 0                # Rate control: enable rate control
+TargetBitrate                       : 1000000          # Rate control: target bitrate, in bps
+KeepHierarchicalBit                 : 2                # Rate control: 0: equal bit allocation; 1: fixed ratio bit allocation; 2: adaptive ratio bit allocation
+LCULevelRateControl                 : 1                # Rate control: 1: LCU level RC; 0: picture level RC
+RCLCUSeparateModel                  : 1                # Rate control: use LCU level separate R-lambda model
+InitialQP                           : 0                # Rate control: initial QP
+RCForceIntraQP                      : 0                # Rate control: force intra QP to be equal to initial QP
+
+#============ JEM settings ======================
+LoopFilterTcOffset_div2             : 0
+SEIDecodedPictureHash               : 0
+CbQpOffset                          : 0
+CrQpOffset                          : 0
+
+#============ NEXT ====================
+
+# General
+LargeCTU                     : 1      # Large CTU
+CTUSize                      : 128
+LCTUFast                     : 1
+QuadtreeTULog2MaxSize        : 6
+
+DualITree                    : 1      # separate partitioning of luma and chroma channels for I-slices
+MinQTLumaISlice              : 8
+MinQTChromaISlice            : 4
+MinQTNonISlice               : 8
+MaxBTDepth                   : 3
+MaxBTDepthISliceL            : 3
+MaxBTDepthISliceC            : 3
+MTT                          : 1
+
+EMT                          : 1
+EMTFast                      : 1
+Affine                       : 1
+SubPuMvp                     : 1
+MaxNumMergeCand              : 6
+LMChroma                     : 1      # use CCLM only
+DepQuant                     : 1
+IMV                          : 2
+ALF                          : 1
+GBi                          : 1 
+GBiFast                      : 1 
+MHIntra                      : 1
+Triangle                     : 1
+CPR                          : 0      # turned off in CTC
+
+# Fast tools
+PBIntraFast                  : 1
+FastMrg                      : 1
+AMaxBT                       : 1
+
+### DO NOT ADD ANYTHING BELOW THIS LINE ###
+### DO NOT DELETE THE EMPTY LINE BELOW ###
+
+
diff --git a/cfg/encoder_randomaccess_vtm_tiles.cfg b/cfg/encoder_randomaccess_vtm_tiles.cfg
new file mode 100644
index 0000000..8ab1035
--- /dev/null
+++ b/cfg/encoder_randomaccess_vtm_tiles.cfg
@@ -0,0 +1,171 @@
+#======== File I/O =====================
+BitstreamFile                 : str.bin
+ReconFile                     : rec.yuv
+
+#======== Profile ================
+Profile                       : next
+
+#======== Unit definition ================
+MaxCUWidth                    : 64          # Maximum coding unit width in pixel
+MaxCUHeight                   : 64          # Maximum coding unit height in pixel
+MaxPartitionDepth             : 4           # Maximum coding unit depth
+# obsoleted by TULog2MaxSize
+#QuadtreeTULog2MinSize         : 2           # Log2 of minimum transform size for
+#                                            # quadtree-based TU coding (2...6)
+QuadtreeTUMaxDepthInter       : 3
+QuadtreeTUMaxDepthIntra       : 3
+
+#======== Coding Structure =============
+IntraPeriod                   : 32          # Period of I-Frame ( -1 = only first)
+DecodingRefreshType           : 1           # Random Accesss 0:none, 1:CRA, 2:IDR, 3:Recovery Point SEI
+GOPSize                       : 16          # GOP Size (number of B slice = GOPSize-1)
+
+IntraQPOffset                 : -3
+LambdaFromQpEnable            : 1           # see JCTVC-X0038 for suitable parameters for IntraQPOffset, QPoffset, QPOffsetModelOff, QPOffsetModelScale when enabled
+#        Type POC QPoffset QPOffsetModelOff QPOffsetModelScale CbQPoffset CrQPoffset QPfactor tcOffsetDiv2 betaOffsetDiv2 temporal_id #ref_pics_active #ref_pics reference pictures     predict deltaRPS #ref_idcs reference idcs
+Frame1:  B   16   1        0.0                      0.0            0          0          1.0      0            0              0           2                3         -16 -24 -32            0
+Frame2:  B    8   1       -4.8848                   0.2061         0          0          1.0      0            0              1           2                3         -8  -16   8            1       8        4         1 1 0 1
+Frame3:  B    4   4       -5.7476                   0.2286         0          0          1.0      0            0              2           2                4         -4  -12   4  12        1       4        4         1 1 1 1
+Frame4:  B    2   5       -5.90                     0.2333         0          0          1.0      0            0              3           2                5         -2  -10   2   6  14    1       2        5         1 1 1 1 1
+Frame5:  B    1   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1    1  3    7  15    1       1        6         1 0 1 1 1 1
+Frame6:  B    3   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1   -3   1   5  13    1      -2        6         1 1 1 1 1 0
+Frame7:  B    6   5       -5.90                     0.2333         0          0          1.0      0            0              3           2                4         -2   -6   2  10        1      -3        6         0 1 1 1 1 0
+Frame8:  B    5   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1   -5   1   3  11    1       1        5         1 1 1 1 1
+Frame9:  B    7   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1   -3  -7   1   9    1      -2        6         1 1 1 1 1 0
+Frame10: B   12   4       -5.7476                   0.2286         0          0          1.0      0            0              2           2                3         -4  -12   4            1      -5        6         0 0 1 1 1 0
+Frame11: B   10   5       -5.90                     0.2333         0          0          1.0      0            0              3           2                4         -2  -10   2   6        1       2        4         1 1 1 1
+Frame12: B    9   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1   -9   1   3   7    1       1        5         1 1 1 1 1
+Frame13: B   11   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1   -3 -11   1   5    1      -2        6         1 1 1 1 1 0
+Frame14: B   14   5       -5.90                     0.2333         0          0          1.0      0            0              3           2                4         -2   -6 -14   2        1      -3        6         0 1 1 1 1 0
+Frame15: B   13   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1   -5 -13   1   3    1       1        5         1 1 1 1 1
+Frame16: B   15   6       -7.1444                   0.3            0          0          1.0      0            0              4           2                5         -1   -3 -7  -15   1    1      -2        6         1 1 1 1 1 0
+
+#=========== Motion Search =============
+FastSearch                    : 1           # 0:Full search  1:TZ search
+SearchRange                   : 384         # (0: Search range is a Full frame)
+ASR                           : 1           # Adaptive motion search range
+MinSearchWindow               : 96          # Minimum motion search window size for the adaptive window ME
+BipredSearchRange             : 4           # Search range for bi-prediction refinement
+HadamardME                    : 1           # Use of hadamard measure for fractional ME
+FEN                           : 1           # Fast encoder decision
+FDM                           : 1           # Fast Decision for Merge RD cost
+
+#======== Quantization =============
+QP                            : 32          # Quantization parameter(0-51)
+MaxDeltaQP                    : 0           # CU-based multi-QP optimization
+MaxCuDQPDepth                 : 0           # Max depth of a minimum CuDQP for sub-LCU-level delta QP
+DeltaQpRD                     : 0           # Slice-based multi-QP optimization
+RDOQ                          : 1           # RDOQ
+RDOQTS                        : 1           # RDOQ for transform skip
+
+#=========== Deblock Filter ============
+LoopFilterOffsetInPPS         : 1           # Dbl params: 0=varying params in SliceHeader, param = base_param + GOP_offset_param; 1 (default) =constant params in PPS, param = base_param)
+LoopFilterDisable             : 0           # Disable deblocking filter (0=Filter, 1=No Filter)
+LoopFilterBetaOffset_div2     : 0           # base_param: -6 ~ 6
+LoopFilterTcOffset_div2       : 0           # base_param: -6 ~ 6
+DeblockingFilterMetric        : 0           # blockiness metric (automatically configures deblocking parameters in bitstream). Applies slice-level loop filter offsets (LoopFilterOffsetInPPS and LoopFilterDisable must be 0)
+
+#=========== Misc. ============
+InternalBitDepth              : 10          # codec operating bit-depth
+
+#=========== Coding Tools =================
+SAO                           : 1           # Sample adaptive offset  (0: OFF, 1: ON)
+AMP                           : 1           # Asymmetric motion partitions (0: OFF, 1: ON)
+TransformSkip                 : 1           # Transform skipping (0: OFF, 1: ON)
+TransformSkipFast             : 1           # Fast Transform skipping (0: OFF, 1: ON)
+SAOLcuBoundary                : 0           # SAOLcuBoundary using non-deblocked pixels (0: OFF, 1: ON)
+
+#============ Slices ================
+SliceMode                : 0                # 0: Disable all slice options.
+                                            # 1: Enforce maximum number of LCU in an slice,
+                                            # 2: Enforce maximum number of bytes in an 'slice'
+                                            # 3: Enforce maximum number of tiles in a slice
+SliceArgument            : 1500             # Argument for 'SliceMode'.
+                                            # If SliceMode==1 it represents max. SliceGranularity-sized blocks per slice.
+                                            # If SliceMode==2 it represents max. bytes per slice.
+                                            # If SliceMode==3 it represents max. tiles per slice.
+
+LFCrossSliceBoundaryFlag : 1                # In-loop filtering, including ALF and DB, is across or not across slice boundary.
+                                            # 0:not across, 1: across
+
+#============ PCM ================
+PCMEnabledFlag                      : 0                # 0: No PCM mode
+PCMLog2MaxSize                      : 5                # Log2 of maximum PCM block size.
+PCMLog2MinSize                      : 3                # Log2 of minimum PCM block size.
+PCMInputBitDepthFlag                : 1                # 0: PCM bit-depth is internal bit-depth. 1: PCM bit-depth is input bit-depth.
+PCMFilterDisableFlag                : 0                # 0: Enable loop filtering on I_PCM samples. 1: Disable loop filtering on I_PCM samples.
+
+#============ Tiles ================
+TileUniformSpacing                  : 1                # 0: the column boundaries are indicated by TileColumnWidth array, the row boundaries are indicated by TileRowHeight array
+                                                       # 1: the column and row boundaries are distributed uniformly
+NumTileColumnsMinus1                : 1                # Number of tile columns in a picture minus 1
+TileColumnWidthArray                : 2 3              # Array containing tile column width values in units of CTU (from left to right in picture)
+NumTileRowsMinus1                   : 1                # Number of tile rows in a picture minus 1
+TileRowHeightArray                  : 2                # Array containing tile row height values in units of CTU (from top to bottom in picture)
+
+LFCrossTileBoundaryFlag             : 0                # In-loop filtering is across or not across tile boundary.
+                                                       # 0:not across, 1: across
+
+#MCTSEncConstraint                   : 1
+
+#============ Lossless ================
+TransquantBypassEnable     : 0                         # Value of PPS flag.
+CUTransquantBypassFlagForce: 0                         # Force transquant bypass mode, when transquant_bypass_enable_flag is enabled
+
+#============ Rate Control ======================
+RateControl                         : 0                # Rate control: enable rate control
+TargetBitrate                       : 1000000          # Rate control: target bitrate, in bps
+KeepHierarchicalBit                 : 2                # Rate control: 0: equal bit allocation; 1: fixed ratio bit allocation; 2: adaptive ratio bit allocation
+LCULevelRateControl                 : 1                # Rate control: 1: LCU level RC; 0: picture level RC
+RCLCUSeparateModel                  : 1                # Rate control: use LCU level separate R-lambda model
+InitialQP                           : 0                # Rate control: initial QP
+RCForceIntraQP                      : 0                # Rate control: force intra QP to be equal to initial QP
+
+#============ JEM settings ======================
+LoopFilterTcOffset_div2             : 0
+SEIDecodedPictureHash               : 0
+CbQpOffset                          : 0
+CrQpOffset                          : 0
+
+#============ NEXT ====================
+
+# General
+LargeCTU                     : 1      # Large CTU
+CTUSize                      : 128
+LCTUFast                     : 1
+QuadtreeTULog2MaxSize        : 6
+
+DualITree                    : 1      # separate partitioning of luma and chroma channels for I-slices
+MinQTLumaISlice              : 8
+MinQTChromaISlice            : 4
+MinQTNonISlice               : 8
+MaxBTDepth                   : 3
+MaxBTDepthISliceL            : 3
+MaxBTDepthISliceC            : 3
+MTT                          : 1
+
+EMT                          : 1
+EMTFast                      : 1
+Affine                       : 1
+SubPuMvp                     : 1
+MaxNumMergeCand              : 6
+LMChroma                     : 1      # use CCLM only
+DepQuant                     : 1
+IMV                          : 2
+ALF                          : 1
+GBi                          : 1 
+GBiFast                      : 1
+BIO                          : 1 
+MHIntra                      : 1
+Triangle                     : 1
+CPR                          : 0      # turned off in CTC
+
+# Fast tools
+PBIntraFast                  : 1
+FastMrg                      : 1
+AMaxBT                       : 1
+
+### DO NOT ADD ANYTHING BELOW THIS LINE ###
+### DO NOT DELETE THE EMPTY LINE BELOW ###
+
+
diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index 3c2f719..eb496f0 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -447,7 +447,9 @@ void DecApp::xWriteOutput( PicList* pcListPic, uint32_t tId )
         {
           dpbFullness--;
         }
-
+#if ENABLE_COMPR_PIC_STAT
+        DTRACE_STAT( *pcPic->cs );
+#endif
 
         if (!m_reconFileName.empty())
         {
@@ -567,7 +569,9 @@ void DecApp::xFlushOutput( PicList* pcListPic )
       if (pcPic->neededForOutput)
       {
         // write to file
-
+#if ENABLE_COMPR_PIC_STAT
+        DTRACE_STAT( *pcPic->cs );
+#endif
         if (!m_reconFileName.empty())
         {
           const Window &conf    = pcPic->cs->sps->getConformanceWindow();
diff --git a/source/App/DecoderApp/DecAppCfg.cpp b/source/App/DecoderApp/DecAppCfg.cpp
index ca55e24..8cf372c 100644
--- a/source/App/DecoderApp/DecAppCfg.cpp
+++ b/source/App/DecoderApp/DecAppCfg.cpp
@@ -112,6 +112,9 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
                                                                                    "\t2: enable tool statistic\n"
                                                                                    "\t3: enable bit and tool statistic\n")
 #endif
+#if 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
   ;
 
   po::setDefaults(opts);
@@ -148,6 +151,10 @@ bool DecAppCfg::parseCfg( int argc, char* argv[] )
   }
 #endif
 
+#if 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 +237,9 @@ DecAppCfg::DecAppCfg()
 , m_bClipOutputVideoToRec709Range(false)
 , m_packedYUVMode(false)
 , m_statMode(0)
+#if 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 7b370eb..c803b2c 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 MCTS_DEC_CHECK
+  bool          m_mctsCheck;
+#endif
 
 public:
   DecAppCfg();
diff --git a/source/App/DecoderApp/decmain.cpp b/source/App/DecoderApp/decmain.cpp
index 698eaa6..30aa59d 100644
--- a/source/App/DecoderApp/decmain.cpp
+++ b/source/App/DecoderApp/decmain.cpp
@@ -66,6 +66,12 @@ int main(int argc, char* argv[])
   df::program_options_lite::scanArgv( optsSimd, argc, ( const char** ) argv, err );
   fprintf( stdout, "[SIMD=%s] ", read_x86_extension( SIMD ) );
 #endif
+#if MCTS_DEC_CHECK
+  fprintf( stdout, "[MCTS_DEC_CHECK] " );
+#endif
+#if MCTS_REC_CHECK
+  fprintf( stdout, "[MCTS_REC_CHECK] " );
+#endif
 #if ENABLE_TRACING
   fprintf( stdout, "[ENABLE_TRACING] " );
 #endif
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index ceddaf7..3672ef4 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -424,6 +424,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setSOPDescriptionSEIEnabled                          ( m_SOPDescriptionSEIEnabled );
   m_cEncLib.setScalableNestingSEIEnabled                         ( m_scalableNestingSEIEnabled );
   m_cEncLib.setTMCTSSEIEnabled                                   ( m_tmctsSEIEnabled );
+#if MCTS_ENC_CONTSTRAINT
+  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 bf8b618..6c63f70 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -1273,6 +1273,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 MCTS_ENC_CONTSTRAINT
+  ("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\")")
@@ -2797,6 +2800,30 @@ bool EncAppCfg::xCheckParameter()
 #endif
   }
 
+#if MCTS_ENC_CONTSTRAINT
+  g_mctsEncConstraint = m_MCTSEncConstraint;
+  if ((m_MCTSEncConstraint) && (m_bLFCrossTileBoundaryFlag))
+  {
+    printf("Warning: Constrained Encoding for Temporal Motion Constrained Tile Sets is enabled. Disabling filtering across tile boundaries!\n");
+    m_bLFCrossTileBoundaryFlag = false;
+  }
+  if ((m_MCTSEncConstraint) && (m_TMVPModeId))
+  {
+    printf("Warning: Constrained Encoding for Temporal Motion Constrained Tile Sets is enabled. Disabling TMVP!\n");
+    m_TMVPModeId = 0;
+  }
+  if ((m_MCTSEncConstraint) && ( m_alf ))
+  {
+    printf("Warning: Constrained Encoding for Temporal Motion Constrained Tile Sets is enabled. Disabling ALF!\n");
+    m_alf = false;
+  }
+  if( ( m_MCTSEncConstraint ) && ( m_BIO ) )
+  {
+    printf( "Warning: Constrained Encoding for Temporal Motion Constrained Tile Sets is enabled. Disabling BIO!\n" );
+    m_BIO = false;
+  }
+#endif
+
 
   if (m_toneMappingInfoSEIEnabled)
   {
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 6737b13..412837c 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -449,6 +449,10 @@ protected:
   uint32_t      m_greenMetadataType;
   uint32_t      m_xsdMetricType;
 
+#if MCTS_ENC_CONTSTRAINT
+  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/App/EncoderApp/encmain.cpp b/source/App/EncoderApp/encmain.cpp
index 0953a34..81be4d1 100644
--- a/source/App/EncoderApp/encmain.cpp
+++ b/source/App/EncoderApp/encmain.cpp
@@ -98,6 +98,9 @@ int main(int argc, char* argv[])
   df::program_options_lite::scanArgv( opts, argc, ( const char** ) argv, err );
   fprintf( stdout, "[SIMD=%s] ", read_x86_extension( SIMD ) );
 #endif
+#if MCTS_ENC_CONTSTRAINT
+  fprintf( stdout, "[MCTS] " );
+#endif
 #if ENABLE_TRACING
   fprintf( stdout, "[ENABLE_TRACING] " );
 #endif
diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp
index 0b8ebbd..61101d9 100644
--- a/source/Lib/CommonLib/CodingStructure.cpp
+++ b/source/Lib/CommonLib/CodingStructure.cpp
@@ -126,9 +126,17 @@ void CodingStructure::destroy()
 
 void CodingStructure::releaseIntermediateData()
 {
+#if ENABLE_COMPR_PIC_STAT
+#if !ENABLE_TRACING
   clearTUs();
   clearPUs();
   clearCUs();
+#endif
+#else
+  clearTUs();
+  clearPUs();
+  clearCUs();
+#endif
 }
 
 bool CodingStructure::isDecomp( const Position &pos, const ChannelType effChType )
diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h
index ce4209d..1df7613 100644
--- a/source/Lib/CommonLib/CodingStructure.h
+++ b/source/Lib/CommonLib/CodingStructure.h
@@ -56,7 +56,16 @@ enum PictureType
   PIC_PREDICTION,
   PIC_RESIDUAL,
   PIC_ORG_RESI,
-  NUM_PIC_TYPES
+#if MCTS_REC_CHECK
+  PIC_REC_TILE_0,
+  PIC_REC_TILE_1,
+  PIC_REC_TILE_2,
+  PIC_REC_LAST_TILE,
+#endif
+  NUM_PIC_TYPES,
+#if MCTS_REC_CHECK
+  NUM_PIC_REC_TILES = PIC_REC_LAST_TILE - PIC_REC_TILE_0 + 1,
+#endif
 };
 #if JVET_L0293_CPR
 enum CprLumaCoverage
diff --git a/source/Lib/CommonLib/CprHashMap.cpp b/source/Lib/CommonLib/CprHashMap.cpp
index 4c06d20..a19b4fd 100644
--- a/source/Lib/CommonLib/CprHashMap.cpp
+++ b/source/Lib/CommonLib/CprHashMap.cpp
@@ -35,7 +35,7 @@
     \brief    CPR hash map encoder class
 */
 
-#include "CommonLib/dtrace_codingstruct.h"
+//#include "CommonLib/dtrace_codingstruct.h"
 #include "CommonLib/Picture.h"
 #include "CommonLib/UnitTools.h"
 #include "CprHashMap.h"
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index aecfc90..6eb64e6 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -144,7 +144,6 @@ void InterPrediction::init( RdCost* pcRdCost, ChromaFormat chromaFormatIDC )
 {
   m_pcRdCost = pcRdCost;
 
-
   // if it has been initialised before, but the chroma format has changed, release the memory and start again.
   if( m_acYuvPred[REF_PIC_LIST_0][COMPONENT_Y] != nullptr && m_currChromaFormat != chromaFormatIDC )
   {
@@ -675,7 +674,11 @@ void InterPrediction::xPredInterBlk ( const ComponentID& compID, const Predictio
   CPelBuf refBuf;
   {
     Position offset = pu.blocks[compID].pos().offset( _mv.getHor() >> shiftHor, _mv.getVer() >> shiftVer );
+#if MCTS_REC_CHECK
+    refBuf = refPic->getRecoBuf( CompArea( compID, chFmt, offset, pu.blocks[compID].size() ), refPic->tileMap->getTileIdxMap( pu.blocks[COMPONENT_Y].pos() ) );
+#else
     refBuf = refPic->getRecoBuf( CompArea( compID, chFmt, offset, pu.blocks[compID].size() ) );
+#endif
   }
 
 #if JVET_L0256_BIO
@@ -939,7 +942,11 @@ void InterPrediction::xPredAffineBlk( const ComponentID& compID, const Predictio
         yFrac = iMvScaleTmpVer & 31;
       }
 
+#if MCTS_REC_CHECK
+      const CPelBuf refBuf = refPic->getRecoBuf( CompArea( compID, chFmt, pu.blocks[compID].offset( xInt + w, yInt + h ), pu.blocks[compID] ), refPic->tileMap->getTileIdxMap( pu.blocks[COMPONENT_Y] ) );
+#else
       const CPelBuf refBuf = refPic->getRecoBuf( CompArea( compID, chFmt, pu.blocks[compID].offset(xInt + w, yInt + h), pu.blocks[compID] ) );
+#endif
       PelBuf &dstBuf = dstPic.bufs[compID];
 
       if ( yFrac == 0 )
@@ -1557,11 +1564,26 @@ void InterPrediction::motionCompensation4Triangle( CodingUnit &cu, MergeCtx &tri
     triangleMrgCtx.setMergeInfo( pu, candIdx0 );
     PU::spanMotionInfo( pu );
     motionCompensation( pu, tmpTriangleBuf );
+#if MCTS_DEC_CHECK
+    {
+      if( g_mctsDecCheckEnabled && !checkTMctsMv( 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 MCTS_DEC_CHECK
+    {
+      if( g_mctsDecCheckEnabled && !checkTMctsMv( 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
     weightedTriangleBlk( pu, PU::getTriangleWeights(pu, triangleMrgCtx, candIdx0, candIdx1), splitDir, MAX_NUM_CHANNEL_TYPE, predBuf, tmpTriangleBuf, predBuf );
   }
 }
@@ -1666,4 +1688,223 @@ void InterPrediction::cacheAssign( CacheModel *cache )
 }
 #endif
 
+
+#if MCTS_ENC_CONTSTRAINT || MCTS_DEC_CHECK
+
+void getRefPUPartPos(PredictionUnit& pu, int xOff, int yOff, const Mv& mv, int& ruiPredXLeft, int& ruiPredYTop, int& ruiPredXRight, int& ruiPredYBottom)
+{
+  Mv _mv = mv;
+  
+  int predShift = (2 + VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE);
+  
+  ruiPredXLeft = (_mv.getHor() >> predShift) + pu.lx() + xOff;
+  ruiPredYTop  = (_mv.getVer() >> predShift) + pu.ly() + yOff;
+  ruiPredXRight  = ruiPredXLeft + ( pu.lwidth()  - xOff ) - 1;
+  ruiPredYBottom = ruiPredYTop  + ( pu.lheight() - yOff ) - 1;
+}
+
+bool checkMVPRange(const Picture* pic, const Mv& mv, int ctuLength, int tileXPosInCtus, int tileYPosInCtus, int tileWidthtInCtus, int tileHeightInCtus, int PredXLeft, int PredXRight, int PredYTop, int PredYBottom, ChromaFormat chromaFormat, const int offsetBIO, bool bTmpFlag )
+{
+  // all calculations in High Precision
+  Mv _mv=mv;
+  
+  // filter length of sub-sample generation filter to be considered
+#if JVET_L0256_BIO
+  const int LumaLTSampleOffset = 3 + offsetBIO;
+  const int LumaRBSampleOffset = 4 + offsetBIO;
+  const int CromaLTSampleoffset = 2 ; //1; // 2 in luma coordinates!
+  const int CromaRBSampleoffset = 3 ; //2; // 3 in luma coordinates!
+#else
+  const int LumaLTSampleOffset = 3;
+  const int LumaRBSampleOffset = 4;
+  const int CromaLTSampleoffset = 2; //1; // 2 in luma coordinates!
+  const int CromaRBSampleoffset = 3; //2; // 3 in luma coordinates!
+#endif
+
+  // tile position in full pel
+  const int leftTopPelPosX = ctuLength * tileXPosInCtus;
+  const int leftTopPelPosY = ctuLength * tileYPosInCtus;
+  const int rightBottomPelPosX = std::min<int>( ((tileWidthtInCtus + tileXPosInCtus) * ctuLength), (int)pic->lwidth() ) - 1;
+  const int rightBottomPelPosY = std::min<int>( ((tileHeightInCtus + tileYPosInCtus) * ctuLength), (int)pic->lheight() ) - 1;
+
+  int fracDiv = 1 << (2 + VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE);
+
+  // Luma MV range check
+  const bool isFullPelHorLuma = (_mv.getHor() % fracDiv == 0);
+  const bool isFullPelVerLuma = (_mv.getVer() % fracDiv == 0);
+
+#if  JVET_L0256_BIO
+  const int lRangeXLeft   = leftTopPelPosX + ( isFullPelHorLuma ? offsetBIO : LumaLTSampleOffset );
+  const int lRangeYTop    = leftTopPelPosY + ( isFullPelVerLuma ? offsetBIO : LumaLTSampleOffset );
+  const int lRangeXRight  = rightBottomPelPosX - ( isFullPelHorLuma ? offsetBIO : LumaRBSampleOffset );
+  const int lRangeYBottom = rightBottomPelPosY - ( isFullPelVerLuma ? offsetBIO : LumaRBSampleOffset );
+#else
+  const int lRangeXLeft = leftTopPelPosX + ( isFullPelHorLuma ? 0 : LumaLTSampleOffset );
+  const int lRangeYTop = leftTopPelPosY + ( isFullPelVerLuma ? 0 : LumaLTSampleOffset );
+  const int lRangeXRight = rightBottomPelPosX - ( isFullPelHorLuma ? 0 : LumaRBSampleOffset );
+  const int lRangeYBottom = rightBottomPelPosY - ( isFullPelVerLuma ? 0 : LumaRBSampleOffset );
+#endif
+
+  if (!(PredXLeft >= lRangeXLeft && PredXLeft <= lRangeXRight) || !(PredXRight >= lRangeXLeft && PredXRight <= lRangeXRight))
+  {
+    if( bTmpFlag )
+    {
+      msg( WARNING, "LUMA: pu motion vector across tile boundaries MV(%d,%d) RangeLR(%d,%d) PredLR(%d,%d)\n", mv.getHor(), mv.getVer(), lRangeXLeft, lRangeXRight, PredXLeft, PredXRight );
+    }
+    return false;
+  }
+  else if (!(PredYTop >= lRangeYTop && PredYTop <= lRangeYBottom) || !(PredYBottom >= lRangeYTop && PredYBottom <= lRangeYBottom))
+  {
+    if( bTmpFlag )
+    {
+      msg( WARNING, "LUMA: pu motion vector across tile boundaries MV(%d,%d) RangeTB(%d,%d) PredTB(%d,%d)\n", mv.getHor(), mv.getVer(), lRangeYTop, lRangeYBottom, PredYTop, PredYBottom );
+    }
+    return false;
+  }
+
+  if ((chromaFormat != CHROMA_444) && (chromaFormat != CHROMA_400))
+  {
+    // Chroma MV range check
+    int fracDiv = 1 << (3 + VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE);
+
+    const bool isFullPelHorChroma = (_mv.getHor() % fracDiv == 0);
+    const bool isFullPelVerChroma = (_mv.getVer() % fracDiv == 0);
+
+    const int cRangeXLeft = leftTopPelPosX + (isFullPelHorChroma ? 0 : CromaLTSampleoffset);
+    const int cRangeYTop = leftTopPelPosY + (isFullPelVerChroma ? 0 : CromaLTSampleoffset);
+    const int cRangeXRight = rightBottomPelPosX - (isFullPelHorChroma ? 0 : CromaRBSampleoffset);
+    const int cRangeYBottom = rightBottomPelPosY - (isFullPelVerChroma ? 0 : CromaRBSampleoffset);
+
+    if (!(PredXLeft >= cRangeXLeft && PredXLeft <= cRangeXRight) || !(PredXRight >= cRangeXLeft && PredXRight <= cRangeXRight))
+    {
+      if( bTmpFlag )
+      {
+        msg( WARNING, "CHROMA: pu motion vector across tile boundaries MV(%d,%d) RangeLR(%d,%d) PredLR(%d,%d)\n", mv.getHor(), mv.getVer(), cRangeXLeft, cRangeXRight, PredXLeft, PredXRight );
+      }
+      return false;
+    }
+    else if ((!(PredYTop >= cRangeYTop && PredYTop <= cRangeYBottom) || !(PredYBottom >= cRangeYTop && PredYBottom <= cRangeYBottom)) && (chromaFormat != CHROMA_422))
+    {
+      if( bTmpFlag )
+      {
+        msg( WARNING, "CHROMA: pu motion vector across tile boundaries MV(%d,%d) RangeTB(%d,%d) PredTB(%d,%d)\n", mv.getHor(), mv.getVer(), cRangeYTop, cRangeYBottom, PredYTop, PredYBottom );
+      }
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool InterPrediction::checkTMctsMv(PredictionUnit &pu, bool bTmpFlag)
+{
+  int  tileXPosInCtus = 0;
+  int  tileYPosInCtus = 0;
+  int  tileWidthtInCtus = 0;
+  int  tileHeightInCtus = 0;
+
+  getTilePosition(pu, tileXPosInCtus, tileYPosInCtus, tileWidthtInCtus, tileHeightInCtus);
+
+  const uint32_t            ctuLength = pu.cs->sps->getMaxCUWidth();
+  const ChromaFormat chromaFormat = pu.cs->sps->getChromaFormatIdc();
+
+  int   predXLeft;
+  int   predYTop;
+  int   predXRight;
+  int   predYBottom;
+
+  const int offsetBIO = PU::isMCTSBIORestriction( pu ) ? MCTS_BIO_CONSTRAINT_NUM_SAMPLES : 0;
+
+  const MotionBuf mb = pu.getMotionBuf();
+
+  for (int y = 0; y < mb.height; y++)
+  {
+    for (int x = 0; x < mb.width; x++)
+    {
+      const MotionInfo &mi = mb.at(x, y);
+
+      //CHECK(!mi.isInter, "But it should be!");
+
+      int xOff = x << g_miScaling.posx;
+      int yOff = y << g_miScaling.posy;
+
+      if (xCheckIdenticalMotion(pu))
+      {
+        RefPicList eRefPicList = REF_PIC_LIST_0;
+        const Mv mv = mi.mv[eRefPicList];
+        CHECK( ( pu.refIdx[eRefPicList] < 0 ), "Corrupted motion data!\n" );
+        getRefPUPartPos(pu, xOff, yOff, mv, predXLeft, predYTop, predXRight, predYBottom);
+        if (!checkMVPRange( pu.cs->picture, mv, ctuLength, tileXPosInCtus, tileYPosInCtus, tileWidthtInCtus, tileHeightInCtus, predXLeft, predXRight, predYTop, predYBottom, chromaFormat, offsetBIO, bTmpFlag ))
+        {
+          return false;
+        }
+      }
+      else
+      {
+        for (int refList = 0; refList < NUM_REF_PIC_LIST_01; refList++)
+        {
+          RefPicList eRefPicList = (refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
+          if( pu.refIdx[refList] >= 0 )
+          {
+            const Mv mv = mi.mv[eRefPicList];;
+            getRefPUPartPos( pu, xOff, yOff, mv, predXLeft, predYTop, predXRight, predYBottom );
+            if( !checkMVPRange( pu.cs->picture, mv, ctuLength, tileXPosInCtus, tileYPosInCtus, tileWidthtInCtus, tileHeightInCtus, predXLeft, predXRight, predYTop, predYBottom, chromaFormat, offsetBIO, bTmpFlag ) )
+            {
+              return false;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  return true;
+}
+#endif
+
+#if MCTS_ENC_CONTSTRAINT
+void MCTSTileInfo::init( CodingStructure* cs, int ctuAddr )
+{
+  int  tileXPosInCtus = 0;
+  int  tileYPosInCtus = 0;
+  int  tileWidthtInCtus = 0;
+  int  tileHeightInCtus = 0;
+
+  getTilePosition( cs, ctuAddr, tileXPosInCtus, tileYPosInCtus, tileWidthtInCtus, tileHeightInCtus );
+  const int  ctuLength = cs->pcv->maxCUWidth;
+
+  // tile position in full pels
+  const int tileLeftTopPelPosX = ctuLength * tileXPosInCtus;
+  const int tileLeftTopPelPosY = ctuLength * tileYPosInCtus;
+  const int tileRightBottomPelPosX = std::min<int>( ( ( tileWidthtInCtus + tileXPosInCtus ) * ctuLength ), (int)cs->picture->lwidth()  ) - 1;
+  const int tileRightBottomPelPosY = std::min<int>( ( ( tileHeightInCtus + tileYPosInCtus ) * ctuLength ), (int)cs->picture->lheight() ) - 1;
+
+  init( tileLeftTopPelPosX, tileLeftTopPelPosY, tileRightBottomPelPosX, tileRightBottomPelPosY );
+}
+
+Area MCTSTileInfo::getTileAreaSubPelRestricted( const PredictionUnit &pu )
+{
+  int offLT = 4;
+  int offRB = 4;
+#if JVET_L0256_BIO
+  const int offset = PU::isMCTSBIORestriction( pu ) ? MCTS_BIO_CONSTRAINT_NUM_SAMPLES : 0;
+  offLT += offset;
+  offRB += offset;
+#endif
+  const Area& tileArea = getTileArea();
+  return Area( tileArea.x + offLT, tileArea.y + offLT, tileArea.width - ( offLT + offRB ), tileArea.height - ( offLT + offRB ) );
+}
+
+Area MCTSTileInfo::getTileAreaFullPelRestricted( const PredictionUnit &pu )
+{
+  const Area& tileArea = getTileArea();
+#if JVET_L0256_BIO
+  const int offset = PU::isMCTSBIORestriction( pu ) ? MCTS_BIO_CONSTRAINT_NUM_SAMPLES : 0;
+#else
+  const int offset = 0;
+#endif
+  return Area( tileArea.x + offset, tileArea.y + offset, tileArea.width - 2 * offset, tileArea.height - 2 * offset );
+}
+
+#endif
 //! \}
diff --git a/source/Lib/CommonLib/InterPrediction.h b/source/Lib/CommonLib/InterPrediction.h
index 75e803d..418a302 100644
--- a/source/Lib/CommonLib/InterPrediction.h
+++ b/source/Lib/CommonLib/InterPrediction.h
@@ -59,6 +59,63 @@ class Mv;
 // ====================================================================================================================
 // Class definition
 // ====================================================================================================================
+#if MCTS_ENC_CONTSTRAINT  
+class MCTSTileInfo
+{
+private:
+  int   m_tileLeftTopPelPosX;
+  int   m_tileLeftTopPelPosY;
+  int   m_tileRightBottomPelPosX;
+  int   m_tileRightBottomPelPosY;
+  Area  m_tileArea;
+
+public:
+  MCTSTileInfo()
+    : m_tileLeftTopPelPosX( 0 )
+    , m_tileLeftTopPelPosY( 0 )
+    , m_tileRightBottomPelPosX( 0 )
+    , m_tileRightBottomPelPosY( 0 )
+    , m_tileArea( Area( 0, 0, 0, 0 ) )
+  {};
+
+  int   getTileLeftTopPelPosX() const { return m_tileLeftTopPelPosX; }
+  int   getTileLeftTopPelPosY() const { return m_tileLeftTopPelPosY; }
+  int   getTileRightBottomPelPosX() const { return m_tileRightBottomPelPosX; }
+  int   getTileRightBottomPelPosY() const { return m_tileRightBottomPelPosY; }
+  bool  isInitialized() { return m_tileRightBottomPelPosX > 0; }
+
+  // -------------------------------------------------------------------------------------------------------------------
+  // initialization functions
+  // -------------------------------------------------------------------------------------------------------------------
+  MCTSTileInfo( int tileLeftTopPelPosX, int tileLeftTopPelPosY, int tileRightBottomPelPosX, int tileRightBottomPelPosY )
+    : m_tileLeftTopPelPosX( tileLeftTopPelPosX )
+    , m_tileLeftTopPelPosY( tileLeftTopPelPosY )
+    , m_tileRightBottomPelPosX( tileRightBottomPelPosX )
+    , m_tileRightBottomPelPosY( tileRightBottomPelPosY )
+    , m_tileArea( Area( m_tileLeftTopPelPosX, m_tileLeftTopPelPosY, m_tileRightBottomPelPosX - m_tileLeftTopPelPosX + 1, m_tileRightBottomPelPosY - m_tileLeftTopPelPosY + 1 ) )
+  {};
+
+  void init( CodingStructure* cs, int ctuAddr );
+
+  void init( int tileLeftTopPelPosX, int tileLeftTopPelPosY, int tileRightBottomPelPosX, int tileRightBottomPelPosY )
+  {
+    m_tileLeftTopPelPosX = tileLeftTopPelPosX;
+    m_tileLeftTopPelPosY = tileLeftTopPelPosY;
+    m_tileRightBottomPelPosX = tileRightBottomPelPosX;
+    m_tileRightBottomPelPosY = tileRightBottomPelPosY;
+    m_tileArea = Area( m_tileLeftTopPelPosX, m_tileLeftTopPelPosY, m_tileRightBottomPelPosX - m_tileLeftTopPelPosX + 1, m_tileRightBottomPelPosY - m_tileLeftTopPelPosY + 1 );
+  }
+
+  Area        getTileArea()       { return m_tileArea; }
+  const Area& getTileArea() const { return m_tileArea; }
+
+  Area getTileAreaSubPelRestricted( const PredictionUnit &pu );
+  Area getTileAreaFullPelRestricted( const PredictionUnit &pu );
+
+};
+#endif
+
+
 
 class InterPrediction : public WeightPrediction
 {
@@ -110,6 +167,9 @@ protected:
   bool            xCalcBiPredSubBlkDist(const PredictionUnit &pu, const Pel* yuvSrc0, const int src0Stride, const Pel* yuvSrc1, const int src1Stride, const BitDepths &clipBitDepths);
   void            bioSampleExtendBilinearFilter(Pel const* src, int srcStride, Pel *dst, int dstStride, int width, int height, int dim, int fracX, int fracY, bool isLast, const ChromaFormat fmt, const ClpRng& clpRng);
 #endif
+#if MCTS_ENC_CONTSTRAINT
+  MCTSTileInfo         m_mctsTileInfo;
+#endif
 
   void xPredInterUni            ( const PredictionUnit& pu, const RefPicList& eRefPicList, PelUnitBuf& pcYuvPred, const bool& bi 
 #if JVET_L0256_BIO
@@ -189,6 +249,11 @@ public:
   void    cacheAssign( CacheModel *cache );
 #endif
 
+#if MCTS_ENC_CONTSTRAINT
+  bool          checkTMctsMvBIO( PredictionUnit &pu, const RefPicList& eRefPicList );
+  bool          checkTMctsMv( PredictionUnit &pu, bool bTmpFlag = false );
+  MCTSTileInfo& getMCTSTileInfo() { return m_mctsTileInfo; }
+#endif
 };
 
 //! \}
diff --git a/source/Lib/CommonLib/Mv.cpp b/source/Lib/CommonLib/Mv.cpp
index 81e2624..99ae394 100644
--- a/source/Lib/CommonLib/Mv.cpp
+++ b/source/Lib/CommonLib/Mv.cpp
@@ -99,4 +99,19 @@ void clipMv( Mv& rcMv, const Position& pos,
   rcMv.setVer( std::min( iVerMax, std::max( iVerMin, rcMv.getVer() ) ) );
 }
 
+#if MCTS_ENC_CONTSTRAINT
+void clipMvToArea( Mv& rcMv, const Area& block, const Area& clipArea, const SPS& sps, int subPelPrecision )
+{
+  int iMvShift = subPelPrecision;
+  int iHorMax = ( clipArea.x + clipArea.width - (int)block.x - (int)block.width ) << iMvShift;
+  int iHorMin = ( clipArea.x - (int)block.x ) << iMvShift;
+
+  int iVerMax = ( clipArea.y + clipArea.height - (int)block.y - (int)block.height ) << iMvShift;
+  int iVerMin = ( clipArea.y - (int)block.y ) << iMvShift;
+
+  rcMv.setHor( Clip3( iHorMin, iHorMax, rcMv.getHor() ) );
+  rcMv.setVer( Clip3( iVerMin, iVerMax, rcMv.getVer() ) );
+}
+#endif
+
 //! \}
diff --git a/source/Lib/CommonLib/Mv.h b/source/Lib/CommonLib/Mv.h
index a1525dd..167afa6 100644
--- a/source/Lib/CommonLib/Mv.h
+++ b/source/Lib/CommonLib/Mv.h
@@ -293,6 +293,9 @@ void clipMv ( Mv& rcMv, const struct Position& pos,
 #endif
               const class SPS& sps );
 
+#if MCTS_ENC_CONTSTRAINT
+void clipMvToArea          ( Mv& rcMv, const struct Area& block, const struct Area& clipArea, const SPS& sps, int subPelPrecision = 4 );
+#endif
 void roundAffineMv( int& mvx, int& mvy, int nShift );
 
 //! \}
diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp
index db251d4..4b9cb22 100644
--- a/source/Lib/CommonLib/Picture.cpp
+++ b/source/Lib/CommonLib/Picture.cpp
@@ -747,6 +747,15 @@ void Picture::create(const ChromaFormat &_chromaFormat, const Size &size, const
 
   m_ctuArea = UnitArea( _chromaFormat, Area( Position{ 0, 0 }, Size( _maxCUSize, _maxCUSize ) ) );
 #endif
+  
+#if MCTS_REC_CHECK
+  //for( PictureType i = PIC_REC_TILE_0; i < NUM_PIC_REC_TILES; i++ )
+  for( int tileIdx = 0; tileIdx < NUM_PIC_REC_TILES; tileIdx++ )
+  {
+    PictureType j = PictureType( (int)PIC_REC_TILE_0 + tileIdx );
+    M_BUFS( 0, j ).create( _chromaFormat, a, _maxCUSize, _margin, MEMORY_ALIGN_DEF_SIZE );
+  }
+#endif
 }
 
 void Picture::destroy()
@@ -864,6 +873,11 @@ const CPelBuf     Picture::getRecoBuf(const CompArea &blk)      const { return g
 const CPelUnitBuf Picture::getRecoBuf(const UnitArea &unit)     const { return getBuf(unit,                      PIC_RECONSTRUCTION); }
        PelUnitBuf Picture::getRecoBuf()                               { return M_BUFS(scheduler.getSplitPicId(), PIC_RECONSTRUCTION); }
 const CPelUnitBuf Picture::getRecoBuf()                         const { return M_BUFS(scheduler.getSplitPicId(), PIC_RECONSTRUCTION); }
+#if MCTS_REC_CHECK
+       PelBuf     Picture::getRecoBuf(const CompArea &blk, int tileIdx )            { return getBuf(blk, PictureType( (int)PIC_REC_TILE_0 + tileIdx ) ); }
+const CPelBuf     Picture::getRecoBuf(const CompArea &blk, int tileIdx )      const { return getBuf(blk, PictureType( (int)PIC_REC_TILE_0 + tileIdx ) ); }
+       PelUnitBuf Picture::getRecoBuf(const UnitArea &unit, int tileIdx)            { return getBuf(unit, PictureType( (int)PIC_REC_TILE_0 + tileIdx ) ); }
+#endif
 
 void Picture::finalInit( const SPS& sps, const PPS& pps )
 {
@@ -1166,3 +1180,87 @@ bool Picture::getSpliceFull()
     return false;
   return true;
 }
+
+
+#if MCTS_REC_CHECK
+static FILE *tf = nullptr;
+
+inline void writeUnitComp( FILE *f, const PelUnitBuf& pelUnitBuf, const UnitArea& ua, ComponentID compId )
+{
+  Pel* ptr = pelUnitBuf.bufs[compId].buf;
+  uint32_t       uiStride = pelUnitBuf.bufs[compId].stride;
+  uint32_t       uiWidth = ua.blocks[compId].width;
+  uint32_t       uiHeight = ua.blocks[compId].height;
+  //int x0 = ua.lumaPos().x;
+  //int y0 = ua.lumaPos().y;
+
+  for( int j = 0; j < uiHeight; j++ )
+  {
+    fwrite( ptr, 1, uiWidth * sizeof( Pel ), f );
+    ptr += uiStride;
+  }
+}
+
+
+void establishPictureTilesRefBuffers( Picture *pcPic, Slice *pcSlice )
+{
+  //Picture *pcPic = this;
+  CHECK( pcPic->tileMap->numTiles > NUM_PIC_REC_TILES, "Too much tiles, pic buffer should be extended!" );
+  if( 1 )
+  {
+    //for( PictureType i = PIC_REC_TILE_0; i < NUM_PIC_REC_TILES; i++ )
+    for( int tileIdx = 0; tileIdx < pcPic->tileMap->numTiles; tileIdx++ )
+    {
+      //PictureType j = PictureType( (int)PIC_REC_TILE_0 + tileIdx );
+      //for(  )
+      {
+        const TileMap*   tileMap = pcPic->tileMap;
+        //const int        tileIdx = tileMap->getTileIdxMap( ctuAddr );
+        const Tile&      currentTile = tileMap->tiles[tileIdx];
+
+        const int      frameWidthInCtus = pcPic->cs->pcv->widthInCtus;
+        const int  firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr();
+
+        int tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus;
+        int tileYPosInCtus = firstCtuRsAddrOfTile / frameWidthInCtus;
+        int tileWidthtInCtus = currentTile.getTileWidthInCtus();
+        int tileHeightInCtus = currentTile.getTileHeightInCtus();
+
+        const int ctuSizeX = 128;
+        const int ctuSizeY = 128;
+        int tileX = tileXPosInCtus * ctuSizeX;
+        int tileY = tileYPosInCtus * ctuSizeY;
+        int tileWidth = tileWidthtInCtus * ctuSizeX;
+        int tileHeight = tileHeightInCtus * ctuSizeY;
+        
+        if( tileX + tileWidth > pcPic->lwidth() )
+          tileWidth = pcPic->lwidth() - tileX;
+        if( tileY + tileHeight > pcPic->lheight() )
+          tileHeight =  pcPic->lheight() - tileY;
+
+        Area area( tileX, tileY, tileWidth, tileHeight );
+        UnitArea unitArea( CHROMA_420,
+          CompArea( COMPONENT_Y, CHROMA_420, area ),
+          CompArea( COMPONENT_Cb, CHROMA_420, area, true ),
+          CompArea( COMPONENT_Cr, CHROMA_420, area, true ) );
+
+        //Position offset = pu.blocks[compID].pos().offset( _mv.getHor() >> shiftHor, _mv.getVer() >> shiftVer );
+        CPelUnitBuf refBuf = pcPic->getRecoBuf( unitArea );
+        PelUnitBuf  dstBuf = pcPic->getRecoBuf( unitArea, tileIdx );
+        dstBuf.copyFrom( refBuf );
+        
+        if( tileIdx == 3 )
+        {
+          if( tf == nullptr )
+            tf = fopen( "tile.yuv", "wb" );
+
+          //PelUnitBuf& buf = pcPic->getRecoBuf( *pcPic );
+          const PelUnitBuf& buf = pcPic->getRecoBuf( *pcPic, tileIdx );
+          for( int i = 0; i < 3; i++ )
+            writeUnitComp( tf, buf, *pcPic, ComponentID( i ) );
+        }
+      }
+    }
+  }
+}
+#endif
diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h
index 1e4e5c3..a503147 100644
--- a/source/Lib/CommonLib/Picture.h
+++ b/source/Lib/CommonLib/Picture.h
@@ -211,8 +211,12 @@ struct Picture : public UnitArea
   const CPelUnitBuf getRecoBuf(const UnitArea &unit) const;
          PelUnitBuf getRecoBuf();
   const CPelUnitBuf getRecoBuf() const;
-
-         PelBuf     getBuf(const ComponentID compID, const PictureType &type);
+#if MCTS_REC_CHECK
+         PelUnitBuf getRecoBuf( const UnitArea &unit, int tileIdx );
+         PelBuf     getRecoBuf( const CompArea &blk, int tileIdx );
+  const CPelBuf     getRecoBuf( const CompArea &blk, int tileIdx ) const;
+#endif
+         PelBuf     getBuf( const ComponentID compID, const PictureType &type );
   const CPelBuf     getBuf(const ComponentID compID, const PictureType &type) const;
          PelBuf     getBuf(const CompArea &blk,      const PictureType &type);
   const CPelBuf     getBuf(const CompArea &blk,      const PictureType &type) const;
@@ -318,5 +322,7 @@ int calcAndPrintHashStatus(const CPelUnitBuf& pic, const class SEIDecodedPicture
 
 
 typedef std::list<Picture*> PicList;
-
+#if MCTS_REC_CHECK
+void establishPictureTilesRefBuffers( Picture *pcPic, Slice *pcSlice );
+#endif
 #endif
diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp
index 93ee217..6ba133c 100644
--- a/source/Lib/CommonLib/Rom.cpp
+++ b/source/Lib/CommonLib/Rom.cpp
@@ -50,6 +50,15 @@
 
 #if ENABLE_TRACING
 CDTrace *g_trace_ctx = NULL;
+#if ENABLE_COMPR_PIC_STAT
+CBitCounter g_bitCounterCU;
+#endif
+#endif
+#if MCTS_ENC_CONTSTRAINT
+bool g_mctsEncConstraint = false;
+#endif
+#if MCTS_DEC_CHECK
+bool g_mctsDecCheckEnabled = false;
 #endif
 
 
diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h
index 13792f9..cf4cfea 100644
--- a/source/Lib/CommonLib/Rom.h
+++ b/source/Lib/CommonLib/Rom.h
@@ -205,6 +205,9 @@ extern UnitScale     g_miScaling; // scaling object for motion scaling
 #if ENABLE_TRACING
 #include "dtrace.h"
 extern CDTrace* g_trace_ctx;
+#if ENABLE_COMPR_PIC_STAT
+extern CBitCounter g_bitCounterCU;
+#endif
 #endif
 
 const char* nalUnitTypeToString(NalUnitType type);
@@ -267,5 +270,12 @@ extern const uint8_t g_triangleCombination[TRIANGLE_MAX_NUM_CANDS][3];
 extern const uint8_t g_triangleIdxBins[TRIANGLE_MAX_NUM_CANDS];
 #endif
 
+#if MCTS_ENC_CONTSTRAINT
+extern bool g_mctsEncConstraint;
+#endif
+#if MCTS_DEC_CHECK
+extern bool g_mctsDecCheckEnabled;
+#endif
+
 #endif  //__TCOMROM__
 
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 71359f0..ddf4cd4 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -1763,6 +1763,9 @@ private:
 #if  JVET_L0266_HMVP
   LutMotionCand*             m_MotionCandLut;
 #endif
+#if MCTS_ENC_CONTSTRAINT
+  Area                       m_interPredRefPicArea;
+#endif
 
 public:
                               Slice();
@@ -2043,6 +2046,11 @@ public:
   void resetProcessingTime()       { m_dProcessingTime = m_iProcessingStartTime = 0; }
   double getProcessingTime() const { return m_dProcessingTime; }
 
+#if MCTS_ENC_CONTSTRAINT
+  void                        setInterPredRefPicArea( const Area& area ) { m_interPredRefPicArea = area; }
+  const Area&                 getInterPredRefPicArea() const             { return m_interPredRefPicArea; }
+#endif
+
   void                        setAlfSliceParam( AlfSliceParam& alfSliceParam ) { m_alfSliceParam = alfSliceParam; }
   AlfSliceParam&              getAlfSliceParam() { return m_alfSliceParam; }
 #if  JVET_L0266_HMVP
@@ -2299,6 +2307,9 @@ public:
     , isEncoder           ( _isEncoder )
 #if JVET_L0217_L0678_SPS_CLEANUP
     , ISingleTree         ( !sps.getUseDualITree() )
+#if MCTS_ENC_CONTSTRAINT
+    , mvRefPicArea        ( -(int)sps.getMaxCUWidth() - 8, -(int)sps.getMaxCUHeight() - 8, sps.getPicWidthInLumaSamples() + sps.getMaxCUWidth() + 2 * 8, sps.getPicHeightInLumaSamples() + sps.getMaxCUHeight() + 2 * 8 )
+#endif
     , maxBtDepth          { sps.getMaxBTDepthI(), sps.getMaxBTDepth(), sps.getMaxBTDepthIChroma() }
     , minBtSize           { MIN_BT_SIZE, MIN_BT_SIZE_INTER, MIN_BT_SIZE_C }
     , maxBtSize           { sps.getMaxBTSizeI(), sps.getMaxBTSize(), sps.getMaxBTSizeIChroma() }
@@ -2350,6 +2361,9 @@ public:
   const bool         noChroma2x2;
   const bool         isEncoder;
   const bool         ISingleTree;
+#if MCTS_ENC_CONTSTRAINT
+  const Area         mvRefPicArea;
+#endif
 
 private:
   const unsigned     maxBtDepth[3];
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 0589e0d..150d8b9 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -203,6 +203,8 @@
 #endif
 #endif // ! ENABLE_TRACING
 
+#define ENABLE_COMPR_PIC_STAT                           ( 1 && ENABLE_TRACING )
+
 #define WCG_EXT                                           0 // part of JEM sharp Luma qp
 #define WCG_WPSNR                                         WCG_EXT
 
@@ -223,6 +225,17 @@
 #define HEVC_USE_SIGN_HIDING                              1
 #endif
 
+#define HHI_MCTS                                          1  ///< MCTS functionality
+
+#if HHI_MCTS
+#define HEVC_TILES_WPP                                    1
+#define MCTS_ENC_CONTSTRAINT                            ( 1 && HEVC_TILES_WPP )///< Temporal MCTS encoder constraint and decoder checks. Also requires SEITMCTSTileConstraint to be enabled to enforce constraint
+#define HHI_BUG_FIX_FOR_MCTS                            ( 1 && MCTS_ENC_CONTSTRAINT )
+#define MCTS_ENC_CHECK                                  ( 0 && MCTS_ENC_CONTSTRAINT )
+#define MCTS_DEC_CHECK                                    0
+#define MCTS_REC_CHECK                                    0
+#define MCTS_BIO_CONSTRAINT_NUM_SAMPLES                   1
+#endif
 
 #define KEEP_PRED_AND_RESI_SIGNALS                        0
 
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 77cffb6..e574f57 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -279,6 +279,12 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
 #if JVET_L0293_CPR
   cpr               = other.cpr;
 #endif
+#if ENABLE_COMPR_PIC_STAT
+  cost              = other.cost;
+  infoBits          = other.infoBits;
+  trafoBits         = other.trafoBits;
+  otherBits         = other.otherBits;
+#endif
   return *this;
 }
 
@@ -318,6 +324,12 @@ void CodingUnit::initData()
 #if JVET_L0293_CPR
   cpr               = false;
 #endif
+#if ENABLE_COMPR_PIC_STAT
+  cost              = 0;
+  infoBits          = 0;
+  trafoBits         = 0;
+  otherBits         = 0;
+#endif
 }
 
 
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 3142b13..fcbfe3c 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -318,6 +318,14 @@ struct CodingUnit : public UnitArea
   int8_t          imvNumCand;
 #if JVET_L0293_CPR
   bool           cpr;
+
+#endif
+#if ENABLE_COMPR_PIC_STAT
+  // needed for COMPRPICSTAT tracing
+  uint64_t         cost;
+  uint64_t         infoBits;
+  uint64_t         trafoBits;
+  uint64_t         otherBits;
 #endif
 
   CodingUnit() : chType( CH_L ) { }
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index fee9892..7f92b5d 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -2986,7 +2986,6 @@ void PU::fillAffineMvpCand(PredictionUnit &pu, const RefPicList &eRefPicList, co
   }
 #endif
 
-
 #if !JVET_L0271_AFFINE_AMVP_SIMPLIFY
   if ( affiAMVPInfo.numCand < 2 )
   {
@@ -5584,5 +5583,64 @@ uint32_t getCtuAddr( const Position& pos, const PreCalcValues& pcv )
   return ( pos.x >> pcv.maxCUWidthLog2 ) + ( pos.y >> pcv.maxCUHeightLog2 ) * pcv.widthInCtus;
 }
 
+#if MCTS_ENC_CONTSTRAINT
+
+void getTilePosition(const PredictionUnit &pu, int &tileXPosInCtus, int &tileYPosInCtus, int &tileWidthtInCtus, int &tileHeightInCtus)
+{
+  const int        ctuAddr     = getCtuAddr(pu.cu->lumaPos(), *(pu.cs->pcv));
+  const TileMap*   tileMap     = pu.cs->picture->tileMap;
+  const int        tileIdx     = tileMap->getTileIdxMap(ctuAddr);
+  const Tile&      currentTile = tileMap->tiles[tileIdx];
+
 
+  const int      frameWidthInCtus = pu.cs->pcv->widthInCtus;
+  const int  firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr();
 
+  tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus;
+  tileYPosInCtus = firstCtuRsAddrOfTile / frameWidthInCtus;
+  tileWidthtInCtus = currentTile.getTileWidthInCtus();
+  tileHeightInCtus = currentTile.getTileHeightInCtus();
+}
+
+void getTilePosition( const CodingStructure* cs, const int ctuAddr, int &tileXPosInCtus, int &tileYPosInCtus, int &tileWidthtInCtus, int &tileHeightInCtus)
+{
+  //const int        ctuAddr     = getCtuAddr(pu.cu->lumaPos(), *(pu.cs->pcv));
+  const TileMap*   tileMap     = cs->picture->tileMap;
+  const int        tileIdx     = tileMap->getTileIdxMap(ctuAddr);
+  const Tile&      currentTile = tileMap->tiles[tileIdx];
+
+
+  const int      frameWidthInCtus = cs->pcv->widthInCtus;
+  const int  firstCtuRsAddrOfTile = currentTile.getFirstCtuRsAddr();
+
+  tileXPosInCtus = firstCtuRsAddrOfTile % frameWidthInCtus;
+  tileYPosInCtus = firstCtuRsAddrOfTile / frameWidthInCtus;
+  tileWidthtInCtus = currentTile.getTileWidthInCtus();
+  tileHeightInCtus = currentTile.getTileHeightInCtus();
+}
+
+#endif
+
+#if MCTS_ENC_CONTSTRAINT || MCTS_DEC_CHECK
+bool PU::isMCTSBIORestriction( const PredictionUnit& pu )
+{
+#if 0
+  return true;
+#else
+  const PPS   &pps = *pu.cs->pps;
+  const Slice &slice = *pu.cs->slice;
+  const bool biocheck0 = !( pps.getWPBiPred() && slice.getSliceType() == B_SLICE );
+  const bool biocheck1 = !( pps.getUseWP() && slice.getSliceType() == P_SLICE );
+  if( pu.cs->sps->getSpsNext().getUseBIO()
+    && biocheck0
+    && biocheck1
+    && slice.getCheckLDC() == false /*PU::isBiPredFromDifferentDir( pu )*/
+    && !( pu.Y().height == 4 || ( pu.Y().width == 4 && pu.Y().height == 8 ) )
+    )
+  {
+    return true;
+  }
+  return false;
+#endif
+}
+#endif
\ No newline at end of file
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index e111b0b..56ca11b 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -197,6 +197,9 @@ namespace PU
   bool getDerivedBV(PredictionUnit &pu, const Mv& currentMv, Mv& derivedMv);
   bool isBlockVectorValid(PredictionUnit& pu, int xPos, int yPos, int width, int height, int picWidth, int picHeight, int xStartInCU, int yStartInCU, int xBv, int yBv, int ctuSize);
 #endif
+#if MCTS_ENC_CONTSTRAINT || MCTS_DEC_CHECK
+  bool isMCTSBIORestriction           ( const PredictionUnit& pu );
+#endif
 }
 
 // TU tools
@@ -373,5 +376,9 @@ uint32_t updateDoubleCandList(T mode, double cost, static_vector<T, N>& candMode
 }
 #endif
 
+#if MCTS_ENC_CONTSTRAINT
+void getTilePosition(const PredictionUnit& pu, int &tileXPosInCtus, int &tileYPosInCtus, int &tileWidthtInCtus, int &tileHeightInCtus);
+void getTilePosition( const CodingStructure* cs, const int ctuAddr, int &tileXPosInCtus, int &tileYPosInCtus, int &tileWidthtInCtus, int &tileHeightInCtus );
+#endif
 
 #endif
diff --git a/source/Lib/CommonLib/dtrace.h b/source/Lib/CommonLib/dtrace.h
index 2d13a63..6e96837 100644
--- a/source/Lib/CommonLib/dtrace.h
+++ b/source/Lib/CommonLib/dtrace.h
@@ -155,6 +155,56 @@ public:
 #endif
 };
 
+#if ENABLE_COMPR_PIC_STAT
+// Class CBitCounter: a simple straight forward counter for processed bits
+typedef enum {
+  BS_SIGNALING,
+  BS_TEXTURE,
+  BS_OTHER,
+  BS_NUM_STAGES,
+} BITCOUNTER_STAGE;
+
+class CBitCounter
+{
+public:
+  CBitCounter() {};
+  ~CBitCounter() {};
+
+  void reset()
+  {
+    for( int i = 0; i < BS_NUM_STAGES; i++ ) m_bits[i] = 0;
+  }
+  void startCount( BITCOUNTER_STAGE s, int bits )
+  {
+    m_stage = s;
+    m_prevBits = bits;
+  }
+  void startCountWithReset( BITCOUNTER_STAGE s, int bits )
+  {
+    reset();
+    startCount( s, bits );
+  }
+  void stopCount( int bits )
+  {
+    m_bits[m_stage] += bits - m_prevBits;
+  }
+  void accumBits( BITCOUNTER_STAGE s, int bits )
+  {
+    m_bits[m_stage] += bits - m_prevBits;
+    startCount( s, bits );
+  }
+  void accumulate( CBitCounter* pcSrc )
+  {
+    for( int j = 0; j < BS_NUM_STAGES; j++ )
+      m_bits[j] += pcSrc->m_bits[j];
+  }
 
+public:
+  int64_t m_bits[BS_NUM_STAGES];
+private:
+  int m_prevBits;
+  BITCOUNTER_STAGE m_stage;
+};
+#endif
 #endif // _DTRACE_H_
 
diff --git a/source/Lib/CommonLib/dtrace_codingstruct.h b/source/Lib/CommonLib/dtrace_codingstruct.h
index e48a45a..d62abe5 100644
--- a/source/Lib/CommonLib/dtrace_codingstruct.h
+++ b/source/Lib/CommonLib/dtrace_codingstruct.h
@@ -176,6 +176,187 @@ inline void dtraceBestMode(CodingStructure *&tempCS, CodingStructure *&bestCS, d
   }
 }
 
+#if ENABLE_COMPR_PIC_STAT
+static inline void dtraceComprPicStat( const CodingStructure& cs, bool isEncoder = false )
+{
+  if( cs.slice == nullptr )
+  {
+    return;
+  }
+
+  if( cs.picture->poc == 0 )
+  {
+    DTRACE( g_trace_ctx, D_COMPRPICSTAT, "# Lib 1.0.12\n" );
+  }
+
+  // NOTE: Example for using of user defined mode (intra/inter flag)
+  //       Step 1: Set range of user mode data here (0...MaxValue)
+  int userDefinedMode1Range = 2; // <--- define the range of user defined mode data here
+  int userDefinedMode2Range = 0; // <--- define the range of user defined mode data here
+
+  // Header
+  DTRACE( g_trace_ctx, D_COMPRPICSTAT, "H:W=%d,H=%d,CTU=%d,SType=%d,POC=%d,TID=%d,U0=%d,U1=%d\n", cs.area.lumaSize().width, cs.area.lumaSize().height, g_aucLog2[cs.pcv->maxCUWidth], cs.slice->getSliceType() == I_SLICE ? 1 : 0, cs.picture->poc, cs.slice->getTLayer(), userDefinedMode1Range, userDefinedMode2Range );
+
+  for( const auto &cu : cs.traverseCUs( cs.area, CHANNEL_TYPE_LUMA/*cs.chType*/ ) )
+  {
+    for( const auto &pu : CU::traversePUs( cu ) )
+    {
+      const Area& puArea = pu.Y();
+
+      // NOTE: Example for using of user defined mode (PU intra/inter flag)
+      //       Step 2: Assign user mode
+      int userDefinedMode1 = CU::isIntra( cu ) ? 1 : 0; // <--- users can output their modes/parameters here (PU-level)
+      int userDefinedMode2 = 0;                        // <--- users can output their modes/parameters here (PU-level)
+
+      bool bHighPrecMv = true;
+      // PU-info
+      DTRACE( g_trace_ctx, D_COMPRPICSTAT, "P:%d,%d,%d,%d,%d,%d", cs.picture->poc, 0, puArea.x, puArea.y, puArea.width, puArea.height );
+      if( CU::isInter( cu ) )
+      {
+        Mv mv[NUM_REF_PIC_LIST_01];
+        CMotionBuf mb = pu.getMotionBuf();
+        mv[L0] = mb.at( 0, 0 ).mv[L0];
+        mv[L1] = mb.at( 0, 0 ).mv[L1];
+        if( bHighPrecMv )
+        {
+          mv[0] >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+          mv[1] >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+        }
+
+        if( cu.skip || pu.mergeFlag )
+        {
+          DTRACE( g_trace_ctx, D_COMPRPICSTAT, ",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+            cu.skip ? 2 : 3,
+            pu.mergeIdx,
+            pu.refIdx[0], pu.refIdx[1],
+            mv[0].getHor(), mv[0].getVer(),
+            mv[1].getHor(), mv[1].getVer(),
+            0,
+            userDefinedMode1,
+            userDefinedMode2,
+            cu.imv,
+            0/*InterFTMRegIdx*/,
+            false/*bHighPrecMv*/,
+            cu.affine
+          );
+
+          if( cu.affine )
+          {
+            Mv mv;
+            CMotionBuf mb = pu.getMotionBuf();
+            for( int j = 0; j < 2; j++ )
+            {
+              for( int l = 0; l < 2; l++ )
+              {
+                RefPicList eRefList = RefPicList( l );
+                if( pu.cs->slice->getNumRefIdx( eRefList ) > 0 && ( pu.interDir & ( 1 << l ) ) )
+                {
+                  mv = ( j == 0 )? mb.at( mb.width - 1, 0 ).mv[l]: mb.at( mb.width - 1, mb.height - 1 ).mv[l];
+                  if( bHighPrecMv )
+                  {
+                    mv >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+                  }
+                  DTRACE( g_trace_ctx, D_COMPRPICSTAT, ",%d,%d"
+                    , mv.getHor(), mv.getVer()
+                  );
+                }
+              }
+            }
+          }
+        }
+        else
+        {
+          Mv mvd[NUM_REF_PIC_LIST_01];
+
+          if( cu.affine )
+          {
+            mvd[L0] = Mv( pu.mvdAffi[L0][0] ) >>= ( cu.imv << 1 );
+            mvd[L1] = Mv( pu.mvdAffi[L1][0] ) >>= ( cu.imv << 1 );
+          }
+          else
+          {
+            mvd[L0] = Mv( pu.mvd[L0] ) >>= ( cu.imv << 1 );
+            mvd[L1] = Mv( pu.mvd[L1] ) >>= ( cu.imv << 1 );
+          }
+
+          DTRACE( g_trace_ctx, D_COMPRPICSTAT, ",%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+            cu.predMode,
+            pu.interDir, 0,
+            pu.refIdx[0], pu.refIdx[1],
+            mv[0].getHor(), mv[0].getVer(),
+            mv[1].getHor(), mv[1].getVer(),
+            mvd[0].getHor(), mvd[0].getVer(),
+            mvd[1].getHor(), mvd[1].getVer(),
+            0,
+            userDefinedMode1,
+            userDefinedMode2,
+            cu.imv,
+            false/*bHighPrecMv*/,
+            cu.affine
+          );
+
+          if( cu.affine )
+          {
+            Mv mv;
+            Mv mvd;
+            CMotionBuf mb = pu.getMotionBuf();
+            for( int j = 0; j < 2; j++ )
+            {
+              for( int l = 0; l < 2; l++ )
+              {
+                RefPicList eRefList = RefPicList( l );
+                if( pu.cs->slice->getNumRefIdx( eRefList ) > 0 && ( pu.interDir & ( 1 << l ) ) )
+                {
+                  mv = ( j == 0 ) ? mb.at( mb.width - 1, 0 ).mv[l] : mb.at( mb.width - 1, mb.height - 1 ).mv[l];
+                  mvd = Mv( pu.mvdAffi[l][j+1] ) >>= ( cu.imv << 1 );
+                  if( bHighPrecMv )
+                  {
+                    mv >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+                  }
+                  DTRACE( g_trace_ctx, D_COMPRPICSTAT, ",%d,%d,%d,%d",
+                    mv.getHor(), mv.getVer(),
+                    mvd.getHor(), mvd.getVer()
+                  );
+                }
+              }
+            }
+          }
+        }
+        DTRACE( g_trace_ctx, D_COMPRPICSTAT, "\n" );
+      }
+      else
+      {
+        CHECK( !CU::isIntra( cu ), "Expecting an intra CU" );
+        DTRACE( g_trace_ctx, D_COMPRPICSTAT, ",%d,%d,%d,%d,%d,%d\n", cu.predMode, pu.intraDir[0], pu.intraDir[1], 0, userDefinedMode1, userDefinedMode2 );
+      }
+    }
+
+    // CU-info
+    const Area& area = cu.Y();
+    DTRACE( g_trace_ctx, D_COMPRPICSTAT, "C:%d,%d,%d,%d,%d,%d", cs.picture->poc, 0, area.x, area.y, area.width, area.height );
+    uint64_t bits[3] = { cu.infoBits, cu.trafoBits, cu.otherBits };
+    if( isEncoder )
+    {
+      bits[0] >>= SCALE_BITS; bits[1] >>= SCALE_BITS; bits[2] >>= SCALE_BITS;
+    }
+    int predMode = cu.skip ? 2 : ( cs.sps->getPTL()->getGeneralPTL()->getProfileIdc() == Profile::NEXT && cu.firstPU->mergeFlag ) ? 3 : cu.predMode;
+    int emtIdx = cu.firstTU ? cu.firstTU->emtIdx : 0;
+    int cbfLuma = cu.firstTU ? cu.firstTU->cbf[COMPONENT_Y] : 0;
+    int trafoSkipLuma = cu.firstTU ? cu.firstTU->transformSkip[COMPONENT_Y] : 0;
+    int userDefinedMode1 = 0; // <--- users can output their modes/parameters here (CU-level)
+    int userDefinedMode2 = 0; // <--- users can output their modes/parameters here (CU-level)
+
+    DTRACE( g_trace_ctx, D_COMPRPICSTAT, ",%d,%d,%d,%d,%d,%d,%d,%d", predMode, 0/*cu.partSize*/, cu.cost, bits[0], bits[1], bits[2], userDefinedMode1, userDefinedMode2 );
+    DTRACE( g_trace_ctx, D_COMPRPICSTAT, ",%d,%d,%d,%d,%d,%d\n", cbfLuma, trafoSkipLuma, cu.emtFlag, emtIdx, 0 /*cu.nsstIdx*/, cu.affine );
+    //}
+  }
+}
+#endif
+
+
+
+
+
 
 #define DTRACE_PIC_COMP(...)             dtracePicComp( __VA_ARGS__ )
 #define DTRACE_BEST_MODE(...)            dtraceBestMode(__VA_ARGS__)
diff --git a/source/Lib/CommonLib/dtrace_next.h b/source/Lib/CommonLib/dtrace_next.h
index 508072b..d732e19 100644
--- a/source/Lib/CommonLib/dtrace_next.h
+++ b/source/Lib/CommonLib/dtrace_next.h
@@ -142,6 +142,9 @@ enum DTRACE_CHANNEL
   D_RDOQ_COST,
   D_TMP,
   D_CRC
+#if ENABLE_COMPR_PIC_STAT
+  , D_COMPRPICSTAT
+#endif
 #if K0149_BLOCK_STATISTICS
   ,
   D_BLOCK_STATISTICS_ALL,
@@ -243,6 +246,9 @@ inline CDTrace* tracing_init( std::string& sTracingFile, std::string& sTracingRu
     _CNL_DEF( D_RDOQ_COST ),
     _CNL_DEF( D_TMP ),
     _CNL_DEF( D_CRC )
+#if ENABLE_COMPR_PIC_STAT
+    , _CNL_DEF( D_COMPRPICSTAT )
+#endif
   #if K0149_BLOCK_STATISTICS
     ,
     _CNL_DEF( D_BLOCK_STATISTICS_ALL ),
@@ -282,5 +288,14 @@ inline CDTrace* tracing_init( std::string& sTracingFile, std::string& sTracingRu
 
 #endif
 
-
+#if ENABLE_COMPR_PIC_STAT
+#if ENABLE_TRACING
+//#define BITCOUNT_CU                           &g_bitCounterCU
+#define BITCOUNT_RESET(_o)                    (_o)->reset()
+#define BITCOUNT_START(_o,_stage,_bits)       (_o)->startCountWithReset(_stage,_bits)
+#define BITCOUNT_STOP(_o,_bits)               (_o)->stopCount(_bits)
+#define BITCOUNT_ACCUM(_o,_stage,_bits)       (_o)->accumBits(_stage,_bits)
+#define BITCOUNT_GET_BITS(_o,_stage,_dst)     (_dst)=(_o)->m_bits[_stage]
+#endif
+#endif
 #endif // _DTRACE_HEVC_H_
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index b4af456..4bd6b87 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -62,6 +62,23 @@
 #define RExt__DECODER_DEBUG_BIT_STATISTICS_SET(x)
 #endif
 
+#if ENABLE_COMPR_PIC_STAT
+#define GET_NUM_BITS_READ                get_num_bits_read()
+#define BITCNT_CU                        &g_bitCounterCU
+#define BITCNT_START(_stage)             BITCOUNT_START( BITCNT_CU, _stage, GET_NUM_BITS_READ )
+#define BITCNT_STOP()                    BITCOUNT_STOP ( BITCNT_CU,         GET_NUM_BITS_READ )
+#define BITCNT_ACCUM(_stage)             BITCOUNT_ACCUM( BITCNT_CU, _stage, GET_NUM_BITS_READ )
+#define BITCNT_GET_BITS(_info,_trafo,_other) {          \
+  BITCOUNT_GET_BITS( BITCNT_CU,BS_SIGNALING,  _info  ); \
+  BITCOUNT_GET_BITS( BITCNT_CU,BS_TEXTURE,    _trafo ); \
+  BITCOUNT_GET_BITS( BITCNT_CU,BS_OTHER,      _other ); \
+}
+// #else
+// #define BITCNT_START(_stage)
+// #define BITCNT_STOP()
+// #define BITCNT_ACCUM(_stage)
+// #define BITCNT_GET_BITS(_info,_trafo,_other)
+#endif
 
 void CABACReader::initCtxModels( Slice& slice )
 {
@@ -143,9 +160,14 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i
   Partitioner *partitioner = PartitionerFactory::get( *cs.slice );
 
   partitioner->initCtu( area, CH_L, *cs.slice );
-
+#if ENABLE_COMPR_PIC_STAT
+  BITCNT_START( BS_SIGNALING );
+#endif
 
   sao( cs, ctuRsAddr );
+#if ENABLE_COMPR_PIC_STAT
+  BITCNT_ACCUM( BS_OTHER );
+#endif
 
   AlfSliceParam& alfSliceParam = cs.slice->getAlfSliceParam();
 
@@ -159,9 +181,9 @@ bool CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i
     const Position      pos( rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight );
     const uint32_t          curSliceIdx = cs.slice->getIndependentSliceIdx();
 #if HEVC_TILES_WPP
-    const uint32_t          curTileIdx = cs.picture->tileMap->getTileIdxMap( pos );
-    bool                leftMergeAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
-    bool                aboveMergeAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
+    const uint32_t      curTileIdx = cs.picture->tileMap->getTileIdxMap( pos );
+    bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
+    bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
 #else
     bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, CH_L ) ? true : false;
     bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, CH_L ) ? true : false;
@@ -559,7 +581,9 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU
       }
     }
   }
-
+#if ENABLE_COMPR_PIC_STAT
+  BITCNT_ACCUM( BS_SIGNALING );
+#endif
 
   CodingUnit& cu = cs.addCU( CS::getArea( cs, currArea, partitioner.chType ), partitioner.chType );
 
@@ -587,6 +611,11 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU
   bool isLastCtu = coding_unit( cu, partitioner, cuCtx );
 
   DTRACE( g_trace_ctx, D_QP, "x=%d, y=%d, w=%d, h=%d, qp=%d\n", cu.Y().x, cu.Y().y, cu.Y().width, cu.Y().height, cu.qp );
+#if ENABLE_COMPR_PIC_STAT
+  BITCNT_STOP();
+  BITCNT_GET_BITS( cu.infoBits, cu.trafoBits, cu.otherBits );
+  BITCNT_START( BS_OTHER );
+#endif
   return isLastCtu;
 }
 
@@ -2229,7 +2258,9 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID )
   // parse transform skip and explicit rdpcm mode
   transform_skip_flag( tu, compID );
   explicit_rdpcm_mode( tu, compID );
-
+#if ENABLE_COMPR_PIC_STAT
+  BITCNT_ACCUM( BS_TEXTURE );
+#endif
 
 #if HEVC_USE_SIGN_HIDING
   // determine sign hiding
@@ -2298,6 +2329,9 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID )
       emt_tu_index( tu );
     }
   }
+#if ENABLE_COMPR_PIC_STAT
+  BITCNT_ACCUM( BS_SIGNALING );
+#endif
 }
 
 
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index c90d2b5..582e480 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -526,6 +526,7 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         if( pu.cu->triangle )
         {
           PU::getTriangleMergeCandidates( pu, m_triangleMrgCtx );
+          //PU::spanTriangleMotionInfo( *cu.firstPU, m_triangleMrgCtx, mergeIdx, splitDir, candIdx0, candIdx1 );
         }
         else
         {
@@ -722,6 +723,16 @@ void DecCu::xDeriveCUMV( CodingUnit &cu )
         PU::spanMotionInfo( pu, mrgCtx );
       }
     }
+#if MCTS_DEC_CHECK
+    if( !cu.triangle )
+    {
+      if( g_mctsDecCheckEnabled && !m_pcInterPred->checkTMctsMv( 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/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index e0a9f3b..d45adef 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -579,6 +579,10 @@ void DecLib::finishPicture(int& poc, PicList*& rpcListPic, MsgLevel msgl )
 
   msg( msgl, "\n");
 
+#if MCTS_REC_CHECK
+  establishPictureTilesRefBuffers( m_pcPic, pcSlice );
+#endif
+
   m_pcPic->neededForOutput = (pcSlice->getPicOutputFlag() ? true : false);
   m_pcPic->reconstructed = true;
 
diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp
index 523619d..6993c7e 100644
--- a/source/Lib/DecoderLib/DecSlice.cpp
+++ b/source/Lib/DecoderLib/DecSlice.cpp
@@ -112,13 +112,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream )
 #else
   const int       startCtuTsAddr          = slice->getSliceCurStartCtuTsAddr();
 #endif
-#if HEVC_TILES_WPP
-  const int       startCtuRsAddr          = tileMap.getCtuTsToRsAddrMap(startCtuTsAddr);
-#else
+//#if HEVC_TILES_WPP
+//  const int       startCtuRsAddr          = tileMap.getCtuTsToRsAddrMap(startCtuTsAddr);
+//#else
 #if HEVC_DEPENDENT_SLICES
   const int       startCtuRsAddr          = startCtuTsAddr;
 #endif
-#endif
+//#endif
   const unsigned  numCtusInFrame          = cs.pcv->sizeInCtus;
   const unsigned  widthInCtus             = cs.pcv->widthInCtus;
 #if HEVC_DEPENDENT_SLICES
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 80a6589..5ba04fd 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -445,6 +445,7 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS )
 #if HEVC_TILES_WPP
   READ_FLAG( uiCode, "tiles_enabled_flag" );    pcPPS->setTilesEnabledFlag( uiCode == 1 );
 #endif
+
 #if HEVC_TILES_WPP
   READ_FLAG( uiCode, "entropy_coding_sync_enabled_flag" );    pcPPS->setEntropyCodingSyncEnabledFlag( uiCode == 1 );
 
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 6197f1f..d4e05e6 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -542,6 +542,7 @@ void CABACWriter::split_cu_flag( bool split, const CodingStructure& cs, Partitio
   {
     return;
   }
+  
   unsigned  ctxId = DeriveCtx::CtxCUsplit( cs, partitioner );
   m_BinEncoder.encodeBin( (split), Ctx::SplitFlag(ctxId) );
 
@@ -2831,8 +2832,10 @@ void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr,
     const uint32_t          curSliceIdx = cs.slice->getIndependentSliceIdx();
 #if HEVC_TILES_WPP
     const uint32_t          curTileIdx = cs.picture->tileMap->getTileIdxMap( pos );
-    bool                leftMergeAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
-    bool                aboveMergeAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
+    bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
+    bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
+    //bool                leftMergeAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
+    //bool                aboveMergeAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, curTileIdx, CH_L ) ? true : false;
 #else
     bool                leftAvail = cs.getCURestricted( pos.offset( -(int)pcv.maxCUWidth, 0 ), curSliceIdx, CH_L ) ? true : false;
     bool                aboveAvail = cs.getCURestricted( pos.offset( 0, -(int)pcv.maxCUHeight ), curSliceIdx, CH_L ) ? true : false;
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index bf5375d..5ecb1d9 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -448,6 +448,9 @@ protected:
   bool      m_SOPDescriptionSEIEnabled;
   bool      m_scalableNestingSEIEnabled;
   bool      m_tmctsSEIEnabled;
+#if MCTS_ENC_CONTSTRAINT
+  bool      m_MCTSEncConstraint;
+#endif
   bool      m_timeCodeSEIEnabled;
   int       m_timeCodeSEINumTs;
   SEITimeSet   m_timeSetArray[MAX_TIMECODE_SEI_SETS];
@@ -1207,6 +1210,10 @@ public:
   bool  getScalableNestingSEIEnabled() const                         { return m_scalableNestingSEIEnabled; }
   void  setTMCTSSEIEnabled(bool b)                                   { m_tmctsSEIEnabled = b; }
   bool  getTMCTSSEIEnabled()                                         { return m_tmctsSEIEnabled; }
+#if MCTS_ENC_CONTSTRAINT
+  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 5d394c7..7708915 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -608,7 +608,6 @@ void EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS,
           xFillPCMBuffer( cu );
         }
       }
-
       std::swap( tempCS, bestCS );
       // store temp best CI for next CU coding
       m_CurrCtx->best = m_CABACEstimator->getCtx();
@@ -1560,7 +1559,6 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P
   m_CABACEstimator->pcm_data       ( cu );
 #endif
 
-
   tempCS->fracBits = m_CABACEstimator->getEstFracBits();
   tempCS->cost     = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist);
 
@@ -1623,7 +1621,6 @@ void EncCu::xCheckDQP( CodingStructure& cs, Partitioner& partitioner, bool bKeep
     cs.fracBits += m_CABACEstimator->getEstFracBits(); // dQP bits
     cs.cost      = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist);
 
-
     if( !bKeepCtx ) m_CABACEstimator->getCtx() = SubCtx( Ctx::DeltaQP, ctxTemp );
 
     // NOTE: reset QPs for CUs without residuals up to first coded CU
@@ -2361,6 +2358,15 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #endif
       PU::spanMotionInfo( pu, mergeCtx );
 
+#if MCTS_ENC_CONTSTRAINT 
+      if( m_pcEncCfg->getMCTSEncConstraint() && ( !( m_pcInterSearch->checkTMctsMv( pu ) ) ) )
+      {
+        // Do not use this mode
+        tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+        continue;
+      }
+#endif
+
       if( mrgTempBufSet )
       {
 #if JVET_L0100_MULTI_HYPOTHESIS_INTRA
@@ -2435,7 +2441,11 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
       if( m_pcEncCfg->getUseFastDecisionForMerge() && !bestIsSkip )
 #endif
       {
+#if MCTS_ENC_CONTSTRAINT
+        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
@@ -2526,6 +2536,9 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
     cu.predMode = MODE_INTER;
     cu.slice    = tempCS->slice;
     cu.triangle = true;
+#if HEVC_TILES_WPP
+    cu.tileIdx  = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
 #if JVET_L0054_MMVD
     cu.mmvdSkip = false;
 #endif    
@@ -2544,7 +2557,14 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
       triangleBuffer[mergeCand] = m_acMergeBuffer[mergeCand].getBuf(localUnitArea);
       triangleMrgCtx.setMergeInfo( pu, mergeCand );
       PU::spanMotionInfo( pu, triangleMrgCtx );
-      
+#if MCTS_ENC_CONTSTRAINT
+      if( m_pcEncCfg->getMCTSEncConstraint() && ( !( m_pcInterSearch->checkTMctsMv( pu ) ) ) )
+      {
+        // Do not use this mode
+        tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+        return;
+      }
+#endif      
       m_pcInterSearch->motionCompensation( pu, triangleBuffer[mergeCand] );
     }
   }
@@ -2570,6 +2590,9 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
     cu.chromaQpAdj      = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
     cu.qp               = encTestMode.qp;
     cu.triangle         = true;
+#if HEVC_TILES_WPP
+    cu.tileIdx          = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
 #if JVET_L0054_MMVD
     cu.mmvdSkip         = false;
 #endif
@@ -2675,6 +2698,9 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
         cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
         cu.qp = encTestMode.qp;
         cu.triangle = true;
+#if HEVC_TILES_WPP
+        cu.tileIdx  = tempCS->picture->tileMap->getTileIdxMap( tempCS->area.lumaPos() );
+#endif
 #if JVET_L0054_MMVD
         cu.mmvdSkip = false;
 #endif
@@ -2960,6 +2986,15 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
       }
 #endif
 
+#if MCTS_ENC_CONTSTRAINT
+      if( m_pcEncCfg->getMCTSEncConstraint() && ( !( m_pcInterSearch->checkTMctsMv( *cu.firstPU ) ) ) )
+      {
+        // Do not use this mode
+        tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+        return;
+      }
+#endif
+
       if ( mrgTempBufSet )
       {
         tempCS->getPredBuf().copyFrom( acMergeBuffer[uiMergeCand] );
@@ -3062,6 +3097,15 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
 
   PU::spanMotionInfo( *cu.firstPU );
 
+#if MCTS_ENC_CONTSTRAINT
+  if( m_pcEncCfg->getMCTSEncConstraint() && ( !( m_pcInterSearch->checkTMctsMv( *cu.firstPU ) ) ) )
+  {
+    // Do not use this mode
+    tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+    return;
+  }
+#endif
+
   m_pcInterSearch->motionCompensation( cu );
 
   xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0
@@ -3836,6 +3880,15 @@ bool EncCu::xCheckRDCostInterIMV( CodingStructure *&tempCS, CodingStructure *&be
 #endif
   }
 
+#if MCTS_ENC_CONTSTRAINT 
+  if( m_pcEncCfg->getMCTSEncConstraint() && ( ( cu.firstPU->refIdx[L0] < 0 && cu.firstPU->refIdx[L1] < 0 ) || ( !( m_pcInterSearch->checkTMctsMv( *cu.firstPU ) ) ) ) )
+  {
+    // Do not use this mode
+    tempCS->initStructData( encTestMode.qp, encTestMode.lossless );
+    continue;
+  }
+#endif
+
 #if JVET_L0646_GBI
   if( testGbi && gbiIdx == GBI_DEFAULT ) // Enabled GBi but the search results is uni.
   {
@@ -4107,7 +4160,6 @@ void EncCu::xEncodeDontSplit( CodingStructure &cs, Partitioner &partitioner )
 
   cs.fracBits += m_CABACEstimator->getEstFracBits(); // split bits
   cs.cost      = m_pcRdCost->calcRdCost( cs.fracBits, cs.dist );
-
 }
 
 #if REUSE_CU_RESULTS
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index fc22bee..00557c2 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -2461,7 +2461,6 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
   delete pcBitstreamRedirect;
 
   CHECK(!( (m_iNumPicCoded == iNumPicRcvd) ), "Unspecified error");
-
 }
 
 void EncGOP::printOutSummary(uint32_t uiNumAllPicCoded, bool isField, const bool printMSEBasedSNR, const bool printSequenceMSE, const bool printHexPsnr, const BitDepths &bitDepths)
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 4949777..6e4ee98 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -1450,6 +1450,7 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps)
   xInitPPSforTiles(pps);
 #endif
 
+#
   pps.pcv = new PreCalcValues( sps, pps, true );
 }
 
@@ -1756,6 +1757,9 @@ void  EncLib::xInitPPSforTiles(PPS &pps)
   }
   pps.setLoopFilterAcrossTilesEnabledFlag( m_loopFilterAcrossTilesEnabledFlag );
 
+#if MCTS_ENC_CONTSTRAINT
+  printf( "\n -- Tiles = %dx%d\n", m_iNumColumnsMinus1 + 1, m_iNumRowsMinus1 + 1 );
+#endif
   // # substreams is "per tile" when tiles are independent.
 }
 #endif
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 0d62e21..466b55f 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -1283,9 +1283,14 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
     if (cs.sps->getSpsNext().getCPRMode() && !cuECtx.bestTU)
       return true;
 #endif
+ #if !MCTS_ENC_CONTSTRAINT
     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
+
 	  ( ( !m_pcEncCfg->getDisableIntraPUsInInterSlices() ) && !relatedCU.isInter && (
                                          ( cuECtx.bestTU->cbf[0] != 0 ) ||
            ( ( numComp > COMPONENT_Cb ) && cuECtx.bestTU->cbf[1] != 0 ) ||
@@ -1729,7 +1734,11 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt
   }
 
   // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded
+#if HHI_BUG_FIX_FOR_MCTS
+  if( tempCS->features[ENC_FT_RD_COST] != MAX_DOUBLE && ( !cuECtx.bestCS || tempCS->features[ENC_FT_RD_COST] < cuECtx.bestCS->features[ENC_FT_RD_COST] ) )
+#else
   if( !cuECtx.bestCS || tempCS->features[ENC_FT_RD_COST] < cuECtx.bestCS->features[ENC_FT_RD_COST] )
+#endif
   {
     cuECtx.bestCS = tempCS;
     cuECtx.bestCU = tempCS->cus[0];
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index 1ebdd44..59df733 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -1674,6 +1674,15 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
     }
 #endif
 
+#if MCTS_ENC_CONTSTRAINT
+    cs.slice->setInterPredRefPicArea( cs.pcv->mvRefPicArea );
+    if( !cs.slice->isIntra() && pCfg->getMCTSEncConstraint() )
+    {
+      m_pcInterSearch->getMCTSTileInfo().init( &cs, ctuRsAddr );
+      cs.slice->setInterPredRefPicArea( m_pcInterSearch->getMCTSTileInfo().getTileArea() );
+    }
+#endif
+
 #if ENABLE_WPP_PARALLELISM
     pEncLib->getCuEncoder( dataId )->compressCtu( cs, ctuArea, ctuRsAddr, prevQP, currQP );
 #else
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index 35afb98..690f2c8 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -1534,8 +1534,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 MCTS_ENC_CONTSTRAINT
+  int          iRefIdxBi[2] = { -1, -1 };
+#else
   int          iRefIdxBi[2];
-
+#endif
   uint32_t         uiMbBits[3] = {1, 1, 0};
 
   uint32_t         uiLastMode = 0;
@@ -1715,6 +1718,9 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
 #endif 
         )
       {
+#if MCTS_ENC_CONTSTRAINT
+        bool doBiPred = true;
+#endif
         cMvBi[0] = cMv[0];
         cMvBi[1] = cMv[1];
         iRefIdxBi[0] = iRefIdx[0];
@@ -1741,6 +1747,21 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
           pu.refIdx[REF_PIC_LIST_1] = iRefIdxBi[1];
           pu.mvpIdx[REF_PIC_LIST_1] = bestBiPMvpL1;
 
+#if MCTS_ENC_CONTSTRAINT
+            if( m_pcEncCfg->getMCTSEncConstraint() )
+            {
+              Mv restrictedMv = pu.mv[REF_PIC_LIST_1];
+              Area curTileAreaRestricted;
+              curTileAreaRestricted = m_mctsTileInfo.getTileAreaSubPelRestricted( pu );
+              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 );
 
@@ -1769,6 +1790,10 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
           uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
         }
 
+#if MCTS_ENC_CONTSTRAINT
+        if( doBiPred )
+        {
+#endif
         // 4-times iteration (default)
         int iNumIter = 4;
 
@@ -1914,6 +1939,10 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
             break;
           }
         } // for loop-iter
+#if MCTS_ENC_CONTSTRAINT
+        }
+#endif
+
 #if JVET_L0646_GBI
         cu.refIdxBi[0] = iRefIdxBi[0];
         cu.refIdxBi[1] = iRefIdxBi[1];
@@ -2132,6 +2161,16 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
         uiAffineCost += m_pcRdCost->getCost( 1 ); // add one bit for affine_type
       }
 
+#if MCTS_ENC_CONTSTRAINT
+      if( uiAffineCost < uiHevcCost )
+      {
+        if( m_pcEncCfg->getMCTSEncConstraint() && !checkTMctsMv( pu ) )
+        {
+          uiAffineCost = std::numeric_limits<Distortion>::max();
+        }
+      }
+#endif
+
       if ( uiHevcCost <= uiAffineCost )
       {
         // set hevc me result
@@ -2172,6 +2211,13 @@ void InterSearch::predInterSearch(CodingUnit& cu, Partitioner& partitioner)
       PU::spanMotionInfo( pu, mergeCtx );
     }
 
+#if MCTS_ENC_CHECK
+    if( m_pcEncCfg->getMCTSEncConstraint() && ( !( checkTMctsMv( pu, true ) ) ) )
+    {
+      msg( WARNING, "ENCODER: pu motion vector across tile boundaries (%d,%d,%d,%d)\n", pu.lx(), pu.ly(), pu.lwidth(), pu.lheight() );
+    }
+#endif
+
     //  MC
     PelUnitBuf predBuf = pu.cs->getPredBuf(pu);
     motionCompensation( pu, predBuf, REF_PIC_LIST_X );
@@ -2541,18 +2587,37 @@ void InterSearch::xMotionEstimation(PredictionUnit& pu, PelUnitBuf& origBuf, Ref
     }
   }
 
-  DTRACE( g_trace_ctx, D_ME, "%d %d %d :MECostFPel<L%d,%d>: %d,%d,%dx%d, %d", DTRACE_GET_COUNTER( g_trace_ctx, D_ME ), pu.cu->slice->getPOC(), 0, ( int ) eRefPicList, ( int ) bBi, pu.Y().x, pu.Y().y, pu.Y().width, pu.Y().height, ruiCost );
+  DTRACE( g_trace_ctx, D_ME, "%d %d %d :MECostFPel<L%d,%d>: %d,%d,%dx%d,%2d: %d", DTRACE_GET_COUNTER( g_trace_ctx, D_ME ), pu.cu->slice->getPOC(), 0, ( int ) eRefPicList, ( int ) bBi, pu.Y().x, pu.Y().y, pu.Y().width, pu.Y().height, ruiCost );
   // sub-pel refinement for sub-pel resolution
   if( pu.cu->imv == 0 )
   {
-    xPatternSearchFracDIF( pu, eRefPicList, iRefIdxPred, cStruct, rcMv, cMvHalf, cMvQter, ruiCost );
-    m_pcRdCost->setCostScale( 0 );
-    rcMv <<= 2;
-    rcMv  += ( cMvHalf <<= 1 );
-    rcMv  += cMvQter;
-    uint32_t uiMvBits = m_pcRdCost->getBitsOfVectorWithPredictor( rcMv.getHor(), rcMv.getVer(), cStruct.imvShift );
-    ruiBits += uiMvBits;
-    ruiCost = ( Distortion ) ( floor( fWeight * ( ( double ) ruiCost - ( double ) m_pcRdCost->getCost( uiMvBits ) ) ) + ( double ) m_pcRdCost->getCost( ruiBits ) );
+#if MCTS_ENC_CONTSTRAINT
+    bool doFracSearch = true;
+    if( m_pcEncCfg->getMCTSEncConstraint() )
+    {
+      Area curTileAreaSubPelRestricted = m_mctsTileInfo.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 ) )
+      {
+        clipMvToArea( rcMv, pu.cu->Y(), curTileAreaSubPelRestricted, *pu.cs->sps, 0 );
+      }
+    }
+
+    if( doFracSearch )
+#endif
+    {
+      xPatternSearchFracDIF( pu, eRefPicList, iRefIdxPred, cStruct, rcMv, cMvHalf, cMvQter, ruiCost );
+      m_pcRdCost->setCostScale( 0 );
+      rcMv <<= 2;
+      rcMv += ( cMvHalf <<= 1 );
+      rcMv += cMvQter;
+      uint32_t uiMvBits = m_pcRdCost->getBitsOfVectorWithPredictor( rcMv.getHor(), rcMv.getVer(), cStruct.imvShift );
+      ruiBits += uiMvBits;
+      ruiCost = (Distortion)( floor( fWeight * ( (double)ruiCost - (double)m_pcRdCost->getCost( uiMvBits ) ) ) + (double)m_pcRdCost->getCost( ruiBits ) );
+    }
   }
   else // integer refinement for integer-pel and 4-pel resolution
   {
@@ -2588,12 +2653,14 @@ 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(),
 #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);
   Mv mvBR(cFPMvPred.getHor() + (iSrchRng << iMvShift), cFPMvPred.getVer() + (iSrchRng << iMvShift), cFPMvPred.highPrec);
@@ -2602,6 +2669,26 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu,
   Mv mvBR(cFPMvPred.getHor() + (iSrchRng << iMvShift), cFPMvPred.getVer() + (iSrchRng << iMvShift));
 #endif
 
+#if MCTS_ENC_CONTSTRAINT
+  if (m_pcEncCfg->getMCTSEncConstraint())
+  {
+    clipMvToArea( mvTL, pu.Y(), pu.cs->slice->getInterPredRefPicArea(), *pu.cs->sps );
+    clipMvToArea( mvBR, pu.Y(), pu.cs->slice->getInterPredRefPicArea(), *pu.cs->sps );
+  }
+  else
+  {
+    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 );
+  }
+#else
   clipMv( mvTL, pu.cu->lumaPos(),
 #if JVET_L0231_WRAPAROUND
           pu.cu->lumaSize(),
@@ -2612,6 +2699,7 @@ void InterSearch::xSetSearchRange ( const PredictionUnit& pu,
           pu.cu->lumaSize(),
 #endif
           *pu.cs->sps );
+#endif
 
   mvTL.divideByPowerOf2( iMvShift );
   mvBR.divideByPowerOf2( iMvShift );
@@ -2761,6 +2849,13 @@ 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
+#if MCTS_ENC_CONTSTRAINT
+  if( m_pcEncCfg->getMCTSEncConstraint() )
+  {
+    clipMvToArea( rcMv, pu.Y(), pu.cs->slice->getInterPredRefPicArea(), *pu.cs->sps );
+  }
+  else
+#endif
   clipMv( rcMv, pu.cu->lumaPos(),
 #if JVET_L0231_WRAPAROUND
           pu.cu->lumaSize(),
@@ -2806,6 +2901,13 @@ 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
+#if MCTS_ENC_CONTSTRAINT
+    if( m_pcEncCfg->getMCTSEncConstraint() )
+    {
+      clipMvToArea( integerMv2Nx2NPred, pu.Y(), pu.cs->slice->getInterPredRefPicArea(), *pu.cs->sps );
+    }
+    else
+#endif
     clipMv( integerMv2Nx2NPred, pu.cu->lumaPos(),
 #if JVET_L0231_WRAPAROUND
             pu.cu->lumaSize(),
@@ -3234,9 +3336,34 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct&
       cTestMv[iMVPIdx] += cBaseMvd[iMVPIdx];
       cTestMv[iMVPIdx] += amvpInfo.mvCand[iMVPIdx];
 
+#if MCTS_ENC_CONTSTRAINT
+      // MCTS and IMV
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        Mv cTestMVRestr = cTestMv[iMVPIdx];
+#if REMOVE_MV_ADAPT_PREC
+        cTestMVRestr <<= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+#endif
+        clipMvToArea( cTestMVRestr, pu.cu->Y(), m_mctsTileInfo.getTileAreaFullPelRestricted( pu ), *pu.cs->sps );
+
+#if REMOVE_MV_ADAPT_PREC
+        cTestMVRestr >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+#endif
+        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 MCTS_ENC_CONTSTRAINT
+        if( !m_pcEncCfg->getMCTSEncConstraint() )
+        {
+#endif
 #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;
@@ -3250,6 +3377,9 @@ 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
+#if MCTS_ENC_CONTSTRAINT
+        }
+#endif
         m_cDistParam.cur.buf = cStruct.piRefY  + cStruct.iRefStride * (cTempMV.getVer() >>  2) + (cTempMV.getHor() >> 2);
         uiDist = uiSATD = (Distortion) (m_cDistParam.distFunc( m_cDistParam ) * fWeight);
       }
@@ -3272,7 +3402,13 @@ void InterSearch::xPatternSearchIntRefine(PredictionUnit& pu, IntTZSearchStruct&
       }
     }
   }
-
+#if MCTS_ENC_CONTSTRAINT
+  if( uiBestDist == std::numeric_limits<Distortion>::max() )
+  {
+    ruiCost = std::numeric_limits<Distortion>::max();
+    return;
+  }
+#endif
   rcMv = cBestMv;
   rcMvPred = amvpInfo.mvCand[iBestMVPIdx];
   riMVPIdx = iBestMVPIdx;
@@ -3740,6 +3876,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
     ::memcpy( aaiMvpIdxBi, aaiMvpIdx, sizeof(aaiMvpIdx) );
 
     uint32_t uiMotBits[2];
+#if MCTS_ENC_CONTSTRAINT
+    bool doBiPred = true;
+#endif
 
     if ( slice.getMvdL1ZeroFlag() ) // GPB, list 1 only use Mvp
     {
@@ -3756,6 +3895,28 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
       ::memcpy( cMvTemp[1][bestBiPRefIdxL1],   pcMvTemp, sizeof(Mv)*3 );
       iRefIdxBi[1] = bestBiPRefIdxL1;
 
+#if MCTS_ENC_CONTSTRAINT
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        Area curTileAreaRestricted;
+        curTileAreaRestricted = m_mctsTileInfo.getTileAreaSubPelRestricted( pu );
+        for( int i = 0; i < mvNum; i++ )
+        {
+          Mv restrictedMv = pcMvTemp[i];
+          restrictedMv <<= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+          clipMvToArea( restrictedMv, pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+          restrictedMv >>= VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
+
+          // 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 REMOVE_MV_ADAPT_PREC
@@ -3789,6 +3950,10 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
       uiBits[2] = uiMbBits[2] + uiMotBits[0] + uiMotBits[1];
     }
 
+#if MCTS_ENC_CONTSTRAINT
+    if( doBiPred )
+    {
+#endif
     // 4-times iteration (default)
     int iNumIter = 4;
     // fast encoder setting or GPB: only one iteration
@@ -3937,6 +4102,9 @@ void InterSearch::xPredAffineInterSearch( PredictionUnit&       pu,
         break;
       }
     } // for loop-iter
+#if MCTS_ENC_CONTSTRAINT
+    }
+#endif
   } // if (B_SLICE)
 
   pu.mv    [REF_PIC_LIST_0] = Mv();
@@ -4307,6 +4475,19 @@ void InterSearch::xAffineMotionEstimation( PredictionUnit& pu,
   uint32_t uiBitsBest = 0;
 
   // do motion compensation with origin mv
+#if MCTS_ENC_CONTSTRAINT
+  if( m_pcEncCfg->getMCTSEncConstraint() )
+  {
+    Area curTileAreaRestricted = m_mctsTileInfo.getTileAreaSubPelRestricted( pu );
+    clipMvToArea( acMvTemp[0], pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+    clipMvToArea( acMvTemp[1], pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+    if( pu.cu->affineType == AFFINEMODEL_6PARAM )
+    {
+      clipMvToArea( acMvTemp[2], pu.cu->Y(), curTileAreaRestricted, *pu.cs->sps );
+    }
+  }
+  else
+#endif
   clipMv( acMvTemp[0], pu.cu->lumaPos(),
 #if JVET_L0231_WRAPAROUND
           pu.cu->lumaSize(),
@@ -4496,6 +4677,13 @@ 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();
+#if MCTS_ENC_CONTSTRAINT
+      if( m_pcEncCfg->getMCTSEncConstraint() )
+      {
+        clipMvToArea( acMvTemp[i], pu.cu->Y(), m_mctsTileInfo.getTileAreaSubPelRestricted( pu ), *pu.cs->sps );
+      }
+      else
+#endif
       clipMv(acMvTemp[i], pu.cu->lumaPos(),
 #if JVET_L0231_WRAPAROUND
              pu.cu->lumaSize(),
@@ -5633,7 +5821,6 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
     cs.dist     = distortion;
     cs.fracBits = m_CABACEstimator->getEstFracBits();
     cs.cost     = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist);
-
     return;
   }
 
diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h
index 5c90bb0..531beb4 100644
--- a/source/Lib/EncoderLib/InterSearch.h
+++ b/source/Lib/EncoderLib/InterSearch.h
@@ -327,6 +327,10 @@ protected:
                                     bool                  bBi = false
                                   );
 
+#if MCTS_ENC_CONTSTRAINT
+  void xInitMctsTileInfo(const PredictionUnit& pu, MCTSTileInfo& mctsTileInfo);
+#endif
+
   void xTZSearch                  ( const PredictionUnit& pu,
                                     IntTZSearchStruct&    cStruct,
                                     Mv&                   rcMv,
diff --git a/source/Lib/EncoderLib/SEIEncoder.cpp b/source/Lib/EncoderLib/SEIEncoder.cpp
index 9eb691e..5a987d3 100644
--- a/source/Lib/EncoderLib/SEIEncoder.cpp
+++ b/source/Lib/EncoderLib/SEIEncoder.cpp
@@ -359,6 +359,19 @@ void SEIEncoder::initSEITempMotionConstrainedTileSets (SEITempMotionConstrainedT
 
   if(pps->getTilesEnabledFlag())
   {
+#if MCTS_ENC_CONTSTRAINT
+    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 +392,9 @@ void SEIEncoder::initSEITempMotionConstrainedTileSets (SEITempMotionConstrainedT
       sei->tileSetData(i).m_mcts_tier_level_idc_present_flag = false;
     }
   }
+#if MCTS_ENC_CONTSTRAINT
+  }
+#endif
   else
   {
     CHECK(!(!"Tile is not enabled"), "Unspecified error");
-- 
2.13.0.windows.1

