diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 7e979bfa9d3f6291760e964bff6e4334285d968f..f261177ea76a8fb2e74d167a448ed7040a48ae49 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -196,6 +196,12 @@ static const int ADJ_DEQUANT_SHIFT =            ( ADJ_QUANT_SHIFT + 1 );
 
 static const int RVM_VCEGAM10_M =                                   4;
 
+#if JVET_L0283_MULTI_REF_LINE
+static const int MAX_REF_LINE_IDX =                                 3; //highest refLine offset in the list
+static const int MRL_NUM_REF_LINES =                                3; //number of candidates in the array
+static const int MULTI_REF_LINE_IDX[4] =               { 0, 1, 3, 0 };
+#endif
+
 static const int NUM_LUMA_MODE =                                   67; ///< Planar + DC + 65 directional mode (4*16 + 1)
 #if JVET_L0338_MDLM
 static const int NUM_LMC_MODE =                                    1 + 2; ///< LMC + MDLM_T + MDLM_L
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 4130a64624c5ce1c4569267d6aebd5cf197a2358..ede67ef3e71c9822a2454d511579fa5f08fa2130 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -349,6 +349,15 @@ const CtxSet ContextSetCfg::PredMode = ContextSetCfg::addCtxSet
   {  CNU,},
 });
 
+#if JVET_L0283_MULTI_REF_LINE
+const CtxSet ContextSetCfg::MultiRefLineIdx = ContextSetCfg::addCtxSet
+({
+  { 154, 154, 154 },
+  { 154, 154, 154 },
+  { CNU, CNU, CNU },
+  });
+#endif
+
 const CtxSet ContextSetCfg::IPredMode[] =
 {
   ContextSetCfg::addCtxSet
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index 718a8b2341f47cffe95ab659dc08f0122cfa964e..522bf65184bac528f532095216c38c96cd8d888c 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -161,6 +161,9 @@ public:
   static const CtxSet   MergeIdx;
   static const CtxSet   PartSize;
   static const CtxSet   PredMode;
+#if JVET_L0283_MULTI_REF_LINE
+  static const CtxSet   MultiRefLineIdx;
+#endif
   static const CtxSet   IPredMode       [2];    // [ ChannelType ]
   static const CtxSet   PdpcFlag;
   static const CtxSet   DeltaQP;
diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index fccc63284123487e41ed213023a15f43b05b711b..9bc68a0e2b03254d93e5208dac92f14e9f0f08dc 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -210,7 +210,11 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth
 
   if (m_piYuvExt[COMPONENT_Y][PRED_BUF_UNFILTERED] == nullptr) // check if first is null (in which case, nothing initialised yet)
   {
+#if JVET_L0283_MULTI_REF_LINE
+    m_iYuvExtSize = (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 5) * (MAX_CU_SIZE * 2 + 1 + MAX_REF_LINE_IDX * 5);
+#else
     m_iYuvExtSize = (MAX_CU_SIZE * 2 + 1) * (MAX_CU_SIZE * 2 + 1);
+#endif
 
     for (uint32_t ch = 0; ch < MAX_NUM_COMPONENT; ch++)
     {
@@ -339,9 +343,14 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
   CHECK( g_aucLog2[iWidth] < 2 && pu.cs->pcv->noChroma2x2, "Size not allowed" );
   CHECK( g_aucLog2[iWidth] > 7, "Size not allowed" );
   CHECK( iWidth != iHeight && !pu.cs->pcv->rectCUs, "Rectangular block are only allowed with QTBT" );
-
+#if JVET_L0283_MULTI_REF_LINE
+  const int  multiRefIdx = (compID == COMPONENT_Y) ? pu.multiRefIdx : 0;
+  const int  srcStride   = m_topRefLength  + 1 + 5 * multiRefIdx;
+  const int  srcHStride  = m_leftRefLength + 1 + 5 * multiRefIdx;
+#else
   const int  srcStride  = m_topRefLength  + 1;
   const int  srcHStride = m_leftRefLength + 1;
+#endif
 
   Pel *ptrSrc = getPredictorPtr(compID, useFilteredPredSamples);
   const ClpRng& clpRng(pu.cu->cs->slice->clpRng(compID));
@@ -356,17 +365,33 @@ void IntraPrediction::predIntraAng( const ComponentID compId, PelBuf &piPred, co
     case(VDIA_IDX):
       if (getWideAngle(iWidth, iHeight, uiDirMode) == static_cast<int>(uiDirMode)) // check if uiDirMode is not wide-angle
       {
-        xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, useFilteredPredSamples); 
+        xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps
+#if JVET_L0283_MULTI_REF_LINE
+          , multiRefIdx
+#endif
+          , useFilteredPredSamples); 
         break;
       }
-    default:          xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, useFilteredPredSamples); break;
+    default:          xPredIntraAng(CPelBuf(getPredictorPtr(compID, false), srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps
+#if JVET_L0283_MULTI_REF_LINE
+      , multiRefIdx
+#endif
+      , useFilteredPredSamples); break;
 #else //JVET_L0628_4TAP_INTRA
-    default:          xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps, false); break;
+    default:          xPredIntraAng(CPelBuf(ptrSrc, srcStride, srcHStride), piPred, channelType, uiDirMode, clpRng, *pu.cs->sps
+#if JVET_L0283_MULTI_REF_LINE
+      , multiRefIdx
+#endif
+      , false); break;
 #endif //JVET_L0628_4TAP_INTRA
   }
 
   bool pdpcCondition = (uiDirMode == PLANAR_IDX || uiDirMode == DC_IDX || uiDirMode == HOR_IDX || uiDirMode == VER_IDX);
+#if JVET_L0283_MULTI_REF_LINE
+  if (pdpcCondition && multiRefIdx == 0)
+#else
   if (pdpcCondition)
+#endif
   {
     const CPelBuf srcBuf = CPelBuf(ptrSrc, srcStride, srcStride);
     PelBuf dstBuf = piPred;
@@ -593,11 +618,23 @@ void IntraPrediction::xDCPredFiltering(const CPelBuf &pSrc, PelBuf &pDst, const
 */
 //NOTE: Bit-Limit - 25-bit source
 #if HEVC_USE_HOR_VER_PREDFILTERING
-void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps, const bool enableBoundaryFilter )
+void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps
+#if JVET_L0283_MULTI_REF_LINE
+  , int multiRefIdx
+#endif
+  , const bool enableBoundaryFilter )
 #elif JVET_L0628_4TAP_INTRA
-void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool useFilteredPredSamples )
+void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps
+#if JVET_L0283_MULTI_REF_LINE
+  , int multiRefIdx
+#endif
+  , const bool useFilteredPredSamples )
 #else
-void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool enableBoundaryFilter )
+void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps
+#if JVET_L0283_MULTI_REF_LINE
+  , int multiRefIdx
+#endif
+  , const bool enableBoundaryFilter )
 #endif
 {
   int width =int(pDst.width);
@@ -626,9 +663,13 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
   Pel* refMain;
   Pel* refSide;
 
+#if JVET_L0283_MULTI_REF_LINE
+  Pel  refAbove[2 * MAX_CU_SIZE + 3 + 5 * MAX_REF_LINE_IDX];
+  Pel  refLeft [2 * MAX_CU_SIZE + 3 + 5 * MAX_REF_LINE_IDX];
+#else
   Pel  refAbove[2 * MAX_CU_SIZE + 3];
   Pel  refLeft [2 * MAX_CU_SIZE + 3];
-
+#endif
 
   // Initialize the Main and Left reference array.
   if (intraPredAngle < 0)
@@ -636,14 +677,26 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
 #if JVET_L0628_4TAP_INTRA
     auto width    = int(pDst.width) +1;
     auto height   = int(pDst.height)+1;  
+#if JVET_L0283_MULTI_REF_LINE
+    auto lastIdx  = (bIsModeVer ? width : height) + multiRefIdx;
+#else
     auto lastIdx  = bIsModeVer ? width : height;
+#endif
     auto firstIdx = ( ((bIsModeVer ? height : width) -1) * intraPredAngle ) >> 5;
 #endif //JVET_L0628_4TAP_INTRA
+#if JVET_L0283_MULTI_REF_LINE
+    for (int x = 0; x < width + 1 + multiRefIdx; x++)
+#else
     for( int x = 0; x < width + 1; x++ )
+#endif
     {
       refAbove[x + height - 1] = pSrc.at( x, 0 );
     }
+#if JVET_L0283_MULTI_REF_LINE
+    for (int y = 0; y < height + 1 + multiRefIdx; y++)
+#else
     for( int y = 0; y < height + 1; y++ )
+#endif
     {
       refLeft[y + width - 1] = pSrc.at( 0, y );
     }
@@ -669,7 +722,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
   }
   else
   {
+#if JVET_L0283_MULTI_REF_LINE
+    for (int x = 0; x < m_topRefLength + 1 + 5 * multiRefIdx; x++)
+#else
     for( int x = 0; x < m_topRefLength + 1; x++ )
+#endif
     {
 #if JVET_L0628_4TAP_INTRA
       refAbove[x+1] = pSrc.at(x, 0);
@@ -677,7 +734,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
       refAbove[x] = pSrc.at(x, 0);
 #endif //JVET_L0628_4TAP_INTRA
     }
+#if JVET_L0283_MULTI_REF_LINE
+    for (int y = 0; y < m_leftRefLength + 1 + 5 * multiRefIdx; y++)
+#else
     for( int y = 0; y < m_leftRefLength + 1; y++ )
+#endif
     {
 #if JVET_L0628_4TAP_INTRA
       refLeft[y+1]  = pSrc.at(0, y);
@@ -692,7 +753,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
     refMain++;
     refSide++;
     refMain[-1] = refMain[0];
+#if JVET_L0283_MULTI_REF_LINE
+    auto lastIdx = 1 + ((bIsModeVer) ? m_topRefLength : m_leftRefLength) + 5 * multiRefIdx;
+#else
     auto lastIdx = 1 + ((bIsModeVer) ? m_topRefLength : m_leftRefLength);
+#endif
     refMain[lastIdx] = refMain[lastIdx-1];
 #endif //JVET_L0628_4TAP_INTRA
   }
@@ -706,6 +771,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
     std::swap(width, height);
   }
 
+#if JVET_L0283_MULTI_REF_LINE
+  // compensate for line offset in reference line buffers
+  refMain += multiRefIdx;
+  refSide += multiRefIdx;
+#endif
 
   if( intraPredAngle == 0 )  // pure vertical or pure horizontal
   {
@@ -717,7 +787,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
       }
     }
 #if HEVC_USE_HOR_VER_PREDFILTERING
+#if JVET_L0283_MULTI_REF_LINE
+    if (edgeFilter && multiRefIdx == 0)
+#else
     if (edgeFilter)
+#endif
     {
       for( int y = 0; y < height; y++ )
       {
@@ -729,8 +803,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
   else
   {
     Pel *pDsty=pDstBuf;
-
+#if JVET_L0283_MULTI_REF_LINE
+    for (int y = 0, deltaPos = intraPredAngle * (1 + multiRefIdx); y<height; y++, deltaPos += intraPredAngle, pDsty += dstStride)
+#else
     for (int y=0, deltaPos=intraPredAngle; y<height; y++, deltaPos+=intraPredAngle, pDsty+=dstStride)
+#endif
     {
       const int deltaInt   = deltaPos >> 5;
       const int deltaFract = deltaPos & (32 - 1);
@@ -747,7 +824,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
         if( isLuma(channelType) )
         {
           Pel                        p[4];
+#if JVET_L0283_MULTI_REF_LINE
+          const bool                 useCubicFilter = !useFilteredPredSamples || multiRefIdx > 0;
+#else
           const bool                 useCubicFilter = !useFilteredPredSamples;
+#endif
           TFilterCoeff const * const f              = (useCubicFilter) ? InterpolationFilter::getChromaFilterTable(deltaFract) : g_intraGaussFilter[deltaFract];
 
           int         refMainIndex   = deltaInt + 1;
@@ -792,8 +873,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
       const int numModes = 8;
       const int scale = ((g_aucLog2[width] - 2 + g_aucLog2[height] - 2 + 2) >> 2);
       CHECK(scale < 0 || scale > 31, "PDPC: scale < 0 || scale > 31");
-
+#if JVET_L0283_MULTI_REF_LINE
+      if ((predMode == 2 || predMode == VDIA_IDX) && multiRefIdx == 0)
+#else
       if (predMode == 2 || predMode == VDIA_IDX)
+#endif
       {
         int wT = 16 >> std::min(31, ((y << 1) >> scale));
 
@@ -809,7 +893,11 @@ void IntraPrediction::xPredIntraAng( const CPelBuf &pSrc, PelBuf &pDst, const Ch
           pDsty[x] = ClipPel((wL * left + wT * top + (64 - wL - wT) * pDsty[x] + 32) >> 6, clpRng);
         }
       }
+#if JVET_L0283_MULTI_REF_LINE
+      else if (((predMode >= VDIA_IDX - numModes && predMode != VDIA_IDX) || (predMode != 2 && predMode <= (2 + numModes))) && multiRefIdx == 0)
+#else
       else if ((predMode >= VDIA_IDX - numModes && predMode != VDIA_IDX) || (predMode != 2 && predMode <= (2 + numModes)))
+#endif
       {
         int invAngleSum0 = 2;
         for (int x = 0; x < width; x++)
@@ -1006,7 +1094,11 @@ void IntraPrediction::initIntraPatternChType(const CodingUnit &cu, const CompAre
   // ----- Step 2: filtered reference samples -----
   if( bFilterRefSamples )
   {
-    xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps );
+    xFilterReferenceSamples( refBufUnfiltered, refBufFiltered, area, *cs.sps 
+#if JVET_L0283_MULTI_REF_LINE
+      , cu.firstPU->multiRefIdx
+#endif
+    );
   }
 }
 
@@ -1017,11 +1109,19 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf
   const SPS             &sps    = *cs.sps;
   const PreCalcValues   &pcv    = *cs.pcv;
 
+#if JVET_L0283_MULTI_REF_LINE
+  const int multiRefIdx         = (area.compID == COMPONENT_Y) ? cu.firstPU->multiRefIdx : 0;
+#endif
+
   const int  tuWidth            = area.width;
   const int  tuHeight           = area.height;
   const int  predSize           = m_topRefLength;
   const int  predHSize          = m_leftRefLength;
+#if JVET_L0283_MULTI_REF_LINE
+  const int  predStride         = predSize + 1 + 5 * multiRefIdx;
+#else
   const int  predStride         = predSize + 1;
+#endif
 
   const bool noShift            = pcv.noChroma2x2 && area.width == 4; // don't shift on the lowest level (chroma not-split)
   const int  unitWidth          = pcv.minCUWidth  >> (noShift ? 0 : getComponentScaleX( area.compID, sps.getChromaFormatIdc() ));
@@ -1067,20 +1167,198 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf
   if( numIntraNeighbor == 0 )
   {
     // Fill border with DC value
+#if JVET_L0283_MULTI_REF_LINE
+    for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = valueDC; }
+    for (int i = 1; i <= predHSize + multiRefIdx; i++) { ptrDst[i*predStride] = valueDC; }
+#else
     for( int j = 0; j <= predSize; j++ ) { ptrDst[j]            = valueDC; }
     for( int i = 1; i <= predHSize; i++ ) { ptrDst[i*predStride] = valueDC; }
+#endif
   }
   else if( numIntraNeighbor == totalUnits )
   {
     // Fill top-left border and top and top right with rec. samples
+#if JVET_L0283_MULTI_REF_LINE
+    ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx);
+    for (int j = 0; j <= predSize + multiRefIdx; j++) { ptrDst[j] = ptrSrc[j]; }
+    ptrSrc = srcBuf - multiRefIdx * srcStride - (1 + multiRefIdx);
+    for (int i = 1; i <= predHSize + multiRefIdx; i++) { ptrDst[i*predStride] = *(ptrSrc); ptrSrc += srcStride; }
+#else
     ptrSrc = srcBuf - srcStride - 1;
     for( int j = 0; j <= predSize; j++ ) { ptrDst[j] = ptrSrc[j]; }
     // Fill left and below left border with rec. samples
     ptrSrc = srcBuf - 1;
     for( int i = 1; i <= predHSize; i++ ) { ptrDst[i*predStride] = *(ptrSrc); ptrSrc += srcStride; }
+#endif
   }
   else // reference samples are partially available
   {
+#if JVET_L0283_MULTI_REF_LINE
+    // Fill top-left sample(s) if available
+    ptrSrc = srcBuf - (1 + multiRefIdx) * srcStride - (1 + multiRefIdx);
+    ptrDst = refBufUnfiltered;
+    if (neighborFlags[totalLeftUnits])
+    {
+      ptrDst[0] = ptrSrc[0];
+      for (int i = 1; i <= multiRefIdx; i++)
+      {
+        ptrDst[i] = ptrSrc[i];
+        ptrDst[i*predStride] = ptrSrc[i*srcStride];
+      }
+    }
+
+    // Fill left & below-left samples if available (downwards)
+    ptrSrc += (1 + multiRefIdx) * srcStride;
+    ptrDst += (1 + multiRefIdx) * predStride;
+    for (int unitIdx = totalLeftUnits - 1; unitIdx > 0; unitIdx--)
+    {
+      if (neighborFlags[unitIdx])
+      {
+        for (int i = 0; i < unitHeight; i++)
+        {
+          ptrDst[i*predStride] = ptrSrc[i*srcStride];
+        }
+      }
+      ptrSrc += unitHeight * srcStride;
+      ptrDst += unitHeight * predStride;
+    }
+    // Fill last below-left sample(s)
+    if (neighborFlags[0])
+    {
+      int lastSample = (predHSize % unitHeight == 0) ? unitHeight : predHSize % unitHeight;
+      for (int i = 0; i < lastSample; i++)
+      {
+        ptrDst[i*predStride] = ptrSrc[i*srcStride];
+      }
+    }
+
+    // Fill above & above-right samples if available (left-to-right)
+    ptrSrc = srcBuf - srcStride * (1 + multiRefIdx);
+    ptrDst = refBufUnfiltered + 1 + multiRefIdx;
+    for (int unitIdx = totalLeftUnits + 1; unitIdx < totalUnits - 1; unitIdx++)
+    {
+      if (neighborFlags[unitIdx])
+      {
+        for (int j = 0; j < unitWidth; j++)
+        {
+          ptrDst[j] = ptrSrc[j];
+        }
+      }
+      ptrSrc += unitWidth;
+      ptrDst += unitWidth;
+    }
+    // Fill last above-right sample(s)
+    if (neighborFlags[totalUnits - 1])
+    {
+      int lastSample = (predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth;
+      for (int j = 0; j < lastSample; j++)
+      {
+        ptrDst[j] = ptrSrc[j];
+      }
+    }
+
+    // pad from first available down to the last below-left
+    ptrDst = refBufUnfiltered;
+    int lastAvailUnit = 0;
+    if (!neighborFlags[0])
+    {
+      int firstAvailUnit = 1;
+      while (firstAvailUnit < totalUnits && !neighborFlags[firstAvailUnit])
+      {
+        firstAvailUnit++;
+      }
+
+      // first available sample
+      int firstAvailRow = 0;
+      int firstAvailCol = 0;
+      if (firstAvailUnit < totalLeftUnits)
+      {
+        firstAvailRow = (totalLeftUnits - firstAvailUnit) * unitHeight + multiRefIdx;
+      }
+      else if (firstAvailUnit == totalLeftUnits)
+      {
+        firstAvailRow = multiRefIdx;
+      }
+      else
+      {
+        firstAvailCol = (firstAvailUnit - totalLeftUnits - 1) * unitWidth + 1 + multiRefIdx;
+      }
+      const Pel firstAvailSample = ptrDst[firstAvailCol + firstAvailRow * predStride];
+
+      // last sample below-left (n.a.)
+      int lastRow = predHSize + multiRefIdx;
+
+      // fill left column
+      for (int i = lastRow; i > firstAvailRow; i--)
+      {
+        ptrDst[i*predStride] = firstAvailSample;
+      }
+      // fill top row
+      if (firstAvailCol > 0)
+      {
+        for (int j = 0; j < firstAvailCol; j++)
+        {
+          ptrDst[j] = firstAvailSample;
+        }
+      }
+      lastAvailUnit = firstAvailUnit;
+    }
+
+    // pad all other reference samples.
+    int currUnit = lastAvailUnit + 1;
+    while (currUnit < totalUnits)
+    {
+      if (!neighborFlags[currUnit]) // samples not available
+      {
+        // last available sample
+        int lastAvailRow = 0;
+        int lastAvailCol = 0;
+        if (lastAvailUnit < totalLeftUnits)
+        {
+          lastAvailRow = (totalLeftUnits - lastAvailUnit - 1) * unitHeight + multiRefIdx + 1;
+        }
+        else if (lastAvailUnit == totalLeftUnits)
+        {
+          lastAvailCol = multiRefIdx;
+        }
+        else
+        {
+          lastAvailCol = (lastAvailUnit - totalLeftUnits) * unitWidth + multiRefIdx;
+        }
+        const Pel lastAvailSample = ptrDst[lastAvailCol + lastAvailRow * predStride];
+
+        // fill current unit with last available sample
+        if (currUnit < totalLeftUnits)
+        {
+          for (int i = lastAvailRow - 1; i <= lastAvailRow + unitHeight; i++)
+          {
+            ptrDst[i*predStride] = lastAvailSample;
+          }
+        }
+        else if (currUnit == totalLeftUnits)
+        {
+          for (int i = 1; i < multiRefIdx + 1; i++)
+          {
+            ptrDst[i*predStride] = lastAvailSample;
+          }
+          for (int j = 0; j < multiRefIdx + 1; j++)
+          {
+            ptrDst[j] = lastAvailSample;
+          }
+        }
+        else
+        {
+          int numSamplesInUnit = (currUnit == totalUnits - 1) ? ((predSize % unitWidth == 0) ? unitWidth : predSize % unitWidth) : unitWidth;
+          for (int j = lastAvailCol + 1; j <= lastAvailCol + numSamplesInUnit; j++)
+          {
+            ptrDst[j] = lastAvailSample;
+          }
+        }
+      }
+      lastAvailUnit = currUnit;
+      currUnit++;
+    }
+#else
     // BB: old implementation using tmpLineBuf
     // ---------------------------------------
     Pel  tmpLineBuf[5 * MAX_CU_SIZE];
@@ -1182,13 +1460,35 @@ void IntraPrediction::xFillReferenceSamples( const CPelBuf &recoBuf, Pel* refBuf
 
     ptrTmp = tmpLineBuf + (totalLeftUnits * unitHeight);
     for( int i = 1; i <= predHSize; i++ ) { ptrDst[i*predStride] = ptrTmp[-i]; }
-  }
+#endif  
+}
+#if JVET_L0283_MULTI_REF_LINE
+  // padding of extended samples above right with the last sample
+  int lastSample = multiRefIdx + predSize;
+  for (int j = 1; j <= 4 * multiRefIdx; j++) { ptrDst[lastSample + j] = ptrDst[lastSample]; }
+  // padding of extended samples below left with the last sample
+  lastSample = multiRefIdx + predHSize;
+  for (int i = 1; i <= 4 * multiRefIdx; i++) { ptrDst[(lastSample + i)*predStride] = ptrDst[lastSample*predStride]; }
+#endif
 }
 
-void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps )
+void IntraPrediction::xFilterReferenceSamples( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps 
+#if JVET_L0283_MULTI_REF_LINE
+  , int multiRefIdx
+#endif
+)
 {
+#if JVET_L0283_MULTI_REF_LINE
+  if (area.compID != COMPONENT_Y)
+  {
+    multiRefIdx = 0;
+  }
+  const int  predSize  = m_topRefLength  + 5 * multiRefIdx;
+  const int  predHSize = m_leftRefLength + 5 * multiRefIdx;
+#else
   const int  predSize   = m_topRefLength;
   const int  predHSize  = m_leftRefLength;
+#endif
   const int  predStride = predSize + 1;
 
 
@@ -1268,6 +1568,10 @@ bool IntraPrediction::useFilteredIntraRefSamples( const ComponentID &compID, con
 
   if( !modeSpecific )                                                                                    { return true; }
 
+#if JVET_L0283_MULTI_REF_LINE
+  if (pu.multiRefIdx)                                                                                    { return false; }
+#endif
+
   // pred. mode related conditions
   const int dirMode = PU::getFinalIntraMode( pu, chType );
   int predMode = getWideAngle(tuArea.blocks[compID].width, tuArea.blocks[compID].height, dirMode);
diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h
index 72618f957e6ce5079df408bae35f3a0b7d885bf3..51ff65bfd9934e18934f08c197dac41884ac6a52 100644
--- a/source/Lib/CommonLib/IntraPrediction.h
+++ b/source/Lib/CommonLib/IntraPrediction.h
@@ -92,18 +92,34 @@ protected:
   void xPredIntraPlanar           ( const CPelBuf &pSrc, PelBuf &pDst,                                                                                                         const SPS& sps );
   void xPredIntraDc               ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType,                                                                                          const bool enableBoundaryFilter = true );
 #if HEVC_USE_HOR_VER_PREDFILTERING
-  void xPredIntraAng              ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps, const bool enableBoundaryFilter = true );
+  void xPredIntraAng              ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const bool bEnableEdgeFilters, const SPS& sps
+#if JVET_L0283_MULTI_REF_LINE
+    , int multiRefIdx
+#endif
+    , const bool enableBoundaryFilter = true );
 #else
 #if JVET_L0628_4TAP_INTRA
-  void xPredIntraAng              ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool useFilteredPredSamples );
+  void xPredIntraAng              ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps
+#if JVET_L0283_MULTI_REF_LINE
+    , int multiRefIdx
+#endif    
+    , const bool useFilteredPredSamples );
 #else
-  void xPredIntraAng              ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps, const bool enableBoundaryFilter = true );
+  void xPredIntraAng              ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const uint32_t dirMode, const ClpRng& clpRng, const SPS& sps
+#if JVET_L0283_MULTI_REF_LINE
+    , int multiRefIdx
+#endif    
+    , const bool enableBoundaryFilter = true );
 #endif //JVET_L0628_4TAP_INTRA
 #endif
   Pel  xGetPredValDc              ( const CPelBuf &pSrc, const Size &dstSize );
 
   void xFillReferenceSamples      ( const CPelBuf &recoBuf,      Pel* refBufUnfiltered, const CompArea &area, const CodingUnit &cu );
-  void xFilterReferenceSamples    ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps );
+  void xFilterReferenceSamples    ( const Pel* refBufUnfiltered, Pel* refBufFiltered, const CompArea &area, const SPS &sps 
+#if JVET_L0283_MULTI_REF_LINE
+    , int multiRefIdx
+#endif
+  );
 
 #if HEVC_USE_DC_PREDFILTERING
   // dc filtering
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index e6e7ff8eb8f2eedc447bd8bcd469d196a64489d8..7006892d179f75a81967da37b3973745cc903769 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -107,6 +107,8 @@
 
 #define JVET_L0260_AFFINE_ME                              1
 
+#define JVET_L0283_MULTI_REF_LINE                         1
+
 #define JVET_L0256_BIO                                    1
 
 #define JVET_L0646_GBI                                    1 // Generalized bi-prediction (GBi)
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 098732295cef633a568eb54b362b13bc77f64139..c491ac84dc64e68663ba7a0d682a98d56ad8d32c 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -329,6 +329,9 @@ void PredictionUnit::initData()
   // intra data - need this default initialization for PCM
   intraDir[0] = DC_IDX;
   intraDir[1] = PLANAR_IDX;
+#if JVET_L0283_MULTI_REF_LINE
+  multiRefIdx = 0;
+#endif
 
   // inter data
   mergeFlag   = false;
@@ -368,6 +371,9 @@ PredictionUnit& PredictionUnit::operator=(const IntraPredictionData& predData)
   {
     intraDir[i] = predData.intraDir[i];
   }
+#if JVET_L0283_MULTI_REF_LINE
+  multiRefIdx = predData.multiRefIdx;
+#endif
 
   return *this;
 }
@@ -413,6 +419,9 @@ PredictionUnit& PredictionUnit::operator=( const PredictionUnit& other )
   {
     intraDir[ i ] = other.intraDir[ i ];
   }
+#if JVET_L0283_MULTI_REF_LINE
+  multiRefIdx = other.multiRefIdx;
+#endif
 
   mergeFlag   = other.mergeFlag;
   mergeIdx    = other.mergeIdx;
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 976dfdf1f9620351bfc109b7717aa33c7e3c499c..e18c8854d45d43dc9fbd8c540091a999cc81f661 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -349,6 +349,9 @@ struct CodingUnit : public UnitArea
 struct IntraPredictionData
 {
   uint32_t  intraDir[MAX_NUM_CHANNEL_TYPE];
+#if JVET_L0283_MULTI_REF_LINE
+  int       multiRefIdx;
+#endif
 };
 
 struct InterPredictionData
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 509d3e7971aed4f02a573e1a61a27f4ac2419397..29e609e47241011d056b166923d5693d361bfc33 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -299,6 +299,9 @@ cTUTraverser CU::traverseTUs( const CodingUnit& cu )
 int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType &channelType /*= CHANNEL_TYPE_LUMA*/ )
 {
   const unsigned numMPMs = pu.cs->pcv->numMPMs;
+#if JVET_L0283_MULTI_REF_LINE
+  const int extendRefLine = (channelType == CHANNEL_TYPE_LUMA) ? pu.multiRefIdx : 0;
+#endif
   {
     int numCand      = -1;
 #if JVET_L0165_6MPM
@@ -327,56 +330,130 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType
     const int offset = (int)NUM_LUMA_MODE - 6;
     const int mod = offset + 3;
 
-    mpm[0] = leftIntraDir;
-    mpm[1] = (mpm[0] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX;
-    mpm[2] = VER_IDX;
-    mpm[3] = HOR_IDX;
-    mpm[4] = VER_IDX - 4;
-    mpm[5] = VER_IDX + 4;
-
-    if (leftIntraDir == aboveIntraDir)
+#if JVET_L0283_MULTI_REF_LINE
+    if (extendRefLine)
     {
-      numCand = 1;
+      int modeIdx = 0;
+      int angularMode[2] = { 0, 0 };
+
       if (leftIntraDir > DC_IDX)
       {
-        mpm[0] = leftIntraDir;
-        mpm[1] = PLANAR_IDX;
-        mpm[2] = DC_IDX;
-        mpm[3] = ((leftIntraDir + offset) % mod) + 2;
-        mpm[4] = ((leftIntraDir - 1) % mod) + 2;
-        mpm[5] = ((leftIntraDir + offset - 1) % mod) + 2;
+        angularMode[modeIdx++] = leftIntraDir;
+      }
+      if (aboveIntraDir > DC_IDX)
+      {
+        angularMode[modeIdx++] = aboveIntraDir;
+      }
+      if (modeIdx == 0)
+      {
+        mpm[0] = VER_IDX;
+        mpm[1] = HOR_IDX;
+        mpm[2] = 2;
+        mpm[3] = DIA_IDX;
+        mpm[4] = VDIA_IDX;
+        mpm[5] = 26;
+      }
+      else if (modeIdx == 1)
+      {
+        mpm[0] = angularMode[0];
+        mpm[1] = ((angularMode[0] + offset) % mod) + 2;
+        mpm[2] = ((angularMode[0] - 1) % mod) + 2;
+        mpm[3] = ((angularMode[0] + offset - 1) % mod) + 2;
+        mpm[4] = (angularMode[0] % mod) + 2;
+        mpm[5] = ((angularMode[0] + offset - 2) % mod) + 2;
+      }
+      else
+      {
+        mpm[0] = angularMode[0];
+        mpm[1] = angularMode[1];
+        int maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
+        int minCandModeIdx = 1 - maxCandModeIdx;
+        if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 1)
+        {
+          mpm[2] = ((angularMode[minCandModeIdx] + offset) % mod) + 2;
+          mpm[3] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2;
+          mpm[4] = ((angularMode[minCandModeIdx] + offset - 1) % mod) + 2;
+          mpm[5] = ( angularMode[maxCandModeIdx] % mod) + 2;
+        }
+        else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] >= 62)
+        {
+          mpm[2] = ((angularMode[minCandModeIdx] - 1) % mod) + 2;
+          mpm[3] = ((angularMode[maxCandModeIdx] + offset) % mod) + 2;
+          mpm[4] = ((angularMode[minCandModeIdx]) % mod) + 2;
+          mpm[5] = ((angularMode[maxCandModeIdx] + offset - 1) % mod) + 2;
+        }
+        else if (mpm[maxCandModeIdx] - mpm[minCandModeIdx] == 2)
+        {
+          mpm[2] = ((angularMode[minCandModeIdx] - 1) % mod) + 2;
+          mpm[3] = ((angularMode[minCandModeIdx] + offset) % mod) + 2;
+          mpm[4] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2;
+          mpm[5] = ((angularMode[minCandModeIdx] + offset - 1) % mod) + 2;
+        }
+        else
+        {
+          mpm[2] = ((angularMode[minCandModeIdx] + offset) % mod) + 2;
+          mpm[3] = ((angularMode[minCandModeIdx] - 1) % mod) + 2;
+          mpm[4] = ((angularMode[maxCandModeIdx] + offset) % mod) + 2;
+          mpm[5] = ((angularMode[maxCandModeIdx] - 1) % mod) + 2;
+        }
       }
     }
-    else //L!=A
+    else
     {
-      numCand = 2;
+#endif
       mpm[0] = leftIntraDir;
-      mpm[1] = aboveIntraDir;
-      bool maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
+      mpm[1] = (mpm[0] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX;
+      mpm[2] = VER_IDX;
+      mpm[3] = HOR_IDX;
+      mpm[4] = VER_IDX - 4;
+      mpm[5] = VER_IDX + 4;
 
-      if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
+      if (leftIntraDir == aboveIntraDir)
       {
-        mpm[2] = PLANAR_IDX;
-        mpm[3] = DC_IDX;
-        if ((mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] < 63) && (mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] > 1))
+        numCand = 1;
+        if (leftIntraDir > DC_IDX)
         {
-          mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
-          mpm[5] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
-        }
-        else
-        {
-          mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
-          mpm[5] = ((mpm[maxCandModeIdx] ) % mod) + 2;
+          mpm[0] = leftIntraDir;
+          mpm[1] = PLANAR_IDX;
+          mpm[2] = DC_IDX;
+          mpm[3] = ((leftIntraDir + offset) % mod) + 2;
+          mpm[4] = ((leftIntraDir - 1) % mod) + 2;
+          mpm[5] = ((leftIntraDir + offset - 1) % mod) + 2;
         }
       }
-      else if (leftIntraDir + aboveIntraDir >= 2)
+      else //L!=A
       {
-        mpm[2] = (mpm[!maxCandModeIdx] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX;
-        mpm[3] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
-        mpm[4] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
-        mpm[5] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
+        numCand = 2;
+        mpm[0] = leftIntraDir;
+        mpm[1] = aboveIntraDir;
+        bool maxCandModeIdx = mpm[0] > mpm[1] ? 0 : 1;
+
+        if ((leftIntraDir > DC_IDX) && (aboveIntraDir > DC_IDX))
+        {
+          mpm[2] = PLANAR_IDX;
+          mpm[3] = DC_IDX;
+          if ((mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] < 63) && (mpm[maxCandModeIdx] - mpm[!maxCandModeIdx] > 1))
+          {
+            mpm[4] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
+            mpm[5] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
+          }
+          else
+          {
+            mpm[4] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
+            mpm[5] = ((mpm[maxCandModeIdx]) % mod) + 2;
+          }
+        }
+        else if (leftIntraDir + aboveIntraDir >= 2)
+        {
+          mpm[2] = (mpm[!maxCandModeIdx] == PLANAR_IDX) ? DC_IDX : PLANAR_IDX;
+          mpm[3] = ((mpm[maxCandModeIdx] + offset) % mod) + 2;
+          mpm[4] = ((mpm[maxCandModeIdx] - 1) % mod) + 2;
+          mpm[5] = ((mpm[maxCandModeIdx] + offset - 1) % mod) + 2;
+        }
       }
+#if JVET_L0283_MULTI_REF_LINE
     }
+#endif
 #else
     int leftIntraDir = DC_IDX, aboveIntraDir = DC_IDX;
 
@@ -422,6 +499,71 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType
     const int offset = 61;
     const int mod    = 64;
 
+#if JVET_L0283_MULTI_REF_LINE
+    if (extendRefLine)
+    {
+      if (leftIntraDir == aboveIntraDir)
+      {
+        numCand = 1;
+
+        if (leftIntraDir > DC_IDX)   // angular modes
+        {
+          mpm[0] = leftIntraDir;
+          mpm[1] = ((leftIntraDir + offset) % mod) + 2;
+          mpm[2] = ((leftIntraDir - 1) % mod) + 2;
+        }
+        else   // non-angular
+        {
+          mpm[0] = 2;
+          mpm[1] = HOR_IDX;
+          mpm[2] = VER_IDX;
+        }
+      }
+      else
+      {
+        numCand = 2;
+
+        if (leftIntraDir <= DC_IDX && aboveIntraDir <= DC_IDX) // both non-angular
+        {
+          mpm[0] = 2;
+          mpm[1] = HOR_IDX;
+          mpm[2] = VER_IDX;
+        }
+        else if (leftIntraDir <= DC_IDX) // left non-angular
+        {
+          mpm[0] = aboveIntraDir;
+          mpm[1] = ((aboveIntraDir + offset) % mod) + 2;
+          mpm[2] = ((aboveIntraDir - 1) % mod) + 2;
+        }
+        else if (aboveIntraDir <= DC_IDX) // above non-angular
+        {
+          mpm[0] = leftIntraDir;
+          mpm[1] = ((leftIntraDir + offset) % mod) + 2;
+          mpm[2] = ((leftIntraDir - 1) % mod) + 2;
+        }
+        else // both angular
+        {
+          mpm[0] = leftIntraDir;
+          mpm[1] = aboveIntraDir;
+          if (leftIntraDir == VER_IDX)
+          {
+            mpm[2] = aboveIntraDir == HOR_IDX ? 2 : HOR_IDX;
+          }
+          else if (leftIntraDir == HOR_IDX)
+          {
+            mpm[2] = aboveIntraDir == VER_IDX ? 2 : VER_IDX;
+          }
+          else
+          {
+            mpm[2] = aboveIntraDir == VER_IDX ? HOR_IDX : VER_IDX;
+          }
+        }
+      }
+    }
+    else
+    {
+#endif
+
     if (leftIntraDir == aboveIntraDir)
     {
       numCand = 1;
@@ -455,6 +597,9 @@ int PU::getIntraMPMs( const PredictionUnit &pu, unsigned* mpm, const ChannelType
         mpm[2] = (leftIntraDir + aboveIntraDir) < 2 ? VER_IDX : DC_IDX;
       }
     }
+#if JVET_L0283_MULTI_REF_LINE
+    }
+#endif
 #endif
     for (int i = 0; i < numMPMs; i++)
     {
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 2b517549724865c6326351b0fc351d64a1876d2b..633e15e33d06f016eca6666536bdc1c7b2cfebee 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -216,9 +216,17 @@ uint32_t getCtuAddr        (const Position& pos, const PreCalcValues &pcv);
 
 template<typename T, size_t N>
 #if JVET_L0054_MMVD
-uint32_t updateCandList(T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, size_t uiFastCandNum = N, int* iserttPos = nullptr)
+uint32_t updateCandList(T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList
+#if JVET_L0283_MULTI_REF_LINE
+  , static_vector<int, N>& extendRefList, int extendRef
+#endif  
+  , size_t uiFastCandNum = N, int* iserttPos = nullptr)
 #else
-uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, size_t uiFastCandNum = N )
+uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeList, static_vector<double, N>& candCostList
+#if JVET_L0283_MULTI_REF_LINE
+  , static_vector<int, N>& extendRefList, int extendRef
+#endif  
+  , size_t uiFastCandNum = N )
 #endif
 {
   CHECK( std::min( uiFastCandNum, candModeList.size() ) != std::min( uiFastCandNum, candCostList.size() ), "Sizes do not match!" );
@@ -239,9 +247,21 @@ uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeL
     {
       candModeList[currSize - i] = candModeList[currSize - 1 - i];
       candCostList[currSize - i] = candCostList[currSize - 1 - i];
+#if JVET_L0283_MULTI_REF_LINE
+      if (extendRef != -1)
+      {
+        extendRefList[currSize - i] = extendRefList[currSize - 1 - i];
+      }  
+#endif
     }
     candModeList[currSize - shift] = uiMode;
     candCostList[currSize - shift] = uiCost;
+#if JVET_L0283_MULTI_REF_LINE
+    if (extendRef != -1)
+    {
+      extendRefList[currSize - shift] = extendRef;
+    }
+#endif
 #if JVET_L0054_MMVD
     if (iserttPos != nullptr)
     {
@@ -254,6 +274,12 @@ uint32_t updateCandList( T uiMode, double uiCost, static_vector<T, N>& candModeL
   {
     candModeList.insert( candModeList.end() - shift, uiMode );
     candCostList.insert( candCostList.end() - shift, uiCost );
+#if JVET_L0283_MULTI_REF_LINE
+    if (extendRef != -1)
+    {
+      extendRefList.insert(extendRefList.end() - shift, extendRef);
+    }
+#endif
 #if JVET_L0054_MMVD
     if (iserttPos != nullptr)
     {
@@ -318,7 +344,7 @@ uint32_t updateDoubleCandList(T mode, double cost, static_vector<T, N>& candMode
 #if JVET_L0054_MMVD
     if (iserttPos != nullptr)
     {
-      *iserttPos = int(candModeList.size() - shift - 1);
+      *iserttPos = int(candModeList.size() - shift - 1);  
     }
 #endif
     return 1;
@@ -335,5 +361,4 @@ uint32_t updateDoubleCandList(T mode, double cost, static_vector<T, N>& candMode
 #endif
 
 
-#endif
-
+#endif
\ No newline at end of file
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index a4404254d4dcc5279e51691228bf5b248a260418..8b2c28b7ee4f5a4072fc2726bfb6df2b4614ac12 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -708,6 +708,10 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx&
   // --> create PUs
   CU::addPUs( cu );
 
+#if JVET_L0283_MULTI_REF_LINE
+  extend_ref_line( cu );
+#endif
+
   // pcm samples
   if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N )
   {
@@ -929,6 +933,46 @@ void CABACReader::xReadTruncBinCode(uint32_t& symbol, uint32_t maxSymbol)
   }
 }
 #endif
+#if JVET_L0283_MULTI_REF_LINE
+void CABACReader::extend_ref_line(CodingUnit& cu)
+{
+  if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType))
+  {
+    cu.firstPU->multiRefIdx = 0;
+    return;
+  }
+
+  const int numBlocks = CU::getNumPUs(cu);
+  PredictionUnit* pu = cu.firstPU;
+
+  for (int k = 0; k < numBlocks; k++)
+  {
+    bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
+    if (isFirstLineOfCtu)
+    {
+      pu->multiRefIdx = 0;
+      continue;
+    }
+    int multiRefIdx = 0;
+
+    if (MRL_NUM_REF_LINES > 1)
+    {
+      multiRefIdx = m_BinDecoder.decodeBin(Ctx::MultiRefLineIdx(0)) == 1 ? MULTI_REF_LINE_IDX[1] : MULTI_REF_LINE_IDX[0];
+      if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
+      {
+        multiRefIdx = m_BinDecoder.decodeBin(Ctx::MultiRefLineIdx(1)) == 1 ? MULTI_REF_LINE_IDX[2] : MULTI_REF_LINE_IDX[1];
+        if (MRL_NUM_REF_LINES > 3 && multiRefIdx != MULTI_REF_LINE_IDX[1])
+        {
+          multiRefIdx = m_BinDecoder.decodeBin(Ctx::MultiRefLineIdx(2)) == 1 ? MULTI_REF_LINE_IDX[3] : MULTI_REF_LINE_IDX[2];
+        }
+      }
+
+    }
+    pu->multiRefIdx = multiRefIdx;
+    pu = pu->next;
+  }
+}
+#endif
 
 void CABACReader::intra_luma_pred_modes( CodingUnit &cu )
 {
@@ -946,6 +990,14 @@ void CABACReader::intra_luma_pred_modes( CodingUnit &cu )
   int mpmFlag[4];
   for( int k = 0; k < numBlocks; k++ )
   {
+#if JVET_L0283_MULTI_REF_LINE
+    CHECK(numBlocks != 1, "not supported yet");
+    if (cu.firstPU->multiRefIdx)
+    {
+      mpmFlag[0] = true;
+    }
+    else
+#endif
     mpmFlag[k] = m_BinDecoder.decodeBin( Ctx::IPredMode[0]() );
   }
 
diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h
index 16699dcdf16d6bfa201ac7caebb89e50e8e5264a..10ce7a50e3478b054706a681eea9759f084ef530 100644
--- a/source/Lib/DecoderLib/CABACReader.h
+++ b/source/Lib/DecoderLib/CABACReader.h
@@ -82,6 +82,9 @@ public:
   void        cu_pred_data              ( CodingUnit&                   cu );
 #if JVET_L0646_GBI
   void        cu_gbi_flag               ( CodingUnit&                   cu );
+#endif
+#if JVET_L0283_MULTI_REF_LINE
+  void        extend_ref_line           (CodingUnit&                     cu);
 #endif
   void        intra_luma_pred_modes     ( CodingUnit&                   cu );
   void        intra_chroma_pred_modes   ( CodingUnit&                   cu );
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 4f3ec1ddd969d0daa4b297a34b5fb1606eba148b..66e1b1d0e9add550014bf61b6eb2dc4602013a5a 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -634,6 +634,10 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C
   // prediction mode and partitioning data
   pred_mode ( cu );
 
+#if JVET_L0283_MULTI_REF_LINE
+  extend_ref_line(cu);
+#endif
+
   // pcm samples
   if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N )
   {
@@ -815,6 +819,70 @@ void CABACWriter::xWriteTruncBinCode(uint32_t symbol, uint32_t maxSymbol)
 }
 #endif
 
+#if JVET_L0283_MULTI_REF_LINE
+void CABACWriter::extend_ref_line(const PredictionUnit& pu)
+{
+  const CodingUnit& cu = *pu.cu;
+  if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType))
+  {
+    return;
+  }
+  bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
+  if (isFirstLineOfCtu)
+  {
+    return;
+  }
+  int multiRefIdx = pu.multiRefIdx;
+  if (MRL_NUM_REF_LINES > 1)
+  {
+    m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0));
+    if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
+    {
+      m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1));
+      if (MRL_NUM_REF_LINES > 3 && multiRefIdx != MULTI_REF_LINE_IDX[1])
+      {
+        m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[2], Ctx::MultiRefLineIdx(2));
+      }
+    }
+  }
+}
+
+void CABACWriter::extend_ref_line(const CodingUnit& cu)
+{
+  if (!cu.Y().valid() || cu.predMode != MODE_INTRA || !isLuma(cu.chType))
+  {
+    return;
+  }
+
+  const int numBlocks = CU::getNumPUs(cu);
+  const PredictionUnit* pu = cu.firstPU;
+
+  for (int k = 0; k < numBlocks; k++)
+  {
+    bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
+    if (isFirstLineOfCtu)
+    {
+      return;
+    }
+    int multiRefIdx = pu->multiRefIdx;
+    if (MRL_NUM_REF_LINES > 1)
+    {
+      m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0));
+      if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
+      {
+        m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1));
+        if (MRL_NUM_REF_LINES > 3 && multiRefIdx != MULTI_REF_LINE_IDX[1])
+        {
+          m_BinEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[2], Ctx::MultiRefLineIdx(2));
+        }
+      }
+
+    }
+    pu = pu->next;
+  }
+}
+#endif
+
 void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu )
 {
   if( !cu.Y().valid() )
@@ -850,6 +918,13 @@ void CABACWriter::intra_luma_pred_modes( const CodingUnit& cu )
         break;
       }
     }
+#if JVET_L0283_MULTI_REF_LINE
+    if (pu->multiRefIdx)
+    {
+      CHECK(mpm_idx >= numMPMs, "use of non-MPM");
+    }
+    else
+#endif
     m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() );
 
     pu = pu->next;
@@ -936,6 +1011,13 @@ void CABACWriter::intra_luma_pred_mode( const PredictionUnit& pu )
       break;
     }
   }
+#if JVET_L0283_MULTI_REF_LINE
+  if (pu.multiRefIdx)
+  {
+    CHECK(mpm_idx >= numMPMs, "use of non-MPM");
+  }
+  else
+#endif
   m_BinEncoder.encodeBin( mpm_idx < numMPMs, Ctx::IPredMode[0]() );
 
   // mpm_idx / rem_intra_luma_pred_mode
diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h
index 2e25dcac24ec79910d933bb84b769415002a7a14..3e3a23e4ec53d2f598587742c99a6b2345f8a21f 100644
--- a/source/Lib/EncoderLib/CABACWriter.h
+++ b/source/Lib/EncoderLib/CABACWriter.h
@@ -95,6 +95,10 @@ public:
   void        cu_pred_data              ( const CodingUnit&             cu );
 #if JVET_L0646_GBI
   void        cu_gbi_flag               ( const CodingUnit&             cu );
+#endif
+#if JVET_L0283_MULTI_REF_LINE
+  void        extend_ref_line           (const PredictionUnit&          pu );
+  void        extend_ref_line           (const CodingUnit&              cu );
 #endif
   void        intra_luma_pred_modes     ( const CodingUnit&             cu );
   void        intra_luma_pred_mode      ( const PredictionUnit&         pu );
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index d459e98d14eca69498d786bf70caa3090f33f9be..940040d3e0584f746a0048f318a235cd42be46ca 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -1415,6 +1415,9 @@ void EncCu::xCheckRDCostIntra( CodingStructure *&tempCS, CodingStructure *&bestC
       m_CABACEstimator->cu_skip_flag ( cu );
     }
     m_CABACEstimator->pred_mode      ( cu );
+#if JVET_L0283_MULTI_REF_LINE
+    m_CABACEstimator->extend_ref_line( cu );
+#endif
     m_CABACEstimator->cu_pred_data   ( cu );
     m_CABACEstimator->pcm_data       ( cu );
 
@@ -1867,7 +1870,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if JVET_L0100_MULTI_HYPOTHESIS_INTRA
         updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
 #else
-        updateCandList(uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+#if JVET_L0283_MULTI_REF_LINE
+        static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
+#endif
+        updateCandList(uiMergeCand, cost, RdModeList, candCostList
+#if JVET_L0283_MULTI_REF_LINE
+          , *nullList, -1
+#endif          
+          , uiNumMrgSATDCand, &insertPos);
 #endif
         if (insertPos != -1)
         {
@@ -1889,7 +1899,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if JVET_L0100_MULTI_HYPOTHESIS_INTRA
         updateDoubleCandList(uiMergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand);
 #else
-        updateCandList( uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand );
+#if JVET_L0283_MULTI_REF_LINE
+        static_vector<int, MRG_MAX_NUM_CANDS> * nullList = nullptr;
+#endif
+        updateCandList( uiMergeCand, cost, RdModeList, candCostList
+#if JVET_L0283_MULTI_REF_LINE
+          , *nullList, -1
+#endif
+          , uiNumMrgSATDCand );
 #endif
 #endif
         CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
@@ -2071,7 +2088,14 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
 #if JVET_L0100_MULTI_HYPOTHESIS_INTRA
         updateDoubleCandList(mergeCand, cost, RdModeList, candCostList, RdModeList2, (uint32_t)NUM_LUMA_MODE, uiNumMrgSATDCand, &insertPos);
 #else
-        updateCandList(mergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand, &insertPos);
+#if JVET_L0283_MULTI_REF_LINE
+        static_vector<int, MRG_MAX_NUM_CANDS + MMVD_ADD_NUM> * nullList = nullptr;
+#endif
+        updateCandList(mergeCand, cost, RdModeList, candCostList
+#if JVET_L0283_MULTI_REF_LINE
+          , *nullList, -1
+#endif
+          , uiNumMrgSATDCand, &insertPos);
 #endif
         if (insertPos != -1)
         {
@@ -2500,7 +2524,14 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
 
       double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;
 
-      updateCandList( mergeCand, cost, triangleRdModeList, tianglecandCostList, triangleNumMrgSATDCand );
+#if JVET_L0283_MULTI_REF_LINE
+      static_vector<int, TRIANGLE_MAX_NUM_CANDS> * nullList = nullptr;
+#endif
+      updateCandList( mergeCand, cost, triangleRdModeList, tianglecandCostList
+#if JVET_L0283_MULTI_REF_LINE
+        , *nullList, -1
+#endif
+        , triangleNumMrgSATDCand );
     }
         
     // limit number of candidates using SATD-costs
@@ -2757,8 +2788,14 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
           uiBitsCand--;
         }
         double cost = (double)uiSad + (double)uiBitsCand * sqrtLambdaForFirstPass;
-
-        updateCandList( uiMergeCand, cost, RdModeList, candCostList, uiNumMrgSATDCand );
+#if JVET_L0283_MULTI_REF_LINE
+        static_vector<int, AFFINE_MRG_MAX_NUM_CANDS> * nullList = nullptr;
+#endif
+        updateCandList( uiMergeCand, cost, RdModeList, candCostList
+#if JVET_L0283_MULTI_REF_LINE
+          , *nullList, -1
+#endif
+          , uiNumMrgSATDCand );
 
         CHECK( std::min( uiMergeCand + 1, uiNumMrgSATDCand ) != RdModeList.size(), "" );
       }
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index bbdfb101941a67738530abe2c80717e1de239942..2e8376650e925ca594c81d6cd86793cb26d823be 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -317,12 +317,20 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
   static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandCostList;
   static_vector<double, FAST_UDI_MAX_RDMODE_NUM> CandHadList;
 
+#if JVET_L0283_MULTI_REF_LINE
+  static_vector<int, FAST_UDI_MAX_RDMODE_NUM> extendRefList;
+  static_vector<int, FAST_UDI_MAX_RDMODE_NUM>* nullList = NULL;
+#endif
+
   auto &pu = *cu.firstPU;
   int puIndex = 0;
   {
     CandHadList.clear();
     CandCostList.clear();
     uiHadModeList.clear();
+#if JVET_L0283_MULTI_REF_LINE
+    extendRefList.clear();
+#endif
 
     CHECK(pu.cu != &cu, "PU is not contained in the CU");
 
@@ -350,6 +358,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
     {
       // this should always be true
       CHECK( !pu.Y().valid(), "PU is not valid" );
+#if JVET_L0283_MULTI_REF_LINE
+      bool isFirstLineOfCtu = (((pu.block(COMPONENT_Y).y)&((pu.cs->sps)->getMaxCUWidth() - 1)) == 0);
+      int numOfPassesExtendRef = (isFirstLineOfCtu ? 1 : MRL_NUM_REF_LINES);
+      pu.multiRefIdx = 0;
+#endif
 
       //===== init pattern for luma prediction =====
       initIntraPatternChType( cu, pu.Y(), IntraPrediction::useFilteredIntraRefSamples( COMPONENT_Y, pu, false, pu ) );
@@ -409,13 +422,25 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
 
             DTRACE( g_trace_ctx, D_INTRA_COST, "IntraHAD: %u, %llu, %f (%d)\n", uiSad, fracModeBits, cost, uiMode );
 
-            updateCandList( uiMode, cost,  uiRdModeList, CandCostList, numModesForFullRD + extraModes );
-            updateCandList(uiMode, (double) uiSad, uiHadModeList, CandHadList, 3 + extraModes);
+            updateCandList( uiMode, cost,  uiRdModeList, CandCostList
+#if JVET_L0283_MULTI_REF_LINE
+              , extendRefList, 0
+#endif              
+              , numModesForFullRD + extraModes );
+            updateCandList(uiMode, (double) uiSad, uiHadModeList, CandHadList
+#if JVET_L0283_MULTI_REF_LINE
+              , *nullList, -1
+#endif              
+              , 3 + extraModes);
           }
         } // NSSTFlag
 
         // forget the extra modes
         uiRdModeList.resize( numModesForFullRD );
+#if JVET_L0283_MULTI_REF_LINE
+        CandCostList.resize(numModesForFullRD);
+        extendRefList.resize(numModesForFullRD);
+#endif
         static_vector<unsigned, FAST_UDI_MAX_RDMODE_NUM> parentCandList(FAST_UDI_MAX_RDMODE_NUM);
         std::copy_n(uiRdModeList.begin(), numModesForFullRD, parentCandList.begin());
 
@@ -453,19 +478,75 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
 
                 double cost = (double) sad + (double) fracModeBits * sqrtLambdaForFirstPass;
 
-                updateCandList(mode, cost, uiRdModeList, CandCostList, numModesForFullRD);
-                updateCandList(mode, (double)sad, uiHadModeList, CandHadList, 3);
+                updateCandList(mode, cost, uiRdModeList, CandCostList
+#if JVET_L0283_MULTI_REF_LINE
+                  , extendRefList, 0
+#endif
+                  , numModesForFullRD);
+                updateCandList(mode, (double)sad, uiHadModeList, CandHadList
+#if JVET_L0283_MULTI_REF_LINE
+                  , *nullList, -1
+#endif                 
+                  , 3);
 
                 bSatdChecked[mode] = true;
               }
             }
           }
         }
+#if JVET_L0283_MULTI_REF_LINE
+        pu.multiRefIdx = 1;
+        unsigned  numMPMs = pu.cs->pcv->numMPMs;
+        unsigned *multiRefMPM = (unsigned*)alloca(pu.cs->pcv->numMPMs * sizeof(unsigned));
+        PU::getIntraMPMs(pu, multiRefMPM);
+        for (int mRefNum = 1; mRefNum < numOfPassesExtendRef; mRefNum++)
+        {
+          int multiRefIdx = MULTI_REF_LINE_IDX[mRefNum];
+
+          pu.multiRefIdx = multiRefIdx;
+          {
+            initIntraPatternChType(cu, pu.Y(), IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, false, pu));
+          }
+          for (int x = 0; x < numMPMs; x++)
+          {
+            uint32_t mode = multiRefMPM[x];
+            {
+              pu.intraDir[0] = mode;
+
+              if (useDPCMForFirstPassIntraEstimation(pu, mode))
+              {
+                encPredIntraDPCM(COMPONENT_Y, piOrg, piPred, mode);
+              }
+              else
+              {
+                predIntraAng(COMPONENT_Y, piPred, pu, IntraPrediction::useFilteredIntraRefSamples(COMPONENT_Y, pu, true, pu));
+              }
+
+              // use Hadamard transform here
+              Distortion sad = distParam.distFunc(distParam);
+
+              // NB xFracModeBitsIntra will not affect the mode for chroma that may have already been pre-estimated.
+              m_CABACEstimator->getCtx() = SubCtx(Ctx::IPredMode[CHANNEL_TYPE_LUMA], ctxStartIntraMode);
+
+              uint64_t fracModeBits = xFracModeBitsIntra(pu, mode, CHANNEL_TYPE_LUMA);
+
+              double cost = (double)sad + (double)fracModeBits * sqrtLambdaForFirstPass;
+              updateCandList(mode, cost, uiRdModeList, CandCostList, extendRefList, multiRefIdx, numModesForFullRD);
+            }
+          }
+        }
+        CandCostList.resize(numModesForFullRD);
+        extendRefList.resize(numModesForFullRD);
+#endif
         if( m_pcEncCfg->getFastUDIUseMPMEnabled() )
         {
           unsigned  numMPMs = pu.cs->pcv->numMPMs;
           unsigned *uiPreds = ( unsigned* ) alloca( numMPMs * sizeof( unsigned ) );
 
+#if JVET_L0283_MULTI_REF_LINE
+          pu.multiRefIdx = 0;
+#endif
+
           const int numCand = PU::getIntraMPMs( pu, uiPreds );
 
           for( int j = 0; j < numCand; j++ )
@@ -476,10 +557,17 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
 
             for( int i = 0; i < numModesForFullRD; i++ )
             {
+#if JVET_L0283_MULTI_REF_LINE
+              mostProbableModeIncluded |= (mostProbableMode == uiRdModeList[i] && extendRefList[i] == 0);
+#else
               mostProbableModeIncluded |= ( mostProbableMode == uiRdModeList[i] );
+#endif
             }
             if( !mostProbableModeIncluded )
             {
+#if JVET_L0283_MULTI_REF_LINE
+              extendRefList.push_back(0);
+#endif
               numModesForFullRD++;
               uiRdModeList.push_back( mostProbableMode );
             }
@@ -498,6 +586,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
         // Store the modes to be checked with RD
         m_savedNumRdModes[puIndex] = numModesForFullRD;
         std::copy_n( uiRdModeList.begin(), numModesForFullRD, m_savedRdModeList[puIndex] );
+#if JVET_L0283_MULTI_REF_LINE
+        std::copy_n(extendRefList.begin(), numModesForFullRD, m_savedExtendRefList[puIndex]);
+#endif
       }
     }
     else //emtUsage = 2 (here we potentially reduce the number of modes that will be full-RD checked)
@@ -529,6 +620,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
           if( m_modeCostStore[puIndex][i] <= thresholdSkipMode * m_bestModeCostStore[puIndex] )
           {
             uiRdModeList.push_back( m_savedRdModeList[puIndex][i] );
+#if JVET_L0283_MULTI_REF_LINE
+            extendRefList.push_back(m_savedExtendRefList[puIndex][i]);
+#endif
             numModesForFullRD++;
           }
         }
@@ -539,6 +633,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
         numModesForFullRD = m_savedNumRdModes[puIndex];
         uiRdModeList.resize( numModesForFullRD );
         std::copy_n( m_savedRdModeList[puIndex], m_savedNumRdModes[puIndex], uiRdModeList.begin() );
+#if JVET_L0283_MULTI_REF_LINE
+        CandCostList.resize(numModesForFullRD);
+        extendRefList.resize(numModesForFullRD);
+        std::copy_n(m_savedExtendRefList[puIndex], m_savedNumRdModes[puIndex], extendRefList.begin());
+#endif
       }
     }
 
@@ -576,6 +675,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
     double dSecondBestPUCost = MAX_DOUBLE;
 #endif
     uint32_t       uiBestPUMode  = 0;
+#if JVET_L0283_MULTI_REF_LINE
+    int            bestExtendRef = 0;
+#endif
 
     CodingStructure *csTemp = m_pTempCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )];
     CodingStructure *csBest = m_pBestCS[gp_sizeIdxInfo->idxFrom( cu.lwidth() )][gp_sizeIdxInfo->idxFrom( cu.lheight() )];
@@ -593,6 +695,11 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
       uint32_t uiOrgMode = uiRdModeList[uiMode];
 
       pu.intraDir[0] = uiOrgMode;
+#if JVET_L0283_MULTI_REF_LINE
+      int multiRefIdx = extendRefList[uiMode];
+      pu.multiRefIdx  = multiRefIdx;
+      CHECK(pu.multiRefIdx && (pu.intraDir[0] == DC_IDX || pu.intraDir[0] == PLANAR_IDX), "ERL");
+#endif
 
 
       // set context models
@@ -622,6 +729,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
         dSecondBestPUCost = csTemp->cost;
 #endif
         uiBestPUMode  = uiOrgMode;
+#if JVET_L0283_MULTI_REF_LINE
+        bestExtendRef = multiRefIdx;
+#endif
 
         if( ( emtUsageFlag == 1 ) && m_pcEncCfg->getFastIntraEMT() )
         {
@@ -644,6 +754,9 @@ void IntraSearch::estIntraPredLumaQT( CodingUnit &cu, Partitioner &partitioner )
     csBest->releaseIntermediateData();
     //=== update PU data ====
     pu.intraDir[0] = uiBestPUMode;
+#if JVET_L0283_MULTI_REF_LINE
+    pu.multiRefIdx = bestExtendRef;
+#endif
   }
 
   //===== reset context models =====
@@ -978,6 +1091,9 @@ void IntraSearch::xEncIntraHeader(CodingStructure &cs, Partitioner &partitioner,
         m_CABACEstimator->cu_skip_flag( cu );
         m_CABACEstimator->pred_mode   ( cu );
       }
+#if JVET_L0283_MULTI_REF_LINE
+      m_CABACEstimator->extend_ref_line(cu);
+#endif
       if( CU::isIntra(cu) && cu.partSize == SIZE_2Nx2N )
       {
         m_CABACEstimator->pcm_data( cu );
@@ -1918,9 +2034,15 @@ uint64_t IntraSearch::xFracModeBitsIntra(PredictionUnit &pu, const uint32_t &uiM
       m_CABACEstimator->MHIntra_luma_pred_modes(*pu.cu);
     else
     {
+#if JVET_L0283_MULTI_REF_LINE
+      m_CABACEstimator->extend_ref_line(pu);
+#endif
       m_CABACEstimator->intra_luma_pred_mode(pu);
     }
 #else
+#if JVET_L0283_MULTI_REF_LINE
+    m_CABACEstimator->extend_ref_line(pu);
+#endif
     m_CABACEstimator->intra_luma_pred_mode( pu );
 #endif
   }
diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h
index 424f78da79fb42c1554a766a6494ae446f8d175d..ca9ae80e86a051f02485fbf2bd06b29fcf05fd25 100644
--- a/source/Lib/EncoderLib/IntraSearch.h
+++ b/source/Lib/EncoderLib/IntraSearch.h
@@ -78,6 +78,9 @@ private:
   double m_bestModeCostStore[4];                                    // RD cost of the best mode for each PU using DCT2
   double m_modeCostStore    [4][NUM_LUMA_MODE];                         // RD cost of each mode for each PU using DCT2
   uint32_t   m_savedRdModeList  [4][NUM_LUMA_MODE], m_savedNumRdModes[4];
+#if JVET_L0283_MULTI_REF_LINE
+  int        m_savedExtendRefList[4][NUM_LUMA_MODE];
+#endif
 
 protected:
   // interface to option