diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index f2934a764eded8cb3368edf624360d7f354ba51c..a6aeaf7a147bc4c7460ee4a7045aa50171f7907d 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -1028,6 +1028,13 @@ static const double CCCM_NO_SUB_WEIGHT    = 1.1;
 static const int CCCM_LOC_SHIFT           = 3;
 static const int CCCM_LOC_OFFSET          = (1 << CCCM_LOC_SHIFT);
 #endif
+#if JVET_AD0202_CCCM_MDF
+static const int CCCM_NUM_PRED_FILTER = 4;
+static const int TOTAL_NUM_CCCM_MODES = CCCM_NUM_MODES * CCCM_NUM_PRED_FILTER;
+static const int VALID_NUM_CCCM_MODES = TOTAL_NUM_CCCM_MODES - 6;
+static const int CCCM_MULTI_PRED_FILTER_NUM_PARAMS = 10;
+static const int CCCM_MULTI_PRED_FILTER_NUM_PARAMS2 = 11;
+#endif
 #endif
 
 #if JVET_AA0126_GLM
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 45e3e711b5dd452a1633db007b65f28a94d5090e..1e3c94757e62e1942e1b2bea3ebb52372b618b84 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -3254,6 +3254,23 @@ const CtxSet ContextSetCfg::CccmFlag = ContextSetCfg::addCtxSet
   { DWO, },
 #endif
 });
+
+#if JVET_AD0202_CCCM_MDF
+const CtxSet ContextSetCfg::CccmMpfFlag = ContextSetCfg::addCtxSet
+({
+  { CNU, CNU, CNU, },
+  { CNU, CNU, CNU, },
+  { CNU, CNU, CNU, },
+  { DWS, DWS, DWS, },
+  { DWS, DWS, DWS, },
+  { DWS, DWS, DWS, },
+  { DWE, DWE, DWE, },
+  { DWE, DWE, DWE, },
+  { DWE, DWE, DWE, },
+  { DWO, DWO, DWO, },
+  { DWO, DWO, DWO, },
+});
+#endif
 #endif
 
 #if JVET_AC0119_LM_CHROMA_FUSION
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index 5729dc52c25a308d2f8112cdc1ced728cdedf461..f21ab30db9395dc13a07b69d1a05205c8919dd80 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -546,6 +546,9 @@ public:
 #if JVET_AA0057_CCCM
   static const CtxSet   CccmFlag;
 #endif
+#if JVET_AD0202_CCCM_MDF
+  static const CtxSet   CccmMpfFlag;
+#endif
 #if JVET_AB0157_TMRL
   static const CtxSet   TmrlDerive;
 #endif
diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index a9c5681c65fab2f338814f28173031011df7bdcb..8c27698ea59465039ed655c7c000c901869ca79f 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -130,8 +130,15 @@ IntraPrediction::IntraPrediction()
 #endif
 #if JVET_AA0057_CCCM
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+  for (int i = 0; i < (CCCM_NUM_PRED_FILTER + 1); i++)
+  {
+    m_cccmLumaBuf[i] = nullptr;
+  }
+#else
   m_cccmLumaBuf[0] = nullptr;
   m_cccmLumaBuf[1] = nullptr;
+#endif
 #else
   m_cccmLumaBuf = nullptr;
 #endif
@@ -229,11 +236,19 @@ void IntraPrediction::destroy()
 
 #if JVET_AA0057_CCCM
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+  for (int i = 0; i < (CCCM_NUM_PRED_FILTER + 1); i++)
+  {
+    delete[] m_cccmLumaBuf[i];
+    m_cccmLumaBuf[i] = nullptr;
+  }
+#else
   delete[] m_cccmLumaBuf[0];
   m_cccmLumaBuf[0] = nullptr;
 
   delete[] m_cccmLumaBuf[1];
   m_cccmLumaBuf[1] = nullptr;
+#endif
 #else
   delete[] m_cccmLumaBuf;
   m_cccmLumaBuf = nullptr;
@@ -406,6 +421,23 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth
 
 #if JVET_AA0057_CCCM
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+  if (m_cccmLumaBuf[0] == nullptr)
+  {
+    const int chromaScaleX = getChannelTypeScaleX(CHANNEL_TYPE_CHROMA, chromaFormatIDC);
+    const int chromaScaleY = getChannelTypeScaleY(CHANNEL_TYPE_CHROMA, chromaFormatIDC);
+
+    m_cccmLumaBuf[0] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY)) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY))];
+  }
+
+  for (int i = 1; i < (CCCM_NUM_PRED_FILTER + 1); i++)
+  {
+    if (m_cccmLumaBuf[i] == nullptr)
+    {
+      m_cccmLumaBuf[i] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING)];
+    }
+  }
+#else
   if( m_cccmLumaBuf[0] == nullptr )
   {
     m_cccmLumaBuf[0] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + 2 * CCCM_FILTER_PADDING)];
@@ -418,6 +450,7 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth
 
     m_cccmLumaBuf[1] = new Pel[(2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY)) * (2 * MAX_CU_SIZE + CCCM_WINDOW_SIZE + (CCCM_FILTER_PADDING << chromaScaleX) + (CCCM_FILTER_PADDING << chromaScaleY))];
   }
+#endif
 #else
   if (m_cccmLumaBuf == nullptr)
   {
@@ -8281,7 +8314,11 @@ void IntraPrediction::xGetLumaRecPixelsGlmAll(const PredictionUnit &pu, CompArea
 #endif
 
 // LumaRecPixels
-void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea)
+void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea
+#if JVET_AD0202_CCCM_MDF
+  , int downsFilterIdx
+#endif
+)
 {
 #if JVET_AA0057_CCCM
   if ( pu.cccmFlag )
@@ -8293,7 +8330,11 @@ void IntraPrediction::xGetLumaRecPixels(const PredictionUnit &pu, CompArea chrom
       return;
     }
 #endif
-    xCccmCreateLumaRef(pu, chromaArea);
+    xCccmCreateLumaRef(pu, chromaArea
+#if JVET_AD0202_CCCM_MDF
+      , downsFilterIdx
+#endif
+    );
     return;
   }
 #endif
@@ -10816,7 +10857,11 @@ void IntraPrediction::xCccmSetLumaRefValue(const PredictionUnit& pu)
 #endif
 
 // Calculate a single downsampled luma reference value (copied from IntraPrediction::xGetLumaRecPixels)
-Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y) const
+Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y
+#if JVET_AD0202_CCCM_MDF
+  , int downsFilterIdx
+#endif
+) const
 {
   const Pel* piSrc = pi.buf;
   const int iRecStride = pi.stride;
@@ -10852,6 +10897,65 @@ Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi,
   }
   else
   {
+#if JVET_AD0202_CCCM_MDF
+    const int lumaPosPicX1 = 2 * x;
+    const int lumaPosPicY1 = 2 * y;
+    int lumaPosPicX0 = lumaPosPicX1 - 1; lumaPosPicX0 = lumaPosPicX0 < 0 ? 0 : lumaPosPicX0;
+    const int lumaPosPicX2 = lumaPosPicX1 + 1;
+    const int lumaPosPicY2 = lumaPosPicY1 + 1;
+    const int shift0 = iRecStride * lumaPosPicY1;
+    const int shift1 = iRecStride * lumaPosPicY2;
+
+    if (downsFilterIdx == 0)
+    {
+      int s = 4;
+
+      s += piSrc[lumaPosPicX1 + shift0] * 2;
+      s += piSrc[lumaPosPicX0 + shift0];
+      s += piSrc[lumaPosPicX2 + shift0];
+      s += piSrc[lumaPosPicX1 + shift1] * 2;
+      s += piSrc[lumaPosPicX0 + shift1];
+      s += piSrc[lumaPosPicX2 + shift1];
+      ypval = s >> 3;
+    }
+    else if (downsFilterIdx == 1)
+    {
+      int s = 0;
+
+      s += piSrc[lumaPosPicX0 + shift0];
+      s -= piSrc[lumaPosPicX2 + shift0];
+      s += piSrc[lumaPosPicX0 + shift1];
+      s -= piSrc[lumaPosPicX2 + shift1];
+
+      ypval = s < 0 ? 0 : s;
+    }
+    else if (downsFilterIdx == 2)
+    {
+      int s = 0;
+
+      s += piSrc[lumaPosPicX0 + shift0];
+      s += piSrc[lumaPosPicX1 + shift0] * 2;
+      s += piSrc[lumaPosPicX2 + shift0];
+      s -= piSrc[lumaPosPicX0 + shift1];
+      s -= piSrc[lumaPosPicX1 + shift1] * 2;
+      s -= piSrc[lumaPosPicX2 + shift1];
+
+      ypval = s < 0 ? 0 : s;
+    }
+    else
+    {
+      int s = 0;
+
+      s -= piSrc[lumaPosPicX0 + shift0];
+      s += piSrc[lumaPosPicX1 + shift0];
+      s += piSrc[lumaPosPicX2 + shift0] * 2;
+      s -= piSrc[lumaPosPicX0 + shift1] * 2;
+      s -= piSrc[lumaPosPicX1 + shift1];
+      s += piSrc[lumaPosPicX2 + shift1];
+
+      ypval = s < 0 ? 0 : s;
+    }
+#else
     int s = 4;
     int offLeft = x > 0 ? -1 : 0;
     s += piSrc[2 * x + iRecStride * y * 2] * 2;
@@ -10861,6 +10965,7 @@ Pel IntraPrediction::xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi,
     s += piSrc[2 * x + offLeft + iRecStride * (y * 2 + 1)];
     s += piSrc[2 * x + 1 + iRecStride * (y * 2 + 1)];
     ypval = s >> 3;
+#endif
   }
 
 #if JVET_AB0174_CCCM_DIV_FREE
@@ -10905,6 +11010,67 @@ void IntraPrediction::predIntraCCCM( const PredictionUnit &pu, PelBuf &predCb, P
     }
   }
   else
+#endif
+#if JVET_AD0202_CCCM_MDF
+  if (pu.cccmMultiFilterIdx == 1)
+  {
+    CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCb(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA));
+    CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> cccmModelCr(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA));
+
+#if JVET_AB0143_CCCM_TS
+    if (intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX)
+#else
+    if (PU::cccmSingleModeAvail(pu, intraDir))
+#endif
+    {
+      xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 0, 0);
+      xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb);
+      xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr);
+    }
+    else
+    {
+      // Multimode case
+      int modelThr = xCccmCalcRefAver(pu);
+
+      xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 1, modelThr);
+      xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb);
+      xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr);
+
+      xCccmCalcModels2(pu, cccmModelCb, cccmModelCr, 2, modelThr);
+      xCccmApplyModel2(pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb);
+      xCccmApplyModel2(pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr);
+    }
+  }
+  else if (pu.cccmMultiFilterIdx > 1)
+  {
+    CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCb(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA));
+    CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> cccmModelCr(pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_LUMA));
+
+#if JVET_AB0143_CCCM_TS
+    if (intraDir == LM_CHROMA_IDX || intraDir == MDLM_L_IDX || intraDir == MDLM_T_IDX)
+#else
+    if (PU::cccmSingleModeAvail(pu, intraDir))
+#endif
+    {
+      xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 0, 0);
+      xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 0, 0, predCb);
+      xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 0, 0, predCr);
+    }
+    else
+    {
+      // Multimode case
+      int modelThr = xCccmCalcRefAver(pu);
+
+      xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 1, modelThr);
+      xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 1, modelThr, predCb);
+      xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 1, modelThr, predCr);
+
+      xCccmCalcModels3(pu, cccmModelCb, cccmModelCr, 2, modelThr);
+      xCccmApplyModel3(pu, COMPONENT_Cb, cccmModelCb, 2, modelThr, predCb);
+      xCccmApplyModel3(pu, COMPONENT_Cr, cccmModelCr, 2, modelThr, predCr);
+    }
+  }
+  else
 #endif
   if ( pu.cccmFlag )
   {
@@ -11479,6 +11645,327 @@ void IntraPrediction::xCccmCreateLumaNoSubRef( const PredictionUnit& pu, CompAre
 }
 #endif
 
+#if JVET_AD0202_CCCM_MDF
+void IntraPrediction::xCccmCalcModels2(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr)
+{
+  int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY;
+
+#if JVET_AC0147_CCCM_NO_SUBSAMPLING
+  CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled");
+#endif
+
+  const CPelBuf recoCb = pu.cs->picture->getRecoBuf(COMPONENT_Cb);
+  const CPelBuf recoCr = pu.cs->picture->getRecoBuf(COMPONENT_Cr);
+
+  PelBuf        refLuma1, refLuma2, refLuma3;
+  PelBuf        refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, 0, 3, &refLuma1, &refLuma3, &refLuma2);
+
+  int sampleNum = 0;
+
+#if JVET_AB0174_CCCM_DIV_FREE
+  int chromaOffsetCb = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1);
+  int chromaOffsetCr = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1);
+
+  if (refSizeX || refSizeY)
+  {
+    int refPosX = refSizeX > 0 ? refSizeX - 1 : 0;
+    int refPosY = refSizeY > 0 ? refSizeY - 1 : 0;
+
+    chromaOffsetCb = recoCb.at(refPosPicX + refPosX, refPosPicY + refPosY);
+    chromaOffsetCr = recoCr.at(refPosPicX + refPosX, refPosPicY + refPosY);
+  }
+#endif
+
+  // Collect reference data to input matrix A and target vector Y
+  static Pel A[CCCM_MULTI_PRED_FILTER_NUM_PARAMS][CCCM_MAX_REF_SAMPLES];
+  static Pel YCb[CCCM_MAX_REF_SAMPLES];
+  static Pel YCr[CCCM_MAX_REF_SAMPLES];
+
+#if JVET_AB0143_CCCM_TS
+  int yStart = pu.cccmFlag == 2 ? refSizeY : 0;
+  int yEnd = pu.cccmFlag == 3 ? refSizeY : areaHeight;
+  int xStart = pu.cccmFlag == 3 ? refSizeX : 0;
+  int xEnd = pu.cccmFlag == 2 ? refSizeX : areaWidth;
+
+  for (int y = yStart; y < yEnd; y++)
+  {
+    for (int x = xStart; x < xEnd; x++)
+    {
+#else
+  for (int y = 0; y < areaHeight; y++)
+  {
+    for (int x = 0; x < areaWidth; x++)
+    {
+#endif
+      if (x >= refSizeX && y >= refSizeY)
+      {
+        continue;
+      }
+
+      if (modelId == 1 && refLuma.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold
+      {
+        continue;
+      }
+      if (modelId == 2 && refLuma.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold
+      {
+        continue;
+      }
+
+      // 7-tap cross
+      A[0][sampleNum] = refLuma.at(x, y);
+      A[1][sampleNum] = refLuma1.at(x, y);
+      A[2][sampleNum] = refLuma2.at(x, y);
+      A[3][sampleNum] = refLuma3.at(x, y);
+      A[4][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x, y));
+      A[5][sampleNum] = cccmModelCb.nonlinear(refLuma1.at(x, y));
+      A[6][sampleNum] = cccmModelCb.nonlinear(refLuma2.at(x, y));
+      A[7][sampleNum] = ((y + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate
+      A[8][sampleNum] = ((x + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate
+      A[9][sampleNum] = cccmModelCb.bias();
+
+      YCb[sampleNum] = recoCb.at(refPosPicX + x, refPosPicY + y);
+      YCr[sampleNum++] = recoCr.at(refPosPicX + x, refPosPicY + y);
+    }
+  }
+
+  if (!sampleNum) // Number of samples can go to zero in the multimode case
+  {
+    cccmModelCb.clearModel();
+    cccmModelCr.clearModel();
+  }
+  else
+  {
+#if JVET_AB0174_CCCM_DIV_FREE
+    m_cccmMultiDownSolver.solve2(A, YCb, YCr, sampleNum, chromaOffsetCb, chromaOffsetCr, cccmModelCb, cccmModelCr);
+#else
+    m_cccmMultiDownSolver.solve2(A, YCb, YCr, sampleNum, cccmModelCb, cccmModelCr);
+#endif
+  }
+}
+
+void IntraPrediction::xCccmApplyModel2(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const
+{
+  const  ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId));
+  static Pel     samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS];
+
+#if JVET_AC0147_CCCM_NO_SUBSAMPLING
+  CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled");
+#endif
+#if JVET_AC0054_GLCCCM
+  int refSizeX = m_cccmBlkArea.x - m_cccmRefArea.x; // Reference lines available left and above
+  int refSizeY = m_cccmBlkArea.y - m_cccmRefArea.y;
+#endif
+  CPelBuf refLumaBlk1, refLumaBlk2, refLumaBlk3;
+  CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 3, &refLumaBlk1, &refLumaBlk3, &refLumaBlk2);
+
+  for (int y = 0; y < refLumaBlk.height; y++)
+  {
+    for (int x = 0; x < refLumaBlk.width; x++)
+    {
+      if (modelId == 1 && refLumaBlk.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold
+      {
+        continue;
+      }
+      if (modelId == 2 && refLumaBlk.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold
+      {
+        continue;
+      }
+
+      // 7-tap cross
+      samples[0] = refLumaBlk.at(x, y); // C
+      samples[1] = refLumaBlk1.at(x, y); // W
+      samples[2] = refLumaBlk2.at(x, y); // E
+      samples[3] = refLumaBlk3.at(x, y);
+      samples[4] = cccmModel.nonlinear(refLumaBlk.at(x, y));
+      samples[5] = cccmModel.nonlinear(refLumaBlk1.at(x, y));
+      samples[6] = cccmModel.nonlinear(refLumaBlk2.at(x, y));
+      samples[7] = ((y + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate
+      samples[8] = ((x + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate
+      samples[9] = cccmModel.bias();
+
+      piPred.at(x, y) = ClipPel<Pel>(cccmModel.convolve(samples), clpRng);
+    }
+  }
+}
+
+void IntraPrediction::xCccmCalcModels3(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCr, int modelId, int modelThr)
+{
+  int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY;
+
+#if JVET_AC0147_CCCM_NO_SUBSAMPLING
+  CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled");
+#endif
+
+  const CPelBuf recoCb = pu.cs->picture->getRecoBuf(COMPONENT_Cb);
+  const CPelBuf recoCr = pu.cs->picture->getRecoBuf(COMPONENT_Cr);
+  PelBuf        refLuma1, refLuma3;
+  PelBuf        refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY, 0, 2, &refLuma1, &refLuma3);
+
+  int sampleNum = 0;
+
+#if JVET_AB0174_CCCM_DIV_FREE
+  int chromaOffsetCb = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1);
+  int chromaOffsetCr = 1 << (pu.cu->slice->getSPS()->getBitDepth(CHANNEL_TYPE_CHROMA) - 1);
+
+  if (refSizeX || refSizeY)
+  {
+    int refPosX = refSizeX > 0 ? refSizeX - 1 : 0;
+    int refPosY = refSizeY > 0 ? refSizeY - 1 : 0;
+
+    chromaOffsetCb = recoCb.at(refPosPicX + refPosX, refPosPicY + refPosY);
+    chromaOffsetCr = recoCr.at(refPosPicX + refPosX, refPosPicY + refPosY);
+  }
+#endif
+
+  // Collect reference data to input matrix A and target vector Y
+  static Pel A[CCCM_MULTI_PRED_FILTER_NUM_PARAMS2][CCCM_MAX_REF_SAMPLES];
+  static Pel YCb[CCCM_MAX_REF_SAMPLES];
+  static Pel YCr[CCCM_MAX_REF_SAMPLES];
+
+#if JVET_AB0143_CCCM_TS
+  int yStart = pu.cccmFlag == 2 ? refSizeY : 0;
+  int yEnd = pu.cccmFlag == 3 ? refSizeY : areaHeight;
+  int xStart = pu.cccmFlag == 3 ? refSizeX : 0;
+  int xEnd = pu.cccmFlag == 2 ? refSizeX : areaWidth;
+
+  for (int y = yStart; y < yEnd; y++)
+  {
+    for (int x = xStart; x < xEnd; x++)
+    {
+#else
+  for (int y = 0; y < areaHeight; y++)
+  {
+    for (int x = 0; x < areaWidth; x++)
+    {
+#endif
+      if (x >= refSizeX && y >= refSizeY)
+      {
+        continue;
+      }
+
+      if (modelId == 1 && refLuma.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold
+      {
+        continue;
+      }
+      if (modelId == 2 && refLuma.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold
+      {
+        continue;
+      }
+
+      // 7-tap cross
+      if (pu.cccmMultiFilterIdx == 2)
+      {
+        A[0][sampleNum] = refLuma.at(x, y); // C
+        A[1][sampleNum] = refLuma.at(x - 1, y); // W
+        A[2][sampleNum] = refLuma.at(x + 1, y); // E
+        A[3][sampleNum] = refLuma1.at(x, y); // C
+        A[4][sampleNum] = refLuma1.at(x - 1, y); // W
+        A[5][sampleNum] = refLuma1.at(x + 1, y); // E
+        A[6][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x, y));
+        A[7][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x - 1, y));
+        A[8][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x + 1, y));
+        A[9][sampleNum] = ((x + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate
+        A[10][sampleNum] = cccmModelCb.bias();
+      }
+      else
+      {
+        A[0][sampleNum] = refLuma.at(x, y); // C
+        A[1][sampleNum] = refLuma.at(x + 1, y - 1); // EN
+        A[2][sampleNum] = refLuma.at(x - 1, y + 1); // WS
+        A[3][sampleNum] = refLuma3.at(x, y); // C
+        A[4][sampleNum] = refLuma3.at(x + 1, y - 1); // EN
+        A[5][sampleNum] = refLuma3.at(x - 1, y + 1); // WS
+        A[6][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x, y));
+        A[7][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x + 1, y - 1));
+        A[8][sampleNum] = cccmModelCb.nonlinear(refLuma.at(x - 1, y + 1));
+        A[9][sampleNum] = ((y + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate
+        A[10][sampleNum] = cccmModelCb.bias();
+      }
+
+      YCb[sampleNum] = recoCb.at(refPosPicX + x, refPosPicY + y);
+      YCr[sampleNum++] = recoCr.at(refPosPicX + x, refPosPicY + y);
+    }
+  }
+
+  if (!sampleNum) // Number of samples can go to zero in the multimode case
+  {
+    cccmModelCb.clearModel();
+    cccmModelCr.clearModel();
+  }
+  else
+  {
+#if JVET_AB0174_CCCM_DIV_FREE
+    m_cccmMultiDownSolver2.solve2(A, YCb, YCr, sampleNum, chromaOffsetCb, chromaOffsetCr, cccmModelCb, cccmModelCr);
+#else
+    m_cccmMultiDownSolver.solve2(A, YCb, YCr, sampleNum, cccmModelCb, cccmModelCr);
+#endif
+  }
+}
+
+void IntraPrediction::xCccmApplyModel3(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const
+{
+  const  ClpRng& clpRng(pu.cu->cs->slice->clpRng(compId));
+  static Pel     samples[CCCM_MULTI_PRED_FILTER_NUM_PARAMS2];
+
+#if JVET_AC0147_CCCM_NO_SUBSAMPLING
+  CHECK(pu.cccmNoSubFlag, "cccmNoSubFlag shall be disabled");
+#endif
+#if JVET_AC0054_GLCCCM
+  int refSizeX = m_cccmBlkArea.x - m_cccmRefArea.x; // Reference lines available left and above
+  int refSizeY = m_cccmBlkArea.y - m_cccmRefArea.y;
+#endif
+  CPelBuf refLumaBlk1, refLumaBlk3;
+  CPelBuf refLumaBlk = xCccmGetLumaPuBuf(pu, 0, 2, &refLumaBlk1, &refLumaBlk3);
+
+  for (int y = 0; y < refLumaBlk.height; y++)
+  {
+    for (int x = 0; x < refLumaBlk.width; x++)
+    {
+      if (modelId == 1 && refLumaBlk.at(x, y) > modelThr) // Model 1: Include only samples below or equal to the threshold
+      {
+        continue;
+      }
+      if (modelId == 2 && refLumaBlk.at(x, y) <= modelThr) // Model 2: Include only samples above the threshold
+      {
+        continue;
+      }
+
+      // 7-tap cross
+      if (pu.cccmMultiFilterIdx == 2)
+      {
+        samples[0] = refLumaBlk.at(x, y); // C
+        samples[1] = refLumaBlk.at(x - 1, y); // W
+        samples[2] = refLumaBlk.at(x + 1, y); // E
+        samples[3] = refLumaBlk1.at(x, y); // C
+        samples[4] = refLumaBlk1.at(x - 1, y); // W
+        samples[5] = refLumaBlk1.at(x + 1, y); // E
+        samples[6] = cccmModel.nonlinear(refLumaBlk.at(x, y));
+        samples[7] = cccmModel.nonlinear(refLumaBlk.at(x - 1, y));
+        samples[8] = cccmModel.nonlinear(refLumaBlk.at(x + 1, y));
+        samples[9] = ((x + refSizeX + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // X coordinate
+        samples[10] = cccmModel.bias();
+      }
+      else
+      {
+        samples[0] = refLumaBlk.at(x, y); // C
+        samples[1] = refLumaBlk.at(x + 1, y - 1); // EN
+        samples[2] = refLumaBlk.at(x - 1, y + 1); // WS
+        samples[3] = refLumaBlk3.at(x, y); // C
+        samples[4] = refLumaBlk3.at(x + 1, y - 1); // EN
+        samples[5] = refLumaBlk3.at(x - 1, y + 1); // WS
+        samples[6] = cccmModel.nonlinear(refLumaBlk.at(x, y));
+        samples[7] = cccmModel.nonlinear(refLumaBlk.at(x + 1, y - 1));
+        samples[8] = cccmModel.nonlinear(refLumaBlk.at(x - 1, y + 1));
+        samples[9] = ((y + refSizeY + CCCM_LOC_OFFSET) << CCCM_LOC_SHIFT); // Y coordinate
+        samples[10] = cccmModel.bias();
+      }
+
+      piPred.at(x, y) = ClipPel<Pel>(cccmModel.convolve(samples), clpRng);
+    }
+  }
+}
+#endif
+
 // Using the same availability checking as in IntraPrediction::xFillReferenceSamples
 void IntraPrediction::xCccmCalcRefArea(const PredictionUnit& pu, CompArea chromaArea)
 {
@@ -11527,7 +12014,11 @@ void IntraPrediction::xCccmCalcRefArea(const PredictionUnit& pu, CompArea chroma
 }
 
 // Return downsampled luma buffer that contains PU and the reference areas above and left of the PU
-PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY ) const
+PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY
+#if JVET_AD0202_CCCM_MDF
+  , int cccmDownsamplesFilterIdx, int numBuffer, PelBuf* refLuma1, PelBuf* refLuma3, PelBuf* refLuma2
+#endif
+) const
 {
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
   if( pu.cccmNoSubFlag )
@@ -11544,7 +12035,11 @@ PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWi
 
     int refStride = areaWidth + 2 * (CCCM_FILTER_PADDING << chromaScaleX); // Including paddings required for the 2D filter
     int refOrigin = refStride * (CCCM_FILTER_PADDING << chromaScaleY) + (CCCM_FILTER_PADDING << chromaScaleX);
+#if JVET_AD0202_CCCM_MDF
+    return PelBuf(m_cccmLumaBuf[0] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area 
+#else
     return PelBuf( m_cccmLumaBuf[1] + refOrigin, refStride, areaWidth, areaHeight ); // Points to the top-left corner of the reference area 
+#endif
   }
 #endif
 
@@ -11559,14 +12054,38 @@ PelBuf IntraPrediction::xCccmGetLumaRefBuf(const PredictionUnit& pu, int &areaWi
   int refOrigin = refStride * CCCM_FILTER_PADDING + CCCM_FILTER_PADDING;
 
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+  if (numBuffer == 0)
+  {
+    return PelBuf(m_cccmLumaBuf[cccmDownsamplesFilterIdx + 1] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area
+}
+  else if (numBuffer == 2)
+  {
+    *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, areaWidth, areaHeight);
+    *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, areaWidth, areaHeight);
+    return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area
+  }
+  else
+  {
+    *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, areaWidth, areaHeight);
+    *refLuma2 = PelBuf(m_cccmLumaBuf[3] + refOrigin, refStride, areaWidth, areaHeight);
+    *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, areaWidth, areaHeight);
+    return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area
+  }
+#else
   return PelBuf( m_cccmLumaBuf[0] + refOrigin, refStride, areaWidth, areaHeight ); // Points to the top-left corner of the reference area
+#endif
 #else
   return PelBuf(m_cccmLumaBuf + refOrigin, refStride, areaWidth, areaHeight); // Points to the top-left corner of the reference area
 #endif
 }
 
 // Return downsampled luma buffer for a PU
-PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu) const
+PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu
+#if JVET_AD0202_CCCM_MDF
+  , int cccmDownsamplesFilterIdx, int numBuffer, CPelBuf* refLuma1, CPelBuf* refLuma3, CPelBuf* refLuma2
+#endif
+) const
 {
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
   if( pu.cccmNoSubFlag )
@@ -11581,7 +12100,11 @@ PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu) const
 
     int refStride = (m_cccmRefArea.width + 2 * CCCM_FILTER_PADDING) << chromaScaleX; // Including paddings required for the 2D filter
     int refOrigin = refStride * (refSizeY + (CCCM_FILTER_PADDING << chromaScaleY)) + refSizeX + (CCCM_FILTER_PADDING << chromaScaleX);
+#if JVET_AD0202_CCCM_MDF
+    return PelBuf(m_cccmLumaBuf[0] + refOrigin, refStride, tuWidth, tuHeight);  // Points to the top-left corner of the block
+#else
     return PelBuf( m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight );  // Points to the top-left corner of the block
+#endif
   }
 #endif
 
@@ -11593,7 +12116,27 @@ PelBuf IntraPrediction::xCccmGetLumaPuBuf(const PredictionUnit& pu) const
   int refOrigin = refStride * (refSizeY + CCCM_FILTER_PADDING) + refSizeX + CCCM_FILTER_PADDING;
 
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+  if (numBuffer == 0)
+  {
+    return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight);  // Points to the top-left corner of the block
+  }
+  else if (numBuffer == 2)
+  {
+    *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, tuWidth, tuHeight);
+    *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, tuWidth, tuHeight);
+    return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight);  // Points to the top-left corner of the block
+  }
+  else
+  {
+    *refLuma1 = PelBuf(m_cccmLumaBuf[2] + refOrigin, refStride, tuWidth, tuHeight);
+    *refLuma2 = PelBuf(m_cccmLumaBuf[3] + refOrigin, refStride, tuWidth, tuHeight);
+    *refLuma3 = PelBuf(m_cccmLumaBuf[4] + refOrigin, refStride, tuWidth, tuHeight);
+    return PelBuf(m_cccmLumaBuf[1] + refOrigin, refStride, tuWidth, tuHeight);  // Points to the top-left corner of the block
+  }
+#else
   return PelBuf( m_cccmLumaBuf[0] + refOrigin, refStride, tuWidth, tuHeight );  // Points to the top-left corner of the block
+#endif
 #else
   return PelBuf(m_cccmLumaBuf + refOrigin, refStride, tuWidth, tuHeight);  // Points to the top-left corner of the block
 #endif
@@ -11663,7 +12206,11 @@ int IntraPrediction::xCccmCalcRefAver(const PredictionUnit& pu) const
 #endif
 }
 
-void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chromaArea)
+void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chromaArea
+#if JVET_AD0202_CCCM_MDF
+  , int downsFilterIdx
+#endif
+)
 {
   const CPelBuf recoLuma = pu.cs->picture->getRecoBuf(COMPONENT_Y);
   const int  maxPosPicX  = pu.cs->picture->chromaSize().width  - 1;
@@ -11673,7 +12220,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
   
   int areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY;
 
-  PelBuf refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY);
+  PelBuf refLuma = xCccmGetLumaRefBuf(pu, areaWidth, areaHeight, refSizeX, refSizeY, refPosPicX, refPosPicY
+#if JVET_AD0202_CCCM_MDF
+    , downsFilterIdx
+#endif
+  );
   
   int puBorderX = refSizeX + m_cccmBlkArea.width;
   int puBorderY = refSizeY + m_cccmBlkArea.height;
@@ -11699,7 +12250,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
       chromaPosPicX = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX;
       chromaPosPicY = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY;
       
-      refLuma.at( x, y ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, chromaPosPicY);
+      refLuma.at( x, y ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, chromaPosPicY
+#if JVET_AD0202_CCCM_MDF
+        , downsFilterIdx
+#endif
+      );
     }
   }
 
@@ -11757,7 +12312,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
         int chromaPosPicY = refPosPicY + y;
         chromaPosPicY     = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY;
 
-        refLuma.at( areaWidth, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY);
+        refLuma.at( areaWidth, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY
+#if JVET_AD0202_CCCM_MDF
+          , downsFilterIdx
+#endif
+        );
       }
     }
 
@@ -11771,7 +12330,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
         int chromaPosPicY = refPosPicY + y;
         chromaPosPicY     = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY;
 
-        refLuma.at( puBorderX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY);
+        refLuma.at( puBorderX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY
+#if JVET_AD0202_CCCM_MDF
+          , downsFilterIdx
+#endif
+        );
       }
     }
 
@@ -11785,7 +12348,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
         int chromaPosPicY = refPosPicY + y;
         chromaPosPicY     = chromaPosPicY < 0 ? 0 : chromaPosPicY > maxPosPicY ? maxPosPicY : chromaPosPicY;
 
-        refLuma.at( refSizeX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY);
+        refLuma.at( refSizeX, y ) = xCccmGetLumaVal(pu, recoLuma, padPosPicX, chromaPosPicY
+#if JVET_AD0202_CCCM_MDF
+          , downsFilterIdx
+#endif
+        );
       }
     }
     
@@ -11799,7 +12366,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
         int chromaPosPicX = refPosPicX + x;
         chromaPosPicX     = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX;
         
-        refLuma.at( x, areaHeight ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY);
+        refLuma.at( x, areaHeight ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY
+#if JVET_AD0202_CCCM_MDF
+          , downsFilterIdx
+#endif
+        );
       }
     }
     
@@ -11813,7 +12384,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
         int chromaPosPicX = refPosPicX + x;
         chromaPosPicX     = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX;
         
-        refLuma.at( x, puBorderY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY);
+        refLuma.at( x, puBorderY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY
+#if JVET_AD0202_CCCM_MDF
+          , downsFilterIdx
+#endif
+        );
       }
     }
 
@@ -11832,7 +12407,11 @@ void IntraPrediction::xCccmCreateLumaRef(const PredictionUnit& pu, CompArea chro
         int chromaPosPicX = refPosPicX + x;
         chromaPosPicX     = chromaPosPicX < 0 ? 0 : chromaPosPicX > maxPosPicX ? maxPosPicX : chromaPosPicX;
         
-        refLuma.at( x, refSizeY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY);
+        refLuma.at( x, refSizeY ) = xCccmGetLumaVal(pu, recoLuma, chromaPosPicX, padPosPicY
+#if JVET_AD0202_CCCM_MDF
+          , downsFilterIdx
+#endif
+        );
       }
     }
   }
diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h
index fc4b8541f476834337bf0b8969145775677d0d42..5a8106f8e994257f6c04f48dd43188a18d8f38e1 100644
--- a/source/Lib/CommonLib/IntraPrediction.h
+++ b/source/Lib/CommonLib/IntraPrediction.h
@@ -216,7 +216,11 @@ private:
 #if JVET_AA0057_CCCM
   Area m_cccmRefArea;
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+  Pel* m_cccmLumaBuf[CCCM_NUM_PRED_FILTER + 1];
+#else
   Pel* m_cccmLumaBuf[2];
+#endif
 #else
   Pel* m_cccmLumaBuf;
 #endif
@@ -322,6 +326,10 @@ protected:
 
 #if JVET_AA0057_CCCM
   CccmCovariance<CCCM_NUM_PARAMS, CCCM_MAX_REF_SAMPLES> m_cccmSolver;
+#if JVET_AD0202_CCCM_MDF
+  CccmCovariance<CCCM_MULTI_PRED_FILTER_NUM_PARAMS, CCCM_MAX_REF_SAMPLES> m_cccmMultiDownSolver;
+  CccmCovariance<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2, CCCM_MAX_REF_SAMPLES> m_cccmMultiDownSolver2;
+#endif
 #endif
 #if JVET_AB0092_GLM_WITH_LUMA
   CccmCovariance<GLM_NUM_PARAMS, GLM_MAX_REF_SAMPLES> m_glmSolver;
@@ -419,7 +427,11 @@ public:
   void init                       (ChromaFormat chromaFormatIDC, const unsigned bitDepthY);
 
 #if JVET_AA0057_CCCM || JVET_AC0119_LM_CHROMA_FUSION
-  Pel    xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y) const;
+  Pel    xCccmGetLumaVal(const PredictionUnit& pu, const CPelBuf pi, const int x, const int y
+#if JVET_AD0202_CCCM_MDF
+    , int downsFilterIdx = 0
+#endif
+  ) const;
 #if JVET_AB0174_CCCM_DIV_FREE
   void   xCccmSetLumaRefValue(const PredictionUnit& pu);
 #endif
@@ -428,9 +440,21 @@ public:
   void   predIntraCCCM            (const PredictionUnit& pu, PelBuf &predCb, PelBuf &predCr, int intraDir);
   void   xCccmCalcModels          (const PredictionUnit& pu, CccmModel<CCCM_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr);
   void   xCccmApplyModel          (const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const;
-  void   xCccmCreateLumaRef       (const PredictionUnit& pu, CompArea chromaArea);
-  PelBuf xCccmGetLumaRefBuf       (const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY) const;
-  PelBuf xCccmGetLumaPuBuf        (const PredictionUnit& pu) const;
+  void   xCccmCreateLumaRef       (const PredictionUnit& pu, CompArea chromaArea
+#if JVET_AD0202_CCCM_MDF
+    , int downsFilterIdx
+#endif
+  );
+  PelBuf xCccmGetLumaRefBuf       (const PredictionUnit& pu, int &areaWidth, int &areaHeight, int &refSizeX, int &refSizeY, int &refPosPicX, int &refPosPicY
+#if JVET_AD0202_CCCM_MDF
+    , int cccmDownsamplesFilterIdx = 0, int numBuffer = 0, PelBuf* refLuma1 = NULL, PelBuf* refLuma3 = NULL, PelBuf* refLuma2 = NULL
+#endif
+  ) const;
+  PelBuf xCccmGetLumaPuBuf        (const PredictionUnit& pu
+#if JVET_AD0202_CCCM_MDF
+    , int cccmDownsamplesFilterIdx = 0, int numBuffer = 0, CPelBuf* refLuma1 = NULL, CPelBuf* refLuma3 = NULL, CPelBuf* refLuma2 = NULL
+#endif
+  ) const;
   int    xCccmCalcRefAver         (const PredictionUnit& pu) const;
   void   xCccmCalcRefArea         (const PredictionUnit& pu, CompArea chromaArea);
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
@@ -438,6 +462,12 @@ public:
   void   xCccmApplyModel          ( const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_NO_SUB_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred ) const;
   void   xCccmCalcModels          ( const PredictionUnit& pu, CccmModel<CCCM_NO_SUB_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_NO_SUB_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr );
 #endif
+#if JVET_AD0202_CCCM_MDF
+  void   xCccmCalcModels2(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModelCr, int modelId, int modelThr);
+  void   xCccmApplyModel2(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const;
+  void   xCccmCalcModels3(const PredictionUnit& pu, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCb, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModelCr, int modelId, int modelThr);
+  void   xCccmApplyModel3(const PredictionUnit& pu, const ComponentID compId, CccmModel<CCCM_MULTI_PRED_FILTER_NUM_PARAMS2> &cccmModel, int modelId, int modelThr, PelBuf &piPred) const;
+#endif
 #endif
 #if JVET_AB0092_GLM_WITH_LUMA
   void   xGlmCalcModel            (const PredictionUnit& pu, const ComponentID compId, const CompArea& chromaArea, CccmModel<GLM_NUM_PARAMS> &glmModel);
@@ -586,7 +616,11 @@ public:
 
   // Cross-component Chroma
   void predIntraChromaLM(const ComponentID compID, PelBuf &piPred, const PredictionUnit &pu, const CompArea& chromaArea, int intraDir, bool createModel = true, CclmModel *cclmModelStored = nullptr);
-  void xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea);
+  void xGetLumaRecPixels(const PredictionUnit &pu, CompArea chromaArea
+#if JVET_AD0202_CCCM_MDF
+    , int downsFilterIdx = 0
+#endif
+  );
 #if JVET_AA0126_GLM
   void xGetLumaRecPixelsGlmAll(const PredictionUnit &pu, CompArea chromaArea);
   Pel xGlmGetLumaVal    (const int s[6], const int c[6], const int glmIdx, const Pel val) const;
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 6a53b54cd4bd59cb56fd866829b89fd9936d3241..9e750f43f2ae7f065ab7e6abf7dbf2b552c64504 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -156,6 +156,7 @@
 #define JVET_AB0143_CCCM_TS                               1 // JVET-AB0143: CCCM template selection
 #define JVET_AC0147_CCCM_NO_SUBSAMPLING                   1 // JVET-AC0147: Subsampling is not applied to CCCM
 #define JVET_AC0054_GLCCCM                                1 // JVET_AC0054: Gradient and location based CCCM
+#define JVET_AD0202_CCCM_MDF                              1 // JVET_AD0202: CCCM with multiple downsampling filters
 #endif
 #define JVET_AA0126_GLM                                   1 // JVET-AA0126: Gradient linear model
 #if JVET_AA0126_GLM
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index fbeeffca3f5ddc4bdc60f0d169677b9cd7b1f87b..4b7b7319934faecd80e494383ab2c91178973306 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -816,6 +816,9 @@ void PredictionUnit::initData()
 #if JVET_AC0054_GLCCCM
   glCccmFlag = 0;
 #endif
+#if JVET_AD0202_CCCM_MDF
+  cccmMultiFilterIdx = 0;
+#endif
 #endif
   // inter data
 #if JVET_AC0185_ENHANCED_TEMPORAL_MOTION_DERIVATION
@@ -970,6 +973,9 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData)
 #if JVET_AC0054_GLCCCM
   glCccmFlag = predData.glCccmFlag;
 #endif
+#if JVET_AD0202_CCCM_MDF
+  cccmMultiFilterIdx = predData.cccmMultiFilterIdx;
+#endif
 #endif
   return *this;
 }
@@ -1124,6 +1130,9 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
 #if JVET_AC0054_GLCCCM
   glCccmFlag = other.glCccmFlag;
 #endif
+#if JVET_AD0202_CCCM_MDF
+  cccmMultiFilterIdx = other.cccmMultiFilterIdx;
+#endif
 #endif
 
   mergeFlag   = other.mergeFlag;
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 8c0524a6065a621eeda552c0e81ce2bafd1faf19..337e2ba14648523609283ce8725719c21f04d827 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -519,6 +519,9 @@ struct IntraPredictionData
 #if JVET_AC0054_GLCCCM
   int       glCccmFlag;
 #endif
+#if JVET_AD0202_CCCM_MDF
+  int       cccmMultiFilterIdx;
+#endif
 #endif
 };
 
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 840300c2281f83bdbf88e4eec5e8e1c8c91d5133..a24f4fc6da9ed5af622fb970be8e44116b5e56ba 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -2279,6 +2279,33 @@ bool PU::isTopCccmMode(const PredictionUnit& pu, int intraMode)
 
   return modeIsOk && area.x && area.y;
 }
+
+#if JVET_AD0202_CCCM_MDF
+bool PU::isMultiCccmWithMdf(const PredictionUnit& pu, int intraMode)
+{
+  const Area area = pu.blocks[COMPONENT_Cb];
+  int th, tv;
+  PU::getCccmRefLineNum(pu, area, th, tv);
+  int nsamples;
+  bool nSampleCheck;
+  if (intraMode == MMLM_CHROMA_IDX)
+  {
+    nsamples = ((area.width + th) * (area.height + tv) - (area.area()));
+    nSampleCheck = (nsamples >= 96);
+  }
+  else if (intraMode == MMLM_L_IDX)
+  {
+    nsamples = th * area.height;
+    nSampleCheck = (nsamples >= 256);
+  }
+  else
+  {
+    nsamples = tv * area.width;
+    nSampleCheck = (nsamples >= 256);
+  }
+  return nSampleCheck;
+}
+#endif
 #endif
 #endif
 
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index f4f5cb12822a7f1613ad9dc87bf4bd2cb12d4aab..1a5f04953b7868ea0b494171c66f8ebf5d7cc786 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -613,6 +613,9 @@ namespace PU
 #if JVET_AB0143_CCCM_TS
   bool isLeftCccmMode(const PredictionUnit& pu, int intraMode);
   bool isTopCccmMode(const PredictionUnit& pu, int intraMode);
+#if JVET_AD0202_CCCM_MDF
+  bool isMultiCccmWithMdf(const PredictionUnit& pu, int intraMode);
+#endif
 #endif
 #endif
 #if JVET_Z0050_DIMD_CHROMA_FUSION
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index c1514feaa2017a4af814a26eb72756dd132280c1..5eab24f9ed9a2690ea602e79b760f2aeb18e50ac 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -2526,7 +2526,41 @@ void CABACReader::cccmFlag(PredictionUnit& pu)
 #else
       pu.cccmFlag = (intraDir == MDLM_T_IDX) ? 3 : (intraDir == MDLM_L_IDX) ? 2 : 1;
 #endif
-        
+#if JVET_AD0202_CCCM_MDF
+      bool isCccmWithMdfEnabled = true;
+      if (intraDir == MMLM_CHROMA_IDX)
+      {
+        isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_CHROMA_IDX);
+      }
+      else if (intraDir == MMLM_L_IDX)
+      {
+        isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_L_IDX);
+      }
+      else if (intraDir == MMLM_T_IDX)
+      {
+        isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_T_IDX);
+      }
+
+      if (isCccmWithMdfEnabled)
+      {
+        pu.cccmMultiFilterIdx = m_BinDecoder.decodeBin(Ctx::CccmMpfFlag(0));
+        if (pu.cccmMultiFilterIdx > 0)
+        {
+          pu.cccmMultiFilterIdx += m_BinDecoder.decodeBin(Ctx::CccmMpfFlag(1));
+          if (pu.cccmMultiFilterIdx > 1)
+          {
+            pu.cccmMultiFilterIdx += m_BinDecoder.decodeBin(Ctx::CccmMpfFlag(2));
+          }
+        }
+      }
+      else
+      {
+        pu.cccmMultiFilterIdx = 0;
+      }
+
+      if (!pu.cccmMultiFilterIdx)
+      {
+#endif
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
       pu.cccmNoSubFlag = 0;
       if ( pu.cs->sps->getUseCccm() == 2 )
@@ -2545,6 +2579,9 @@ void CABACReader::cccmFlag(PredictionUnit& pu)
       {
         pu.glCccmFlag = m_BinDecoder.decodeBin( Ctx::CccmFlag( ctxId ) );
       }
+#endif
+#if JVET_AD0202_CCCM_MDF
+      }
 #endif
     }
 #endif
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 0bf108475f6f4fb77bc43d2e96f4344ed30a7552..e82b0e9e8f66c26a3b4b6c9995d1c5bf0f7acc9f 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -620,10 +620,38 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID )
     // Create both Cb and Cr predictions when here for Cb
     if( compID == COMPONENT_Cb )
     {
+#if JVET_AD0202_CCCM_MDF
+      PredictionUnit& pu = *tu.cu->firstPU;
+#else
       const PredictionUnit& pu = *tu.cu->firstPU;
+#endif
       PelBuf predCr            = cs.getPredBuf( tu.blocks[COMPONENT_Cr] );
       
+#if JVET_AD0202_CCCM_MDF
+      if (pu.cccmMultiFilterIdx == 1)
+      {
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 0);
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 1);
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 2);
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 3);
+      }
+      else if (pu.cccmMultiFilterIdx == 2)
+      {
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 0);
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 1);
+      }
+      else if (pu.cccmMultiFilterIdx == 3)
+      {
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 0);
+        m_pcIntraPred->xGetLumaRecPixels(pu, area, 3);
+      }
+      else
+      {
+        m_pcIntraPred->xGetLumaRecPixels(pu, area);
+      }
+#else
       m_pcIntraPred->xGetLumaRecPixels( pu, area );
+#endif
       m_pcIntraPred->predIntraCCCM( pu, piPred, predCr, uiChFinalMode );
     }
   }
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index ea6a716bd682fc0375ffd90bf6f550aa10c86814..80a8e4c8408331a639d4e921f5d9ed02bb516a3f 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -2257,6 +2257,40 @@ void CABACWriter::cccmFlag(const PredictionUnit& pu)
 #endif
   {
     m_BinEncoder.encodeBin( pu.cccmFlag ? 1 : 0, Ctx::CccmFlag( 0 ) );
+#if JVET_AD0202_CCCM_MDF
+    if (pu.cccmFlag)
+    {
+      bool isCccmWithMdfEnabled = true;
+      if (intraDir == MMLM_CHROMA_IDX)
+      {
+        isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_CHROMA_IDX);
+      }
+      else if (intraDir == MMLM_L_IDX)
+      {
+        isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_L_IDX);
+      }
+      else if (intraDir == MMLM_T_IDX)
+      {
+        isCccmWithMdfEnabled = PU::isMultiCccmWithMdf(pu, MMLM_T_IDX);
+      }
+
+      if (isCccmWithMdfEnabled)
+      {
+        m_BinEncoder.encodeBin(pu.cccmMultiFilterIdx > 0 ? 1 : 0, Ctx::CccmMpfFlag(0));
+        if (pu.cccmMultiFilterIdx > 0)
+        {
+          m_BinEncoder.encodeBin(pu.cccmMultiFilterIdx > 1 ? 1 : 0, Ctx::CccmMpfFlag(1));
+          if (pu.cccmMultiFilterIdx > 1)
+          {
+            m_BinEncoder.encodeBin(pu.cccmMultiFilterIdx > 2 ? 1 : 0, Ctx::CccmMpfFlag(2));
+          }
+        }
+      }
+    }
+
+    if (!pu.cccmMultiFilterIdx)
+    {
+#endif
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
     if ( pu.cccmFlag && ( pu.cs->sps->getUseCccm() == 2 ) )
     {
@@ -2274,6 +2308,9 @@ void CABACWriter::cccmFlag(const PredictionUnit& pu)
     {
       m_BinEncoder.encodeBin( pu.glCccmFlag ? 1 : 0, Ctx::CccmFlag( ctxId ) );
     }
+#endif
+#if JVET_AD0202_CCCM_MDF
+    }
 #endif
   }
 }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 97819cdd4201e69c57382655ddd7e8696d9b09ff..4bf6f9e6f211bd9ff4358c40eeec92a2aa673d9b 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -2466,6 +2466,9 @@ bool EncCu::xCheckRDCostIntra(CodingStructure *&tempCS, CodingStructure *&bestCS
 #endif
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
   m_pcIntraSearch->m_skipCCCMSATD = false;
+#endif
+#if JVET_AD0202_CCCM_MDF
+  m_pcIntraSearch->m_skipCCCMwithMdfSATD = false;
 #endif
   for( int trGrpIdx = 0; trGrpIdx < grpNumMax; trGrpIdx++ )
   {
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index 6e06a23afa0cf52b9d17c66baed780c9a387e361..fba1a8f1ca7f6c25a176c4954dc01d5941894c84 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -195,7 +195,11 @@ void IntraSearch::destroy()
 #endif
 
 #if JVET_AB0143_CCCM_TS
+#if JVET_AD0202_CCCM_MDF
+  for (uint32_t cccmIdx = 0; cccmIdx < TOTAL_NUM_CCCM_MODES; cccmIdx++)
+#else
   for (uint32_t cccmIdx = 0; cccmIdx < CCCM_NUM_MODES; cccmIdx++)
+#endif
   {
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
     m_cccmStorage[0][cccmIdx].destroy();
@@ -314,7 +318,11 @@ void IntraSearch::init( EncCfg*        pcEncCfg,
 #endif
 
 #if JVET_AB0143_CCCM_TS
+#if JVET_AD0202_CCCM_MDF
+  for (uint32_t cccmIdx = 0; cccmIdx < TOTAL_NUM_CCCM_MODES; cccmIdx++)
+#else
   for (uint32_t cccmIdx = 0; cccmIdx < CCCM_NUM_MODES; cccmIdx++)
+#endif
   {
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
     m_cccmStorage[0][cccmIdx].create(UnitArea(cform, Area(0, 0, MAX_CU_SIZE, MAX_CU_SIZE)));
@@ -2608,6 +2616,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 #if JVET_AC0054_GLCCCM
     int      glCccmBest = 0;
 #endif
+#if JVET_AD0202_CCCM_MDF
+    int      cccmMultiFilterIdxBest = 0;
+#endif
 #endif
 #if JVET_Z0050_CCLM_SLOPE
     CclmOffsets bestCclmOffsets = {};
@@ -2981,11 +2992,38 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 #endif
 #endif
 
+#if JVET_AD0202_CCCM_MDF   
+      int satdCccmFilterIndex[TOTAL_NUM_CCCM_MODES];
+#if JVET_AC0054_GLCCCM
+      int satdCccmFlagList[TOTAL_NUM_CCCM_MODES];
+#endif
+#else
 #if JVET_AC0054_GLCCCM
       int satdCccmFlagList[CCCM_NUM_MODES];
 #endif
+#endif
         
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF  
+      int64_t satdCccmSortedCost[2][TOTAL_NUM_CCCM_MODES];
+      int satdCccmModeList[2][TOTAL_NUM_CCCM_MODES];
+      for (int i = 0; i < CCCM_NUM_PRED_FILTER; i++)
+      {
+        int startIdx = i * CCCM_NUM_MODES;
+        for (int j = 0; j < CCCM_NUM_MODES; j++)
+        {
+          int currCccmModeIdx = startIdx + j;
+          satdCccmSortedCost[0][currCccmModeIdx] = LLONG_MAX; // for the mode not pre-select by SATD, do RDO by default, so set the initial value 0.
+          satdCccmSortedCost[1][currCccmModeIdx] = LLONG_MAX; // for the mode not pre-select by SATD, do RDO by default, so set the initial value 0.
+          satdCccmModeList[0][currCccmModeIdx] = chromaCandCccmModes[j];
+          satdCccmModeList[1][currCccmModeIdx] = chromaCandCccmModes[j];
+#if JVET_AC0054_GLCCCM
+          satdCccmFlagList[currCccmModeIdx] = j < (CCCM_NUM_MODES / 2) ? 1 : 2; // 1: cccm, 2: glCccm
+#endif
+          satdCccmFilterIndex[currCccmModeIdx] = i;
+        }
+      }
+#else
       int64_t satdCccmSortedCost[2][CCCM_NUM_MODES];
       int satdCccmModeList[2][CCCM_NUM_MODES];
 
@@ -2999,6 +3037,7 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
         satdCccmFlagList[i] = i < (CCCM_NUM_MODES / 2) ? 1 : 2; // 1: cccm, 2: glCccm
 #endif
       }
+#endif
       int64_t bestCccmCost[2] = { LLONG_MAX, LLONG_MAX};
 
       bool isCccmFullEnabled = PU::cccmSingleModeAvail(pu, LM_CHROMA_IDX);
@@ -3009,17 +3048,38 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
       bool isMultiCccmLeftEnabled = PU::cccmMultiModeAvail(pu, MMLM_L_IDX);
       bool isMultiCccmTopEnabled = PU::cccmMultiModeAvail(pu, MMLM_T_IDX);
 #endif
+#if JVET_AD0202_CCCM_MDF
+      bool isMultiCccmFullEnabled2 = PU::isMultiCccmWithMdf(pu, MMLM_CHROMA_IDX);
+      bool isMultiCccmLeftEnabled2 = PU::isMultiCccmWithMdf(pu, MMLM_L_IDX);
+      bool isMultiCccmTopEnabled2 = PU::isMultiCccmWithMdf(pu, MMLM_T_IDX);
+#endif
 
       const UnitArea localUnitArea(cs.area.chromaFormat, Area(0, 0, (pu.Cb().width) << 1, (pu.Cb().height) << 1));
+#if JVET_AD0202_CCCM_MDF
+      PelUnitBuf cccmStorage[2][TOTAL_NUM_CCCM_MODES];
+#else
       PelUnitBuf cccmStorage[2][CCCM_NUM_MODES];
+#endif
 
       pu.cccmFlag = 1;
 
+#if JVET_AD0202_CCCM_MDF
+      pu.cccmNoSubFlag = 1;
+      xGetLumaRecPixels(pu, pu.Cb());
+      pu.cccmNoSubFlag = 0;
+      xGetLumaRecPixels(pu, pu.Cb());
+      xGetLumaRecPixels(pu, pu.Cb(), 1);
+      xGetLumaRecPixels(pu, pu.Cb(), 2);
+      xGetLumaRecPixels(pu, pu.Cb(), 3);
+#endif
+
       for (int sub = 0; sub < pu.cu->slice->getSPS()->getUseCccm(); sub++)
       {
         pu.cccmNoSubFlag = sub;
 
+#if !JVET_AD0202_CCCM_MDF
         xGetLumaRecPixels(pu, pu.Cb());
+#endif
 
         bool isCCCMEnabled = false;
 
@@ -3090,11 +3150,68 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
             pu.cccmFlag =   idx == 3 ? 1
             : idx == 4 ? 2 : 3;
 #endif
+
+#if JVET_AD0202_CCCM_MDF
+            if (isCCCMEnabled)
+            {
+              if (m_skipCCCMwithMdfSATD)
+              {
+                if (m_isCccmWithMdfEnabledInRdo[4][mode] == 0)
+                {
+                  continue;
+                }
+              }
+            }
+#endif
          }
 #endif
 
           if (isCCCMEnabled)
           {
+#if JVET_AD0202_CCCM_MDF
+            for (int32_t filterIdx = 0; filterIdx < CCCM_NUM_PRED_FILTER; filterIdx++)
+            {
+            if (filterIdx > 0)
+            {
+              if (sub == 1 || idx > 5)
+              {
+                continue;
+              }
+
+              if (m_skipCCCMwithMdfSATD)
+              {
+                if (m_isCccmWithMdfEnabledInRdo[filterIdx][mode] == 0)
+                {
+                  continue;
+                }
+              }
+
+              if (mode == MMLM_CHROMA_IDX && !isMultiCccmFullEnabled2)
+              {
+                continue;
+              }
+              else if (mode == MMLM_L_IDX && !isMultiCccmLeftEnabled2)
+              {
+                continue;
+              }
+              else if (mode == MMLM_T_IDX && !isMultiCccmTopEnabled2)
+              {
+                continue;
+              }
+            }
+            else if (sub == 0 && idx <= 5)
+            {
+              if (m_skipCCCMwithMdfSATD)
+              {
+                if (m_isCccmWithMdfEnabledInRdo[filterIdx][mode] == 0)
+                {
+                  continue;
+                }
+              }
+            }
+
+            pu.cccmMultiFilterIdx = filterIdx;
+#endif
             pu.intraDir[1] = mode; // temporary assigned, for SATD checking.
 
             if ( ( sub == 1 ) && m_skipCCCMSATD )
@@ -3117,24 +3234,42 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
             DistParam distParamSadCr;
             DistParam distParamSatdCr;
 
+#if JVET_AD0202_CCCM_MDF
+            const int cccmBufferIdx = filterIdx * CCCM_NUM_MODES + idx;
+            cccmStorage[sub][cccmBufferIdx] = m_cccmStorage[sub][cccmBufferIdx].getBuf(localUnitArea);
+#else
             cccmStorage[sub][idx] = m_cccmStorage[sub][idx].getBuf(localUnitArea);
+#endif
 
             CompArea areaCb = pu.Cb();
             PelBuf orgCb = cs.getOrgBuf(areaCb);
             CompArea areaCr = pu.Cr();
             PelBuf orgCr = cs.getOrgBuf(areaCr);
 
+#if JVET_AD0202_CCCM_MDF
+            m_pcRdCost->setDistParam(distParamSadCb, orgCb, cccmStorage[sub][cccmBufferIdx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false);
+            m_pcRdCost->setDistParam(distParamSatdCb, orgCb, cccmStorage[sub][cccmBufferIdx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true);
+#else
             m_pcRdCost->setDistParam(distParamSadCb, orgCb, cccmStorage[sub][idx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, false);
             m_pcRdCost->setDistParam(distParamSatdCb, orgCb, cccmStorage[sub][idx].Cb(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cb, true);
+#endif
             distParamSadCb.applyWeight = false;
             distParamSatdCb.applyWeight = false;
+#if JVET_AD0202_CCCM_MDF
+            m_pcRdCost->setDistParam(distParamSadCr, orgCr, cccmStorage[sub][cccmBufferIdx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false);
+            m_pcRdCost->setDistParam(distParamSatdCr, orgCr, cccmStorage[sub][cccmBufferIdx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true);
+#else
             m_pcRdCost->setDistParam(distParamSadCr, orgCr, cccmStorage[sub][idx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, false);
             m_pcRdCost->setDistParam(distParamSatdCr, orgCr, cccmStorage[sub][idx].Cr(), pu.cs->sps->getBitDepth(CHANNEL_TYPE_CHROMA), COMPONENT_Cr, true);
-
+#endif
             distParamSadCr.applyWeight = false;
             distParamSatdCr.applyWeight = false;
 
+#if JVET_AD0202_CCCM_MDF
+            predIntraCCCM(pu, cccmStorage[sub][cccmBufferIdx].Cb(), cccmStorage[sub][cccmBufferIdx].Cr(), mode);
+#else
             predIntraCCCM(pu, cccmStorage[sub][idx].Cb(), cccmStorage[sub][idx].Cr(), mode);
+#endif
 
             sadCb = distParamSadCb.distFunc(distParamSadCb) * 2;
             satdCb = distParamSatdCb.distFunc(distParamSatdCb);
@@ -3143,12 +3278,19 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
             satdCr = distParamSatdCr.distFunc(distParamSatdCr);
             sad += std::min(sadCr, satdCr);
 
+#if JVET_AD0202_CCCM_MDF
+            satdCccmSortedCost[sub][cccmBufferIdx] = sad;
+#else
             satdCccmSortedCost[sub][idx] = sad;
+#endif
 
             if (sad < bestCccmCost[sub])
             {
               bestCccmCost[sub] = sad;
             }
+#if JVET_AD0202_CCCM_MDF
+            }
+#endif
           }
         }
       }
@@ -3158,7 +3300,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
       int tempCccmIdx = 0;
       int64_t tempCccmCost = 0;
 #if JVET_AC0054_GLCCCM
+#if JVET_AD0202_CCCM_MDF 
+      for (int i = 1; i < 7; i++)
+#else
       for (int i = 1; i < CCCM_NUM_MODES; i++)
+#endif
 #else
 #if MMLM
       for (int i = 1; i < 4; i++)
@@ -3167,7 +3313,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 #endif
 #endif
       {
+#if JVET_AD0202_CCCM_MDF
+        for (int j = i + 1; j < VALID_NUM_CCCM_MODES; j++)
+#else
         for (int j = i + 1; j < CCCM_NUM_MODES; j++)
+#endif
         {
           if (satdCccmSortedCost[0][j] < satdCccmSortedCost[0][i])
           {
@@ -3182,6 +3332,11 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
             tempGlCccmFlag = satdCccmFlagList[i];
             satdCccmFlagList[i] = satdCccmFlagList[j];
             satdCccmFlagList[j] = tempGlCccmFlag;
+#endif
+#if JVET_AD0202_CCCM_MDF 
+            tempCccmIdx = satdCccmFilterIndex[i];
+            satdCccmFilterIndex[i] = satdCccmFilterIndex[j];
+            satdCccmFilterIndex[j] = tempCccmIdx;
 #endif
           }
         }
@@ -3189,16 +3344,26 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 
 #if MMLM
       bool isCccmModeEnabledInRdo[2][MMLM_T_IDX + 1] = { false };
+#if !JVET_AD0202_CCCM_MDF
       isCccmModeEnabledInRdo[0][satdCccmModeList[0][0]] = true;
+#endif
 #if JVET_AC0054_GLCCCM
       bool isGlCccmModeEnabledInRdo[MMLM_T_IDX + 1] = { false };
+#if !JVET_AD0202_CCCM_MDF
       if (satdCccmFlagList[0] == 2)
       {
         isCccmModeEnabledInRdo[0][satdCccmModeList[0][0]] = false;
         isGlCccmModeEnabledInRdo[satdCccmModeList[0][0]] = true;
       }
 #endif
+#endif
+#if JVET_AD0202_CCCM_MDF 
+      bool isCccmWithMulDownSamplingEnabledInRdo[MMLM_T_IDX + 1][CCCM_NUM_PRED_FILTER] = { false };
+      isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][0]][satdCccmFilterIndex[0]] = true;
+      for (int i = 1; i < 7; i++)
+#else
       for (int i = 1; i < 4; i++)
+#endif
 #else
       bool isCccmModeEnabledInRdo[MDLM_T_IDX + 1] = { false };
       isCccmModeEnabledInRdo[satdCccmModeList[0]] = true;
@@ -3224,27 +3389,57 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
         }
         else
         {
+#if JVET_AD0202_CCCM_MDF 
+          isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] = true;
+#else
           isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = true;
+#endif
         }
 #else
         isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = true;
 #endif
       }
+#if JVET_AD0202_CCCM_MDF
+      if (m_skipCCCMwithMdfSATD == false)
+      {
+        m_skipCCCMwithMdfSATD = true;
+        for (int i = LM_CHROMA_IDX; i <= MMLM_T_IDX; i++)
+        {
+          m_isCccmWithMdfEnabledInRdo[4][i] = isGlCccmModeEnabledInRdo[i] ? 1 : 0;
+
+          for (int j = 0; j < 4; j++)
+          {
+            m_isCccmWithMdfEnabledInRdo[j][i] = isCccmWithMulDownSamplingEnabledInRdo[i][j] ? 1 : 0;
+          }
+        }
+      }
+#endif
 
       if (pu.cu->slice->getSPS()->getUseCccm() == 2)
       {
         if (bestCccmCost[1] < bestCccmCost[0])
         {
 #if MMLM
+#if JVET_AD0202_CCCM_MDF
+          for (int i = 1; i < 7; i++)
+#else
           for (int i = 0; i < 4; i++)
+#endif
 #else
           for (int i = 0; i < 3; i++)
 #endif
           {
+#if JVET_AD0202_CCCM_MDF
+            if (isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] && (satdCccmSortedCost[0][i] >= 1.2 * bestCccmCost[1]))
+            {
+              isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] = false;
+            }
+#else
             if (isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] && (satdCccmSortedCost[0][i] >= 1.2 * bestCccmCost[1]))
             {
               isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = false;
             }
+#endif
             else
             {
               bestCccmCost[0] = satdCccmSortedCost[0][i];
@@ -3280,6 +3475,7 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
         {
           if (satdCccmSortedCost[1][i] >= CCCM_NO_SUB_WEIGHT * bestCccmCost[1])
           {
+#if !JVET_AD0202_CCCM_MDF
 #if JVET_AC0054_GLCCCM
             if (satdCccmSortedCost[1][i - 1] > bestCccmCost[0] && satdCccmFlagList[0] != 2)
 #else
@@ -3289,10 +3485,16 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
               bestCccmCost[0] = satdCccmSortedCost[1][i - 1];
             }
             bestCccmCost[1] = satdCccmSortedCost[1][i - 1];
+#endif
             break;
           }
           isCccmModeEnabledInRdo[1][satdCccmModeList[1][i]] = true;
         }
+#if JVET_AD0202_CCCM_MDF
+        bestCccmCost[1] = (isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]] && satdCccmSortedCost[1][0] < satdCccmSortedCost[1][1]) ? satdCccmSortedCost[1][1] : satdCccmSortedCost[1][0];
+        bestCccmCost[0] = (bestCccmCost[1] > bestCccmCost[0]) ? bestCccmCost[1] : bestCccmCost[0];
+        bestCccmCost[0] = (satdCccmSortedCost[0][0] > bestCccmCost[0]) ? satdCccmSortedCost[0][0] : bestCccmCost[0];
+#endif
         if (m_skipCCCMSATD == false)
         {
           m_skipCCCMSATD = true;
@@ -3307,6 +3509,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 #if JVET_AC0054_GLCCCM
       pu.glCccmFlag = 0;
 #endif
+#if JVET_AD0202_CCCM_MDF 
+      pu.cccmMultiFilterIdx = 0;
+#endif
 #else
       int64_t satdCccmSortedCost[CCCM_NUM_MODES];
       int satdCccmModeList[CCCM_NUM_MODES];
@@ -3501,31 +3706,59 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
       if (pu.cu->slice->getSPS()->getUseCccm() == 2)
       {
 #if JVET_AC0054_GLCCCM
+#if JVET_AD0202_CCCM_MDF
+        int32_t lastModeIdx = uiMaxMode - 1 - reducedModeNumber; ;
+        if (satdSortedCost[lastModeIdx] > bestCccmCost[0])
+#else
         if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] > bestCccmCost[0] && satdCccmFlagList[uiMaxMode - 1 - reducedModeNumber] != 2)
+#endif
 #else
         if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] > bestCccmCost[0])
 #endif
+#if JVET_AD0202_CCCM_MDF
+        {
+          modeIsEnable[satdModeList[lastModeIdx]] = 0; // disable the last reducedModeNumber modes
+        }
+        else if (satdSortedCost[lastModeIdx] < bestCccmCost[0])
+        {
+          for (int i = 6; i > 0; i--)
+#else
         {
           modeIsEnable[satdModeList[uiMaxMode - 1 - reducedModeNumber]] = 0; // disable the last reducedModeNumber modes
         }
         else if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] < bestCccmCost[0])
         {
           for (int i = 3; i > 0; i--)
+#endif
           {
 #if JVET_AC0054_GLCCCM
+#if JVET_AD0202_CCCM_MDF
+            if ((satdCccmSortedCost[0][i] > satdSortedCost[lastModeIdx]) && isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]])
+#else
             if ((satdCccmSortedCost[0][i] > satdSortedCost[uiMaxMode - 1 - reducedModeNumber]) && (isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]]) && satdCccmFlagList[uiMaxMode - 1 - reducedModeNumber] != 2)
+#endif
 #else
             if ((satdCccmSortedCost[0][i] > satdSortedCost[uiMaxMode - 1 - reducedModeNumber]) && (isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]]))
 #endif
             {
+#if JVET_AD0202_CCCM_MDF
+              isCccmWithMulDownSamplingEnabledInRdo[satdCccmModeList[0][i]][satdCccmFilterIndex[i]] = false;
+#else
               isCccmModeEnabledInRdo[0][satdCccmModeList[0][i]] = false;
+#endif
               break;
             }
           }
         }
+#if JVET_AD0202_CCCM_MDF
+        if (satdSortedCost[lastModeIdx] < bestCccmCost[1])
+        {
+          if ((satdCccmSortedCost[1][1] > satdSortedCost[lastModeIdx]) && (isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]]))
+#else
         if (satdSortedCost[uiMaxMode - 1 - reducedModeNumber] < bestCccmCost[1])
         {
           if ((satdCccmSortedCost[1][1] > satdSortedCost[uiMaxMode - 1 - reducedModeNumber]) && (isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]]))
+#endif
           {
             isCccmModeEnabledInRdo[1][satdCccmModeList[1][1]] = false;
           }
@@ -4133,10 +4366,12 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
             continue;
           }
         }
+#if !JVET_AD0202_CCCM_MDF 
         else
         {
+#endif
 #endif // JVET_AC0054_GLCCCM
-        
+#if !JVET_AD0202_CCCM_MDF 
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
           if (!isCccmModeEnabledInRdo[0][chromaIntraModeInCCCM] && !isCccmModeEnabledInRdo[1][chromaIntraModeInCCCM])
 #else
@@ -4147,6 +4382,7 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
           }
 #if JVET_AC0054_GLCCCM
         }
+#endif
 #endif
             
         if (isCCCMEnabled)
@@ -4170,13 +4406,33 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
           for (int sub = 0; sub < pu.cu->slice->getSPS()->getUseCccm(); sub++)
           {
+#if JVET_AD0202_CCCM_MDF
+            for (int32_t filterIdx = 0; filterIdx < CCCM_NUM_PRED_FILTER; filterIdx++)
+            {
+              if (filterIdx > 0 && (sub == 1 || uiMode > 5))
+              {
+                continue;
+              }
+              pu.cccmMultiFilterIdx = filterIdx;
+#endif
               pu.cccmNoSubFlag = sub;
 #if JVET_AC0054_GLCCCM
               if (sub && ((uiMode >= CCCM_NUM_MODES / 2) || pu.glCccmFlag))
               {
                 continue;
               }
+#if JVET_AD0202_CCCM_MDF
+              else if (sub == 0 && uiMode < 6)
+              {
+                if (!isCccmWithMulDownSamplingEnabledInRdo[chromaIntraModeInCCCM][filterIdx])
+                {
+                  continue;
+                }
+              }
+              else if (sub)
+#else
               else
+#endif
               {
                 if (!isCccmModeEnabledInRdo[sub][chromaIntraModeInCCCM])
                 {
@@ -4202,7 +4458,12 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
           pu.intraDir[1] = chromaIntraModeInCCCM;
 
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+          const int cccmBufferIdx = filterIdx * CCCM_NUM_MODES + uiMode;
+          xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[sub][cccmBufferIdx]);
+#else
           xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[sub][uiMode]);
+#endif
 #else
           xRecurIntraChromaCodingQT(cs, partitioner, bestCostSoFar, ispType, cccmStorage[uiMode]);
 #endif
@@ -4274,15 +4535,24 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 #if JVET_AC0054_GLCCCM
             glCccmBest      = pu.glCccmFlag;
 #endif
+#if JVET_AD0202_CCCM_MDF
+            cccmMultiFilterIdxBest = pu.cccmMultiFilterIdx;
+#endif
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING 
             cccmNoSubBest  = pu.cccmNoSubFlag;
             }
+#endif
+#if JVET_AD0202_CCCM_MDF
+          }
 #endif
           }
         }
       }
         
       pu.cccmFlag = 0;
+#if JVET_AD0202_CCCM_MDF
+      pu.cccmMultiFilterIdx = 0;
+#endif
 #endif
       for( uint32_t i = getFirstComponentOfChannel( CHANNEL_TYPE_CHROMA ); i < numberValidComponents; i++ )
       {
@@ -4323,6 +4593,9 @@ void IntraSearch::estIntraPredChromaQT( CodingUnit &cu, Partitioner &partitioner
 #if JVET_AC0054_GLCCCM
     pu.glCccmFlag = glCccmBest;
 #endif
+#if JVET_AD0202_CCCM_MDF
+    pu.cccmMultiFilterIdx = cccmMultiFilterIdxBest;
+#endif
 #endif
 #if JVET_Z0050_DIMD_CHROMA_FUSION
     pu.isChromaFusion = isChromaFusion;
diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h
index 40df261b1366c78413b27b33f34d78b84b2b742e..4583288416b91437b21b9a7123ff45e8a7f28898 100644
--- a/source/Lib/EncoderLib/IntraSearch.h
+++ b/source/Lib/EncoderLib/IntraSearch.h
@@ -493,7 +493,11 @@ private:
   PelStorage      m_colorTransResiBuf;
 #if JVET_AB0143_CCCM_TS
 #if JVET_AC0147_CCCM_NO_SUBSAMPLING
+#if JVET_AD0202_CCCM_MDF
+  PelStorage      m_cccmStorage[2][TOTAL_NUM_CCCM_MODES];
+#else
   PelStorage      m_cccmStorage[2][CCCM_NUM_MODES];
+#endif
 #else
   PelStorage      m_cccmStorage[CCCM_NUM_MODES];
 #endif
@@ -540,6 +544,10 @@ public:
   bool            m_skipCCCMSATD;
   int             m_isCccmNoSubModeEnabledInRdo[MMLM_T_IDX + 1];
 #endif 
+#if JVET_AD0202_CCCM_MDF
+  bool            m_skipCCCMwithMdfSATD;
+  int             m_isCccmWithMdfEnabledInRdo[5][MMLM_T_IDX + 1];
+#endif
   IntraSearch();
   ~IntraSearch();