diff --git a/cfg/encoder_intra_vtm.cfg b/cfg/encoder_intra_vtm.cfg
index ddc4dedad848dad11a83c285a8722612bbfe97b5..1a07b246f7967cb7eb0e1e5a166df3a098aeef4e 100644
--- a/cfg/encoder_intra_vtm.cfg
+++ b/cfg/encoder_intra_vtm.cfg
@@ -114,7 +114,7 @@ LMCSEnable                   : 1      # LMCS: 0: disable, 1:enable
 LMCSSignalType               : 0      # Input signal type: 0:SDR, 1:HDR-PQ, 2:HDR-HLG
 LMCSUpdateCtrl               : 1      # LMCS model update control: 0:RA, 1:AI, 2:LDB/LDP
 MIP                          : 1
-
+JointCbCr                    : 1      # JointCbCr: 0: disable, 1: enable
 # Fast tools
 PBIntraFast                  : 1
 ISPFast                      : 1
diff --git a/cfg/encoder_lowdelay_P_vtm.cfg b/cfg/encoder_lowdelay_P_vtm.cfg
index 2d24145ce7acb6aabf6cc9e5b58d88f1aa0d3db0..73175d5e95b3ef77f04e663bc208470f3a4a0bb8 100644
--- a/cfg/encoder_lowdelay_P_vtm.cfg
+++ b/cfg/encoder_lowdelay_P_vtm.cfg
@@ -130,10 +130,12 @@ LMCSEnable                   : 1      # LMCS: 0: disable, 1:enable
 LMCSSignalType               : 0      # Input signal type: 0:SDR, 1:HDR-PQ, 2:HDR-HLG
 LMCSUpdateCtrl               : 2      # LMCS model update control: 0:RA, 1:AI, 2:LDB/LDP
 MIP                          : 1
+JointCbCr                    : 1      # JointCbCr: 0: disable, 1: enable
+PROF                         : 1
 
 # Fast tools
 PBIntraFast                  : 1
-ISPFast                      : 1
+ISPFast                      : 0
 FastMrg                      : 1
 AMaxBT                       : 1
 FastMIP                      : 0
diff --git a/cfg/encoder_lowdelay_vtm.cfg b/cfg/encoder_lowdelay_vtm.cfg
index 148f03230bde4390f01110b46104acdc695b9252..08ac2388cab1055a6acb53934bee9dfa7112a77a 100644
--- a/cfg/encoder_lowdelay_vtm.cfg
+++ b/cfg/encoder_lowdelay_vtm.cfg
@@ -134,11 +134,12 @@ LMCSEnable                   : 1      # LMCS: 0: disable, 1:enable
 LMCSSignalType               : 0      # Input signal type: 0:SDR, 1:HDR-PQ, 2:HDR-HLG
 LMCSUpdateCtrl               : 2      # LMCS model update control: 0:RA, 1:AI, 2:LDB/LDP
 MIP                          : 1
+JointCbCr                    : 1      # JointCbCr: 0: disable, 1: enable
 PROF                         : 1
 
 # Fast tools
 PBIntraFast                  : 1
-ISPFast                      : 1
+ISPFast                      : 0
 FastMrg                      : 1
 AMaxBT                       : 1
 FastMIP                      : 0
diff --git a/cfg/encoder_randomaccess_vtm.cfg b/cfg/encoder_randomaccess_vtm.cfg
index 2e4c7a0332fbd01f2bda17df62aded26c0a047bd..15dd5ee617dcb6b145f48e030dac7b0c2c5367ab 100644
--- a/cfg/encoder_randomaccess_vtm.cfg
+++ b/cfg/encoder_randomaccess_vtm.cfg
@@ -152,11 +152,12 @@ LMCSUpdateCtrl               : 0      # LMCS model update control: 0:RA, 1:AI, 2
 MIP                          : 1
 DMVR                         : 1
 SMVD                         : 1
+JointCbCr                    : 1      # JointCbCr: 0: disable, 1: enable
 PROF                         : 1
 
 # Fast tools
 PBIntraFast                  : 1
-ISPFast                      : 1
+ISPFast                      : 0
 FastMrg                      : 1
 AMaxBT                       : 1
 FastMIP                      : 0
diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index a2aeb0b0287e680f9c1ae3b0243f420e709c9b20..0e0a2124c6a844c27dbd152817e01c3f133268e8 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -1165,6 +1165,12 @@ Specifies the maximum number of merge candidates to use.
 Specifies the maximum number of triangle merge candidates to use.
 \\
 
+\Option{MaxNumIBCMergeCand} &
+%\ShortOption{\None} &
+\Default{6} &
+Specifies the maximum number of IBC merge candidates to use.
+\\
+
 \Option{DisableIntraInInter} &
 %\ShortOption{\None} &
 \Default{0} &
@@ -1334,6 +1340,57 @@ $\lambda = \lambda_{base} \times max(2, min(4, (sliceQP-12)/6))$
 In addition, independent on the IntraQPFactor, if HadamardME=false, then for an inter slice the final $\lambda$ is scaled by a factor of $0.95$.
 \\
 
+\Option{UseIdentityTableForNon420Chroma}
+\Default{1}
+Specifies whether identity chroma QP mapping tables are used for 4:2:2 and 4:4:4 content. When set to 1, the identity chroma QP mapping table is used for all the three chroma components for 4:2:2 or 4:4:4 content. When set to 0, chroma QP 
+mapping table may be specified by other parameters in the configuration.
+\\
+
+\Option{SameCQPTablesForAllChroma}
+\Default{1)
+Specifies that the Cb, Cr and joint Cb-Cr components all use the same
+chroma mapping table. When set to 1, the values of QpInValCr, 
+QpOutValCr, QpInValCbCr and QpOutValCbCr are ignored. When set to 0, all
+Cb, Cr and joint Cb-Cr components may have different chroma QP mapping tables specified in the configuration file. \\ Note that 
+SameCQPTablesForAllChroma is ignored when UseIdentityTableForNon420Chroma is set to 1 for 4:2:2 and 4:4:4 content.
+\\
+
+\Option{QpInValCb}%
+\Option{QpOutValCb}&
+\Default{\NotSet}
+Specifies the input and coordinates of the pivot points used to specify the chroma QP mapping tables for the Cb component. Default values are as follows: 
+\begin{tabular}{cp{0.45\textwidth}}
+ QpInValCb: 25, 33, 43 \\
+ QpOutValCb: 25, 32, 37 \\
+\end{tabular}
+The values specify the pivot points for the chroma QP mapping table, the unspecified QP values are interpolated from the remaining values. E.g., the default values above specify that  the pivot points for the chroma QP mapping table for the Cb component are (25, 25), (33, 32), (43, 37).
+\\ Note that that QpInValCr and QpOutValCr are ignored when UseIdentityTableForNon420Chroma is set to 1 for 4:2:2 and 4:4:4 content.
+\\
+
+\Option{QpInValCr}%
+\Option{QpOutValCr}&
+\Default{\NotSet}
+Specifies the input and coordinates of the pivot points used to specify the chroma QP mapping tables for the Cr component. Default values are as follows: 
+\begin{tabular}{cp{0.45\textwidth}}
+ QpInValCr: 0 \\
+ QpOutValCr: 0 \\
+\end{tabular}
+The default values specify a pivot point of (0,0) which corresponds to an identity chroma QP mapping table. \\ Note that that QpInValCr and QpOutValCr are ignored 
+when SameCQPTablesForAllChroma is set to 1 or when UseIdentityTableForNon420Chroma is set to 1 for 4:2:2 and 4:4:4 content.
+\\
+
+\Option{QpInValCbCr}%
+\Option{QpOutValCbCr}&
+\Default{\NotSet}
+Specifies the input and coordinates of the pivot points used to specify the chroma QP mapping tables for the joint Cb-Cr component. Default values are as follows: 
+\begin{tabular}{cp{0.45\textwidth}}
+ QpInValrCr: 0 \\
+ QpOutValCbCr: 0 \\
+\end{tabular}
+The default values specify a pivot point of (0,0) which corresponds to a identity chroma QP mapping table. Note that that QpInValCbCr and QpOutVaCblCr are ignored 
+when SameCQPTablesForAllChroma is set to 1  or when UseIdentityTableForNon420Chroma is set to 1 for 4:2:2 and 4:4:4 content.
+\\
+
 \Option{CbQpOffset (-cbqpofs)}%
 \Option{CrQpOffset (-crqpofs)} &
 %\ShortOption{-cbqpofs}%
@@ -1822,6 +1879,12 @@ Enables or disables reduced testing of non-DCT-II transforms if ISP is likely to
 This option has no effect if either ISP or MTS are disabled.
 \\
 
+\Option{JointCbCr} &
+%\ShortOption{\None} &
+\Default{false} &
+Enables or disables the joint coding of chroma residuals.
+\\
+
 \Option{SAO} &
 %\ShortOption{\None} &
 \Default{true} &
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 26d403b891480fee09c59380706099ba48bac49f..9e6bfb2080662d270dc587e2c5dbc4a870578761 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -136,6 +136,9 @@ void EncApp::xInitLibCfg()
 #if JVET_O1136_TS_BDPCM_SIGNALLING
   m_cEncLib.setNoBDPCMConstraintFlag                             ( !m_useBDPCM );
 #endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  m_cEncLib.setNoJointCbCrConstraintFlag                         (!m_JointCbCrMode);
+#endif 
   m_cEncLib.setNoQpDeltaConstraintFlag                           ( m_bNoQpDeltaConstraintFlag );
   m_cEncLib.setNoDepQuantConstraintFlag                          ( !m_depQuantEnabledFlag);
   m_cEncLib.setNoSignDataHidingConstraintFlag                    ( !m_signDataHidingEnabledFlag );
@@ -167,6 +170,10 @@ void EncApp::xInitLibCfg()
 #if X0038_LAMBDA_FROM_QP_CAPABILITY
   m_cEncLib.setIntraQPOffset                                     ( m_intraQPOffset );
   m_cEncLib.setLambdaFromQPEnable                                ( m_lambdaFromQPEnable );
+#endif
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  m_cEncLib.setChromaQpMappingTableParams                         (m_chromaQpMappingTableParams);
+
 #endif
   m_cEncLib.setPad                                               ( m_aiPad );
 
@@ -292,9 +299,12 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setDMVR                                              ( m_DMVR );
   m_cEncLib.setMMVD                                              ( m_MMVD );
   m_cEncLib.setMmvdDisNum                                        (m_MmvdDisNum);
-  m_cEncLib.setRDPCM                                              ( m_RdpcmMode );
+  m_cEncLib.setRDPCM                                             ( m_RdpcmMode );
 #if JVET_O0119_BASE_PALETTE_444
   m_cEncLib.setPLTMode                                           ( m_PLTMode);
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  m_cEncLib.setJointCbCr                                         ( m_JointCbCrMode );
 #endif
   m_cEncLib.setIBCMode                                           ( m_IBCMode );
   m_cEncLib.setIBCLocalSearchRangeX                              ( m_IBCLocalSearchRangeX );
@@ -386,6 +396,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setMaxNumMergeCand                                   ( m_maxNumMergeCand );
   m_cEncLib.setMaxNumAffineMergeCand                             ( m_maxNumAffineMergeCand );
   m_cEncLib.setMaxNumTriangleCand                                ( m_maxNumTriangleCand );
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  m_cEncLib.setMaxNumIBCMergeCand                                ( m_maxNumIBCMergeCand );
+#endif
 
   //====== Weighted Prediction ========
   m_cEncLib.setUseWP                                             ( m_useWeightedPred     );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index 9d3212a1f6712b6c5c55674e30c24cbe1f6bec1a..9e71362bef7e3483b05c6507a5ab6c43ff7c779c 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -137,6 +137,9 @@ EncAppCfg::EncAppCfg()
 #if JVET_O1136_TS_BDPCM_SIGNALLING
 , m_noBDPCMConstraintFlag(false)
 #endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+, m_noJointCbCrConstraintFlag(false)
+#endif
 , m_bNoQpDeltaConstraintFlag(false)
 , m_bNoDepQuantConstraintFlag(false)
 , m_bNoSignDataHidingConstraintFlag(false)
@@ -714,7 +717,17 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   SMultiValueInput<int>  cfg_lumaLeveltoDQPMappingLuma       (0, std::numeric_limits<int>::max(), 0, LUMA_LEVEL_TO_DQP_LUT_MAXSIZE, defaultLumaLevelTodQp_LumaChangePoints, sizeof(defaultLumaLevelTodQp_LumaChangePoints)/sizeof(int));
   uint32_t lumaLevelToDeltaQPMode;
 #endif
-
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  const int qpInVals[] = { 25, 33, 43 };                // qpInVal values used to derive the chroma QP mapping table used in VTM-5.0
+  const int qpOutVals[] = { 25, 32, 37 };               // qpOutVal values used to derive the chroma QP mapping table used in VTM-5.0
+  SMultiValueInput<int> cfg_qpInValCb                   (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, qpInVals, sizeof(qpInVals)/sizeof(int));
+  SMultiValueInput<int> cfg_qpOutValCb                  (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, qpOutVals, sizeof(qpOutVals) / sizeof(int));
+  const int zeroVector[] = { 0 };
+  SMultiValueInput<int> cfg_qpInValCr                   (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, zeroVector, 1);
+  SMultiValueInput<int> cfg_qpOutValCr                  (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, zeroVector, 1);
+  SMultiValueInput<int> cfg_qpInValCbCr                 (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, zeroVector, 1);
+  SMultiValueInput<int> cfg_qpOutValCbCr                (MIN_QP_VALUE_FOR_16_BIT, MAX_QP, 0, MAX_NUM_QP_VALUES, zeroVector, 1);
+#endif
   const uint32_t defaultInputKneeCodes[3]  = { 600, 800, 900 };
   const uint32_t defaultOutputKneeCodes[3] = { 100, 250, 450 };
   SMultiValueInput<uint32_t> cfg_kneeSEIInputKneePointValue      (1,  999, 0, 999, defaultInputKneeCodes,  sizeof(defaultInputKneeCodes )/sizeof(uint32_t));
@@ -906,6 +919,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ( "RDPCM",                                          m_RdpcmMode,                                       false, "RDPCM")
 #if JVET_O0119_BASE_PALETTE_444
   ("PLT",                                             m_PLTMode,                                           0u, "PLTMode (0x1:enabled, 0x0:disabled)  [default: disabled]")
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  ("JointCbCr",                                       m_JointCbCrMode,                                  false, "Enable joint coding of chroma residuals (JointCbCr, 0:off, 1:on)")
 #endif
   ( "IBC",                                            m_IBCMode,                                           0u, "IBCMode (0x1:enabled, 0x0:disabled)  [default: disabled]")
   ( "IBCLocalSearchRangeX",                           m_IBCLocalSearchRangeX,                            128u, "Search range of IBC local search in x direction")
@@ -1021,7 +1037,16 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("LumaLevelToDeltaQPMappingLuma",                   cfg_lumaLeveltoDQPMappingLuma,  cfg_lumaLeveltoDQPMappingLuma, "Luma to Delta QP Mapping - luma thresholds")
   ("LumaLevelToDeltaQPMappingDQP",                    cfg_lumaLeveltoDQPMappingQP,  cfg_lumaLeveltoDQPMappingQP, "Luma to Delta QP Mapping - DQP values")
 #endif
-
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  ("UseIdentityTableForNon420Chroma",                 m_useIdentityTableForNon420Chroma,                 true, "True: Indicates that 422/444 chroma uses identity chroma QP mapping tables; False: explicit Qp table may be specified in config")
+  ("SameCQPTablesForAllChroma",                       m_chromaQpMappingTableParams.m_sameCQPTableForAllChromaFlag,                        true, "0: Different tables for Cb, Cr and joint Cb-Cr components, 1 (default): Same tables for all three chroma components")
+  ("QpInValCb",                                       cfg_qpInValCb,                            cfg_qpInValCb, "Input coordinates for the QP table for Cb component")
+  ("QpOutValCb",                                      cfg_qpOutValCb,                          cfg_qpOutValCb, "Output coordinates for the QP table for Cb component")
+  ("QpInValCr",                                       cfg_qpInValCr,                            cfg_qpInValCr, "Input coordinates for the QP table for Cr component")
+  ("QpOutValCr",                                      cfg_qpOutValCr,                          cfg_qpOutValCr, "Output coordinates for the QP table for Cr component")
+  ("QpInValCbCr",                                     cfg_qpInValCbCr,                        cfg_qpInValCbCr, "Input coordinates for the QP table for joint Cb-Cr component")
+  ("QpOutValCbCr",                                    cfg_qpOutValCbCr,                      cfg_qpOutValCbCr, "Output coordinates for the QP table for joint Cb-Cr component")
+#endif
   ("CbQpOffset,-cbqpofs",                             m_cbQpOffset,                                         0, "Chroma Cb QP Offset")
   ("CrQpOffset,-crqpofs",                             m_crQpOffset,                                         0, "Chroma Cr QP Offset")
   ("CbQpOffsetDualTree",                              m_cbQpOffsetDualTree,                                 0, "Chroma Cb QP Offset for dual tree")
@@ -1139,7 +1164,10 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("MaxNumMergeCand",                                 m_maxNumMergeCand,                                   5u, "Maximum number of merge candidates")
   ("MaxNumAffineMergeCand",                           m_maxNumAffineMergeCand,                             5u, "Maximum number of affine merge candidates")
   ("MaxNumTriangleCand",                              m_maxNumTriangleCand,                                5u, "Maximum number of triangle candidates")
-  /* Misc. */
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  ("MaxNumIBCMergeCand",                              m_maxNumIBCMergeCand,                                6u, "Maximum number of IBC merge candidates")
+#endif
+    /* Misc. */
   ("SEIDecodedPictureHash,-dph",                      tmpDecodedPictureHashSEIMappedType,                   0, "Control generation of decode picture hash SEI messages\n"
                                                                                                                "\t3: checksum\n"
                                                                                                                "\t2: CRC\n"
@@ -1910,6 +1938,53 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
     }
   }
 #endif
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+
+  CHECK(cfg_qpInValCb.values.size() != cfg_qpOutValCb.values.size(), "Chroma QP table for Cb is incomplete.");
+  CHECK(cfg_qpInValCr.values.size() != cfg_qpOutValCr.values.size(), "Chroma QP table for Cr is incomplete.");
+  CHECK(cfg_qpInValCbCr.values.size() != cfg_qpOutValCbCr.values.size(), "Chroma QP table for CbCr is incomplete.");
+  if (m_useIdentityTableForNon420Chroma && m_chromaFormatIDC != CHROMA_420) 
+  {
+    m_chromaQpMappingTableParams.m_sameCQPTableForAllChromaFlag = true;
+    cfg_qpInValCb.values = { 0 };
+    cfg_qpInValCr.values = { 0 };
+    cfg_qpInValCbCr.values = { 0 };
+  }
+  m_chromaQpMappingTableParams.m_deltaQpInValMinus1[0].resize(cfg_qpInValCb.values.size());
+  m_chromaQpMappingTableParams.m_deltaQpOutVal[0].resize(cfg_qpOutValCb.values.size());
+  m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[0] = (int)cfg_qpOutValCb.values.size()-1;
+  int qpBdOffsetC = 6 * (m_internalBitDepth[CHANNEL_TYPE_CHROMA] - 8);
+  for (int i = 0; i < cfg_qpInValCb.values.size(); i++)
+  {
+    CHECK(cfg_qpInValCb.values[i] < -qpBdOffsetC || cfg_qpInValCb.values[i] > MAX_QP, "Some entries cfg_qpInValCb are out of valid range of -qpBdOffsetC to 63, inclusive.");
+    CHECK(cfg_qpOutValCb.values[i] < -qpBdOffsetC || cfg_qpOutValCb.values[i] > MAX_QP, "Some entries cfg_qpOutValCb are out of valid range of -qpBdOffsetC to 63, inclusive.");
+    m_chromaQpMappingTableParams.m_deltaQpInValMinus1[0][i] = (i == 0) ? cfg_qpInValCb.values[i] + qpBdOffsetC : cfg_qpInValCb.values[i] - cfg_qpInValCb.values[i - 1] - 1;
+    m_chromaQpMappingTableParams.m_deltaQpOutVal[0][i] = (i == 0) ? cfg_qpOutValCb.values[i] + qpBdOffsetC : cfg_qpOutValCb.values[i] - cfg_qpOutValCb.values[i - 1];
+  }
+  if (!m_chromaQpMappingTableParams.m_sameCQPTableForAllChromaFlag)
+  {
+    m_chromaQpMappingTableParams.m_deltaQpInValMinus1[1].resize(cfg_qpInValCr.values.size());
+    m_chromaQpMappingTableParams.m_deltaQpOutVal[1].resize(cfg_qpOutValCr.values.size());
+    m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[1] = (int)cfg_qpOutValCr.values.size()-1;
+    for (int i = 0; i < cfg_qpInValCb.values.size(); i++)
+    {
+      CHECK(cfg_qpInValCr.values[i] < -qpBdOffsetC || cfg_qpInValCr.values[i] > MAX_QP, "Some entries cfg_qpInValCr are out of valid range of -qpBdOffsetC to 63, inclusive.");
+      CHECK(cfg_qpOutValCr.values[i] < -qpBdOffsetC || cfg_qpOutValCr.values[i] > MAX_QP, "Some entries cfg_qpOutValCr are out of valid range of -qpBdOffsetC to 63, inclusive.");
+      m_chromaQpMappingTableParams.m_deltaQpInValMinus1[1][i] = (i == 0) ? cfg_qpInValCr.values[i] + qpBdOffsetC : cfg_qpInValCr.values[i] - cfg_qpInValCr.values[i - 1] - 1;
+      m_chromaQpMappingTableParams.m_deltaQpOutVal[1][i] = (i == 0) ? cfg_qpOutValCr.values[i] + qpBdOffsetC : cfg_qpOutValCr.values[i] - cfg_qpOutValCr.values[i - 1];
+    }
+    m_chromaQpMappingTableParams.m_deltaQpInValMinus1[2].resize(cfg_qpInValCbCr.values.size());
+    m_chromaQpMappingTableParams.m_deltaQpOutVal[2].resize(cfg_qpOutValCbCr.values.size());
+    m_chromaQpMappingTableParams.m_numPtsInCQPTableMinus1[2] = (int)cfg_qpOutValCbCr.values.size()-1;
+    for (int i = 0; i < cfg_qpInValCbCr.values.size(); i++)
+    {
+      CHECK(cfg_qpInValCbCr.values[i] < -qpBdOffsetC || cfg_qpInValCbCr.values[i] > MAX_QP, "Some entries cfg_qpInValCbCr are out of valid range of -qpBdOffsetC to 63, inclusive.");
+      CHECK(cfg_qpOutValCbCr.values[i] < -qpBdOffsetC || cfg_qpOutValCbCr.values[i] > MAX_QP, "Some entries cfg_qpOutValCbCr are out of valid range of -qpBdOffsetC to 63, inclusive.");
+      m_chromaQpMappingTableParams.m_deltaQpInValMinus1[2][i] = (i == 0) ? cfg_qpInValCbCr.values[i] + qpBdOffsetC : cfg_qpInValCbCr.values[i] - cfg_qpInValCbCr.values[i - 1] - 1;
+      m_chromaQpMappingTableParams.m_deltaQpOutVal[2][i] = (i == 0) ? cfg_qpOutValCbCr.values[i] + qpBdOffsetC : cfg_qpOutValCbCr.values[i] - cfg_qpOutValCbCr.values[i - 1];
+    }
+  }
+#endif
 
 #if LUMA_ADAPTIVE_DEBLOCKING_FILTER_QP_OFFSET
   if ( m_LadfEnabed )
@@ -2215,6 +2290,9 @@ bool EncAppCfg::xCheckParameter()
     xConfirmPara(m_DMVR, "DMVR only allowed with NEXT profile");
     xConfirmPara(m_MmvdDisNum, "Number of distance MMVD entry setting only allowed with NEXT profile");
     xConfirmPara(m_RdpcmMode, "RDPCM only allowed with NEXT profile");
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+    xConfirmPara(m_JointCbCrMode, "JointCbCr only allowed with NEXT profile");
+#endif
     // ADD_NEW_TOOL : (parameter check) add a check for next tools here
   }
   else
@@ -2504,11 +2582,27 @@ bool EncAppCfg::xCheckParameter()
   xConfirmPara( m_cbQpOffsetDualTree >  12,   "Max. Chroma Cb QP Offset for dual tree is  12" );
   xConfirmPara( m_crQpOffsetDualTree < -12,   "Min. Chroma Cr QP Offset for dual tree is -12" );
   xConfirmPara( m_crQpOffsetDualTree >  12,   "Max. Chroma Cr QP Offset for dual tree is  12" );
-  xConfirmPara( m_cbCrQpOffset < -12,         "Min. Joint Cb-Cr QP Offset is -12" );
-  xConfirmPara( m_cbCrQpOffset >  12,         "Max. Joint Cb-Cr QP Offset is  12" );
-  xConfirmPara( m_cbCrQpOffsetDualTree < -12, "Min. Joint Cb-Cr QP Offset for dual tree is -12" );
-  xConfirmPara( m_cbCrQpOffsetDualTree >  12, "Max. Joint Cb-Cr QP Offset for dual tree is  12" );
-
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  if (m_JointCbCrMode && (m_chromaFormatIDC == CHROMA_400))
+  {
+    msg( WARNING, "****************************************************************************\n");
+    msg( WARNING, "** WARNING: --JointCbCr has been disabled due to the chromaFormat is 400       **\n");
+    msg( WARNING, "****************************************************************************\n");
+    m_JointCbCrMode = false;
+  }
+  if (m_JointCbCrMode)
+  {
+    xConfirmPara( m_cbCrQpOffset < -12, "Min. Joint Cb-Cr QP Offset is -12");
+    xConfirmPara( m_cbCrQpOffset >  12, "Max. Joint Cb-Cr QP Offset is  12");
+    xConfirmPara( m_cbCrQpOffsetDualTree < -12, "Min. Joint Cb-Cr QP Offset for dual tree is -12");
+    xConfirmPara( m_cbCrQpOffsetDualTree >  12, "Max. Joint Cb-Cr QP Offset for dual tree is  12");
+  }
+#else
+  xConfirmPara( m_cbCrQpOffset < -12, "Min. Joint Cb-Cr QP Offset is -12");
+  xConfirmPara( m_cbCrQpOffset >  12, "Max. Joint Cb-Cr QP Offset is  12");
+  xConfirmPara( m_cbCrQpOffsetDualTree < -12, "Min. Joint Cb-Cr QP Offset for dual tree is -12");
+  xConfirmPara( m_cbCrQpOffsetDualTree >  12, "Max. Joint Cb-Cr QP Offset for dual tree is  12");
+#endif
   xConfirmPara( m_iQPAdaptationRange <= 0,                                                  "QP Adaptation Range must be more than 0" );
   if (m_iDecodingRefreshType == 2)
   {
@@ -2521,20 +2615,26 @@ bool EncAppCfg::xCheckParameter()
   xConfirmPara( m_uiMinQT[1] < 1<<MIN_CU_LOG2,                                              "Minimum QT size should be larger than or equal to 4");
   xConfirmPara( m_uiCTUSize < 16,                                                           "Maximum partition width size should be larger than or equal to 16");
   xConfirmPara( m_uiCTUSize < 16,                                                           "Maximum partition height size should be larger than or equal to 16");
+#if !JVET_O0640_PICTURE_SIZE_CONSTRAINT
   xConfirmPara( (m_iSourceWidth  % (1<<MIN_CU_LOG2))!=0,                                    "Resulting coded frame width must be a multiple of the minimum unit size");
   xConfirmPara( (m_iSourceHeight % (1<<MIN_CU_LOG2))!=0,                                    "Resulting coded frame height must be a multiple of the minimum unit size");
   xConfirmPara( (m_iSourceWidth  % (1<<MIN_CU_LOG2))!=0,                                    "Resulting coded frame width must be a multiple of the minimum unit size");
   xConfirmPara( (m_iSourceHeight % (1<<MIN_CU_LOG2))!=0,                                    "Resulting coded frame height must be a multiple of the minimum unit size");
   xConfirmPara( (m_iSourceWidth  % (1<<MIN_CU_LOG2))!=0,                                    "Resulting coded frame width must be a multiple of the minimum unit size");
   xConfirmPara( (m_iSourceHeight % (1<<MIN_CU_LOG2))!=0,                                    "Resulting coded frame height must be a multiple of the minimum unit size");
+#endif
   xConfirmPara( m_uiMaxCUDepth < 1,                                                         "MaxPartitionDepth must be greater than zero");
   xConfirmPara( (m_uiMaxCUWidth  >> m_uiMaxCUDepth) < 4,                                    "Minimum partition width size should be larger than or equal to 8");
   xConfirmPara( (m_uiMaxCUHeight >> m_uiMaxCUDepth) < 4,                                    "Minimum partition height size should be larger than or equal to 8");
   xConfirmPara( m_uiMaxCUWidth < 16,                                                        "Maximum partition width size should be larger than or equal to 16");
   xConfirmPara( m_uiMaxCUHeight < 16,                                                       "Maximum partition height size should be larger than or equal to 16");
+#if JVET_O0640_PICTURE_SIZE_CONSTRAINT
+  xConfirmPara( (m_iSourceWidth  % (std::max(8, int(m_uiMaxCUWidth  >> (m_uiMaxCUDepth - 1))))) != 0, "Resulting coded frame width must be a multiple of Max(8, the minimum CU size)");
+  xConfirmPara( (m_iSourceHeight % (std::max(8, int(m_uiMaxCUHeight >> (m_uiMaxCUDepth - 1))))) != 0, "Resulting coded frame height must be a multiple of Max(8, the minimum CU size)");
+#else
   xConfirmPara( (m_iSourceWidth  % (m_uiMaxCUWidth  >> (m_uiMaxCUDepth-1)))!=0,             "Resulting coded frame width must be a multiple of the minimum CU size");
   xConfirmPara( (m_iSourceHeight % (m_uiMaxCUHeight >> (m_uiMaxCUDepth-1)))!=0,             "Resulting coded frame height must be a multiple of the minimum CU size");
-
+#endif
 #if MAX_TB_SIZE_SIGNALLING
   xConfirmPara( m_log2MaxTbSize > 6, "Log2MaxTbSize must be 6 or smaller." );
 #endif
@@ -2546,7 +2646,10 @@ bool EncAppCfg::xCheckParameter()
   xConfirmPara( m_maxNumTriangleCand > TRIANGLE_MAX_NUM_UNI_CANDS, "MaxNumTriangleCand must be no more than TRIANGLE_MAX_NUM_UNI_CANDS." );
   xConfirmPara( m_maxNumTriangleCand > m_maxNumMergeCand, "MaxNumTriangleCand must be no more than MaxNumMergeCand." );
   xConfirmPara( 0 < m_maxNumTriangleCand && m_maxNumTriangleCand < 2, "MaxNumTriangleCand must be no less than 2 unless MaxNumTriangleCand is 0." );
-
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  xConfirmPara( m_maxNumIBCMergeCand < 1, "MaxNumIBCMergeCand must be 1 or greater." );
+  xConfirmPara( m_maxNumIBCMergeCand > IBC_MRG_MAX_NUM_CANDS, "MaxNumIBCMergeCand must be no more than IBC_MRG_MAX_NUM_CANDS." );
+#endif 
   xConfirmPara( m_maxNumAffineMergeCand < 1, "MaxNumAffineMergeCand must be 1 or greater." );
   xConfirmPara( m_maxNumAffineMergeCand > AFFINE_MRG_MAX_NUM_CANDS, "MaxNumAffineMergeCand must be no more than AFFINE_MRG_MAX_NUM_CANDS." );
   if ( m_Affine == 0 )
@@ -3294,6 +3397,9 @@ void EncAppCfg::xPrintParameter()
   msg( DETAILS, "Max Num Merge Candidates               : %d\n", m_maxNumMergeCand );
   msg( DETAILS, "Max Num Affine Merge Candidates        : %d\n", m_maxNumAffineMergeCand );
   msg( DETAILS, "Max Num Triangle Merge Candidates      : %d\n", m_maxNumTriangleCand );
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  msg( DETAILS, "Max Num IBC Merge Candidates           : %d\n", m_maxNumIBCMergeCand );
+#endif
   msg( DETAILS, "\n");
 
   msg( VERBOSE, "TOOL CFG: ");
@@ -3396,6 +3502,9 @@ void EncAppCfg::xPrintParameter()
     msg(VERBOSE, "DMVR:%d ", m_DMVR);
     msg(VERBOSE, "MmvdDisNum:%d ", m_MmvdDisNum);
     msg(VERBOSE, "RDPCM:%d ", m_RdpcmMode );
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+    msg(VERBOSE, "JointCbCr:%d ", m_JointCbCrMode);
+#endif
   }
 #if JVET_O0119_BASE_PALETTE_444
     m_PLTMode = ( m_chromaFormatIDC == CHROMA_444) ? m_PLTMode : 0u;
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 16432d47fca4d4f4b31c9cd2fd26e106970bdb93..ebfc9e723a501e0d4ab3d4a79f75449e885a2f7e 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -145,6 +145,9 @@ protected:
   bool      m_noTransformSkipConstraintFlag;
 #if JVET_O1136_TS_BDPCM_SIGNALLING
   bool      m_noBDPCMConstraintFlag;
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool      m_noJointCbCrConstraintFlag;
 #endif
   bool      m_bNoQpDeltaConstraintFlag;
   bool      m_bNoDepQuantConstraintFlag;
@@ -202,6 +205,10 @@ protected:
   double    m_fQP;                                            ///< QP value of key-picture (floating point)
 #endif
   int       m_iQP;                                            ///< QP value of key-picture (integer)
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  bool      m_useIdentityTableForNon420Chroma;
+  ChromaQpMappingTableParams m_chromaQpMappingTableParams;
+#endif
 #if X0038_LAMBDA_FROM_QP_CAPABILITY
   int       m_intraQPOffset;                                  ///< QP offset for intra slice (integer)
   bool      m_lambdaFromQPEnable;                             ///< enable flag for QP:lambda fix
@@ -288,6 +295,9 @@ protected:
   bool      m_RdpcmMode;
 #if JVET_O0119_BASE_PALETTE_444
   unsigned  m_PLTMode;
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool      m_JointCbCrMode;
 #endif
   unsigned  m_IBCMode;
   unsigned  m_IBCLocalSearchRangeX;
@@ -518,6 +528,9 @@ protected:
   uint32_t      m_maxNumMergeCand;                                ///< Max number of merge candidates
   uint32_t      m_maxNumAffineMergeCand;                          ///< Max number of affine merge candidates
   uint32_t      m_maxNumTriangleCand;
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  uint32_t      m_maxNumIBCMergeCand;                             ///< Max number of IBC merge candidates
+#endif
 
   int       m_TMVPModeId;
   bool      m_depQuantEnabledFlag;
diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.h b/source/Lib/CommonLib/AdaptiveLoopFilter.h
index 42be89b58354401bf9e554e2edc844d0e997d5b8..da2c5e064614d95f4cd2e3ba49fe81a2eadc6982 100644
--- a/source/Lib/CommonLib/AdaptiveLoopFilter.h
+++ b/source/Lib/CommonLib/AdaptiveLoopFilter.h
@@ -115,7 +115,7 @@ protected:
   static const int             m_classToFilterMapping[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES];
   static const int             m_fixedFilterSetCoeff[ALF_FIXED_FILTER_NUM][MAX_NUM_ALF_LUMA_COEFF];
   short                        m_fixedFilterSetCoeffDec[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF];
-#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB
+#if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB || JVET_O_MAX_NUM_ALF_APS_8
   short                        m_coeffApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES];
   short                        m_clippApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES];
 #else
diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp
index 7af9b1fdf06e828e665bca22880b3f2c5230ff8f..7c671f6773363799eb1803ad84763f6e38f51951 100644
--- a/source/Lib/CommonLib/Buffer.cpp
+++ b/source/Lib/CommonLib/Buffer.cpp
@@ -218,6 +218,36 @@ void gradFilterCore(Pel* pSrc, int srcStride, int width, int height, int gradStr
 #endif
 }
 
+#if JVET_O0304_SIMPLIFIED_BDOF
+void calcBIOSumsCore(const Pel* srcY0Tmp, const Pel* srcY1Tmp, Pel* gradX0, Pel* gradX1, Pel* gradY0, Pel* gradY1, int xu, int yu, const int src0Stride, const int src1Stride, const int widthG, const int bitDepth, int* sumAbsGX, int* sumAbsGY, int* sumDIX, int* sumDIY, int* sumSignGY_GX)
+{
+  int shift4 = std::max<int>(4, (bitDepth - 8));
+  int shift5 = std::max<int>(1, (bitDepth - 11));
+
+  for (int y = 0; y < 6; y++)
+  {
+    for (int x = 0; x < 6; x++)
+    {
+      int tmpGX = (gradX0[x] + gradX1[x]) >> shift5;
+      int tmpGY = (gradY0[x] + gradY1[x]) >> shift5;
+      int tmpDI = (int)((srcY1Tmp[x] >> shift4) - (srcY0Tmp[x] >> shift4));
+      *sumAbsGX += (tmpGX < 0 ? -tmpGX : tmpGX);
+      *sumAbsGY += (tmpGY < 0 ? -tmpGY : tmpGY);
+      *sumDIX += (tmpGX < 0 ? -tmpDI : (tmpGX == 0 ? 0 : tmpDI));
+      *sumDIY += (tmpGY < 0 ? -tmpDI : (tmpGY == 0 ? 0 : tmpDI));
+      *sumSignGY_GX += (tmpGY < 0 ? -tmpGX : (tmpGY == 0 ? 0 : tmpGX));
+
+    }
+    srcY1Tmp += src1Stride;
+    srcY0Tmp += src0Stride;
+    gradX0 += widthG;
+    gradX1 += widthG;
+    gradY0 += widthG;
+    gradY1 += widthG;
+  }
+}
+#endif
+
 void calcBIOParCore(const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, const int bitDepth)
 {
   int shift4 = std::max<int>(4, (bitDepth - 8));
@@ -360,8 +390,12 @@ PelBufferOps::PelBufferOps()
 
   addBIOAvg4      = addBIOAvgCore;
   bioGradFilter   = gradFilterCore;
-  calcBIOPar      = calcBIOParCore;
+#if !JVET_O0304_SIMPLIFIED_BDOF
+  calcBIOPar = calcBIOParCore;
   calcBlkGradient = calcBlkGradientCore;
+#else
+  calcBIOSums = calcBIOSumsCore;
+#endif
 
   copyBuffer = copyBufferCore;
   padding = paddingCore;
diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h
index ed7fb47ecbaaa1d757605b64a3e17e8cfe0f190b..d04861d65f7c10eb9dab65bdbec515c30f745963 100644
--- a/source/Lib/CommonLib/Buffer.h
+++ b/source/Lib/CommonLib/Buffer.h
@@ -70,6 +70,9 @@ struct PelBufferOps
   void(*addBIOAvg4)    (const Pel* src0, int src0Stride, const Pel* src1, int src1Stride, Pel *dst, int dstStride, const Pel *gradX0, const Pel *gradX1, const Pel *gradY0, const Pel*gradY1, int gradStride, int width, int height, int tmpx, int tmpy, int shift, int offset, const ClpRng& clpRng);
   void(*bioGradFilter) (Pel* pSrc, int srcStride, int width, int height, int gradStride, Pel* gradX, Pel* gradY, const int bitDepth);
   void(*calcBIOPar)    (const Pel* srcY0Temp, const Pel* srcY1Temp, const Pel* gradX0, const Pel* gradX1, const Pel* gradY0, const Pel* gradY1, int* dotProductTemp1, int* dotProductTemp2, int* dotProductTemp3, int* dotProductTemp5, int* dotProductTemp6, const int src0Stride, const int src1Stride, const int gradStride, const int widthG, const int heightG, const int bitDepth);
+#if JVET_O0304_SIMPLIFIED_BDOF
+  void(*calcBIOSums)   (const Pel* srcY0Tmp, const Pel* srcY1Tmp, Pel* gradX0, Pel* gradX1, Pel* gradY0, Pel* gradY1, int xu, int yu, const int src0Stride, const int src1Stride, const int widthG, const int bitDepth, int* sumAbsGX, int* sumAbsGY, int* sumDIX, int* sumDIY, int* sumSignGY_GX);
+#endif
   void(*calcBlkGradient)(int sx, int sy, int    *arraysGx2, int     *arraysGxGy, int     *arraysGxdI, int     *arraysGy2, int     *arraysGydI, int     &sGx2, int     &sGy2, int     &sGxGy, int     &sGxdI, int     &sGydI, int width, int height, int unitSize);
   void(*copyBuffer)(Pel *src, int srcStride, Pel *dst, int dstStride, int width, int height);
   void(*padding)(Pel *dst, int stride, int width, int height, int padSize);
diff --git a/source/Lib/CommonLib/ChromaFormat.h b/source/Lib/CommonLib/ChromaFormat.h
index 8be4be331e05168687d292ac87419a38c04be9d5..0400084e1fe7f02773ac735ed6be8b28f905e0e4 100644
--- a/source/Lib/CommonLib/ChromaFormat.h
+++ b/source/Lib/CommonLib/ChromaFormat.h
@@ -115,12 +115,12 @@ static inline int getTransformShift(const int channelBitDepth, const Size size,
 
 
 //------------------------------------------------
-
+#if !JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
 static inline int getScaledChromaQP(int unscaledChromaQP, const ChromaFormat chFmt)
 {
   return g_aucChromaScale[chFmt][Clip3(0, (chromaQPMappingTableSize - 1), unscaledChromaQP)];
 }
-
+#endif
 
 //======================================================================================================================
 //Scaling lists  =======================================================================================================
diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h
index 4029d5cfa3770786ac4344a587d5722a9f7562b7..f641a2ba230b4de66e34caceb67199e6c895f3a6 100644
--- a/source/Lib/CommonLib/CodingStructure.h
+++ b/source/Lib/CommonLib/CodingStructure.h
@@ -97,7 +97,11 @@ public:
   bool        isLossless;
   const SPS *sps;
   const PPS *pps;
+#if JVET_O_MAX_NUM_ALF_APS_8
+  APS*       alfApss[ALF_CTB_MAX_NUM_APS];
+#else
   APS*       alfApss[MAX_NUM_APS];
+#endif
   APS *      lmcsAps;
   const VPS *vps;
   const PreCalcValues* pcv;
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 47b44d290747860c0e2123961d796d812a6490c3..daf78d6ff822b7d7dd250fba507518018256bba9 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -151,7 +151,10 @@ static const int AMVP_MAX_NUM_CANDS_MEM =                           3; ///< AMVP
 static const int AMVP_DECIMATION_FACTOR =                           2;
 static const int MRG_MAX_NUM_CANDS =                                6; ///< MERGE
 static const int AFFINE_MRG_MAX_NUM_CANDS =                         5; ///< AFFINE MERGE
-
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+static const int IBC_MRG_MAX_NUM_CANDS =                            6; ///< IBC MERGE
+#endif
+  
 static const int MAX_TLAYER =                                       7; ///< Explicit temporal layer QP offset - max number of temporal layer
 
 static const int ADAPT_SR_SCALE =                                   1; ///< division factor for adaptive search range
@@ -187,7 +190,11 @@ static const int MAX_NUM_ALF_COEFF           =                     MAX_ALF_FILTE
 static const int MAX_ALF_PADDING_SIZE        =                      4;
 
 static const int ALF_FIXED_FILTER_NUM        =                     64;
+#if JVET_O_MAX_NUM_ALF_APS_8
+static const int ALF_CTB_MAX_NUM_APS         =                      8;
+#else
 static const int ALF_CTB_MAX_NUM_APS         =                      6;
+#endif
 static const int NUM_FIXED_FILTER_SETS       =                     16;
 static const int NUM_TOTAL_FILTER_SETS       =                     NUM_FIXED_FILTER_SETS + ALF_CTB_MAX_NUM_APS;
 
@@ -296,6 +303,11 @@ static const int NUM_LONG_TERM_REF_PIC_SPS =                        0;
 
 
 static const int MAX_QP_OFFSET_LIST_SIZE =                          6; ///< Maximum size of QP offset list is 6 entries
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+static const int MAX_NUM_CQP_MAPPING_TABLES =                       3; ///< Maximum number of chroma QP mapping tables (Cb, Cr and joint Cb-Cr)
+static const int MIN_QP_VALUE_FOR_16_BIT   =                      -48; ////< Minimum value for QP (-6*(bitdepth - 8) ) for bit depth 16 ; actual minimum QP value is bit depth dependent
+static const int MAX_NUM_QP_VALUES =    MAX_QP + 1 - MIN_QP_VALUE_FOR_16_BIT; ////< Maximum number of QP values possible - bit depth dependent
+#endif
 
 // Cost mode support
 static const int LOSSLESS_AND_MIXED_LOSSLESS_RD_COST_TEST_QP =      0; ///< QP to use for lossless coding.
diff --git a/source/Lib/CommonLib/ContextModelling.h b/source/Lib/CommonLib/ContextModelling.h
index af67152c7a99756347c8692c9679de86f34f3946..630d3ac9c06f8fe0f1aad2ccf763c1ae6ea5623d 100644
--- a/source/Lib/CommonLib/ContextModelling.h
+++ b/source/Lib/CommonLib/ContextModelling.h
@@ -446,9 +446,7 @@ public:
                            violatesLfnstConstrained[CHANNEL_TYPE_LUMA  ] = false;
                            violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
 #endif
-                           lastScanPos[COMPONENT_Y ] = -1;
-                           lastScanPos[COMPONENT_Cb] = -1;
-                           lastScanPos[COMPONENT_Cr] = -1;
+                           lfnstLastScanPos = false;
                          }
 #else
                          qgStart(false),
@@ -471,9 +469,7 @@ public:
                            violatesLfnstConstrained[CHANNEL_TYPE_LUMA  ] = false;
                            violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
 #endif
-                           lastScanPos[COMPONENT_Y ] = -1;
-                           lastScanPos[COMPONENT_Cb] = -1;
-                           lastScanPos[COMPONENT_Cr] = -1;
+                           lfnstLastScanPos = false;
                          }
 #else
 #if JVET_O0094_LFNST_ZERO_PRIM_COEFFS
@@ -492,7 +488,7 @@ public:
   bool      isChromaQpAdjCoded;
   bool      qgStart;
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-  int       lastScanPos[MAX_NUM_COMPONENT];
+  bool      lfnstLastScanPos;
 #else
   uint32_t  numNonZeroCoeffNonTs;
 #endif
diff --git a/source/Lib/CommonLib/InterPrediction.cpp b/source/Lib/CommonLib/InterPrediction.cpp
index ae31a9a74c9bc98dc72441fd5c763ff6798cace7..792e3294dd5e2a6eb51fa7c37c3e35e3ae69c4bb 100644
--- a/source/Lib/CommonLib/InterPrediction.cpp
+++ b/source/Lib/CommonLib/InterPrediction.cpp
@@ -1279,7 +1279,7 @@ void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf
   const int   shiftNum = IF_INTERNAL_PREC + 1 - bitDepth;
   const int   offset = (1 << (shiftNum - 1)) + 2 * IF_INTERNAL_OFFS;
   const int   limit = (1<<(std::max<int>(5, bitDepth - 7)));
-
+#if !JVET_O0304_SIMPLIFIED_BDOF
   int*     dotProductTemp1 = m_dotProduct1;
   int*     dotProductTemp2 = m_dotProduct2;
   int*     dotProductTemp3 = m_dotProduct3;
@@ -1287,6 +1287,7 @@ void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf
   int*     dotProductTemp6 = m_dotProduct6;
 
   xCalcBIOPar(srcY0Temp, srcY1Temp, gradX0, gradX1, gradY0, gradY1, dotProductTemp1, dotProductTemp2, dotProductTemp3, dotProductTemp5, dotProductTemp6, src0Stride, src1Stride, widthG, widthG, heightG, bitDepth);
+#endif
 
   int xUnit = (width >> 2);
   int yUnit = (height >> 2);
@@ -1310,7 +1311,7 @@ void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf
         continue;
       }
 #endif
-
+#if !JVET_O0304_SIMPLIFIED_BDOF
       int     sGxdI = 0, sGydI = 0, sGxGy = 0, sGx2 = 0, sGy2 = 0;
       int     tmpx = 0, tmpy = 0;
 
@@ -1336,7 +1337,29 @@ void InterPrediction::applyBiOptFlow(const PredictionUnit &pu, const CPelUnitBuf
         tmpy = rightShiftMSB(((sGydI << 3) - tmpData), sGy2);
         tmpy = Clip3(-limit, limit, tmpy);
       }
-
+#else
+      int tmpx = 0, tmpy = 0;
+      int sumAbsGX = 0, sumAbsGY = 0, sumDIX = 0, sumDIY = 0;
+      int sumSignGY_GX = 0;
+
+      Pel* pGradX0Tmp = m_gradX0 + (xu << 2) + (yu << 2) * widthG;
+      Pel* pGradX1Tmp = m_gradX1 + (xu << 2) + (yu << 2) * widthG;
+      Pel* pGradY0Tmp = m_gradY0 + (xu << 2) + (yu << 2) * widthG;
+      Pel* pGradY1Tmp = m_gradY1 + (xu << 2) + (yu << 2) * widthG;
+      const Pel* SrcY1Tmp = srcY1 + (xu << 2) + (yu << 2) * src1Stride;
+      const Pel* SrcY0Tmp = srcY0 + (xu << 2) + (yu << 2) * src0Stride;
+
+      g_pelBufOP.calcBIOSums(SrcY0Tmp, SrcY1Tmp, pGradX0Tmp, pGradX1Tmp, pGradY0Tmp, pGradY1Tmp, xu, yu, src0Stride, src1Stride, widthG, bitDepth, &sumAbsGX, &sumAbsGY, &sumDIX, &sumDIY, &sumSignGY_GX);
+      tmpx = (sumAbsGX == 0 ? 0 : rightShiftMSB(sumDIX << 3, sumAbsGX));
+      tmpx = Clip3(-limit, limit, tmpx);
+
+      int     mainsGxGy = sumSignGY_GX >> 12;
+      int     secsGxGy = sumSignGY_GX & ((1 << 12) - 1);
+      int     tmpData = tmpx * mainsGxGy;
+      tmpData = ((tmpData << 12) + tmpx*secsGxGy) >> 1;
+      tmpy = (sumAbsGY == 0 ? 0 : rightShiftMSB(((sumDIY << 3) - tmpData), sumAbsGY));
+      tmpy = Clip3(-limit, limit, tmpy);
+#endif
       srcY0Temp = srcY0 + (stridePredMC + 1) + ((yu*src0Stride + xu) << 2);
       srcY1Temp = srcY1 + (stridePredMC + 1) + ((yu*src0Stride + xu) << 2);
       gradX0 = m_gradX0 + offsetPos + ((yu*widthG + xu) << 2);
@@ -2346,7 +2369,7 @@ uint64_t InterPrediction::xDMVRCost(int bitDepth, Pel* pOrg, uint32_t refStride,
   cDistParam.useMR = false;
   m_pcRdCost->setDistParam(cDistParam, pOrg, pRef, orgStride, refStride, bitDepth, COMPONENT_Y, width, height, 1);
   uint64_t uiCost = cDistParam.distFunc(cDistParam);
-  return uiCost;
+  return uiCost>>1;
 }
 
 void xDMVRSubPixelErrorSurface(bool notZeroCost, int16_t *totalDeltaMV, int16_t *deltaMV, uint64_t *pSADsArray)
@@ -2466,7 +2489,7 @@ void InterPrediction::xProcessDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvDst, con
   int bd = pu.cs->slice->getClpRngs().comp[COMPONENT_Y].bd;
 
 #if JVET_O0055_INT_DMVR_DIS_BDOF
-  int            bioEnabledThres = 8 * (dy >> 1) * dx;
+  int            bioEnabledThres = 2 * dy * dx;
   bool           bioAppliedType[MAX_NUM_SUBCU_DMVR];
 #endif
   {
@@ -2577,7 +2600,7 @@ void InterPrediction::xProcessDMVR(PredictionUnit& pu, PelUnitBuf &pcYuvDst, con
 #if JVET_O0590_REDUCE_DMVR_ORIG_MV_COST
             minCost -= (minCost >>2);            
 #endif
-            if (minCost < ((4 * dx * (dy >> 1/*for alternate line*/))))
+            if (minCost < (dx * dy))
             {
               notZeroCost = false;
               break;
diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index a1a40a8b246dfd12abb846530a35f322e5ae5bfa..3ae05f29d10c46ac7552891769e16920b175b3ce 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -336,8 +336,12 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
   const int  srcStride  = m_topRefLength  + 1 + (whRatio + 1) * multiRefIdx;
   const int  srcHStride = m_leftRefLength + 1 + (hwRatio + 1) * multiRefIdx;
 #endif
-
+  
+#if JVET_O0502_ISP_CLEANUP
+  const CPelBuf& srcBuf = pu.cu->ispMode && isLuma(compID) ? getISPBuffer() : CPelBuf(getPredictorPtr(compID), srcStride, srcHStride);
+#else
   const CPelBuf & srcBuf = CPelBuf(getPredictorPtr(compID), srcStride, srcHStride);
+#endif
   const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID));
 
   switch (uiDirMode)
@@ -362,13 +366,14 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
     {
       for (int y = 0; y < iHeight; y++)
       {
-        int wT = 32 >> std::min(31, ((y << 1) >> scale));
+        const int wT   = 32 >> std::min(31, ((y << 1) >> scale));
         const Pel left = srcBuf.at(0, y + 1);
         for (int x = 0; x < iWidth; x++)
         {
-          const Pel top = srcBuf.at(x + 1, 0);
-          int wL = 32 >> std::min(31, ((x << 1) >> scale));
-          dstBuf.at(x, y) = ClipPel((wL * left + wT * top + (64 - wL - wT) * dstBuf.at(x, y) + 32) >> 6, clpRng);
+          const int wL    = 32 >> std::min(31, ((x << 1) >> scale));
+          const Pel top   = srcBuf.at(x + 1, 0);
+          const Pel val   = dstBuf.at(x, y);
+          dstBuf.at(x, y) = val + ((wL * (left - val) + wT * (top - val) + 32) >> 6);
         }
       }
     }
@@ -390,34 +395,6 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
       }
     }
 #endif
-    else if (uiDirMode == HOR_IDX)
-    {
-      const Pel topLeft = srcBuf.at(0, 0);
-      for (int y = 0; y < iHeight; y++)
-      {
-        int wT = 32 >> std::min(31, ((y << 1) >> scale));
-        for (int x = 0; x < iWidth; x++)
-        {
-          const Pel top = srcBuf.at(x + 1, 0);
-          int wTL = wT;
-          dstBuf.at(x, y) = ClipPel((wT * top - wTL * topLeft + (64 - wT + wTL) * dstBuf.at(x, y) + 32) >> 6, clpRng);
-        }
-      }
-    }
-    else if (uiDirMode == VER_IDX)
-    {
-      const Pel topLeft = srcBuf.at(0, 0);
-      for (int y = 0; y < iHeight; y++)
-      {
-        const Pel left = srcBuf.at(0, y + 1);
-        for (int x = 0; x < iWidth; x++)
-        {
-          int wL = 32 >> std::min(31, ((x << 1) >> scale));
-          int wTL = wL;
-          dstBuf.at(x, y) = ClipPel((wL * left - wTL * topLeft + (64 - wL + wTL) * dstBuf.at(x, y) + 32) >> 6, clpRng);
-        }
-      }
-    }
   }
 }
 
@@ -521,13 +498,19 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA
   const int      dirMode = PU::getFinalIntraMode(pu, chType);
   const int     predMode = getWideAngle( blockSize.width, blockSize.height, dirMode );
 
+#if !JVET_O0364_PADDING
   m_ipaParam.whRatio              = std::max( unsigned( 1 ), blockSize.width  / blockSize.height ) ;
   m_ipaParam.hwRatio              = std::max( unsigned( 1 ), blockSize.height / blockSize.width  ) ;
+#endif
   m_ipaParam.isModeVer            = predMode >= DIA_IDX;
   m_ipaParam.multiRefIndex        = isLuma (chType) ? pu.multiRefIdx : 0 ;
   m_ipaParam.refFilterFlag        = false;
   m_ipaParam.interpolationFlag    = false;
+#if JVET_O0502_ISP_CLEANUP
+  m_ipaParam.applyPDPC            = ((puSize.width >= MIN_TB_SIZEY && puSize.height >= MIN_TB_SIZEY) || !isLuma(compId)) && m_ipaParam.multiRefIndex == 0;
+#else
   m_ipaParam.applyPDPC            = !useISP && m_ipaParam.multiRefIndex == 0;
+#endif
 
   const int    intraPredAngleMode = (m_ipaParam.isModeVer) ? predMode - VER_IDX : -(predMode - HOR_IDX);
 
@@ -581,10 +564,12 @@ void IntraPrediction::initPredIntraParams(const PredictionUnit & pu, const CompA
     || DC_IDX == dirMode
     )
   {
+#if !JVET_O0502_ISP_CLEANUP
     if (useISP)
     {
       m_ipaParam.interpolationFlag = (m_ipaParam.isModeVer ? puSize.width : puSize.height) > 8 ? true : false ;
     }
+#endif
   }
   else if (isLuma( chType ) && pu.cu->bdpcmMode) // BDPCM
   {
@@ -649,8 +634,10 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
   int height=int(pDst.height);
 
   const bool bIsModeVer     = m_ipaParam.isModeVer;
+#if !JVET_O0364_PADDING
   const int  whRatio        = m_ipaParam.whRatio;
   const int  hwRatio        = m_ipaParam.hwRatio;
+#endif
   const int  multiRefIdx    = m_ipaParam.multiRefIndex;
   const int  intraPredAngle = m_ipaParam.intraPredAngle;
   const int  invAngle       = m_ipaParam.invAngle;
@@ -726,11 +713,14 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
     refSide = bIsModeVer ? refLeft : refAbove;
 
     // Extend main reference to right using replication
-    int maxIndex = multiRefIdx * (bIsModeVer ? whRatio : hwRatio) + 2;
-    Pel val = bIsModeVer ? pSrc.at(m_topRefLength + multiRefIdx, 0) : pSrc.at(0, m_leftRefLength + multiRefIdx);
+    const int log2Ratio = g_aucLog2[width] - g_aucLog2[height];
+    const int s         = std::max<int>(0, bIsModeVer ? log2Ratio : -log2Ratio);
+    const int maxIndex  = (multiRefIdx << s) + 2;
+    const int refLength = bIsModeVer ? m_topRefLength : m_leftRefLength;
+    const Pel val       = refMain[refLength + multiRefIdx];
     for (int z = 1; z <= maxIndex; z++)
     {
-      refMain[(bIsModeVer ? m_topRefLength : m_leftRefLength) + multiRefIdx + z] = val;
+      refMain[refLength + multiRefIdx + z] = val;
     }
 #else
     for (int x = 0; x < m_topRefLength + 1 + (whRatio + 1) * multiRefIdx; x++)
@@ -765,59 +755,78 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
   refMain += multiRefIdx;
   refSide += multiRefIdx;
 
+  Pel *pDsty = pDstBuf;
+
   if( intraPredAngle == 0 )  // pure vertical or pure horizontal
   {
     for( int y = 0; y < height; y++ )
     {
       for( int x = 0; x < width; x++ )
       {
-        pDstBuf[y*dstStride + x] = refMain[x + 1];
+        pDsty[x] = refMain[x + 1];
+      }
+
+      if (m_ipaParam.applyPDPC)
+      {
+        const int scale   = (g_aucLog2[width] + g_aucLog2[height] - 2) >> 2;
+        const Pel topLeft = refMain[0];
+        const Pel left    = refSide[1 + y];
+        for (int x = 0; x < std::min(3 << scale, width); x++)
+        {
+          const int wL  = 32 >> (2 * x >> scale);
+          const Pel val = pDsty[x];
+          pDsty[x]      = ClipPel(val + ((wL * (left - topLeft) + 32) >> 6), clpRng);
+        }
       }
+
+      pDsty += dstStride;
     }
   }
   else
   {
-    Pel *pDsty=pDstBuf;
     for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride)
     {
       const int deltaInt   = deltaPos >> 5;
-      const int deltaFract = deltaPos & (32 - 1);
+      const int deltaFract = deltaPos & 31;
 
       if ( !isIntegerSlope( abs(intraPredAngle) ) )
       {
         if( isLuma(channelType) )
         {
-          Pel                        p[4];
-          const bool                 useCubicFilter = !m_ipaParam.interpolationFlag;
-          TFilterCoeff const * const f              = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : g_intraGaussFilter[deltaFract];
+          const bool useCubicFilter = !m_ipaParam.interpolationFlag;
 
-          int         refMainIndex   = deltaInt + 1;
+          const TFilterCoeff *const f =
+            (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : g_intraGaussFilter[deltaFract];
 
-          for( int x = 0; x < width; x++, refMainIndex++ )
+          for (int x = 0; x < width; x++)
           {
-            p[0] = refMain[refMainIndex - 1];
-            p[1] = refMain[refMainIndex];
-            p[2] = refMain[refMainIndex + 1];
-            p[3] = f[3] != 0 ? refMain[refMainIndex + 2] : 0;
+            Pel p[4];
 
-            pDstBuf[y*dstStride + x] = static_cast<Pel>((static_cast<int>(f[0] * p[0]) + static_cast<int>(f[1] * p[1]) + static_cast<int>(f[2] * p[2]) + static_cast<int>(f[3] * p[3]) + 32) >> 6);
+            p[0] = refMain[deltaInt + x];
+            p[1] = refMain[deltaInt + x + 1];
+            p[2] = refMain[deltaInt + x + 2];
+#if JVET_O0364_PADDING
+            p[3] = refMain[deltaInt + x + 3];
+#else
+            p[3] = f[3] != 0 ? refMain[deltaInt + x + 3] : 0;
+#endif
+
+            Pel val = (f[0] * p[0] + f[1] * p[1] + f[2] * p[2] + f[3] * p[3] + 32) >> 6;
 
-            if( useCubicFilter ) // only cubic filter has negative coefficients and requires clipping
-            {
-              pDstBuf[y*dstStride + x] = ClipPel( pDstBuf[y*dstStride + x], clpRng );
-            }
+            pDsty[x] = ClipPel(val, clpRng);   // always clip even though not always needed
           }
         }
         else
         {
           // Do linear filtering
-          const Pel *pRM = refMain + deltaInt + 1;
-          int lastRefMainPel = *pRM++;
-          for( int x = 0; x < width; pRM++, x++ )
+          for (int x = 0; x < width; x++)
           {
-            int thisRefMainPel = *pRM;
-            pDsty[x + 0] = ( Pel ) ( ( ( 32 - deltaFract )*lastRefMainPel + deltaFract*thisRefMainPel + 16 ) >> 5 );
-            lastRefMainPel = thisRefMainPel;
+            Pel p[2];
+
+            p[0] = refMain[deltaInt + x + 1];
+            p[1] = refMain[deltaInt + x + 2];
+
+            pDsty[x] = p[0] + ((deltaFract * (p[1] - p[0]) + 16) >> 5);
           }
         }
       }
@@ -1062,7 +1071,11 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre
   Pel *refBufUnfiltered   = m_piYuvExt[area.compID][PRED_BUF_UNFILTERED];
   Pel *refBufFiltered     = m_piYuvExt[area.compID][PRED_BUF_FILTERED];
 
+#if JVET_O0502_ISP_CLEANUP
+  setReferenceArrayLengths( area );
+#else
   setReferenceArrayLengths( cu.ispMode && isLuma( area.compID ) ? cu.blocks[area.compID] : area );
+#endif
 
   // ----- Step 1: unfiltered reference samples -----
   xFillReferenceSamples( cs.picture->getRecoBuf( area ), refBufUnfiltered, area, cu );
@@ -1073,6 +1086,130 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre
   }
 }
 
+#if JVET_O0502_ISP_CLEANUP
+void IntraPrediction::initIntraPatternChTypeISP(const CodingUnit& cu, const CompArea& area, PelBuf& recBuf, const bool forceRefFilterFlag)
+{
+  const CodingStructure& cs = *cu.cs;
+
+  if (!forceRefFilterFlag)
+  {
+    initPredIntraParams(*cu.firstPU, area, *cs.sps);
+  }
+
+  const Position posLT = area;
+  bool           isLeftAvail = cs.isDecomp(posLT.offset(-1, 0), CHANNEL_TYPE_LUMA);
+  bool           isAboveAvail = cs.isDecomp(posLT.offset(0, -1), CHANNEL_TYPE_LUMA);
+  // ----- Step 1: unfiltered reference samples -----
+#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
+  if (cu.blocks[area.compID].x == area.x && cu.blocks[area.compID].y == area.y)
+#else
+  if (CU::isISPFirst(cu, area, area.compID))
+#endif
+  {
+    Pel* refBufUnfiltered = m_piYuvExt[area.compID][PRED_BUF_UNFILTERED];
+    // With the first subpartition all the CU reference samples are fetched at once in a single call to xFillReferenceSamples 
+    if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
+    {
+      m_leftRefLength = cu.Y().height << 1;
+      m_topRefLength = cu.Y().width + area.width;
+    }
+    else //if (cu.ispMode == VER_INTRA_SUBPARTITIONS)
+    {
+      m_leftRefLength = cu.Y().height + area.height;
+      m_topRefLength = cu.Y().width << 1;
+    }
+
+    const int srcStride = m_topRefLength + 1;
+    const int srcHStride = m_leftRefLength + 1;
+
+    m_pelBufISP[0] = m_pelBufISPBase[0] = PelBuf(m_piYuvExt[area.compID][PRED_BUF_UNFILTERED], srcStride, srcHStride);
+    m_pelBufISP[1] = m_pelBufISPBase[1] = PelBuf(m_piYuvExt[area.compID][PRED_BUF_FILTERED], srcStride, srcHStride);
+
+    xFillReferenceSamples(cs.picture->getRecoBuf(cu.Y()), refBufUnfiltered, cu.Y(), cu);
+
+    // After having retrieved all the CU reference samples, the number of reference samples is now adjusted for the current subpartition 
+    m_topRefLength = cu.blocks[area.compID].width + area.width;
+    m_leftRefLength = cu.blocks[area.compID].height + area.height;
+  }
+  else
+  {
+    //Now we only need to fetch the newly available reconstructed samples from the previously coded TU 
+    Position tuPos = area;
+    tuPos.relativeTo(cu.Y());
+    m_pelBufISP[0] = m_pelBufISPBase[0].subBuf(tuPos, area.size());
+    m_pelBufISP[1] = m_pelBufISPBase[1].subBuf(tuPos, area.size());
+
+    PelBuf& dstBuf = m_pelBufISP[0];
+
+    m_topRefLength = cu.blocks[area.compID].width + area.width;
+    m_leftRefLength = cu.blocks[area.compID].height + area.height;
+
+    const int predSizeHor = m_topRefLength;
+    const int predSizeVer = m_leftRefLength;
+    if (cu.ispMode == HOR_INTRA_SUBPARTITIONS)
+    {
+      Pel* src = recBuf.bufAt(0, -1);
+      Pel* dst = dstBuf.bufAt(1, 0);
+      for (int i = 0; i < area.width; i++)
+      {
+        dst[i] = src[i];
+      }
+      Pel sample = src[area.width - 1];
+      dst += area.width;
+      for (int i = 0; i < predSizeHor - area.width; i++)
+      {
+        dst[i] = sample;
+      }
+      if (!isLeftAvail) //if left is not avaible, then it is necessary to fetch these samples for each subpartition
+      {
+        Pel* dst = dstBuf.bufAt(0, 0);
+        Pel  sample = src[0];
+        for (int i = 0; i < predSizeVer + 1; i++)
+        {
+          *dst = sample;
+          dst += dstBuf.stride;
+        }
+      }
+    }
+    else
+    {
+      Pel* src = recBuf.bufAt(-1, 0);
+      Pel* dst = dstBuf.bufAt(0, 1);
+      for (int i = 0; i < area.height; i++)
+      {
+        *dst = *src;
+        src += recBuf.stride;
+        dst += dstBuf.stride;
+      }
+      Pel sample = src[-recBuf.stride];
+      for (int i = 0; i < predSizeVer - area.height; i++)
+      {
+        *dst = sample;
+        dst += dstBuf.stride;
+      }
+
+      if (!isAboveAvail) //if above is not avaible, then it is necessary to fetch these samples for each subpartition
+      {
+        Pel* dst = dstBuf.bufAt(0, 0);
+        Pel  sample = recBuf.at(-1, 0);
+        for (int i = 0; i < predSizeHor + 1; i++)
+        {
+          dst[i] = sample;
+        }
+      }
+    }
+  }
+  // ----- Step 2: filtered reference samples -----
+  if (m_ipaParam.refFilterFlag || forceRefFilterFlag)
+  {
+    Pel* refBufUnfiltered = m_pelBufISP[0].buf;
+    Pel* refBufFiltered = m_pelBufISP[1].buf;
+    xFilterReferenceSamples(refBufUnfiltered, refBufFiltered, area, *cs.sps, cu.firstPU->multiRefIdx, m_pelBufISP[0].stride);
+  }
+}
+#endif
+
+
 void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu )
 {
   const ChannelType      chType = toChannelType( area.compID );
@@ -1330,6 +1467,9 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf
 
 void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps
   , int multiRefIdx
+#if JVET_O0502_ISP_CLEANUP
+  , int stride
+#endif
 )
 {
   if (area.compID != COMPONENT_Y)
@@ -1345,7 +1485,11 @@ void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel*
   const int  predSize  = m_topRefLength  + (whRatio + 1) * multiRefIdx;
   const int  predHSize = m_leftRefLength + (hwRatio + 1) * multiRefIdx;
 #endif
+#if JVET_O0502_ISP_CLEANUP
+  const int predStride = stride == 0 ? predSize + 1 : stride;
+#else
   const int  predStride = predSize + 1;
+#endif
 
 
 
diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h
index 2d498e61c4ba44a87e1b63b0363756381b579657..29ccc472f74c33e190f19c10ad4e397a2e2ad66a 100644
--- a/source/Lib/CommonLib/IntraPrediction.h
+++ b/source/Lib/CommonLib/IntraPrediction.h
@@ -68,6 +68,10 @@ class IntraPrediction
 private:
 
   Pel* m_piYuvExt[MAX_NUM_COMPONENT][NUM_PRED_BUF];
+#if JVET_O0502_ISP_CLEANUP
+  PelBuf m_pelBufISPBase[2];
+  PelBuf m_pelBufISP[2];
+#endif
   int  m_iYuvExtSize;
 
   Pel* m_yuvExt2[MAX_NUM_COMPONENT][4];
@@ -81,8 +85,10 @@ private:
     bool applyPDPC;
     bool isModeVer;
     int  multiRefIndex;
+#if !JVET_O0364_PADDING
     int  whRatio;
     int  hwRatio;
+#endif
     int  intraPredAngle;
     int  invAngle;
     bool interpolationFlag;
@@ -90,16 +96,25 @@ private:
     int  angularScale;
 #endif
 
-    IntraPredParam() :
-      refFilterFlag     ( false                           ),
-      applyPDPC         ( false                           ),
-      isModeVer         ( false                           ),
-      multiRefIndex     ( -1                              ),
-      whRatio           ( 0                               ),
-      hwRatio           ( 0                               ),
-      intraPredAngle    ( std::numeric_limits<int>::max() ),
-      invAngle          ( std::numeric_limits<int>::max() ),
-      interpolationFlag ( false                           ) {}
+    // clang-format off
+    IntraPredParam()
+      : refFilterFlag(false)
+      , applyPDPC(false)
+      , isModeVer(false)
+      , multiRefIndex(-1)
+#if !JVET_O0364_PADDING
+      , whRatio(0)
+      , hwRatio(0)
+#endif
+      , intraPredAngle(std::numeric_limits<int>::max())
+      , invAngle(std::numeric_limits<int>::max())
+      , interpolationFlag(false)
+#if JVET_O0364_PDPC_ANGULAR
+      , angularScale(-1)
+#endif
+    // clang-format on
+    {
+    }
   };
 
   IntraPredParam m_ipaParam;
@@ -140,6 +155,9 @@ protected:
   void xFillReferenceSamples      ( const CPelBuf &recoBuf,      Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu );
   void xFilterReferenceSamples    ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps
     , int multiRefIdx
+#if JVET_O0502_ISP_CLEANUP
+    , int predStride = 0
+#endif
   );
 
   static int getWideAngle         ( int width, int height, int predMode );
@@ -163,6 +181,10 @@ public:
   void xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea);
   /// set parameters from CU data for accessing intra data
   void initIntraPatternChType     (const CodingUnit &cu, const CompArea &area, const bool forceRefFilterFlag = false); // use forceRefFilterFlag to get both filtered and unfiltered buffers
+#if JVET_O0502_ISP_CLEANUP
+  void initIntraPatternChTypeISP  (const CodingUnit& cu, const CompArea& area, PelBuf& piReco, const bool forceRefFilterFlag = false); // use forceRefFilterFlag to get both filtered and unfiltered buffers 
+  const PelBuf& getISPBuffer      () { return m_pelBufISP[m_ipaParam.refFilterFlag ? PRED_BUF_FILTERED : PRED_BUF_UNFILTERED]; }
+#endif
 
   // Matrix-based intra prediction
   void initIntraMip               (const PredictionUnit &pu);
diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp
index 309c0131927d1487f22db65ebfdccc99fac58753..8ce43b547e7458e737df6e740bc0aaee895a5e2b 100644
--- a/source/Lib/CommonLib/LoopFilter.cpp
+++ b/source/Lib/CommonLib/LoopFilter.cpp
@@ -1300,6 +1300,10 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed
         const int chromaQPOffset = pps.getQpOffset( ComponentID( chromaIdx + 1 ) );
         Pel* piTmpSrcChroma = (chromaIdx == 0) ? piTmpSrcCb : piTmpSrcCr;
 
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+        int iQP = sps.getMappedChromaQpValue(ComponentID(chromaIdx + 1), ((cuP.qp + cuQ.qp + 1) >> 1));
+        iQP = Clip3(0, MAX_QP, iQP + chromaQPOffset);
+#else
         int iQP = ( ( cuP.qp + cuQ.qp + 1 ) >> 1 ) + chromaQPOffset;
         if (iQP >= chromaQPMappingTableSize)
         {
@@ -1316,6 +1320,7 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed
         {
           iQP = getScaledChromaQP(iQP, sps.getChromaFormatIdc());
         }
+#endif
 
         const int iIndexTC = Clip3<int>(0, MAX_QP + DEFAULT_INTRA_TC_OFFSET, iQP + DEFAULT_INTRA_TC_OFFSET * (bS[chromaIdx] - 1) + (tcOffsetDiv2 << 1));
 #if JVET_O0159_10BITTCTABLE_DEBLOCKING
diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp
index b3e3d9f9b588d2d0366592c1a5dc553c4b3977ae..a32727d252c738d8f5f1874d7b631bc489735548 100644
--- a/source/Lib/CommonLib/Picture.cpp
+++ b/source/Lib/CommonLib/Picture.cpp
@@ -961,7 +961,11 @@ Slice *Picture::swapSliceObject(Slice * p, uint32_t i)
   slices[i] = p;
   pTmp->setSPS(0);
   pTmp->setPPS(0);
+#if JVET_O_MAX_NUM_ALF_APS_8
+  memset(pTmp->getAlfAPSs(), 0, sizeof(*pTmp->getAlfAPSs())*ALF_CTB_MAX_NUM_APS);
+#else
   memset(pTmp->getAlfAPSs(), 0, sizeof(*pTmp->getAlfAPSs())*MAX_NUM_APS);
+#endif
 
   pTmp->setLmcsAPS(0);
   return pTmp;
diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp
index 71ca554f0148e2ad52516b588d51bfb7591be9d3..f3adf0b586ba6861774d9e82b3af2edc10fc0bac 100644
--- a/source/Lib/CommonLib/Quant.cpp
+++ b/source/Lib/CommonLib/Quant.cpp
@@ -63,23 +63,39 @@
 // ====================================================================================================================
 
 QpParam::QpParam(const int           qpy,
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+                 const ComponentID   compID,
+#else
                  const ChannelType   chType,
+#endif
                  const int           qpBdOffset,
 #if JVET_O0919_TS_MIN_QP
                  const int           minQpPrimeTsMinus4,
 #endif
                  const int           chromaQPOffset,
                  const ChromaFormat  chFmt,
-                 const int           dqp )
+                 const int           dqp 
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+              ,  const SPS           *sps
+#endif
+)
 {
   int baseQp;
-
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  if (isLuma(compID))
+#else
   if(isLuma(chType))
+#endif
   {
     baseQp = qpy + qpBdOffset;
   }
   else
   {
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+    int qpi = Clip3(-qpBdOffset, MAX_QP, qpy);
+    baseQp = sps->getMappedChromaQpValue(compID, qpi);
+    baseQp = Clip3(-qpBdOffset, MAX_QP, baseQp + chromaQPOffset) + qpBdOffset;
+#else
     baseQp = Clip3( -qpBdOffset, (chromaQPMappingTableSize - 1), qpy + chromaQPOffset );
 
     if(baseQp < 0)
@@ -90,6 +106,7 @@ QpParam::QpParam(const int           qpy,
     {
       baseQp = getScaledChromaQP(baseQp, chFmt) + qpBdOffset;
     }
+#endif
   }
 
   baseQp = Clip3( 0, MAX_QP+qpBdOffset, baseQp + dqp );
@@ -100,8 +117,11 @@ QpParam::QpParam(const int           qpy,
   rems[0]=baseQp%6;
 
   int baseQpTS = baseQp;
-
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  if (isLuma(compID))
+#else
   if( isLuma( chType ) )
+#endif
   {
     baseQpTS = std::max(baseQpTS , 4 + minQpPrimeTsMinus4);
   }
@@ -147,10 +167,23 @@ QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int
   int dqp = 0;
 
 #if JVET_O0919_TS_MIN_QP
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, compID, tu.cs->sps->getQpBDOffset(toChannelType(compID)), tu.cs->sps->getMinQpPrimeTsMinus4(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp, tu.cs->sps);
+#else
   *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, toChannelType(compID), tu.cs->sps->getQpBDOffset(toChannelType(compID)), tu.cs->sps->getMinQpPrimeTsMinus4(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp);
+#endif
+#else
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+#if JVET_O0105_ICT
+  const bool useJQP = isChroma(compID) && (abs(TU::getICTMode(tu)) == 2);
+#else
+  const bool useJQP = isChroma(compID) && tu.jointCbCr;
+#endif
+  *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, useJQP ? JOINT_CbCr : compID, tu.cs->sps->getQpBDOffset(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp, tu.cs->sps);
 #else
   *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, toChannelType(compID), tu.cs->sps->getQpBDOffset(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp);
 #endif
+#endif
 }
 
 
diff --git a/source/Lib/CommonLib/Quant.h b/source/Lib/CommonLib/Quant.h
index 16eba76cbc871781b021e5b6ebfe1909bc67c25f..eb36a1a4f80646d4731ba686f75a31f5eed9c622 100644
--- a/source/Lib/CommonLib/Quant.h
+++ b/source/Lib/CommonLib/Quant.h
@@ -84,14 +84,22 @@ struct QpParam
 private:
 
   QpParam(const int           qpy,
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+          const ComponentID   compID,
+#else
           const ChannelType   chType,
+#endif
           const int           qpBdOffset,
 #if JVET_O0919_TS_MIN_QP
           const int           minQpPrimeTsMinus4,
 #endif
           const int           chromaQPOffset,
           const ChromaFormat  chFmt,
-          const int           dqp );
+          const int           dqp 
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+        , const SPS           *sps
+#endif
+  );
 
 public:
 
diff --git a/source/Lib/CommonLib/Reshape.cpp b/source/Lib/CommonLib/Reshape.cpp
index f404313a2143b17f73b235761f96d2ba0a8944d7..754af0b4573ddb3671c04e508683f9e01c1e80f9 100644
--- a/source/Lib/CommonLib/Reshape.cpp
+++ b/source/Lib/CommonLib/Reshape.cpp
@@ -49,13 +49,15 @@
  // ====================================================================================================================
 
 Reshape::Reshape()
-{
-  m_CTUFlag = false;
-  m_recReshaped = false;
-  m_reshape = true;
+: m_CTUFlag (false)
+, m_recReshaped (false)
+, m_reshape (true)
 #if  JVET_O1109_UNFIY_CRS
-  m_chromaScale = (1 << CSCALE_FP_PREC);
+, m_chromaScale (1 << CSCALE_FP_PREC)
 #endif
+, m_vpduX (-1)
+, m_vpduY (-1)
+{
 }
 
 Reshape::~Reshape()
diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp
index f36a0692a98f74013c8e870a53dc988647a330c4..c6895b6e2d611312566f195431651cd9b980147e 100644
--- a/source/Lib/CommonLib/Rom.cpp
+++ b/source/Lib/CommonLib/Rom.cpp
@@ -544,7 +544,7 @@ const int g_invQuantScales[2][SCALING_LIST_REM_NUM] = // can be represented as a
 //--------------------------------------------------------------------------------------------------
 //coefficients
 //--------------------------------------------------------------------------------------------------
-
+#if !JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
 const uint8_t g_aucChromaScale[NUM_CHROMA_FORMAT][chromaQPMappingTableSize] =
 {
   //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69
@@ -553,7 +553,7 @@ const uint8_t g_aucChromaScale[NUM_CHROMA_FORMAT][chromaQPMappingTableSize] =
   { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,63,63,63,63,63,63 },
   { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,63,63,63,63,63,63 }
 };
-
+#endif
 // ====================================================================================================================
 // Intra prediction
 // ====================================================================================================================
diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h
index 7303299f15115ebbb7c97a176abb8a42cecb153a..1dc86ce08a62f22a60a4ed7e612b547a6e415ddb 100644
--- a/source/Lib/CommonLib/Rom.h
+++ b/source/Lib/CommonLib/Rom.h
@@ -83,14 +83,14 @@ extern const uint8_t g_intraMode65to33AngMapping[NUM_INTRA_MODE];
 extern const uint8_t g_mapMipToAngular65[3][MAX_NUM_MIP_MODE];
 extern const uint8_t g_mapAngular33ToMip[3][35];
 extern const int     g_sortedMipMpms    [3][NUM_MPM_MIP];
-
+#if !JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
 // ====================================================================================================================
 // Luma QP to Chroma QP mapping
 // ====================================================================================================================
 static const int chromaQPMappingTableSize = (MAX_QP + 7);
 
 extern const uint8_t  g_aucChromaScale[NUM_CHROMA_FORMAT][chromaQPMappingTableSize];
-
+#endif
 
 // ====================================================================================================================
 // Scanning order & context mapping table
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 193da424023941630c2901263cbf059bd83c87e5..2404f16821df58912232b775e2dd1a19a4a8b6dc 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -82,6 +82,9 @@ Slice::Slice()
 , m_maxNumMergeCand               ( 0 )
 , m_maxNumAffineMergeCand         ( 0 )
 , m_maxNumTriangleCand            ( 0 )
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+, m_maxNumIBCMergeCand            ( 0 )
+#endif
 , m_disFracMMVD                   ( false )
 #if JVET_O1140_SLICE_DISABLE_BDOF_DMVR_FLAG
 , m_disBdofDmvrFlag               ( false )
@@ -192,6 +195,9 @@ void Slice::initSlice()
 
   m_maxNumMergeCand = MRG_MAX_NUM_CANDS;
   m_maxNumAffineMergeCand = AFFINE_MRG_MAX_NUM_CANDS;
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  m_maxNumIBCMergeCand = IBC_MRG_MAX_NUM_CANDS;
+#endif
 
   m_bFinalized=false;
 
@@ -703,6 +709,9 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll)
   m_maxNumMergeCand               = pSrc->m_maxNumMergeCand;
   m_maxNumAffineMergeCand         = pSrc->m_maxNumAffineMergeCand;
   m_maxNumTriangleCand            = pSrc->m_maxNumTriangleCand;
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  m_maxNumIBCMergeCand            = pSrc->m_maxNumIBCMergeCand;
+#endif
   m_disFracMMVD                   = pSrc->m_disFracMMVD;
 #if JVET_O1140_SLICE_DISABLE_BDOF_DMVR_FLAG
   m_disBdofDmvrFlag               = pSrc->m_disBdofDmvrFlag;
@@ -1411,6 +1420,9 @@ SPS::SPS()
 , m_transformSkipEnabledFlag  (false)
 , m_BDPCMEnabledFlag          (false)
 #endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+, m_JointCbCrEnabledFlag      (false)
+#endif
 , m_bPCMFilterDisableFlag     (false)
 , m_sbtmvpEnabledFlag         (false)
 , m_bdofEnabledFlag           (false)
@@ -1502,6 +1514,62 @@ void  SPS::createRPLList1(int numRPL)
 const int SPS::m_winUnitX[]={1,2,2,1};
 const int SPS::m_winUnitY[]={1,2,1,1};
 
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+void ChromaQpMappingTable::setParams(const ChromaQpMappingTableParams &params, const int qpBdOffset)
+{
+  m_qpBdOffset = qpBdOffset;
+  m_sameCQPTableForAllChromaFlag = params.m_sameCQPTableForAllChromaFlag;
+  for (int i = 0; i < MAX_NUM_CQP_MAPPING_TABLES; i++)
+  {
+    m_numPtsInCQPTableMinus1[i] = params.m_numPtsInCQPTableMinus1[i];
+    m_deltaQpInValMinus1[i] = params.m_deltaQpInValMinus1[i];
+    m_deltaQpOutVal[i] = params.m_deltaQpOutVal[i];
+  }
+}
+void ChromaQpMappingTable::derivedChromaQPMappingTables()
+{
+  for (int i = 0; i < (getSameCQPTableForAllChromaFlag() ? 1 : 3); i++)
+  {
+    const int qpBdOffsetC = m_qpBdOffset;
+    const int numPtsInCQPTableMinus1 = getNumPtsInCQPTableMinus1(i);
+    std::vector<int> qpInVal(numPtsInCQPTableMinus1 + 1), qpOutVal(numPtsInCQPTableMinus1 + 1);
+
+    qpInVal[0] = -qpBdOffsetC + getDeltaQpInValMinus1(i, 0);
+    qpOutVal[0] = -qpBdOffsetC + getDeltaQpOutVal(i, 0);
+    for (int j = 1; j <= getNumPtsInCQPTableMinus1(i); j++)
+    {
+      qpInVal[j] = qpInVal[j - 1] + getDeltaQpInValMinus1(i, j) + 1;
+      qpOutVal[j] = qpOutVal[j - 1] + getDeltaQpOutVal(i, j);
+    }
+
+    for (int j = 0; j <= getNumPtsInCQPTableMinus1(i); j++)
+    {
+      CHECK(qpInVal[j]  < -qpBdOffsetC || qpInVal[j]  > MAX_QP, "qpInVal out of range");
+      CHECK(qpOutVal[j] < -qpBdOffsetC || qpOutVal[j] > MAX_QP, "qpOutVal out of range");
+    }
+
+    m_chromaQpMappingTables[i][qpInVal[0]] = qpOutVal[0];
+    for (int k = qpInVal[0] - 1; k >= -qpBdOffsetC; k--)
+    {
+      m_chromaQpMappingTables[i][k] = Clip3(-qpBdOffsetC, MAX_QP, m_chromaQpMappingTables[i][k + 1] - 1);
+    }
+    for (int j = 0; j < numPtsInCQPTableMinus1; j++)
+    {
+      int sh = (getDeltaQpInValMinus1(i, j + 1) + 1 + 1) >> 1;
+      for (int k = qpInVal[j] + 1, m = 1; k <= qpInVal[j + 1]; k++, m++)
+      {
+        m_chromaQpMappingTables[i][k] = m_chromaQpMappingTables[i][qpInVal[j]]
+          + (getDeltaQpOutVal(i, j + 1) * m + sh) / (getDeltaQpInValMinus1(i, j + 1) + 1);
+      }
+    }
+    for (int k = qpInVal[numPtsInCQPTableMinus1]+1; k <= MAX_QP; k++)
+    {
+      m_chromaQpMappingTables[i][k] = Clip3(-qpBdOffsetC, MAX_QP, m_chromaQpMappingTables[i][k - 1] + 1);
+    }
+  }
+}
+#endif
+
 PPSRExt::PPSRExt()
 : m_log2MaxTransformSkipBlockSize      (2)
 , m_crossComponentPredictionEnabledFlag(false)
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index c6517b756d4b0ac8d25328ae54524bcb99e308bd..bf8fa59fd884f8ffdcff9dffe16b26f7b4e71862 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -208,6 +208,9 @@ class ConstraintInfo
   bool              m_noTransformSkipConstraintFlag;
 #if JVET_O1136_TS_BDPCM_SIGNALLING
   bool              m_noBDPCMConstraintFlag;
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool              m_noJointCbCrConstraintFlag;
 #endif
   bool              m_noQpDeltaConstraintFlag;
   bool              m_noDepQuantConstraintFlag;
@@ -246,6 +249,9 @@ public:
     , m_noTransformSkipConstraintFlag(false)
 #if JVET_O1136_TS_BDPCM_SIGNALLING
     , m_noBDPCMConstraintFlag    (false)
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+    , m_noJointCbCrConstraintFlag (false)
 #endif
     , m_noQpDeltaConstraintFlag  (false)
     , m_noDepQuantConstraintFlag (false)
@@ -287,6 +293,10 @@ public:
   void          setNoSaoConstraintFlag(bool bVal) { m_noSaoConstraintFlag = bVal; }
   bool          getNoAlfConstraintFlag() const { return m_noAlfConstraintFlag; }
   void          setNoAlfConstraintFlag(bool bVal) { m_noAlfConstraintFlag = bVal; }
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool          getNoJointCbCrConstraintFlag() const { return m_noJointCbCrConstraintFlag; }
+  void          setNoJointCbCrConstraintFlag(bool bVal) { m_noJointCbCrConstraintFlag = bVal; }
+#endif
   bool          getNoPcmConstraintFlag() const { return m_noPcmConstraintFlag; }
   void          setNoPcmConstraintFlag(bool bVal) { m_noPcmConstraintFlag = bVal; }
   bool          getNoRefWraparoundConstraintFlag() const { return m_noRefWraparoundConstraintFlag; }
@@ -431,8 +441,43 @@ struct ChromaQpAdj
 #endif
   } u;
 };
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+struct ChromaQpMappingTableParams {
+  int               m_qpBdOffset;
+  bool              m_sameCQPTableForAllChromaFlag;
+  int               m_numPtsInCQPTableMinus1[MAX_NUM_CQP_MAPPING_TABLES];
+  std::vector<int>  m_deltaQpInValMinus1[MAX_NUM_CQP_MAPPING_TABLES];
+  std::vector<int>  m_deltaQpOutVal[MAX_NUM_CQP_MAPPING_TABLES];
+
+  ChromaQpMappingTableParams()
+  {
+    m_qpBdOffset = 12;
+    m_sameCQPTableForAllChromaFlag = true;
+    m_numPtsInCQPTableMinus1[0] = 0;
+    m_deltaQpInValMinus1[0] = { 0 };
+    m_deltaQpOutVal[0] = { 0 };
+  }
 
+  void      setSameCQPTableForAllChromaFlag(bool b)                             { m_sameCQPTableForAllChromaFlag = b; }
+  bool      getSameCQPTableForAllChromaFlag()                             const { return m_sameCQPTableForAllChromaFlag; }
+  void      setNumPtsInCQPTableMinus1(int tableIdx, int n)                      { m_numPtsInCQPTableMinus1[tableIdx] = n; }
+  int       getNumPtsInCQPTableMinus1(int tableIdx)                       const { return m_numPtsInCQPTableMinus1[tableIdx]; }
+  void      setDeltaQpInValMinus1(int tableIdx, std::vector<int> &inVals)       { m_deltaQpInValMinus1[tableIdx] = inVals; }
+  void      setDeltaQpInValMinus1(int tableIdx, int idx, int n)                 { m_deltaQpInValMinus1[tableIdx][idx] = n; }
+  int       getDeltaQpInValMinus1(int tableIdx, int idx)                  const { return m_deltaQpInValMinus1[tableIdx][idx]; }
+  void      setDeltaQpOutVal(int tableIdx, std::vector<int> &outVals)           { m_deltaQpOutVal[tableIdx] = outVals; }
+  void      setDeltaQpOutVal(int tableIdx, int idx, int n)                      { m_deltaQpOutVal[tableIdx][idx] = n; }
+  int       getDeltaQpOutVal(int tableIdx, int idx)                       const { return m_deltaQpOutVal[tableIdx][idx]; }
+};
+struct ChromaQpMappingTable : ChromaQpMappingTableParams
+{
+  std::map<int, int> m_chromaQpMappingTables[MAX_NUM_CQP_MAPPING_TABLES];
 
+  int       getMappedChromaQpValue(ComponentID compID, const int qpVal)  const { return m_chromaQpMappingTables[m_sameCQPTableForAllChromaFlag ? 0 : (int)compID - 1].at(qpVal); }
+  void      derivedChromaQPMappingTables();
+  void      setParams(const ChromaQpMappingTableParams &params, const int qpBdOffset);
+};
+#endif
 class DPS
 {
 private:
@@ -734,7 +779,9 @@ private:
   bool              m_transformSkipEnabledFlag;
   bool              m_BDPCMEnabledFlag;
 #endif
-
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool              m_JointCbCrEnabledFlag;
+#endif
   // Parameter
   BitDepths         m_bitDepths;
   int               m_qpBDOffset[MAX_NUM_CHANNEL_TYPE];
@@ -819,6 +866,9 @@ private:
   int               m_LadfIntervalLowerBound[MAX_LADF_INTERVALS];
 #endif
   bool              m_MIP;
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  ChromaQpMappingTable m_chromaQpMappingTable;
+#endif
 
 public:
 
@@ -955,7 +1005,10 @@ public:
 
   bool                    getALFEnabledFlag() const                                                       { return m_alfEnabledFlag; }
   void                    setALFEnabledFlag( bool b )                                                     { m_alfEnabledFlag = b; }
-
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  void                    setJointCbCrEnabledFlag(bool bVal)                                              { m_JointCbCrEnabledFlag = bVal; }
+  bool                    getJointCbCrEnabledFlag() const                                                 { return m_JointCbCrEnabledFlag; }
+#endif
   bool                    getSBTMVPEnabledFlag() const                                                    { return m_sbtmvpEnabledFlag; }
   void                    setSBTMVPEnabledFlag(bool b)                                                    { m_sbtmvpEnabledFlag = b; }
 
@@ -1085,6 +1138,12 @@ public:
   void      setUseWP              ( bool b )                                        { m_useWeightPred = b; }
   void      setUseWPBiPred        ( bool b )                                        { m_useWeightedBiPred = b; }
 #endif
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  void      setChromaQpMappingTableFromParams(const ChromaQpMappingTableParams &params, const int qpBdOffset)   { m_chromaQpMappingTable.setParams(params, qpBdOffset); }
+  void      derivedChromaQPMappingTables()                                          { m_chromaQpMappingTable.derivedChromaQPMappingTables(); }
+  const ChromaQpMappingTable& getChromaQpMappingTable()                   const     { return m_chromaQpMappingTable;}
+  int       getMappedChromaQpValue(ComponentID compID, int qpVal)         const     { return m_chromaQpMappingTable.getMappedChromaQpValue(compID, qpVal); }
+#endif
 };
 
 
@@ -1522,6 +1581,9 @@ private:
   uint32_t                       m_maxNumMergeCand;
   uint32_t                   m_maxNumAffineMergeCand;
   uint32_t                   m_maxNumTriangleCand;
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  uint32_t                   m_maxNumIBCMergeCand;
+#endif
   bool                       m_disFracMMVD;
 #if JVET_O1140_SLICE_DISABLE_BDOF_DMVR_FLAG
   bool                       m_disBdofDmvrFlag;
@@ -1580,7 +1642,11 @@ private:
   uint32_t                   m_uiMaxTTSizeIChroma;
   uint32_t                   m_uiMaxBTSize;
 
+#if JVET_O_MAX_NUM_ALF_APS_8
+  APS*                       m_alfApss[ALF_CTB_MAX_NUM_APS];
+#else
   APS*                       m_alfApss[MAX_NUM_APS];
+#endif
   bool                       m_tileGroupAlfEnabledFlag[MAX_NUM_COMPONENT];
   int                        m_tileGroupNumAps;
   std::vector<int>           m_tileGroupLumaApsId;
@@ -1771,6 +1837,10 @@ public:
   uint32_t                    getMaxNumAffineMergeCand() const                       { return m_maxNumAffineMergeCand; }
   void                        setMaxNumTriangleCand(uint32_t val)                    { m_maxNumTriangleCand = val;}
   uint32_t                    getMaxNumTriangleCand() const                          { return m_maxNumTriangleCand;}
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  void                        setMaxNumIBCMergeCand( uint32_t val )                  { m_maxNumIBCMergeCand = val; }
+  uint32_t                    getMaxNumIBCMergeCand() const                          { return m_maxNumIBCMergeCand; }
+#endif
   void                        setDisFracMMVD( bool val )                             { m_disFracMMVD = val;                                          }
   bool                        getDisFracMMVD() const                                 { return m_disFracMMVD;                                         }
 #if JVET_O1140_SLICE_DISABLE_BDOF_DMVR_FLAG
@@ -2089,7 +2159,11 @@ protected:
   ParameterSetMap<APS> m_apsMap;
   ParameterSetMap<DPS> m_dpsMap;
 
+#if JVET_O_MAX_NUM_ALF_APS_8
+  APS* m_apss[ALF_CTB_MAX_NUM_APS];
+#else
   APS* m_apss[MAX_NUM_APS];
+#endif
 
   int m_activeDPSId; // -1 for nothing active
   int m_activeSPSId; // -1 for nothing active
diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp
index d45791d5d0dc44ec8d24bd8292d3c2fbc87faf4a..ddf049944672ecf852292f6b0c0ecdcf9e154ea2 100644
--- a/source/Lib/CommonLib/TrQuant.cpp
+++ b/source/Lib/CommonLib/TrQuant.cpp
@@ -1056,7 +1056,11 @@ void TrQuant::xQuant(TransformUnit &tu, const ComponentID &compID, const CCoeffB
   m_quant->quant( tu, compID, pSrc, uiAbsSum, cQP, ctx );
 }
 
+#if JVET_O0502_ISP_CLEANUP
+void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, std::vector<TrMode>* trModes, const int maxCand )
+#else
 void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio, double* horVerRatio )
+#endif
 {
         CodingStructure &cs = *tu.cs;
   const CompArea &rect      = tu.blocks[compID];
@@ -1111,9 +1115,11 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const
     it++;
   }
 
+#if !JVET_O0502_ISP_CLEANUP
   // it gets the distribution of the DCT-II coefficients energy, which will be useful to discard ISP tests
   CoeffBuf coeffsDCT( m_mtsCoeffs[0], rect );
   xGetCoeffEnergy( tu, compID, coeffsDCT, diagRatio, horVerRatio );
+#endif
   int numTests = 0;
   std::vector<TrCost>::iterator itC = trCosts.begin();
   const double fac   = facBB[g_aucLog2[std::max(width, height)]-2];
@@ -1128,7 +1134,11 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const
   }
 }
 
+#if JVET_O0502_ISP_CLEANUP
+void TrQuant::transformNxN( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, TCoeff& uiAbsSum, const Ctx& ctx, const bool loadTr )
+#else
 void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr, double* diagRatio, double* horVerRatio )
+#endif
 {
         CodingStructure &cs = *tu.cs;
   const SPS &sps            = *cs.sps;
@@ -1207,6 +1217,7 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const
       }
       }
 
+#if !JVET_O0502_ISP_CLEANUP
       //we do this only with the DCT-II coefficients
       if( isLuma(compID) &&
         !loadTr && tu.mtsIdx == MTS_DCT2_DCT2
@@ -1215,6 +1226,7 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const
         //it gets the distribution of the coefficients energy, which will be useful to discard ISP tests
         xGetCoeffEnergy( tu, compID, tempCoeff, diagRatio, horVerRatio );
       }
+#endif
 
       if( sps.getUseLFNST() )
       {
@@ -1233,6 +1245,7 @@ void TrQuant::transformNxN( TransformUnit &tu, const ComponentID &compID, const
   TU::setCbfAtDepth (tu, compID, tu.depth, uiAbsSum > 0);
 }
 
+#if !JVET_O0502_ISP_CLEANUP
 void TrQuant::xGetCoeffEnergy( TransformUnit &tu, const ComponentID &compID, const CoeffBuf& coeffs, double* diagRatio, double* horVerRatio )
 {
   if( nullptr == diagRatio || nullptr == horVerRatio ) return;
@@ -1266,6 +1279,7 @@ void TrQuant::xGetCoeffEnergy( TransformUnit &tu, const ComponentID &compID, con
     *diagRatio   = 0 == wdtE && 0 == hgtE && 0 == diaE ? 1 : double( diaE ) / double( wdtE + hgtE );
   }
 }
+#endif
 
 void TrQuant::applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &mode)
 {
diff --git a/source/Lib/CommonLib/TrQuant.h b/source/Lib/CommonLib/TrQuant.h
index f762386ac69e657895902d7540923876f41d29bd..ba4e30823bad883025a8d44e28e88d1f239a5d0c 100644
--- a/source/Lib/CommonLib/TrQuant.h
+++ b/source/Lib/CommonLib/TrQuant.h
@@ -94,9 +94,13 @@ protected:
 public:
 
   void invTransformNxN  (TransformUnit &tu, const ComponentID &compID, PelBuf &pResi, const QpParam &cQPs);
-
+#if JVET_O0502_ISP_CLEANUP
+  void transformNxN     ( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, std::vector<TrMode>* trModes, const int maxCand );
+  void transformNxN     ( TransformUnit& tu, const ComponentID& compID, const QpParam& cQP, TCoeff& uiAbsSum, const Ctx& ctx, const bool loadTr = false );
+#else
   void transformNxN     ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, std::vector<TrMode>* trModes, const int maxCand, double* diagRatio = nullptr, double* horVerRatio = nullptr );
   void transformNxN     ( TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const Ctx &ctx, const bool loadTr = false, double* diagRatio = nullptr, double* horVerRatio = nullptr );
+#endif
   void rdpcmNxN         (TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum,       RDPCMMode &rdpcmMode);
   void applyForwardRDPCM(TransformUnit &tu, const ComponentID &compID, const QpParam &cQP, TCoeff &uiAbsSum, const RDPCMMode &rdpcmMode);
 
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 0805c4173eeb90de03af2bff4c3215e4d5de18fe..2f47b2e91688c2b3651f58d05c0d5cf89e1fc96b 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,8 +50,21 @@
 #include <assert.h>
 #include <cassert>
 
+
 #define JVET_O0119_BASE_PALETTE_444                       1 // JVET-O0119: Palette mode in HEVC and palette mode signaling in JVET-N0258. Only enabled for YUV444.    
 
+#define JVET_O0304_SIMPLIFIED_BDOF                        1 // JVET-O0304: Reduction of number of multiplications in BDOF
+
+#define JVET_O0455_IBC_MAX_MERGE_NUM                      1 // JVET-O0455: Control the max number of IBC merge candidates independently from regular merge candidates
+
+#define JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE          1 // JVET-O0650: Signal chroma QP mapping tables and move chroma PPS/slice offsets after mapping table
+
+#define JVET_O0502_ISP_CLEANUP                            1 // JVET-O0502: Enable PDPC and all 67 intra modes and apply the cubic filter always (also included in JVET-O0341) for ISP
+
+#define JVET_O0640_PICTURE_SIZE_CONSTRAINT                1 // JVET-O0640: Picture width and height shall be a multiple of Max(8, minCU size)
+
+#define JVET_O_MAX_NUM_ALF_APS_8                          1 // JVET-O: number of ALF APSs is reduced to 8
+
 #define JVET_O0070_PROF                                   1 // JVET-O0070 method 4-2.1a: Prediction refinement with optical flow for affine mode
 
 #define JVET_O0570_GRAD_SIMP                              1 // JVET-O0570/JVET-O0211, SMID friendly spatial gradient calculation
@@ -215,6 +228,8 @@
 #define JVET_O0249_MERGE_SYNTAX                           1 // JVET-O0249: merge syntax change 
 #define JVET_O0594_BDOF_REF_SAMPLE_PADDING                1 // JVET-O0594/O0252/O0506/O0615/O0624: BDOF reference sample padding using the nearest integer sample position
 
+
+#define JVET_O0376_SPS_JOINTCBCR_FLAG                          1 // JVET-O0376: add the JointCbCr control flag in SPS
 #define JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS         1 // JVET-O0472: LFNST index signalling depends on the position of last significant coefficient
 
 #define FIX_DB_MAX_TRANSFORM_SIZE                         1
@@ -485,7 +500,12 @@ enum ISPType
   NOT_INTRA_SUBPARTITIONS       = 0,
   HOR_INTRA_SUBPARTITIONS       = 1,
   VER_INTRA_SUBPARTITIONS       = 2,
+#if JVET_O0502_ISP_CLEANUP
+  NUM_INTRA_SUBPARTITIONS_MODES = 3,
+  INTRA_SUBPARTITIONS_RESERVED  = 4
+#else
   NUM_INTRA_SUBPARTITIONS_MODES = 3
+#endif
 };
 
 enum SbtIdx
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index faa4c2f961c1cd5de9e651a90b1931bd255c5ab7..55da1ffc2535c31f9fa55ffab3d6bbe13b58da8e 100755
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -289,6 +289,7 @@ bool CU::divideTuInRows( const CodingUnit &cu )
   return cu.ispMode == HOR_INTRA_SUBPARTITIONS ? true : false;
 }
 
+#if !JVET_O0502_ISP_CLEANUP
 bool CU::firstTestISPHorSplit( const int width, const int height, const ComponentID compID, const CodingUnit *cuLeft, const CodingUnit *cuAbove )
 {
   //this function decides which split mode (horizontal or vertical) is tested first (encoder only)
@@ -358,6 +359,7 @@ bool CU::firstTestISPHorSplit( const int width, const int height, const Componen
     return true;
   }
 }
+#endif
 
 PartSplit CU::getISPType( const CodingUnit &cu, const ComponentID compID )
 {
@@ -439,6 +441,30 @@ uint32_t CU::getISPSplitDim( const int width, const int height, const PartSplit
   return partitionSize;
 }
 
+#if JVET_O0502_ISP_CLEANUP
+bool CU::allLumaCBFsAreZero(const CodingUnit& cu)
+{
+  if (!cu.ispMode)
+  {
+    return TU::getCbf(*cu.firstTU, COMPONENT_Y) == false;
+  }
+  else
+  {
+    int numTotalTUs = cu.ispMode == HOR_INTRA_SUBPARTITIONS ? cu.lheight() >> g_aucLog2[cu.firstTU->lheight()] : cu.lwidth() >> g_aucLog2[cu.firstTU->lwidth()];
+    TransformUnit* tuPtr = cu.firstTU;
+    for (int tuIdx = 0; tuIdx < numTotalTUs; tuIdx++)
+    {
+      if (TU::getCbf(*tuPtr, COMPONENT_Y) == true)
+      {
+        return false;
+      }
+      tuPtr = tuPtr->next;
+    }
+    return true;
+  }
+}
+#endif
+
 
 PUTraverser CU::traversePUs( CodingUnit& cu )
 {
@@ -1014,7 +1040,11 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 {
   const CodingStructure &cs = *pu.cs;
   const Slice &slice = *pu.cs->slice;
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  const uint32_t maxNumMergeCand = slice.getMaxNumIBCMergeCand();
+#else
   const uint32_t maxNumMergeCand = slice.getMaxNumMergeCand();
+#endif
   const bool canFastExit = pu.cs->pps->getLog2ParallelMergeLevelMinus2() == 0;
 
   for (uint32_t ui = 0; ui < maxNumMergeCand; ++ui)
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index a7610dd5ea825c92393836186b4c749f3b02af7f..0530ae2dbb4e6348bb7e98e7cd58140e62fe1e72 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -99,13 +99,18 @@ namespace CU
 
 
   bool      divideTuInRows            ( const CodingUnit &cu );
+#if !JVET_O0502_ISP_CLEANUP
   bool      firstTestISPHorSplit      ( const int width, const int height,            const ComponentID compID, const CodingUnit *cuLeft = nullptr, const CodingUnit *cuAbove = nullptr );
+#endif
   PartSplit getISPType                ( const CodingUnit &cu,                         const ComponentID compID );
   bool      isISPLast                 ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID );
   bool      isISPFirst                ( const CodingUnit &cu, const CompArea &tuArea, const ComponentID compID );
   bool      canUseISP                 ( const CodingUnit &cu,                         const ComponentID compID );
   bool      canUseISP                 ( const int width, const int height, const int maxTrSize = MAX_TB_SIZEY );
   uint32_t  getISPSplitDim            ( const int width, const int height, const PartSplit ispType );
+#if JVET_O0502_ISP_CLEANUP
+  bool      allLumaCBFsAreZero        ( const CodingUnit& cu );
+#endif
 
   PUTraverser traversePUs             (      CodingUnit& cu);
   TUTraverser traverseTUs             (      CodingUnit& cu);
diff --git a/source/Lib/CommonLib/x86/BufferX86.h b/source/Lib/CommonLib/x86/BufferX86.h
index 6e82e3f411a3b3666cc0ec707988be68d023abd2..a09ae89b2110cbaf8b3318b8a6eaf583ae53d222 100644
--- a/source/Lib/CommonLib/x86/BufferX86.h
+++ b/source/Lib/CommonLib/x86/BufferX86.h
@@ -278,6 +278,62 @@ void addBIOAvg4_SSE(const Pel* src0, int src0Stride, const Pel* src1, int src1St
   }
 }
 
+#if JVET_O0304_SIMPLIFIED_BDOF
+template< X86_VEXT vext >
+void calcBIOSums_SSE(const Pel* srcY0Tmp, const Pel* srcY1Tmp, Pel* gradX0, Pel* gradX1, Pel* gradY0, Pel* gradY1, int xu, int yu, const int src0Stride, const int src1Stride, const int widthG, const int bitDepth, int* sumAbsGX, int* sumAbsGY, int* sumDIX, int* sumDIY, int* sumSignGY_GX)
+
+{
+  int shift4 = std::max<int>(4, (bitDepth - 8));
+  int shift5 = std::max<int>(1, (bitDepth - 11));
+
+  __m128i sumAbsGXTmp = _mm_setzero_si128();
+  __m128i sumDIXTmp = _mm_setzero_si128();
+  __m128i sumAbsGYTmp = _mm_setzero_si128();
+  __m128i sumDIYTmp = _mm_setzero_si128();
+  __m128i sumSignGyGxTmp = _mm_setzero_si128();
+  Pel tmpStore[8];
+  for (int y = 0; y < 6; y++)
+  {
+    __m128i shiftSrcY0Tmp = _mm_srai_epi16(_mm_loadu_si128((__m128i*)(srcY0Tmp)), shift4);
+    __m128i shiftSrcY1Tmp = _mm_srai_epi16(_mm_loadu_si128((__m128i*)(srcY1Tmp)), shift4);
+    __m128i loadGradX0 = _mm_loadu_si128((__m128i*)(gradX0));
+    __m128i loadGradX1 = _mm_loadu_si128((__m128i*)(gradX1));
+    __m128i loadGradY0 = _mm_loadu_si128((__m128i*)(gradY0));
+    __m128i loadGradY1 = _mm_loadu_si128((__m128i*)(gradY1));
+    __m128i subTemp1 = _mm_sub_epi16(shiftSrcY1Tmp, shiftSrcY0Tmp);
+    __m128i packTempX = _mm_srai_epi16(_mm_add_epi16(loadGradX0, loadGradX1), shift5);
+    __m128i packTempY = _mm_srai_epi16(_mm_add_epi16(loadGradY0, loadGradY1), shift5);
+    __m128i gX = _mm_abs_epi16(packTempX);
+    __m128i gY = _mm_abs_epi16(packTempY);
+    __m128i dIX       = _mm_sign_epi16(subTemp1,  packTempX );
+    __m128i dIY       = _mm_sign_epi16(subTemp1,  packTempY );
+    __m128i signGY_GX = _mm_sign_epi16(packTempX, packTempY );
+
+    sumAbsGXTmp = _mm_add_epi16(sumAbsGXTmp, gX);
+    sumDIXTmp = _mm_add_epi16(sumDIXTmp, dIX);
+    sumAbsGYTmp = _mm_add_epi16(sumAbsGYTmp, gY);
+    sumDIYTmp = _mm_add_epi16(sumDIYTmp, dIY);
+    sumSignGyGxTmp = _mm_add_epi16(sumSignGyGxTmp, signGY_GX);
+    srcY0Tmp += src0Stride;
+    srcY1Tmp += src1Stride;
+    gradX0 += widthG;
+    gradX1 += widthG;
+    gradY0 += widthG;
+    gradY1 += widthG;
+  }
+  _mm_storeu_si128((__m128i *)tmpStore, sumAbsGXTmp);
+  *sumAbsGX = tmpStore[0] + tmpStore[1] + tmpStore[2] + tmpStore[3] + tmpStore[4] + tmpStore[5];
+  _mm_storeu_si128((__m128i *)tmpStore, sumAbsGYTmp);
+  *sumAbsGY = tmpStore[0] + tmpStore[1] + tmpStore[2] + tmpStore[3] + tmpStore[4] + tmpStore[5];
+  _mm_storeu_si128((__m128i *)tmpStore, sumDIXTmp);
+  *sumDIX = tmpStore[0] + tmpStore[1] + tmpStore[2] + tmpStore[3] + tmpStore[4] + tmpStore[5];
+  _mm_storeu_si128((__m128i *)tmpStore, sumDIYTmp);
+  *sumDIY = tmpStore[0] + tmpStore[1] + tmpStore[2] + tmpStore[3] + tmpStore[4] + tmpStore[5];
+  _mm_storeu_si128((__m128i *)tmpStore, sumSignGyGxTmp);
+  *sumSignGY_GX = tmpStore[0] + tmpStore[1] + tmpStore[2] + tmpStore[3] + tmpStore[4] + tmpStore[5];
+}
+#endif
+
 #if JVET_O0070_PROF
 template< X86_VEXT vext >
 void applyPROF_SSE(Pel* dstPel, int dstStride, const Pel* srcPel, int srcStride, int width, int height, const Pel* gradX, const Pel* gradY, int gradStride, const int* dMvX, const int* dMvY, int dMvStride, int shiftNum, Pel offset, const ClpRng& clpRng)
@@ -1184,8 +1240,12 @@ void PelBufferOps::_initPelBufOpsX86()
 
   addBIOAvg4      = addBIOAvg4_SSE<vext>;
   bioGradFilter   = gradFilter_SSE<vext>;
-  calcBIOPar      = calcBIOPar_SSE<vext>;
+#if !JVET_O0304_SIMPLIFIED_BDOF
+  calcBIOPar = calcBIOPar_SSE<vext>;
   calcBlkGradient = calcBlkGradient_SSE<vext>;
+#else
+  calcBIOSums = calcBIOSums_SSE<vext>;
+#endif
 
   copyBuffer = copyBufferSimd<vext>;
   padding    = paddingSimd<vext>;
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 7621fa18d202b70c55f1001ad21822590daaa0ad..ca63508c569648ad3d13229120c5022a75c68af0 100755
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -1362,7 +1362,11 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu )
   for( int k = 0; k < numBlocks; k++ )
   {
     CHECK(numBlocks != 1, "not supported yet");
+#if JVET_O0502_ISP_CLEANUP
+    if ( cu.firstPU->multiRefIdx )
+#else
     if( cu.firstPU->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) )
+#endif
     {
       mpmFlag[0] = true;
     }
@@ -1584,9 +1588,7 @@ void CABACReader::cu_residual( CodingUnit& cu, Partitioner &partitioner, CUCtx&
   cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
 #endif
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-  cuCtx.lastScanPos[COMPONENT_Y ] = -1;
-  cuCtx.lastScanPos[COMPONENT_Cb] = -1;
-  cuCtx.lastScanPos[COMPONENT_Cr] = -1;
+  cuCtx.lfnstLastScanPos = false;
 #endif
 
   ChromaCbfs chromaCbfs;
@@ -2399,7 +2401,7 @@ void CABACReader::merge_data( PredictionUnit& pu )
       return;
     }
 
-    const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB();
+    const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB() && pu.cu->cs->slice->getMaxNumTriangleCand() > 1;
     const bool ciipAvailable = pu.cs->sps->getUseMHIntra() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE;
     if (pu.cu->lwidth() * pu.cu->lheight() >= 64
       && (triangleAvailable || ciipAvailable))
@@ -2533,6 +2535,12 @@ void CABACReader::merge_idx( PredictionUnit& pu )
     return;
   }
 
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  if (pu.cu->predMode == MODE_IBC)
+  {
+    numCandminus1 = int(pu.cs->slice->getMaxNumIBCMergeCand()) - 1;
+  }
+#endif
   if( numCandminus1 > 0 )
   {
     if( m_BinDecoder.decodeBin( Ctx::MergeIdx() ) )
@@ -3298,6 +3306,13 @@ void CABACReader::cu_chroma_qp_offset( CodingUnit& cu )
 #if JVET_O0105_ICT
 void CABACReader::joint_cb_cr( TransformUnit& tu, const int cbfMask )
 {
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  if ( !tu.cu->slice->getSPS()->getJointCbCrEnabledFlag() )
+  {
+    return;
+  }
+#endif
+
 #if JVET_O0543_ICT_ICU_ONLY
   if( ( CU::isIntra( *tu.cu ) && cbfMask ) || ( cbfMask == 3 ) )
 #else
@@ -3378,7 +3393,8 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID )
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
   if( tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 )
   {
-    cuCtx.lastScanPos[compID] = cctx.scanPosLast();
+    const int lfnstLastScanPosTh = isLuma( compID ) ? LFNST_LAST_SIG_LUMA : LFNST_LAST_SIG_CHROMA;
+    cuCtx.lfnstLastScanPos |= cctx.scanPosLast() >= lfnstLastScanPosTh;
   }
 #endif
   // parse subblocks
@@ -3546,24 +3562,20 @@ void CABACReader::residual_lfnst_mode( CodingUnit& cu )
 #else
     bool nonZeroCoeffNonTsCorner8x8 = CU::getNumNonZeroCoeffNonTsCorner8x8( cu, lumaFlag, chromaFlag ) > 0;
 #endif
-#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-    const bool skipLfnst            = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA ) :
-                                    ( cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ) ) :
-                                    ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA && cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA );
-#else
+#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
     const int  nonZeroCoeffThr       = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA;
     nonZeroCoeffNonTs = CU::getNumNonZeroCoeffNonTs( cu, lumaFlag, chromaFlag ) > nonZeroCoeffThr;
 #endif
 #if JVET_O0368_LFNST_WITH_DCT2_ONLY
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2);
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-    if( skipLfnst || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
+    if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
 #else
     if (!nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 || isNonDCT2)
 #endif
 #else
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-    if( skipLfnst || nonZeroCoeffNonTsCorner8x8 )
+    if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 )
 #else
     if( !nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 )
 #endif
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 2d698114da8bd10f55243b3d2acd8fa9eae16569..5ae1d31d1cf367047c219a18196c530ee65e3b06 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -211,8 +211,39 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID )
 
   const PredictionUnit &pu  = *tu.cs->getPU( area.pos(), chType );
   const uint32_t uiChFinalMode  = PU::getFinalIntraMode( pu, chType );
+#if JVET_O0502_ISP_CLEANUP
+  PelBuf pReco              = cs.getRecoBuf(area);
+#endif
 
   //===== init availability pattern =====
+#if JVET_O0502_ISP_CLEANUP
+#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
+  bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID);
+  bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area);
+  CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area);
+#endif
+  if (tu.cu->ispMode && isLuma(compID))
+  {
+#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
+    if (predRegDiffFromTB)
+    {
+      if (firstTBInPredReg)
+      {
+        CU::adjustPredArea(areaPredReg);
+        m_pcIntraPred->initIntraPatternChTypeISP(*tu.cu, areaPredReg, pReco);
+      }
+    }
+    else
+#endif
+    {
+      m_pcIntraPred->initIntraPatternChTypeISP(*tu.cu, area, pReco);
+    }
+  }
+  else
+  {
+    m_pcIntraPred->initIntraPatternChType(*tu.cu, area);
+  }
+#else
 #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
   bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID);
   bool firstTBInPredReg  = CU::isFirstTBInPredReg (*tu.cu, compID, area);
@@ -228,6 +259,7 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID )
   else
 #endif
     m_pcIntraPred->initIntraPatternChType(*tu.cu, area);
+#endif
 
   //===== get prediction signal =====
   if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) )
@@ -330,7 +362,9 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID )
     CrossComponentPrediction::crossComponentPrediction( tu, compID, cs.getResiBuf( tu.Y() ), piResi, piResi, true );
   }
 
+#if !JVET_O0502_ISP_CLEANUP
   PelBuf pReco = cs.getRecoBuf( area );
+#endif
 
   if( !tu.cu->ispMode || !isLuma( compID ) )
   {
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 58538bd8bc46086e2f414ee3398de10563a5bc21..a8b680961d7c05a057bdd5c29dd37484560c3795 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -740,7 +740,11 @@ void DecLib::xActivateParameterSets()
   if (m_bFirstSliceInPicture)
   {
     APS** apss = m_parameterSetManager.getAPSs();
+#if JVET_O_MAX_NUM_ALF_APS_8
+    memset(apss, 0, sizeof(*apss) * ALF_CTB_MAX_NUM_APS);
+#else
     memset(apss, 0, sizeof(*apss) * MAX_NUM_APS);
+#endif
     const PPS *pps = m_parameterSetManager.getPPS(m_apcSlicePilot->getPPSId()); // this is a temporary PPS object. Do not store this value
     CHECK(pps == 0, "No PPS present");
 
@@ -935,7 +939,11 @@ void DecLib::xActivateParameterSets()
     {
       EXIT("Error - a new PPS has been decoded while processing a picture");
     }
+#if JVET_O_MAX_NUM_ALF_APS_8
+    for (int i = 0; i < ALF_CTB_MAX_NUM_APS; i++)
+#else
     for (int i = 0; i < MAX_NUM_APS; i++)
+#endif
     {
       APS* aps = m_parameterSetManager.getAPS(i, ALF_APS);
       if (aps && m_parameterSetManager.getAPSChangedFlag(i, ALF_APS))
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 819538ca3a44948e7ea2d5c78d873dec66ab18f5..7e5b0c48a79db3abc46c7e3c8786565bc02bb004 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -1189,6 +1189,12 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   READ_UVLC(uiCode, "log2_min_luma_coding_block_size_minus2");
   int log2MinCUSize = uiCode + 2;
   pcSPS->setLog2MinCodingBlockSize(log2MinCUSize);
+
+#if JVET_O0640_PICTURE_SIZE_CONSTRAINT
+  CHECK((pcSPS->getPicWidthInLumaSamples()  % (std::max(8, int(pcSPS->getMaxCUWidth()  >> (pcSPS->getMaxCodingDepth() - 1))))) != 0, "Coded frame width must be a multiple of Max(8, the minimum unit size)");
+  CHECK((pcSPS->getPicHeightInLumaSamples() % (std::max(8, int(pcSPS->getMaxCUHeight() >> (pcSPS->getMaxCodingDepth() - 1))))) != 0, "Coded frame height must be a multiple of Max(8, the minimum unit size)");
+#endif
+
   READ_FLAG(uiCode, "partition_constraints_override_enabled_flag"); pcSPS->setSplitConsOverrideEnabledFlag(uiCode);
   READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_tile_group_luma");      minQT[0] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
   READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_tile_group");      minQT[1] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
@@ -1233,10 +1239,35 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   READ_UVLC( uiCode, "log2_max_luma_transform_block_size_minus2" ); pcSPS->setLog2MaxTbSize( uiCode + 2 );
 #endif
 #endif
+
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  if (pcSPS->getChromaFormatIdc() != CHROMA_400)
+  {
+    ChromaQpMappingTableParams chromaQpMappingTableParams;
+    READ_FLAG(uiCode, "same_qp_table_for_chroma");        chromaQpMappingTableParams.setSameCQPTableForAllChromaFlag(uiCode);
+    for (int i = 0; i < (chromaQpMappingTableParams.getSameCQPTableForAllChromaFlag() ? 1 : 3); i++)
+    {
+      READ_UVLC(uiCode, "num_points_in_qp_table_minus1"); chromaQpMappingTableParams.setNumPtsInCQPTableMinus1(i,uiCode);
+      std::vector<int> deltaQpInValMinus1(chromaQpMappingTableParams.getNumPtsInCQPTableMinus1(i) + 1);
+      std::vector<int> deltaQpOutVal(chromaQpMappingTableParams.getNumPtsInCQPTableMinus1(i) + 1);
+      for (int j = 0; j <= chromaQpMappingTableParams.getNumPtsInCQPTableMinus1(i); j++)
+      {
+        READ_UVLC(uiCode, "delta_qp_in_val_minus1");  deltaQpInValMinus1[j] = uiCode; 
+        READ_UVLC(uiCode, "delta_qp_out_val");        deltaQpOutVal[j] = uiCode; 
+      }
+      chromaQpMappingTableParams.setDeltaQpInValMinus1(i, deltaQpInValMinus1);
+      chromaQpMappingTableParams.setDeltaQpOutVal(i, deltaQpOutVal);
+    }
+    pcSPS->setChromaQpMappingTableFromParams(chromaQpMappingTableParams, pcSPS->getQpBDOffset(CHANNEL_TYPE_CHROMA));
+    pcSPS->derivedChromaQPMappingTables();
+  }
+#endif
+
 #if JVET_O0244_DELTA_POC
   READ_FLAG( uiCode, "sps_weighted_pred_flag" );                    pcSPS->setUseWP( uiCode ? true : false );
   READ_FLAG( uiCode, "sps_weighted_bipred_flag" );                  pcSPS->setUseWPBiPred( uiCode ? true : false );
 #endif
+  
   READ_FLAG( uiCode, "sps_sao_enabled_flag" );                      pcSPS->setSAOEnabledFlag ( uiCode ? true : false );
   READ_FLAG( uiCode, "sps_alf_enabled_flag" );                      pcSPS->setALFEnabledFlag ( uiCode ? true : false );
 
@@ -1257,7 +1288,9 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
     READ_FLAG(uiCode, "sps_bdpcm_enabled_flag"); pcSPS->setBDPCMEnabledFlag(uiCode ? true : false);
   }
 #endif
-
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  READ_FLAG( uiCode, "sps_joint_cbcr_enabled_flag");                pcSPS->setJointCbCrEnabledFlag (uiCode ? true : false);
+#endif
   if( pcSPS->getCTUSize() + 2*(1 << pcSPS->getLog2MinCodingBlockSize()) <= pcSPS->getPicWidthInLumaSamples() )
   {    
   READ_FLAG(uiCode, "sps_ref_wraparound_enabled_flag");                  pcSPS->setWrapAroundEnabledFlag( uiCode ? true : false );
@@ -1822,7 +1855,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
       if (uiCode)
       {
 #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL
+#if JVET_O_MAX_NUM_ALF_APS_8
+        READ_CODE(3, uiCode, "tile_group_num_APS");
+#else
         xReadTruncBinCode(uiCode, ALF_CTB_MAX_NUM_APS + 1);
+#endif
 #else
         if (pcSlice->isIntra())
         {
@@ -1830,7 +1867,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
         }
         else
         {
+#if JVET_O_MAX_NUM_ALF_APS_8
+          READ_CODE(3, uiCode, "tile_group_num_APS");
+#else
           xReadTruncBinCode(uiCode, ALF_CTB_MAX_NUM_APS + 1);
+#endif
         }
 #endif
         int numAps = uiCode;
@@ -1838,7 +1879,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
         std::vector<int> apsId(numAps, -1);
         for (int i = 0; i < numAps; i++)
         {
+#if JVET_O_MAX_NUM_ALF_APS_8
+          READ_CODE(3, uiCode, "tile_group_aps_id");
+#else
           READ_CODE(5, uiCode, "tile_group_aps_id");
+#endif
           apsId[i] = uiCode;
         }
 		
@@ -1859,7 +1904,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
         if (alfChromaIdc)
         {
 #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL
+#if JVET_O_MAX_NUM_ALF_APS_8
+          READ_CODE(3, uiCode, "tile_group_aps_id_chroma");
+#else
           READ_CODE(5, uiCode, "tile_group_aps_id_chroma");
+#endif
 #else
           if (pcSlice->isIntra() && pcSlice->getTileGroupNumAps() == 1)
           {
@@ -1867,7 +1916,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
           }
           else
           {
+#if JVET_O_MAX_NUM_ALF_APS_8
+            READ_CODE(3, uiCode, "tile_group_aps_id_chroma");
+#else
             READ_CODE(5, uiCode, "tile_group_aps_id_chroma");
+#endif
           }
 #endif
           pcSlice->setTileGroupApsIdChroma(uiCode);
@@ -2065,7 +2118,11 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
       }
     }
 
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+    if (!pcSlice->isIntra())
+#else
     if (!pcSlice->isIntra() || sps->getIBCFlag())
+#endif
     {
       READ_UVLC(uiCode, "six_minus_max_num_merge_cand");
       pcSlice->setMaxNumMergeCand(MRG_MAX_NUM_CANDS - uiCode);
@@ -2118,11 +2175,30 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
         pcSlice->setMaxNumTriangleCand(0);
       }
     }
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+    if (sps->getIBCFlag())
+    {
+      READ_UVLC(uiCode, "six_minus_max_num_ibc_merge_cand");
+      pcSlice->setMaxNumIBCMergeCand(IBC_MRG_MAX_NUM_CANDS - uiCode);
+    }
+#endif
+
 #if JVET_O0105_ICT
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+    if (sps->getJointCbCrEnabledFlag())
+    {
+      READ_FLAG( uiCode, "slice_joint_cbcr_sign_flag" ); pcSlice->setJointCbCrSignFlag(uiCode != 0);
+    }
+    else
+    {
+      pcSlice->setJointCbCrSignFlag(0);
+    }
+#else
     if (bChroma)
     {
-      READ_FLAG( uiCode, "joint_cb_cr_sign_flag" ); pcSlice->setJointCbCrSignFlag( uiCode != 0 );
+      READ_FLAG( uiCode, "slice_joint_cbcr_sign_flag" ); pcSlice->setJointCbCrSignFlag(uiCode != 0);
     }
+#endif 
 #endif
 
     READ_SVLC( iCode, "slice_qp_delta" );
@@ -2152,13 +2228,24 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
         CHECK( pcSlice->getSliceChromaQpDelta(COMPONENT_Cr) >  12, "Invalid chroma QP offset" );
         CHECK( (pps->getQpOffset(COMPONENT_Cr) + pcSlice->getSliceChromaQpDelta(COMPONENT_Cr)) < -12, "Invalid chroma QP offset" );
         CHECK( (pps->getQpOffset(COMPONENT_Cr) + pcSlice->getSliceChromaQpDelta(COMPONENT_Cr)) >  12, "Invalid chroma QP offset" );
-
-        READ_SVLC( iCode, "slice_cb_cr_qp_offset" );
-        pcSlice->setSliceChromaQpDelta(JOINT_CbCr, iCode );
-        CHECK( pcSlice->getSliceChromaQpDelta(JOINT_CbCr) < -12, "Invalid chroma QP offset" );
-        CHECK( pcSlice->getSliceChromaQpDelta(JOINT_CbCr) >  12, "Invalid chroma QP offset" );
-        CHECK( (pps->getQpOffset(JOINT_CbCr) + pcSlice->getSliceChromaQpDelta(JOINT_CbCr)) < -12, "Invalid chroma QP offset" );
-        CHECK( (pps->getQpOffset(JOINT_CbCr) + pcSlice->getSliceChromaQpDelta(JOINT_CbCr)) >  12, "Invalid chroma QP offset" );
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+        if (sps->getJointCbCrEnabledFlag())
+        {
+          READ_SVLC(iCode, "slice_joint_cbcr_qp_offset" );
+          pcSlice->setSliceChromaQpDelta(JOINT_CbCr, iCode);
+          CHECK( pcSlice->getSliceChromaQpDelta(JOINT_CbCr) < -12, "Invalid chroma QP offset");
+          CHECK( pcSlice->getSliceChromaQpDelta(JOINT_CbCr) >  12, "Invalid chroma QP offset");
+          CHECK( (pps->getQpOffset(JOINT_CbCr) + pcSlice->getSliceChromaQpDelta(JOINT_CbCr)) < -12, "Invalid chroma QP offset");
+          CHECK( (pps->getQpOffset(JOINT_CbCr) + pcSlice->getSliceChromaQpDelta(JOINT_CbCr)) >  12, "Invalid chroma QP offset");
+        }
+#else
+        READ_SVLC(iCode, "slice_joint_cbcr_qp_offset");
+        pcSlice->setSliceChromaQpDelta(JOINT_CbCr, iCode);
+        CHECK( pcSlice->getSliceChromaQpDelta(JOINT_CbCr) < -12, "Invalid chroma QP offset");
+        CHECK( pcSlice->getSliceChromaQpDelta(JOINT_CbCr) >  12, "Invalid chroma QP offset");
+        CHECK( (pps->getQpOffset(JOINT_CbCr) + pcSlice->getSliceChromaQpDelta(JOINT_CbCr)) < -12, "Invalid chroma QP offset");
+        CHECK( (pps->getQpOffset(JOINT_CbCr) + pcSlice->getSliceChromaQpDelta(JOINT_CbCr)) >  12, "Invalid chroma QP offset");
+#endif
       }
     }
 
@@ -2351,6 +2438,10 @@ void HLSyntaxReader::parseConstraintInfo(ConstraintInfo *cinfo)
   READ_FLAG(symbol, "no_partition_constraints_override_constraint_flag"); cinfo->setNoPartitionConstraintsOverrideConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol,  "no_sao_constraint_flag");                    cinfo->setNoSaoConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol,  "no_alf_constraint_flag");                    cinfo->setNoAlfConstraintFlag(symbol > 0 ? true : false);
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  READ_FLAG(symbol,  "no_joint_cbcr_constraint_flag");             cinfo->setNoJointCbCrConstraintFlag(symbol > 0 ? true : false);
+#endif
+
   READ_FLAG(symbol,  "no_pcm_constraint_flag");                    cinfo->setNoPcmConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol,  "no_ref_wraparound_constraint_flag");         cinfo->setNoRefWraparoundConstraintFlag(symbol > 0 ? true : false);
   READ_FLAG(symbol,  "no_temporal_mvp_constraint_flag");           cinfo->setNoTemporalMvpConstraintFlag(symbol > 0 ? true : false);
@@ -2816,6 +2907,9 @@ void HLSyntaxReader::alfFilter( AlfParam& alfParam, const bool isChroma )
 #else
       coeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] = alfGolombDecode( kMinTab[alfShape.golombIdx[i]] );
 #endif
+      CHECK( isChroma &&
+             ( coeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] > 127 || coeff[ind * MAX_NUM_ALF_LUMA_COEFF + i] < -127 )
+             , "AlfCoeffC shall be in the range of −127 to 127, inclusive" );
     }
   }
 
@@ -2859,6 +2953,8 @@ void HLSyntaxReader::alfFilter( AlfParam& alfParam, const bool isChroma )
         }
       }
 #endif
+      CHECK( std::any_of( recCoeff,  recCoeff + numFilters * MAX_NUM_ALF_LUMA_COEFF, [](short c) {return (c <-128 || c > 127);} )
+             , "AlfCoeffL shall be in the range of −128 to 127, inclusive" );
     }
 #endif
 
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 71755be775f6768021b9744de9acb46d3e39897a..d6b0d3ad2cf356cb0f4350f59dec0012b92f81a9 100755
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -1103,7 +1103,11 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu )
         break;
       }
     }
+#if JVET_O0502_ISP_CLEANUP
+    if ( pu->multiRefIdx )
+#else
     if( pu->multiRefIdx || ( cu.ispMode && isLuma( cu.chType ) ) )
+#endif
     {
       CHECK(mpm_idx >= numMPMs, "use of non-MPM");
     }
@@ -1203,7 +1207,11 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu )
       break;
     }
   }
+#if JVET_O0502_ISP_CLEANUP
+  if ( pu.multiRefIdx )
+#else
   if( pu.multiRefIdx || ( pu.cu->ispMode && isLuma( pu.cu->chType ) ) )
+#endif
   {
     CHECK(mpm_idx >= numMPMs, "use of non-MPM");
   }
@@ -1429,9 +1437,7 @@ void CABACWriter::cu_residual( const CodingUnit& cu, Partitioner& partitioner, C
   cuCtx.violatesLfnstConstrained[CHANNEL_TYPE_CHROMA] = false;
 #endif
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-  cuCtx.lastScanPos[COMPONENT_Y ] = -1;
-  cuCtx.lastScanPos[COMPONENT_Cb] = -1;
-  cuCtx.lastScanPos[COMPONENT_Cr] = -1;
+  cuCtx.lfnstLastScanPos = false;
 #endif
 
 #if !JVET_O0596_CBF_SIG_ALIGN_TO_SPEC
@@ -2191,7 +2197,7 @@ void CABACWriter::merge_data(const PredictionUnit& pu)
     merge_idx(pu);
     return;
   }
-  const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB();
+  const bool triangleAvailable = pu.cu->cs->slice->getSPS()->getUseTriangle() && pu.cu->cs->slice->isInterB() && pu.cu->cs->slice->getMaxNumTriangleCand() > 1;
   const bool ciipAvailable = pu.cs->sps->getUseMHIntra() && !pu.cu->skip && pu.cu->lwidth() < MAX_CU_SIZE && pu.cu->lheight() < MAX_CU_SIZE;
   if (pu.cu->lwidth() * pu.cu->lheight() >= 64
     && (triangleAvailable || ciipAvailable))
@@ -2368,7 +2374,15 @@ void CABACWriter::merge_idx( const PredictionUnit& pu )
       encodeOneIdx(candIdx1, maxNumTriangleCand - 2);
       return;
     }
-  int numCandminus1 = int( pu.cs->slice->getMaxNumMergeCand() ) - 1;
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+    int numCandminus1;
+    if (pu.cu->predMode == MODE_IBC)
+      numCandminus1 = int(pu.cs->slice->getMaxNumIBCMergeCand()) - 1;
+    else
+      numCandminus1 = int(pu.cs->slice->getMaxNumMergeCand()) - 1;
+#else
+    int numCandminus1 = int(pu.cs->slice->getMaxNumMergeCand()) - 1;
+#endif
   if( numCandminus1 > 0 )
   {
     if( pu.mergeIdx == 0 )
@@ -3117,6 +3131,13 @@ void CABACWriter::cu_chroma_qp_offset( const CodingUnit& cu )
 #if JVET_O0105_ICT
 void CABACWriter::joint_cb_cr( const TransformUnit& tu, const int cbfMask )
 {
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  if ( !tu.cu->slice->getSPS()->getJointCbCrEnabledFlag() )
+  {
+    return;
+  }
+#endif
+
   CHECK( tu.jointCbCr && tu.jointCbCr != cbfMask, "wrong value of jointCbCr (" << (int)tu.jointCbCr << " vs " << (int)cbfMask << ")" );
 #if JVET_O0543_ICT_ICU_ONLY
   if( ( CU::isIntra( *tu.cu ) && cbfMask ) || ( cbfMask == 3 ) )
@@ -3209,7 +3230,8 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID)
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
   if( cuCtx && tu.mtsIdx != MTS_SKIP && tu.blocks[ compID ].height >= 4 && tu.blocks[ compID ].width >= 4 )
   {
-    cuCtx->lastScanPos[compID] = cctx.scanPosLast();
+    const int lfnstLastScanPosTh = isLuma( compID ) ? LFNST_LAST_SIG_LUMA : LFNST_LAST_SIG_CHROMA;
+    cuCtx->lfnstLastScanPos |= cctx.scanPosLast() >= lfnstLastScanPosTh;
   }
 #endif
   // code last coeff position
@@ -3370,11 +3392,7 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
 #else
           bool nonZeroCoeffNonTsCorner8x8 = CU::getNumNonZeroCoeffNonTsCorner8x8( cu, lumaFlag, chromaFlag ) > 0;
 #endif
-#if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-    const bool skipLfnst                  = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA ) :
-                                          ( cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ) ) :
-                                          ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA && cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA );
-#else
+#if !JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
     const int  nonZeroCoeffThr            = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? LFNST_SIG_NZ_LUMA : LFNST_SIG_NZ_CHROMA ) : LFNST_SIG_NZ_LUMA + LFNST_SIG_NZ_CHROMA;
     cuCtx.numNonZeroCoeffNonTs            = CU::getNumNonZeroCoeffNonTs( cu, lumaFlag, chromaFlag );
     nonZeroCoeffNonTs                     = cuCtx.numNonZeroCoeffNonTs > nonZeroCoeffThr;
@@ -3382,13 +3400,13 @@ void CABACWriter::residual_lfnst_mode( const CodingUnit& cu, CUCtx& cuCtx )
 #if JVET_O0368_LFNST_WITH_DCT2_ONLY
     const bool isNonDCT2 = (TU::getCbf(*cu.firstTU, ComponentID(COMPONENT_Y)) && cu.firstTU->mtsIdx != MTS_DCT2_DCT2);
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-    if( skipLfnst || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
+    if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
 #else
     if (!nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 || isNonDCT2 )
 #endif
 #else
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-    if( skipLfnst || nonZeroCoeffNonTsCorner8x8 )
+    if( !cuCtx.lfnstLastScanPos || nonZeroCoeffNonTsCorner8x8 )
 #else
     if( !nonZeroCoeffNonTs || nonZeroCoeffNonTsCorner8x8 )
 #endif
diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp
index 488b2d768ebc2ee332267273885ca9adad089851..a3c85e561c39afd65f859d1c686060d30ed4b4ab 100644
--- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp
+++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp
@@ -501,7 +501,11 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co
     m_diffFilterCoeff[i] = new int[MAX_NUM_ALF_LUMA_COEFF];
   }
 
+#if JVET_O_MAX_NUM_ALF_APS_8
+  m_apsIdStart = ALF_CTB_MAX_NUM_APS;
+#else
   m_apsIdStart = (int)MAX_NUM_APS;
+#endif
   m_ctbDistortionFixedFilter = new double[m_numCTUsInPic];
   for (int comp = 0; comp < MAX_NUM_COMPONENT; comp++)
   {
@@ -654,10 +658,19 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda
 {
   if (cs.slice->getPendingRasInit() || cs.slice->isIDRorBLA())
   {
+#if JVET_O_MAX_NUM_ALF_APS_8
+    memset(cs.slice->getAlfAPSs(), 0, sizeof(*cs.slice->getAlfAPSs())*ALF_CTB_MAX_NUM_APS);
+    m_apsIdStart = ALF_CTB_MAX_NUM_APS;
+#else
     memset(cs.slice->getAlfAPSs(), 0, sizeof(*cs.slice->getAlfAPSs())*MAX_NUM_APS);
     m_apsIdStart = (int)MAX_NUM_APS;
+#endif
     m_apsMap->clear();
+#if JVET_O_MAX_NUM_ALF_APS_8
+    for (int i = 0; i < ALF_CTB_MAX_NUM_APS; i++)
+#else
     for (int i = 0; i < MAX_NUM_APS; i++)
+#endif
     {
       APS* alfAPS = m_apsMap->getPS((i << NUM_APS_TYPE_LEN) + ALF_APS);
       m_apsMap->clearChangedFlag((i << NUM_APS_TYPE_LEN) + ALF_APS);
@@ -2966,16 +2979,28 @@ void EncAdaptiveLoopFilter::setCtuEnableFlag( uint8_t** ctuFlags, ChannelType ch
 std::vector<int> EncAdaptiveLoopFilter::getAvaiApsIdsLuma(CodingStructure& cs, int &newApsId)
 {
   APS** apss = cs.slice->getAlfAPSs();
+#if JVET_O_MAX_NUM_ALF_APS_8
+  for (int i = 0; i < ALF_CTB_MAX_NUM_APS; i++)
+#else
   for (int i = 0; i < MAX_NUM_APS; i++)
+#endif
   {
     apss[i] = m_apsMap->getPS((i << NUM_APS_TYPE_LEN) + ALF_APS);
   }
 
   std::vector<int> result;
   int apsIdChecked = 0, curApsId = m_apsIdStart;
+#if JVET_O_MAX_NUM_ALF_APS_8
+  if (curApsId < ALF_CTB_MAX_NUM_APS)
+#else
   if (curApsId < int(MAX_NUM_APS))
+#endif
   {
+#if JVET_O_MAX_NUM_ALF_APS_8
+    while (apsIdChecked < ALF_CTB_MAX_NUM_APS && !cs.slice->isIntra() && result.size() < ALF_CTB_MAX_NUM_APS && !cs.slice->getPendingRasInit() && !cs.slice->isIDRorBLA())
+#else
     while (apsIdChecked < MAX_NUM_APS && !cs.slice->isIntra() && result.size() < (ALF_CTB_MAX_NUM_APS - 1) && !cs.slice->getPendingRasInit() && !cs.slice->isIDRorBLA())
+#endif
     {
       APS* curAPS = cs.slice->getAlfAPSs()[curApsId];
       if (curAPS && curAPS->getTemporalId() <= cs.slice->getTLayer() && curAPS->getAlfAPSParam().newFilterFlag[CHANNEL_TYPE_LUMA])
@@ -2983,7 +3008,11 @@ std::vector<int> EncAdaptiveLoopFilter::getAvaiApsIdsLuma(CodingStructure& cs, i
         result.push_back(curApsId);
       }
       apsIdChecked++;
+#if JVET_O_MAX_NUM_ALF_APS_8
+      curApsId = (curApsId + 1) % ALF_CTB_MAX_NUM_APS;
+#else
       curApsId = (curApsId + 1) % MAX_NUM_APS;
+#endif
     }
   }
   cs.slice->setTileGroupNumAps((int)result.size());
@@ -2991,10 +3020,17 @@ std::vector<int> EncAdaptiveLoopFilter::getAvaiApsIdsLuma(CodingStructure& cs, i
   newApsId = m_apsIdStart - 1;
   if (newApsId < 0)
   {
+#if JVET_O_MAX_NUM_ALF_APS_8
+    newApsId = ALF_CTB_MAX_NUM_APS - 1;
+#else
     newApsId = (int)MAX_NUM_APS - 1;
+#endif
   }
-
+#if JVET_O_MAX_NUM_ALF_APS_8
+  CHECK(newApsId >= ALF_CTB_MAX_NUM_APS, "Wrong APS index assignment in getAvaiApsIdsLuma");
+#else
   CHECK(newApsId >= (int)MAX_NUM_APS, "Wrong APS index assignment in getAvaiApsIdsLuma");
+#endif
   return result;
 }
 void  EncAdaptiveLoopFilter::initDistortion()
@@ -3062,6 +3098,12 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
     int numIter = useNewFilter ? 2 : 1;
     for (int numTemporalAps = 0; numTemporalAps <= apsIds.size(); numTemporalAps++)
     {
+#if JVET_O_MAX_NUM_ALF_APS_8
+      if (numTemporalAps + useNewFilter >= ALF_CTB_MAX_NUM_APS)
+      {
+        continue;
+      }
+#endif
       cs.slice->setTileGroupNumAps(numTemporalAps + useNewFilter);
       int numFilterSet = NUM_FIXED_FILTER_SETS + numTemporalAps + useNewFilter;
       if (numTemporalAps == apsIds.size() && numTemporalAps > 0 && useNewFilter && newApsId == apsIds.back()) //last temporalAPS is occupied by new filter set and this temporal APS becomes unavailable
@@ -3072,7 +3114,11 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
       {
         m_alfParamTemp = alfParamNewFilters;
         m_alfParamTemp.enabledFlag[CHANNEL_TYPE_LUMA] = true;
+#if JVET_O_MAX_NUM_ALF_APS_8
+        double curCost = 3 * m_lambda[CHANNEL_TYPE_LUMA];
+#else
         double curCost = getTBlength(numTemporalAps + useNewFilter, ALF_CTB_MAX_NUM_APS + 1) * m_lambda[CHANNEL_TYPE_LUMA];
+#endif
         if (iter > 0)  //re-derive new filter-set
         {
           double dDistOrgNewFilter = 0;
@@ -3232,9 +3278,17 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
           }
         } //for(ctbIdx)
 #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL
+#if JVET_O_MAX_NUM_ALF_APS_8
+        int tmpBits = bitsNewFilter + 3 * (numFilterSet - NUM_FIXED_FILTER_SETS);
+#else
         int tmpBits = bitsNewFilter + 5 * (numFilterSet - NUM_FIXED_FILTER_SETS) + getTBlength(numFilterSet - NUM_FIXED_FILTER_SETS, ALF_CTB_MAX_NUM_APS + 1);
+#endif
+#else
+#if JVET_O_MAX_NUM_ALF_APS_8
+        int tmpBits = bitsNewFilter + 3 * (numFilterSet - NUM_FIXED_FILTER_SETS) + (cs.slice->isIntra() ? 1 : 3);
 #else
         int tmpBits = bitsNewFilter + 5 * (numFilterSet - NUM_FIXED_FILTER_SETS) + (cs.slice->isIntra() ? 1 : getTBlength(numFilterSet - NUM_FIXED_FILTER_SETS, ALF_CTB_MAX_NUM_APS + 1));
+#endif
 #endif
         curCost += tmpBits * m_lambda[COMPONENT_Y];
         if (curCost < costMin)
@@ -3334,7 +3388,11 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
       curId--;
       if (curId < 0)
       {
+#if JVET_O_MAX_NUM_ALF_APS_8
+        curId = ALF_CTB_MAX_NUM_APS - 1;
+#else
         curId = (int)MAX_NUM_APS - 1;
+#endif
       }
       if (std::find(bestApsIds.begin(), bestApsIds.end(), curId) == bestApsIds.end())
       {
@@ -3342,7 +3400,11 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
       }
     }
   }
+#if JVET_O_MAX_NUM_ALF_APS_8
+  for (int curApsId = 0; curApsId < ALF_CTB_MAX_NUM_APS; curApsId++)
+#else
   for (int curApsId = 0; curApsId < MAX_NUM_APS; curApsId++)
+#endif
   {
     if ((cs.slice->getPendingRasInit() || cs.slice->isIDRorBLA() || cs.slice->isIntra()) && curApsId != newApsIdChroma)
     {
@@ -3350,9 +3412,17 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
     }
     APS* curAPS = m_apsMap->getPS((curApsId << NUM_APS_TYPE_LEN) + ALF_APS);
 #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL
+#if JVET_O_MAX_NUM_ALF_APS_8
+    double curCost = m_lambda[CHANNEL_TYPE_CHROMA] * 3;
+#else
     double curCost = m_lambda[CHANNEL_TYPE_CHROMA] * 5;
+#endif
+#else
+#if JVET_O_MAX_NUM_ALF_APS_8
+    double curCost = (cs.slice->isIntra() && cs.slice->getTileGroupNumAps() == 1) ? 0 : (m_lambda[CHANNEL_TYPE_CHROMA] * 3);
 #else
     double curCost = (cs.slice->isIntra() && cs.slice->getTileGroupNumAps() == 1) ? 0 : (m_lambda[CHANNEL_TYPE_CHROMA] * 5);
+#endif
 #endif
     if (curApsId == newApsIdChroma)
     {
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index 924e81feca44cb0ccbe826eec85c3e054fac51fd..03d0d061258b58838dcdf60b04d67c7932b6bbfa 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -204,6 +204,9 @@ protected:
   bool      m_noTransformSkipConstraintFlag;
 #if JVET_O1136_TS_BDPCM_SIGNALLING
   bool      m_noBDPCMConstraintFlag;
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool      m_noJointCbCrConstraintFlag;
 #endif
   bool      m_bNoQpDeltaConstraintFlag;
   bool      m_bNoDepQuantConstraintFlag;
@@ -239,6 +242,9 @@ protected:
   int       m_numReorderPics[MAX_TLAYER];
 
   int       m_iQP;                              //  if (AdaptiveQP == OFF)
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  ChromaQpMappingTableParams m_chromaQpMappingTableParams;
+#endif
 #if X0038_LAMBDA_FROM_QP_CAPABILITY
   int       m_intraQPOffset;                    ///< QP offset for intra slice (integer)
   int       m_lambdaFromQPEnable;               ///< enable lambda derivation from QP
@@ -304,6 +310,9 @@ protected:
   bool      m_RdpcmMode;
 #if JVET_O0119_BASE_PALETTE_444
   unsigned  m_PLTMode;
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool      m_JointCbCrMode;
 #endif
   unsigned  m_IBCMode;
   unsigned  m_IBCLocalSearchRangeX;
@@ -562,6 +571,9 @@ protected:
   uint32_t      m_maxNumMergeCand;                    ///< Maximum number of merge candidates
   uint32_t      m_maxNumAffineMergeCand;              ///< Maximum number of affine merge candidates
   uint32_t      m_maxNumTriangleCand;
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  uint32_t      m_maxNumIBCMergeCand;                 ///< Max number of IBC merge candidates
+#endif
   ScalingListMode m_useScalingListId;             ///< Using quantization matrix i.e. 0=off, 1=default, 2=file.
   std::string m_scalingListFileName;              ///< quantization matrix file name
   int       m_TMVPModeId;
@@ -712,6 +724,10 @@ public:
 #if JVET_O1136_TS_BDPCM_SIGNALLING
   bool      getNoBDPCMConstraintFlag() const { return m_noBDPCMConstraintFlag; }
   void      setNoBDPCMConstraintFlag(bool bVal) { m_noBDPCMConstraintFlag = bVal; }
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool      getNoJointCbCrConstraintFlag() const { return m_noJointCbCrConstraintFlag; }
+  void      setNoJointCbCrConstraintFlag(bool bVal) { m_noJointCbCrConstraintFlag = bVal; }
 #endif
   bool      getNoQpDeltaConstraintFlag() const { return m_bNoQpDeltaConstraintFlag; }
   void      setNoQpDeltaConstraintFlag(bool bVal) { m_bNoQpDeltaConstraintFlag = bVal; }
@@ -784,6 +800,10 @@ public:
   void      setIntraQPOffset                ( int   i )         { m_intraQPOffset = i; }
   void      setLambdaFromQPEnable           ( bool  b )         { m_lambdaFromQPEnable = b; }
 #endif
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  void      setChromaQpMappingTableParams   (const ChromaQpMappingTableParams &params) { m_chromaQpMappingTableParams = params; }
+#endif
+
   void      setPad                          ( int*  iPad                   )      { for ( int i = 0; i < 2; i++ ) m_aiPad[i] = iPad[i]; }
 
   int       getMaxRefPicNum                 ()                              { return m_iMaxRefPicNum;           }
@@ -886,6 +906,10 @@ public:
 #if JVET_O0119_BASE_PALETTE_444
   void      setPLTMode                   ( unsigned n)    { m_PLTMode = n; }
   unsigned  getPLTMode                   ()         const { return m_PLTMode; }
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  void      setJointCbCr                    ( bool b )       { m_JointCbCrMode = b; }
+  bool      getJointCbCr                    ()         const { return m_JointCbCrMode; }
 #endif
   void      setIBCMode                      (unsigned n)     { m_IBCMode = n; }
   unsigned  getIBCMode                      ()         const { return m_IBCMode; }
@@ -1174,6 +1198,10 @@ public:
 #if JVET_O1136_TS_BDPCM_SIGNALLING
   bool getUseBDPCM                                     ()         { return m_useBDPCM; }
   void setUseBDPCM                                     ( bool b ) { m_useBDPCM  = b;   }
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  bool getUseJointCbCr                                 ()         { return m_JointCbCrMode; }
+  void setUseJointCbCr                                 (bool b)   { m_JointCbCrMode = b; }
 #endif
   bool getPersistentRiceAdaptationEnabledFlag          ()                 const { return m_persistentRiceAdaptationEnabledFlag;  }
   void setPersistentRiceAdaptationEnabledFlag          (const bool value)       { m_persistentRiceAdaptationEnabledFlag = value; }
@@ -1416,6 +1444,10 @@ public:
   uint32_t     getMaxNumAffineMergeCand          ()                  { return m_maxNumAffineMergeCand; }
   void         setMaxNumTriangleCand             ( uint32_t u )      { m_maxNumTriangleCand = u;    }
   uint32_t     getMaxNumTriangleCand             ()                  { return m_maxNumTriangleCand; }
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  void         setMaxNumIBCMergeCand             ( uint32_t u )      { m_maxNumIBCMergeCand = u; }
+  uint32_t     getMaxNumIBCMergeCand             ()                  { return m_maxNumIBCMergeCand; }
+#endif
   void         setUseScalingListId    ( ScalingListMode u )          { m_useScalingListId       = u;   }
   ScalingListMode getUseScalingListId    ()                          { return m_useScalingListId;      }
   void         setScalingListFileName       ( const std::string &s ) { m_scalingListFileName = s;      }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 3304b3e5f1ee226fece3774478ac5e9d8faee9dc..a9f27ffd47693410f4a834034c8a4a4977b86464 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -574,8 +574,15 @@ bool EncCu::xCheckBestMode( CodingStructure *&tempCS, CodingStructure *&bestCS,
 
 }
 
+#if JVET_O0502_ISP_CLEANUP
+void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& partitioner, double maxCostAllowed )
+#else
 void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner )
+#endif
 {
+#if JVET_O0502_ISP_CLEANUP
+  CHECK(maxCostAllowed < 0, "Wrong value of maxCostAllowed!");
+#endif
   if (m_shareState == NO_SHARE)
   {
     tempCS->sharedBndPos = tempCS->area.Y().lumaPos();
@@ -706,6 +713,9 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
   }
 #endif
     EncTestMode currTestMode = m_modeCtrl->currTestMode();
+#if JVET_O0502_ISP_CLEANUP
+    currTestMode.maxCostAllowed = maxCostAllowed;
+#endif
 
     if (pps.getUseDQP() && CS::isDualITree(*tempCS) && isChroma(partitioner.chType))
     {
@@ -1355,7 +1365,13 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
 #if JVET_O0070_PROF
       tempSubCS->bestParent = bestSubCS->bestParent = bestCS;
 #endif
+#if JVET_O0502_ISP_CLEANUP
+      double newMaxCostAllowed = isLuma(partitioner.chType) ? std::min(encTestMode.maxCostAllowed, bestCS->cost - m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist)) : MAX_DOUBLE;
+      newMaxCostAllowed = std::max(0.0, newMaxCostAllowed);
+      xCompressCU(tempSubCS, bestSubCS, partitioner, newMaxCostAllowed);
+#else
       xCompressCU( tempSubCS, bestSubCS, partitioner );
+#endif
 #if JVET_O0070_PROF
       tempSubCS->bestParent = bestSubCS->bestParent = nullptr;
 #endif
@@ -1577,8 +1593,17 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
           bool validCandRet = false;
           if( isLuma( partitioner.chType ) )
           {
+#if JVET_O0502_ISP_CLEANUP
+            //ISP uses the value of the best cost so far (luma if it is the fast version) to avoid test non-necessary subpartitions
+            double bestCostSoFar = CS::isDualITree(*tempCS) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost;
+            if (CS::isDualITree(*tempCS) && encTestMode.maxCostAllowed < bestCostSoFar)
+            {
+              bestCostSoFar = encTestMode.maxCostAllowed;
+            }
+#else
             //the Intra SubPartitions mode uses the value of the best cost so far (luma if it is the fast version) to avoid test non-necessary lines
             const double bestCostSoFar = CS::isDualITree( *tempCS ) ? m_modeCtrl->getBestCostWithoutSplitFlags() : bestCU && bestCU->predMode == MODE_INTRA ? bestCS->lumaCost : bestCS->cost;
+#endif
             validCandRet = m_pcIntraSearch->estIntraPredLumaQT( cu, partitioner, bestCostSoFar, mtsFlag, startMTSIdx[ trGrpIdx ], endMTSIdx[ trGrpIdx ], ( trGrpIdx > 0 ) );
             if( sps.getUseLFNST() && ( !validCandRet || ( cu.ispMode && cu.firstTU->cbf[ COMPONENT_Y ] == 0 ) ) )
             {
@@ -1667,12 +1692,10 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
 
           // Check if low frequency non-separable transform (LFNST) is too expensive
 #if JVET_O0472_LFNST_SIGNALLING_LAST_SCAN_POS
-          const bool skipLfnst = CS::isDualITree( *cu.cs ) ? ( isLuma( cu.chType ) ? ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA ) :
-                              ( cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA ) ) :
-                              ( cuCtx.lastScanPos[ COMPONENT_Y ] < LFNST_LAST_SIG_LUMA && cuCtx.lastScanPos[ COMPONENT_Cb ] < LFNST_LAST_SIG_CHROMA && cuCtx.lastScanPos[ COMPONENT_Cr ] < LFNST_LAST_SIG_CHROMA );
-          if( lfnstIdx && skipLfnst )
+          if( lfnstIdx && !cuCtx.lfnstLastScanPos )
           {
-            if( cuCtx.lastScanPos[ COMPONENT_Y ] > -1 || cuCtx.lastScanPos[ COMPONENT_Cb ] > -1 || cuCtx.lastScanPos[ COMPONENT_Cr ] > -1 )
+            bool cbfAtZeroDepth = CS::isDualITree( *tempCS ) ? cu.rootCbf : std::min( cu.firstTU->blocks[ 1 ].width, cu.firstTU->blocks[ 1 ].height ) < 4 ? TU::getCbfAtDepth( *cu.firstTU, COMPONENT_Y, 0 ) : cu.rootCbf;
+            if( cbfAtZeroDepth )
             {
               tempCS->cost = MAX_DOUBLE;
             }
@@ -1739,13 +1762,22 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
               }
             }
 
+#if JVET_O0502_ISP_CLEANUP
+            //we decide to skip the non-DCT-II transforms and LFNST according to the ISP results
+            if ((endMtsFlag > 0 || endLfnstIdx > 0) && cu.ispMode && !mtsFlag && !lfnstIdx && tempCS->slice->isIntra() && m_pcEncCfg->getUseFastISP())
+#else
             //we decide to skip the second emt pass or not according to the ISP results
             if( considerMtsSecondPass && cu.ispMode && !mtsFlag && tempCS->slice->isIntra() )
+#endif
             {
               double bestCostDct2NoIsp = m_modeCtrl->getMtsFirstPassNoIspCost();
               CHECKD( bestCostDct2NoIsp <= bestIspCost, "wrong cost!" );
+#if JVET_O0502_ISP_CLEANUP
+              double threshold = 1.4;
+#else
               double nSamples  = ( double ) ( cu.lwidth() << g_aucLog2[ cu.lheight() ] );
               double threshold = 1 + 1.4 / sqrt( nSamples );
+#endif
 
               double lfnstThreshold = 1.01 * threshold;
               if( bestCostDct2NoIsp > bestIspCost*lfnstThreshold )
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 29912cc07a8663ce88707bac9130466cbfeabfaa..82bc30422d8ee48587975dc213a98e57757633fd 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -175,7 +175,11 @@ protected:
   void xCalDebCost            ( CodingStructure &cs, Partitioner &partitioner, bool calDist = false );
   Distortion getDistortionDb  ( CodingStructure &cs, CPelBuf org, CPelBuf reco, ComponentID compID, const CompArea& compArea, bool afterDb );
 
+#if JVET_O0502_ISP_CLEANUP
+  void xCompressCU            ( CodingStructure*& tempCS, CodingStructure*& bestCS, Partitioner& pm, double maxCostAllowed = MAX_DOUBLE );
+#else
   void xCompressCU            ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm );
+#endif
 #if ENABLE_SPLIT_PARALLELISM
   void xCompressCUParallel    ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm );
   void copyState              ( EncCu* other, Partitioner& pm, const UnitArea& currArea, const bool isDist );
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index c348ae0e23623207e95894ef085a82df0ac29ec8..d710ec005e9c74873396b22f2f4171b61aa0bf0f 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -2092,7 +2092,14 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
       // overwrite chroma qp offset for dual tree
       pcSlice->setSliceChromaQpDelta(COMPONENT_Cb, m_pcCfg->getChromaCbQpOffsetDualTree());
       pcSlice->setSliceChromaQpDelta(COMPONENT_Cr, m_pcCfg->getChromaCrQpOffsetDualTree());
-      pcSlice->setSliceChromaQpDelta(JOINT_CbCr,   m_pcCfg->getChromaCbCrQpOffsetDualTree());
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+      if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
+      {
+        pcSlice->setSliceChromaQpDelta(JOINT_CbCr, m_pcCfg->getChromaCbCrQpOffsetDualTree());
+      }
+#else
+      pcSlice->setSliceChromaQpDelta(JOINT_CbCr, m_pcCfg->getChromaCbCrQpOffsetDualTree());
+#endif
       m_pcSliceEncoder->setUpLambda(pcSlice, pcSlice->getLambdas()[0], pcSlice->getSliceQp());
     }
     if (pcSlice->getSPS()->getUseReshaper())
@@ -2494,7 +2501,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
 
       if (pcSlice->getSPS()->getALFEnabledFlag() && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
       {
+#if JVET_O_MAX_NUM_ALF_APS_8
+        for (int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++)
+#else
         for (int apsId = 0; apsId < MAX_NUM_APS; apsId++)   //HD: shouldn't this be looping over slice_alf_aps_id_luma[ i ]? By looping over MAX_NUM_APS, it is possible unused ALF APS is written. Please check!
+#endif
         {
           ParameterSetMap<APS> *apsMap = m_pcEncLib->getApsMap();
 
@@ -3410,6 +3421,18 @@ void EncGOP::xCalculateAddPSNR(Picture* pcPic, PelUnitBuf cPicD, const AccessUni
     if (useLumaWPSNR)
     {
       msg(NOTICE, " [WY %6.4lf dB    WU %6.4lf dB    WV %6.4lf dB]", dPSNRWeighted[COMPONENT_Y], dPSNRWeighted[COMPONENT_Cb], dPSNRWeighted[COMPONENT_Cr]);
+
+      if (m_pcEncLib->getPrintHexPsnr())
+      {
+        uint64_t xPsnrWeighted[MAX_NUM_COMPONENT];
+        for (int i = 0; i < MAX_NUM_COMPONENT; i++)
+        {
+          copy(reinterpret_cast<uint8_t *>(&dPSNRWeighted[i]),
+               reinterpret_cast<uint8_t *>(&dPSNRWeighted[i]) + sizeof(dPSNRWeighted[i]),
+               reinterpret_cast<uint8_t *>(&xPsnrWeighted[i]));
+        }
+        msg(NOTICE, " [xWY %16" PRIx64 " xWU %16" PRIx64 " xWV %16" PRIx64 "]", xPsnrWeighted[COMPONENT_Y], xPsnrWeighted[COMPONENT_Cb], xPsnrWeighted[COMPONENT_Cr]);
+      }
     }
 #endif
     msg( NOTICE, " [ET %5.0f ]", dEncTime );
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index c3fc09a16e01cd7a5b4e35779658396a1fc81bf4..daca183e0847f7c4fdb8d19e513339d9a697d83f 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -872,6 +872,9 @@ void EncLib::xInitSPS(SPS &sps)
   cinfo->setNoTransformSkipConstraintFlag(m_noTransformSkipConstraintFlag);
 #if JVET_O1136_TS_BDPCM_SIGNALLING
   cinfo->setNoBDPCMConstraintFlag(m_noBDPCMConstraintFlag);
+#endif
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  cinfo->setNoJointCbCrConstraintFlag(m_noJointCbCrConstraintFlag);
 #endif
   cinfo->setNoQpDeltaConstraintFlag(m_bNoQpDeltaConstraintFlag);
   cinfo->setNoDepQuantConstraintFlag(m_bNoDepQuantConstraintFlag);
@@ -1000,7 +1003,9 @@ void EncLib::xInitSPS(SPS &sps)
 #endif
 
   sps.setSAOEnabledFlag( m_bUseSAO );
-
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  sps.setJointCbCrEnabledFlag( m_JointCbCrMode );
+#endif
   sps.setMaxTLayers( m_maxTempLayer );
   sps.setTemporalIdNestingFlag( ( m_maxTempLayer == 1 ) ? true : false );
 
@@ -1044,6 +1049,10 @@ void EncLib::xInitSPS(SPS &sps)
     sps.setLtRefPicPocLsbSps(k, 0);
     sps.setUsedByCurrPicLtSPSFlag(k, 0);
   }
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  sps.setChromaQpMappingTableFromParams(m_chromaQpMappingTableParams, sps.getQpBDOffset(CHANNEL_TYPE_CHROMA));
+  sps.derivedChromaQPMappingTables();
+#endif
 
 #if U0132_TARGET_BITS_SATURATION
   if( getPictureTimingSEIEnabled() || getDecodingUnitInfoSEIEnabled() || getCpbSaturationEnabled() )
diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h
index 4b50555b0d2240d3b7e0038e098b02a5f47f7620..09eaa50d4d436359042ec64f3002938493a4b37f 100644
--- a/source/Lib/EncoderLib/EncLib.h
+++ b/source/Lib/EncoderLib/EncLib.h
@@ -138,7 +138,11 @@ private:
   CacheModel                m_cacheModel;
 #endif
 
+#if JVET_O_MAX_NUM_ALF_APS_8
+  APS*                      m_apss[ALF_CTB_MAX_NUM_APS];
+#else
   APS*                      m_apss[MAX_NUM_APS];
+#endif
 
   APS*                      m_lmcsAPS;
 
diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h
index 3360e87681f649a08d37e3eb0d9910e612012047..9cb8ce809b41cccbdb8eab23ed1bf5733b8ca22a 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.h
+++ b/source/Lib/EncoderLib/EncModeCtrl.h
@@ -115,6 +115,9 @@ struct EncTestMode
   EncTestModeOpts opts;
   int             qp;
   bool            lossless;
+#if JVET_O0502_ISP_CLEANUP
+  double          maxCostAllowed;
+#endif
 };
 
 
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index c49ab3ea3fc9abcfecf4d22b5291cff9aa5b3e6f..349701bfa8041e81b363c87646fd66648e0b5797 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -117,7 +117,11 @@ EncSlice::setUpLambda( Slice* slice, const double dLambda, int iQP)
   {
     const ComponentID compID = ComponentID( compIdx );
     int chromaQPOffset       = slice->getPPS()->getQpOffset( compID ) + slice->getSliceChromaQpDelta( compID );
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+    int qpc = slice->getSPS()->getMappedChromaQpValue(compID, iQP) + chromaQPOffset;
+#else
     int qpc                  = ( iQP + chromaQPOffset < 0 ) ? iQP : getScaledChromaQP( iQP + chromaQPOffset, m_pcCfg->getChromaFormatIdc() );
+#endif
     double tmpWeight         = pow( 2.0, ( iQP - qpc ) / 3.0 );  // takes into account of the chroma qp mapping and chroma qp Offset
     if( m_pcCfg->getDepQuantEnabledFlag() && !( m_pcCfg->getLFNST() ) )
     {
@@ -296,7 +300,11 @@ static int applyQPAdaptationChroma (Picture* const pcPic, Slice* const pcSlice,
         savedLumaQP = averageAdaptedLumaQP;
       } // savedLumaQP < 0
 
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+      const int lumaChromaMappingDQP = savedLumaQP - pcSlice->getSPS()->getMappedChromaQpValue(compID, savedLumaQP);
+#else
       const int lumaChromaMappingDQP = savedLumaQP - getScaledChromaQP (savedLumaQP, pcEncCfg->getChromaFormatIdc());
+#endif
 
       optSliceChromaQpOffset[comp-1] = std::min (3 + lumaChromaMappingDQP, adaptChromaQPOffset + lumaChromaMappingDQP);
     }
@@ -715,6 +723,9 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr
   rpcSlice->setMaxNumMergeCand      ( m_pcCfg->getMaxNumMergeCand()      );
   rpcSlice->setMaxNumAffineMergeCand( m_pcCfg->getMaxNumAffineMergeCand() );
   rpcSlice->setMaxNumTriangleCand   ( m_pcCfg->getMaxNumTriangleCand() );
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+  rpcSlice->setMaxNumIBCMergeCand   ( m_pcCfg->getMaxNumIBCMergeCand() );
+#endif
   rpcSlice->setSplitConsOverrideFlag(false);
   rpcSlice->setMinQTSize( rpcSlice->getSPS()->getMinQTSize(eSliceType));
   rpcSlice->setMaxBTDepth( rpcSlice->isIntra() ? rpcSlice->getSPS()->getMaxBTDepthI() : rpcSlice->getSPS()->getMaxBTDepth() );
@@ -1571,7 +1582,14 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
   checkDisFracMmvd( pcPic, startCtuTsAddr, boundingCtuTsAddr );
 
 #if JVET_O0105_ICT
-  setJointCbCrModes( cs, Position(0, 0), cs.area.lumaSize() );
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
+  {
+    setJointCbCrModes(cs, Position(0, 0), cs.area.lumaSize());
+  }
+#else
+  setJointCbCrModes(cs, Position(0, 0), cs.area.lumaSize());
+#endif
 #endif
 
   // for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment)
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index aa185316bef82966e93cd0a1f7feed517fb2d049..c95bce6643f1a34ef114a6020d06881121a109cb 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -6889,10 +6889,18 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
             m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cRescale*cRescale));
           }
 #if JVET_O0105_ICT
-          if( isChroma( compID ) && tu.cu->cs->slice->getSliceQp() > 18 )
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+          if ( sps.getJointCbCrEnabledFlag() && isChroma( compID ) && ( tu.cu->cs->slice->getSliceQp() > 18 ) )
           {
             m_pcTrQuant->setLambda( 1.05 * m_pcTrQuant->getLambda() );
           }
+
+#else
+          if ( isChroma( compID ) && tu.cu->cs->slice->getSliceQp() > 18 )
+          {
+            m_pcTrQuant->setLambda( 1.05 * m_pcTrQuant->getLambda() );
+          }
+#endif
 #endif
           TCoeff     currAbsSum = 0;
           uint64_t   currCompFracBits = 0;
@@ -7093,9 +7101,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
     {
       const CompArea& cbArea = tu.blocks[COMPONENT_Cb];
       const CompArea& crArea = tu.blocks[COMPONENT_Cr];
-
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+      bool checkJointCbCr = (sps.getJointCbCrEnabledFlag()) && (!tu.noResidual) && (TU::getCbf(tu, COMPONENT_Cb) || TU::getCbf(tu, COMPONENT_Cr));
+#else
       bool checkJointCbCr = !tu.noResidual && (TU::getCbf(tu, COMPONENT_Cb) || TU::getCbf(tu, COMPONENT_Cr));
-
+#endif
 #if JVET_O0105_ICT
       const int channelBitDepth = sps.getBitDepth(toChannelType(COMPONENT_Cb));
       bool      reshape         = slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && slice.getLmcsChromaResidualScaleFlag()
@@ -7153,10 +7163,17 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
         const int    absIct = abs( TU::getICTMode(tu) );
         const double lfact  = ( absIct == 1 || absIct == 3 ? 0.8 : 0.5 );
         m_pcTrQuant->setLambda( lfact * m_pcTrQuant->getLambda() );
-        if( tu.cu->cs->slice->getSliceQp() > 18 )
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+        if ( checkJointCbCr && (tu.cu->cs->slice->getSliceQp() > 18))
+        {
+            m_pcTrQuant->setLambda( 1.05 * m_pcTrQuant->getLambda() );
+        }
+#else
+        if ( tu.cu->cs->slice->getSliceQp() > 18 )
         {
           m_pcTrQuant->setLambda( 1.05 * m_pcTrQuant->getLambda() );
         }
+#endif
 #else
         m_pcTrQuant->setLambda( 0.60 * m_pcTrQuant->getLambda() );
 #endif
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index cfc8e590066d9da4b79ecf65c9226634fadf33e5..84b60311982caf02c879ba19f0dff37c79308d58 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -324,6 +324,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
 #else
   bool testISP = sps.getUseISP() && cu.mtsFlag == 0 && cu.lfnstIdx == 0 && CU::canUseISP( width, height, MAX_TB_SIZEY );
 #endif
+#if !JVET_O0502_ISP_CLEANUP
   bool ispHorIsFirstTest = testISP ? CU::firstTestISPHorSplit( width, height, COMPONENT_Y, nullptr, nullptr ) : true;
   int ispOptions[] = { NOT_INTRA_SUBPARTITIONS, HOR_INTRA_SUBPARTITIONS, VER_INTRA_SUBPARTITIONS };
   if ( !ispHorIsFirstTest )
@@ -331,8 +332,19 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
     ispOptions[1] = VER_INTRA_SUBPARTITIONS;
     ispOptions[2] = HOR_INTRA_SUBPARTITIONS;
   }
+#endif
   if( testISP )
   {
+#if JVET_O0502_ISP_CLEANUP
+    //reset the variables used for the tests
+    m_ispCandListHor.clear();
+    m_ispCandListVer.clear();
+    m_regIntraRDListWithCosts.clear();
+    m_ispTestedModes.clear();
+    //save the number of subpartitions
+    m_ispTestedModes.numTotalParts[0] = (int)height >> g_aucLog2[CU::getISPSplitDim(width, height, TU_1D_HORZ_SPLIT)];
+    m_ispTestedModes.numTotalParts[1] = (int)width >> g_aucLog2[CU::getISPSplitDim(width, height, TU_1D_VERT_SPLIT)];
+#else
     //variables for the full RD list without MRL modes
     m_rdModeListWithoutMrl      .clear();
     m_rdModeListWithoutMrlHor   .clear();
@@ -341,6 +353,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
     m_intraModeDiagRatio        .clear();
     m_intraModeHorVerRatio      .clear();
     m_intraModeTestedNormalIntra.clear();
+#endif
   }
 
 #if JVET_O1136_TS_BDPCM_SIGNALLING
@@ -558,8 +571,13 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
         }
         if ( testISP )
         {
+#if JVET_O0502_ISP_CLEANUP
+          // we save the regular intra modes list
+          m_ispCandListHor = uiRdModeList;
+#else
           //we save the list with no mrl modes to keep only the Hadamard selected modes (no mpms)
           m_rdModeListWithoutMrl = uiRdModeList;
+#endif
         }
 #if ENABLE_JVET_L0283_MRL
         pu.multiRefIdx = 1;
@@ -672,6 +690,23 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
           }
           if ( testISP )
           {
+#if JVET_O0502_ISP_CLEANUP
+            // we add the MPMs to the list that contains only regular intra modes
+            for (int j = 0; j < numCand; j++)
+            {
+              bool     mostProbableModeIncluded = false;
+              ModeInfo mostProbableMode(false, 0, NOT_INTRA_SUBPARTITIONS, uiPreds[j]);
+
+              for (int i = 0; i < m_ispCandListHor.size(); i++)
+              {
+                mostProbableModeIncluded |= (mostProbableMode == m_ispCandListHor[i]);
+              }
+              if (!mostProbableModeIncluded)
+              {
+                m_ispCandListHor.push_back(mostProbableMode);
+              }
+            }
+#else
             //we add the ISP MPMs to the list without mrl modes
             m_rdModeListWithoutMrlHor = m_rdModeListWithoutMrl;
             m_rdModeListWithoutMrlVer = m_rdModeListWithoutMrl;
@@ -702,6 +737,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
               }
             }
             cu.ispMode = NOT_INTRA_SUBPARTITIONS;
+#endif
           }
         }
         //*** Add MPMs for MIP to candidate list
@@ -766,6 +802,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       }
     }
 
+#if !JVET_O0502_ISP_CLEANUP
     if( testISP ) // we remove the non-MPMs from the ISP lists
     {
       static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> uiRdModeListCopyHor = m_rdModeListWithoutMrlHor;
@@ -801,6 +838,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       }
       cu.ispMode = NOT_INTRA_SUBPARTITIONS;
     }
+#endif
 
 
     CHECK( numModesForFullRD != uiRdModeList.size(), "Inconsistent state!" );
@@ -822,8 +860,12 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
         uiRdModeList.resize(std::min<size_t>(uiRdModeList.size(), maxSize));
         if ( testISP )
         {
+#if JVET_O0502_ISP_CLEANUP
+          m_ispCandListHor.resize(std::min<size_t>(m_ispCandListHor.size(), maxSize));
+#else
           m_rdModeListWithoutMrlHor.resize(std::min<size_t>(m_rdModeListWithoutMrlHor.size(), maxSize));
           m_rdModeListWithoutMrlVer.resize(std::min<size_t>(m_rdModeListWithoutMrlVer.size(), maxSize));
+#endif
         }
       }
       if (maxSize == 0)
@@ -843,8 +885,18 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       }
     }
 
+#if JVET_O0502_ISP_CLEANUP
+    int numNonISPModes = (int)uiRdModeList.size();
+#endif
+
     if ( testISP )
     {
+#if JVET_O0502_ISP_CLEANUP
+      // we reserve positions for ISP in the common full RD list 
+      const int maxNumRDModesISP = 16;
+      for (int i = 0; i < maxNumRDModesISP; i++)
+        uiRdModeList.push_back(ModeInfo(false, 0, INTRA_SUBPARTITIONS_RESERVED, 0));
+#else
       //we create a single full RD list that includes all intra modes using regular intra, MRL and ISP
       auto* firstIspList  = ispOptions[1] == HOR_INTRA_SUBPARTITIONS ? &m_rdModeListWithoutMrlHor : &m_rdModeListWithoutMrlVer;
       auto* secondIspList = ispOptions[1] == HOR_INTRA_SUBPARTITIONS ? &m_rdModeListWithoutMrlVer : &m_rdModeListWithoutMrlHor;
@@ -878,6 +930,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
         uiRdModeList.insert( uiRdModeList.end(), secondIspList->begin(), secondIspList->end() );
         uiRdModeList.insert( uiRdModeList.end(), firstIspList->begin() , firstIspList->end()  );
       }
+#endif
     }
 
     //===== check modes (using r-d costs) =====
@@ -921,14 +974,18 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
     }
     // just to be sure
     numModesForFullRD = ( int ) uiRdModeList.size();
+#if !JVET_O0502_ISP_CLEANUP
     PartSplit intraSubPartitionsProcOrder = TU_NO_ISP;
     int       bestNormalIntraModeIndex    = -1;
+#endif
     TUIntraSubPartitioner subTuPartitioner( partitioner );
     if( !cu.ispMode && !cu.mtsFlag )
     {
       m_modeCtrl->setMtsFirstPassNoIspCost( MAX_DOUBLE );
     }
+#if !JVET_O0502_ISP_CLEANUP
     bool      ispHorAllZeroCbfs = false, ispVerAllZeroCbfs = false;
+#endif
 
     for (int mode = -2 * int(testBDPCM); mode < (int)uiRdModeList.size(); mode++)
     {
@@ -953,6 +1010,18 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       else
       {
         cu.bdpcmMode = 0;
+#if JVET_O0502_ISP_CLEANUP
+        if (uiRdModeList[mode].ispMod == INTRA_SUBPARTITIONS_RESERVED)
+        {
+          if (mode == numNonISPModes) // the list needs to be sorted only once
+          {
+            xSortISPCandList(bestCurrentCost, csBest->cost);
+          }
+          xGetNextISPMode(uiRdModeList[mode], (mode > 0 ? &uiRdModeList[mode - 1] : nullptr), Size(width, height));
+          if (uiRdModeList[mode].ispMod == INTRA_SUBPARTITIONS_RESERVED)
+            continue;
+        }
+#endif
         uiOrgMode = uiRdModeList[mode];
       cu.mipFlag                     = uiOrgMode.mipFlg;
       cu.ispMode                     = uiOrgMode.ispMod;
@@ -963,6 +1032,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       CHECK(pu.multiRefIdx && (pu.intraDir[0] == PLANAR_IDX), "Error: combination of MRL and Planar mode not supported");
       CHECK(cu.ispMode && cu.mipFlag, "Error: combination of ISP and MIP not supported");
       CHECK(cu.ispMode && pu.multiRefIdx, "Error: combination of ISP and MRL not supported");
+#if !JVET_O0502_ISP_CLEANUP
         if( cu.ispMode )
         {
           intraSubPartitionsProcOrder = CU::getISPType( cu, COMPONENT_Y );
@@ -980,6 +1050,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
             continue;
           }
         }
+#endif
       }
 
       // set context models
@@ -991,8 +1062,23 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
       bool tmpValidReturn = false;
       if( cu.ispMode )
       {
+#if JVET_O0502_ISP_CLEANUP
+        tmpValidReturn = xIntraCodingLumaISP(*csTemp, subTuPartitioner, bestCurrentCost);
+        if (csTemp->tus.size() == 0)
+        {
+          // no TUs were coded
+          csTemp->cost = MAX_DOUBLE;
+          continue;
+        }
+        if (!cu.mtsFlag && !cu.lfnstIdx)
+        {
+          // we save the data for future tests
+          m_ispTestedModes.setModeResults((ISPType)cu.ispMode, (int)uiOrgMode.modeId, (int)csTemp->tus.size(), csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] ? csTemp->cost : MAX_DOUBLE, csBest->cost);
+        }
+#else
         tmpValidReturn = xRecurIntraCodingLumaQT( *csTemp, subTuPartitioner, bestCurrentCost, 0, intraSubPartitionsProcOrder, false,
                                                   mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst );
+#endif
       }
       else
       {
@@ -1004,8 +1090,16 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
                                                   mtsCheckRangeFlag, mtsFirstCheckId, mtsLastCheckId, moreProbMTSIdxFirst );
       }
 
+#if JVET_O0502_ISP_CLEANUP
+      if (!cu.ispMode && !cu.mtsFlag && !cu.lfnstIdx && !cu.bdpcmMode && !pu.multiRefIdx && !cu.mipFlag && testISP)
+      {
+        m_regIntraRDListWithCosts.push_back(ModeInfoWithCost(cu.mipFlag, pu.multiRefIdx, cu.ispMode, uiOrgMode.modeId, csTemp->cost));
+      }
+#endif
+
       if( cu.ispMode && !csTemp->cus[0]->firstTU->cbf[COMPONENT_Y] )
       {
+#if !JVET_O0502_ISP_CLEANUP
         if( !sps.getUseLFNST() )
         {
           if ( cu.ispMode == HOR_INTRA_SUBPARTITIONS )
@@ -1017,6 +1111,7 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
             ispVerAllZeroCbfs |= ( m_pcEncCfg->getUseFastISP() && csTemp->tus[0]->lwidth() > 2 && csTemp->cost >= bestCurrentCost );
           }
         }
+#endif
         csTemp->cost = MAX_DOUBLE;
         csTemp->costDbOffset = 0;
         tmpValidReturn = false;
@@ -1028,8 +1123,13 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
         m_modeCostStore[ lfnstIdx ][ testMip ? rdModeIdxList[ mode ] : mode ] = tmpValidReturn ? csTemp->cost : ( MAX_DOUBLE / 2.0 ); //(MAX_DOUBLE / 2.0) ??
       }
 
-
+#if JVET_O0502_ISP_CLEANUP
+      DTRACE(g_trace_ctx, D_INTRA_COST, "IntraCost T [x=%d,y=%d,w=%d,h=%d] %f (%d,%d,%d,%d,%d,%d) \n", cu.blocks[0].x,
+        cu.blocks[0].y, (int)width, (int)height, csTemp->cost, uiOrgMode.modeId, uiOrgMode.ispMod,
+        pu.multiRefIdx, cu.mipFlag, cu.lfnstIdx, cu.mtsFlag);
+#else
       DTRACE( g_trace_ctx, D_INTRA_COST, "IntraCost T %f (%d) \n", csTemp->cost, uiOrgMode.modeId );
+#endif
 
 
       if( tmpValidReturn )
@@ -1057,7 +1157,9 @@ bool IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner,
         if( !cu.ispMode && !cu.bdpcmMode && csBest->cost < bestCostNonBDPCM )
         {
           bestCostNonBDPCM = csBest->cost;
+#if !JVET_O0502_ISP_CLEANUP
           bestNormalIntraModeIndex = mode;
+#endif
         }
       }
 
@@ -2384,7 +2486,9 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
 
   const bool           bUseCrossCPrediction = pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma( compID ) && PU::isChromaIntraModeCrossCheckMode( pu ) && checkCrossCPrediction;
   const bool           ccUseRecoResi        = m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate();
+#if !JVET_O0502_ISP_CLEANUP
   const bool           ispSplitIsAllowed    = sps.getUseISP() && CU::canUseISP( *tu.cu, compID );
+#endif
 
 
   //===== init availability pattern =====
@@ -2398,6 +2502,32 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
   PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area );
   if( default0Save1Load2 != 2 )
   {
+#if JVET_O0502_ISP_CLEANUP
+#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
+    bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID);
+    bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area);
+    CompArea areaPredReg(COMPONENT_Y, tu.chromaFormat, area);
+#endif
+    if (tu.cu->ispMode && isLuma(compID))
+    {
+#if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
+      if (predRegDiffFromTB)
+      {
+        if (firstTBInPredReg)
+        {
+          CU::adjustPredArea(areaPredReg);
+          initIntraPatternChTypeISP(*tu.cu, areaPredReg, piReco);
+        }
+      }
+      else
+#endif
+        initIntraPatternChTypeISP(*tu.cu, area, piReco);
+    }
+    else
+    {
+      initIntraPatternChType(*tu.cu, area);
+    }
+#else
 #if JVET_O0106_ISP_4xN_PREDREG_FOR_1xN_2xN
     bool predRegDiffFromTB = CU::isPredRegDiffFromTB(*tu.cu, compID);
     bool firstTBInPredReg = CU::isFirstTBInPredReg(*tu.cu, compID, area);
@@ -2413,6 +2543,7 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
     else
 #endif
       initIntraPatternChType(*tu.cu, area);
+#endif
 
     //===== get prediction signal =====
     if( compID != COMPONENT_Y && PU::isLMCMode( uiChFinalMode ) )
@@ -2570,12 +2701,23 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
 #endif
   }
 #if JVET_O0105_ICT
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  if ( sps.getJointCbCrEnabledFlag() && isChroma(compID) && (tu.cu->cs->slice->getSliceQp() > 18) )
+  {
+    m_pcTrQuant->setLambda( 1.3 * m_pcTrQuant->getLambda() );
+  }
+#else
   if( isChroma(compID) && tu.cu->cs->slice->getSliceQp() > 18 )
   {
     m_pcTrQuant->setLambda( 1.3 * m_pcTrQuant->getLambda() );
   }
+  #endif
+#else
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  else if ( sps.getJointCbCrEnabledFlag() && isChroma(compID) && (tu.cu->cs->slice->getSliceQp() > 18) )
 #else
   else if ( isChroma(compID) && tu.cu->cs->slice->getSliceQp() > 18 )
+#endif
     m_pcTrQuant->setLambda( 1.10 * m_pcTrQuant->getLambda() );
 #endif
 
@@ -2583,6 +2725,14 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
   if( isLuma(compID) )
   {
 #endif
+#if JVET_O0502_ISP_CLEANUP
+    if (trModes)
+    {
+      m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, CU::isIntra(*tu.cu) ? m_pcEncCfg->getIntraMTSMaxCand() : m_pcEncCfg->getInterMTSMaxCand());
+      tu.mtsIdx = trModes->at(0).first;
+    }
+    m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
+#else
   double diagRatio = 0, horVerRatio = 0;
 
   if( trModes )
@@ -2597,10 +2747,20 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
     m_intraModeHorVerRatio      .push_back(horVerRatio);
     m_intraModeTestedNormalIntra.push_back((int)uiChFinalMode);
   }
+#endif
 
 
   DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), compID, uiAbsSum );
 
+#if JVET_O0502_ISP_CLEANUP
+  if (tu.cu->ispMode && isLuma(compID) && CU::isISPLast(*tu.cu, area, area.compID) && CU::allLumaCBFsAreZero(*tu.cu))
+  {
+    // ISP has to have at least one non-zero CBF
+    ruiDist = MAX_INT;
+    return;
+  }
+#endif
+
 
   //--- inverse transform ---
   if (uiAbsSum > 0)
@@ -2771,6 +2931,118 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
   }
 }
 
+#if JVET_O0502_ISP_CLEANUP
+bool IntraSearch::xIntraCodingLumaISP(CodingStructure& cs, Partitioner& partitioner, const double bestCostSoFar)
+{
+  int               subTuCounter = 0;
+  const CodingUnit& cu = *cs.getCU(partitioner.currArea().lumaPos(), partitioner.chType);
+  bool              earlySkipISP = false;
+  bool              splitCbfLuma = false;
+  const PartSplit   ispType = CU::getISPType(cu, COMPONENT_Y);
+
+  cs.cost = 0;
+
+  partitioner.splitCurrArea(ispType, cs);
+
+  do   // subpartitions loop
+  {
+    uint32_t   numSig = 0;
+    Distortion singleDistTmpLuma = 0;
+    uint64_t   singleTmpFracBits = 0;
+    double     singleCostTmp = 0;
+
+    TransformUnit& tu = cs.addTU(CS::getArea(cs, partitioner.currArea(), partitioner.chType), partitioner.chType);
+    tu.depth = partitioner.currTrDepth;
+
+    // Encode TU
+    xIntraCodingTUBlock(tu, COMPONENT_Y, false, singleDistTmpLuma, 0, &numSig);
+
+    if (singleDistTmpLuma == MAX_INT)   // all zero CBF skip
+    {
+      earlySkipISP = true;
+      partitioner.exitCurrSplit();
+      cs.cost = MAX_DOUBLE;
+      return false;
+    }
+
+    {
+      if (m_pcRdCost->calcRdCost(cs.fracBits, cs.dist + singleDistTmpLuma) > bestCostSoFar)
+      {
+        // The accumulated cost + distortion is already larger than the best cost so far, so it is not necessary to calculate the rate
+        earlySkipISP = true;
+      }
+      else
+      {
+        singleTmpFracBits = xGetIntraFracBitsQT(cs, partitioner, true, false, subTuCounter, ispType);
+      }
+      singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma);
+    }
+
+    cs.cost += singleCostTmp;
+    cs.dist += singleDistTmpLuma;
+    cs.fracBits += singleTmpFracBits;
+
+    subTuCounter++;
+
+    splitCbfLuma |= TU::getCbfAtDepth(*cs.getTU(partitioner.currArea().lumaPos(), partitioner.chType, subTuCounter - 1), COMPONENT_Y, partitioner.currTrDepth);
+    int nSubPartitions = m_ispTestedModes.numTotalParts[cu.ispMode - 1];
+    if (subTuCounter < nSubPartitions)
+    {
+      // exit condition if the accumulated cost is already larger than the best cost so far (no impact in RD performance)
+      if (cs.cost > bestCostSoFar)
+      {
+        earlySkipISP = true;
+        break;
+      }
+      else if (subTuCounter < nSubPartitions)
+      {
+        // more restrictive exit condition
+        double threshold = nSubPartitions == 2 ? 0.95 : subTuCounter == 1 ? 0.83 : 0.91;
+        if (subTuCounter < nSubPartitions && cs.cost > bestCostSoFar * threshold)
+        {
+          earlySkipISP = true;
+          break;
+        }
+      }
+    }
+  } while (partitioner.nextPart(cs));   // subpartitions loop
+
+  partitioner.exitCurrSplit();
+  const UnitArea& currArea = partitioner.currArea();
+  const uint32_t  currDepth = partitioner.currTrDepth;
+
+  if (earlySkipISP)
+  {
+    cs.cost = MAX_DOUBLE;
+  }
+  else
+  {
+    cs.cost = m_pcRdCost->calcRdCost(cs.fracBits, cs.dist);
+    // The cost check is necessary here again to avoid superfluous operations if the maximum number of coded subpartitions was reached and yet ISP did not win
+    if (cs.cost < bestCostSoFar)
+    {
+      cs.setDecomp(cu.Y());
+      cs.picture->getRecoBuf(currArea.Y()).copyFrom(cs.getRecoBuf(currArea.Y()));
+
+      for (auto& ptu : cs.tus)
+      {
+        if (currArea.Y().contains(ptu->Y()))
+        {
+          TU::setCbfAtDepth(*ptu, COMPONENT_Y, currDepth, splitCbfLuma ? 1 : 0);
+        }
+      }
+    }
+    else
+    {
+      cs.cost = MAX_DOUBLE;
+      earlySkipISP = true;
+    }
+  }
+  return !earlySkipISP;
+}
+#endif
+
+
 bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &partitioner, const double bestCostSoFar, const int subTuIdx, const PartSplit ispType, const bool ispIsCurrentWinner, bool mtsCheckRangeFlag, int mtsFirstCheckId, int mtsLastCheckId, bool moreProbMTSIdxFirst )
 {
         int   subTuCounter = subTuIdx;
@@ -3551,11 +3823,17 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
 #if JVET_O0105_ICT
       bool       lastIsBest     = false;
       std::vector<int>  jointCbfMasksToTest;
-      if( TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr) )
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+      if ( cs.sps->getJointCbCrEnabledFlag() && (TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr)))
       {
-        jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates( currTU, orgResiCb, orgResiCr );
+        jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(currTU, orgResiCb, orgResiCr);
       }
-
+#else
+      if (TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr))
+      {
+        jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(currTU, orgResiCb, orgResiCr);
+      }
+#endif
       for( int cbfMask : jointCbfMasksToTest )
 #else
       bool       checkJointCbCr = TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr);
@@ -3858,3 +4136,263 @@ void IntraSearch::reduceHadCandList(static_vector<T, N>& candModeList, static_ve
   candCostList = tempCandCostList;
   numModesForFullRD = int(candModeList.size());
 }
+
+#if JVET_O0502_ISP_CLEANUP
+// It decides which modes from the ISP lists can be full RD tested
+void IntraSearch::xGetNextISPMode(ModeInfo& modeInfo, const ModeInfo* lastMode, const Size cuSize)
+{
+  static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM>* rdModeLists[2] = { &m_ispCandListHor, &m_ispCandListVer };
+
+  ISPType nextISPcandSplitType;
+  if (!m_ispTestedModes.stopTestingHorSplit && !m_ispTestedModes.stopTestingVerSplit)
+  {
+    nextISPcandSplitType = !lastMode ? HOR_INTRA_SUBPARTITIONS : lastMode->ispMod == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS;
+  }
+  else if (!m_ispTestedModes.stopTestingHorSplit && m_ispTestedModes.stopTestingVerSplit)
+  {
+    nextISPcandSplitType = HOR_INTRA_SUBPARTITIONS;
+  }
+  else if (m_ispTestedModes.stopTestingHorSplit && !m_ispTestedModes.stopTestingVerSplit)
+  {
+    nextISPcandSplitType = VER_INTRA_SUBPARTITIONS;
+  }
+  else
+  {
+    return;   // no more modes will be tested
+  }
+
+  int maxNumSubPartitions = m_ispTestedModes.numTotalParts[nextISPcandSplitType - 1];
+
+  if (m_ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2)
+  {
+    // Split stop criteria after checking the performance of previously tested intra modes
+    const int thresholdSplit1 = maxNumSubPartitions;
+
+    int mode1 = m_ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 0);
+    mode1 = mode1 == DC_IDX ? -1 : mode1;
+    int numSubPartsBestMode1 = mode1 != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode1) : -1;
+    int mode2 = m_ispTestedModes.getTestedIntraMode((ISPType)nextISPcandSplitType, 1);
+    mode2 = mode2 == DC_IDX ? -1 : mode2;
+    int numSubPartsBestMode2 = mode2 != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)nextISPcandSplitType, mode2) : -1;
+
+    // 1) The 2 most promising modes do not reach a certain number of sub-partitions
+    if (numSubPartsBestMode1 != -1 && numSubPartsBestMode2 != -1)
+    {
+      if (numSubPartsBestMode1 < thresholdSplit1 && numSubPartsBestMode2 < thresholdSplit1)
+      {
+        m_ispTestedModes.stopTestingVerSplit = nextISPcandSplitType == VER_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingVerSplit;
+        m_ispTestedModes.stopTestingHorSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingHorSplit;
+        return;
+      }
+    }
+
+    // 2) One split is better than the other after PLANAR and one angle have been tested
+    ISPType otherSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? VER_INTRA_SUBPARTITIONS : HOR_INTRA_SUBPARTITIONS;
+    int  numSubPartsBestAngleOtherSplit = mode2 != -1 ? m_ispTestedModes.getNumCompletedSubParts(otherSplit, mode2) : -1;
+    bool stopThisSplit = false;
+    if (numSubPartsBestAngleOtherSplit != -1 && numSubPartsBestMode2 != -1)
+    {
+      if (numSubPartsBestAngleOtherSplit > numSubPartsBestMode2)
+      {
+        stopThisSplit = true;
+      }
+      else if (numSubPartsBestAngleOtherSplit == numSubPartsBestMode2 && numSubPartsBestAngleOtherSplit == maxNumSubPartitions)
+      {
+        double rdCostBestAngleThisSplit = m_ispTestedModes.getRDCost(nextISPcandSplitType, mode2, maxNumSubPartitions);
+        double rdCostBestAngleOtherSplit = m_ispTestedModes.getRDCost(otherSplit, mode2, maxNumSubPartitions);
+
+        if (rdCostBestAngleThisSplit == MAX_DOUBLE || rdCostBestAngleOtherSplit < rdCostBestAngleThisSplit * 1.3)
+        {
+          stopThisSplit = true;
+        }
+      }
+    }
+    if (stopThisSplit)
+    {
+      m_ispTestedModes.stopTestingVerSplit = nextISPcandSplitType == VER_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingVerSplit;
+      m_ispTestedModes.stopTestingHorSplit = nextISPcandSplitType == HOR_INTRA_SUBPARTITIONS ? true : m_ispTestedModes.stopTestingHorSplit;
+      return;
+    }
+  }
+
+  // Now a new mode is retrieved from the list and it has to be decided whether it should be tested or not
+  if (m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1] < rdModeLists[nextISPcandSplitType - 1]->size())
+  {
+    ModeInfo candidate = rdModeLists[nextISPcandSplitType - 1]->at(m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1]);
+    m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1]++;
+
+    // extra modes are only tested if ISP has won so far
+    if (m_ispTestedModes.candIndexInList[nextISPcandSplitType - 1] > m_ispTestedModes.numOrigModesToTest)
+    {
+      if (m_ispTestedModes.bestSplitSoFar != candidate.ispMod || m_ispTestedModes.bestModeSoFar == PLANAR_IDX)
+      {
+        return;
+      }
+    }
+
+    bool testCandidate = true;
+
+    // we look for a reference mode that has already been tested within the window and decide to test the new one according to the reference mode costs
+    if (candidate.modeId >= DC_IDX && maxNumSubPartitions > 2 && m_ispTestedModes.numTestedModes[nextISPcandSplitType - 1] >= 2)
+    {
+      const int angWindowSize = 5;
+      int       numSubPartsLeftMode, numSubPartsRightMode, numSubPartsRefMode, leftIntraMode = -1, rightIntraMode = -1;
+      int       windowSize = candidate.modeId > DC_IDX ? angWindowSize : 1;
+      int       numSamples = cuSize.width << g_aucLog2[cuSize.height];
+      int       numSubPartsLimit = numSamples >= 256 ? maxNumSubPartitions - 1 : 2;
+
+      xFindAlreadyTestedNearbyIntraModes((int)candidate.modeId, &leftIntraMode, &rightIntraMode, (ISPType)candidate.ispMod, windowSize);
+
+      numSubPartsLeftMode = leftIntraMode != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, leftIntraMode) : -1;
+      numSubPartsRightMode = rightIntraMode != -1 ? m_ispTestedModes.getNumCompletedSubParts((ISPType)candidate.ispMod, rightIntraMode) : -1;
+
+      numSubPartsRefMode = std::max(numSubPartsLeftMode, numSubPartsRightMode);
+
+      if (numSubPartsRefMode > 0)
+      {
+        // The mode was found. Now we check the condition
+        testCandidate = numSubPartsRefMode > numSubPartsLimit;
+      }
+    }
+
+    if (testCandidate)
+    {
+      modeInfo = candidate;
+    }
+  }
+}
+
+void IntraSearch::xFindAlreadyTestedNearbyIntraModes(int currentIntraMode, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize)
+{
+  bool leftModeFound = false, rightModeFound = false;
+  *leftIntraMode = -1;
+  *rightIntraMode = -1;
+  const unsigned st = ispOption - 1;
+
+  for (int k = 1; k <= windowSize; k++)
+  {
+    int off = currentIntraMode - 2 - k;
+    int leftMode = (off < 0) ? NUM_LUMA_MODE + off : currentIntraMode - k;
+    int rightMode = currentIntraMode > DC_IDX ? (((int)currentIntraMode - 2 + k) % 65) + 2 : PLANAR_IDX;
+
+    leftModeFound = leftMode != (int)currentIntraMode ? m_ispTestedModes.modeHasBeenTested[leftMode][st] : false;
+    rightModeFound = rightMode != (int)currentIntraMode ? m_ispTestedModes.modeHasBeenTested[rightMode][st] : false;
+    if (leftModeFound || rightModeFound)
+    {
+      *leftIntraMode = leftModeFound ? leftMode : -1;
+      *rightIntraMode = rightModeFound ? rightMode : -1;
+      break;
+    }
+  }
+}
+
+void IntraSearch::xSortISPCandList(double bestCostSoFar, double bestNonISPCost)
+{
+  if (m_pcEncCfg->getUseFastISP())
+  {
+    double thSkipISP = 1.4;
+    if (bestNonISPCost > bestCostSoFar * thSkipISP)
+    {
+      m_ispTestedModes.stopTestingHorSplit = true;
+      m_ispTestedModes.stopTestingVerSplit = true;
+      return;
+    }
+  }
+
+  for (int k = 0; k < m_ispCandListHor.size(); k++)
+  {
+    m_ispCandListHor.at(k).ispMod = HOR_INTRA_SUBPARTITIONS; //we set the correct ISP split type value
+  }
+
+  auto origHadList = m_ispCandListHor;   // save the original hadamard list of regular intra
+  bool modeIsInList[NUM_LUMA_MODE] = { false };
+
+  m_ispCandListHor.clear();
+  m_ispCandListVer.clear();
+
+  // we sort the normal intra modes according to their full RD costs
+  std::sort(m_regIntraRDListWithCosts.begin(), m_regIntraRDListWithCosts.end(), ModeInfoWithCost::compareModeInfoWithCost);
+
+  // we get the best angle from the regular intra list
+  int bestNormalIntraAngle = -1;
+  for (int modeIdx = 0; modeIdx < m_regIntraRDListWithCosts.size(); modeIdx++)
+  {
+    if (bestNormalIntraAngle == -1 && m_regIntraRDListWithCosts.at(modeIdx).modeId > DC_IDX)
+    {
+      bestNormalIntraAngle = m_regIntraRDListWithCosts.at(modeIdx).modeId;
+      break;
+    }
+  }
+
+  int mode1 = PLANAR_IDX;
+  int mode2 = bestNormalIntraAngle;
+
+  ModeInfo refMode = origHadList.at(0);
+  auto* destListPtr = &m_ispCandListHor;
+  // 1) Planar
+  destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, mode1));
+  modeIsInList[mode1] = true;
+  // 2) Best angle in regular intra
+  if (mode2 != -1)
+  {
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, mode2));
+    modeIsInList[mode2] = true;
+  }
+  // 3) Remaining regular intra modes that were full RD tested (except DC, which is added after the angles from regular intra)
+  int dcModeIndex = -1;
+  for (int remModeIdx = 0; remModeIdx < m_regIntraRDListWithCosts.size(); remModeIdx++)
+  {
+    int currentMode = m_regIntraRDListWithCosts.at(remModeIdx).modeId;
+    if (currentMode != mode1 && currentMode != mode2)
+    {
+      if (currentMode > DC_IDX)
+      {
+        destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, currentMode));
+        modeIsInList[currentMode] = true;
+      }
+      else if (currentMode == DC_IDX)
+      {
+        dcModeIndex = remModeIdx;
+      }
+    }
+  }
+  // 4) DC is added after the angles from regular intra
+  if (dcModeIndex != -1)
+  {
+    destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, DC_IDX));
+    modeIsInList[DC_IDX] = true;
+  }
+
+  // 5) We add extra candidates to the list that will only be tested if ISP is likely to win
+  m_ispTestedModes.numOrigModesToTest = (int)destListPtr->size();
+  const int addedModesFromHadList = 3;
+  int       newModesAdded = 0;
+
+  for (int k = 0; k < origHadList.size(); k++)
+  {
+    if (newModesAdded == addedModesFromHadList)
+    {
+      break;
+    }
+    if (!modeIsInList[origHadList.at(k).modeId])
+    {
+      destListPtr->push_back(ModeInfo(refMode.mipFlg, refMode.mRefId, refMode.ispMod, origHadList.at(k).modeId));
+      newModesAdded++;
+    }
+  }
+
+  // Copy modes to other split-type list
+  m_ispCandListVer = m_ispCandListHor;
+  for (int i = 0; i < m_ispCandListVer.size(); i++)
+  {
+    m_ispCandListVer[i].ispMod = VER_INTRA_SUBPARTITIONS;
+  }
+
+  // Reset the tested modes information to 0
+  for (int i = 0; i < m_ispCandListHor.size(); i++)
+  {
+    m_ispTestedModes.clearISPModeInfo(m_ispCandListHor[i].modeId);
+  }
+}
+
+#endif 
diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h
index ceb359f0f762c7f0f3f980037b02bac3b435a4ec..0176b146ebc0ebe01ff53799b01fde793f9cfe0e 100644
--- a/source/Lib/EncoderLib/IntraSearch.h
+++ b/source/Lib/EncoderLib/IntraSearch.h
@@ -191,10 +191,131 @@ private:
     ModeInfo(const bool mipf, const int mrid, const uint8_t ispm, const uint32_t mode) : mipFlg(mipf), mRefId(mrid), ispMod(ispm), modeId(mode) {}
     bool operator==(const ModeInfo cmp) const { return (mipFlg == cmp.mipFlg && mRefId == cmp.mRefId && ispMod == cmp.ispMod && modeId == cmp.modeId); }
   };
+#if JVET_O0502_ISP_CLEANUP
+  struct ModeInfoWithCost : public ModeInfo
+  {
+    double rdCost;
+    ModeInfoWithCost() : ModeInfo(), rdCost(MAX_DOUBLE) {}
+    ModeInfoWithCost(const bool mipf, const int mrid, const uint8_t ispm, const uint32_t mode, double cost) : ModeInfo(mipf, mrid, ispm, mode), rdCost(cost) {}
+    bool operator==(const ModeInfoWithCost cmp) const { return (mipFlg == cmp.mipFlg && mRefId == cmp.mRefId && ispMod == cmp.ispMod && modeId == cmp.modeId && rdCost == cmp.rdCost); }
+    static bool compareModeInfoWithCost(ModeInfoWithCost a, ModeInfoWithCost b) { return a.rdCost < b.rdCost; }
+  };
+
+  struct ISPTestedModeInfo
+  {
+    int    numCompSubParts;
+    double rdCost;
+
+    ISPTestedModeInfo() {}
+
+    void setMode(int numParts, double cost)
+    {
+      numCompSubParts = numParts;
+      rdCost = cost;
+    }
+    void clear()
+    {
+      numCompSubParts = -1;
+      rdCost = MAX_DOUBLE;
+    }
+  };
+  struct ISPTestedModesInfo
+  {
+    ISPTestedModeInfo                           intraMode[NUM_LUMA_MODE][2];
+    bool                                        modeHasBeenTested[NUM_LUMA_MODE][2];
+    int                                         numTotalParts[2];
+    static_vector<int, FAST_UDI_MAX_RDMODE_NUM> testedModes[2];
+    int                                         bestModeSoFar;
+    ISPType                                     bestSplitSoFar;
+    int                                         bestMode[2];
+    double                                      bestCost[2];
+    int                                         numTestedModes[2];
+    int                                         candIndexInList[2];
+    bool                                        stopTestingHorSplit;
+    bool                                        stopTestingVerSplit;
+    int                                         numOrigModesToTest;
+
+    // set a tested mode results
+    void setModeResults(ISPType splitType, int iModeIdx, int numCompletedParts, double rdCost, double currentBestCost)
+    {
+      const unsigned st = splitType - 1;
+      CHECKD(st > 1, "The split type is invalid!");
+      const int maxNumParts = numTotalParts[st];
+      intraMode[iModeIdx][st].setMode(numCompletedParts, numCompletedParts == maxNumParts ? rdCost : MAX_DOUBLE);
+      testedModes[st].push_back(iModeIdx);
+      numTestedModes[st]++;
+      modeHasBeenTested[iModeIdx][st] = true;
+      if (numCompletedParts == maxNumParts && rdCost < bestCost[st])   // best mode update
+      {
+        bestMode[st] = iModeIdx;
+        bestCost[st] = rdCost;
+      }
+      if (numCompletedParts == maxNumParts && rdCost < currentBestCost)   // best mode update
+      {
+        bestModeSoFar = iModeIdx;
+        bestSplitSoFar = splitType;
+      }
+    }
 
+    int getNumCompletedSubParts(ISPType splitType, int iModeIdx)
+    {
+      const unsigned st = splitType - 1;
+      CHECK(st < 0 || st > 1, "The split type is invalid!");
+      CHECK(iModeIdx < 0 || iModeIdx >(NUM_LUMA_MODE - 1), "The modeIdx is invalid");
+      return modeHasBeenTested[iModeIdx][st] ? intraMode[iModeIdx][st].numCompSubParts : -1;
+    }
+
+    double getRDCost(ISPType splitType, int iModeIdx, int maxNumSubParts)
+    {
+      const unsigned st = splitType - 1;
+      CHECKD(st > 1, "The split type is invalid!");
+      return modeHasBeenTested[iModeIdx][st] && intraMode[iModeIdx][st].numCompSubParts == maxNumSubParts
+        ? intraMode[iModeIdx][st].rdCost
+        : -1;
+    }
+
+    // get a tested intra mode index
+    int getTestedIntraMode(ISPType splitType, int pos)
+    {
+      const unsigned st = splitType - 1;
+      CHECKD(st > 1, "The split type is invalid!");
+      return pos < testedModes[st].size() ? testedModes[st].at(pos) : -1;
+    }
+
+    // set everything to default values
+    void clear()
+    {
+      numTestedModes[0] = numTestedModes[1] = 0;
+      candIndexInList[0] = candIndexInList[1] = 0;
+      stopTestingHorSplit = false;
+      stopTestingVerSplit = false;
+      testedModes[0].clear();
+      testedModes[1].clear();
+      bestCost[0] = MAX_DOUBLE;
+      bestCost[1] = MAX_DOUBLE;
+      bestMode[0] = -1;
+      bestMode[1] = -1;
+      bestModeSoFar = -1;
+      bestSplitSoFar = NOT_INTRA_SUBPARTITIONS;
+      numOrigModesToTest = -1;
+      memset(modeHasBeenTested, 0, sizeof(modeHasBeenTested));
+    }
+    void clearISPModeInfo(int idx)
+    {
+      intraMode[idx][0].clear();
+      intraMode[idx][1].clear();
+    }
+  };
+
+  static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_ispCandListHor, m_ispCandListVer;
+  static_vector<ModeInfoWithCost, FAST_UDI_MAX_RDMODE_NUM> m_regIntraRDListWithCosts;
+
+  ISPTestedModesInfo m_ispTestedModes;
+#else
   static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrl;
   static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlHor;
   static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_rdModeListWithoutMrlVer;
+#endif
 
   //cost variables for the EMT algorithm and new modes list
   double     m_bestModeCostStore[ NUM_LFNST_NUM_PER_SET ];                                    // RD cost of the best mode for each PU using DCT2
@@ -202,9 +323,11 @@ private:
   ModeInfo   m_savedRdModeList[ NUM_LFNST_NUM_PER_SET ][ NUM_LUMA_MODE ];
   int32_t    m_savedNumRdModes[ NUM_LFNST_NUM_PER_SET ];
 
+#if !JVET_O0502_ISP_CLEANUP
   static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeDiagRatio;
   static_vector<double, FAST_UDI_MAX_RDMODE_NUM> m_intraModeHorVerRatio;
   static_vector<int,    FAST_UDI_MAX_RDMODE_NUM> m_intraModeTestedNormalIntra;
+#endif
 
   static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_uiSavedRdModeListLFNST;
   static_vector<ModeInfo, FAST_UDI_MAX_RDMODE_NUM> m_uiSavedHadModeListLFNST;
@@ -288,7 +411,9 @@ protected:
 
   ChromaCbfs xRecurIntraChromaCodingQT( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE,                          const PartSplit ispType = TU_NO_ISP );
   bool       xRecurIntraCodingLumaQT  ( CodingStructure &cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE, const int subTuIdx = -1, const PartSplit ispType = TU_NO_ISP, const bool ispIsCurrentWinner = false, bool mtsCheckRangeFlag = false, int mtsFirstCheckId = 0, int mtsLastCheckId = 0, bool moreProbMTSIdxFirst = false );
-
+#if JVET_O0502_ISP_CLEANUP
+  bool       xIntraCodingLumaISP      ( CodingStructure& cs, Partitioner& pm, const double bestCostSoFar = MAX_DOUBLE );
+#endif
 
   void encPredIntraDPCM( const ComponentID &compID, PelBuf &pOrg, PelBuf &pDst, const uint32_t &uiDirMode );
   static bool useDPCMForFirstPassIntraEstimation( const PredictionUnit &pu, const uint32_t &uiDirMode );
@@ -304,6 +429,11 @@ protected:
   void   calcPixelPred(CodingStructure& cs, Partitioner& partitioner, uint32_t yPos, uint32_t xPos, ComponentID compBegin, uint32_t numComp);
   void   preCalcPLTIndex(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp);
 #endif
+#if JVET_O0502_ISP_CLEANUP
+  void xGetNextISPMode                    ( ModeInfo& modeInfo, const ModeInfo* lastMode, const Size cuSize );
+  void xFindAlreadyTestedNearbyIntraModes ( int currentIntraMode, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize );
+  void xSortISPCandList                   ( double bestCostSoFar, double bestNonISPCost );
+#endif
 };// END CLASS DEFINITION EncSearch
 
 //! \}
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 5c0f4a6a751578e991167881dc6d59d90e8c61f8..5e6eaa0cc1b498ea19092b77ff2aaa69817c1e03 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -839,10 +839,30 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   WRITE_UVLC( pcSPS->getLog2MaxTbSize() - 2,                                 "log2_max_luma_transform_block_size_minus2" );
 #endif
 #endif
+
+#if JVET_O0650_SIGNAL_CHROMAQP_MAPPING_TABLE
+  if (pcSPS->getChromaFormatIdc() != CHROMA_400)
+  {
+    const ChromaQpMappingTable& chromaQpMappingTable = pcSPS->getChromaQpMappingTable();
+    WRITE_FLAG(chromaQpMappingTable.getSameCQPTableForAllChromaFlag(), "same_qp_table_for_chroma");
+    for (int i = 0; i < (chromaQpMappingTable.getSameCQPTableForAllChromaFlag() ? 1 : 3); i++)
+    {
+      WRITE_UVLC(chromaQpMappingTable.getNumPtsInCQPTableMinus1(i), "num_points_in_qp_table_minus1"); 
+
+      for (int j = 0; j <= chromaQpMappingTable.getNumPtsInCQPTableMinus1(i); j++)
+      {
+        WRITE_UVLC(chromaQpMappingTable.getDeltaQpInValMinus1(i,j),  "delta_qp_in_val_minus1");
+        WRITE_UVLC(chromaQpMappingTable.getDeltaQpOutVal(i, j),       "delta_qp_out_val");
+      }
+    }
+  }
+#endif
+
 #if JVET_O0244_DELTA_POC
   WRITE_FLAG( pcSPS->getUseWP() ? 1 : 0, "sps_weighted_pred_flag" );   // Use of Weighting Prediction (P_SLICE)
   WRITE_FLAG( pcSPS->getUseWPBiPred() ? 1 : 0, "sps_weighted_bipred_flag" );  // Use of Weighting Bi-Prediction (B_SLICE)
 #endif
+
   WRITE_FLAG( pcSPS->getSAOEnabledFlag(),                                            "sps_sao_enabled_flag");
   WRITE_FLAG( pcSPS->getALFEnabledFlag(),                                            "sps_alf_enabled_flag" );
 
@@ -863,7 +883,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
     WRITE_FLAG(pcSPS->getBDPCMEnabledFlag() ? 1 : 0, "sps_bdpcm_enabled_flag");
   }
 #endif
-
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  WRITE_FLAG( pcSPS->getJointCbCrEnabledFlag(),                                           "sps_joint_cbcr_enabled_flag");
+#endif
   if( pcSPS->getCTUSize() + 2*(1 << pcSPS->getLog2MinCodingBlockSize()) <= pcSPS->getPicWidthInLumaSamples() )
   {    
   WRITE_FLAG( pcSPS->getWrapAroundEnabledFlag() ? 1 : 0,                              "sps_ref_wraparound_enabled_flag" );
@@ -1284,7 +1306,11 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
       if (alfEnabled)
       {
 #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL
+#if JVET_O_MAX_NUM_ALF_APS_8
+        WRITE_CODE(pcSlice->getTileGroupNumAps(), 3, "tile_group_num_aps");
+#else
         xWriteTruncBinCode(pcSlice->getTileGroupNumAps(), ALF_CTB_MAX_NUM_APS + 1);
+#endif
 #else
         if (pcSlice->isIntra())
         {
@@ -1292,13 +1318,21 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
         }
         else
         {
+#if JVET_O_MAX_NUM_ALF_APS_8
+          WRITE_CODE(pcSlice->getTileGroupNumAps(), 3, "tile_group_num_aps");
+#else
           xWriteTruncBinCode(pcSlice->getTileGroupNumAps(), ALF_CTB_MAX_NUM_APS + 1);
+#endif
         }
 #endif
         const std::vector<int>&   apsId = pcSlice->getTileGroupApsIdLuma();
         for (int i = 0; i < pcSlice->getTileGroupNumAps(); i++)
         {
+#if JVET_O_MAX_NUM_ALF_APS_8
+          WRITE_CODE(apsId[i], 3, "tile_group_aps_id");
+#else
           WRITE_CODE(apsId[i], 5, "tile_group_aps_id");
+#endif
         }
 
         const int alfChromaIdc = pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) + pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) * 2 ;
@@ -1313,7 +1347,11 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
         if (alfChromaIdc)
         {
 #if JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL
+#if JVET_O_MAX_NUM_ALF_APS_8
+          WRITE_CODE(pcSlice->getTileGroupApsIdChroma(), 3, "tile_group_aps_id_chroma");
+#else
           WRITE_CODE(pcSlice->getTileGroupApsIdChroma(), 5, "tile_group_aps_id_chroma");
+#endif
 #else
           if (pcSlice->isIntra()&& pcSlice->getTileGroupNumAps() == 1)
           {
@@ -1321,7 +1359,11 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
           }
           else
           {
+#if JVET_O_MAX_NUM_ALF_APS_8
+            WRITE_CODE(pcSlice->getTileGroupApsIdChroma(), 3, "tile_group_aps_id_chroma");
+#else
             WRITE_CODE(pcSlice->getTileGroupApsIdChroma(), 5, "tile_group_aps_id_chroma");
+#endif
           }
 #endif
         }
@@ -1446,7 +1488,11 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
         }
       }
     }
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+    if (!cs.slice->isIntra())
+#else
     if (!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag())
+#endif
     {
       CHECK(pcSlice->getMaxNumMergeCand() > MRG_MAX_NUM_CANDS, "More merge candidates signalled than supported");
       WRITE_UVLC(MRG_MAX_NUM_CANDS - pcSlice->getMaxNumMergeCand(), "six_minus_max_num_merge_cand");
@@ -1496,11 +1542,25 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
         pcSlice->setMaxNumTriangleCand(0);
       }
     }
+#if JVET_O0455_IBC_MAX_MERGE_NUM
+    if ( pcSlice->getSPS()->getIBCFlag() )
+    {
+      CHECK( pcSlice->getMaxNumIBCMergeCand() > IBC_MRG_MAX_NUM_CANDS, "More IBC merge candidates signalled than supported" );
+      WRITE_UVLC( IBC_MRG_MAX_NUM_CANDS - pcSlice->getMaxNumIBCMergeCand(), "six_minus_max_num_ibc_merge_cand" );
+    }
+#endif
 #if JVET_O0105_ICT
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+    if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
+    {
+      WRITE_FLAG( pcSlice->getJointCbCrSignFlag() ? 1 : 0, "slice_joint_cbcr_sign_flag");
+    }
+#else
     if (chromaEnabled)
     {
-      WRITE_FLAG( pcSlice->getJointCbCrSignFlag() ? 1 : 0, "joint_cb_cr_sign_flag" );
+      WRITE_FLAG( pcSlice->getJointCbCrSignFlag() ? 1 : 0, "slice_joint_cbcr_sign_flag");
     }
+#endif 
 #endif
 
     int iCode = pcSlice->getSliceQp() - ( pcSlice->getPPS()->getPicInitQPMinus26() + 26 );
@@ -1514,7 +1574,14 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
       if (numberValidComponents > COMPONENT_Cr)
       {
         WRITE_SVLC( pcSlice->getSliceChromaQpDelta(COMPONENT_Cr), "slice_cr_qp_offset" );
-        WRITE_SVLC( pcSlice->getSliceChromaQpDelta(JOINT_CbCr),   "slice_cb_cr_qp_offset" );
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+        if (pcSlice->getSPS()->getJointCbCrEnabledFlag())
+        {
+          WRITE_SVLC( pcSlice->getSliceChromaQpDelta(JOINT_CbCr), "slice_joint_cbcr_qp_offset");
+        }
+#else
+        WRITE_SVLC( pcSlice->getSliceChromaQpDelta(JOINT_CbCr), "slice_joint_cbcr_qp_offset");
+#endif
       }
       CHECK(numberValidComponents < COMPONENT_Cr+1, "Too many valid components");
     }
@@ -1595,6 +1662,9 @@ void  HLSWriter::codeConstraintInfo  ( const ConstraintInfo* cinfo )
   WRITE_FLAG(cinfo->getNoPartitionConstraintsOverrideConstraintFlag() ? 1 : 0, "no_partition_constraints_override_constraint_flag");
   WRITE_FLAG(cinfo->getNoSaoConstraintFlag() ? 1 : 0, "no_sao_constraint_flag");
   WRITE_FLAG(cinfo->getNoAlfConstraintFlag() ? 1 : 0, "no_alf_constraint_flag");
+#if JVET_O0376_SPS_JOINTCBCR_FLAG
+  WRITE_FLAG(cinfo->getNoJointCbCrConstraintFlag() ? 1 : 0, "no_joint_cbcr_constraint_flag");
+#endif
   WRITE_FLAG(cinfo->getNoPcmConstraintFlag() ? 1 : 0, "no_pcm_constraint_flag");
   WRITE_FLAG(cinfo->getNoRefWraparoundConstraintFlag() ? 1 : 0, "no_ref_wraparound_constraint_flag");
   WRITE_FLAG(cinfo->getNoTemporalMvpConstraintFlag() ? 1 : 0, "no_temporal_mvp_constraint_flag");