diff --git a/doc/software-manual.tex b/doc/software-manual.tex
index 582dcbe4f6685daedad9b725df548eabd84be4b5..3b71317ac238fe468bfca2a594682e1bae4d997f 100644
--- a/doc/software-manual.tex
+++ b/doc/software-manual.tex
@@ -856,6 +856,12 @@ Enables harmonization of Gop first field couple.
 Add Access Unit Delimiter NAL units between all Access Units.
 \\
 
+\Option{EnablePictureHeaderInSliceHeader} &
+%\ShortOption{\None} &
+\Default{1} &
+Enable Picture Header to be signalled in Slice Header when encoding with single slice per picture.
+\\
+
 \Option{ScalingRatioHor} &
 %\ShortOption{\None} &
 \Default{1.0} &
@@ -1277,6 +1283,12 @@ $}
 \end{displaymath}
 \\
 
+\Option{Log2ParallelMergeLevel} &
+%\ShortOption{\None} &
+\Default{2} &
+Defines the SPS-derived Log2ParallelMergeLevel variable.
+\\
+
 \Option{MaxNumMergeCand} &
 %\ShortOption{\None} &
 \Default{5} &
@@ -2233,6 +2245,18 @@ switched at CTB level. Set to 1 to disable alternative chroma filters.
 Value shall be in the range 1..8.
 \\
 
+\Option{CCALF} &
+%\ShortOption{\None} &
+\Default{true} &
+Enables cross-component ALF.
+\\
+
+\Option{CCALFQpTh} &
+%\ShortOption{\None} &
+\Default{37} &
+QP threshold above which the encoder reduces cross-component ALF usage.
+\\
+
 \Option{SMVD} &
 %\ShortOption{\None} &
 \Default{false} &
diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp
index 69d4b1f7c4d22bd4d197ee0aeccda4890f1b4a79..b6584f0754dd08616524ea3096dae8904859a3eb 100644
--- a/source/App/DecoderApp/DecApp.cpp
+++ b/source/App/DecoderApp/DecApp.cpp
@@ -282,6 +282,12 @@ uint32_t DecApp::decode()
 bool DecApp::deriveOutputLayerSet()
 {
   int vps_max_layers_minus1 = m_cDecLib.getVPS()->getMaxLayers() - 1;
+  if(m_iTargetOLS == - 1 || vps_max_layers_minus1 == 0)
+  {
+    m_targetDecLayerIdSet.clear();
+    return true;
+  }
+
   int TotalNumOlss = 0;
   int each_layer_is_an_ols_flag = m_cDecLib.getVPS()->getEachLayerIsAnOlsFlag();
   int ols_mode_idc = m_cDecLib.getVPS()->getOlsModeIdc();
@@ -492,8 +498,12 @@ bool DecApp::isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytest
           ret = true;
           finished = true;
           break;
-        
+
+#if JVET_Q0775_PH_IN_SH
+        // NUT that may be the start of a new picture - check first bit in slice header
+#else
         // NUT that are not the start of a new picture
+#endif
         case NAL_UNIT_CODED_SLICE_TRAIL:
         case NAL_UNIT_CODED_SLICE_STSA:
         case NAL_UNIT_CODED_SLICE_RASL:
@@ -507,6 +517,13 @@ bool DecApp::isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytest
         case NAL_UNIT_CODED_SLICE_GDR:
         case NAL_UNIT_RESERVED_IRAP_VCL_11:
         case NAL_UNIT_RESERVED_IRAP_VCL_12:
+#if JVET_Q0775_PH_IN_SH
+          ret = checkPictureHeaderInSliceHeaderFlag(nalu);
+          finished = true;
+          break;
+
+        // NUT that are not the start of a new picture
+#endif
         case NAL_UNIT_EOS:
         case NAL_UNIT_EOB:
         case NAL_UNIT_SUFFIX_APS:
diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 77f765178b1b70b789850c6e9c59035a7721233f..f66a4fb1273339cee97d5608d522d50dec4ebb82 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -212,6 +212,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setNoPartitionConstraintsOverrideConstraintFlag      ( !m_SplitConsOverrideEnabledFlag );
   m_cEncLib.setNoSaoConstraintFlag                               ( !m_bUseSAO );
   m_cEncLib.setNoAlfConstraintFlag                               ( !m_alf );
+#if JVET_Q0795_CCALF
+  m_cEncLib.setNoAlfConstraintFlag                               ( !m_ccalf );
+#endif
   m_cEncLib.setNoRefWraparoundConstraintFlag                     ( m_bNoRefWraparoundConstraintFlag );
   m_cEncLib.setNoTemporalMvpConstraintFlag                       ( m_TMVPModeId ? false : true );
   m_cEncLib.setNoSbtmvpConstraintFlag                            ( m_SubPuMvpMode ? false : true );
@@ -277,6 +280,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setPad                                               ( m_aiPad );
 
   m_cEncLib.setAccessUnitDelimiter                               ( m_AccessUnitDelimiter );
+#if JVET_Q0775_PH_IN_SH
+  m_cEncLib.setEnablePictureHeaderInSliceHeader                  ( m_enablePictureHeaderInSliceHeader );
+#endif
 
   m_cEncLib.setMaxTempLayer                                      ( m_maxTempLayer );
 
@@ -517,6 +523,11 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setUseWP                                             ( m_useWeightedPred     );
   m_cEncLib.setWPBiPred                                          ( m_useWeightedBiPred   );
 
+#if JVET_Q0297_MER
+  //====== Parallel Merge Estimation ========
+  m_cEncLib.setLog2ParallelMergeLevelMinus2(m_log2ParallelMergeLevel - 2);
+#endif
+
   //====== Tiles and Slices ========
   m_cEncLib.setNoPicPartitionFlag( !m_picPartitionFlag );
   if( m_picPartitionFlag )
@@ -755,6 +766,10 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setForceSingleSplitThread                            ( m_forceSplitSequential );
 #endif
   m_cEncLib.setUseALF                                            ( m_alf );
+#if JVET_Q0795_CCALF
+  m_cEncLib.setUseCCALF                                          ( m_ccalf );
+  m_cEncLib.setCCALFQpThreshold                                  ( m_ccalfQpThreshold );
+#endif
   m_cEncLib.setLmcs                                              ( m_lmcsEnabled );
   m_cEncLib.setReshapeSignalType                                 ( m_reshapeSignalType );
   m_cEncLib.setReshapeIntraCMD                                   ( m_intraCMD );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index cdad7cff4d66dfd3bc7e3c999f4ffeb9b2a050e5..19e2ed64d039068ce96a2f1eca9a9daae5b618cb 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -87,6 +87,9 @@ EncAppCfg::EncAppCfg()
 , m_noPartitionConstraintsOverrideConstraintFlag(false)
 , m_bNoSaoConstraintFlag(false)
 , m_bNoAlfConstraintFlag(false)
+#if JVET_Q0795_CCALF
+, m_noCCAlfConstraintFlag(false)
+#endif
 , m_bNoRefWraparoundConstraintFlag(false)
 , m_bNoTemporalMvpConstraintFlag(false)
 , m_bNoSbtmvpConstraintFlag(false)
@@ -804,6 +807,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("ConfWinTop",                                      m_confWinTop,                                         0, "Top offset for window conformance mode 3")
   ("ConfWinBottom",                                   m_confWinBottom,                                      0, "Bottom offset for window conformance mode 3")
   ("AccessUnitDelimiter",                             m_AccessUnitDelimiter,                            false, "Enable Access Unit Delimiter NALUs")
+#if JVET_Q0775_PH_IN_SH
+  ("EnablePictureHeaderInSliceHeader",                m_enablePictureHeaderInSliceHeader,                true, "Enable Picture Header in Slice Header")
+#endif
   ("FrameRate,-fr",                                   m_iFrameRate,                                         0, "Frame rate")
   ("FrameSkip,-fs",                                   m_FrameSkip,                                         0u, "Number of frames to skip at start of input YUV")
   ("TemporalSubsampleRatio,-ts",                      m_temporalSubsampleRatio,                            1u, "Temporal sub-sample ratio when reading input YUV")
@@ -1130,6 +1136,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("WeightedPredP,-wpP",                              m_useWeightedPred,                                false, "Use weighted prediction in P slices")
   ("WeightedPredB,-wpB",                              m_useWeightedBiPred,                              false, "Use weighted (bidirectional) prediction in B slices")
   ("WeightedPredMethod,-wpM",                         tmpWeightedPredictionMethod, int(WP_PER_PICTURE_WITH_SIMPLE_DC_COMBINED_COMPONENT), "Weighted prediction method")
+#if JVET_Q0297_MER
+  ("Log2ParallelMergeLevel",                          m_log2ParallelMergeLevel,                            2u, "Parallel merge estimation region")
+#endif
   ("WaveFrontSynchro",                                m_entropyCodingSyncEnabledFlag,                   false, "0: entropy coding sync disabled; 1 entropy coding sync enabled")
   ("ScalingList",                                     m_useScalingListId,                    SCALING_LIST_OFF, "0/off: no scaling list, 1/default: default scaling lists, 2/file: scaling lists specified in ScalingListFile")
   ("ScalingListFile",                                 m_scalingListFileName,                       string(""), "Scaling list file name. Use an empty string to produce help.")
@@ -1357,7 +1366,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("NumWppExtraLines",                                m_numWppExtraLines,                           0, "Number of additional wpp lines to switch when threads are blocked")
   ("DebugCTU",                                        m_debugCTU,                                  -1, "If DebugBitstream is present, load frames up to this POC from this bitstream. Starting with DebugPOC-frame at CTUline containin debug CTU.")
   ("EnsureWppBitEqual",                               m_ensureWppBitEqual,                      false, "Ensure the results are equal to results with WPP-style parallelism, even if WPP is off")
-  ( "ALF",                                             m_alf,                                    true, "Adpative Loop Filter\n" )
+  ( "ALF",                                             m_alf,                                    true, "Adaptive Loop Filter\n" )
+#if JVET_Q0795_CCALF
+  ( "CCALF",                                           m_ccalf,                                  true, "Cross-component Adaptive Loop Filter" )
+  ( "CCALFQpTh",                                       m_ccalfQpThreshold,                         37, "QP threshold above which encoder reduces CCALF usage")
+#endif
   ( "ScalingRatioHor",                                m_scalingRatioHor,                          1.0, "Scaling ratio in hor direction" )
   ( "ScalingRatioVer",                                m_scalingRatioVer,                          1.0, "Scaling ratio in ver direction" )
   ( "FractionNumFrames",                              m_fractionOfFrames,                         1.0, "Encode a fraction of the specified in FramesToBeEncoded frames" )
@@ -2533,6 +2546,12 @@ bool EncAppCfg::xCheckParameter()
   }
 
 
+#if JVET_Q0795_CCALF
+  if (!m_alf)
+  {
+    xConfirmPara( m_ccalf, "CCALF cannot be enabled when ALF is disabled" );
+  }
+#endif
 
 
   xConfirmPara( m_iSourceWidth  % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Picture width must be an integer multiple of the specified chroma subsampling");
@@ -3405,7 +3424,9 @@ bool EncAppCfg::xCheckParameter()
       xConfirmPara( m_gcmpSEIGuardBandSamplesMinus1 < 0 || m_gcmpSEIGuardBandSamplesMinus1 > 15, "SEIGcmpGuardBandSamplesMinus1 must be in the range of 0 to 15");
     }
   }
-
+#if JVET_Q0297_MER
+  xConfirmPara(m_log2ParallelMergeLevel < 2, "Log2ParallelMergeLevel should be larger than or equal to 2");
+#endif
 #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI
   xConfirmPara(m_preferredTransferCharacteristics > 255, "transfer_characteristics_idc should not be greater than 255.");
 #endif
@@ -3422,6 +3443,9 @@ bool EncAppCfg::xCheckParameter()
 #endif
 
   xConfirmPara(m_useBDPCM < 0 || m_useBDPCM > 2, "BDPCM must be in range 0..2");
+#if JVET_Q0820_ACT
+  xConfirmPara(m_useColorTrans && (m_log2MaxTbSize == 6), "Log2MaxTbSize must be less than 6 when ACT is enabled, otherwise ACT needs to be disabled");
+#endif
 
 #undef xConfirmPara
   return check_failed;
@@ -3604,9 +3628,15 @@ void EncAppCfg::xPrintParameter()
   msg( VERBOSE, "MCTS:%d ", m_MCTSEncConstraint );
   msg( VERBOSE, "SAO:%d ", (m_bUseSAO)?(1):(0));
   msg( VERBOSE, "ALF:%d ", m_alf ? 1 : 0 );
+#if JVET_Q0795_CCALF
+  msg( VERBOSE, "CCALF:%d ", m_ccalf ? 1 : 0 );
+#endif
 
   msg( VERBOSE, "WPP:%d ", (int)m_useWeightedPred);
   msg( VERBOSE, "WPB:%d ", (int)m_useWeightedBiPred);
+#if JVET_Q0297_MER
+  msg( VERBOSE, "PME:%d ", m_log2ParallelMergeLevel);
+#endif
   const int iWaveFrontSubstreams = m_entropyCodingSyncEnabledFlag ? (m_iSourceHeight + m_uiMaxCUHeight - 1) / m_uiMaxCUHeight : 1;
   msg( VERBOSE, " WaveFrontSynchro:%d WaveFrontSubstreams:%d", m_entropyCodingSyncEnabledFlag?1:0, iWaveFrontSubstreams);
   msg( VERBOSE, " ScalingList:%d ", m_useScalingListId );
@@ -3654,7 +3684,11 @@ void EncAppCfg::xPrintParameter()
     msg(VERBOSE, "MmvdDisNum:%d ", m_MmvdDisNum);
     msg(VERBOSE, "JointCbCr:%d ", m_JointCbCrMode);
   }
+#if JVET_Q0820_ACT
+  m_useColorTrans = (m_chromaFormatIDC == CHROMA_444) ? m_useColorTrans : 0u;
+#else
   m_useColorTrans = (m_chromaFormatIDC == CHROMA_444 && m_costMode != COST_LOSSLESS_CODING) ? m_useColorTrans : 0u;
+#endif
   msg(VERBOSE, "ACT:%d ", m_useColorTrans);
     m_PLTMode = ( m_chromaFormatIDC == CHROMA_444) ? m_PLTMode : 0u;
     msg(VERBOSE, "PLT:%d ", m_PLTMode);
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index 4ce37e402f737e4f6cecb69d29b34f4c1b5b426d..ead8d9d727e78d39b471bb8158bd101ff5321d21 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -115,6 +115,9 @@ protected:
   int       m_framesToBeEncoded;                              ///< number of encoded frames
   int       m_aiPad[2];                                       ///< number of padded pixels for width and height
   bool      m_AccessUnitDelimiter;                            ///< add Access Unit Delimiter NAL units
+#if JVET_Q0775_PH_IN_SH
+  bool      m_enablePictureHeaderInSliceHeader;               ///< Enable Picture Header in Slice Header
+#endif
   InputColourSpaceConversion m_inputColourSpaceConvert;       ///< colour space conversion to apply to input video
   bool      m_snrInternalColourSpace;                       ///< if true, then no colour space conversion is applied for snr calculation, otherwise inverse of input is applied.
   bool      m_outputInternalColourSpace;                    ///< if true, then no colour space conversion is applied for reconstructed video, otherwise inverse of input is applied.
@@ -137,6 +140,9 @@ protected:
   bool      m_noPartitionConstraintsOverrideConstraintFlag;
   bool      m_bNoSaoConstraintFlag;
   bool      m_bNoAlfConstraintFlag;
+#if JVET_Q0795_CCALF
+  bool      m_noCCAlfConstraintFlag;
+#endif
   bool      m_bNoRefWraparoundConstraintFlag;
   bool      m_bNoTemporalMvpConstraintFlag;
   bool      m_bNoSbtmvpConstraintFlag;
@@ -581,6 +587,9 @@ protected:
   bool      m_useWeightedBiPred;                  ///< Use of bi-directional weighted prediction in B slices
   WeightedPredictionMethod m_weightedPredictionMethod;
 
+#if JVET_Q0297_MER
+  uint32_t      m_log2ParallelMergeLevel;                         ///< Parallel merge estimation region
+#endif
   uint32_t      m_maxNumMergeCand;                                ///< Max number of merge candidates
   uint32_t      m_maxNumAffineMergeCand;                          ///< Max number of affine merge candidates
   uint32_t      m_maxNumTriangleCand;
@@ -664,6 +673,10 @@ protected:
   bool        m_forceDecodeBitstream1;
 
   bool        m_alf;                                          ///< Adaptive Loop Filter
+#if JVET_Q0795_CCALF
+  bool        m_ccalf;
+  int         m_ccalfQpThreshold;
+#endif
 
   double      m_scalingRatioHor;
   double      m_scalingRatioVer;
diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
index 998041f9ca20acb7d7fec5f48a9f287a365765f6..b1ef4b056c62ed8c62b353fd8829ad0cf7703eeb 100644
--- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
+++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp
@@ -63,6 +63,9 @@ AdaptiveLoopFilter::AdaptiveLoopFilter()
   }
 
   m_deriveClassificationBlk = deriveClassificationBlk;
+#if JVET_Q0795_CCALF
+  m_filterCcAlf = filterBlkCcAlf<CC_ALF>;
+#endif
   m_filter5x5Blk = filterBlk<ALF_FILTER_5>;
   m_filter7x7Blk = filterBlk<ALF_FILTER_7>;
 
@@ -285,6 +288,47 @@ const int AdaptiveLoopFilter::m_classToFilterMapping[NUM_FIXED_FILTER_SETS][MAX_
   { 16,  31,  32,  15,  60,  30,   4,  17,  19,  25,  22,  20,   4,  53,  19,  21,  22,  46,  25,  55,  26,  48,  63,  58,  55 },
 };
 
+#if JVET_Q0795_CCALF
+void AdaptiveLoopFilter::applyCcAlfFilter(CodingStructure &cs, ComponentID compID, const PelBuf &dstBuf,
+                                          const PelUnitBuf &recYuvExt, uint8_t *filterControl,
+                                          const short filterSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF],
+                                          const int   selectedFilterIdx)
+{
+  int ctuIdx = 0;
+  for( int yPos = 0; yPos < m_picHeight; yPos += m_maxCUHeight )
+  {
+    for( int xPos = 0; xPos < m_picWidth; xPos += m_maxCUWidth )
+    {
+      const int width = ( xPos + m_maxCUWidth > m_picWidth ) ? ( m_picWidth - xPos ) : m_maxCUWidth;
+      const int height = ( yPos + m_maxCUHeight > m_picHeight ) ? ( m_picHeight - yPos ) : m_maxCUHeight;
+      const UnitArea area( m_chromaFormat, Area( xPos, yPos, width, height ) );
+      const int chromaScaleX = getComponentScaleX( compID, m_chromaFormat );
+      const int chromaScaleY = getComponentScaleY( compID, m_chromaFormat );
+
+      Area blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY);
+      Area blkSrc(xPos, yPos, width, height);
+
+      int filterIdx =
+        (filterControl == nullptr)
+          ? selectedFilterIdx
+          : filterControl[(yPos >> cs.pcv->maxCUHeightLog2) * cs.pcv->widthInCtus + (xPos >> cs.pcv->maxCUWidthLog2)];
+      bool skipFiltering = (filterControl != nullptr && filterIdx == 0) ? true : false;
+      if (!skipFiltering)
+      {
+        if (filterControl != nullptr)
+          filterIdx--;
+
+        const int16_t *filterCoeff = filterSet[filterIdx];
+
+        m_filterCcAlf(dstBuf, recYuvExt, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight,
+                      m_alfVBLumaPos);
+      }
+      ctuIdx++;
+    }
+  }
+}
+#endif
+
 void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs)
 {
 
@@ -342,6 +386,12 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs)
       for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )
       {
         ctuEnableFlag |= m_ctuEnableFlag[compIdx][ctuIdx] > 0;
+#if JVET_Q0795_CCALF
+        if (cu->slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1])
+        {
+          ctuEnableFlag |= m_ccAlfFilterControl[compIdx - 1][ctuIdx] > 0;
+        }
+#endif
       }
       int rasterSliceAlfPad = 0;
       if( ctuEnableFlag && isCrossedByVirtualBoundaries( cs, xPos, yPos, width, height, clipTop, clipBottom, clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos, rasterSliceAlfPad ) )
@@ -417,6 +467,24 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs)
                   , m_alfVBChmaCTUHeight
                    , m_alfVBChmaPos );
               }
+#if JVET_Q0795_CCALF
+              if (cu->slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1])
+              {
+                const int filterIdx = m_ccAlfFilterControl[compIdx - 1][ctuIdx];
+
+                if (filterIdx != 0)
+                {
+                  const Area blkSrc(0, 0, w >> chromaScaleX, h >> chromaScaleY);
+                  Area       blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX,
+                              height >> chromaScaleY);
+
+                  const int16_t *filterCoeff = m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1][filterIdx - 1];
+
+                  m_filterCcAlf(recYuv.get(compID), tmpYuv, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs,
+                                m_alfVBLumaCTUHeight, m_alfVBLumaPos);
+                }
+              }
+#endif
             }
 
             xStart = xEnd;
@@ -427,46 +495,63 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs)
       }
       else
       {
-      const UnitArea area( cs.area.chromaFormat, Area( xPos, yPos, width, height ) );
-      if( m_ctuEnableFlag[COMPONENT_Y][ctuIdx] )
-      {
-        Area blk( xPos, yPos, width, height );
-        deriveClassification( m_classifier, tmpYuv.get( COMPONENT_Y ), blk, blk );
-        short filterSetIndex = alfCtuFilterIndex[ctuIdx];
-        short *coeff;
-        short *clip;
-        if (filterSetIndex >= NUM_FIXED_FILTER_SETS)
+        const UnitArea area( cs.area.chromaFormat, Area( xPos, yPos, width, height ) );
+        if( m_ctuEnableFlag[COMPONENT_Y][ctuIdx] )
         {
-          coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
-          clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
+          Area blk( xPos, yPos, width, height );
+          deriveClassification( m_classifier, tmpYuv.get( COMPONENT_Y ), blk, blk );
+          short filterSetIndex = alfCtuFilterIndex[ctuIdx];
+          short *coeff;
+          short *clip;
+          if (filterSetIndex >= NUM_FIXED_FILTER_SETS)
+          {
+            coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
+            clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS];
+          }
+          else
+          {
+            coeff = m_fixedFilterSetCoeffDec[filterSetIndex];
+            clip = m_clipDefault;
+          }
+          m_filter7x7Blk(m_classifier, recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs
+            , m_alfVBLumaCTUHeight
+            , m_alfVBLumaPos
+          );
         }
-        else
+
+        for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )
         {
-          coeff = m_fixedFilterSetCoeffDec[filterSetIndex];
-          clip = m_clipDefault;
-        }
-        m_filter7x7Blk(m_classifier, recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs
-          , m_alfVBLumaCTUHeight
-          , m_alfVBLumaPos
-        );
-      }
+          ComponentID compID = ComponentID( compIdx );
+          const int chromaScaleX = getComponentScaleX( compID, tmpYuv.chromaFormat );
+          const int chromaScaleY = getComponentScaleY( compID, tmpYuv.chromaFormat );
 
-      for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )
-      {
-        ComponentID compID = ComponentID( compIdx );
-        const int chromaScaleX = getComponentScaleX( compID, tmpYuv.chromaFormat );
-        const int chromaScaleY = getComponentScaleY( compID, tmpYuv.chromaFormat );
+          if (m_ctuEnableFlag[compIdx][ctuIdx])
+          {
+            Area    blk(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY);
+            uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx];
+            m_filter5x5Blk(m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num],
+                           m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight,
+                           m_alfVBChmaPos);
+          }
+#if JVET_Q0795_CCALF
+          if (cu->slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1])
+          {
+            const int filterIdx = m_ccAlfFilterControl[compIdx - 1][ctuIdx];
 
-        if( m_ctuEnableFlag[compIdx][ctuIdx] )
-        {
-          Area blk( xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY );
-          uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx];
-          m_filter5x5Blk(m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs
-            , m_alfVBChmaCTUHeight
-            , m_alfVBChmaPos);
+            if (filterIdx != 0)
+            {
+              Area blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY);
+              Area blkSrc(xPos, yPos, width, height);
+
+              const int16_t *filterCoeff = m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1][filterIdx - 1];
+
+              m_filterCcAlf(recYuv.get(compID), tmpYuv, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs,
+                            m_alfVBLumaCTUHeight, m_alfVBLumaPos);
+            }
+          }
+#endif
         }
       }
-      }
       ctuIdx++;
     }
   }
@@ -581,6 +666,10 @@ void AdaptiveLoopFilter::create( const int picWidth, const int picHeight, const
   m_numCTUsInWidth = ( m_picWidth / m_maxCUWidth ) + ( ( m_picWidth % m_maxCUWidth ) ? 1 : 0 );
   m_numCTUsInHeight = ( m_picHeight / m_maxCUHeight ) + ( ( m_picHeight % m_maxCUHeight ) ? 1 : 0 );
   m_numCTUsInPic = m_numCTUsInHeight * m_numCTUsInWidth;
+#if JVET_Q0795_CCALF
+  m_filterShapesCcAlf[0].push_back(AlfFilterShape(size_CC_ALF));
+  m_filterShapesCcAlf[1].push_back(AlfFilterShape(size_CC_ALF));
+#endif
   m_filterShapes[CHANNEL_TYPE_LUMA].push_back( AlfFilterShape( 7 ) );
   m_filterShapes[CHANNEL_TYPE_CHROMA].push_back( AlfFilterShape( 5 ) );
   m_alfVBLumaPos = m_maxCUHeight - ALF_VB_POS_ABOVE_CTUROW_LUMA;
@@ -657,6 +746,11 @@ void AdaptiveLoopFilter::create( const int picWidth, const int picHeight, const
     m_clipDefault[i] = m_alfClippingValues[CHANNEL_TYPE_LUMA][0];
   }
   m_created = true;
+
+#if JVET_Q0795_CCALF
+  m_ccAlfFilterControl[0] = new uint8_t[m_numCTUsInPic];
+  m_ccAlfFilterControl[1] = new uint8_t[m_numCTUsInPic];
+#endif
 }
 
 void AdaptiveLoopFilter::destroy()
@@ -678,6 +772,22 @@ void AdaptiveLoopFilter::destroy()
   m_filterShapes[CHANNEL_TYPE_LUMA].clear();
   m_filterShapes[CHANNEL_TYPE_CHROMA].clear();
   m_created = false;
+
+#if JVET_Q0795_CCALF
+  m_filterShapesCcAlf[0].clear();
+  m_filterShapesCcAlf[1].clear();
+  if ( m_ccAlfFilterControl[0] )
+  {
+    delete [] m_ccAlfFilterControl[0];
+    m_ccAlfFilterControl[0] = nullptr;
+  }
+
+  if ( m_ccAlfFilterControl[1] )
+  {
+    delete [] m_ccAlfFilterControl[1];
+    m_ccAlfFilterControl[1] = nullptr;
+  }
+#endif
 }
 
 void AdaptiveLoopFilter::deriveClassification( AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk )
@@ -1152,3 +1262,96 @@ void AdaptiveLoopFilter::filterBlk(AlfClassifier **classifier, const PelUnitBuf
     pImgYPad6 += srcStride2;
   }
 }
+
+#if JVET_Q0795_CCALF
+template<AlfFilterType filtTypeCcAlf>
+void AdaptiveLoopFilter::filterBlkCcAlf(const PelBuf &dstBuf, const CPelUnitBuf &recSrc, const Area &blkDst,
+                                        const Area &blkSrc, const ComponentID compId, const int16_t *filterCoeff,
+                                        const ClpRngs &clpRngs, CodingStructure &cs, int vbCTUHeight, int vbPos)
+{
+  CHECK(1 << floorLog2(vbCTUHeight) != vbCTUHeight, "Not a power of 2");
+
+  CHECK(!isChroma(compId), "Must be chroma");
+
+  const SPS*     sps           = cs.slice->getSPS();
+  ChromaFormat nChromaFormat   = sps->getChromaFormatIdc();
+  const int clsSizeY           = 4;
+  const int clsSizeX           = 4;
+  const int      startHeight        = blkDst.y;
+  const int      endHeight          = blkDst.y + blkDst.height;
+  const int      startWidth         = blkDst.x;
+  const int      endWidth           = blkDst.x + blkDst.width;
+  const int scaleX             = getComponentScaleX(compId, nChromaFormat);
+  const int scaleY             = getComponentScaleY(compId, nChromaFormat);
+
+  CHECK( startHeight % clsSizeY, "Wrong startHeight in filtering" );
+  CHECK( startWidth % clsSizeX, "Wrong startWidth in filtering" );
+  CHECK( ( endHeight - startHeight ) % clsSizeY, "Wrong endHeight in filtering" );
+  CHECK( ( endWidth - startWidth ) % clsSizeX, "Wrong endWidth in filtering" );
+
+  CPelBuf     srcBuf     = recSrc.get(COMPONENT_Y);
+  const int   lumaStride = srcBuf.stride;
+  const Pel * lumaPtr    = srcBuf.buf + blkSrc.y * lumaStride + blkSrc.x;
+
+  const int   chromaStride = dstBuf.stride;
+  Pel *       chromaPtr    = dstBuf.buf + blkDst.y * chromaStride + blkDst.x;
+
+  for( int i = 0; i < endHeight - startHeight; i += clsSizeY )
+  {
+    for( int j = 0; j < endWidth - startWidth; j += clsSizeX )
+    {
+      for( int ii = 0; ii < clsSizeY; ii++ )
+      {
+        int row       = ii;
+        int col       = j;
+        Pel *srcSelf  = chromaPtr + col + row * chromaStride;
+
+        int offset1 = lumaStride;
+        int offset2 = -lumaStride;
+        int offset3 = 2 * lumaStride;
+        row <<= scaleY;
+        col <<= scaleX;
+        const Pel *srcCross = lumaPtr + col + row * lumaStride;
+
+        int pos = ((startHeight + i + ii) << scaleY) & (vbCTUHeight - 1);
+        if (pos == (vbPos - 2) || pos == (vbPos + 1))
+        {
+          offset3 = offset1;
+        }
+        else if (pos == (vbPos - 1) || pos == vbPos)
+        {
+          offset1 = 0;
+          offset2 = 0;
+          offset3 = 0;
+        }
+
+        for (int jj = 0; jj < clsSizeX; jj++)
+        {
+          const int jj2     = (jj << scaleX);
+          const int offset0 = 0;
+
+          int sum = 0;
+          const Pel currSrcCross = srcCross[offset0 + jj2];
+          sum += filterCoeff[0] * (srcCross[offset2 + jj2    ] - currSrcCross);
+          sum += filterCoeff[1] * (srcCross[offset0 + jj2 - 1] - currSrcCross);
+          sum += filterCoeff[2] * (srcCross[offset0 + jj2 + 1] - currSrcCross);
+          sum += filterCoeff[3] * (srcCross[offset1 + jj2 - 1] - currSrcCross);
+          sum += filterCoeff[4] * (srcCross[offset1 + jj2    ] - currSrcCross);
+          sum += filterCoeff[5] * (srcCross[offset1 + jj2 + 1] - currSrcCross);
+          sum += filterCoeff[6] * (srcCross[offset3 + jj2    ] - currSrcCross);
+
+          sum = (sum + ((1 << m_scaleBits ) >> 1)) >> m_scaleBits;
+          const int offset = 1 << clpRngs.comp[compId].bd >> 1;
+          sum = ClipPel(sum + offset, clpRngs.comp[compId]) - offset;
+          sum += srcSelf[jj];
+          srcSelf[jj] = ClipPel(sum, clpRngs.comp[compId]);
+        }
+      }
+    }
+
+    chromaPtr += chromaStride * clsSizeY;
+
+    lumaPtr += lumaStride * clsSizeY << getComponentScaleY(compId, nChromaFormat);
+  }
+}
+#endif
diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.h b/source/Lib/CommonLib/AdaptiveLoopFilter.h
index f93fd8e6c72fb1a6fc1b391c4da527acf33945cd..39d1731146ded03a37db884b96724846ba77b4ac 100644
--- a/source/Lib/CommonLib/AdaptiveLoopFilter.h
+++ b/source/Lib/CommonLib/AdaptiveLoopFilter.h
@@ -91,6 +91,13 @@ public:
                                       const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, const int shift,
                                       const int vbCTUHeight, int vbPos);
   void deriveClassification( AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk );
+#if JVET_Q0795_CCALF
+  template<AlfFilterType filtTypeCcAlf>
+  static void filterBlkCcAlf(const PelBuf &dstBuf, const CPelUnitBuf &recSrc, const Area &blkDst, const Area &blkSrc,
+                             const ComponentID compId, const int16_t *filterCoeff, const ClpRngs &clpRngs,
+                             CodingStructure &cs, int vbCTUHeight, int vbPos);
+#endif
+
   template<AlfFilterType filtType>
   static void filterBlk(AlfClassifier **classifier, const PelUnitBuf &recDst, const CPelUnitBuf &recSrc,
                         const Area &blkDst, const Area &blk, const ComponentID compId, const short *filterSet,
@@ -100,6 +107,17 @@ public:
                                     const Area &blkDst, const Area &blk, const int shift, const int vbCTUHeight,
                                     int vbPos);
 
+#if JVET_Q0795_CCALF
+  void (*m_filterCcAlf)(const PelBuf &dstBuf, const CPelUnitBuf &recSrc, const Area &blkDst, const Area &blkSrc,
+                        const ComponentID compId, const int16_t *filterCoeff, const ClpRngs &clpRngs,
+                        CodingStructure &cs, int vbCTUHeight, int vbPos);
+  void applyCcAlfFilter(CodingStructure &cs, ComponentID compID, const PelBuf &dstBuf, const PelUnitBuf &recYuvExt,
+                        uint8_t *   filterControl,
+                        const short filterSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF],
+                        const int   selectedFilterIdx);
+  CcAlfFilterParam &getCcAlfFilterParam() { return m_ccAlfFilterParam; }
+  uint8_t* getCcAlfControlIdc(const ComponentID compID)   { return m_ccAlfFilterControl[compID-1]; }
+#endif
   void (*m_filter5x5Blk)(AlfClassifier **classifier, const PelUnitBuf &recDst, const CPelUnitBuf &recSrc,
                          const Area &blkDst, const Area &blk, const ComponentID compId, const short *filterSet,
                          const short *fClipSet, const ClpRng &clpRng, CodingStructure &cs, const int vbCTUHeight,
@@ -117,6 +135,11 @@ public:
 
 protected:
   bool isCrossedByVirtualBoundaries( const CodingStructure& cs, const int xPos, const int yPos, const int width, const int height, bool& clipTop, bool& clipBottom, bool& clipLeft, bool& clipRight, int& numHorVirBndry, int& numVerVirBndry, int horVirBndryPos[], int verVirBndryPos[], int& rasterSliceAlfPad );
+#if JVET_Q0795_CCALF
+  static constexpr int   m_scaleBits = 7; // 8-bits
+  CcAlfFilterParam       m_ccAlfFilterParam;
+  uint8_t*               m_ccAlfFilterControl[2];
+#endif
   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];
@@ -127,6 +150,9 @@ protected:
   short                        m_chromaCoeffFinal[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF];
   AlfParam*                    m_alfParamChroma;
   Pel                          m_alfClippingValues[MAX_NUM_CHANNEL_TYPE][MaxAlfNumClippingValues];
+#if JVET_Q0795_CCALF
+  std::vector<AlfFilterShape>  m_filterShapesCcAlf[2];
+#endif
   std::vector<AlfFilterShape>  m_filterShapes[MAX_NUM_CHANNEL_TYPE];
   AlfClassifier**              m_classifier;
   short                        m_coeffFinal[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF];
diff --git a/source/Lib/CommonLib/AlfParameters.h b/source/Lib/CommonLib/AlfParameters.h
index abaef3a4968ab6d5dd6535656592652056abe129..45fa9b275ddc919a153392eff223b38aa0d7c6d4 100644
--- a/source/Lib/CommonLib/AlfParameters.h
+++ b/source/Lib/CommonLib/AlfParameters.h
@@ -48,9 +48,17 @@ enum AlfFilterType
 {
   ALF_FILTER_5,
   ALF_FILTER_7,
+#if JVET_Q0795_CCALF
+  CC_ALF,
+#endif
   ALF_NUM_OF_FILTER_TYPES
 };
 
+
+#if JVET_Q0795_CCALF
+static const int size_CC_ALF = -1;
+#endif
+
 struct AlfFilterShape
 {
   AlfFilterShape( int size )
@@ -97,6 +105,16 @@ struct AlfFilterShape
 
       filterType = ALF_FILTER_7;
     }
+#if JVET_Q0795_CCALF
+    else if (size == size_CC_ALF)
+    {
+      size = 4;
+      filterLength = 8;
+      numCoeff = 8;
+      filterSize = 8;
+      filterType   = CC_ALF;
+    }
+#endif
     else
     {
       filterType = ALF_NUM_OF_FILTER_TYPES;
@@ -231,6 +249,43 @@ struct AlfParam
   }
 };
 
+#if JVET_Q0795_CCALF
+struct CcAlfFilterParam
+{
+  bool    ccAlfFilterEnabled[2];
+  bool    ccAlfFilterIdxEnabled[2][MAX_NUM_CC_ALF_FILTERS];
+  uint8_t ccAlfFilterCount[2];
+  short   ccAlfCoeff[2][MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF];
+  int     newCcAlfFilter[2];
+  int     numberValidComponents;
+  CcAlfFilterParam()
+  {
+    reset();
+  }
+  void reset()
+  {
+    std::memset( ccAlfFilterEnabled, false, sizeof( ccAlfFilterEnabled ) );
+    std::memset( ccAlfFilterIdxEnabled, false, sizeof( ccAlfFilterIdxEnabled ) );
+    std::memset( ccAlfCoeff, 0, sizeof( ccAlfCoeff ) );
+    ccAlfFilterCount[0] = ccAlfFilterCount[1] = MAX_NUM_CC_ALF_FILTERS;
+    numberValidComponents = 3;
+    newCcAlfFilter[0] = newCcAlfFilter[1] = 0;
+  }
+  const CcAlfFilterParam& operator = ( const CcAlfFilterParam& src )
+  {
+    std::memcpy( ccAlfFilterEnabled, src.ccAlfFilterEnabled, sizeof( ccAlfFilterEnabled ) );
+    std::memcpy( ccAlfFilterIdxEnabled, src.ccAlfFilterIdxEnabled, sizeof( ccAlfFilterIdxEnabled ) );
+    std::memcpy( ccAlfCoeff, src.ccAlfCoeff, sizeof( ccAlfCoeff ) );
+    ccAlfFilterCount[0] = src.ccAlfFilterCount[0];
+    ccAlfFilterCount[1] = src.ccAlfFilterCount[1];
+    numberValidComponents = src.numberValidComponents;
+    newCcAlfFilter[0] = src.newCcAlfFilter[0];
+    newCcAlfFilter[1] = src.newCcAlfFilter[1];
+
+    return *this;
+  }
+};
+#endif
 //! \}
 
 #endif  // end of #ifndef  __ALFPARAMETERS__
diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp
index e1f967f14fef717a85f2c5904e8cc6377feb69eb..8320dbe7c8ae76e93689d0b7b581b5681bd9696d 100644
--- a/source/Lib/CommonLib/Buffer.cpp
+++ b/source/Lib/CommonLib/Buffer.cpp
@@ -779,7 +779,11 @@ const CPelUnitBuf PelStorage::getBuf( const UnitArea &unit ) const
 }
 
 template<>
+#if JVET_Q0820_ACT
+void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward, const ClpRng& clpRng)
+#else
 void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward)
+#endif
 {
   const Pel* pOrg0 = bufs[COMPONENT_Y].buf;
   const Pel* pOrg1 = bufs[COMPONENT_Cb].buf;
@@ -793,6 +797,9 @@ void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forwa
 
   int width = bufs[COMPONENT_Y].width;
   int height = bufs[COMPONENT_Y].height;
+#if JVET_Q0820_ACT
+  int maxAbsclipBD = (1 << (clpRng.bd + 1)) - 1;
+#endif
   int r, g, b;
   int y0, cg, co;
 
@@ -810,12 +817,21 @@ void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forwa
           g = pOrg0[x];
           b = pOrg1[x];
 
+#if JVET_Q0820_ACT
+          co = r - b;
+          int t = b + (co >> 1);
+          cg = g - t;
+          pDst0[x] = t + (cg >> 1);
+          pDst1[x] = cg;
+          pDst2[x] = co;
+#else
           pDst0[x] = (g << 1) + r + b;
           pDst1[x] = (g << 1) - r - b;
           pDst2[x] = ((r - b) << 1);
           pDst0[x] = (pDst0[x] + 2) >> 2;
           pDst1[x] = (pDst1[x] + 2) >> 2;
           pDst2[x] = (pDst2[x] + 2) >> 2;
+#endif
         }
         pOrg0 += strideOrg;
         pOrg1 += strideOrg;
@@ -835,9 +851,20 @@ void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forwa
           cg = pOrg1[x];
           co = pOrg2[x];
 
+#if JVET_Q0820_ACT
+          y0 = Clip3((-maxAbsclipBD - 1), maxAbsclipBD, y0);
+          cg = Clip3((-maxAbsclipBD - 1), maxAbsclipBD, cg);
+          co = Clip3((-maxAbsclipBD - 1), maxAbsclipBD, co);
+
+          int t = y0 - (cg >> 1);
+          pDst0[x] = cg + t;
+          pDst1[x] = t - (co >> 1);
+          pDst2[x] = co + pDst1[x];
+#else
           pDst0[x] = (y0 + cg);
           pDst1[x] = (y0 - cg - co);
           pDst2[x] = (y0 - cg + co);
+#endif
         }
 
         pOrg0 += strideOrg;
diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h
index 9b461389d48aa12dc181aa7d4dac732a7caca5c2..0fbd97a5edcceb94333a08174c9ad91a48e0a555 100644
--- a/source/Lib/CommonLib/Buffer.h
+++ b/source/Lib/CommonLib/Buffer.h
@@ -779,7 +779,11 @@ struct UnitBuf
 
         UnitBuf<      T> subBuf (const UnitArea& subArea);
   const UnitBuf<const T> subBuf (const UnitArea& subArea) const;
+#if JVET_Q0820_ACT
+  void colorSpaceConvert(const UnitBuf<T> &other, const bool forward, const ClpRng& clpRng);
+#else
   void colorSpaceConvert(const UnitBuf<T> &other, const bool forward);
+#endif
 };
 
 typedef UnitBuf<      Pel>  PelUnitBuf;
@@ -880,13 +884,21 @@ void UnitBuf<T>::addAvg(const UnitBuf<const T> &other1, const UnitBuf<const T> &
 }
 
 template<typename T>
+#if JVET_Q0820_ACT
+void UnitBuf<T>::colorSpaceConvert(const UnitBuf<T> &other, const bool forward, const ClpRng& clpRng)
+#else
 void UnitBuf<T>::colorSpaceConvert(const UnitBuf<T> &other, const bool forward)
+#endif
 {
   THROW("Type not supported");
 }
 
 template<>
+#if JVET_Q0820_ACT
+void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward, const ClpRng& clpRng);
+#else
 void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward);
+#endif
 
 template<typename T>
 void UnitBuf<T>::extendSingleBorderPel()
diff --git a/source/Lib/CommonLib/CodingStatistics.h b/source/Lib/CommonLib/CodingStatistics.h
index 375ed6ec212e215c9472c0daca7185bde3b8a6f7..59b610717e1fd61074fa6cb2c88217775b98f38b 100644
--- a/source/Lib/CommonLib/CodingStatistics.h
+++ b/source/Lib/CommonLib/CodingStatistics.h
@@ -117,6 +117,9 @@ enum CodingStatisticsType
   STATS__CABAC_BITS__MULTI_REF_LINE,
   STATS__CABAC_BITS__SYMMVD_FLAG,
   STATS__CABAC_BITS__BDPCM_MODE,
+#if JVET_Q0795_CCALF
+  STATS__CABAC_BITS__CROSS_COMPONENT_ALF_BLOCK_LEVEL_IDC,
+#endif
   STATS__TOOL_TOTAL_FRAME,// This is a special case and is not included in the report.
   STATS__TOOL_AFF,
   STATS__TOOL_EMT,
@@ -209,6 +212,9 @@ static inline const char* getName(CodingStatisticsType name)
     "CABAC_BITS__MULTI_REF_LINE",
     "CABAC_BITS__SYMMVD_FLAG",
     "CABAC_BITS__BDPCM_MODE",
+#if JVET_Q0795_CCALF
+    "CABAC_BITS__CROSS_COMPONENT_ALF_BLOCK_LEVEL_IDC",
+#endif
     "TOOL_FRAME",
     "TOOL_AFFINE",
     "TOOL_EMT",
diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp
index 336daef4fdb05d365d34eff86c583b47ac09e3c8..b9282a2e30d3d9393430d87f96d3e6e166b54300 100644
--- a/source/Lib/CommonLib/CodingStructure.cpp
+++ b/source/Lib/CommonLib/CodingStructure.cpp
@@ -908,6 +908,31 @@ void CodingStructure::reorderPrevPLT(PLTBuf& prevPLT, uint8_t curPLTSize[MAX_NUM
   }
 }
 
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+void CodingStructure::setPrevPLT(PLTBuf predictor)
+{
+  for (int comp = 0; comp < MAX_NUM_CHANNEL_TYPE; comp++)
+  {
+    prevPLT.curPLTSize[comp] = predictor.curPLTSize[comp];
+  }
+  for (int comp = 0; comp < MAX_NUM_COMPONENT; comp++)
+  {
+    memcpy(prevPLT.curPLT[comp], predictor.curPLT[comp], MAXPLTPREDSIZE * sizeof(Pel));
+  }
+}
+void CodingStructure::storePrevPLT(PLTBuf& predictor)
+{
+  for (int comp = 0; comp < MAX_NUM_CHANNEL_TYPE; comp++)
+  {
+    predictor.curPLTSize[comp] = prevPLT.curPLTSize[comp];
+  }
+  for (int comp = 0; comp < MAX_NUM_COMPONENT; comp++)
+  {
+    memcpy(predictor.curPLT[comp], prevPLT.curPLT[comp], MAXPLTPREDSIZE * sizeof(Pel));
+  }
+}
+#endif
+
 void CodingStructure::rebindPicBufs()
 {
   CHECK( parent, "rebindPicBufs can only be used for the top level CodingStructure" );
diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h
index 317e330ba33e86f62432527e1ab5182a0c0ad072..227a90d21933e8d575862c3da3e295f0b4ac9f70 100644
--- a/source/Lib/CommonLib/CodingStructure.h
+++ b/source/Lib/CommonLib/CodingStructure.h
@@ -202,7 +202,10 @@ public:
   PLTBuf prevPLT;
   void resetPrevPLT(PLTBuf& prevPLT);
   void reorderPrevPLT(PLTBuf& prevPLT, uint8_t curPLTSize[MAX_NUM_CHANNEL_TYPE], Pel curPLT[MAX_NUM_COMPONENT][MAXPLTSIZE], bool reuseflag[MAX_NUM_CHANNEL_TYPE][MAXPLTPREDSIZE], uint32_t compBegin, uint32_t numComp, bool jointPLT);
-
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+  void setPrevPLT(PLTBuf predictor);
+  void storePrevPLT(PLTBuf& predictor);
+#endif
 private:
 
   // needed for TU encoding
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index f24085c106c07b6c6028cd2bd81a9fcccf32d1f8..fb83cf5b8b4b13bc96acbccc099206c2aa30b324 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -187,6 +187,12 @@ static const int MAX_NUM_ALF_CHROMA_COEFF    =                      7;
 static const int MAX_ALF_FILTER_LENGTH       =                      7;
 static const int MAX_NUM_ALF_COEFF           =                     MAX_ALF_FILTER_LENGTH * MAX_ALF_FILTER_LENGTH / 2 + 1;
 static const int MAX_ALF_PADDING_SIZE        =                      4;
+#if JVET_Q0795_CCALF
+#define MAX_NUM_CC_ALF_FILTERS                                      4
+static constexpr int MAX_NUM_CC_ALF_CHROMA_COEFF    =               8;
+static constexpr int CCALF_DYNAMIC_RANGE            =               6;
+static constexpr int CCALF_BITS_PER_COEFF_LEVEL     =               3;
+#endif
 
 static const int ALF_FIXED_FILTER_NUM        =                     64;
 static const int ALF_CTB_MAX_NUM_APS         =                      8;
@@ -479,8 +485,12 @@ static const int ENC_PPS_ID_RPR =                                 3;
 static const int SCALE_RATIO_BITS =                              14;
 static const int MAX_SCALING_RATIO =                              2;  // max downsampling ratio for RPR
 static const std::pair<int, int> SCALE_1X = std::pair<int, int>( 1 << SCALE_RATIO_BITS, 1 << SCALE_RATIO_BITS );  // scale ratio 1x
+#if JVET_Q0820_ACT
+static const int DELTA_QP_ACT[4] =                  { -5, 1, 3, 1 };
+#else
 static const int DELTA_QP_FOR_Y_Cg =                             -5;
 static const int DELTA_QP_FOR_Co =                               -3;
+#endif
 
 // ====================================================================================================================
 // Macro functions
@@ -700,6 +710,11 @@ static inline int ceilLog2(uint32_t x)
 #define PARL_PARAM0(DEF)
 #endif
 
+#if JVET_Q0795_CCALF
+static const uint32_t CCALF_CANDS_COEFF_NR = 8;
+static const int CCALF_SMALL_TAB[CCALF_CANDS_COEFF_NR] = { 0, 1, 2, 4, 8, 16, 32, 64 };
+#endif
+
 //! \}
 
 #endif // end of #ifndef  __COMMONDEF__
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 749b8673911c7b3ddbd2404daa1bcc53481c306c..840e718022d7fe96554c26ba30c06e479855d9e6 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -825,6 +825,16 @@ const CtxSet ContextSetCfg::AlfUseTemporalFilt = ContextSetCfg::addCtxSet
   {   0, },
 });
 
+#if JVET_Q0795_CCALF
+const CtxSet ContextSetCfg::CcAlfFilterControlFlag = ContextSetCfg::addCtxSet
+({
+  {  35,  35,  35,  35,  35,  35 },
+  {  35,  35,  35,  35,  35,  35 },
+  {  35,  35,  35,  35,  35,  35 },
+  { DWS, DWS, DWS, DWS, DWS, DWS },
+});
+#endif
+
 const CtxSet ContextSetCfg::CiipFlag = ContextSetCfg::addCtxSet
 ({
   {  50, },
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index e831206ce0d8cb2ab264fcfc706bff726236383e..d17ce051c9c97dda638745f13f97ae85fb3c35a9 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -263,6 +263,9 @@ public:
   static const CtxSet   ctbAlfFlag;
   static const CtxSet   ctbAlfAlternative;
   static const CtxSet   AlfUseTemporalFilt;
+#if JVET_Q0795_CCALF
+  static const CtxSet   CcAlfFilterControlFlag;
+#endif
   static const CtxSet   CiipFlag;
   static const CtxSet   SmvdFlag;
   static const CtxSet   IBCFlag;
diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp
index f2ca851eae904fbfd67aee1d9ff870f6a0b0566f..5ab5c8486362ccb84df10cf2020324d8627c5f32 100644
--- a/source/Lib/CommonLib/LoopFilter.cpp
+++ b/source/Lib/CommonLib/LoopFilter.cpp
@@ -1227,8 +1227,13 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed
         const TransformUnit& tuQ = *cuQ.cs->getTU(posQ, cuQ.chType);
         const TransformUnit& tuP = *cuP.cs->getTU(posP, cuP.chType); 
 
+#if JVET_Q0820_ACT
+        const QpParam cQP(tuP, ComponentID(chromaIdx + 1), -MAX_INT, false);
+        const QpParam cQQ(tuQ, ComponentID(chromaIdx + 1), -MAX_INT, false);
+#else
         const QpParam cQP(tuP, ComponentID(chromaIdx + 1));
         const QpParam cQQ(tuQ, ComponentID(chromaIdx + 1));
+#endif
         const int qpBdOffset = tuP.cs->sps->getQpBDOffset(toChannelType(ComponentID(chromaIdx + 1)));
         int baseQp_P = cQP.Qp(0) - qpBdOffset;
         int baseQp_Q = cQQ.Qp(0) - qpBdOffset;
diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp
index f30351c8ece34e456fd51111ed6408b4044da9f6..90c526ab907779ec1df3ccfa90596db7ce9370e7 100644
--- a/source/Lib/CommonLib/Quant.cpp
+++ b/source/Lib/CommonLib/Quant.cpp
@@ -70,6 +70,9 @@ QpParam::QpParam(const int           qpy,
                  const ChromaFormat  chFmt,
                  const int           dqp
               ,  const SPS           *sps
+#if JVET_Q0820_ACT
+              , const bool           applyACTQpoffset
+#endif
 )
 {
   int baseQp;
@@ -84,6 +87,12 @@ QpParam::QpParam(const int           qpy,
     baseQp = Clip3(-qpBdOffset, MAX_QP, baseQp + chromaQPOffset) + qpBdOffset;
   }
 
+#if JVET_Q0820_ACT
+  if (applyACTQpoffset)
+  {
+    baseQp += DELTA_QP_ACT[compID];
+  }
+#endif
   baseQp = Clip3( 0, MAX_QP+qpBdOffset, baseQp + dqp );
 
   Qps[0] =baseQp;
@@ -98,7 +107,11 @@ QpParam::QpParam(const int           qpy,
   rems[1] = baseQpTS % 6;
 }
 
+#if JVET_Q0820_ACT
+QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int QP /*= -MAX_INT*/, const bool allowACTQpoffset /*= true*/)
+#else
 QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int QP /*= -MAX_INT*/)
+#endif
 {
   int chromaQpOffset = 0;
   ComponentID compID = MAP_CHROMA(compIDX);
@@ -116,7 +129,12 @@ QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int
   int dqp = 0;
 
   const bool useJQP = isChroma(compID) && (abs(TU::getICTMode(tu)) == 2);
+#if JVET_Q0820_ACT
+  bool applyACTQpoffset = tu.cu->colorTransform && allowACTQpoffset;
+  *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, useJQP ? JOINT_CbCr : compID, tu.cs->sps->getQpBDOffset(toChannelType(compID)), tu.cs->sps->getMinQpPrimeTsMinus4(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp, tu.cs->sps, applyACTQpoffset);
+#else
   *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, useJQP ? JOINT_CbCr : compID, tu.cs->sps->getQpBDOffset(toChannelType(compID)), tu.cs->sps->getMinQpPrimeTsMinus4(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp, tu.cs->sps);
+#endif
 }
 
 
@@ -1255,7 +1273,11 @@ void Quant::lambdaAdjustColorTrans(bool forward)
     for (uint8_t component = 0; component < MAX_NUM_COMPONENT; component++)
     {
       ComponentID compID = (ComponentID)component;
+#if JVET_Q0820_ACT
+      int       delta_QP = DELTA_QP_ACT[compID];
+#else
       int       delta_QP = (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg);
+#endif
       double lamdbaAdjustRate = pow(2.0, delta_QP / 3.0);
 
       m_lambdasStore[0][component] = m_lambdas[component];
diff --git a/source/Lib/CommonLib/Quant.h b/source/Lib/CommonLib/Quant.h
index d2ffa8bbf336cd14f2ccbaf77ccd0ca0813bf71c..c5c638a8acabe25cacce59033d5ca8627acc4e05 100644
--- a/source/Lib/CommonLib/Quant.h
+++ b/source/Lib/CommonLib/Quant.h
@@ -82,11 +82,18 @@ private:
           const ChromaFormat  chFmt,
           const int           dqp
         , const SPS           *sps
+#if JVET_Q0820_ACT
+        , const bool          applyACTQpoffset
+#endif 
   );
 
 public:
 
+#if JVET_Q0820_ACT 
+  QpParam(const TransformUnit& tu, const ComponentID &compID, const int QP = -MAX_INT, const bool allowACTQpoffset = true);
+#else
   QpParam(const TransformUnit& tu, const ComponentID &compID, const int QP = -MAX_INT);
+#endif
 
   int Qp ( const bool ts ) const { return Qps [ts?1:0]; }
   int per( const bool ts ) const { return pers[ts?1:0]; }
diff --git a/source/Lib/CommonLib/RdCost.cpp b/source/Lib/CommonLib/RdCost.cpp
index 7f48f5d5ea9fca804b4e8de7f230cb99dec5add3..7c0960cb71eade8f2df88a1b26038d034d460c63 100644
--- a/source/Lib/CommonLib/RdCost.cpp
+++ b/source/Lib/CommonLib/RdCost.cpp
@@ -92,7 +92,11 @@ void RdCost::lambdaAdjustColorTrans(bool forward, ComponentID componentID)
     for (uint8_t component = 0; component < MAX_NUM_COMPONENT; component++)
     {
       ComponentID compID = (ComponentID)component;
+#if JVET_Q0820_ACT
+      int       delta_QP = DELTA_QP_ACT[compID];
+#else
       int       delta_QP = (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg);
+#endif
       double lamdbaAdjustRate = pow(2.0, delta_QP / 3.0);
 
       m_lambdaStore[0][component] = m_dLambda;
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index 9602f7e4804a846b02be53a810130281b6ab20df..d779e5c594f970f46ea64de41ba8dda599f4aaa4 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -53,7 +53,13 @@ Slice::Slice()
 , m_iAssociatedIRAPType           ( NAL_UNIT_INVALID )
 , m_rpl0Idx                       ( -1 )
 , m_rpl1Idx                       ( -1 )
+#if JVET_Q0155_COLOUR_ID
+, m_colourPlaneId                 ( 0 )
+#endif
 , m_eNalUnitType                  ( NAL_UNIT_CODED_SLICE_IDR_W_RADL )
+#if JVET_Q0775_PH_IN_SH
+, m_pictureHeaderInSliceHeader   ( false )
+#endif
 , m_eSliceType                    ( I_SLICE )
 , m_iSliceQp                      ( 0 )
 , m_ChromaQpAdjEnabled            ( false )
@@ -128,6 +134,12 @@ Slice::Slice()
   }
 
   memset(m_alfApss, 0, sizeof(m_alfApss));
+#if JVET_Q0795_CCALF
+  m_ccAlfFilterParam.reset();
+  resetTileGroupAlfEnabledFlag();
+  resetTileGroupCcAlCbfEnabledFlag();
+  resetTileGroupCcAlCrfEnabledFlag();
+#endif
 
   m_sliceMap.initSliceMap();
 }
@@ -145,7 +157,9 @@ void Slice::initSlice()
     m_aiNumRefIdx[i]      = 0;
   }
   m_colFromL0Flag = true;
-
+#if JVET_Q0155_COLOUR_ID
+  m_colourPlaneId = 0;
+#endif
   m_colRefIdx = 0;
   initEqualRef();
 
@@ -171,6 +185,13 @@ void Slice::initSlice()
   m_isDRAP               = false;
   m_latestDRAPPOC        = MAX_INT;
   resetTileGroupAlfEnabledFlag();
+#if JVET_Q0795_CCALF
+  m_ccAlfFilterParam.reset();
+  m_tileGroupCcAlfCbEnabledFlag = 0;
+  m_tileGroupCcAlfCrEnabledFlag = 0;
+  m_tileGroupCcAlfCbApsId = -1;
+  m_tileGroupCcAlfCrApsId = -1;
+#endif
 }
 
 void Slice::inheritFromPicHeader( PicHeader *picHeader, const PPS *pps, const SPS *sps )
@@ -212,7 +233,15 @@ void Slice::inheritFromPicHeader( PicHeader *picHeader, const PPS *pps, const SP
   setTileGroupAlfEnabledFlag(COMPONENT_Cr, picHeader->getAlfEnabledFlag(COMPONENT_Cr));
   setTileGroupNumAps(picHeader->getNumAlfAps());
   setAlfAPSs(picHeader->getAlfAPSs());
-  setTileGroupApsIdChroma(picHeader->getAlfApsIdChroma());   
+  setTileGroupApsIdChroma(picHeader->getAlfApsIdChroma());
+#if JVET_Q0795_CCALF
+  setTileGroupCcAlfCbEnabledFlag(picHeader->getCcAlfEnabledFlag(COMPONENT_Cb));
+  setTileGroupCcAlfCrEnabledFlag(picHeader->getCcAlfEnabledFlag(COMPONENT_Cr));
+  setTileGroupCcAlfCbApsId(picHeader->getCcAlfCbApsId());
+  setTileGroupCcAlfCrApsId(picHeader->getCcAlfCrApsId());
+  m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] = picHeader->getCcAlfEnabledFlag(COMPONENT_Cb);
+  m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] = picHeader->getCcAlfEnabledFlag(COMPONENT_Cr);
+#endif
 }
 
 void  Slice::setNumEntryPoints( const PPS *pps ) 
@@ -814,6 +843,15 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll)
       m_scalingRatio[i][j]          = pSrc->m_scalingRatio[i][j];
     }
   }
+#if JVET_Q0795_CCALF
+  m_ccAlfFilterParam                        = pSrc->m_ccAlfFilterParam;
+  m_ccAlfFilterControl[0]                   = pSrc->m_ccAlfFilterControl[0];
+  m_ccAlfFilterControl[1]                   = pSrc->m_ccAlfFilterControl[1];
+  m_tileGroupCcAlfCbEnabledFlag             = pSrc->m_tileGroupCcAlfCbEnabledFlag;
+  m_tileGroupCcAlfCrEnabledFlag             = pSrc->m_tileGroupCcAlfCrEnabledFlag;
+  m_tileGroupCcAlfCbApsId                   = pSrc->m_tileGroupCcAlfCbApsId;
+  m_tileGroupCcAlfCrApsId                   = pSrc->m_tileGroupCcAlfCrApsId;
+#endif
 }
 
 
@@ -1563,7 +1601,9 @@ PicHeader::PicHeader()
 , m_loopFilterAcrossVirtualBoundariesDisabledFlag ( 0 )
 , m_numVerVirtualBoundaries                       ( 0 )
 , m_numHorVirtualBoundaries                       ( 0 )
+#if !JVET_Q0155_COLOUR_ID
 , m_colourPlaneId                                 ( 0 )
+#endif
 , m_picOutputFlag                                 ( true )
 , m_picRplPresentFlag                             ( 0 )
 , m_pRPL0                                         ( 0 )
@@ -1653,7 +1693,9 @@ void PicHeader::initPicHeader()
   m_loopFilterAcrossVirtualBoundariesDisabledFlag = 0;
   m_numVerVirtualBoundaries                       = 0;
   m_numHorVirtualBoundaries                       = 0;
+#if !JVET_Q0155_COLOUR_ID
   m_colourPlaneId                                 = 0;
+#endif
   m_picOutputFlag                                 = true;
   m_picRplPresentFlag                             = 0;
   m_pRPL0                                         = 0;
@@ -1747,7 +1789,7 @@ SPS::SPS()
 , m_SBT                       ( false )
 , m_ISP                       ( false )
 , m_chromaFormatIdc           (CHROMA_420)
-, m_separateColourPlaneFlag(0)
+, m_separateColourPlaneFlag   ( 0 )
 , m_uiMaxTLayers              (  1)
 // Structure
 , m_maxWidthInLumaSamples     (352)
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index b9548511340b5066a17fc95c00f5d225ebad1ee2..fc5bfaf13377f04c14ded8c19120f2d63183a45d 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -242,6 +242,9 @@ class ConstraintInfo
   bool              m_noPartitionConstraintsOverrideConstraintFlag;
   bool              m_noSaoConstraintFlag;
   bool              m_noAlfConstraintFlag;
+#if JVET_Q0795_CCALF
+  bool              m_noCCAlfConstraintFlag;
+#endif
   bool              m_noRefWraparoundConstraintFlag;
   bool              m_noTemporalMvpConstraintFlag;
   bool              m_noSbtmvpConstraintFlag;
@@ -286,6 +289,9 @@ public:
     , m_noPartitionConstraintsOverrideConstraintFlag(false)
     , m_noSaoConstraintFlag      (false)
     , m_noAlfConstraintFlag      (false)
+#if JVET_Q0795_CCALF
+    , m_noCCAlfConstraintFlag      (false)
+#endif
     , m_noRefWraparoundConstraintFlag(false)
     , m_noTemporalMvpConstraintFlag(false)
     , m_noSbtmvpConstraintFlag   (false)
@@ -353,6 +359,10 @@ public:
   void          setNoSaoConstraintFlag(bool bVal) { m_noSaoConstraintFlag = bVal; }
   bool          getNoAlfConstraintFlag() const { return m_noAlfConstraintFlag; }
   void          setNoAlfConstraintFlag(bool bVal) { m_noAlfConstraintFlag = bVal; }
+#if JVET_Q0795_CCALF
+  bool          getNoCCAlfConstraintFlag() const { return m_noCCAlfConstraintFlag; }
+  void          setNoCCAlfConstraintFlag(bool val) { m_noCCAlfConstraintFlag = val; }
+#endif
   bool          getNoJointCbCrConstraintFlag() const { return m_noJointCbCrConstraintFlag; }
   void          setNoJointCbCrConstraintFlag(bool bVal) { m_noJointCbCrConstraintFlag = bVal; }
   bool          getNoRefWraparoundConstraintFlag() const { return m_noRefWraparoundConstraintFlag; }
@@ -1128,7 +1138,9 @@ private:
   ProfileTierLevel  m_profileTierLevel;
 
   bool              m_alfEnabledFlag;
-
+#if JVET_Q0795_CCALF
+  bool              m_ccalfEnabledFlag;
+#endif
   bool              m_wrapAroundEnabledFlag;
   unsigned          m_wrapAroundOffset;
   unsigned          m_IBCFlag;
@@ -1166,6 +1178,10 @@ private:
   bool              m_rprEnabledFlag;
   bool              m_interLayerPresentFlag;
 
+#if JVET_Q0297_MER
+  uint32_t          m_log2ParallelMergeLevelMinus2;
+#endif
+
 public:
 
   SPS();
@@ -1323,6 +1339,10 @@ public:
 
   bool                    getALFEnabledFlag() const                                                       { return m_alfEnabledFlag; }
   void                    setALFEnabledFlag( bool b )                                                     { m_alfEnabledFlag = b; }
+#if JVET_Q0795_CCALF
+bool                    getCCALFEnabledFlag() const                                                       { return m_ccalfEnabledFlag; }
+void                    setCCALFEnabledFlag( bool b )                                                     { m_ccalfEnabledFlag = b; }
+#endif
   void                    setJointCbCrEnabledFlag(bool bVal)                                              { m_JointCbCrEnabledFlag = bVal; }
   bool                    getJointCbCrEnabledFlag() const                                                 { return m_JointCbCrEnabledFlag; }
 
@@ -1470,6 +1490,10 @@ public:
   bool      getInterLayerPresentFlag()                                        const { return m_interLayerPresentFlag; }
   void      setInterLayerPresentFlag( bool b )                                      { m_interLayerPresentFlag = b; }
 
+#if JVET_Q0297_MER
+  uint32_t  getLog2ParallelMergeLevelMinus2() const { return m_log2ParallelMergeLevelMinus2; }
+  void      setLog2ParallelMergeLevelMinus2(uint32_t mrgLevel) { m_log2ParallelMergeLevelMinus2 = mrgLevel; }
+#endif
 };
 
 
@@ -1835,6 +1859,9 @@ private:
   AlfParam               m_alfAPSParam;
   SliceReshapeInfo       m_reshapeAPSInfo;
   ScalingList            m_scalingListApsInfo;
+#if JVET_Q0795_CCALF
+  CcAlfFilterParam       m_ccAlfAPSParam;
+#endif
 
 public:
   APS();
@@ -1857,6 +1884,10 @@ public:
   SliceReshapeInfo&      getReshaperAPSInfo()                                             { return m_reshapeAPSInfo;                      }
   void                   setScalingList( ScalingList& scalingListAPSInfo )                { m_scalingListApsInfo = scalingListAPSInfo;    }
   ScalingList&           getScalingList()                                                 { return m_scalingListApsInfo;                  }
+#if JVET_Q0795_CCALF
+  void                   setCcAlfAPSParam(CcAlfFilterParam& ccAlfAPSParam)                { m_ccAlfAPSParam = ccAlfAPSParam;              }
+  CcAlfFilterParam&      getCcAlfAPSParam()  { return m_ccAlfAPSParam; }
+#endif
 };
 struct WPScalingParam
 {
@@ -1901,7 +1932,9 @@ private:
   unsigned                    m_numHorVirtualBoundaries;                                //!< number of horizontal virtual boundaries
   unsigned                    m_virtualBoundariesPosX[3];                               //!< horizontal virtual boundary positions
   unsigned                    m_virtualBoundariesPosY[3];                               //!< vertical virtual boundary positions
+#if !JVET_Q0155_COLOUR_ID
   unsigned                    m_colourPlaneId;                                          //!< 4:4:4 colour plane ID
+#endif
   bool                        m_picOutputFlag;                                          //!< picture output flag
   bool                        m_picRplPresentFlag;                                      //!< reference lists present in picture header or not
   const ReferencePictureList* m_pRPL0;                                                  //!< pointer to RPL for L0, either in the SPS or the local RPS in the picture header
@@ -1933,6 +1966,11 @@ private:
   int                         m_numAlfAps;                                              //!< number of alf aps active for the picture
   std::vector<int>            m_alfApsId;                                               //!< list of alf aps for the picture
   int                         m_alfChromaApsId;                                         //!< chroma alf aps ID
+#if JVET_Q0795_CCALF
+  bool m_ccalfEnabledFlag[MAX_NUM_COMPONENT];
+  int  m_ccalfCbApsId;
+  int  m_ccalfCrApsId;
+#endif
   bool                        m_depQuantEnabledFlag;                                    //!< dependent quantization enabled flag
   bool                        m_signDataHidingEnabledFlag;                              //!< sign data hiding enabled flag
   bool                        m_deblockingFilterOverridePresentFlag;                    //!< deblocking filter override controls present in picture header
@@ -1989,8 +2027,10 @@ public:
   unsigned                    getVirtualBoundariesPosX(unsigned idx) const              { CHECK( idx >= 3, "boundary index exceeds valid range" ); return m_virtualBoundariesPosX[idx];}
   void                        setVirtualBoundariesPosY(unsigned u, unsigned idx)        { CHECK( idx >= 3, "boundary index exceeds valid range" ); m_virtualBoundariesPosY[idx] = u;   }
   unsigned                    getVirtualBoundariesPosY(unsigned idx) const              { CHECK( idx >= 3, "boundary index exceeds valid range" ); return m_virtualBoundariesPosY[idx];}
+#if !JVET_Q0155_COLOUR_ID
   void                        setColourPlaneId(unsigned u)                              { m_colourPlaneId = u;                                                                         }
   unsigned                    getColourPlaneId() const                                  { return m_colourPlaneId;                                                                      }
+#endif
   void                        setPicOutputFlag( bool b )                                { m_picOutputFlag = b;                                                                         }
   bool                        getPicOutputFlag() const                                  { return m_picOutputFlag;                                                                      }
   void                        setPicRplPresentFlag( bool b )                            { m_picRplPresentFlag = b;                                                                     }
@@ -2053,7 +2093,16 @@ public:
   void                        setNumAlfAps(int i)                                       { m_numAlfAps = i;                                                                             }
   int                         getNumAlfAps() const                                      { return m_numAlfAps;                                                                          }
   void                        setAlfApsIdChroma(int i)                                  { m_alfChromaApsId = i;                                                                        }
-  int                         getAlfApsIdChroma() const                                 { return m_alfChromaApsId;                                                                     }  
+  int                         getAlfApsIdChroma() const                                 { return m_alfChromaApsId;                                                                     }
+#if JVET_Q0795_CCALF
+  void setCcAlfEnabledFlag(ComponentID compId, bool b) { m_ccalfEnabledFlag[compId] = b; }
+  bool getCcAlfEnabledFlag(ComponentID compId) const { return m_ccalfEnabledFlag[compId]; }
+
+  void setCcAlfCbApsId(int i) { m_ccalfCbApsId = i; }
+  int  getCcAlfCbApsId() const { return m_ccalfCbApsId; }
+  void setCcAlfCrApsId(int i) { m_ccalfCrApsId = i; }
+  int  getCcAlfCrApsId() const { return m_ccalfCrApsId; }
+#endif
   void                        setDepQuantEnabledFlag( bool b )                          { m_depQuantEnabledFlag = b;                                                                   }
   bool                        getDepQuantEnabledFlag() const                            { return m_depQuantEnabledFlag;                                                                }  
   void                        setSignDataHidingEnabledFlag( bool b )                    { m_signDataHidingEnabledFlag = b;                                                             }
@@ -2142,7 +2191,13 @@ private:
   ReferencePictureList        m_localRPL1;            //< RPL for L1 when present in slice header
   int                         m_rpl0Idx;              //< index of used RPL in the SPS or -1 for local RPL in the slice header
   int                         m_rpl1Idx;              //< index of used RPL in the SPS or -1 for local RPL in the slice header
+#if JVET_Q0155_COLOUR_ID
+  int                        m_colourPlaneId;                         //!< 4:4:4 colour plane ID
+#endif
   NalUnitType                m_eNalUnitType;         ///< Nal unit type for the slice
+#if JVET_Q0775_PH_IN_SH
+  bool                       m_pictureHeaderInSliceHeader;
+#endif
   SliceType                  m_eSliceType;
   int                        m_iSliceQp;
   int                        m_iSliceQpBase;
@@ -2225,6 +2280,12 @@ private:
   int                        m_tileGroupNumAps;
   std::vector<int>           m_tileGroupLumaApsId;
   int                        m_tileGroupChromaApsId;
+#if JVET_Q0795_CCALF
+  bool                       m_tileGroupCcAlfCbEnabledFlag;
+  bool                       m_tileGroupCcAlfCrEnabledFlag;
+  int                        m_tileGroupCcAlfCbApsId;
+  int                        m_tileGroupCcAlfCrApsId;
+#endif
   bool                       m_disableSATDForRd;
 public:
                               Slice();
@@ -2286,13 +2347,17 @@ public:
   int                         getRefPOC( RefPicList e, int iRefIdx) const            { return m_aiRefPOCList[e][iRefIdx];                            }
   int                         getDepth() const                                       { return m_iDepth;                                              }
   bool                        getColFromL0Flag() const                               { return m_colFromL0Flag;                                       }
-  uint32_t                        getColRefIdx() const                                   { return m_colRefIdx;                                           }
+  uint32_t                    getColRefIdx() const                                   { return m_colRefIdx;                                           }
   void                        checkColRefIdx(uint32_t curSliceSegmentIdx, const Picture* pic);
   bool                        getIsUsedAsLongTerm(int i, int j) const                { return m_bIsUsedAsLongTerm[i][j];                             }
   void                        setIsUsedAsLongTerm(int i, int j, bool value)          { m_bIsUsedAsLongTerm[i][j] = value;                            }
   bool                        getCheckLDC() const                                    { return m_bCheckLDC;                                           }
   int                         getList1IdxToList0Idx( int list1Idx ) const            { return m_list1IdxToList0Idx[list1Idx];                        }
   void                        setPOC( int i )                                        { m_iPOC              = i;                                      }
+#if JVET_Q0775_PH_IN_SH
+  bool                        getPictureHeaderInSliceHeader() const                  { return m_pictureHeaderInSliceHeader;                         }
+  void                        setPictureHeaderInSliceHeader( bool e )                { m_pictureHeaderInSliceHeader = e;                            }
+#endif
   void                        setNalUnitType( NalUnitType e )                        { m_eNalUnitType      = e;                                      }
   NalUnitType                 getNalUnitType() const                                 { return m_eNalUnitType;                                        }
   bool                        getRapPicFlag() const;
@@ -2343,6 +2408,10 @@ public:
   bool                        isPocRestrictedByDRAP( int poc, bool precedingDRAPinDecodingOrder );
   bool                        isPOCInRefPicList( const ReferencePictureList *rpl, int poc );
   void                        checkConformanceForDRAP( uint32_t temporalId );
+#if JVET_Q0155_COLOUR_ID
+  void                        setColourPlaneId( int id )                             { m_colourPlaneId = id;                                         }
+  int                         getColourPlaneId() const                               { return m_colourPlaneId;                                       }
+#endif
 
   void                        setLambdas( const double lambdas[MAX_NUM_COMPONENT] )  { for (int component = 0; component < MAX_NUM_COMPONENT; component++) m_lambdas[component] = lambdas[component]; }
   const double*               getLambdas() const                                     { return m_lambdas;                                             }
@@ -2468,6 +2537,20 @@ public:
       m_tileGroupLumaApsId[i] = ApsIDs[i];
     }
   }
+#if JVET_Q0795_CCALF
+  void resetTileGroupCcAlCbfEnabledFlag() { m_tileGroupCcAlfCbEnabledFlag = 0; }
+  void resetTileGroupCcAlCrfEnabledFlag() { m_tileGroupCcAlfCrEnabledFlag = 0; }
+
+  void setTileGroupCcAlfCbEnabledFlag(bool b) { m_tileGroupCcAlfCbEnabledFlag = b; }
+  void setTileGroupCcAlfCrEnabledFlag(bool b) { m_tileGroupCcAlfCrEnabledFlag = b; }
+  void setTileGroupCcAlfCbApsId(int i) { m_tileGroupCcAlfCbApsId = i; }
+  void setTileGroupCcAlfCrApsId(int i) { m_tileGroupCcAlfCrApsId = i; }
+
+  bool getTileGroupCcAlfCbEnabledFlag() { return m_tileGroupCcAlfCbEnabledFlag; }
+  bool getTileGroupCcAlfCrEnabledFlag() { return m_tileGroupCcAlfCrEnabledFlag; }
+  int  getTileGroupCcAlfCbApsId() { return m_tileGroupCcAlfCbApsId; }
+  int  getTileGroupCcAlfCrApsId() { return m_tileGroupCcAlfCrApsId; }
+#endif
   void                        setDisableSATDForRD(bool b) { m_disableSATDForRd = b; }
   bool                        getDisableSATDForRD() { return m_disableSATDForRd; }
   void                        scaleRefPicList( Picture *scaledRefPic[ ], PicHeader *picHeader, APS** apss, APS* lmcsAps, APS* scalingListAps, const bool isDecoder );
@@ -2477,6 +2560,11 @@ public:
   void                        setNumEntryPoints( const PPS *pps );
   uint32_t                    getNumEntryPoints( ) const { return m_numEntryPoints;  }
 
+#if JVET_Q0795_CCALF
+  CcAlfFilterParam            m_ccAlfFilterParam;
+  uint8_t*                    m_ccAlfFilterControl[2];
+#endif
+
 protected:
   Picture*              xGetRefPic( PicList& rcListPic, int poc, const int layerId );
   Picture*              xGetLongTermRefPic( PicList& rcListPic, int poc, bool pocHasMsb, const int layerId );
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 892d1e776441b4bae9309af02d249fa3d85e0d55..e3ed2531e86f3fcd314042a821565d6978c54e63 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,12 +50,26 @@
 #include <assert.h>
 #include <cassert>
 
+
+#define JVET_Q0820_ACT                                    1 // JVET-Q0820: ACT bug fixes and reversible ACT transform 
+
+#define JVET_Q0353_ACT_SW_FIX                             1 // JVET-Q0353: Bug fix of ACT 
+
+#define JVET_Q0695_CHROMA_TS_JCCR                         1 // JVET-Q0695: Enabling the RD checking of chroma transform-skip mode for JCCR at encoder
 #define JVET_Q0500_CCLM_REF_PADDING                       1 // JVET-Q0500: Reference samples padding for CCLM
 
 #define JVET_Q0128_DMVR_BDOF_ENABLING_CONDITION           1 // JVET-Q0128: Cleanup of enabling condition for DMVR and BDOF 
 
 #define JVET_Q0784_LFNST_COMBINATION                      1 // lfnst signaling, latency reduction and a bugfix for scaling from Q0106, Q0686, Q0133
 
+#define JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU              1 // JVET-Q0501: Initialize palette predictor from above CTU row in WPP 
+
+#define JVET_Q0819_PH_CHANGES                             1 // JVET-Q0819: Combination of PH related syntax changes
+
+#define JVET_Q0481_PARTITION_CONSTRAINTS_ORDER            1 // JVET-Q0481: Ordering of partition constraints syntax elements in the SPS
+
+#define JVET_Q0155_COLOUR_ID                              1 // JVET-Q0155: move colour_plane_id from PH to SH
+
 #define JVET_Q0147_JCCR_SIGNALLING                        1 // JVET-Q0147: Conditional signaling of sps_joint_cbcr_enabled_flag based on ChromaArrayType
 
 #define JVET_Q0267_RESET_CHROMA_QP_OFFSET                 1 // JVET-Q0267: Reset chroma QP offsets at the start of each chroma QP offset group
@@ -75,6 +89,9 @@
 #define JVET_Q0249_ALF_CHROMA_CLIPFLAG                    1 // JVET-Q0249: Cleanup of chroma clipping flags for ALF
 #define JVET_Q0150                                        1 // fix for ALF virtual horizontal CTU boundary processing
 #define JVET_Q0054                                        1 // fix for long luma deblocking decision
+#define JVET_Q0795_CCALF                                  1 // Cross-component ALF
+
+#define JVET_Q0297_MER                                    1 // JVET_Q0297: Merge estimation region
 
 #define JVET_Q0483_CLIP_TMVP                              1 // JVET-Q0483: Clip TMVP when no scaling is applied
 
@@ -82,6 +99,7 @@
 #define JVET_Q0055_MTS_SIGNALLING                         1 // JVET-Q0055: Check for transform coefficients outside the 16x16 area
 #define JVET_Q0480_RASTER_RECT_SLICES                     1 // JVET-Q0480: Eliminate redundant slice height syntax when in raster rectangular slice mode (tile_idx_delta_present_flag == 0)
 
+#define JVET_Q0775_PH_IN_SH                               1 // JVET-Q0755: Allow picture header in slice header
 
 #define JVET_Q0433_MODIFIED_CHROMA_DIST_WEIGHT            1 // modification of chroma distortion weight (as agreed during presentation of JVET-Q0433)
 
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 95e59ed1e139622e863bbd98a1355c0cc2079fe7..7dae6ae23dc5e80a70fa1075dc85359a119c1ee8 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -250,6 +250,14 @@ void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone )
 
     mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT;
 
+#if JVET_Q0297_MER
+    const unsigned log2ParallelMergeLevel = (pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2);
+    const unsigned xBr = pu.cu->Y().width + pu.cu->Y().x;
+    const unsigned yBr = pu.cu->Y().height + pu.cu->Y().y;
+    bool enableHmvp = ((xBr >> log2ParallelMergeLevel) > (pu.cu->Y().x >> log2ParallelMergeLevel)) && ((yBr >> log2ParallelMergeLevel) > (pu.cu->Y().y >> log2ParallelMergeLevel));
+    bool enableInsertion = CU::isIBC(cu) || enableHmvp;
+    if (enableInsertion)
+#endif
     cu.cs->addMiToLut(CU::isIBC(cu) ? cu.cs->motionLut.lutIbc : cu.cs->motionLut.lut, mi);
   }
 }
@@ -744,7 +752,11 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
   //left
   const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType);
   bool isGt4x4 = pu.lwidth() * pu.lheight() > 16;
+#if JVET_Q0297_MER
+  const bool isAvailableA1 = puLeft && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu);
+#else
   const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu);
+#endif
   if (isGt4x4 && isAvailableA1)
   {
     miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0));
@@ -768,7 +780,11 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const
 
   // above
   const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType);
+#if JVET_Q0297_MER
+  bool isAvailableB1 = puAbove && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu);
+#else
   bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu);
+#endif
   if (isGt4x4 && isAvailableB1)
   {
     miAbove = puAbove->getMotionInfo(posRT.offset(0, -1));
@@ -1490,6 +1506,19 @@ bool PU::isDiffMER(const PredictionUnit &pu1, const PredictionUnit &pu2)
   const unsigned xP = pu2.lumaPos().x;
   const unsigned yP = pu2.lumaPos().y;
 
+#if JVET_Q0297_MER
+  unsigned plevel = pu1.cs->sps->getLog2ParallelMergeLevelMinus2() + 2;
+
+  if ((xN >> plevel) != (xP >> plevel))
+  {
+    return true;
+  }
+
+  if ((yN >> plevel) != (yP >> plevel))
+  {
+    return true;
+}
+#else
   if ((xN >> 2) != (xP >> 2))
   {
     return true;
@@ -1499,6 +1528,7 @@ bool PU::isDiffMER(const PredictionUnit &pu1, const PredictionUnit &pu2)
   {
     return true;
   }
+#endif
 
   return false;
 }
@@ -2355,6 +2385,9 @@ const int getAvailableAffineNeighboursForLeftPredictor( const PredictionUnit &pu
   const PredictionUnit *puLeftBottom = pu.cs->getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType );
   if ( puLeftBottom && puLeftBottom->cu->affine
     && puLeftBottom->mergeType == MRG_TYPE_DEFAULT_N
+#if JVET_Q0297_MER
+    && PU::isDiffMER(pu, *puLeftBottom)
+#endif
     )
   {
     npu[num++] = puLeftBottom;
@@ -2364,6 +2397,9 @@ const int getAvailableAffineNeighboursForLeftPredictor( const PredictionUnit &pu
   const PredictionUnit* puLeft = pu.cs->getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType );
   if ( puLeft && puLeft->cu->affine
     && puLeft->mergeType == MRG_TYPE_DEFAULT_N
+#if JVET_Q0297_MER
+    && PU::isDiffMER(pu, *puLeft)
+#endif
     )
   {
     npu[num++] = puLeft;
@@ -2382,6 +2418,9 @@ const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &p
   const PredictionUnit* puAboveRight = pu.cs->getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType );
   if ( puAboveRight && puAboveRight->cu->affine
     && puAboveRight->mergeType == MRG_TYPE_DEFAULT_N
+#if JVET_Q0297_MER
+    && PU::isDiffMER(pu, *puAboveRight)
+#endif
     )
   {
     npu[num++] = puAboveRight;
@@ -2391,6 +2430,9 @@ const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &p
   const PredictionUnit* puAbove = pu.cs->getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType );
   if ( puAbove && puAbove->cu->affine
     && puAbove->mergeType == MRG_TYPE_DEFAULT_N
+#if JVET_Q0297_MER
+    && PU::isDiffMER(pu, *puAbove)
+#endif
     )
   {
     npu[num++] = puAbove;
@@ -2400,6 +2442,9 @@ const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &p
   const PredictionUnit *puAboveLeft = pu.cs->getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType );
   if ( puAboveLeft && puAboveLeft->cu->affine
     && puAboveLeft->mergeType == MRG_TYPE_DEFAULT_N
+#if JVET_Q0297_MER
+    && PU::isDiffMER(pu, *puAboveLeft)
+#endif
     )
   {
     npu[num++] = puAboveLeft;
@@ -2557,6 +2602,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
         const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType );
 
         if ( puNeigh && CU::isInter( *puNeigh->cu )
+#if JVET_Q0297_MER
+          && PU::isDiffMER(pu, *puNeigh)
+#endif
           )
         {
           isAvailable[0] = true;
@@ -2575,6 +2623,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 
 
         if ( puNeigh && CU::isInter( *puNeigh->cu )
+#if JVET_Q0297_MER
+          && PU::isDiffMER(pu, *puNeigh)
+#endif
           )
         {
           isAvailable[1] = true;
@@ -2593,6 +2644,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx
 
 
         if ( puNeigh && CU::isInter( *puNeigh->cu )
+#if JVET_Q0297_MER
+          && PU::isDiffMER(pu, *puNeigh)
+#endif
           )
         {
           isAvailable[2] = true;
@@ -3623,7 +3677,11 @@ bool CU::bdpcmAllowed( const CodingUnit& cu, const ComponentID compID )
        if (isLuma(compID))
            bdpcmAllowed &= (cu.lwidth() <= transformSkipMaxSize && cu.lheight() <= transformSkipMaxSize);
        else
+#if JVET_Q0353_ACT_SW_FIX
+           bdpcmAllowed &= (cu.chromaSize().width <= transformSkipMaxSize && cu.chromaSize().height <= transformSkipMaxSize) && !cu.colorTransform;
+#else
            bdpcmAllowed &= (cu.chromaSize().width <= transformSkipMaxSize && cu.chromaSize().height <= transformSkipMaxSize);
+#endif
   return bdpcmAllowed;
 }
 
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index 2b6e0688128e89e513a2b6886e71e9ec9375ee92..b8f20a7dee8845906193124edffe83d6e396f1a1 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -194,6 +194,25 @@ void CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i
       }
     }
   }
+#if JVET_Q0795_CCALF
+  if (cs.sps->getCCALFEnabledFlag())
+  {
+    for ( int compIdx = 1; compIdx < getNumberValidComponents( cs.pcv->chrFormat ); compIdx++ )
+    {
+      if (cs.slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1])
+      {
+        const int filterCount   = cs.slice->m_ccAlfFilterParam.ccAlfFilterCount[compIdx - 1];
+
+        const int      ry = ctuRsAddr / cs.pcv->widthInCtus;
+        const int      rx = ctuRsAddr % cs.pcv->widthInCtus;
+        const Position lumaPos(rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight);
+
+        ccAlfFilterControlIdc(cs, ComponentID(compIdx), ctuRsAddr, cs.slice->m_ccAlfFilterControl[compIdx - 1], lumaPos,
+                              filterCount);
+      }
+    }
+  }
+#endif
 
 
   if ( CS::isDualITree(cs) && cs.pcv->chrFormat != CHROMA_400 && cs.pcv->maxCUWidth > 64 )
@@ -251,6 +270,45 @@ void CABACReader::readAlfCtuFilterIndex(CodingStructure& cs, unsigned ctuRsAddr)
   }
   alfCtbFilterSetIndex[ctuRsAddr] = filtIndex;
 }
+#if JVET_Q0795_CCALF
+void CABACReader::ccAlfFilterControlIdc(CodingStructure &cs, const ComponentID compID, const int curIdx,
+                                        uint8_t *filterControlIdc, Position lumaPos, int filterCount)
+{
+  RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__CROSS_COMPONENT_ALF_BLOCK_LEVEL_IDC );
+
+  Position       leftLumaPos    = lumaPos.offset(-(int)cs.pcv->maxCUWidth, 0);
+  Position       aboveLumaPos   = lumaPos.offset(0, -(int)cs.pcv->maxCUWidth);
+  const uint32_t curSliceIdx    = cs.slice->getIndependentSliceIdx();
+  const uint32_t curTileIdx     = cs.pps->getTileIdx( lumaPos );
+  bool           leftAvail      = cs.getCURestricted( leftLumaPos,  lumaPos, curSliceIdx, curTileIdx, CH_L ) ? true : false;
+  bool           aboveAvail     = cs.getCURestricted( aboveLumaPos, lumaPos, curSliceIdx, curTileIdx, CH_L ) ? true : false;
+  int            ctxt           = 0;
+
+  if (leftAvail)
+  {
+    ctxt += ( filterControlIdc[curIdx - 1] ) ? 1 : 0;
+  }
+  if (aboveAvail)
+  {
+    ctxt += ( filterControlIdc[curIdx - cs.pcv->widthInCtus] ) ? 1 : 0;
+  }
+  ctxt += ( compID == COMPONENT_Cr ) ? 3 : 0;
+
+  int idcVal  = m_BinDecoder.decodeBin( Ctx::CcAlfFilterControlFlag( ctxt ) );
+  if ( idcVal )
+  {
+    while ( ( idcVal != filterCount ) && m_BinDecoder.decodeBinEP() )
+    {
+      idcVal++;
+    }
+  }
+  filterControlIdc[curIdx] = idcVal;
+
+  DTRACE(g_trace_ctx, D_SYNTAX, "ccAlfFilterControlIdc() compID=%d pos=(%d,%d) ctxt=%d, filterCount=%d, idcVal=%d\n",
+         compID, lumaPos.x, lumaPos.y, ctxt, filterCount, idcVal);
+}
+#endif
+
 //================================================================================
 //  clause 7.3.8.3
 //--------------------------------------------------------------------------------
diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h
index 132c50232a229395cbcde5d257acb71b7f99eec0..e1b33238b52ff4a9db971d2a50615dc0cb8be9f2 100644
--- a/source/Lib/DecoderLib/CABACReader.h
+++ b/source/Lib/DecoderLib/CABACReader.h
@@ -70,6 +70,11 @@ public:
 
   void        readAlfCtuFilterIndex(CodingStructure&              cs, unsigned        ctuRsAddr);
 
+#if JVET_Q0795_CCALF
+  void ccAlfFilterControlIdc(CodingStructure &cs, const ComponentID compID, const int curIdx, uint8_t *filterControlIdc,
+                             Position lumaPos, int filterCount);
+#endif
+
   // coding (quad)tree (clause 7.3.8.4)
   void        coding_tree               ( CodingStructure&              cs,     Partitioner&    pm,       CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr);
   PartSplit   split_cu_mode             ( CodingStructure&              cs,     Partitioner&    pm );
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 3b96128195c8623b5fff067cdcecb0486b61cb18..88b6a9cd3d8bbfdba72c701d9968aa716927c4d7 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -369,12 +369,14 @@ void DecCu::xIntraRecACTBlk(TransformUnit& tu)
     PelBuf piResi = cs.getResiBuf(area);
 
     QpParam cQP(tu, compID);
+#if !JVET_Q0820_ACT
     for (int qpIdx = 0; qpIdx < 2; qpIdx++)
     {
       cQP.Qps[qpIdx] = cQP.Qps[qpIdx] + (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg);
       cQP.pers[qpIdx] = cQP.Qps[qpIdx] / 6;
       cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6;
     }
+#endif
 
     if (tu.jointCbCr && isChroma(compID))
     {
@@ -388,12 +390,14 @@ void DecCu::xIntraRecACTBlk(TransformUnit& tu)
         else
         {
           QpParam qpCr(tu, COMPONENT_Cr);
+#if !JVET_Q0820_ACT
           for (int qpIdx = 0; qpIdx < 2; qpIdx++)
           {
             qpCr.Qps[qpIdx] = qpCr.Qps[qpIdx] + DELTA_QP_FOR_Co;
             qpCr.pers[qpIdx] = qpCr.Qps[qpIdx] / 6;
             qpCr.rems[qpIdx] = qpCr.Qps[qpIdx] % 6;
           }
+#endif
 
           m_pcTrQuant->invTransformNxN(tu, COMPONENT_Cr, resiCr, qpCr);
         }
@@ -421,7 +425,11 @@ void DecCu::xIntraRecACTBlk(TransformUnit& tu)
     cs.setDecomp(area);
   }
 
+#if JVET_Q0820_ACT
+  cs.getResiBuf(tu).colorSpaceConvert(cs.getResiBuf(tu), false, tu.cu->cs->slice->clpRng(COMPONENT_Y));
+#else
   cs.getResiBuf(tu).colorSpaceConvert(cs.getResiBuf(tu), false);
+#endif
 
   for (int i = 0; i < getNumberValidComponents(tu.chromaFormat); i++)
   {
@@ -697,7 +705,11 @@ void DecCu::xReconInter(CodingUnit &cu)
   {
     if (cu.colorTransform)
     {
+#if JVET_Q0820_ACT
+      cs.getResiBuf(cu).colorSpaceConvert(cs.getResiBuf(cu), false, cu.cs->slice->clpRng(COMPONENT_Y));
+#else
       cs.getResiBuf(cu).colorSpaceConvert(cs.getResiBuf(cu), false);
+#endif
     }
 #if REUSE_CU_RESULTS
     const CompArea &area = cu.blocks[COMPONENT_Y];
@@ -759,6 +771,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID )
   PelBuf resiBuf  = cs.getResiBuf(area);
 
   QpParam cQP(currTU, compID);
+#if !JVET_Q0820_ACT
   if (currTU.cu->colorTransform)
   {
     for (int qpIdx = 0; qpIdx < 2; qpIdx++)
@@ -768,6 +781,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID )
       cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6;
     }
   }
+#endif
 
   if( currTU.jointCbCr && isChroma(compID) )
   {
@@ -781,6 +795,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID )
       else
       {
         QpParam qpCr(currTU, COMPONENT_Cr);
+#if !JVET_Q0820_ACT
         if (currTU.cu->colorTransform)
         {
           for (int qpIdx = 0; qpIdx < 2; qpIdx++)
@@ -790,6 +805,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID )
             qpCr.rems[qpIdx] = qpCr.Qps[qpIdx] % 6;
           }
         }
+#endif
         m_pcTrQuant->invTransformNxN( currTU, COMPONENT_Cr, resiCr, qpCr );
       }
       m_pcTrQuant->invTransformICT( currTU, resiBuf, resiCr );
diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp
index 3d87a2be860352a36a51de8389008bf5a03f91a9..253f8dda0fe8f61ccb9047c3aa08fc5663c731fd 100644
--- a/source/Lib/DecoderLib/DecLib.cpp
+++ b/source/Lib/DecoderLib/DecLib.cpp
@@ -222,6 +222,12 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri
                     pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Y,  pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Y));
                     pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Cb));
                     pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Cr));
+#if JVET_Q0795_CCALF
+                    pcEncPic->slices[i]->setTileGroupCcAlfCbApsId(pic->slices[i]->getTileGroupCcAlfCbApsId());
+                    pcEncPic->slices[i]->setTileGroupCcAlfCbEnabledFlag(pic->slices[i]->getTileGroupCcAlfCbEnabledFlag());
+                    pcEncPic->slices[i]->setTileGroupCcAlfCrApsId(pic->slices[i]->getTileGroupCcAlfCrApsId());
+                    pcEncPic->slices[i]->setTileGroupCcAlfCrEnabledFlag(pic->slices[i]->getTileGroupCcAlfCrEnabledFlag());
+#endif
                   }
                 }
 
@@ -579,11 +585,13 @@ void DecLib::executeLoopFilters()
 
   if( cs.sps->getALFEnabledFlag() )
   {
-      // ALF decodes the differentially coded coefficients and stores them in the parameters structure.
-      // Code could be restructured to do directly after parsing. So far we just pass a fresh non-const
-      // copy in case the APS gets used more than once.
-      m_cALF.ALFProcess(cs);
-
+#if JVET_Q0795_CCALF
+    m_cALF.getCcAlfFilterParam() = cs.slice->m_ccAlfFilterParam;
+#endif
+    // ALF decodes the differentially coded coefficients and stores them in the parameters structure.
+    // Code could be restructured to do directly after parsing. So far we just pass a fresh non-const
+    // copy in case the APS gets used more than once.
+    m_cALF.ALFProcess(cs);
   }
 
 #if SUBPIC_DECCHECK 
@@ -916,6 +924,66 @@ void activateAPS(PicHeader* picHeader, Slice* pSlice, ParameterSetManager& param
     }
   }
 
+#if JVET_Q0795_CCALF
+  CcAlfFilterParam &filterParam = pSlice->m_ccAlfFilterParam;
+  // cleanup before copying
+  for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+  {
+    memset( filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], 0, sizeof(filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx]) );
+    memset( filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], 0, sizeof(filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx]) );
+  }
+  memset( filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1], false, sizeof(filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1]) );
+  memset( filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1], false, sizeof(filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1]) );
+
+  if(pSlice->getTileGroupCcAlfCbEnabledFlag())
+  {
+    int apsId = pSlice->getTileGroupCcAlfCbApsId();
+    APS *aps = parameterSetManager.getAPS(apsId, ALF_APS);
+    if(aps)
+    {
+      apss[apsId] = aps;
+      if (false == parameterSetManager.activateAPS(apsId, ALF_APS))
+      {
+        THROW("APS activation failed!");
+      }
+
+      CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
+      //ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
+
+      filterParam.ccAlfFilterCount[COMPONENT_Cb - 1] = aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cb - 1];
+      for (int filterIdx=0; filterIdx < filterParam.ccAlfFilterCount[COMPONENT_Cb - 1]; filterIdx++ )
+      {
+        filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx] = aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx];
+        memcpy(filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], sizeof(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx]));
+      }
+    }
+  }
+
+  if(pSlice->getTileGroupCcAlfCrEnabledFlag())
+  {
+    int apsId = pSlice->getTileGroupCcAlfCrApsId();
+    APS *aps = parameterSetManager.getAPS(apsId, ALF_APS);
+    if(aps)
+    {
+      apss[apsId] = aps;
+      if (false == parameterSetManager.activateAPS(apsId, ALF_APS))
+      {
+        THROW("APS activation failed!");
+      }
+
+      CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" );
+      //ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it.
+
+      filterParam.ccAlfFilterCount[COMPONENT_Cr - 1] = aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cr - 1];
+      for (int filterIdx=0; filterIdx < filterParam.ccAlfFilterCount[COMPONENT_Cr - 1]; filterIdx++ )
+      {
+        filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx] = aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx];
+        memcpy(filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], sizeof(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx]));
+      }
+    }
+  }
+#endif
+
   if (picHeader->getLmcsEnabledFlag() && lmcsAPS == nullptr)
   {
     lmcsAPS = parameterSetManager.getAPS(picHeader->getLmcsAPSId(), LMCS_APS);
@@ -1082,6 +1150,10 @@ void DecLib::xActivateParameterSets( const int layerId )
     {
       m_cALF.create( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getMaxCUWidth(), sps->getMaxCUHeight(), sps->getMaxCodingDepth(), sps->getBitDepths().recon );
     }
+#if JVET_Q0795_CCALF
+    pSlice->m_ccAlfFilterControl[0] = m_cALF.getCcAlfControlIdc(COMPONENT_Cb);
+    pSlice->m_ccAlfFilterControl[1] = m_cALF.getCcAlfControlIdc(COMPONENT_Cr);
+#endif
   }
   else
   {
@@ -1211,15 +1283,21 @@ void DecLib::xParsePrefixSEImessages()
 void DecLib::xDecodePicHeader( InputNALUnit& nalu )
 {
   m_HLSReader.setBitstream( &nalu.getBitstream() );
+#if JVET_Q0775_PH_IN_SH
+  m_HLSReader.parsePictureHeader( &m_picHeader, &m_parameterSetManager, true );
+#else
   m_HLSReader.parsePictureHeader( &m_picHeader, &m_parameterSetManager);
+#endif
   m_picHeader.setValid();
 }
 
 bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDisplay )
 {
+#if !JVET_Q0775_PH_IN_SH
   if(m_picHeader.isValid() == false) {
     return false;
   }
+#endif
   m_apcSlicePilot->setPicHeader( &m_picHeader );
   m_apcSlicePilot->initSlice(); // the slice pilot is an object to prepare for a new slice
                                 // it is not associated with picture, sps or pps structures.
@@ -1255,6 +1333,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl
     CHECK(nalu.m_temporalId != 0, "Current GDR picture has TemporalId not equal to 0");
 
   m_HLSReader.setBitstream( &nalu.getBitstream() );
+#if JVET_Q0795_CCALF
+  m_apcSlicePilot->m_ccAlfFilterParam = m_cALF.getCcAlfFilterParam();
+#endif
   m_HLSReader.parseSliceHeader( m_apcSlicePilot, &m_picHeader, &m_parameterSetManager, m_prevTid0POC );
 
   // update independent slice index
diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp
index 8adadb3a22e641dc8db273f76428105e7b0f7380..9e4d1360f7ecba1201d193cf282e85e70cf90cac 100644
--- a/source/Lib/DecoderLib/DecSlice.cpp
+++ b/source/Lib/DecoderLib/DecSlice.cpp
@@ -170,6 +170,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
       {
         // Top is available, so use it.
         cabacReader.getCtx() = m_entropyCodingSyncContextState;
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+        cs.setPrevPLT(m_palettePredictorSyncState);
+#endif
       }
       pic->m_prevQP[0] = pic->m_prevQP[1] = slice->getSliceQp();
     }
@@ -203,6 +206,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
     if( ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled )
     {
       m_entropyCodingSyncContextState = cabacReader.getCtx();
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+      cs.storePrevPLT(m_palettePredictorSyncState);
+#endif
     }
 
 
diff --git a/source/Lib/DecoderLib/DecSlice.h b/source/Lib/DecoderLib/DecSlice.h
index 1ff2a2282be31abb227e326a9167d515ffffe64d..cd918ed76d3fe28fab725c5efd40965359a4af74 100644
--- a/source/Lib/DecoderLib/DecSlice.h
+++ b/source/Lib/DecoderLib/DecSlice.h
@@ -63,6 +63,9 @@ private:
   DecCu*          m_pcCuDecoder;
 
   Ctx             m_entropyCodingSyncContextState;      ///< context storage for state of contexts at the wavefront/WPP/entropy-coding-sync second CTU of tile-row
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+  PLTBuf          m_palettePredictorSyncState;      /// palette predictor storage at wavefront/WPP
+#endif
 
 public:
   DecSlice();
diff --git a/source/Lib/DecoderLib/NALread.cpp b/source/Lib/DecoderLib/NALread.cpp
index 07dddd03f67e8834f26b88a790f14d2d247b4b5b..819bcc25180de163afd088f8e2ff0f93e26f2484 100644
--- a/source/Lib/DecoderLib/NALread.cpp
+++ b/source/Lib/DecoderLib/NALread.cpp
@@ -167,4 +167,12 @@ void read(InputNALUnit& nalu)
   bitstream.resetToStart();
   readNalUnitHeader(nalu);
 }
+#if JVET_Q0775_PH_IN_SH
+bool checkPictureHeaderInSliceHeaderFlag(InputNALUnit& nalu)
+{
+  InputBitstream& bitstream = nalu.getBitstream();
+  CHECK(bitstream.getByteLocation() != 2, "The picture_header_in_slice_header_flag is the first bit after the NAL unit header");
+  return (bool)bitstream.read(1);
+}
+#endif
 //! \}
diff --git a/source/Lib/DecoderLib/NALread.h b/source/Lib/DecoderLib/NALread.h
index 1778dc5055e3013313ed48bd88c6cc9bacad224f..f807fbed75608d03e84197ae2f75534585c8d47b 100644
--- a/source/Lib/DecoderLib/NALread.h
+++ b/source/Lib/DecoderLib/NALread.h
@@ -67,7 +67,9 @@ class InputNALUnit : public NALUnit
 
 void read(InputNALUnit& nalu);
 void readNalUnitHeader(InputNALUnit& nalu);
-
+#if JVET_Q0775_PH_IN_SH
+bool checkPictureHeaderInSliceHeaderFlag(InputNALUnit & nalu);
+#endif
 //! \}
 
 #endif
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index fd516bb03df6123e3e66fb94fbef8c56de7d964e..68d4bdba0d209c2cc817d7c8d129be65ee6c6015 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -825,8 +825,17 @@ void HLSyntaxReader::parseAlfAps( APS* aps )
   READ_FLAG(code, "alf_chroma_new_filter");
   param.newFilterFlag[CHANNEL_TYPE_CHROMA] = code;
 
-  CHECK(param.newFilterFlag[CHANNEL_TYPE_LUMA] == 0 && param.newFilterFlag[CHANNEL_TYPE_CHROMA] == 0,
-    "bitstream conformance error, alf_luma_filter_signal_flag and alf_chroma_filter_signal_flag shall not equal to zero at the same time");
+#if JVET_Q0795_CCALF
+  CcAlfFilterParam ccAlfParam = aps->getCcAlfAPSParam();
+  READ_FLAG(code, "alf_cc_cb_filter_signal_flag");
+  ccAlfParam.newCcAlfFilter[COMPONENT_Cb - 1] = code;
+  READ_FLAG(code, "alf_cc_cr_filter_signal_flag");
+  ccAlfParam.newCcAlfFilter[COMPONENT_Cr - 1] = code;
+  CHECK(param.newFilterFlag[CHANNEL_TYPE_LUMA] == 0 && param.newFilterFlag[CHANNEL_TYPE_CHROMA] == 0
+          && ccAlfParam.newCcAlfFilter[COMPONENT_Cb - 1] == 0 && ccAlfParam.newCcAlfFilter[COMPONENT_Cr - 1] == 0,
+        "bitstream conformance error: one of alf_luma_filter_signal_flag, alf_chroma_filter_signal_flag, "
+        "alf_cross_component_cb_filter_signal_flag, and alf_cross_component_cr_filter_signal_flag shall be nonzero");
+#endif
 
   if (param.newFilterFlag[CHANNEL_TYPE_LUMA])
   {
@@ -876,6 +885,62 @@ void HLSyntaxReader::parseAlfAps( APS* aps )
       alfFilter( param, true, altIdx );
     }
   }
+
+#if JVET_Q0795_CCALF
+  for (int ccIdx = 0; ccIdx < 2; ccIdx++)
+  {
+    if (ccAlfParam.newCcAlfFilter[ccIdx])
+    {
+      if (MAX_NUM_CC_ALF_FILTERS > 1)
+      {
+        READ_UVLC(code, ccIdx == 0 ? "alf_cc_cb_filters_signalled_minus1" : "alf_cc_cr_filters_signalled_minus1");
+      }
+      else
+      {
+        code = 0;
+      }
+      ccAlfParam.ccAlfFilterCount[ccIdx] = code + 1;
+
+      for (int filterIdx = 0; filterIdx < ccAlfParam.ccAlfFilterCount[ccIdx]; filterIdx++)
+      {
+        ccAlfParam.ccAlfFilterIdxEnabled[ccIdx][filterIdx] = true;
+        AlfFilterShape alfShape(size_CC_ALF);
+
+        short *coeff = ccAlfParam.ccAlfCoeff[ccIdx][filterIdx];
+        // Filter coefficients
+        for (int i = 0; i < alfShape.numCoeff - 1; i++)
+        {
+          READ_CODE(CCALF_BITS_PER_COEFF_LEVEL, code,
+                    ccIdx == 0 ? "alf_cc_cb_mapped_coeff_abs" : "alf_cc_cr_mapped_coeff_abs");
+          if (code == 0)
+          {
+            coeff[i] = 0;
+          }
+          else
+          {
+            coeff[i] = 1 << (code - 1);
+            READ_FLAG(code, ccIdx == 0 ? "alf_cc_cb_coeff_sign" : "alf_cc_cr_coeff_sign");
+            coeff[i] *= 1 - 2 * code;
+          }
+        }
+
+        DTRACE(g_trace_ctx, D_SYNTAX, "%s coeff filterIdx %d: ", ccIdx == 0 ? "Cb" : "Cr", filterIdx);
+        for (int i = 0; i < alfShape.numCoeff; i++)
+        {
+          DTRACE(g_trace_ctx, D_SYNTAX, "%d ", coeff[i]);
+        }
+        DTRACE(g_trace_ctx, D_SYNTAX, "\n");
+      }
+
+      for (int filterIdx = ccAlfParam.ccAlfFilterCount[ccIdx]; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++)
+      {
+        ccAlfParam.ccAlfFilterIdxEnabled[ccIdx][filterIdx] = false;
+      }
+    }
+  }
+  aps->setCcAlfAPSParam(ccAlfParam);
+#endif
+
   aps->setAlfAPSParam(param);
 }
 
@@ -1115,6 +1180,15 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
       pcSPS->setLoopFilterAcrossSubpicEnabledFlag(picIdx, uiCode);
     }
   }
+  else
+  {
+    pcSPS->setNumSubPics(1);
+    pcSPS->setSubPicCtuTopLeftX(0, 0);
+    pcSPS->setSubPicCtuTopLeftY(0, 0);
+    pcSPS->setSubPicWidth(0, (pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) >> floorLog2(pcSPS->getCTUSize()));
+    pcSPS->setSubPicHeight(0, (pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) >> floorLog2(pcSPS->getCTUSize()));
+  }
+
   READ_FLAG(uiCode, "sps_subpic_id_present_flag");                           pcSPS->setSubPicIdPresentFlag( uiCode != 0 );
   if( pcSPS->getSubPicIdPresentFlag() )
   {
@@ -1253,11 +1327,13 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_slice_luma");
   unsigned minQtLog2SizeIntraY = uiCode + pcSPS->getLog2MinCodingBlockSize();
   minQT[0] = 1 << minQtLog2SizeIntraY;
+#if !JVET_Q0481_PARTITION_CONSTRAINTS_ORDER
   READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_slice");
   unsigned minQtLog2SizeInterY = uiCode + pcSPS->getLog2MinCodingBlockSize();
   minQT[1] = 1 << minQtLog2SizeInterY;
   READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_slice");     maxBTD[1] = uiCode;
   CHECK(uiCode > 2*(ctbLog2SizeY - log2MinCUSize), "sps_max_mtt_hierarchy_depth_inter_slice shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)");
+#endif
   READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_slice_luma");     maxBTD[0] = uiCode;
   CHECK(uiCode > 2 * (ctbLog2SizeY - log2MinCUSize), "sps_max_mtt_hierarchy_depth_intra_slice_luma shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)");
 
@@ -1269,6 +1345,13 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
     READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_slice_luma");     maxTTSize[0] <<= uiCode;
     CHECK(uiCode > ctbLog2SizeY - minQtLog2SizeIntraY, "Invalid code");
   }
+#if JVET_Q0481_PARTITION_CONSTRAINTS_ORDER
+  READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_slice");
+  unsigned minQtLog2SizeInterY = uiCode + pcSPS->getLog2MinCodingBlockSize();
+  minQT[1] = 1 << minQtLog2SizeInterY;
+  READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_slice");     maxBTD[1] = uiCode;
+  CHECK(uiCode > 2*(ctbLog2SizeY - log2MinCUSize), "sps_max_mtt_hierarchy_depth_inter_slice shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)");
+#endif
   maxTTSize[1] = maxBTSize[1] = minQT[1];
   if (maxBTD[1] != 0)
   {
@@ -1334,6 +1417,16 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
 
   READ_FLAG( uiCode, "sps_sao_enabled_flag" );                      pcSPS->setSAOEnabledFlag ( uiCode ? true : false );
   READ_FLAG( uiCode, "sps_alf_enabled_flag" );                      pcSPS->setALFEnabledFlag ( uiCode ? true : false );
+#if JVET_Q0795_CCALF
+  if (pcSPS->getALFEnabledFlag() && pcSPS->getChromaFormatIdc() != CHROMA_400)
+  {
+    READ_FLAG( uiCode, "sps_ccalf_enabled_flag" );                      pcSPS->setCCALFEnabledFlag ( uiCode ? true : false );
+  }
+  else
+  {
+    pcSPS->setCCALFEnabledFlag(false);
+  }
+#endif
 
   READ_FLAG(uiCode, "sps_transform_skip_enabled_flag"); pcSPS->setTransformSkipEnabledFlag(uiCode ? true : false);
   if (pcSPS->getTransformSkipEnabledFlag())
@@ -1425,7 +1518,14 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   }
   if (pcSPS->getChromaFormatIdc() == CHROMA_444)
   {
+#if JVET_Q0820_ACT
+    if (pcSPS->getLog2MaxTbSize() != 6)
+    {
+      READ_FLAG(uiCode, "sps_act_enabled_flag");                                pcSPS->setUseColorTrans(uiCode != 0);
+    }
+#else
     READ_FLAG(uiCode, "sps_act_enabled_flag");                                  pcSPS->setUseColorTrans(uiCode != 0);
+#endif
   }
   else
   {
@@ -1470,6 +1570,11 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS)
   }
 #endif
 
+#if JVET_Q0297_MER
+  READ_UVLC(uiCode, "log2_parallel_merge_level_minus2");
+  pcSPS->setLog2ParallelMergeLevelMinus2(uiCode);
+#endif
+
   // KJS: reference picture sets to be replaced
 
   // KJS: not found in draft -> does not exist
@@ -1721,7 +1826,11 @@ void HLSyntaxReader::parseVPS(VPS* pcVPS)
   xReadRbspTrailingBits();
 }
 
+#if JVET_Q0775_PH_IN_SH
+void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManager *parameterSetManager, bool readRbspTrailingBits )
+#else
 void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManager *parameterSetManager )
+#endif
 {
   uint32_t  uiCode; 
   int       iCode;
@@ -1853,6 +1962,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
     }
   }
   
+#if !JVET_Q0155_COLOUR_ID
   // 4:4:4 colour plane ID
   if( sps->getSeparateColourPlaneFlag() )
   {
@@ -1863,6 +1973,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
   {
     picHeader->setColourPlaneId( 0 );
   }
+#endif
 
   // picture output flag
   if( pps->getOutputFlagPresentFlag() )
@@ -1976,10 +2087,12 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
       READ_UVLC(uiCode, "pic_log2_diff_min_qt_min_cb_intra_slice_luma");
       unsigned minQtLog2SizeIntraY = uiCode + sps->getLog2MinCodingBlockSize();
       minQT[0] = 1 << minQtLog2SizeIntraY;
+#if !JVET_Q0819_PH_CHANGES
       READ_UVLC(uiCode, "pic_log2_diff_min_qt_min_cb_inter_slice");
       unsigned minQtLog2SizeInterY = uiCode + sps->getLog2MinCodingBlockSize();
       minQT[1] = 1 << minQtLog2SizeInterY;
       READ_UVLC(uiCode, "pic_max_mtt_hierarchy_depth_inter_slice");              maxBTD[1] = uiCode;
+#endif
       READ_UVLC(uiCode, "pic_max_mtt_hierarchy_depth_intra_slice_luma");         maxBTD[0] = uiCode;
 
       maxTTSize[0] = maxBTSize[0] = minQT[0];
@@ -1990,6 +2103,12 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
         READ_UVLC(uiCode, "pic_log2_diff_max_tt_min_qt_intra_slice_luma");       maxTTSize[0] <<= uiCode;
         CHECK(uiCode > ctbLog2SizeY - minQtLog2SizeIntraY, "Invalid code");
       }
+#if JVET_Q0819_PH_CHANGES
+      READ_UVLC(uiCode, "pic_log2_diff_min_qt_min_cb_inter_slice");
+      unsigned minQtLog2SizeInterY = uiCode + sps->getLog2MinCodingBlockSize();
+      minQT[1] = 1 << minQtLog2SizeInterY;
+      READ_UVLC(uiCode, "pic_max_mtt_hierarchy_depth_inter_slice");              maxBTD[1] = uiCode;
+#endif
       maxTTSize[1] = maxBTSize[1] = minQT[1];
       if (maxBTD[1] != 0)
       {
@@ -2211,6 +2330,10 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
   }
   
   // alf enable flags and aps IDs
+#if JVET_Q0795_CCALF
+  picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, false);
+  picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, false);
+#endif
   if( sps->getALFEnabledFlag() )
   {
     READ_FLAG(uiCode, "pic_alf_enabled_present_flag");  
@@ -2250,6 +2373,30 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
           READ_CODE(3, uiCode, "pic_alf_aps_id_chroma");
           picHeader->setAlfApsIdChroma(uiCode);
         }
+#if JVET_Q0795_CCALF
+        if (sps->getCCALFEnabledFlag())
+        {
+          READ_FLAG(uiCode, "ph_cc_alf_cb_enabled_flag");
+          picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, uiCode != 0);
+          picHeader->setCcAlfCbApsId(-1);
+          if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cb))
+          {
+            // parse APS ID
+            READ_CODE(3, uiCode, "ph_cc_alf_cb_aps_id");
+            picHeader->setCcAlfCbApsId(uiCode);
+          }
+          // Cr
+          READ_FLAG(uiCode, "ph_cc_alf_cr_enabled_flag");
+          picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, uiCode != 0);
+          picHeader->setCcAlfCrApsId(-1);
+          if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cr))
+          {
+            // parse APS ID
+            READ_CODE(3, uiCode, "ph_cc_alf_cr_aps_id");
+            picHeader->setCcAlfCrApsId(uiCode);
+          }
+        }
+#endif
       }
       else
       {
@@ -2404,7 +2551,14 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag
     }
   }
 
+#if JVET_Q0775_PH_IN_SH
+  if( readRbspTrailingBits )
+  {
+    xReadRbspTrailingBits();
+  }
+#else
   xReadRbspTrailingBits();
+#endif
 }
 
 void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC)
@@ -2417,7 +2571,15 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par
 #endif
   PPS* pps = NULL;
   SPS* sps = NULL;
-
+#if JVET_Q0775_PH_IN_SH
+  READ_FLAG(uiCode, "picture_header_in_slice_header_flag");
+  if (uiCode)
+  {
+    pcSlice->setPictureHeaderInSliceHeader(true);
+    parsePictureHeader(picHeader, parameterSetManager, false);
+    picHeader->setValid();
+  }
+#endif
   CHECK(picHeader==0, "Invalid Picture Header");
   CHECK(picHeader->isValid()==false, "Invalid Picture Header");
   pps = parameterSetManager->getPPS( picHeader->getPPSId() );
@@ -2534,11 +2696,23 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par
 
     READ_UVLC (    uiCode, "slice_type" );            pcSlice->setSliceType((SliceType)uiCode);
 
+#if JVET_Q0155_COLOUR_ID
+    // 4:4:4 colour plane ID
+    if( sps->getSeparateColourPlaneFlag() )
+    {
+      READ_CODE( 2, uiCode, "colour_plane_id" ); pcSlice->setColourPlaneId( uiCode );
+      CHECK( uiCode > 2, "colour_plane_id exceeds valid range" );
+    }
+    else
+    {
+      pcSlice->setColourPlaneId( 0 );
+    }
+#endif
+
     // inherit values from picture header
     //   set default values in case slice overrides are disabled
     pcSlice->inheritFromPicHeader( picHeader, pps, sps );
 
-
     if( picHeader->getPicRplPresentFlag() )
     {
       pcSlice->setRPL0(picHeader->getRPL0());
@@ -2951,6 +3125,41 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par
       }
       pcSlice->setTileGroupAlfEnabledFlag(COMPONENT_Cb, alfChromaIdc & 1);
       pcSlice->setTileGroupAlfEnabledFlag(COMPONENT_Cr, alfChromaIdc >> 1);
+
+#if JVET_Q0795_CCALF
+      CcAlfFilterParam &filterParam = pcSlice->m_ccAlfFilterParam;
+      if (sps->getCCALFEnabledFlag() && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
+      {
+        READ_FLAG(uiCode, "slice_cc_alf_cb_enabled_flag");
+        pcSlice->setTileGroupCcAlfCbEnabledFlag(uiCode);
+        filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] = (uiCode == 1) ? true : false;
+        pcSlice->setTileGroupCcAlfCbApsId(-1);
+        if (filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1])
+        {
+          // parse APS ID
+          READ_CODE(3, uiCode, "slice_cc_alf_cb_aps_id");
+          pcSlice->setTileGroupCcAlfCbApsId(uiCode);
+        }
+        // Cr
+        READ_FLAG(uiCode, "slice_cc_alf_cr_enabled_flag");
+        pcSlice->setTileGroupCcAlfCrEnabledFlag(uiCode);
+        filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] = (uiCode == 1) ? true : false;
+        pcSlice->setTileGroupCcAlfCrApsId(-1);
+        if (filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1])
+        {
+          // parse APS ID
+          READ_CODE(3, uiCode, "slice_cc_alf_cr_aps_id");
+          pcSlice->setTileGroupCcAlfCrApsId(uiCode);
+        }
+      }
+      else
+      {
+        filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] = false;
+        filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] = false;
+        pcSlice->setTileGroupCcAlfCbApsId(-1);
+        pcSlice->setTileGroupCcAlfCrApsId(-1);
+      }
+#endif
     }
 
 
@@ -3130,6 +3339,9 @@ 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_Q0795_CCALF
+  READ_FLAG(symbol,  "no_ccalf_constraint_flag");                  cinfo->setNoCCAlfConstraintFlag(symbol > 0 ? true : false);
+#endif
   READ_FLAG(symbol,  "no_joint_cbcr_constraint_flag");             cinfo->setNoJointCbCrConstraintFlag(symbol > 0 ? true : false);
 
   READ_FLAG(symbol,  "no_ref_wraparound_constraint_flag");         cinfo->setNoRefWraparoundConstraintFlag(symbol > 0 ? true : false);
diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h
index 69e3f479ca770b34ac1efdb3ebb54d0bb22d7ad3..01cad942a0c463a1e98052e0bfffb28dda663a25 100644
--- a/source/Lib/DecoderLib/VLCReader.h
+++ b/source/Lib/DecoderLib/VLCReader.h
@@ -167,7 +167,11 @@ public:
   void  parseConstraintInfo   (ConstraintInfo *cinfo);
   void  parseProfileTierLevel ( ProfileTierLevel *ptl, int maxNumSubLayersMinus1);
   void  parseHrdParameters  ( HRDParameters *hrd, uint32_t firstSubLayer, uint32_t tempLevelHigh );
+#if JVET_Q0775_PH_IN_SH
+  void  parsePictureHeader  ( PicHeader* picHeader, ParameterSetManager *parameterSetManager, bool readRbspTrailingBits );
+#else
   void  parsePictureHeader  ( PicHeader* picHeader, ParameterSetManager *parameterSetManager );
+#endif
   void  parseSliceHeader    ( Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC );
   void  parseSliceHeaderToPoc ( Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC );
   void  parseTerminatingBit ( uint32_t& ruiBit );
@@ -178,6 +182,9 @@ public:
   void  decodeScalingList   ( ScalingList *scalingList, uint32_t scalingListId, bool isPredictor);
   void parseReshaper        ( SliceReshapeInfo& sliceReshaperInfo, const SPS* pcSPS, const bool isIntra );
   void alfFilter( AlfParam& alfParam, const bool isChroma, const int altIdx );
+#if JVET_Q0795_CCALF
+  void ccAlfFilter( Slice *pcSlice );
+#endif
 
 private:
   int  alfGolombDecode( const int k, const bool signed_val=true );
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index c814c521abbd7ecf4bbcf7ab531873b0b10a268f..4044ba80eece7c7925d054bb2c5bf9381686fc5a 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -187,6 +187,26 @@ void CABACWriter::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i
     }
   }
 
+#if JVET_Q0795_CCALF
+  if ( !skipAlf )
+  {
+    for ( int compIdx = 1; compIdx < getNumberValidComponents( cs.pcv->chrFormat ); compIdx++ )
+    {
+      if (cs.slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1])
+      {
+        const int filterCount   = cs.slice->m_ccAlfFilterParam.ccAlfFilterCount[compIdx - 1];
+
+        const int      ry = ctuRsAddr / cs.pcv->widthInCtus;
+        const int      rx = ctuRsAddr % cs.pcv->widthInCtus;
+        const Position lumaPos(rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight);
+
+        codeCcAlfFilterControlIdc(cs.slice->m_ccAlfFilterControl[compIdx - 1][ctuRsAddr], cs, ComponentID(compIdx),
+                                  ctuRsAddr, cs.slice->m_ccAlfFilterControl[compIdx - 1], lumaPos, filterCount);
+      }
+    }
+  }
+#endif
+
   if ( CS::isDualITree(cs) && cs.pcv->chrFormat != CHROMA_400 && cs.pcv->maxCUWidth > 64 )
   {
     CUCtx chromaCuCtx(qps[CH_C]);
@@ -3351,6 +3371,49 @@ void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr,
   }
 }
 
+#if JVET_Q0795_CCALF
+void CABACWriter::codeCcAlfFilterControlIdc(uint8_t idcVal, CodingStructure &cs, const ComponentID compID,
+                                            const int curIdx, const uint8_t *filterControlIdc, Position lumaPos,
+                                            const int filterCount)
+{
+  CHECK(idcVal > filterCount, "Filter index is too large");
+
+  const uint32_t curSliceIdx    = cs.slice->getIndependentSliceIdx();
+  const uint32_t curTileIdx     = cs.pps->getTileIdx( lumaPos );
+  Position       leftLumaPos    = lumaPos.offset(-(int)cs.pcv->maxCUWidth, 0);
+  Position       aboveLumaPos   = lumaPos.offset(0, -(int)cs.pcv->maxCUWidth);
+  bool           leftAvail      = cs.getCURestricted( leftLumaPos,  lumaPos, curSliceIdx, curTileIdx, CH_L ) ? true : false;
+  bool           aboveAvail     = cs.getCURestricted( aboveLumaPos, lumaPos, curSliceIdx, curTileIdx, CH_L ) ? true : false;
+  int            ctxt           = 0;
+
+  if (leftAvail)
+  {
+    ctxt += ( filterControlIdc[curIdx - 1]) ? 1 : 0;
+  }
+  if (aboveAvail)
+  {
+    ctxt += (filterControlIdc[curIdx - cs.pcv->widthInCtus]) ? 1 : 0;
+  }
+  ctxt += ( compID == COMPONENT_Cr ) ? 3 : 0;
+
+  m_BinEncoder.encodeBin( ( idcVal == 0 ) ? 0 : 1, Ctx::CcAlfFilterControlFlag( ctxt ) ); // ON/OFF flag is context coded
+  if ( idcVal > 0 )
+  {
+    int val = (idcVal - 1);
+    while ( val )
+    {
+      m_BinEncoder.encodeBinEP( 1 );
+      val--;
+    }
+    if ( idcVal < filterCount )
+    {
+      m_BinEncoder.encodeBinEP( 0 );
+    }
+  }
+  DTRACE( g_trace_ctx, D_SYNTAX, "ccAlfFilterControlIdc() compID=%d pos=(%d,%d) ctxt=%d, filterCount=%d, idcVal=%d\n", compID, lumaPos.x, lumaPos.y, ctxt, filterCount, idcVal );
+}
+#endif
+
 void CABACWriter::code_unary_fixed( unsigned symbol, unsigned ctxId, unsigned unary_max, unsigned fixed )
 {
   bool unary = (symbol <= unary_max);
diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h
index 940fa4c22be37adc3cf9c970d17187ee34b4dca9..8f2124456874fb612b18025a44150acf086681ab 100644
--- a/source/Lib/EncoderLib/CABACWriter.h
+++ b/source/Lib/EncoderLib/CABACWriter.h
@@ -164,6 +164,10 @@ public:
   void        codeAlfCtuAlternatives     ( CodingStructure& cs, ChannelType channel, AlfParam* alfParam);
   void        codeAlfCtuAlternatives     ( CodingStructure& cs, ComponentID compID, AlfParam* alfParam);
   void        codeAlfCtuAlternative      ( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, const AlfParam* alfParam = NULL );
+#if JVET_Q0795_CCALF
+  void codeCcAlfFilterControlIdc(uint8_t idcVal, CodingStructure &cs, const ComponentID compID, const int curIdx,
+                                 const uint8_t *filterControlIdc, Position lumaPos, const int filterCount);
+#endif
 
 private:
   void        unary_max_symbol          ( unsigned symbol, unsigned ctxId0, unsigned ctxIdN, unsigned maxSymbol );
diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp
index 6de3317a96841f45a070bbe482aac24164d9fed8..252cea9d5bd56f04beaf784fb88c2f9b69846e29 100644
--- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp
+++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp
@@ -42,6 +42,20 @@
 #define AlfCtx(c) SubCtx( Ctx::Alf, c)
 std::vector<double> EncAdaptiveLoopFilter::m_lumaLevelToWeightPLUT;
 
+#if JVET_Q0795_CCALF
+#include <algorithm>
+
+#if MAX_NUM_CC_ALF_FILTERS>1
+struct FilterIdxCount
+{
+  uint64_t count;
+  uint8_t filterIdx;
+};
+
+bool compareCounts(FilterIdxCount a, FilterIdxCount b) { return a.count > b.count; }
+#endif
+#endif
+
 void AlfCovariance::getClipMax(const AlfFilterShape& alfShape, int *clip_max) const
 {
   for( int k = 0; k < numCoeff-1; ++k )
@@ -241,6 +255,27 @@ double AlfCovariance::calcErrorForCoeffs( const int *clip, const int *coeff, con
   return error / factor;
 }
 
+#if JVET_Q0795_CCALF
+double AlfCovariance::calcErrorForCcAlfCoeffs(const int* coeff, const int numCoeff, const int bitDepth) const
+{
+  double factor = 1 << (bitDepth - 1);
+  double error = 0;
+
+  for (int i = 0; i < numCoeff; i++)   // diagonal
+  {
+    double sum = 0;
+    for (int j = i + 1; j < numCoeff; j++)
+    {
+      // E[j][i] = E[i][j], sum will be multiplied by 2 later
+      sum += E[0][0][i][j] * coeff[j];
+    }
+    error += ((E[0][0][i][i] * coeff[i] + sum * 2) / factor - 2 * y[0][i]) * coeff[i];
+  }
+
+  return error / factor;
+}
+#endif
+
 double AlfCovariance::calculateError( const int *clip, const double *coeff, const int numCoeff ) const
 {
   double sum = 0;
@@ -417,6 +452,13 @@ EncAdaptiveLoopFilter::EncAdaptiveLoopFilter( int& apsIdStart )
   m_diffFilterCoeff = nullptr;
 
   m_alfWSSD = 0;
+
+#if JVET_Q0795_CCALF
+  m_alfCovarianceCcAlf[0] = nullptr;
+  m_alfCovarianceCcAlf[1] = nullptr;
+  m_alfCovarianceFrameCcAlf[0] = nullptr;
+  m_alfCovarianceFrameCcAlf[1] = nullptr;
+#endif
 }
 
 void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, const int picHeight, const ChromaFormat chromaFormatIDC, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE], const int internalBitDepth[MAX_NUM_CHANNEL_TYPE] )
@@ -499,6 +541,51 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co
   }
   m_alfCtbFilterSetIndexTmp.resize(m_numCTUsInPic);
   memset(m_clipDefaultEnc, 0, sizeof(m_clipDefaultEnc));
+#if JVET_Q0795_CCALF
+  m_apsIdCcAlfStart[0] = (int) MAX_NUM_APS;
+  m_apsIdCcAlfStart[1] = (int) MAX_NUM_APS;
+  for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ )
+  {
+    int numFilters = MAX_NUM_CC_ALF_FILTERS;
+    m_alfCovarianceCcAlf[compIdx-1] = new AlfCovariance**[m_filterShapesCcAlf[compIdx-1].size()];
+    m_alfCovarianceFrameCcAlf[compIdx-1] = new AlfCovariance*[m_filterShapesCcAlf[compIdx-1].size()];
+    for( int i = 0; i != m_filterShapesCcAlf[compIdx-1].size(); i++ )
+    {
+      m_alfCovarianceFrameCcAlf[compIdx - 1][i] = new AlfCovariance[numFilters];
+      for (int k = 0; k < numFilters; k++)
+      {
+        m_alfCovarianceFrameCcAlf[compIdx - 1][i][k].create(m_filterShapesCcAlf[compIdx - 1][i].numCoeff);
+      }
+
+      m_alfCovarianceCcAlf[compIdx - 1][i] = new AlfCovariance *[numFilters];
+      for (int j = 0; j < numFilters; j++)
+      {
+        m_alfCovarianceCcAlf[compIdx - 1][i][j] = new AlfCovariance[m_numCTUsInPic];
+        for (int k = 0; k < m_numCTUsInPic; k++)
+        {
+          m_alfCovarianceCcAlf[compIdx - 1][i][j][k].create(m_filterShapesCcAlf[compIdx - 1][i].numCoeff);
+        }
+      }
+    }
+  }
+  m_trainingCovControl   = new uint8_t[m_numCTUsInPic];
+  m_unfilteredDistortion = new uint64_t *[1];
+  for (int i = 0; i < 1; i++)
+  {
+    m_unfilteredDistortion[i] = new uint64_t[m_numCTUsInPic];
+  }
+  for ( int i = 0; i < MAX_NUM_CC_ALF_FILTERS; i++ )
+  {
+    m_trainingDistortion[i] = new uint64_t[m_numCTUsInPic];
+  }
+  m_filterControl         = new uint8_t[m_numCTUsInPic];
+  m_bestFilterControl     = new uint8_t[m_numCTUsInPic];
+  uint32_t area           = (picWidth >> getComponentScaleX(COMPONENT_Cb,chromaFormatIDC))*(picHeight >> getComponentScaleY(COMPONENT_Cb,chromaFormatIDC));
+  m_bufOrigin             = ( Pel* ) xMalloc( Pel, area );
+  m_buf                   = new PelBuf( m_bufOrigin, picWidth >> getComponentScaleX(COMPONENT_Cb,chromaFormatIDC), picWidth >> getComponentScaleX(COMPONENT_Cb,chromaFormatIDC), picHeight >> getComponentScaleY(COMPONENT_Cb,chromaFormatIDC) );
+  m_lumaSwingGreaterThanThresholdCount = new uint64_t[m_numCTUsInPic];
+  m_chromaSampleCountNearMidPoint = new uint64_t[m_numCTUsInPic];
+#endif
 }
 
 void EncAdaptiveLoopFilter::destroy()
@@ -622,6 +709,106 @@ void EncAdaptiveLoopFilter::destroy()
     delete[] m_ctbDistortionUnfilter[comp];
     m_ctbDistortionUnfilter[comp] = nullptr;
   }
+
+#if JVET_Q0795_CCALF
+  for (int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++)
+  {
+    int numFilters = MAX_NUM_CC_ALF_FILTERS;
+    if (m_alfCovarianceFrameCcAlf[compIdx - 1])
+    {
+      for (int i = 0; i != m_filterShapesCcAlf[compIdx - 1].size(); i++)
+      {
+        for (int k = 0; k < numFilters; k++)
+        {
+          m_alfCovarianceFrameCcAlf[compIdx - 1][i][k].destroy();
+        }
+        delete[] m_alfCovarianceFrameCcAlf[compIdx - 1][i];
+      }
+      delete[] m_alfCovarianceFrameCcAlf[compIdx - 1];
+      m_alfCovarianceFrameCcAlf[compIdx - 1] = nullptr;
+    }
+
+    if (m_alfCovarianceCcAlf[compIdx - 1])
+    {
+      for (int i = 0; i != m_filterShapesCcAlf[compIdx - 1].size(); i++)
+      {
+        for (int j = 0; j < numFilters; j++)
+        {
+          for (int k = 0; k < m_numCTUsInPic; k++)
+          {
+            m_alfCovarianceCcAlf[compIdx - 1][i][j][k].destroy();
+          }
+          delete[] m_alfCovarianceCcAlf[compIdx - 1][i][j];
+        }
+        delete[] m_alfCovarianceCcAlf[compIdx - 1][i];
+      }
+      delete[] m_alfCovarianceCcAlf[compIdx - 1];
+      m_alfCovarianceCcAlf[compIdx - 1] = nullptr;
+    }
+  }
+
+  if (m_trainingCovControl)
+  {
+    delete[] m_trainingCovControl;
+    m_trainingCovControl = nullptr;
+  }
+
+  for (int i = 0; i < 1; i++)
+  {
+    if (m_unfilteredDistortion[i])
+    {
+      delete[] m_unfilteredDistortion[i];
+      m_unfilteredDistortion[i] = nullptr;
+    }
+  }
+  delete[] m_unfilteredDistortion;
+  m_unfilteredDistortion = nullptr;
+
+  for ( int i = 0; i < MAX_NUM_CC_ALF_FILTERS; i++ )
+  {
+    if (m_trainingDistortion[i])
+    {
+      delete[] m_trainingDistortion[i];
+      m_trainingDistortion[i] = nullptr;
+    }
+  }
+
+  if (m_filterControl)
+  {
+    delete[] m_filterControl;
+    m_filterControl = nullptr;
+  }
+
+  if (m_bestFilterControl)
+  {
+    delete[] m_bestFilterControl;
+    m_bestFilterControl = nullptr;
+  }
+
+  if (m_bufOrigin)
+  {
+    xFree(m_bufOrigin);
+    m_bufOrigin = nullptr;
+  }
+
+  if (m_buf)
+  {
+    delete m_buf;
+    m_buf = nullptr;
+  }
+
+  if (m_lumaSwingGreaterThanThresholdCount)
+  {
+    delete[] m_lumaSwingGreaterThanThresholdCount;
+    m_lumaSwingGreaterThanThresholdCount = nullptr;
+  }
+  if (m_chromaSampleCountNearMidPoint)
+  {
+    delete[] m_chromaSampleCountNearMidPoint;
+    m_chromaSampleCountNearMidPoint = nullptr;
+  }
+#endif
+
   AdaptiveLoopFilter::destroy();
 }
 void EncAdaptiveLoopFilter::initCABACEstimator( CABACEncoder* cabacEncoder, CtxCache* ctxCache, Slice* pcSlice
@@ -634,6 +821,76 @@ void EncAdaptiveLoopFilter::initCABACEstimator( CABACEncoder* cabacEncoder, CtxC
   m_CABACEstimator->resetBits();
 }
 
+#if JVET_Q0795_CCALF
+void EncAdaptiveLoopFilter::xSetupCcAlfAPS( CodingStructure &cs )
+{
+  if (m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1])
+  {
+    int  ccAlfCbApsId = cs.slice->getTileGroupCcAlfCbApsId();
+    APS* aps = m_apsMap->getPS((cs.slice->getTileGroupCcAlfCbApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
+    if (aps == NULL)
+    {
+      aps = m_apsMap->allocatePS((ccAlfCbApsId << NUM_APS_TYPE_LEN) + ALF_APS);
+      aps->setTemporalId(cs.slice->getTLayer());
+    }
+    aps->getCcAlfAPSParam().ccAlfFilterEnabled[COMPONENT_Cb - 1] = 1;
+    aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cb - 1] = m_ccAlfFilterParam.ccAlfFilterCount[COMPONENT_Cb - 1];
+    for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+    {
+      aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx] =
+        m_ccAlfFilterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx];
+      memcpy(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx],
+             m_ccAlfFilterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], sizeof(short) * MAX_NUM_CC_ALF_CHROMA_COEFF);
+    }
+    aps->setAPSId(ccAlfCbApsId);
+    aps->setAPSType(ALF_APS);
+    if (m_reuseApsId[COMPONENT_Cb - 1] < 0)
+    {
+      aps->getCcAlfAPSParam().newCcAlfFilter[COMPONENT_Cb - 1] = 1;
+      m_apsMap->setChangedFlag((ccAlfCbApsId << NUM_APS_TYPE_LEN) + ALF_APS, true);
+      aps->setTemporalId(cs.slice->getTLayer());
+    }
+    cs.slice->setTileGroupCcAlfCbEnabledFlag(true);
+  }
+  else
+  {
+    cs.slice->setTileGroupCcAlfCbEnabledFlag(false);
+  }
+  if (m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1])
+  {
+    int  ccAlfCrApsId = cs.slice->getTileGroupCcAlfCrApsId();
+    APS* aps = m_apsMap->getPS((cs.slice->getTileGroupCcAlfCrApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
+    if (aps == NULL)
+    {
+      aps = m_apsMap->allocatePS((ccAlfCrApsId << NUM_APS_TYPE_LEN) + ALF_APS);
+      aps->setTemporalId(cs.slice->getTLayer());
+    }
+    aps->getCcAlfAPSParam().ccAlfFilterEnabled[COMPONENT_Cr - 1] = 1;
+    aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cr - 1] = m_ccAlfFilterParam.ccAlfFilterCount[COMPONENT_Cr - 1];
+    for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+    {
+      aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx] =
+        m_ccAlfFilterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx];
+      memcpy(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx],
+             m_ccAlfFilterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], sizeof(short) * MAX_NUM_CC_ALF_CHROMA_COEFF);
+    }
+    aps->setAPSId(ccAlfCrApsId);
+    if (m_reuseApsId[COMPONENT_Cr - 1] < 0)
+    {
+      aps->getCcAlfAPSParam().newCcAlfFilter[COMPONENT_Cr - 1] = 1;
+      m_apsMap->setChangedFlag((ccAlfCrApsId << NUM_APS_TYPE_LEN) + ALF_APS, true);
+      aps->setTemporalId(cs.slice->getTLayer());
+    }
+    aps->setAPSType(ALF_APS);
+    cs.slice->setTileGroupCcAlfCrEnabledFlag(true);
+  }
+  else
+  {
+    cs.slice->setTileGroupCcAlfCrEnabledFlag(false);
+  }
+}
+#endif
+
 void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambdas
 #if ENABLE_QPA
                                        , const double lambdaChromaWeight
@@ -656,6 +913,9 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda
       if (alfAPS)
       {
         alfAPS->getAlfAPSParam().reset();
+#if JVET_Q0795_CCALF
+        alfAPS->getCcAlfAPSParam().reset();
+#endif
         alfAPS = nullptr;
       }
     }
@@ -663,6 +923,11 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda
   AlfParam alfParam;
   alfParam.reset();
   const TempCtx  ctxStart(m_CtxCache, AlfCtx(m_CABACEstimator->getCtx()));
+
+#if JVET_Q0795_CCALF
+  const TempCtx ctxStartCcAlf(m_CtxCache, SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx()));
+#endif
+
   // set available filter shapes
   alfParam.filterShapes = m_filterShapes;
 
@@ -796,6 +1061,55 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda
   );
 
   alfReconstructor(cs, recYuv);
+
+#if JVET_Q0795_CCALF
+  // Do not transmit CC ALF if it is unchanged
+  if (cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
+  {
+    for (int32_t lumaAlfApsId : cs.slice->getTileGroupApsIdLuma())
+    {
+      APS* aps = (lumaAlfApsId >= 0) ? m_apsMap->getPS((lumaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS) : nullptr;
+      if (aps && m_apsMap->getChangedFlag((lumaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS))
+      {
+        aps->getCcAlfAPSParam().newCcAlfFilter[0] = false;
+          aps->getCcAlfAPSParam().newCcAlfFilter[1] = false;
+      }
+    }
+  }
+  int chromaAlfApsId = ( cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) || cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) ) ? cs.slice->getTileGroupApsIdChroma() : -1;
+  APS* aps = (chromaAlfApsId >= 0) ? m_apsMap->getPS((chromaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS) : nullptr;
+  if (aps && m_apsMap->getChangedFlag((chromaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS))
+  {
+    aps->getCcAlfAPSParam().newCcAlfFilter[0] = false;
+    aps->getCcAlfAPSParam().newCcAlfFilter[1] = false;
+  }
+
+  if (!cs.slice->getSPS()->getCCALFEnabledFlag())
+  {
+    return;
+  }
+
+  m_tempBuf.get(COMPONENT_Cb).copyFrom(cs.getRecoBuf().get(COMPONENT_Cb));
+  m_tempBuf.get(COMPONENT_Cr).copyFrom(cs.getRecoBuf().get(COMPONENT_Cr));
+  recYuv = m_tempBuf.getBuf(cs.area);
+  recYuv.extendBorderPel(MAX_ALF_FILTER_LENGTH >> 1);
+  m_CABACEstimator->getCtx() = SubCtx(Ctx::CcAlfFilterControlFlag, ctxStartCcAlf);
+  deriveCcAlfFilter(cs, COMPONENT_Cb, orgYuv, recYuv, cs.getRecoBuf());
+  m_CABACEstimator->getCtx() = SubCtx(Ctx::CcAlfFilterControlFlag, ctxStartCcAlf);
+  deriveCcAlfFilter(cs, COMPONENT_Cr, orgYuv, recYuv, cs.getRecoBuf());
+
+  xSetupCcAlfAPS(cs);
+
+  for (int compIdx = 1; compIdx < getNumberValidComponents(cs.pcv->chrFormat); compIdx++)
+  {
+    ComponentID compID     = ComponentID(compIdx);
+    if (m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1])
+    {
+      applyCcAlfFilter(cs, compID, cs.getRecoBuf().get(compID), recYuv, m_ccAlfFilterControl[compIdx - 1],
+                       m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1], -1);
+    }
+  }
+#endif
 }
 
 double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, const int iShapeIdx, ChannelType channel,
@@ -1604,6 +1918,29 @@ void EncAdaptiveLoopFilter::roundFiltCoeff( int *filterCoeffQuant, double *filte
   }
 }
 
+#if JVET_Q0795_CCALF
+void EncAdaptiveLoopFilter::roundFiltCoeffCCALF( int *filterCoeffQuant, double *filterCoeff, const int numCoeff, const int factor )
+{
+  for( int i = 0; i < numCoeff; i++ )
+  {
+    int sign = filterCoeff[i] > 0 ? 1 : -1;
+    double best_err = 128.0*128.0;
+    int best_index = 0;
+    for(int k = 0; k < CCALF_CANDS_COEFF_NR; k++)
+    {
+      double err = (filterCoeff[i] * sign * factor - CCALF_SMALL_TAB[k]);
+      err = err*err;
+      if(err < best_err)
+      {
+        best_err = err;
+        best_index = k;
+      }
+    }
+    filterCoeffQuant[i] = CCALF_SMALL_TAB[best_index] * sign;
+  }
+}
+#endif
+
 void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], const int numClasses, short filterIndices[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES] )
 {
   static int tmpClip[MAX_NUM_ALF_LUMA_COEFF];
@@ -2538,6 +2875,11 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
     }// for (int numTemporalAps = 0; numTemporalAps < apsIds.size(); numTemporalAps++)
   }//for (int useNewFilter = 0; useNewFilter <= 1; useNewFilter++)
 
+#if JVET_Q0795_CCALF
+  cs.slice->setTileGroupCcAlfCbApsId(newApsId);
+  cs.slice->setTileGroupCcAlfCrApsId(newApsId);
+#endif
+
   if (costOff <= costMin)
   {
     cs.slice->resetTileGroupAlfEnabledFlag();
@@ -2735,6 +3077,14 @@ void  EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar
       copyCtuAlternativeChroma(m_ctuAlternativeTmp, m_ctuAlternative);
     }
   }
+
+#if JVET_Q0795_CCALF
+  if (newApsIdChroma >= 0)
+  {
+    cs.slice->setTileGroupCcAlfCbApsId(newApsIdChroma);
+    cs.slice->setTileGroupCcAlfCrApsId(newApsIdChroma);
+  }
+#endif
   if (costOff < costMin)
   {
     cs.slice->setTileGroupAlfEnabledFlag(COMPONENT_Cb, false);
@@ -2971,3 +3321,999 @@ int EncAdaptiveLoopFilter::getMaxNumAlternativesChroma( )
 {
   return std::min<int>( m_numCTUsInPic * 2, m_encCfg->getMaxNumAlfAlternativesChroma() );
 }
+
+#if JVET_Q0795_CCALF
+int EncAdaptiveLoopFilter::getCoeffRateCcAlf(short chromaCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], bool filterEnabled[MAX_NUM_CC_ALF_FILTERS], uint8_t filterCount, ComponentID compID)
+{
+  int bits = 0;
+
+  if ( filterCount > 0 )
+  {
+    bits += lengthUvlc(filterCount - 1);
+    int signaledFilterCount = 0;
+    for ( int filterIdx=0; filterIdx<MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+    {
+      if (filterEnabled[filterIdx])
+      {
+        AlfFilterShape alfShape(size_CC_ALF);
+        // Filter coefficients
+        for (int i = 0; i < alfShape.numCoeff - 1; i++)
+        {
+          bits += CCALF_BITS_PER_COEFF_LEVEL + (chromaCoeff[filterIdx][i] == 0 ? 0 : 1);
+        }
+
+        signaledFilterCount++;
+      }
+    }
+    CHECK(signaledFilterCount != filterCount, "Number of filter signaled not same as indicated");
+  }
+
+  return bits;
+}
+
+void EncAdaptiveLoopFilter::deriveCcAlfFilterCoeff( ComponentID compID, const PelUnitBuf& recYuv, const PelUnitBuf& recYuvExt, short filterCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], const uint8_t filterIdx )
+{
+  int forward_tab[CCALF_CANDS_COEFF_NR * 2 - 1] = {0};
+  for (int i = 0; i < CCALF_CANDS_COEFF_NR; i++)
+  {
+    forward_tab[CCALF_CANDS_COEFF_NR - 1 + i] = CCALF_SMALL_TAB[i];
+    forward_tab[CCALF_CANDS_COEFF_NR - 1 - i] = (-1) * CCALF_SMALL_TAB[i];
+  }
+  using TE = double[MAX_NUM_ALF_LUMA_COEFF][MAX_NUM_ALF_LUMA_COEFF];
+  using Ty = double[MAX_NUM_ALF_LUMA_COEFF];
+
+  static double filterCoeffDbl[MAX_NUM_CC_ALF_CHROMA_COEFF];
+  static int    filterCoeffInt[MAX_NUM_CC_ALF_CHROMA_COEFF];
+
+  TE        kE;
+  Ty        ky;
+  const int size = m_filterShapesCcAlf[compID - 1][0].numCoeff - 1;
+
+  for (int k = 0; k < size; k++)
+  {
+    ky[k] = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].y[0][k];
+    for (int l = 0; l < size; l++)
+    {
+      kE[k][l] = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].E[0][0][k][l];
+    }
+  }
+
+  m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].gnsSolveByChol(kE, ky, filterCoeffDbl, size);
+  roundFiltCoeffCCALF(filterCoeffInt, filterCoeffDbl, size, (1 << m_scaleBits));
+
+  for (int k = 0; k < size; k++)
+  {
+    CHECK( filterCoeffInt[k] < -(1 << CCALF_DYNAMIC_RANGE), "this is not possible: filterCoeffInt[k] <  -(1 << CCALF_DYNAMIC_RANGE)");
+    CHECK( filterCoeffInt[k] > (1 << CCALF_DYNAMIC_RANGE), "this is not possible: filterCoeffInt[k] >  (1 << CCALF_DYNAMIC_RANGE)");
+  }
+
+  // Refine quanitzation
+  int modified       = 1;
+  double errRef      = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].calcErrorForCcAlfCoeffs(filterCoeffInt, size, (m_scaleBits+1));
+  while (modified)
+  {
+    modified = 0;
+    for (int delta : { 1, -1 })
+    {
+      double errMin = MAX_DOUBLE;
+      int    idxMin = -1;
+      int minIndex = -1;
+
+      for (int k = 0; k < size; k++)
+      {
+        int org_idx = -1;
+        for (int i = 0; i < CCALF_CANDS_COEFF_NR * 2 - 1; i++)
+        {
+          if (forward_tab[i] == filterCoeffInt[k])
+          {
+            org_idx = i;
+            break;
+          }
+        }
+        CHECK( org_idx < 0, "this is wrong, does not find coeff from forward_tab");
+        if ( (org_idx - delta < 0) || (org_idx - delta >= CCALF_CANDS_COEFF_NR * 2 - 1) )
+          continue;
+
+        filterCoeffInt[k] = forward_tab[org_idx - delta];
+        double error = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].calcErrorForCcAlfCoeffs(filterCoeffInt, size, (m_scaleBits+1));
+        if( error < errMin )
+        {
+          errMin = error;
+          idxMin = k;
+          minIndex = org_idx;
+        }
+        filterCoeffInt[k] = forward_tab[org_idx];
+      }
+      if (errMin < errRef)
+      {
+        minIndex -= delta;
+        CHECK( minIndex < 0, "this is wrong, index - delta < 0");
+        CHECK( minIndex >= CCALF_CANDS_COEFF_NR * 2 - 1, "this is wrong, index - delta >= CCALF_CANDS_COEFF_NR * 2 - 1");
+        filterCoeffInt[idxMin] = forward_tab[minIndex];
+        modified++;
+        errRef = errMin;
+      }
+    }
+  }
+
+
+  for (int k = 0; k < (size + 1); k++)
+  {
+    CHECK((filterCoeffInt[k] < -(1 << CCALF_DYNAMIC_RANGE)) || (filterCoeffInt[k] > (1 << CCALF_DYNAMIC_RANGE)), "Exceeded valid range for CC ALF coefficient");
+    filterCoeff[filterIdx][k] = filterCoeffInt[k];
+  }
+}
+
+
+void EncAdaptiveLoopFilter::computeLog2BlockSizeDistortion(const Pel *org, int orgStride, const Pel *dec, int decStride,
+                                                           int height, int width, uint64_t *distortionBuf,
+                                                           int distortionBufStride, int log2BlockWidth,
+                                                           int log2BlockHeight, uint64_t& totalDistortion)
+{
+  totalDistortion = 0;
+  for (int y = 0; y < height; y += (1 << log2BlockHeight))
+  {
+    for (int x = 0; x < width; x += (1 << log2BlockWidth))
+    {
+      int      err;
+      uint64_t ssd = 0;
+
+      for (int yOff = 0; yOff < (1 << log2BlockHeight); yOff++)
+      {
+        for (int xOff = 0; xOff < (1 << log2BlockWidth); xOff++)
+        {
+          if ((y + yOff) >= height || (x + xOff) >= width)
+          {
+            continue;
+          }
+
+          err = org[yOff * orgStride + x + xOff] - dec[yOff * decStride + x + xOff];
+          ssd += err * err;
+        }
+      }
+
+      distortionBuf[(y >> log2BlockHeight) * distortionBufStride + (x >> log2BlockWidth)] = ssd;
+      totalDistortion += ssd;
+    }
+    org += (orgStride << log2BlockHeight);
+    dec += (decStride << log2BlockHeight);
+  }
+}
+
+void EncAdaptiveLoopFilter::determineControlIdcValues(CodingStructure &cs, const ComponentID compID, const PelBuf *buf,
+                                                      const int ctuWidthC, const int ctuHeightC, const int picWidthC,
+                                                      const int picHeightC, uint64_t **unfilteredDistortion,
+                                                      uint64_t *trainingDistortion[MAX_NUM_CC_ALF_FILTERS],
+                                                      uint64_t *lumaSwingGreaterThanThresholdCount,
+                                                      uint64_t *chromaSampleCountNearMidPoint,
+                                                      bool reuseTemporalFilterCoeff, uint8_t *trainingCovControl,
+                                                      uint8_t *filterControl, uint64_t &curTotalDistortion,
+                                                      double &curTotalRate, bool filterEnabled[MAX_NUM_CC_ALF_FILTERS],
+                                                      uint8_t  mapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS + 1],
+                                                      uint8_t &ccAlfFilterCount)
+{
+  bool curFilterEnabled[MAX_NUM_CC_ALF_FILTERS];
+  std::fill_n(curFilterEnabled, MAX_NUM_CC_ALF_FILTERS, false);
+
+#if MAX_NUM_CC_ALF_FILTERS>1
+  FilterIdxCount filterIdxCount[MAX_NUM_CC_ALF_FILTERS];
+  for (int i = 0; i < MAX_NUM_CC_ALF_FILTERS; i++)
+  {
+    filterIdxCount[i].count     = 0;
+    filterIdxCount[i].filterIdx = i;
+  }
+
+  double prevRate = curTotalRate;
+#endif
+
+  TempCtx ctxInitial(m_CtxCache);
+  TempCtx ctxBest(m_CtxCache);
+  TempCtx ctxStart(m_CtxCache);
+  ctxInitial = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx());
+  ctxBest    = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx());
+
+  int ctuIdx = 0;
+  for (int yCtu = 0; yCtu < buf->height; yCtu += ctuHeightC)
+  {
+    for (int xCtu = 0; xCtu < buf->width; xCtu += ctuWidthC)
+    {
+      uint64_t ssd;
+      double   rate;
+      double   cost;
+
+      uint64_t bestSSD       = MAX_UINT64;
+      double   bestRate      = MAX_DOUBLE;
+      double   bestCost      = MAX_DOUBLE;
+      uint8_t  bestFilterIdc = 0;
+      uint8_t  bestFilterIdx = 0;
+      const uint32_t thresholdS = std::min<int>(buf->height - yCtu, ctuHeightC) << getComponentScaleY(COMPONENT_Cb, m_chromaFormat);
+      const uint32_t numberOfChromaSamples = std::min<int>(buf->height - yCtu, ctuHeightC) * std::min<int>(buf->width - xCtu, ctuWidthC);
+      const uint32_t thresholdC = (numberOfChromaSamples >> 2);
+
+      m_CABACEstimator->getCtx() = ctxBest;
+      ctxStart                   = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx());
+
+      for (int filterIdx = 0; filterIdx <= MAX_NUM_CC_ALF_FILTERS; filterIdx++)
+      {
+        uint8_t filterIdc = mapFilterIdxToFilterIdc[filterIdx];
+        if (filterIdx < MAX_NUM_CC_ALF_FILTERS && !filterEnabled[filterIdx])
+        {
+          continue;
+        }
+
+        if (filterIdx == MAX_NUM_CC_ALF_FILTERS)
+        {
+          ssd = unfilteredDistortion[0][ctuIdx];   // restore saved distortion computation
+        }
+        else
+        {
+          ssd = trainingDistortion[filterIdx][ctuIdx];
+        }
+        m_CABACEstimator->getCtx() = ctxStart;
+        m_CABACEstimator->resetBits();
+        const Position lumaPos = Position({ xCtu << getComponentScaleX(compID, cs.pcv->chrFormat),
+          yCtu << getComponentScaleY(compID, cs.pcv->chrFormat) });
+        m_CABACEstimator->codeCcAlfFilterControlIdc(filterIdc, cs, compID, ctuIdx, filterControl, lumaPos,
+                                                    ccAlfFilterCount);
+        rate = FRAC_BITS_SCALE * m_CABACEstimator->getEstFracBits();
+        cost = rate * m_lambda[compID] + ssd;
+
+        bool limitationExceeded = false;
+        if (m_limitCcAlf && filterIdx < MAX_NUM_CC_ALF_FILTERS)
+        {
+          limitationExceeded = limitationExceeded || (lumaSwingGreaterThanThresholdCount[ctuIdx] >= thresholdS);
+          limitationExceeded = limitationExceeded || (chromaSampleCountNearMidPoint[ctuIdx] >= thresholdC);
+        }
+        if (cost < bestCost && !limitationExceeded)
+        {
+          bestCost      = cost;
+          bestRate      = rate;
+          bestSSD       = ssd;
+          bestFilterIdc = filterIdc;
+          bestFilterIdx = filterIdx;
+
+          ctxBest = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx());
+
+          trainingCovControl[ctuIdx] = (filterIdx == MAX_NUM_CC_ALF_FILTERS) ? 0 : (filterIdx + 1);
+          filterControl[ctuIdx]      = (filterIdx == MAX_NUM_CC_ALF_FILTERS) ? 0 : (filterIdx + 1);
+        }
+      }
+      if (bestFilterIdc != 0)
+      {
+        curFilterEnabled[bestFilterIdx] = true;
+#if MAX_NUM_CC_ALF_FILTERS>1
+        filterIdxCount[bestFilterIdx].count++;
+#endif
+      }
+      curTotalRate += bestRate;
+      curTotalDistortion += bestSSD;
+      ctuIdx++;
+    }
+  }
+
+#if MAX_NUM_CC_ALF_FILTERS>1
+  if (!reuseTemporalFilterCoeff)
+  {
+    std::copy_n(curFilterEnabled, MAX_NUM_CC_ALF_FILTERS, filterEnabled);
+
+    std::sort(filterIdxCount, filterIdxCount + MAX_NUM_CC_ALF_FILTERS, compareCounts);
+
+    int filterIdc = 1;
+    ccAlfFilterCount = 0;
+    for ( FilterIdxCount &s : filterIdxCount )
+    {
+      const int filterIdx = s.filterIdx;
+      if (filterEnabled[filterIdx])
+      {
+        mapFilterIdxToFilterIdc[filterIdx] = filterIdc;
+        filterIdc++;
+        ccAlfFilterCount++;
+      }
+    }
+
+    curTotalRate = prevRate;
+    m_CABACEstimator->getCtx() = ctxInitial;
+    m_CABACEstimator->resetBits();
+    int ctuIdx = 0;
+    for (int y = 0; y < buf->height; y += ctuHeightC)
+    {
+      for (int x = 0; x < buf->width; x += ctuWidthC)
+      {
+        const int filterIdxPlus1 = filterControl[ctuIdx];
+
+        const Position lumaPos = Position(
+                                          { x << getComponentScaleX(compID, cs.pcv->chrFormat), y << getComponentScaleY(compID, cs.pcv->chrFormat) });
+
+        m_CABACEstimator->codeCcAlfFilterControlIdc(filterIdxPlus1 == 0 ? 0
+                                                    : mapFilterIdxToFilterIdc[filterIdxPlus1 - 1],
+                                                    cs, compID, ctuIdx, filterControl, lumaPos, ccAlfFilterCount);
+
+        ctuIdx++;
+      }
+    }
+    curTotalRate += FRAC_BITS_SCALE*m_CABACEstimator->getEstFracBits();
+  }
+#endif
+
+  // restore for next iteration
+  m_CABACEstimator->getCtx() = ctxInitial;
+}
+
+std::vector<int> EncAdaptiveLoopFilter::getAvailableCcAlfApsIds(CodingStructure& cs, ComponentID compID)
+{
+  APS** apss = cs.slice->getAlfAPSs();
+  for (int i = 0; i < ALF_CTB_MAX_NUM_APS; i++)
+  {
+    apss[i] = m_apsMap->getPS((i << NUM_APS_TYPE_LEN) + ALF_APS);
+  }
+
+  std::vector<int> result;
+  int apsIdChecked = 0, curApsId = m_apsIdStart;
+  if (curApsId < ALF_CTB_MAX_NUM_APS)
+  {
+    while (apsIdChecked < ALF_CTB_MAX_NUM_APS && !cs.slice->isIntra() && result.size() < ALF_CTB_MAX_NUM_APS && !cs.slice->getPendingRasInit() && !cs.slice->isIDRorBLA())
+    {
+      APS* curAPS = cs.slice->getAlfAPSs()[curApsId];
+      if (curAPS && curAPS->getTemporalId() <= cs.slice->getTLayer() && curAPS->getCcAlfAPSParam().newCcAlfFilter[compID - 1])
+      {
+        result.push_back(curApsId);
+      }
+      apsIdChecked++;
+      curApsId = (curApsId + 1) % ALF_CTB_MAX_NUM_APS;
+    }
+  }
+  return result;
+}
+
+void EncAdaptiveLoopFilter::deriveCcAlfFilter( CodingStructure& cs, ComponentID compID, const PelUnitBuf& orgYuv, const PelUnitBuf& tempDecYuvBuf, const PelUnitBuf& dstYuv )
+{
+  if (!cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
+  {
+    m_ccAlfFilterParam.ccAlfFilterEnabled[compID - 1] = false;
+    return;
+  }
+
+  m_limitCcAlf = m_encCfg->getBaseQP() >= m_encCfg->getCCALFQpThreshold();
+  if (m_limitCcAlf && cs.slice->getSliceQp() <= m_encCfg->getBaseQP() + 1)
+  {
+    m_ccAlfFilterParam.ccAlfFilterEnabled[compID - 1] = false;
+    return;
+  }
+
+  uint8_t bestMapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS+1];
+  const int scaleX               = getComponentScaleX(compID, cs.pcv->chrFormat);
+  const int scaleY               = getComponentScaleY(compID, cs.pcv->chrFormat);
+  const int ctuWidthC            = cs.pcv->maxCUWidth >> scaleX;
+  const int ctuHeightC           = cs.pcv->maxCUHeight >> scaleY;
+  const int picWidthC            = cs.pcv->lumaWidth >> scaleX;
+  const int picHeightC           = cs.pcv->lumaHeight >> scaleY;
+  const int maxTrainingIterCount = 15;
+
+  if (m_limitCcAlf)
+  {
+    countLumaSwingGreaterThanThreshold(dstYuv.get(COMPONENT_Y).bufAt(0, 0), dstYuv.get(COMPONENT_Y).stride, dstYuv.get(COMPONENT_Y).height, dstYuv.get(COMPONENT_Y).width, cs.pcv->maxCUWidthLog2, cs.pcv->maxCUHeightLog2, m_lumaSwingGreaterThanThresholdCount, m_numCTUsInWidth);
+  }
+  if (m_limitCcAlf)
+  {
+    countChromaSampleValueNearMidPoint(dstYuv.get(compID).bufAt(0, 0), dstYuv.get(compID).stride, dstYuv.get(compID).height, dstYuv.get(compID).width, cs.pcv->maxCUWidthLog2 - scaleX, cs.pcv->maxCUHeightLog2 - scaleY, m_chromaSampleCountNearMidPoint, m_numCTUsInWidth);
+  }
+
+  for ( int filterIdx = 0; filterIdx <= MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+  {
+    if ( filterIdx < MAX_NUM_CC_ALF_FILTERS)
+    {
+      memset( m_bestFilterCoeffSet[filterIdx], 0, sizeof(m_bestFilterCoeffSet[filterIdx]) );
+      bestMapFilterIdxToFilterIdc[filterIdx] = filterIdx + 1;
+    }
+    else
+    {
+      bestMapFilterIdxToFilterIdc[filterIdx] = 0;
+    }
+  }
+  memset(m_bestFilterControl, 0, sizeof(uint8_t) * m_numCTUsInPic);
+  int ccalfReuseApsId      = -1;
+  m_reuseApsId[compID - 1] = -1;
+
+  const TempCtx ctxStartCcAlfFilterControlFlag  ( m_CtxCache, SubCtx( Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx() ) );
+
+  // compute cost of not filtering
+  const Pel *org                = orgYuv.get( compID ).bufAt(0,0);
+  const Pel *unfiltered         = dstYuv.get( compID ).bufAt(0,0);
+  const int orgStride           = orgYuv.get( compID ).stride;
+  const int unfilteredStride    = dstYuv.get( compID ).stride;
+  const Pel *filtered           = m_buf->bufAt(0,0);
+  const int filteredStride      = m_buf->stride;
+  uint64_t unfilteredDistortion = 0;
+  computeLog2BlockSizeDistortion(org, orgStride, unfiltered, unfilteredStride, m_buf->height, m_buf->width,
+                                 m_unfilteredDistortion[0], m_numCTUsInWidth, cs.pcv->maxCUWidthLog2 - scaleX,
+                                 cs.pcv->maxCUHeightLog2 - scaleY, unfilteredDistortion);
+  double bestUnfilteredTotalCost = 1 * m_lambda[compID] + unfilteredDistortion;   // 1 bit is for gating flag
+
+  static bool  ccAlfFilterIdxEnabled[MAX_NUM_CC_ALF_FILTERS];
+  static short ccAlfFilterCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF];
+  static uint8_t ccAlfFilterCount     = MAX_NUM_CC_ALF_FILTERS;
+  double bestFilteredTotalCost        = MAX_DOUBLE;
+  bool   bestreuseTemporalFilterCoeff = false;
+  std::vector<int> apsIds             = getAvailableCcAlfApsIds(cs, compID);
+
+  for (int testFilterIdx = 0; testFilterIdx < ( apsIds.size() + 1 ); testFilterIdx++ )
+  {
+    bool referencingExistingAps   = (testFilterIdx < apsIds.size()) ? true : false;
+    int maxNumberOfFiltersBeingTested = MAX_NUM_CC_ALF_FILTERS - (testFilterIdx - static_cast<int>(apsIds.size()));
+
+    if (maxNumberOfFiltersBeingTested < 0)
+    {
+      maxNumberOfFiltersBeingTested = 1;
+    }
+
+    {
+      // Instead of rewriting the control buffer for every training iteration just keep a mapping from filterIdx to filterIdc
+      uint8_t mapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS + 1];
+      for (int filterIdx = 0; filterIdx <= MAX_NUM_CC_ALF_FILTERS; filterIdx++)
+      {
+        if (filterIdx == MAX_NUM_CC_ALF_FILTERS)
+        {
+          mapFilterIdxToFilterIdc[filterIdx] = 0;
+        }
+        else
+        {
+          mapFilterIdxToFilterIdc[filterIdx] = filterIdx + 1;
+        }
+      }
+
+      // initialize filters
+      for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+      {
+        ccAlfFilterIdxEnabled[filterIdx] = false;
+        memset(ccAlfFilterCoeff[filterIdx], 0, sizeof(ccAlfFilterCoeff[filterIdx]));
+      }
+      if ( referencingExistingAps )
+      {
+        maxNumberOfFiltersBeingTested = m_apsMap->getPS((apsIds[testFilterIdx] << NUM_APS_TYPE_LEN) + ALF_APS)->getCcAlfAPSParam().ccAlfFilterCount[compID - 1];
+        ccAlfFilterCount = maxNumberOfFiltersBeingTested;
+        for (int filterIdx = 0; filterIdx < maxNumberOfFiltersBeingTested; filterIdx++)
+        {
+          ccAlfFilterIdxEnabled[filterIdx] = true;
+          memcpy(ccAlfFilterCoeff[filterIdx], m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx],
+                 sizeof(ccAlfFilterCoeff[filterIdx]));
+        }
+        memcpy( ccAlfFilterCoeff, m_apsMap->getPS((apsIds[testFilterIdx] << NUM_APS_TYPE_LEN) + ALF_APS)->getCcAlfAPSParam().ccAlfCoeff[compID - 1], sizeof(ccAlfFilterCoeff) );
+      }
+      else
+      {
+        for (int i = 0; i < maxNumberOfFiltersBeingTested; i++)
+        {
+          ccAlfFilterIdxEnabled[i] = true;
+        }
+        ccAlfFilterCount = maxNumberOfFiltersBeingTested;
+      }
+
+      // initialize
+      int controlIdx = 0;
+      const int columnSize = ( m_buf->width / maxNumberOfFiltersBeingTested);
+      for (int y = 0; y < m_buf->height; y += ctuHeightC)
+      {
+        for (int x = 0; x < m_buf->width; x += ctuWidthC)
+        {
+          m_trainingCovControl[controlIdx] = ( x / columnSize ) + 1;
+          controlIdx++;
+        }
+      }
+
+      // compute cost of filtering
+      int    trainingIterCount = 0;
+      bool   keepTraining      = true;
+      bool   improvement       = false;
+      double prevTotalCost     = MAX_DOUBLE;
+      while (keepTraining)
+      {
+        improvement = false;
+        for (int filterIdx = 0; filterIdx < maxNumberOfFiltersBeingTested; filterIdx++)
+        {
+          if (ccAlfFilterIdxEnabled[filterIdx])
+          {
+            if (!referencingExistingAps)
+            {
+              deriveStatsForCcAlfFiltering(orgYuv, tempDecYuvBuf, compID, m_numCTUsInWidth, (filterIdx + 1), cs);
+              deriveCcAlfFilterCoeff(compID, dstYuv, tempDecYuvBuf, ccAlfFilterCoeff, filterIdx);
+            }
+            m_buf->copyFrom(dstYuv.get(compID));
+            applyCcAlfFilter(cs, compID, *m_buf, tempDecYuvBuf, nullptr, ccAlfFilterCoeff, filterIdx);
+
+            uint64_t distortion = 0;
+            computeLog2BlockSizeDistortion(
+                                           org, orgStride, filtered, filteredStride, m_buf->height, m_buf->width, m_trainingDistortion[filterIdx],
+                                           m_numCTUsInWidth, cs.pcv->maxCUWidthLog2 - scaleX, cs.pcv->maxCUHeightLog2 - scaleY, distortion);
+          }
+        }
+
+        m_CABACEstimator->getCtx() = ctxStartCcAlfFilterControlFlag;
+
+        uint64_t curTotalDistortion = 0;
+        double curTotalRate = 0;
+        determineControlIdcValues(cs, compID, m_buf, ctuWidthC, ctuHeightC, picWidthC, picHeightC,
+                                  m_unfilteredDistortion, m_trainingDistortion,
+                                  m_lumaSwingGreaterThanThresholdCount,
+                                  m_chromaSampleCountNearMidPoint,
+                                  (referencingExistingAps == true),
+                                  m_trainingCovControl, m_filterControl, curTotalDistortion, curTotalRate,
+                                  ccAlfFilterIdxEnabled, mapFilterIdxToFilterIdc, ccAlfFilterCount);
+
+        // compute coefficient coding bit cost
+        if (ccAlfFilterCount > 0)
+        {
+          if (referencingExistingAps)
+          {
+            curTotalRate += 1 + 3 + lengthUvlc(ccAlfFilterCount - 1); // +1 for enable flag, +3 APS ID in slice header
+          }
+          else
+          {
+            curTotalRate += getCoeffRateCcAlf(ccAlfFilterCoeff, ccAlfFilterIdxEnabled, ccAlfFilterCount, compID) + 1 + lengthUvlc(ccAlfFilterCount - 1)
+            + 7;   // +1 for the enable flag, +7 two 3-bit APS ID, one in slice header/one in APS, a 1-bit
+            // new filter flags (ignore shared cost such as other new-filter flags/NALU header/RBSP
+            // terminating bit/byte alignment bits)
+          }
+
+          double curTotalCost = curTotalRate * m_lambda[compID] + curTotalDistortion;
+
+          if (curTotalCost < prevTotalCost)
+          {
+            prevTotalCost = curTotalCost;
+            improvement = true;
+          }
+
+          if (curTotalCost < bestFilteredTotalCost)
+          {
+            bestFilteredTotalCost = curTotalCost;
+            memcpy(m_bestFilterIdxEnabled, ccAlfFilterIdxEnabled, sizeof(ccAlfFilterIdxEnabled));
+            memcpy(m_bestFilterCoeffSet, ccAlfFilterCoeff, sizeof(ccAlfFilterCoeff));
+            memcpy(m_bestFilterControl, m_filterControl, sizeof(uint8_t) * m_numCTUsInPic);
+            m_bestFilterCount = ccAlfFilterCount;
+            ccalfReuseApsId = referencingExistingAps ? apsIds[testFilterIdx] : -1;
+            memcpy(bestMapFilterIdxToFilterIdc, mapFilterIdxToFilterIdc, sizeof(mapFilterIdxToFilterIdc));
+          }
+        }
+
+        trainingIterCount++;
+        if (!improvement || trainingIterCount > maxTrainingIterCount || referencingExistingAps)
+        {
+          keepTraining = false;
+        }
+      }
+    }
+  }
+
+  if (bestUnfilteredTotalCost < bestFilteredTotalCost)
+  {
+    memset(m_bestFilterControl, 0, sizeof(uint8_t) * m_numCTUsInPic);
+  }
+
+  // save best coeff and control
+  bool atleastOneBlockUndergoesFitlering = false;
+  for (int controlIdx = 0; m_bestFilterCount > 0 && controlIdx < m_numCTUsInPic; controlIdx++)
+  {
+    if (m_bestFilterControl[controlIdx])
+    {
+      atleastOneBlockUndergoesFitlering = true;
+      break;
+    }
+  }
+  m_ccAlfFilterParam.numberValidComponents          = getNumberValidComponents(m_chromaFormat);
+  m_ccAlfFilterParam.ccAlfFilterEnabled[compID - 1] = atleastOneBlockUndergoesFitlering;
+  if (atleastOneBlockUndergoesFitlering)
+  {
+    // update the filter control indicators
+    if (bestreuseTemporalFilterCoeff!=1)
+    {
+      short storedBestFilterCoeffSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF];
+      for (int filterIdx=0; filterIdx<MAX_NUM_CC_ALF_FILTERS; filterIdx++)
+      {
+        memcpy(storedBestFilterCoeffSet[filterIdx], m_bestFilterCoeffSet[filterIdx], sizeof(m_bestFilterCoeffSet[filterIdx]));
+      }
+      memcpy(m_filterControl, m_bestFilterControl, sizeof(uint8_t) * m_numCTUsInPic);
+
+      int filterCount = 0;
+      for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+      {
+        uint8_t curFilterIdc = bestMapFilterIdxToFilterIdc[filterIdx];
+        if (m_bestFilterIdxEnabled[filterIdx])
+        {
+          for (int controlIdx = 0; controlIdx < m_numCTUsInPic; controlIdx++)
+          {
+            if (m_filterControl[controlIdx] == (filterIdx+1) )
+            {
+              m_bestFilterControl[controlIdx] = curFilterIdc;
+            }
+          }
+          memcpy( m_bestFilterCoeffSet[curFilterIdc-1], storedBestFilterCoeffSet[filterIdx], sizeof(storedBestFilterCoeffSet[filterIdx]) );
+          filterCount++;
+        }
+        m_bestFilterIdxEnabled[filterIdx] = ( filterIdx < m_bestFilterCount ) ? true : false;
+      }
+      CHECK( filterCount != m_bestFilterCount, "Number of filters enabled did not match the filter count");
+    }
+
+    m_ccAlfFilterParam.ccAlfFilterCount[compID - 1] = m_bestFilterCount;
+    // cleanup before copying
+    memset(m_ccAlfFilterControl[compID - 1], 0, sizeof(uint8_t) * m_numCTUsInPic);
+    for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ )
+    {
+      memset(m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx], 0,
+             sizeof(m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx]));
+    }
+    memset(m_ccAlfFilterParam.ccAlfFilterIdxEnabled[compID - 1], false,
+           sizeof(m_ccAlfFilterParam.ccAlfFilterIdxEnabled[compID - 1]));
+    for ( int filterIdx = 0; filterIdx < m_bestFilterCount; filterIdx++ )
+    {
+      m_ccAlfFilterParam.ccAlfFilterIdxEnabled[compID - 1][filterIdx] = m_bestFilterIdxEnabled[filterIdx];
+      memcpy(m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx], m_bestFilterCoeffSet[filterIdx],
+             sizeof(m_bestFilterCoeffSet[filterIdx]));
+    }
+    memcpy(m_ccAlfFilterControl[compID - 1], m_bestFilterControl, sizeof(uint8_t) * m_numCTUsInPic);
+    if ( ccalfReuseApsId >= 0 )
+    {
+      m_reuseApsId[compID - 1] = ccalfReuseApsId;
+      if (compID == COMPONENT_Cb)
+      {
+        cs.slice->setTileGroupCcAlfCbApsId(ccalfReuseApsId);
+      }
+      else
+      {
+        cs.slice->setTileGroupCcAlfCrApsId(ccalfReuseApsId);
+      }
+    }
+  }
+}
+
+void EncAdaptiveLoopFilter::deriveStatsForCcAlfFiltering(const PelUnitBuf &orgYuv, const PelUnitBuf &recYuv,
+                                                         const int compIdx, const int maskStride,
+                                                         const uint8_t filterIdc, CodingStructure &cs)
+{
+  const int filterIdx = filterIdc - 1;
+
+  // init CTU stats buffers
+  for( int shape = 0; shape != m_filterShapesCcAlf[compIdx-1].size(); shape++ )
+  {
+    for (int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ctuIdx++)
+    {
+      m_alfCovarianceCcAlf[compIdx - 1][shape][filterIdx][ctuIdx].reset();
+    }
+  }
+
+  // init Frame stats buffers
+  for (int shape = 0; shape != m_filterShapesCcAlf[compIdx - 1].size(); shape++)
+  {
+    m_alfCovarianceFrameCcAlf[compIdx - 1][shape][filterIdx].reset();
+  }
+
+  int                  ctuRsAddr = 0;
+  const PreCalcValues &pcv       = *cs.pcv;
+  bool                 clipTop = false, clipBottom = false, clipLeft = false, clipRight = false;
+  int                  numHorVirBndry = 0, numVerVirBndry = 0;
+  int                  horVirBndryPos[] = { 0, 0, 0 };
+  int                  verVirBndryPos[] = { 0, 0, 0 };
+
+  for (int yPos = 0; yPos < m_picHeight; yPos += m_maxCUHeight)
+  {
+    for (int xPos = 0; xPos < m_picWidth; xPos += m_maxCUWidth)
+    {
+      if (m_trainingCovControl[ctuRsAddr] == filterIdc)
+      {
+        const int width             = (xPos + m_maxCUWidth > m_picWidth) ? (m_picWidth - xPos) : m_maxCUWidth;
+        const int height            = (yPos + m_maxCUHeight > m_picHeight) ? (m_picHeight - yPos) : m_maxCUHeight;
+        int       rasterSliceAlfPad = 0;
+        if (isCrossedByVirtualBoundaries(cs, xPos, yPos, width, height, clipTop, clipBottom, clipLeft, clipRight,
+                                         numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos,
+                                         rasterSliceAlfPad))
+        {
+          int yStart = yPos;
+          for (int i = 0; i <= numHorVirBndry; i++)
+          {
+            const int  yEnd   = i == numHorVirBndry ? yPos + height : horVirBndryPos[i];
+            const int  h      = yEnd - yStart;
+            const bool clipT  = (i == 0 && clipTop) || (i > 0) || (yStart == 0);
+            const bool clipB  = (i == numHorVirBndry && clipBottom) || (i < numHorVirBndry) || (yEnd == pcv.lumaHeight);
+            int        xStart = xPos;
+            for (int j = 0; j <= numVerVirBndry; j++)
+            {
+              const int  xEnd   = j == numVerVirBndry ? xPos + width : verVirBndryPos[j];
+              const int  w      = xEnd - xStart;
+              const bool clipL  = (j == 0 && clipLeft) || (j > 0) || (xStart == 0);
+              const bool clipR  = (j == numVerVirBndry && clipRight) || (j < numVerVirBndry) || (xEnd == pcv.lumaWidth);
+              const int  wBuf   = w + (clipL ? 0 : MAX_ALF_PADDING_SIZE) + (clipR ? 0 : MAX_ALF_PADDING_SIZE);
+              const int  hBuf   = h + (clipT ? 0 : MAX_ALF_PADDING_SIZE) + (clipB ? 0 : MAX_ALF_PADDING_SIZE);
+              PelUnitBuf recBuf = m_tempBuf2.subBuf(UnitArea(cs.area.chromaFormat, Area(0, 0, wBuf, hBuf)));
+              recBuf.copyFrom(recYuv.subBuf(
+                UnitArea(cs.area.chromaFormat, Area(xStart - (clipL ? 0 : MAX_ALF_PADDING_SIZE),
+                                                    yStart - (clipT ? 0 : MAX_ALF_PADDING_SIZE), wBuf, hBuf))));
+              // pad top-left unavailable samples for raster slice
+              if (xStart == xPos && yStart == yPos && (rasterSliceAlfPad & 1))
+              {
+                recBuf.padBorderPel(MAX_ALF_PADDING_SIZE, 1);
+              }
+
+              // pad bottom-right unavailable samples for raster slice
+              if (xEnd == xPos + width && yEnd == yPos + height && (rasterSliceAlfPad & 2))
+              {
+                recBuf.padBorderPel(MAX_ALF_PADDING_SIZE, 2);
+              }
+              recBuf.extendBorderPel(MAX_ALF_PADDING_SIZE);
+              recBuf = recBuf.subBuf(UnitArea(
+                cs.area.chromaFormat, Area(clipL ? 0 : MAX_ALF_PADDING_SIZE, clipT ? 0 : MAX_ALF_PADDING_SIZE, w, h)));
+
+              const UnitArea area(m_chromaFormat, Area(0, 0, w, h));
+              const UnitArea areaDst(m_chromaFormat, Area(xStart, yStart, w, h));
+
+              const ComponentID compID = ComponentID(compIdx);
+
+              for (int shape = 0; shape != m_filterShapesCcAlf[compIdx - 1].size(); shape++)
+              {
+                getBlkStatsCcAlf(m_alfCovarianceCcAlf[compIdx - 1][0][filterIdx][ctuRsAddr],
+                                 m_filterShapesCcAlf[compIdx - 1][shape], orgYuv, recBuf, areaDst, area, compID, yPos);
+                m_alfCovarianceFrameCcAlf[compIdx - 1][shape][filterIdx] +=
+                  m_alfCovarianceCcAlf[compIdx - 1][shape][filterIdx][ctuRsAddr];
+              }
+
+              xStart = xEnd;
+            }
+
+            yStart = yEnd;
+          }
+        }
+        else
+        {
+          const UnitArea area(m_chromaFormat, Area(xPos, yPos, width, height));
+
+          const ComponentID compID = ComponentID(compIdx);
+
+          for (int shape = 0; shape != m_filterShapesCcAlf[compIdx - 1].size(); shape++)
+          {
+            getBlkStatsCcAlf(m_alfCovarianceCcAlf[compIdx - 1][0][filterIdx][ctuRsAddr],
+                             m_filterShapesCcAlf[compIdx - 1][shape], orgYuv, recYuv, area, area, compID, yPos);
+            m_alfCovarianceFrameCcAlf[compIdx - 1][shape][filterIdx] +=
+              m_alfCovarianceCcAlf[compIdx - 1][shape][filterIdx][ctuRsAddr];
+          }
+        }
+      }
+      ctuRsAddr++;
+    }
+  }
+}
+
+void EncAdaptiveLoopFilter::getBlkStatsCcAlf(AlfCovariance &alfCovariance, const AlfFilterShape &shape,
+                                             const PelUnitBuf &orgYuv, const PelUnitBuf &recYuv,
+                                             const UnitArea &areaDst, const UnitArea &area, const ComponentID compID,
+                                             const int yPos)
+{
+  const int numberOfComponents = getNumberValidComponents( m_chromaFormat );
+  const CompArea &compArea           = areaDst.block(compID);
+  int  recStride[MAX_NUM_COMPONENT];
+  const Pel* rec[MAX_NUM_COMPONENT];
+  for ( int cIdx = 0; cIdx < numberOfComponents; cIdx++ )
+  {
+    recStride[cIdx] = recYuv.get(ComponentID(cIdx)).stride;
+    rec[cIdx] = recYuv.get(ComponentID(cIdx)).bufAt(isLuma(ComponentID(cIdx)) ? area.lumaPos() : area.chromaPos());
+  }
+
+  int        orgStride = orgYuv.get(compID).stride;
+  const Pel *org       = orgYuv.get(compID).bufAt(compArea);
+  const int  numBins   = 1;
+
+  int vbCTUHeight = m_alfVBLumaCTUHeight;
+  int vbPos       = m_alfVBLumaPos;
+  if ((yPos + m_maxCUHeight) >= m_picHeight)
+  {
+    vbPos = m_picHeight;
+  }
+
+  int ELocal[MAX_NUM_CC_ALF_CHROMA_COEFF][1];
+
+  for (int i = 0; i < compArea.height; i++)
+  {
+    int vbDistance = ((i << getComponentScaleX(compID, m_chromaFormat)) % vbCTUHeight) - vbPos;
+    for (int j = 0; j < compArea.width; j++)
+    {
+      std::memset(ELocal, 0, sizeof(ELocal));
+
+      double weight = 1.0;
+      if (m_alfWSSD)
+      {
+        weight = m_lumaLevelToWeightPLUT[org[j]];
+      }
+
+      int yLocal = org[j] - rec[compID][j];
+
+      calcCovarianceCcAlf( ELocal, rec[COMPONENT_Y] + ( j << getComponentScaleX(compID, m_chromaFormat)), recStride[COMPONENT_Y], shape, vbDistance );
+
+      for( int k = 0; k < (shape.numCoeff - 1); k++ )
+      {
+        for( int l = k; l < (shape.numCoeff - 1); l++ )
+        {
+          for( int b0 = 0; b0 < numBins; b0++ )
+          {
+            for (int b1 = 0; b1 < numBins; b1++)
+            {
+              if (m_alfWSSD)
+              {
+                alfCovariance.E[b0][b1][k][l] += weight * (double) (ELocal[k][b0] * ELocal[l][b1]);
+              }
+              else
+              {
+                alfCovariance.E[b0][b1][k][l] += ELocal[k][b0] * ELocal[l][b1];
+              }
+            }
+          }
+        }
+        for (int b = 0; b < numBins; b++)
+        {
+          if (m_alfWSSD)
+          {
+            alfCovariance.y[b][k] += weight * (double) (ELocal[k][b] * yLocal);
+          }
+          else
+          {
+            alfCovariance.y[b][k] += ELocal[k][b] * yLocal;
+          }
+        }
+      }
+      if (m_alfWSSD)
+      {
+        alfCovariance.pixAcc += weight * (double) (yLocal * yLocal);
+      }
+      else
+      {
+        alfCovariance.pixAcc += yLocal * yLocal;
+      }
+    }
+    org += orgStride;
+    for (int srcCIdx = 0; srcCIdx < numberOfComponents; srcCIdx++)
+    {
+      ComponentID srcCompID = ComponentID(srcCIdx);
+      if (toChannelType(srcCompID) == toChannelType(compID))
+      {
+        rec[srcCIdx] += recStride[srcCIdx];
+      }
+      else
+      {
+        if (isLuma(compID))
+        {
+          rec[srcCIdx] += (recStride[srcCIdx] >> getComponentScaleY(srcCompID, m_chromaFormat));
+        }
+        else
+        {
+          rec[srcCIdx] += (recStride[srcCIdx] << getComponentScaleY(compID, m_chromaFormat));
+        }
+      }
+    }
+  }
+
+  for (int k = 1; k < (MAX_NUM_CC_ALF_CHROMA_COEFF - 1); k++)
+  {
+    for (int l = 0; l < k; l++)
+    {
+      for (int b0 = 0; b0 < numBins; b0++)
+      {
+        for (int b1 = 0; b1 < numBins; b1++)
+        {
+          alfCovariance.E[b0][b1][k][l] = alfCovariance.E[b1][b0][l][k];
+        }
+      }
+    }
+  }
+}
+
+void EncAdaptiveLoopFilter::calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA_COEFF][1], const Pel *rec, const int stride, const AlfFilterShape& shape, int vbDistance)
+{
+  CHECK(shape.filterType != CC_ALF, "Bad CC ALF shape");
+
+  const Pel *recYM1 = rec - 1 * stride;
+  const Pel *recY0  = rec;
+  const Pel *recYP1 = rec + 1 * stride;
+  const Pel *recYP2 = rec + 2 * stride;
+
+  if (vbDistance == -2 || vbDistance == +1)
+  {
+    recYP2 = recYP1;
+  }
+  else if (vbDistance == -1 || vbDistance == 0)
+  {
+    recYM1 = recY0;
+    recYP2 = recYP1 = recY0;
+  }
+
+  for (int b = 0; b < 1; b++)
+  {
+    const Pel centerValue = recY0[+0];
+    ELocal[0][b] += recYM1[+0] - centerValue;
+    ELocal[1][b] += recY0[-1] - centerValue;
+    ELocal[2][b] += recY0[+1] - centerValue;
+    ELocal[3][b] += recYP1[-1] - centerValue;
+    ELocal[4][b] += recYP1[+0] - centerValue;
+    ELocal[5][b] += recYP1[+1] - centerValue;
+    ELocal[6][b] += recYP2[+0] - centerValue;
+  }
+}
+
+void EncAdaptiveLoopFilter::countLumaSwingGreaterThanThreshold(const Pel* luma, int lumaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* lumaSwingGreaterThanThresholdCount, int lumaCountStride)
+{
+  const int lumaBitDepth = m_inputBitDepth[CH_L];
+  const int threshold = (1 << ( m_inputBitDepth[CH_L] - 2 )) - 1;
+
+  // 3x4 Diamond
+  int xSupport[] = {  0, -1, 0, 1, -1, 0, 1, 0 };
+  int ySupport[] = { -1,  0, 0, 0,  1, 1, 1, 2 };
+
+  for (int y = 0; y < height; y += (1 << log2BlockHeight))
+  {
+    for (int x = 0; x < width; x += (1 << log2BlockWidth))
+    {
+      lumaSwingGreaterThanThresholdCount[(y >> log2BlockHeight) * lumaCountStride + (x >> log2BlockWidth)] = 0;
+
+      for (int yOff = 0; yOff < (1 << log2BlockHeight); yOff++)
+      {
+        for (int xOff = 0; xOff < (1 << log2BlockWidth); xOff++)
+        {
+          if ((y + yOff) >= (height - 2) || (x + xOff) >= (width - 1) || (y + yOff) < 1 || (x + xOff) < 1) // only consider samples that are fully supported by picture
+          {
+            continue;
+          }
+
+          int minVal = ((1 << lumaBitDepth) - 1);
+          int maxVal = 0;
+          for (int i = 0; i < 8; i++)
+          {
+            Pel p = luma[(yOff + ySupport[i]) * lumaStride + x + xOff + xSupport[i]];
+
+            if ( p < minVal )
+            {
+              minVal = p;
+            }
+            if ( p > maxVal )
+            {
+              maxVal = p;
+            }
+          }
+
+          if ((maxVal - minVal) > threshold)
+          {
+            lumaSwingGreaterThanThresholdCount[(y >> log2BlockHeight) * lumaCountStride + (x >> log2BlockWidth)]++;
+          }
+        }
+      }
+    }
+    luma += (lumaStride << log2BlockHeight);
+  }
+}
+
+void EncAdaptiveLoopFilter::countChromaSampleValueNearMidPoint(const Pel* chroma, int chromaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* chromaSampleCountNearMidPoint, int chromaSampleCountNearMidPointStride)
+{
+  const int midPoint  = (1 << m_inputBitDepth[CH_C]) >> 1;
+  const int threshold = 16;
+
+  for (int y = 0; y < height; y += (1 << log2BlockHeight))
+  {
+    for (int x = 0; x < width; x += (1 << log2BlockWidth))
+    {
+      chromaSampleCountNearMidPoint[(y >> log2BlockHeight)* chromaSampleCountNearMidPointStride + (x >> log2BlockWidth)] = 0;
+
+      for (int yOff = 0; yOff < (1 << log2BlockHeight); yOff++)
+      {
+        for (int xOff = 0; xOff < (1 << log2BlockWidth); xOff++)
+        {
+          if ((y + yOff) >= height || (x + xOff) >= width)
+          {
+            continue;
+          }
+
+          int distanceToMidPoint = abs(chroma[yOff * chromaStride + x + xOff] - midPoint);
+          if (distanceToMidPoint < threshold)
+          {
+            chromaSampleCountNearMidPoint[(y >> log2BlockHeight)* chromaSampleCountNearMidPointStride + (x >> log2BlockWidth)]++;
+          }
+        }
+      }
+    }
+    chroma += (chromaStride << log2BlockHeight);
+  }
+}
+#endif
diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h
index d2ceb026fe13f0c41ea4a5ec403b568965120afb..5c620b053c1cb0eaa42b79c06d7b5674dda76e5e 100644
--- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h
+++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h
@@ -202,15 +202,24 @@ struct AlfCovariance
   double calculateError( const int *clip, const double *coeff ) const { return calculateError(clip, coeff, numCoeff); }
   double calculateError( const int *clip, const double *coeff, const int numCoeff ) const;
   double calcErrorForCoeffs( const int *clip, const int *coeff, const int numCoeff, const int bitDepth ) const;
+#if JVET_Q0795_CCALF
+  double calcErrorForCcAlfCoeffs(const int* coeff, const int numCoeff, const int bitDepth) const;
+#endif
 
   void getClipMax(const AlfFilterShape& alfShape, int *clip_max) const;
   void reduceClipCost(const AlfFilterShape& alfShape, int *clip) const;
 
+#if JVET_Q0795_CCALF
+  int  gnsSolveByChol( TE LHS, double* rhs, double *x, int numEq ) const;
+#endif
+
 private:
   // Cholesky decomposition
 
   int  gnsSolveByChol( const int *clip, double *x, int numEq ) const;
+#if !JVET_Q0795_CCALF
   int  gnsSolveByChol( TE LHS, double* rhs, double *x, int numEq ) const;
+#endif
   void gnsBacksubstitution( TE R, double* z, int size, double* A ) const;
   void gnsTransposeBacksubstitution( TE U, double* rhs, double* x, int order ) const;
   int  gnsCholeskyDec( TE inpMatr, TE outMatr, int numEq ) const;
@@ -231,6 +240,10 @@ private:
   uint8_t*               m_ctuEnableFlagTmp[MAX_NUM_COMPONENT];
   uint8_t*               m_ctuEnableFlagTmp2[MAX_NUM_COMPONENT];
   uint8_t*               m_ctuAlternativeTmp[MAX_NUM_COMPONENT];
+#if JVET_Q0795_CCALF
+  AlfCovariance***       m_alfCovarianceCcAlf[2];           // [compIdx-1][shapeIdx][ctbAddr][filterIdx]
+  AlfCovariance**        m_alfCovarianceFrameCcAlf[2];      // [compIdx-1][shapeIdx][filterIdx]
+#endif
 
   //for RDO
   AlfParam               m_alfParamTemp;
@@ -255,6 +268,25 @@ private:
   int                    m_filterTmp[MAX_NUM_ALF_LUMA_COEFF];
   int                    m_clipTmp[MAX_NUM_ALF_LUMA_COEFF];
 
+#if JVET_Q0795_CCALF
+  int m_apsIdCcAlfStart[2];
+
+  short                  m_bestFilterCoeffSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF];
+  bool                   m_bestFilterIdxEnabled[MAX_NUM_CC_ALF_FILTERS];
+  uint8_t                m_bestFilterCount;
+  uint8_t*               m_trainingCovControl;
+  Pel*                   m_bufOrigin;
+  PelBuf*                m_buf;
+  uint64_t**             m_unfilteredDistortion;  // for different block size
+  uint64_t*              m_trainingDistortion[MAX_NUM_CC_ALF_FILTERS];    // for current block size
+  uint64_t*              m_lumaSwingGreaterThanThresholdCount;
+  uint64_t*              m_chromaSampleCountNearMidPoint;
+  uint8_t*               m_filterControl;         // current iterations filter control
+  uint8_t*               m_bestFilterControl;     // best saved filter control
+  int                    m_reuseApsId[2];
+  bool                   m_limitCcAlf;
+#endif
+
 public:
   EncAdaptiveLoopFilter( int& apsIdStart );
   virtual ~EncAdaptiveLoopFilter() {}
@@ -271,6 +303,9 @@ public:
     , const double lambdaChromaWeight
 #endif
   );
+#if JVET_Q0795_CCALF
+  int getNewCcAlfApsId(CodingStructure &cs, int cIdx);
+#endif
   void initCABACEstimator( CABACEncoder* cabacEncoder, CtxCache* ctxCache, Slice* pcSlice, ParameterSetMap<APS>* apsMap );
   void create( const EncCfg* encCfg, const int picWidth, const int picHeight, const ChromaFormat chromaFormatIDC, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE], const int internalBitDepth[MAX_NUM_CHANNEL_TYPE] );
   void destroy();
@@ -292,6 +327,14 @@ private:
   void   deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnitBuf& recYuv, CodingStructure& cs );
   void   getBlkStats(AlfCovariance* alfCovariace, const AlfFilterShape& shape, AlfClassifier** classifier, Pel* org, const int orgStride, Pel* rec, const int recStride, const CompArea& areaDst, const CompArea& area, const ChannelType channel, int vbCTUHeight, int vbPos);
   void   calcCovariance(int ELocal[MAX_NUM_ALF_LUMA_COEFF][MaxAlfNumClippingValues], const Pel *rec, const int stride, const AlfFilterShape& shape, const int transposeIdx, const ChannelType channel, int vbDistance);
+#if JVET_Q0795_CCALF
+  void   deriveStatsForCcAlfFiltering(const PelUnitBuf &orgYuv, const PelUnitBuf &recYuv, const int compIdx,
+                                      const int maskStride, const uint8_t filterIdc, CodingStructure &cs);
+  void   getBlkStatsCcAlf(AlfCovariance &alfCovariance, const AlfFilterShape &shape, const PelUnitBuf &orgYuv,
+                          const PelUnitBuf &recYuv, const UnitArea &areaDst, const UnitArea &area,
+                          const ComponentID compID, const int yPos);
+  void   calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA_COEFF][1], const Pel* rec, const int stride, const AlfFilterShape& shape, int vbDistance);
+#endif
   void   mergeClasses(const AlfFilterShape& alfShape, AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], const int numClasses, short filterIndices[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES]);
 
 
@@ -305,6 +348,9 @@ private:
 #endif
                                   const int numClasses, const int numCoeff, double& distUnfilter );
   void   roundFiltCoeff( int *filterCoeffQuant, double *filterCoeff, const int numCoeff, const int factor );
+#if JVET_Q0795_CCALF
+  void   roundFiltCoeffCCALF( int *filterCoeffQuant, double *filterCoeff, const int numCoeff, const int factor );
+#endif
 
   double getDistCoeffForce0( bool* codedVarBins, double errorForce0CoeffTab[MAX_NUM_ALF_CLASSES][2], int* bitsVarBin, int zeroBitsVarBin, const int numFilters);
   int    lengthUvlc( int uiCode );
@@ -329,6 +375,28 @@ private:
   void setCtuAlternativeChroma( uint8_t* ctuAlts[MAX_NUM_COMPONENT], uint8_t val );
   void copyCtuAlternativeChroma( uint8_t* ctuAltsDst[MAX_NUM_COMPONENT], uint8_t* ctuAltsSrc[MAX_NUM_COMPONENT] );
   int getMaxNumAlternativesChroma( );
+#if JVET_Q0795_CCALF
+  int  getCoeffRateCcAlf(short chromaCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], bool filterEnabled[MAX_NUM_CC_ALF_FILTERS], uint8_t filterCount, ComponentID compID);
+  void deriveCcAlfFilterCoeff( ComponentID compID, const PelUnitBuf& recYuv, const PelUnitBuf& recYuvExt, short filterCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], const uint8_t filterIdx );
+  void computeLog2BlockSizeDistortion(const Pel *org, int orgStride, const Pel *dec, int decStride, int height,
+                                      int width, uint64_t *distortionBuf, int distortionBufStride, int log2BlockWidth,
+                                      int log2BlockHeight, uint64_t &totalDistortion);
+  void determineControlIdcValues(CodingStructure &cs, const ComponentID compID, const PelBuf *buf, const int ctuWidthC,
+                                 const int ctuHeightC, const int picWidthC, const int picHeightC,
+                                 uint64_t **unfilteredDistortion, uint64_t *trainingDistortion[MAX_NUM_CC_ALF_FILTERS],
+                                 uint64_t *lumaSwingGreaterThanThresholdCount,
+                                 uint64_t *chromaSampleCountNearMidPoint,
+                                 bool reuseFilterCoeff, uint8_t *trainingCovControl, uint8_t *filterControl,
+                                 uint64_t &curTotalDistortion, double &curTotalRate,
+                                 bool     filterEnabled[MAX_NUM_CC_ALF_FILTERS],
+                                 uint8_t  mapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS + 1],
+                                 uint8_t &ccAlfFilterCount);
+  void deriveCcAlfFilter( CodingStructure& cs, ComponentID compID, const PelUnitBuf& orgYuv, const PelUnitBuf& tempDecYuvBuf, const PelUnitBuf& dstYuv );
+  std::vector<int> getAvailableCcAlfApsIds(CodingStructure& cs, ComponentID compID);
+  void xSetupCcAlfAPS( CodingStructure& cs );
+  void countLumaSwingGreaterThanThreshold(const Pel* luma, int lumaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* lumaSwingGreaterThanThresholdCount, int lumaCountStride);
+  void countChromaSampleValueNearMidPoint(const Pel* chroma, int chromaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* chromaSampleCountNearMidPoint, int chromaSampleCountNearMidPointStride);
+#endif
 };
 
 
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index f27bb3c1001942819569517a46d851507e6be885..077dfd54ff71be8acebd5a47bca935b8d49e31fa 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -171,6 +171,9 @@ protected:
   bool      m_noPartitionConstraintsOverrideConstraintFlag;
   bool      m_bNoSaoConstraintFlag;
   bool      m_bNoAlfConstraintFlag;
+#if JVET_Q0795_CCALF
+  bool      m_noCCAlfConstraintFlag;
+#endif
   bool      m_bNoRefWraparoundConstraintFlag;
   bool      m_bNoTemporalMvpConstraintFlag;
   bool      m_bNoSbtmvpConstraintFlag;
@@ -238,6 +241,9 @@ protected:
   int       m_aiPad[2];
 
   bool      m_AccessUnitDelimiter;               ///< add Access Unit Delimiter NAL units
+#if JVET_Q0775_PH_IN_SH
+  bool      m_enablePictureHeaderInSliceHeader;  ///< Enable Picture Header in Slice Header
+#endif
 
   int       m_iMaxRefPicNum;                     ///< this is used to mimic the sliding mechanism used by the decoder
                                                  // TODO: We need to have a common sliding mechanism used by both the encoder and decoder
@@ -592,6 +598,9 @@ protected:
   bool      m_useWeightedPred;       //< Use of Weighting Prediction (P_SLICE)
   bool      m_useWeightedBiPred;    //< Use of Bi-directional Weighting Prediction (B_SLICE)
   WeightedPredictionMethod m_weightedPredictionMethod;
+#if JVET_Q0297_MER
+  uint32_t      m_log2ParallelMergeLevelMinus2;       ///< Parallel merge estimation region
+#endif
   uint32_t      m_maxNumMergeCand;                    ///< Maximum number of merge candidates
   uint32_t      m_maxNumAffineMergeCand;              ///< Maximum number of affine merge candidates
   uint32_t      m_maxNumTriangleCand;
@@ -683,6 +692,10 @@ protected:
 #endif
 
   bool        m_alf;                                          ///< Adaptive Loop Filter
+#if JVET_Q0795_CCALF
+  bool        m_ccalf;
+  int         m_ccalfQpThreshold;
+#endif
 #if JVET_O0756_CALCULATE_HDRMETRICS
   double                       m_whitePointDeltaE[hdrtoolslib::NB_REF_WHITE];
   double                       m_maxSampleValue;
@@ -732,6 +745,10 @@ public:
   void      setNoSaoConstraintFlag(bool bVal) { m_bNoSaoConstraintFlag = bVal; }
   bool      getNoAlfConstraintFlag() const { return m_bNoAlfConstraintFlag; }
   void      setNoAlfConstraintFlag(bool bVal) { m_bNoAlfConstraintFlag = bVal; }
+#if JVET_Q0795_CCALF
+  bool      getNoCCAlfConstraintFlag() const { return m_noCCAlfConstraintFlag; }
+  void      setNoCCAlfConstraintFlag(bool bVal) { m_noCCAlfConstraintFlag = bVal; }
+#endif
   bool      getNoRefWraparoundConstraintFlag() const { return m_bNoRefWraparoundConstraintFlag; }
   void      setNoRefWraparoundConstraintFlag(bool bVal) { m_bNoRefWraparoundConstraintFlag = bVal; }
   bool      getNoTemporalMvpConstraintFlag() const { return m_bNoTemporalMvpConstraintFlag; }
@@ -1183,6 +1200,10 @@ public:
 
   bool      getAccessUnitDelimiter() const  { return m_AccessUnitDelimiter; }
   void      setAccessUnitDelimiter(bool val){ m_AccessUnitDelimiter = val; }
+#if JVET_Q0775_PH_IN_SH
+  bool      getEnablePictureHeaderInSliceHeader() const { return m_enablePictureHeaderInSliceHeader; }
+  void      setEnablePictureHeaderInSliceHeader(bool val) { m_enablePictureHeaderInSliceHeader = val; }
+#endif
 
   //==== Loop/Deblock Filter ========
   bool      getLoopFilterDisable            ()      { return  m_bLoopFilterDisable;       }
@@ -1581,6 +1602,10 @@ public:
   void         setWPBiPred            ( bool b )                     { m_useWeightedBiPred = b;    }
   bool         getUseWP               ()                             { return m_useWeightedPred;   }
   bool         getWPBiPred            ()                             { return m_useWeightedBiPred; }
+#if JVET_Q0297_MER
+  void         setLog2ParallelMergeLevelMinus2(uint32_t u)           { m_log2ParallelMergeLevelMinus2 = u; }
+  uint32_t     getLog2ParallelMergeLevelMinus2()                     { return m_log2ParallelMergeLevelMinus2; }
+#endif
   void         setMaxNumMergeCand                ( uint32_t u )          { m_maxNumMergeCand = u;      }
   uint32_t         getMaxNumMergeCand                ()                  { return m_maxNumMergeCand;   }
   void         setMaxNumAffineMergeCand          ( uint32_t u )      { m_maxNumAffineMergeCand = u;    }
@@ -1770,7 +1795,12 @@ public:
 #endif
   void         setUseALF( bool b ) { m_alf = b; }
   bool         getUseALF()                                      const { return m_alf; }
-
+#if JVET_Q0795_CCALF
+  void         setUseCCALF( bool b )                                  { m_ccalf = b; }
+  bool         getUseCCALF()                                    const { return m_ccalf; }
+  void         setCCALFQpThreshold( int b )                           { m_ccalfQpThreshold = b; }
+  int          getCCALFQpThreshold()                            const { return m_ccalfQpThreshold; }
+#endif
 #if JVET_O0756_CALCULATE_HDRMETRICS
   void        setWhitePointDeltaE( uint32_t index, double value )     { m_whitePointDeltaE[ index ] = value; }
   double      getWhitePointDeltaE( uint32_t index )             const { return m_whitePointDeltaE[ index ]; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 664375b9067a73c1ed886417616ec5762d6b9fd7..e33e976488c070a10814dff2fac039994f5890c7 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -800,7 +800,12 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par
       {
         bool skipSecColorSpace = false;
         skipSecColorSpace = xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? true : false));
-        
+#if JVET_Q0820_ACT
+        if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) && !m_pcEncCfg->getRGBFormatFlag())
+        {
+          skipSecColorSpace = true;
+        }
+#endif 
         if (!skipSecColorSpace && !tempCS->firstColorSpaceTestOnly)
         {
           xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? false : true));
diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp
index 797cd27d26f593d816aa52b7335783dac66d3d05..7e0843829922394be2b7228cf2ba7c13d87e5310 100644
--- a/source/Lib/EncoderLib/EncGOP.cpp
+++ b/source/Lib/EncoderLib/EncGOP.cpp
@@ -401,7 +401,11 @@ int EncGOP::xWritePicHeader( AccessUnit &accessUnit, PicHeader *picHeader )
   m_HLSWriter->setBitstream( &nalu.m_Bitstream );
   nalu.m_temporalId = accessUnit.temporalId;
   nalu.m_nuhLayerId = m_pcEncLib->getLayerId();
+#if JVET_Q0775_PH_IN_SH
+  m_HLSWriter->codePictureHeader( picHeader, true );
+#else
   m_HLSWriter->codePictureHeader( picHeader );
+#endif
   accessUnit.push_back(new NALUnitEBSP(nalu));
   return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8;
 }
@@ -2790,7 +2794,9 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
       m_pcLoopFilter->loopFilterPic( cs );
 
       CS::setRefinedMotionField(cs);
+#if !JVET_Q0795_CCALF
       DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) );
+#endif
 
       if( pcSlice->getSPS()->getSAOEnabledFlag() )
       {
@@ -2844,8 +2850,15 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
           }
           pcPic->slices[s]->setAlfAPSs(cs.slice->getAlfAPSs());
           pcPic->slices[s]->setTileGroupApsIdChroma(cs.slice->getTileGroupApsIdChroma());
+#if JVET_Q0795_CCALF
+          pcPic->slices[s]->setTileGroupCcAlfCbApsId(cs.slice->getTileGroupCcAlfCbApsId());
+          pcPic->slices[s]->setTileGroupCcAlfCrApsId(cs.slice->getTileGroupCcAlfCrApsId());
+#endif
         }
       }
+#if JVET_Q0795_CCALF
+      DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) );
+#endif
       if (m_pcCfg->getUseCompositeRef() && getPrepareLTRef())
       {
         updateCompositeReference(pcSlice, rcListPic, pocCurr);
@@ -2951,7 +2964,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
         }
       }
 
+#if JVET_Q0795_CCALF
+      if (pcSlice->getSPS()->getALFEnabledFlag() && (pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) || pcSlice->getTileGroupCcAlfCbEnabledFlag() || pcSlice->getTileGroupCcAlfCrEnabledFlag()))
+#else
       if (pcSlice->getSPS()->getALFEnabledFlag() && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y))
+#endif
       {
         for (int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++)
         {
@@ -2966,12 +2983,28 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
             *apsMap->allocatePS(apsId) = *aps; //allocate and cpy
             m_pcALF->setApsIdStart( apsId );
           }
+#if JVET_Q0795_CCALF
+          else if (pcSlice->getTileGroupCcAlfCbEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCbApsId())
+          {
+            writeAPS = true;
+            aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCbApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
+          }
+          else if (pcSlice->getTileGroupCcAlfCrEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCrApsId())
+          {
+            writeAPS = true;
+            aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCrApsId() << NUM_APS_TYPE_LEN) + ALF_APS);
+          }
+#endif
 
           if (writeAPS )
           {
             actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true );
             apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS);
+#if JVET_Q0795_CCALF
+            CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "Wrong APS pointer in compressGOP");
+#else
             CHECK(aps != pcSlice->getAlfAPSs()[apsId], "Wrong APS pointer in compressGOP");
+#endif
           }
         }
       }
@@ -3069,6 +3102,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
             picHeader->setNumAlfAps(pcSlice->getTileGroupNumAps());
             picHeader->setAlfAPSs(pcSlice->getTileGroupApsIdLuma());
             picHeader->setAlfApsIdChroma(pcSlice->getTileGroupApsIdChroma());
+#if JVET_Q0795_CCALF
+            picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupCcAlfCbEnabledFlag());
+            picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupCcAlfCrEnabledFlag());
+            picHeader->setCcAlfCbApsId(pcSlice->getTileGroupCcAlfCbApsId());
+            picHeader->setCcAlfCrApsId(pcSlice->getTileGroupCcAlfCrApsId());
+#endif
           }
           else {
             picHeader->setAlfEnabledPresentFlag( false );
@@ -3076,7 +3115,19 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
 
           pcPic->cs->picHeader->setPic(pcPic);
           pcPic->cs->picHeader->setValid();
+#if JVET_Q0775_PH_IN_SH
+          if (pcPic->cs->pps->getNumSlicesInPic() > 1 || m_pcCfg->getEnablePictureHeaderInSliceHeader())
+          {
+            pcSlice->setPictureHeaderInSliceHeader(false);
+            actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader);
+          }
+          else
+          {
+            pcSlice->setPictureHeaderInSliceHeader(true);
+          }
+#else
           actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader);
+#endif
         }
         pcSlice->setPicHeader( pcPic->cs->picHeader );
 
@@ -3091,6 +3142,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
 
 
         tmpBitsBeforeWriting = m_HLSWriter->getNumberOfWrittenBits();
+#if JVET_Q0795_CCALF
+        pcSlice->m_ccAlfFilterParam      = m_pcALF->getCcAlfFilterParam();
+        pcSlice->m_ccAlfFilterControl[0] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cb);
+        pcSlice->m_ccAlfFilterControl[1] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cr);
+#endif
         m_HLSWriter->codeSliceHeader( pcSlice );
         actualHeadBits += ( m_HLSWriter->getNumberOfWrittenBits() - tmpBitsBeforeWriting );
 
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index 3eb5c084637d789d323407f37aee8067091a4c43..ce012c6701bde75ce6c7dc2dfcf4b7072f6b3ed8 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -976,6 +976,9 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
   cinfo->setNoPartitionConstraintsOverrideConstraintFlag(m_noPartitionConstraintsOverrideConstraintFlag);
   cinfo->setNoSaoConstraintFlag(m_bNoSaoConstraintFlag);
   cinfo->setNoAlfConstraintFlag(m_bNoAlfConstraintFlag);
+#if JVET_Q0795_CCALF
+  cinfo->setNoCCAlfConstraintFlag(m_noCCAlfConstraintFlag);
+#endif
   cinfo->setNoRefWraparoundConstraintFlag(m_bNoRefWraparoundConstraintFlag);
   cinfo->setNoTemporalMvpConstraintFlag(m_bNoTemporalMvpConstraintFlag);
   cinfo->setNoSbtmvpConstraintFlag(m_bNoSbtmvpConstraintFlag);
@@ -1146,6 +1149,9 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
 
   sps.setScalingListFlag ( (m_useScalingListId == SCALING_LIST_OFF) ? 0 : 1 );
   sps.setALFEnabledFlag( m_alf );
+#if JVET_Q0795_CCALF
+  sps.setCCALFEnabledFlag( m_ccalf );
+#endif
   sps.setVuiParametersPresentFlag(getVuiParametersPresentFlag());
 
   if (sps.getVuiParametersPresentFlag())
@@ -1260,6 +1266,10 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps )
   }
 
   sps.setRprEnabledFlag( m_rprEnabled || sps.getInterLayerPresentFlag() );
+
+#if JVET_Q0297_MER
+  sps.setLog2ParallelMergeLevelMinus2( m_log2ParallelMergeLevelMinus2 );
+#endif
 }
 
 void EncLib::xInitHrdParameters(SPS &sps)
diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h
index f9b13233e597e85169e374573f23fea701a2e419..2a6d82cadb4c0b1e17ffda28b8bb323dfb2b0925 100644
--- a/source/Lib/EncoderLib/EncLib.h
+++ b/source/Lib/EncoderLib/EncLib.h
@@ -159,6 +159,9 @@ public:
   SPS*                      getSPS( int spsId ) { return m_spsMap.getPS( spsId ); };
   APS**                     getApss() { return m_apss; }
   Ctx                       m_entropyCodingSyncContextState;      ///< leave in addition to vector for compatibility
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+  PLTBuf                    m_palettePredictorSyncState;
+#endif
 
 protected:
   void  xGetNewPicBuffer  ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Picture*& rpcPic, int ppsId ); ///< get picture buffer which will be processed. If ppsId<0, then the ppsMap will be queried for the first match.
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index 922835d58ac9ce7643923b6436c7b5e87d726262..833986d556bfcc41d0d55384bb98477efd857666 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -1830,6 +1830,20 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
     }
 
     if( split == CU_QUAD_SPLIT ) cuECtx.set( DID_QUAD_SPLIT, true );
+#if JVET_Q0297_MER
+    if (cs.sps->getLog2ParallelMergeLevelMinus2())
+    {
+      const CompArea& area = partitioner.currArea().Y();
+      const SizeType size = 1 << (cs.sps->getLog2ParallelMergeLevelMinus2() + 2);
+      if (!cs.slice->isIntra() && (area.width > size || area.height > size))
+      {
+        if (area.height <= size && split == CU_HORZ_SPLIT) return false;
+        if (area.width <= size && split == CU_VERT_SPLIT) return false;
+        if (area.height <= 2 * size && split == CU_TRIH_SPLIT) return false;
+        if (area.width <= 2 * size && split == CU_TRIV_SPLIT) return false;
+      }
+    }
+#endif
     return true;
   }
   else
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index ab194d148c76b8c169a871d9d2cf7335eb4fe844..8e54f7b2873ad0e0d612c07b72eb13a36786a869 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -1444,6 +1444,9 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
       {
         // Top is available, we use it.
         pCABACWriter->getCtx() = pEncLib->m_entropyCodingSyncContextState;
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+        cs.setPrevPLT(pEncLib->m_palettePredictorSyncState);
+#endif
       }
       prevQP[0] = prevQP[1] = pcSlice->getSliceQp();
     }
@@ -1566,6 +1569,9 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
     if( cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && pEncLib->getEntropyCodingSyncEnabledFlag() )
     {
       pEncLib->m_entropyCodingSyncContextState = pCABACWriter->getCtx();
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+      cs.storePrevPLT(pEncLib->m_palettePredictorSyncState);
+#endif
     }
 
     int actualBits = int(cs.fracBits >> SCALE_BITS);
@@ -1683,6 +1689,9 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
       {
         // Top is available, so use it.
         m_CABACWriter->getCtx() = m_entropyCodingSyncContextState;
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+        cs.setPrevPLT(m_palettePredictorSyncState);
+#endif
       }
     }
 
@@ -1698,6 +1707,9 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
     if( cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && wavefrontsEnabled )
     {
       m_entropyCodingSyncContextState = m_CABACWriter->getCtx();
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+      cs.storePrevPLT(m_palettePredictorSyncState);
+#endif
     }
 
     // terminate the sub-stream, if required (end of slice-segment, end of tile, end of wavefront-CTU-row):
diff --git a/source/Lib/EncoderLib/EncSlice.h b/source/Lib/EncoderLib/EncSlice.h
index ed88068075c5a87db40fb86e6750f62e394f6937..6c633aa055bdf8f82315e8157820725cf9b059c0 100644
--- a/source/Lib/EncoderLib/EncSlice.h
+++ b/source/Lib/EncoderLib/EncSlice.h
@@ -92,6 +92,9 @@ private:
   uint32_t                    m_uiSliceSegmentIdx;
   Ctx                     m_entropyCodingSyncContextState;      ///< context storage for state of contexts at the wavefront/WPP/entropy-coding-sync second CTU of tile-row
   SliceType               m_encCABACTableIdx;
+#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU
+  PLTBuf                  m_palettePredictorSyncState;
+#endif
 #if SHARP_LUMA_DELTA_QP || ENABLE_QPA_SUB_CTU
   int                     m_gopID;
 #endif
diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp
index ff5ae6e104bb6162beec220bde5f07cba0b431e6..5cb2192760e3cbd490b12f46305f48ab6c66c381 100644
--- a/source/Lib/EncoderLib/InterSearch.cpp
+++ b/source/Lib/EncoderLib/InterSearch.cpp
@@ -6548,8 +6548,19 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
       
       uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests
       std::vector<TrMode> trModes;
+#if JVET_Q0820_ACT 
+      if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)
+      {
+        nNumTransformCands = 0;
+      }
+      else
+      {
+#endif
       trModes.push_back( TrMode( 0, true ) ); //DCT2
       nNumTransformCands = 1;
+#if JVET_Q0820_ACT 
+      }
+#endif
       //for a SBT-no-residual TU, the RDO process should be called once, in order to get the RD cost
       if( tsAllowed && !tu.noResidual )
       {
@@ -6579,7 +6590,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
         }
       }
 
+#if JVET_Q0820_ACT
+      if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING))
+#else
       if (colorTransFlag)
+#endif
       {
         m_pcTrQuant->lambdaAdjustColorTrans(true);
         m_pcRdCost->lambdaAdjustColorTrans(true, compID);
@@ -6587,15 +6602,19 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
 
       const int crossCPredictionModesToTest = preCalcAlpha != 0 ? 2 : 1;
       const int numTransformCandidates = nNumTransformCands;
+#if !JVET_Q0695_CHROMA_TS_JCCR
       const bool isOneMode                  = crossCPredictionModesToTest == 1 && numTransformCandidates == 1;
 
       bool isLastBest = isOneMode;
+#endif
       for( int transformMode = 0; transformMode < numTransformCandidates; transformMode++ )
       {
         for( int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++ )
         {
           const bool isFirstMode  = transformMode == 0 && crossCPredictionModeId == 0;
+#if !JVET_Q0695_CHROMA_TS_JCCR
           const bool isLastMode   = ( transformMode + 1 ) == numTransformCandidates && ( crossCPredictionModeId + 1 ) == crossCPredictionModesToTest;
+#endif
           const bool bUseCrossCPrediction = crossCPredictionModeId != 0;
 
           // copy the original residual into the residual buffer
@@ -6625,6 +6644,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
           tu.compAlpha[compID]      = bUseCrossCPrediction ? preCalcAlpha : 0;
 
           QpParam cQP(tu, compID);  // note: uses tu.transformSkip[compID]
+#if !JVET_Q0820_ACT
           if (colorTransFlag)
           {
             for (int qpIdx = 0; qpIdx < 2; qpIdx++)
@@ -6634,6 +6654,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
               cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6;
             }
           }
+#endif
 
 #if RDOQ_CHROMA_LAMBDA
           m_pcTrQuant->selectLambda(compID);
@@ -6853,13 +6874,17 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
               }
             }
 
+#if !JVET_Q0695_CHROMA_TS_JCCR
             if( !isLastMode || (compID != COMPONENT_Y && !tu.noResidual) )
             {
+#endif
               bestTU.copyComponentFrom( tu, compID );
               saveCS.getResiBuf( compArea ).copyFrom( csFull->getResiBuf( compArea ) );
+#if !JVET_Q0695_CHROMA_TS_JCCR
             }
 
             isLastBest = isLastMode;
+#endif
           }
           if( tu.noResidual )
           {
@@ -6868,14 +6893,22 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
         }
       }
 
+#if !JVET_Q0695_CHROMA_TS_JCCR
       if( !isLastBest )
       {
+#endif
         // copy component
         tu.copyComponentFrom( bestTU, compID );
         csFull->getResiBuf( compArea ).copyFrom( saveCS.getResiBuf( compArea ) );
+#if !JVET_Q0695_CHROMA_TS_JCCR
       }
+#endif
 
+#if JVET_Q0820_ACT
+      if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING))
+#else
       if (colorTransFlag)
+#endif
       {
         m_pcTrQuant->lambdaAdjustColorTrans(false);
         m_pcRdCost->lambdaAdjustColorTrans(false, compID);
@@ -6887,7 +6920,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
     {
       PelUnitBuf     orgResidual = orgResi->subBuf(relativeUnitArea);
       PelUnitBuf     invColorTransResidual = m_colorTransResiBuf[2].getBuf(relativeUnitArea);
+#if JVET_Q0820_ACT
+      csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false, slice.clpRng(COMPONENT_Y));
+#else
       csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false);
+#endif
 
       for (uint32_t c = 0; c < numTBlocks; c++)
       {
@@ -6902,6 +6939,15 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
       const CompArea& cbArea = tu.blocks[COMPONENT_Cb];
       const CompArea& crArea = tu.blocks[COMPONENT_Cr];
       bool checkJointCbCr = (sps.getJointCbCrEnabledFlag()) && (!tu.noResidual) && (TU::getCbf(tu, COMPONENT_Cb) || TU::getCbf(tu, COMPONENT_Cr));
+#if JVET_Q0695_CHROMA_TS_JCCR 
+      bool checkDCTOnly = (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && !TU::getCbf(tu, COMPONENT_Cr)) ||
+                          (TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2 && !TU::getCbf(tu, COMPONENT_Cb)) ||
+                          (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2);
+
+      bool checkTSOnly = (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_SKIP && !TU::getCbf(tu, COMPONENT_Cr)) ||
+                         (TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_SKIP && !TU::getCbf(tu, COMPONENT_Cb)) ||
+                         (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_SKIP && TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_SKIP);
+#endif
       const int channelBitDepth = sps.getBitDepth(toChannelType(COMPONENT_Cb));
       bool      reshape         = slice.getPicHeader()->getLmcsEnabledFlag() && slice.getPicHeader()->getLmcsChromaResidualScaleFlag()
                                && tu.blocks[COMPONENT_Cb].width * tu.blocks[COMPONENT_Cb].height > 4;
@@ -6910,7 +6956,9 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
       {
         minCostCbCr += minCost[COMPONENT_Y];  // ACT should consider three-component cost
       }
+#if !JVET_Q0695_CHROMA_TS_JCCR
       bool   isLastBest  = false;
+#endif
 
       CompStorage      orgResiCb[4], orgResiCr[4];   // 0:std, 1-3:jointCbCr
       std::vector<int> jointCbfMasksToTest;
@@ -6930,6 +6978,38 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
 
       for (int cbfMask: jointCbfMasksToTest)
       {
+#if JVET_Q0695_CHROMA_TS_JCCR
+        ComponentID codeCompId = (cbfMask >> 1 ? COMPONENT_Cb : COMPONENT_Cr);
+        ComponentID otherCompId = (codeCompId == COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr);
+        bool        tsAllowed = TU::isTSAllowed(tu, codeCompId) && (m_pcEncCfg->getUseChromaTS());
+        uint8_t     numTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
+        bool        cbfDCT2 = true;
+
+        std::vector<TrMode> trModes;
+        if (checkDCTOnly || checkTSOnly)
+        {
+          numTransformCands = 1;
+        }
+
+        if (!checkTSOnly)
+        {
+          trModes.push_back(TrMode(0, true)); // DCT2
+        }
+        if (tsAllowed && !checkDCTOnly)
+        {
+          trModes.push_back(TrMode(1, true));//TS
+        }
+        for (int modeId = 0; modeId < numTransformCands; modeId++)
+        {
+          if (modeId && !cbfDCT2)
+          {
+            continue;
+          }
+          if (!trModes[modeId].second)
+          {
+            continue;
+          }
+#endif
         TCoeff     currAbsSum       = 0;
         uint64_t   currCompFracBits = 0;
         Distortion currCompDistCb   = 0;
@@ -6939,12 +7019,23 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
         tu.jointCbCr = (uint8_t) cbfMask;
         tu.compAlpha[COMPONENT_Cb] = tu.compAlpha[COMPONENT_Cr] = 0;
         // encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode.
+#if JVET_Q0695_CHROMA_TS_JCCR 
+        tu.mtsIdx[codeCompId]  = trModes[modeId].first;
+        tu.mtsIdx[otherCompId] = MTS_DCT2_DCT2;
+#else
         tu.mtsIdx[COMPONENT_Cb] = tu.mtsIdx[COMPONENT_Cr] = MTS_DCT2_DCT2;
+#endif
         int         codedCbfMask = 0;
+#if !JVET_Q0695_CHROMA_TS_JCCR
         ComponentID codeCompId = (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr);
         ComponentID otherCompId = (codeCompId == COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr);
+#endif
 
+#if JVET_Q0820_ACT
+        if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING))
+#else
         if (colorTransFlag)
+#endif
         {
           m_pcTrQuant->lambdaAdjustColorTrans(true);
           m_pcTrQuant->selectLambda(codeCompId);
@@ -6978,6 +7069,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
 
         Distortion currCompDistY = MAX_UINT64;
         QpParam qpCbCr(tu, codeCompId);
+#if !JVET_Q0820_ACT
         if (colorTransFlag)
         {
           for (int qpIdx = 0; qpIdx < 2; qpIdx++)
@@ -6987,12 +7079,26 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
             qpCbCr.rems[qpIdx] = qpCbCr.Qps[qpIdx] % 6;
           }
         }
+#endif
 
         tu.getCoeffs(otherCompId).fill(0);   // do we need that?
         TU::setCbfAtDepth(tu, otherCompId, tu.depth, false);
 
         PelBuf &codeResi   = (codeCompId == COMPONENT_Cr ? crResi : cbResi);
         TCoeff  compAbsSum = 0;
+#if JVET_Q0695_CHROMA_TS_JCCR
+        if (numTransformCands > 1)
+        {
+          if (modeId == 0)
+          {
+            m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, &trModes, m_pcEncCfg->getMTSInterMaxCand());
+            tu.mtsIdx[codeCompId] = trModes[modeId].first;
+            tu.mtsIdx[otherCompId] = MTS_DCT2_DCT2;
+          }
+          m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, compAbsSum, m_CABACEstimator->getCtx(), true);
+        }
+        else
+#endif
         m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, compAbsSum, m_CABACEstimator->getCtx());
         if (compAbsSum > 0)
         {
@@ -7015,6 +7121,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
         }
         currAbsSum = codedCbfMask;
 
+#if JVET_Q0695_CHROMA_TS_JCCR 
+        if (!tu.mtsIdx[codeCompId])
+        {
+          cbfDCT2 = (currAbsSum > 0);
+        }
+#endif 
         if (currAbsSum > 0)
         {
           m_CABACEstimator->cbf_comp(cs, codedCbfMask >> 1, cbArea, currDepth, false);
@@ -7037,7 +7149,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
           {
             PelUnitBuf     orgResidual = orgResi->subBuf(relativeUnitArea);
             PelUnitBuf     invColorTransResidual = m_colorTransResiBuf[2].getBuf(relativeUnitArea);
+#if JVET_Q0820_ACT
+            csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false, slice.clpRng(COMPONENT_Y));
+#else
             csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false);
+#endif
 
             currCompDistY = m_pcRdCost->getDistPart(orgResidual.bufs[COMPONENT_Y], invColorTransResidual.bufs[COMPONENT_Y], sps.getBitDepth(toChannelType(COMPONENT_Y)), COMPONENT_Y, DF_SSE);
             currCompDistCb = m_pcRdCost->getDistPart(orgResidual.bufs[COMPONENT_Cb], invColorTransResidual.bufs[COMPONENT_Cb], sps.getBitDepth(toChannelType(COMPONENT_Cb)), COMPONENT_Cb, DF_SSE);
@@ -7070,8 +7186,10 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
             uiSingleDistComp[COMPONENT_Y] = currCompDistY;
           }
           minCostCbCr                    = currCompCost;
+#if !JVET_Q0695_CHROMA_TS_JCCR
           isLastBest = (cbfMask == jointCbfMasksToTest.back());
           if (!isLastBest)
+#endif
           {
             bestTU.copyComponentFrom(tu, COMPONENT_Cb);
             bestTU.copyComponentFrom(tu, COMPONENT_Cr);
@@ -7080,6 +7198,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
           }
         }
 
+#if !JVET_Q0695_CHROMA_TS_JCCR
         if( !isLastBest )
         {
           // copy component
@@ -7088,11 +7207,27 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par
           csFull->getResiBuf( cbArea ).copyFrom( saveCS.getResiBuf( cbArea ) );
           csFull->getResiBuf( crArea ).copyFrom( saveCS.getResiBuf( crArea ) );
         }
+#endif
+
+#if JVET_Q0820_ACT
+        if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING))
+#else
         if (colorTransFlag)
+#endif
         {
           m_pcTrQuant->lambdaAdjustColorTrans(false);
         }
+#if JVET_Q0695_CHROMA_TS_JCCR
+        }
+#endif
       }
+#if JVET_Q0695_CHROMA_TS_JCCR
+      // copy component
+      tu.copyComponentFrom(bestTU, COMPONENT_Cb);
+      tu.copyComponentFrom(bestTU, COMPONENT_Cr);
+      csFull->getResiBuf(cbArea).copyFrom(saveCS.getResiBuf(cbArea));
+      csFull->getResiBuf(crArea).copyFrom(saveCS.getResiBuf(crArea));
+#endif
     }
 
     m_CABACEstimator->getCtx() = ctxStart;
@@ -7393,7 +7528,11 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
   orgResidual.copyFrom(cs.getResiBuf());
   if (colorTransAllowed)
   {
+#if JVET_Q0820_ACT
+    cs.getResiBuf().colorSpaceConvert(colorTransResidual, true, cu.cs->slice->clpRng(COMPONENT_Y));
+#else
     cs.getResiBuf().colorSpaceConvert(colorTransResidual, true);
+#endif
   }
 
   const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx());
@@ -7549,7 +7688,11 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa
     bestIter = iter;
     if (cu.rootCbf && cu.colorTransform)
     {
+#if JVET_Q0820_ACT
+      cs.getResiBuf(curUnitArea).colorSpaceConvert(cs.getResiBuf(curUnitArea), false, cu.cs->slice->clpRng(COMPONENT_Y));
+#else
       cs.getResiBuf(curUnitArea).colorSpaceConvert(cs.getResiBuf(curUnitArea), false);
+#endif
     }
 
     if (iter != (numAllowedColorSpace - 1))
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index dd6f112b301ba4d98a1f72878fa01b6266bbf721..5ee8d0ee19ec6d5b677ef1ebf56d425d22c76f58 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -2784,7 +2784,11 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
   CHECK( tu.jointCbCr && compID == COMPONENT_Cr, "wrong combination of compID and jointCbCr" );
   bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb;
 
+#if JVET_Q0695_CHROMA_TS_JCCR || JVET_Q0820_ACT
+  if (compID == COMPONENT_Y)
+#else
   if (compID == COMPONENT_Y || (isChroma(compID) && tu.cu->bdpcmModeChroma))
+#endif
   {
   PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area );
   if( default0Save1Load2 != 2 )
@@ -2989,8 +2993,17 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp
 
     if (trModes)
     {
+#if JVET_Q0695_CHROMA_TS_JCCR 
+        m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand());
+        tu.mtsIdx[codeCompId] = trModes->at(0).first;
+        if (tu.jointCbCr)
+        {
+          tu.mtsIdx[(codeCompId == COMPONENT_Cr) ? COMPONENT_Cb : COMPONENT_Cr] = MTS_DCT2_DCT2;
+        }
+#else
         m_pcTrQuant->transformNxN(tu, compID, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand());
         tu.mtsIdx[compID] = trModes->at(0).first;
+#endif
     }
     // encoder bugfix: Set loadTr to aovid redundant transform process
 #if JVET_AHG14_LOSSLESS
@@ -3132,6 +3145,9 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c
 
   m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc());
 
+#if JVET_Q0820_ACT
+  if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif 
   m_pcTrQuant->lambdaAdjustColorTrans(true);
 
   if (jointCbCr)
@@ -3167,19 +3183,32 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c
   if (isLuma(compID))
   {
     QpParam cQP(tu, compID);
+#if !JVET_Q0820_ACT 
     for (int qpIdx = 0; qpIdx < 2; qpIdx++)
     {
       cQP.Qps[qpIdx] = cQP.Qps[qpIdx] + (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg);
       cQP.pers[qpIdx] = cQP.Qps[qpIdx] / 6;
       cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6;
     }
+#endif
 
     if (trModes)
     {
       m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, m_pcEncCfg->getMTSIntraMaxCand());
       tu.mtsIdx[compID] = trModes->at(0).first;
     }
+#if JVET_Q0820_ACT 
+    if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmMode != 0)
+#endif 
     m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
+#if JVET_Q0820_ACT
+    if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) && tu.cu->bdpcmMode == 0)
+    {
+      uiAbsSum = 0;
+      tu.getCoeffs(compID).fill(0);
+      TU::setCbfAtDepth(tu, compID, tu.depth, 0);
+    }
+#endif 
 
     if (uiAbsSum > 0)
     {
@@ -3195,12 +3224,14 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c
     int         codedCbfMask = 0;
     ComponentID codeCompId = (tu.jointCbCr ? (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr) : compID);
     QpParam qpCbCr(tu, codeCompId);
+#if !JVET_Q0820_ACT 
     for (int qpIdx = 0; qpIdx < 2; qpIdx++)
     {
       qpCbCr.Qps[qpIdx] = qpCbCr.Qps[qpIdx] + (codeCompId == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg);
       qpCbCr.pers[qpIdx] = qpCbCr.Qps[qpIdx] / 6;
       qpCbCr.rems[qpIdx] = qpCbCr.Qps[qpIdx] % 6;
     }
+#endif
 
     if (tu.jointCbCr)
     {
@@ -3211,7 +3242,23 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c
 
     PelBuf& codeResi = (codeCompId == COMPONENT_Cr ? crResi : piResi);
     uiAbsSum = 0;
+#if JVET_Q0820_ACT
+    if (trModes)
+    {
+      m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand());
+      tu.mtsIdx[codeCompId] = trModes->at(0).first;
+      if (tu.jointCbCr)
+      {
+        tu.mtsIdx[(codeCompId == COMPONENT_Cr) ? COMPONENT_Cb : COMPONENT_Cr] = MTS_DCT2_DCT2;
+      }
+    }
+    if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[codeCompId] == 0) || tu.cu->bdpcmModeChroma != 0)
+    {
+      m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx(), loadTr);
+    }
+#else
     m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx());
+#endif
     if (uiAbsSum > 0)
     {
       m_pcTrQuant->invTransformNxN(tu, codeCompId, codeResi, qpCbCr);
@@ -3232,6 +3279,9 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c
       if (tu.jointCbCr != codedCbfMask)
       {
         ruiDist = std::numeric_limits<Distortion>::max();
+#if JVET_Q0820_ACT
+        if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif 
         m_pcTrQuant->lambdaAdjustColorTrans(false);
         return;
       }
@@ -3249,6 +3299,9 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c
     }
   }
 
+#if JVET_Q0820_ACT
+  if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif 
   m_pcTrQuant->lambdaAdjustColorTrans(false);
 
   ruiDist += m_pcRdCost->getDistPart(piOrgResi, piResi, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE);
@@ -3449,6 +3502,23 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
     {
       nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests
 
+#if JVET_Q0820_ACT 
+      if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)
+      {
+        nNumTransformCands = 1;
+        CHECK(!tsAllowed && !cu.bdpcmMode, "transform skip should be enabled for LS");
+        if (cu.bdpcmMode)
+        {
+          trModes.push_back(TrMode(0, true));
+        }
+        else
+        {
+          trModes.push_back(TrMode(1, true));
+        }
+      }
+      else
+      {
+#endif
       trModes.push_back( TrMode( 0, true ) ); //DCT2
       if( tsAllowed )
       {
@@ -3461,6 +3531,9 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
           trModes.push_back( TrMode( i, true ) );
         }
       }
+#if JVET_Q0820_ACT 
+      }
+#endif 
     }
 
     CHECK( !tu.Y().valid(), "Invalid TU" );
@@ -3644,7 +3717,17 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par
       if( ( sps.getUseLFNST() ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) )
       {
         //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
+#if JVET_Q0820_ACT 
+        if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif 
         singleCostTmp = MAX_DOUBLE;
+#if JVET_Q0820_ACT 
+        else
+        {
+          singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, subTuCounter, ispType, &cuCtx);
+          singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma);
+        }
+#endif 
       }
       else
       {
@@ -3964,7 +4047,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
         piResi.subtract(piPred);
     }
 
+#if JVET_Q0820_ACT
+    resiBuf.colorSpaceConvert(orgResiBuf, true, cs.slice->clpRng(COMPONENT_Y));
+#else
     resiBuf.colorSpaceConvert(orgResiBuf, true);
+#endif
 
     // 2. luma residual optimization 
     double     dSingleCostLuma = MAX_DOUBLE;
@@ -3991,6 +4078,23 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     }
     else
     {
+#if JVET_Q0820_ACT 
+      if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)
+      {
+        nNumTransformCands = 1;
+        CHECK(!tsAllowed && !cu.bdpcmMode, "transform skip should be enabled for LS");
+        if (cu.bdpcmMode)
+        {
+          trModes.push_back(TrMode(0, true));
+        }
+        else
+        {
+          trModes.push_back(TrMode(1, true));
+        }
+      }
+      else
+      {
+#endif 
       nNumTransformCands = 1 + (tsAllowed ? 1 : 0) + (mtsAllowed ? 4 : 0); // DCT + TS + 4 MTS = 6 tests
 
       trModes.push_back(TrMode(0, true)); //DCT2
@@ -4005,6 +4109,9 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
           trModes.push_back(TrMode(i, true));
         }
       }
+#if JVET_Q0820_ACT 
+      }
+#endif
     }
 
     CodingStructure &saveLumaCS = *m_pSaveCS[0];
@@ -4029,9 +4136,16 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     bool    cbfBestModeValid = false;
     bool    cbfDCT2 = true;
 
+#if JVET_Q0820_ACT
+    if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif
     m_pcRdCost->lambdaAdjustColorTrans(true, COMPONENT_Y);
 
+#if JVET_Q0820_ACT
+    for (int modeId = firstCheckId; modeId <= ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) ? (nNumTransformCands - 1) : lastCheckId); modeId++)
+#else
     for (int modeId = firstCheckId; modeId <= lastCheckId; modeId++)
+#endif
     {
       uint8_t transformIndex = modeId;
       csFull->getResiBuf(tu.Y()).copyFrom(csFull->getOrgResiBuf(tu.Y()));
@@ -4152,7 +4266,17 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
       if ((sps.getUseLFNST() ? (modeId == lastCheckId && modeId != 0 && checkTransformSkip) : (trModes[modeId].first != 0)) && !TU::getCbfAtDepth(tu, COMPONENT_Y, currDepth))
       {
         //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
+#if JVET_Q0820_ACT
+        if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif
         singleCostTmp = MAX_DOUBLE;
+#if JVET_Q0820_ACT
+        else
+        {
+          singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, -1, TU_NO_ISP);
+          singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma, false);
+        }
+#endif
       }
       else
       {
@@ -4167,14 +4291,22 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
           }
           else
           {
+#if JVET_Q0820_ACT
+            singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma, false);
+#else
             singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma);
+#endif
           }
         }
         else
 #else
         singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, -1, TU_NO_ISP);
 #endif
+#if JVET_Q0820_ACT
+        singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma, false);
+#else
         singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma);
+#endif
       }
 
       if (singleCostTmp < dSingleCostLuma)
@@ -4206,6 +4338,9 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
       }
     }
 
+#if JVET_Q0820_ACT
+    if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif
     m_pcRdCost->lambdaAdjustColorTrans(false, COMPONENT_Y);
 
     if (sps.getUseLFNST())
@@ -4242,8 +4377,10 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     CompArea&  cbArea = tu.blocks[COMPONENT_Cb];
     CompArea&  crArea = tu.blocks[COMPONENT_Cr];
 
+#if !JVET_Q0820_ACT
     ctxStart = m_CABACEstimator->getCtx();
     m_CABACEstimator->resetBits();
+#endif
     tu.jointCbCr = 0;
 
     bool doReshaping = (slice.getPicHeader()->getLmcsEnabledFlag() && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && (slice.isIntra() || m_pcReshape->getCTUFlag()) && (cbArea.width * cbArea.height > 4));
@@ -4274,16 +4411,120 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
     for (uint32_t c = COMPONENT_Cb; c < ::getNumberValidTBlocks(*csFull->pcv); c++)
     {
       const ComponentID compID = ComponentID(c);
+#if JVET_Q0820_ACT 
+      double  dSingleBestCostChroma = MAX_DOUBLE;
+      int     bestModeId = -1;
+#if JVET_Q0784_LFNST_COMBINATION
+      bool    tsAllowed = TU::isTSAllowed(tu, compID) && (m_pcEncCfg->getUseChromaTS()) && !cu.lfnstIdx;
+#else
+      bool    tsAllowed = TU::isTSAllowed(tu, compID) && (m_pcEncCfg->getUseChromaTS());
+#endif
+      uint8_t numTransformCands = 1 + (tsAllowed ? 1 : 0);  // DCT + TS = 2 tests
+      bool        cbfDCT2 = true;
+
+      trModes.clear();
+
+      if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)
+      {
+        numTransformCands = 1;
+        CHECK(!tsAllowed && !cu.bdpcmModeChroma, "transform skip should be enabled for LS");
+        if (cu.bdpcmModeChroma)
+        {
+          trModes.push_back(TrMode(0, true));
+        }
+        else
+        {
+          trModes.push_back(TrMode(1, true));
+        }
+      }
+      else
+      {
+        trModes.push_back(TrMode(0, true));                    // DCT
+        if (tsAllowed)
+        {
+          trModes.push_back(TrMode(1, true));                  // TS
+        }
+      }
+
+      if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+        m_pcRdCost->lambdaAdjustColorTrans(true, compID);
+
+      TempCtx ctxBegin(m_CtxCache);
+      ctxBegin = m_CABACEstimator->getCtx();
+
+      for (int modeId = 0; modeId < numTransformCands; modeId++)
+      {
+        if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+        {
+          if (modeId && !cbfDCT2)
+          {
+            continue;
+          }
+          if (!trModes[modeId].second)
+          {
+            continue;
+          }
+        }
+
+        if (modeId > 0)
+        {
+          m_CABACEstimator->getCtx() = ctxBegin;
+        }
+
+        tu.mtsIdx[compID] = trModes[modeId].first;
+#endif
       Distortion singleDistChroma = 0;
+#if JVET_Q0820_ACT
+      if (numTransformCands > 1)
+      {
+        xIntraCodingACTTUBlock(tu, compID, singleDistChroma, modeId == 0 ? &trModes : nullptr, true);
+      }
+      else
+#endif 
       xIntraCodingACTTUBlock(tu, compID, singleDistChroma);
+#if JVET_Q0820_ACT
+      if (!tu.mtsIdx[compID])
+      {
+        cbfDCT2 = TU::getCbfAtDepth(tu, compID, currDepth);
+      }
+      uint64_t fracBitChroma = xGetIntraFracBitsQTChroma(tu, compID);
+      double   dSingleCostChroma = m_pcRdCost->calcRdCost(fracBitChroma, singleDistChroma, false);
+      if (dSingleCostChroma < dSingleBestCostChroma)
+      {
+        dSingleBestCostChroma = dSingleCostChroma;
+        bestModeId = modeId;
+        if (bestModeId != (numTransformCands - 1))
+        {
+          saveChromaCS.getResiBuf(tu.blocks[compID]).copyFrom(csFull->getResiBuf(tu.blocks[compID]));
+          tmpTU->copyComponentFrom(tu, compID);
+          ctxBest = m_CABACEstimator->getCtx();
+        }
+      }
+      }
+
+      if (bestModeId != (numTransformCands - 1))
+      {
+        csFull->getResiBuf(tu.blocks[compID]).copyFrom(saveChromaCS.getResiBuf(tu.blocks[compID]));
+        tu.copyComponentFrom(*tmpTU, compID);
+        m_CABACEstimator->getCtx() = ctxBest;
+      }
+
+      if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+        m_pcRdCost->lambdaAdjustColorTrans(false, compID);
+#else
       xGetIntraFracBitsQTChroma(tu, compID);
+#endif
     }
 
     Position tuPos = tu.Y();
     tuPos.relativeTo(cu.Y());
     const UnitArea relativeUnitArea(tu.chromaFormat, Area(tuPos, tu.Y().size()));
     PelUnitBuf     invColorTransResidual = m_colorTransResiBuf.getBuf(relativeUnitArea);
+#if JVET_Q0820_ACT
+    csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false, cs.slice->clpRng(COMPONENT_Y));
+#else
     csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false);
+#endif
 
     Distortion totalDist = 0;
     for (uint32_t c = COMPONENT_Y; c < ::getNumberValidTBlocks(*csFull->pcv); c++)
@@ -4360,7 +4601,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti
       uint64_t bitsTmp = 0;
       if (distTmp < std::numeric_limits<Distortion>::max())
       {
+#if JVET_Q0820_ACT
+        csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false, csFull->slice->clpRng(COMPONENT_Y));
+#else
         csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false);
+#endif
         distTmp = 0;
         for (uint32_t c = COMPONENT_Y; c < ::getNumberValidTBlocks(*csFull->pcv); c++)
         {
@@ -4666,12 +4911,32 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
 #endif
       uint8_t nNumTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
       std::vector<TrMode> trModes;
+#if JVET_Q0820_ACT
+      if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)
+      {
+        nNumTransformCands = 1;
+        CHECK(!tsAllowed && !currTU.cu->bdpcmModeChroma, "transform skip should be enabled for LS");
+        if (currTU.cu->bdpcmModeChroma)
+        {
+          trModes.push_back(TrMode(0, true));
+        }
+        else
+        {
+          trModes.push_back(TrMode(1, true));
+        }
+      }
+      else
+      {
+#endif
       trModes.push_back(TrMode(0, true)); // DCT2
 
       if (tsAllowed)
       {
           trModes.push_back(TrMode(1, true));//TS
       }
+#if JVET_Q0820_ACT 
+      }
+#endif 
       CHECK(!currTU.Cb().valid(), "Invalid TU");
 
       const int  totalModesToTest            = crossCPredictionModesToTest * nNumTransformCands;
@@ -4739,7 +5004,17 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
 
           if (((crossCPredictionModeId == 1) && (currTU.compAlpha[compID] == 0)) || ((currTU.mtsIdx[compID] == MTS_SKIP && !currTU.cu->bdpcmModeChroma) && !TU::getCbf(currTU, compID))) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden.
           {
+#if JVET_Q0820_ACT
+            if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)
+#endif 
             singleCostTmp = MAX_DOUBLE;
+#if JVET_Q0820_ACT 
+            else
+            {
+              uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma(currTU, compID);
+              singleCostTmp = m_pcRdCost->calcRdCost(fracBitsTmp, singleDistCTmp);
+            }
+#endif 
           }
           else if( lumaUsesISP && bestCostSoFar != MAX_DOUBLE && c == COMPONENT_Cb )
           {
@@ -4809,7 +5084,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
       }
 
       // Done with one component of separate coding of Cr and Cb, just switch to the best Cb contexts if Cr coding is still to be done
+#if JVET_Q0820_ACT 
+      if ((c == COMPONENT_Cb && bestModeId < totalModesToTest) || (c == COMPONENT_Cb && m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING))
+#else
       if ( c == COMPONENT_Cb && bestModeId < totalModesToTest)
+#endif
       {
         m_CABACEstimator->getCtx() = ctxBest;
 
@@ -4823,25 +5102,90 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
       double     bestCostCbCr   = bestCostCb + bestCostCr;
       Distortion bestDistCbCr   = bestDistCb + bestDistCr;
       int        bestJointCbCr  = 0;
+#if !JVET_Q0695_CHROMA_TS_JCCR
       bool       lastIsBest     = false;
+#endif
       std::vector<int>  jointCbfMasksToTest;
       if ( cs.sps->getJointCbCrEnabledFlag() && (TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr)))
       {
         jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(currTU, orgResiCb, orgResiCr);
       }
+#if JVET_Q0695_CHROMA_TS_JCCR 
+      bool checkDCTOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cr)) ||
+                          (TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cb)) ||
+                          (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2);
+
+      bool checkTSOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cr)) ||
+                         (TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cb)) ||
+                         (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP);
+
+      if (jointCbfMasksToTest.size() && currTU.cu->bdpcmModeChroma)
+      {
+        CHECK(!checkTSOnly || checkDCTOnly, "bdpcm only allows transform skip");
+      }
+#endif
       for( int cbfMask : jointCbfMasksToTest )
       {
+#if !JVET_Q0695_CHROMA_TS_JCCR
         Distortion distTmp = 0;
+#endif
 
         currTU.jointCbCr               = (uint8_t)cbfMask;
         currTU.compAlpha[COMPONENT_Cb] = 0;
         currTU.compAlpha[COMPONENT_Cr] = 0;
+#if JVET_Q0695_CHROMA_TS_JCCR
+        ComponentID codeCompId = ((currTU.jointCbCr >> 1) ? COMPONENT_Cb : COMPONENT_Cr);
+        ComponentID otherCompId = ((codeCompId == COMPONENT_Cb) ? COMPONENT_Cr : COMPONENT_Cb);
+#if JVET_Q0784_LFNST_COMBINATION
+        bool        tsAllowed = TU::isTSAllowed(currTU, codeCompId) && (m_pcEncCfg->getUseChromaTS()) && !currTU.cu->lfnstIdx;
+#else
+        bool        tsAllowed = TU::isTSAllowed(currTU, codeCompId) && (m_pcEncCfg->getUseChromaTS());
+#endif
+        uint8_t     numTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests
+        bool        cbfDCT2 = true;
+
+        std::vector<TrMode> trModes;
+        if (checkDCTOnly || checkTSOnly)
+        {
+          numTransformCands = 1;
+        }
+
+        if (!checkTSOnly || currTU.cu->bdpcmModeChroma)
+        {
+          trModes.push_back(TrMode(0, true)); // DCT2 
+        }
+        if (tsAllowed && !checkDCTOnly)
+        {
+          trModes.push_back(TrMode(1, true));//TS
+        }
+        for (int modeId = 0; modeId < numTransformCands; modeId++)
+        {
+          if (modeId && !cbfDCT2)
+          {
+            continue;
+          }
+          if (!trModes[modeId].second)
+          {
+            continue;
+          }
+          Distortion distTmp = 0;
+          currTU.mtsIdx[codeCompId] = currTU.cu->bdpcmModeChroma ? MTS_SKIP : trModes[modeId].first;
+          currTU.mtsIdx[otherCompId] = MTS_DCT2_DCT2;
+#else
         // encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode.
         currTU.mtsIdx[COMPONENT_Cb] = currTU.mtsIdx[COMPONENT_Cr]  = MTS_DCT2_DCT2;
+#endif
         m_CABACEstimator->getCtx() = ctxStartTU;
 
         resiCb.copyFrom( orgResiCb[cbfMask] );
         resiCr.copyFrom( orgResiCr[cbfMask] );
+#if JVET_Q0695_CHROMA_TS_JCCR
+        if (numTransformCands > 1)
+        {
+          xIntraCodingTUBlock(currTU, COMPONENT_Cb, false, distTmp, 0, nullptr, modeId == 0 ? &trModes : nullptr, true);
+        }
+        else
+#endif
         xIntraCodingTUBlock( currTU, COMPONENT_Cb, false, distTmp, 0 );
 
         double costTmp = std::numeric_limits<double>::max();
@@ -4849,7 +5193,19 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
         {
           uint64_t bits  = xGetIntraFracBitsQTChroma( currTU, COMPONENT_Cb );
           costTmp = m_pcRdCost->calcRdCost( bits, distTmp );
+#if JVET_Q0695_CHROMA_TS_JCCR 
+          if (!currTU.mtsIdx[codeCompId])
+          {
+            cbfDCT2 = true;
+          }
+#endif
         }
+#if JVET_Q0695_CHROMA_TS_JCCR 
+        else if (!currTU.mtsIdx[codeCompId])
+        {
+          cbfDCT2 = false;
+        }
+#endif
 
         if( costTmp < bestCostCbCr )
         {
@@ -4858,7 +5214,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
           bestJointCbCr = currTU.jointCbCr;
 
           // store data
+#if !JVET_Q0695_CHROMA_TS_JCCR
           if( cbfMask != jointCbfMasksToTest.back() )
+#endif
           {
 #if KEEP_PRED_AND_RESI_SIGNALS
             saveCS.getOrgResiBuf(cbArea).copyFrom(cs.getOrgResiBuf(cbArea));
@@ -4879,15 +5237,22 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio
 
             ctxBest = m_CABACEstimator->getCtx();
           }
+#if !JVET_Q0695_CHROMA_TS_JCCR
           else
           {
             lastIsBest = true;
           }
+#endif
+        }
+#if JVET_Q0695_CHROMA_TS_JCCR
         }
+#endif
       }
 
       // Retrieve the best CU data (unless it was the very last one tested)
+#if !JVET_Q0695_CHROMA_TS_JCCR
       if ( !( maxModesTested == 1 && jointCbfMasksToTest.empty() ) && !lastIsBest )
+#endif
       {
 #if KEEP_PRED_AND_RESI_SIGNALS
         cs.getPredBuf   (cbArea).copyFrom(saveCS.getPredBuf   (cbArea));
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 4a1fdcc80c3cd856dbec58dbba76fd90eb0290d4..2b34e2daea798f8c82ac97500dfe0aa049363f21 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -515,6 +515,12 @@ void HLSWriter::codeAlfAps( APS* pcAPS )
   WRITE_FLAG(param.newFilterFlag[CHANNEL_TYPE_LUMA], "alf_luma_new_filter");
   WRITE_FLAG(param.newFilterFlag[CHANNEL_TYPE_CHROMA], "alf_chroma_new_filter");
 
+#if JVET_Q0795_CCALF
+  CcAlfFilterParam paramCcAlf = pcAPS->getCcAlfAPSParam();
+  WRITE_FLAG(paramCcAlf.newCcAlfFilter[COMPONENT_Cb - 1], "alf_cc_cb_filter_signal_flag");
+  WRITE_FLAG(paramCcAlf.newCcAlfFilter[COMPONENT_Cr - 1], "alf_cc_cr_filter_signal_flag");
+#endif
+
   if (param.newFilterFlag[CHANNEL_TYPE_LUMA])
   {
 #if JVET_Q0249_ALF_CHROMA_CLIPFLAG
@@ -550,6 +556,52 @@ void HLSWriter::codeAlfAps( APS* pcAPS )
       alfFilter(param, true, altIdx);
     }
   }
+#if JVET_Q0795_CCALF
+  for (int ccIdx = 0; ccIdx < 2; ccIdx++)
+  {
+    if (paramCcAlf.newCcAlfFilter[ccIdx])
+    {
+      const int filterCount = paramCcAlf.ccAlfFilterCount[ccIdx];
+      CHECK(filterCount > MAX_NUM_CC_ALF_FILTERS, "CC ALF Filter count is too large");
+      CHECK(filterCount == 0, "CC ALF Filter count is too small");
+
+      if (MAX_NUM_CC_ALF_FILTERS > 1)
+      {
+        WRITE_UVLC(filterCount - 1,
+                   ccIdx == 0 ? "alf_cc_cb_filters_signalled_minus1" : "alf_cc_cr_filters_signalled_minus1");
+      }
+
+      for (int filterIdx = 0; filterIdx < filterCount; filterIdx++)
+      {
+        AlfFilterShape alfShape(size_CC_ALF);
+
+        const short *coeff = paramCcAlf.ccAlfCoeff[ccIdx][filterIdx];
+        // Filter coefficients
+        for (int i = 0; i < alfShape.numCoeff - 1; i++)
+        {
+          if (coeff[i] == 0)
+          {
+            WRITE_CODE(0, CCALF_BITS_PER_COEFF_LEVEL,
+                       ccIdx == 0 ? "alf_cc_cb_mapped_coeff_abs" : "alf_cc_cr_mapped_coeff_abs");
+          }
+          else
+          {
+            WRITE_CODE(1 + floorLog2(abs(coeff[i])), CCALF_BITS_PER_COEFF_LEVEL,
+                       ccIdx == 0 ? "alf_cc_cb_mapped_coeff_abs" : "alf_cc_cr_mapped_coeff_abs");
+            WRITE_FLAG(coeff[i] < 0 ? 1 : 0, ccIdx == 0 ? "alf_cc_cb_coeff_sign" : "alf_cc_cr_coeff_sign");
+          }
+        }
+
+        DTRACE(g_trace_ctx, D_SYNTAX, "%s coeff filterIdx %d: ", ccIdx == 0 ? "Cb" : "Cr", filterIdx);
+        for (int i = 0; i < alfShape.numCoeff; i++)
+        {
+          DTRACE(g_trace_ctx, D_SYNTAX, "%d ", coeff[i]);
+        }
+        DTRACE(g_trace_ctx, D_SYNTAX, "\n");
+      }
+    }
+  }
+#endif
 }
 
 void HLSWriter::codeLmcsAps( APS* pcAPS )
@@ -809,14 +861,20 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   WRITE_UVLC(pcSPS->getLog2MinCodingBlockSize() - 2, "log2_min_luma_coding_block_size_minus2");
   WRITE_FLAG(pcSPS->getSplitConsOverrideEnabledFlag(), "partition_constraints_override_enabled_flag");
   WRITE_UVLC(floorLog2(pcSPS->getMinQTSize(I_SLICE)) - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_intra_slice_luma");
+#if !JVET_Q0481_PARTITION_CONSTRAINTS_ORDER
   WRITE_UVLC(floorLog2(pcSPS->getMinQTSize(B_SLICE)) - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_inter_slice");
   WRITE_UVLC(pcSPS->getMaxMTTHierarchyDepth(), "sps_max_mtt_hierarchy_depth_inter_slice");
+#endif
   WRITE_UVLC(pcSPS->getMaxMTTHierarchyDepthI(), "sps_max_mtt_hierarchy_depth_intra_slice_luma");
   if (pcSPS->getMaxMTTHierarchyDepthI() != 0)
   {
     WRITE_UVLC(floorLog2(pcSPS->getMaxBTSizeI()) - floorLog2(pcSPS->getMinQTSize(I_SLICE)), "sps_log2_diff_max_bt_min_qt_intra_slice_luma");
     WRITE_UVLC(floorLog2(pcSPS->getMaxTTSizeI()) - floorLog2(pcSPS->getMinQTSize(I_SLICE)), "sps_log2_diff_max_tt_min_qt_intra_slice_luma");
   }
+#if JVET_Q0481_PARTITION_CONSTRAINTS_ORDER
+  WRITE_UVLC(floorLog2(pcSPS->getMinQTSize(B_SLICE)) - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_inter_slice");
+  WRITE_UVLC(pcSPS->getMaxMTTHierarchyDepth(), "sps_max_mtt_hierarchy_depth_inter_slice");
+#endif
   if (pcSPS->getMaxMTTHierarchyDepth() != 0)
   {
     WRITE_UVLC(floorLog2(pcSPS->getMaxBTSize()) - floorLog2(pcSPS->getMinQTSize(B_SLICE)), "sps_log2_diff_max_bt_min_qt_inter_slice");
@@ -864,6 +922,12 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
 
   WRITE_FLAG( pcSPS->getSAOEnabledFlag(),                                            "sps_sao_enabled_flag");
   WRITE_FLAG( pcSPS->getALFEnabledFlag(),                                            "sps_alf_enabled_flag" );
+#if JVET_Q0795_CCALF
+  if (pcSPS->getALFEnabledFlag() && pcSPS->getChromaFormatIdc() != CHROMA_400)
+  {
+    WRITE_FLAG( pcSPS->getCCALFEnabledFlag(),                                            "sps_ccalf_enabled_flag" );
+  }
+#endif
 
   WRITE_FLAG(pcSPS->getTransformSkipEnabledFlag() ? 1 : 0, "sps_transform_skip_enabled_flag");
   if (pcSPS->getTransformSkipEnabledFlag())
@@ -943,7 +1007,14 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
   }
   if (pcSPS->getChromaFormatIdc() == CHROMA_444)
   {
+#if JVET_Q0820_ACT
+    if (pcSPS->getLog2MaxTbSize() != 6)
+    {
+      WRITE_FLAG(pcSPS->getUseColorTrans() ? 1 : 0, "sps_act_enabled_flag");
+    }
+#else
     WRITE_FLAG(pcSPS->getUseColorTrans() ? 1 : 0, "sps_act_enabled_flag");
+#endif
   }
   if (pcSPS->getChromaFormatIdc() == CHROMA_444)
   {
@@ -977,6 +1048,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
     }
   }
 #endif
+#if JVET_Q0297_MER
+  WRITE_UVLC(pcSPS->getLog2ParallelMergeLevelMinus2(), "log2_parallel_merge_level_minus2");
+#endif
 
   // KJS: reference picture sets to be replaced
 
@@ -1168,7 +1242,11 @@ void HLSWriter::codeVPS(const VPS* pcVPS)
   xWriteRbspTrailingBits();
 }
 
+#if JVET_Q0775_PH_IN_SH
+void HLSWriter::codePictureHeader( PicHeader* picHeader, bool writeRbspTrailingBits )
+#else
 void HLSWriter::codePictureHeader( PicHeader* picHeader )
+#endif
 {
   const PPS*  pps = NULL;
   const SPS*  sps = NULL;
@@ -1272,6 +1350,7 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
     }
   }
   
+#if !JVET_Q0155_COLOUR_ID
   // 4:4:4 colour plane ID
   if( sps->getSeparateColourPlaneFlag() )
   {
@@ -1281,6 +1360,7 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
   {
     picHeader->setColourPlaneId( 0 );
   }
+#endif
   
   // picture output flag
   if( pps->getOutputFlagPresentFlag() )
@@ -1374,14 +1454,20 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
     if (picHeader->getSplitConsOverrideFlag())
     {
       WRITE_UVLC(floorLog2(picHeader->getMinQTSize(I_SLICE)) - sps->getLog2MinCodingBlockSize(), "pic_log2_diff_min_qt_min_cb_intra_slice_luma");
+#if !JVET_Q0819_PH_CHANGES
       WRITE_UVLC(floorLog2(picHeader->getMinQTSize(P_SLICE)) - sps->getLog2MinCodingBlockSize(), "pic_log2_diff_min_qt_min_cb_inter_slice");
       WRITE_UVLC(picHeader->getMaxMTTHierarchyDepth(P_SLICE),  "pic_max_mtt_hierarchy_depth_inter_slice");
+#endif
       WRITE_UVLC(picHeader->getMaxMTTHierarchyDepth(I_SLICE), "pic_max_mtt_hierarchy_depth_intra_slice_luma");
       if (picHeader->getMaxMTTHierarchyDepth(I_SLICE) != 0)
       {
         WRITE_UVLC(floorLog2(picHeader->getMaxBTSize(I_SLICE)) - floorLog2(picHeader->getMinQTSize(I_SLICE)), "pic_log2_diff_max_bt_min_qt_intra_slice_luma");
         WRITE_UVLC(floorLog2(picHeader->getMaxTTSize(I_SLICE)) - floorLog2(picHeader->getMinQTSize(I_SLICE)), "pic_log2_diff_max_tt_min_qt_intra_slice_luma");
       }
+#if JVET_Q0819_PH_CHANGES
+      WRITE_UVLC(floorLog2(picHeader->getMinQTSize(P_SLICE)) - sps->getLog2MinCodingBlockSize(), "pic_log2_diff_min_qt_min_cb_inter_slice");
+      WRITE_UVLC(picHeader->getMaxMTTHierarchyDepth(P_SLICE),  "pic_max_mtt_hierarchy_depth_inter_slice");
+#endif
       if (picHeader->getMaxMTTHierarchyDepth(P_SLICE) != 0)
       {
         WRITE_UVLC(floorLog2(picHeader->getMaxBTSize(P_SLICE)) - floorLog2(picHeader->getMinQTSize(P_SLICE)), "pic_log2_diff_max_bt_min_qt_inter_slice");
@@ -1597,6 +1683,21 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
         {
           WRITE_CODE(picHeader->getAlfApsIdChroma(), 3, "pic_alf_aps_id_chroma");
         }
+#if JVET_Q0795_CCALF
+        if (sps->getCCALFEnabledFlag())
+        {
+          WRITE_FLAG(picHeader->getCcAlfEnabledFlag(COMPONENT_Cb), "ph_cc_alf_cb_enabled_flag");
+          if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cb))
+          {
+            WRITE_CODE(picHeader->getCcAlfCbApsId(), 3, "ph_cc_alf_cb_aps_id");
+          }
+          WRITE_FLAG(picHeader->getCcAlfEnabledFlag(COMPONENT_Cr), "ph_cc_alf_cr_enabled_flag");
+          if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cr))
+          {
+            WRITE_CODE(picHeader->getCcAlfCrApsId(), 3, "ph_cc_alf_cr_aps_id");
+          }
+        }
+#endif
       }
     }
     else 
@@ -1604,6 +1705,10 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
       picHeader->setAlfEnabledFlag(COMPONENT_Y,  true);
       picHeader->setAlfEnabledFlag(COMPONENT_Cb, true);
       picHeader->setAlfEnabledFlag(COMPONENT_Cr, true);
+#if JVET_Q0795_CCALF
+      picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, sps->getCCALFEnabledFlag());
+      picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, sps->getCCALFEnabledFlag());
+#endif
     }
   }
   else 
@@ -1611,6 +1716,10 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
     picHeader->setAlfEnabledFlag(COMPONENT_Y,  false);
     picHeader->setAlfEnabledFlag(COMPONENT_Cb, false);
     picHeader->setAlfEnabledFlag(COMPONENT_Cr, false);
+#if JVET_Q0795_CCALF
+    picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, false);
+    picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, false);
+#endif
   }
 
   // dependent quantization
@@ -1720,7 +1829,14 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader )
     WRITE_UVLC(0,"pic_segment_header_extension_length");
   }
   
+#if JVET_Q0775_PH_IN_SH
+  if ( writeRbspTrailingBits )
+  {
+    xWriteRbspTrailingBits();
+  }
+#else
   xWriteRbspTrailingBits();
+#endif
 }
 
 void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
@@ -1730,11 +1846,21 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
 #endif
 
   CodingStructure& cs = *pcSlice->getPic()->cs;
+#if JVET_Q0775_PH_IN_SH
+  PicHeader *picHeader = cs.picHeader;
+#else
   const PicHeader *picHeader = cs.picHeader;
+#endif
   const ChromaFormat format                = pcSlice->getSPS()->getChromaFormatIdc();
   const uint32_t         numberValidComponents = getNumberValidComponents(format);
   const bool         chromaEnabled         = isChromaEnabled(format);
-
+#if JVET_Q0775_PH_IN_SH
+  WRITE_FLAG(pcSlice->getPictureHeaderInSliceHeader() ? 1 : 0, "picture_header_in_slice_header_flag");
+  if (pcSlice->getPictureHeaderInSliceHeader())
+  {
+    codePictureHeader(picHeader, false);
+  }
+#endif
   int pocBits = pcSlice->getSPS()->getBitsForPOC();
   int pocMask = (1 << pocBits) - 1;
   WRITE_CODE(pcSlice->getPOC() & pocMask, pocBits, "slice_pic_order_cnt_lsb");
@@ -1787,7 +1913,13 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
 
     WRITE_UVLC( pcSlice->getSliceType(), "slice_type" );
 
-
+#if JVET_Q0155_COLOUR_ID
+    // 4:4:4 colour plane ID
+    if( pcSlice->getSPS()->getSeparateColourPlaneFlag() )
+    {
+      WRITE_CODE( pcSlice->getColourPlaneId(), 2, "colour_plane_id" );
+    }
+#endif
 
     if( !picHeader->getPicRplPresentFlag() && (!pcSlice->getIdrPicFlag() || pcSlice->getSPS()->getIDRRefParamListPresent()) )
     {
@@ -2030,6 +2162,26 @@ void HLSWriter::codeSliceHeader         ( Slice* pcSlice )
         {
           WRITE_CODE(pcSlice->getTileGroupApsIdChroma(), 3, "slice_alf_aps_id_chroma");
         }
+
+#if JVET_Q0795_CCALF
+        if (pcSlice->getSPS()->getCCALFEnabledFlag())
+        {
+          CcAlfFilterParam &filterParam = pcSlice->m_ccAlfFilterParam;
+          WRITE_FLAG(filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] ? 1 : 0, "slice_cc_alf_cb_enabled_flag");
+          if (filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1])
+          {
+            // write CC ALF Cb APS ID
+            WRITE_CODE(pcSlice->getTileGroupCcAlfCbApsId(), 3, "slice_cc_alf_cb_aps_id");
+          }
+          // Cr
+          WRITE_FLAG(filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] ? 1 : 0, "slice_cc_alf_cr_enabled_flag");
+          if (filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1])
+          {
+            // write CC ALF Cr APS ID
+            WRITE_CODE(pcSlice->getTileGroupCcAlfCrApsId(), 3, "slice_cc_alf_cr_aps_id");
+          }
+        }
+#endif
       }
     }
 
@@ -2088,6 +2240,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_Q0795_CCALF
+  WRITE_FLAG(cinfo->getNoCCAlfConstraintFlag() ? 1 : 0, "no_ccalf_constraint_flag");
+#endif
   WRITE_FLAG(cinfo->getNoJointCbCrConstraintFlag() ? 1 : 0, "no_joint_cbcr_constraint_flag");
   WRITE_FLAG(cinfo->getNoRefWraparoundConstraintFlag() ? 1 : 0, "no_ref_wraparound_constraint_flag");
   WRITE_FLAG(cinfo->getNoTemporalMvpConstraintFlag() ? 1 : 0, "no_temporal_mvp_constraint_flag");
diff --git a/source/Lib/EncoderLib/VLCWriter.h b/source/Lib/EncoderLib/VLCWriter.h
index 7816710363be97eb40bad3bca4f212ca57290756..5fb0ad39090298fbb7e82fa0359a5bd92718156a 100644
--- a/source/Lib/EncoderLib/VLCWriter.h
+++ b/source/Lib/EncoderLib/VLCWriter.h
@@ -129,7 +129,11 @@ public:
   void  codeScalingListAps      ( APS* pcAPS );
   void  codeVPS                 ( const VPS* pcVPS );
   void  codeDPS                 ( const DPS* dps );
+#if JVET_Q0775_PH_IN_SH
+  void  codePictureHeader       ( PicHeader* picHeader, bool writeRbspTrailingBits );
+#else
   void  codePictureHeader       ( PicHeader* picHeader );
+#endif
   void  codeSliceHeader         ( Slice* pcSlice );
   void  codeConstraintInfo      ( const ConstraintInfo* cinfo );
   void  codeProfileTierLevel    ( const ProfileTierLevel* ptl, int maxNumSubLayersMinus1 );