diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp
index 573358b74760a58601c227ed83c4ed3645831125..a28133ff38f2f16daf1e76e333f2fee56e7180e8 100644
--- a/source/App/EncoderApp/EncApp.cpp
+++ b/source/App/EncoderApp/EncApp.cpp
@@ -290,6 +290,9 @@ void EncApp::xInitLibCfg()
   m_cEncLib.setMMVD                                              ( m_MMVD );
   m_cEncLib.setMmvdDisNum                                        (m_MmvdDisNum);
   m_cEncLib.setRDPCM                                              ( m_RdpcmMode );
+#if JVET_O0119_BASE_PALETTE_444
+  m_cEncLib.setPLTMode											 ( m_PLTMode);
+#endif
   m_cEncLib.setIBCMode                                           ( m_IBCMode );
   m_cEncLib.setIBCLocalSearchRangeX                              ( m_IBCLocalSearchRangeX );
   m_cEncLib.setIBCLocalSearchRangeY                              ( m_IBCLocalSearchRangeY );
diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp
index ef215530217ef29335e185a47f542afef723e0ae..71207368941f621b7c350273bab1014fe9141cbd 100644
--- a/source/App/EncoderApp/EncAppCfg.cpp
+++ b/source/App/EncoderApp/EncAppCfg.cpp
@@ -900,7 +900,10 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
   ("AffineAmvrEncOpt",                                m_AffineAmvrEncOpt,                               false, "Enable encoder optimization of affine AMVR")
   ("DMVR",                                            m_DMVR,                                           false, "Decoder-side Motion Vector Refinement")
   ("MmvdDisNum",                                      m_MmvdDisNum,                                     8,     "Number of MMVD Distance Entries")
-  ( "RDPCM",                                         m_RdpcmMode,                                       false, "RDPCM")
+  ( "RDPCM",                                          m_RdpcmMode,                                       false, "RDPCM")
+#if JVET_O0119_BASE_PALETTE_444
+  ("PLT",											  m_PLTMode,										   0u, "PLTMode (0x1:enabled, 0x0:disabled)  [default: disabled]")
+#endif
   ( "IBC",                                            m_IBCMode,                                           0u, "IBCMode (0x1:enabled, 0x0:disabled)  [default: disabled]")
   ( "IBCLocalSearchRangeX",                           m_IBCLocalSearchRangeX,                            128u, "Search range of IBC local search in x direction")
   ( "IBCLocalSearchRangeY",                           m_IBCLocalSearchRangeY,                            128u, "Search range of IBC local search in y direction")
@@ -2181,7 +2184,10 @@ bool EncAppCfg::xCheckParameter()
 #endif
     xConfirmPara( m_LMChroma, "LMChroma only allowed with NEXT profile" );
     xConfirmPara( m_ImvMode, "IMV is only allowed with NEXT profile" );
-    xConfirmPara(m_IBCMode, "IBC Mode only allowed with NEXT profile");
+#if JVET_O0119_BASE_PALETTE_444
+	xConfirmPara( m_PLTMode, "PLT Mode only allowed with NEXT profile");
+#endif
+	xConfirmPara(m_IBCMode, "IBC Mode only allowed with NEXT profile");
     xConfirmPara( m_HashME, "Hash motion estimation only allowed with NEXT profile" );
     xConfirmPara( m_useFastLCTU, "Fast large CTU can only be applied when encoding with NEXT profile" );
     xConfirmPara( m_MTS, "MTS only allowed with NEXT profile" );
@@ -3367,6 +3373,10 @@ void EncAppCfg::xPrintParameter()
     msg(VERBOSE, "MmvdDisNum:%d ", m_MmvdDisNum);
     msg(VERBOSE, "RDPCM:%d ", m_RdpcmMode );
   }
+#if JVET_O0119_BASE_PALETTE_444
+    m_PLTMode = ( m_chromaFormatIDC == CHROMA_444) ? m_PLTMode : 0u;
+    msg(VERBOSE, "PLT:%d ", m_PLTMode);
+#endif
     msg(VERBOSE, "IBC:%d ", m_IBCMode);
   msg( VERBOSE, "HashME:%d ", m_HashME );
   msg( VERBOSE, "WrapAround:%d ", m_wrapAround);
diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h
index d8bf7be18f069c1f38b5b122e87ccfea3145b6ec..4938a1d0dcfab4034955f2d41bc626698f84df6b 100644
--- a/source/App/EncoderApp/EncAppCfg.h
+++ b/source/App/EncoderApp/EncAppCfg.h
@@ -283,6 +283,9 @@ protected:
   bool      m_MMVD;
   int       m_MmvdDisNum;
   bool      m_RdpcmMode;
+#if JVET_O0119_BASE_PALETTE_444
+  unsigned  m_PLTMode;
+#endif
   unsigned  m_IBCMode;
   unsigned  m_IBCLocalSearchRangeX;
   unsigned  m_IBCLocalSearchRangeY;
diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h
index 5c287d84f7402454d793450f58b932a65c7a0d36..37421bbf40ae5bf6ae2ae00ebbe46d5d390c64ad 100644
--- a/source/Lib/CommonLib/Buffer.h
+++ b/source/Lib/CommonLib/Buffer.h
@@ -164,6 +164,13 @@ typedef AreaBuf<const TCoeff> CCoeffBuf;
 typedef AreaBuf<      MotionInfo>  MotionBuf;
 typedef AreaBuf<const MotionInfo> CMotionBuf;
 
+#if JVET_O0119_BASE_PALETTE_444
+typedef AreaBuf<      TCoeff>  PLTescapeBuf;
+typedef AreaBuf<const TCoeff> CPLTescapeBuf;
+
+typedef AreaBuf<      bool>	   PLTtypeBuf;
+typedef AreaBuf<const bool>	  CPLTtypeBuf;
+#endif
 
 #define SIZE_AWARE_PER_EL_OP( OP, INC )                     \
 if( ( width & 7 ) == 0 )                                    \
diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp
index 84ffabcac71ccc790cabb5ff1ee995b20724ffe9..3df44f2c9b3127516eaad3b4f5b483b788ec0d1a 100644
--- a/source/Lib/CommonLib/CodingStructure.cpp
+++ b/source/Lib/CommonLib/CodingStructure.cpp
@@ -72,6 +72,10 @@ CodingStructure::CodingStructure(CUCache& cuCache, PUCache& puCache, TUCache& tu
   {
     m_coeffs[ i ] = nullptr;
     m_pcmbuf[ i ] = nullptr;
+#if JVET_O0119_BASE_PALETTE_444
+	m_runType[i] = nullptr;
+	m_runLength[i] = nullptr;
+#endif
 
     m_offsets[ i ] = 0;
   }
@@ -501,6 +505,10 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c
 
   TCoeff *coeffs[5] = { nullptr, nullptr, nullptr, nullptr, nullptr };
   Pel    *pcmbuf[5] = { nullptr, nullptr, nullptr, nullptr, nullptr };
+#if JVET_O0119_BASE_PALETTE_444 
+  bool	 *runType[5]   = { nullptr, nullptr, nullptr, nullptr, nullptr };
+  Pel    *runLength[5] = { nullptr, nullptr, nullptr, nullptr, nullptr };
+#endif
 
   uint32_t numCh = ::getNumberValidComponents( area.chromaFormat );
 
@@ -537,12 +545,20 @@ TransformUnit& CodingStructure::addTU( const UnitArea &unit, const ChannelType c
 
     coeffs[i] = m_coeffs[i] + m_offsets[i];
     pcmbuf[i] = m_pcmbuf[i] + m_offsets[i];
+#if JVET_O0119_BASE_PALETTE_444
+	runType[i]   = m_runType[i]   + m_offsets[i];
+	runLength[i] = m_runLength[i] + m_offsets[i];
+#endif
 
     unsigned areaSize = tu->blocks[i].area();
     m_offsets[i] += areaSize;
   }
 
+#if JVET_O0119_BASE_PALETTE_444
+  tu->init( coeffs, pcmbuf, runLength, runType);
+#else
   tu->init( coeffs, pcmbuf );
+#endif
 
   return *tu;
 }
@@ -705,6 +721,64 @@ void CodingStructure::addMiToLut(static_vector<MotionInfo, MAX_NUM_HMVP_CANDS> &
   lut.push_back(mi);
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+void CodingStructure::resetPrevPLT(PLTBuf& prevPLT)
+{
+	for (int comp = 0; comp < MAX_NUM_COMPONENT; comp++)
+	{
+		prevPLT.curPLTSize[comp] = 0;
+		memset(prevPLT.curPLT[comp], 0, MAXPLTPREDSIZE * sizeof(Pel));
+	}
+}
+
+void CodingStructure::reorderPrevPLT(PLTBuf& prevPLT, uint32_t curPLTSize[MAX_NUM_COMPONENT], Pel curPLT[MAX_NUM_COMPONENT][MAXPLTSIZE], bool reuseflag[MAX_NUM_COMPONENT][MAXPLTPREDSIZE], uint32_t compBegin, uint32_t NumComp, bool jointPLT)
+{
+	Pel stuffedPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE];
+	uint32_t tempCurPLTsize[MAX_NUM_COMPONENT];
+	uint32_t stuffPLTsize[MAX_NUM_COMPONENT];
+
+	for (int i = compBegin; i < (compBegin + NumComp); i++)
+	{
+		ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+		tempCurPLTsize[comID] = curPLTSize[comID];
+		stuffPLTsize[i] = 0;
+		memcpy(stuffedPLT[i], curPLT[i], curPLTSize[comID] * sizeof(Pel));
+	}
+
+	for (int ch = compBegin; ch < (compBegin + NumComp); ch++)
+	{
+		ComponentID comID = jointPLT ? (ComponentID)compBegin : ((ch > 0) ? COMPONENT_Cb : COMPONENT_Y);
+		if (ch > 1) break;
+		for (int i = 0; i < prevPLT.curPLTSize[comID]; i++)
+		{
+			if (tempCurPLTsize[comID] + stuffPLTsize[ch] >= MAXPLTPREDSIZE)
+				break;
+
+			if (!reuseflag[comID][i])
+			{
+				if (ch == COMPONENT_Y)
+				{
+					stuffedPLT[0][tempCurPLTsize[comID] + stuffPLTsize[ch]] = prevPLT.curPLT[0][i];
+				}
+				else
+				{
+					stuffedPLT[1][tempCurPLTsize[comID] + stuffPLTsize[ch]] = prevPLT.curPLT[1][i];
+					stuffedPLT[2][tempCurPLTsize[comID] + stuffPLTsize[ch]] = prevPLT.curPLT[2][i];
+				}
+				stuffPLTsize[ch]++;
+			}
+		}
+	}
+
+	for (int i = compBegin; i < (compBegin + NumComp); i++)
+	{
+		ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+		prevPLT.curPLTSize[comID] = curPLTSize[comID] + stuffPLTsize[comID];
+		memcpy(prevPLT.curPLT[i], stuffedPLT[i], prevPLT.curPLTSize[comID] * sizeof(Pel));
+	}
+}
+#endif
+
 void CodingStructure::rebindPicBufs()
 {
   CHECK( parent, "rebindPicBufs can only be used for the top level CodingStructure" );
@@ -732,6 +806,10 @@ void CodingStructure::createCoeffs()
 
     m_coeffs[i] = _area > 0 ? ( TCoeff* ) xMalloc( TCoeff, _area ) : nullptr;
     m_pcmbuf[i] = _area > 0 ? ( Pel*    ) xMalloc( Pel,    _area ) : nullptr;
+#if JVET_O0119_BASE_PALETTE_444
+	m_runType[i]   = _area > 0 ? (bool*)xMalloc( bool, _area) : nullptr;
+	m_runLength[i] = _area > 0 ? (Pel*) xMalloc( Pel,  _area) : nullptr;
+#endif
   }
 }
 
@@ -741,6 +819,10 @@ void CodingStructure::destroyCoeffs()
   {
     if( m_coeffs[i] ) { xFree( m_coeffs[i] ); m_coeffs[i] = nullptr; }
     if( m_pcmbuf[i] ) { xFree( m_pcmbuf[i] ); m_pcmbuf[i] = nullptr; }
+#if JVET_O0119_BASE_PALETTE_444
+	if (m_runType[i])   { xFree(m_runType[i]);	 m_runType[i]   = nullptr; }
+	if (m_runLength[i]) { xFree(m_runLength[i]); m_runLength[i] = nullptr; }
+#endif
   }
 }
 
@@ -784,6 +866,10 @@ void CodingStructure::initSubStructure( CodingStructure& subStruct, const Channe
 
   subStruct.motionLut = motionLut;
 
+#if JVET_O0119_BASE_PALETTE_444
+  subStruct.prevPLT = prevPLT;
+#endif
+
   subStruct.initStructData( currQP[_chType], isLossless );
 
   if( isTuEnc )
@@ -845,6 +931,10 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C
 
     motionLut = subStruct.motionLut;
   }
+#if JVET_O0119_BASE_PALETTE_444
+  prevPLT = subStruct.prevPLT;
+#endif
+
 #if ENABLE_WPP_PARALLELISM
 
   if( nullptr == parent )
@@ -1027,6 +1117,9 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel
 
     motionLut = other.motionLut;
   }
+#if JVET_O0119_BASE_PALETTE_444
+  prevPLT = other.prevPLT;
+#endif
 
   if( copyTUs )
   {
diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h
index aa41d96111a05bcd4ef733a685e2dc232ec67569..1c9b86ee7169fbfac71eb72f119cb457d1054ba8 100644
--- a/source/Lib/CommonLib/CodingStructure.h
+++ b/source/Lib/CommonLib/CodingStructure.h
@@ -197,6 +197,11 @@ public:
 
   void addMiToLut(static_vector<MotionInfo, MAX_NUM_HMVP_CANDS>& lut, const MotionInfo &mi);
 
+#if JVET_O0119_BASE_PALETTE_444
+  PLTBuf prevPLT;
+  void resetPrevPLT(PLTBuf& prevPLT);
+  void reorderPrevPLT(PLTBuf& prevPLT, uint32_t curPLTSize[MAX_NUM_COMPONENT], Pel curPLT[MAX_NUM_COMPONENT][MAXPLTSIZE], bool reuseflag[MAX_NUM_COMPONENT][MAXPLTPREDSIZE], uint32_t compBegin, uint32_t NumComp, bool jointPLT);
+#endif
 private:
 
   // needed for TU encoding
@@ -224,7 +229,10 @@ private:
 
   TCoeff *m_coeffs [ MAX_NUM_COMPONENT ];
   Pel    *m_pcmbuf [ MAX_NUM_COMPONENT ];
-
+#if JVET_O0119_BASE_PALETTE_444
+  bool   *m_runType  [MAX_NUM_COMPONENT];
+  Pel    *m_runLength[MAX_NUM_COMPONENT];
+#endif
   int     m_offsets[ MAX_NUM_COMPONENT ];
 
   MotionInfo *m_motionBuf;
diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h
index 36dd1f45f6e57e451bd2341e0eb4e08a7ec53c80..39a5ffbdaf7bb7701c6fc9a66ca99aa565d7fade 100644
--- a/source/Lib/CommonLib/CommonDef.h
+++ b/source/Lib/CommonLib/CommonDef.h
@@ -469,6 +469,14 @@ static const int CSCALE_FP_PREC =                                11;
 static const int  NEIG_NUM_LOG  =                                 6;
 static const int  NEIG_NUM =                      1 << NEIG_NUM_LOG;
 #endif
+#if JVET_O0119_BASE_PALETTE_444
+static const int MAXPLTPREDSIZE = 63;
+static const int MAXPLTSIZE = 31;
+static const int PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE = 4;
+static const int PLT_RUN_MSB_IDX_CTX_T1 = 1;
+static const int PLT_RUN_MSB_IDX_CTX_T2 = 3;
+static const int PLT_FAST_RATIO = 100;
+#endif
 #if RExt__DECODER_DEBUG_TOOL_MAX_FRAME_STATS
 static const int  EPBIN_WEIGHT_FACTOR =                           4;
 #endif
diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp
index 0241a7569425fba2a5ad31e4e079f70533d15a08..58b75c8ce8e52e827b7c667c5a144c515017e191 100644
--- a/source/Lib/CommonLib/Contexts.cpp
+++ b/source/Lib/CommonLib/Contexts.cpp
@@ -679,6 +679,48 @@ const CtxSet ContextSetCfg::LFNSTIdx = ContextSetCfg::addCtxSet
   {   8,   8, },
 } );
 
+#if JVET_O0119_BASE_PALETTE_444
+const CtxSet ContextSetCfg::PLTFlag = ContextSetCfg::addCtxSet
+({
+	{ 146 },
+	{ 146 },
+	{ 147 },
+	{ 1 }
+});
+
+const CtxSet ContextSetCfg::RotationFlag = ContextSetCfg::addCtxSet
+({
+	{ 153 },
+	{ 138 },
+	{ 168 },
+	{ 5 }
+});
+
+const CtxSet ContextSetCfg::RunTypeFlag = ContextSetCfg::addCtxSet
+({
+	{ 167 },
+	{ 167 },
+	{ 167 },
+	{ 8 }
+});
+
+const CtxSet ContextSetCfg::IdxRunModel = ContextSetCfg::addCtxSet
+({
+	{ 157, 169, 138, 170, 155 },
+	{ 186, 169, 166, 186, 185 },
+	{ 155, 168, 167, 155, 154 },
+	{ 5,   6,   5,   9,  10 }
+});
+
+const CtxSet ContextSetCfg::CopyRunModel = ContextSetCfg::addCtxSet
+({
+	{ 187, 172, 156 },
+	{ 187, 187, 185 },
+	{ 201, 171, 155 },
+	{ 0,   5,   5 }
+});
+#endif
+
 const CtxSet ContextSetCfg::RdpcmFlag = ContextSetCfg::addCtxSet
 ({
   { CNU, CNU, },
@@ -905,6 +947,9 @@ const unsigned ContextSetCfg::NumberOfContexts = (unsigned)ContextSetCfg::sm_Ini
 
 
 // combined sets
+#if JVET_O0119_BASE_PALETTE_444 
+const CtxSet ContextSetCfg::Palette = { ContextSetCfg::RotationFlag, ContextSetCfg::RunTypeFlag, ContextSetCfg::IdxRunModel, ContextSetCfg::CopyRunModel };
+#endif
 const CtxSet ContextSetCfg::Sao = { ContextSetCfg::SaoMergeFlag, ContextSetCfg::SaoTypeIdx };
 
 const CtxSet ContextSetCfg::Alf = { ContextSetCfg::ctbAlfFlag, ContextSetCfg::AlfUseLatestFilt, ContextSetCfg::AlfUseTemporalFilt };
diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h
index 10654ba93fbe654ae28846e2601f516b8e7a15db..c6e9b71b3860bf2b6eb9b728b3064db0e081cd94 100644
--- a/source/Lib/CommonLib/Contexts.h
+++ b/source/Lib/CommonLib/Contexts.h
@@ -248,6 +248,13 @@ public:
   static const CtxSet   MTSIndex;
   static const CtxSet   TransquantBypassFlag;
   static const CtxSet   LFNSTIdx;
+#if JVET_O0119_BASE_PALETTE_444
+  static const CtxSet   PLTFlag;
+  static const CtxSet   RotationFlag;
+  static const CtxSet   RunTypeFlag;
+  static const CtxSet   IdxRunModel;    
+  static const CtxSet   CopyRunModel;    
+#endif
   static const CtxSet   RdpcmFlag;
   static const CtxSet   RdpcmDir;
   static const CtxSet   SbtFlag;
@@ -274,6 +281,9 @@ public:
   // NOTE: The contained CtxSet's should directly follow each other in the initalization list;
   //       otherwise, you will copy more elements than you want !!!
   static const CtxSet   Sao;
+#if JVET_O0119_BASE_PALETTE_444
+  static const CtxSet   Palette;
+#endif
 
 public:
   static const std::vector<uint8_t>&  getInitTable( unsigned initId );
diff --git a/source/Lib/CommonLib/IntraPrediction.cpp b/source/Lib/CommonLib/IntraPrediction.cpp
index e63eab3936eb31bffd0d610777f59f260350d768..6185fc70caa48bad10ca61be5dbda1928acc0b5a 100644
--- a/source/Lib/CommonLib/IntraPrediction.cpp
+++ b/source/Lib/CommonLib/IntraPrediction.cpp
@@ -175,6 +175,10 @@ void IntraPrediction::destroy()
   m_piTemp = nullptr;
   delete[] m_pMdlmTemp;
   m_pMdlmTemp = nullptr;
+#if JVET_O0119_BASE_PALETTE_444
+  if (m_runTypeRD) { xFree(m_runTypeRD);	 m_runTypeRD = NULL; }
+  if (m_runLengthRD) { xFree(m_runLengthRD); m_runLengthRD = NULL; }
+#endif
 }
 
 void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepthY)
@@ -226,6 +230,10 @@ void IntraPrediction::init(ChromaFormat chromaFormatIDC, const unsigned bitDepth
   {
     m_pMdlmTemp = new Pel[(2 * MAX_CU_SIZE + 1)*(2 * MAX_CU_SIZE + 1)];//MDLM will use top-above and left-below samples.
   }
+#if JVET_O0119_BASE_PALETTE_444
+  m_runTypeRD = (bool*)xMalloc(bool, MAX_CU_SIZE*MAX_CU_SIZE);
+  m_runLengthRD = (Pel*)xMalloc(Pel, MAX_CU_SIZE*MAX_CU_SIZE);
+#endif
 }
 
 // ====================================================================================================================
@@ -1928,4 +1936,150 @@ void IntraPrediction::predIntraMip( const ComponentID compId, PelBuf &piPred, co
   m_matrixIntraPred.predBlock( pu.Y(), pu.intraDir[CHANNEL_TYPE_LUMA], piPred, bitDepth );
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+bool IntraPrediction::calCopyRun(CodingStructure &cs, Partitioner& partitioner, uint32_t uiStartPos, uint32_t uiTotal, uint32_t &uiRun, ComponentID compBegin)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+	TransformUnit &tu = *cs.getTU(partitioner.chType);
+	PelBuf curPLTIdx = tu.getcurPLTIdx(compBegin);
+	PLTtypeBuf runType = tu.getrunType(compBegin);
+
+	uint32_t uiIdx = uiStartPos;
+	uint32_t uiX;
+	uint32_t uiY;
+	bool valid = false;
+	uiRun = 0;
+	while (uiIdx < uiTotal)
+	{
+		uiX = m_puiScanOrder[uiIdx].x;
+		uiY = m_puiScanOrder[uiIdx].y;
+		runType.at(uiX, uiY) = PLT_RUN_COPY;
+
+		if (uiY == 0 && !cu.useRotation[compBegin])
+		{
+			return false;
+		}
+		if (uiX == 0 && cu.useRotation[compBegin])
+		{
+			return false;
+		}
+		if (!cu.useRotation[compBegin] && curPLTIdx.at(uiX, uiY) == curPLTIdx.at(uiX, uiY - 1))
+		{
+			uiRun++;
+			valid = true;
+		}
+		else if (cu.useRotation[compBegin] && curPLTIdx.at(uiX, uiY) == curPLTIdx.at(uiX - 1, uiY))
+		{
+			uiRun++;
+			valid = true;
+		}
+		else
+		{
+			break;
+		}
+		uiIdx++;
+	}
+	return valid;
+}
+bool IntraPrediction::calIndexRun(CodingStructure &cs, Partitioner& partitioner, uint32_t uiStartPos, uint32_t uiTotal, uint32_t &uiRun, ComponentID compBegin)
+{
+	TransformUnit &tu = *cs.getTU(partitioner.chType);
+	PelBuf curPLTIdx = tu.getcurPLTIdx(compBegin);
+	PLTtypeBuf runType = tu.getrunType(compBegin);
+
+	uiRun = 1;
+	uint32_t uiIdx = uiStartPos;
+	while (uiIdx < uiTotal)
+	{
+		uint32_t uiX = m_puiScanOrder[uiIdx].x;
+		uint32_t uiY = m_puiScanOrder[uiIdx].y;
+		runType.at(uiX, uiY) = PLT_RUN_INDEX;
+
+		uint32_t uiXprev = uiIdx == 0 ? 0 : m_puiScanOrder[uiIdx - 1].x;
+		uint32_t uiYprev = uiIdx == 0 ? 0 : m_puiScanOrder[uiIdx - 1].y;
+		if (uiIdx > uiStartPos && curPLTIdx.at(uiX, uiY) == curPLTIdx.at(uiXprev, uiYprev))
+		{
+			uiRun++;
+		}
+		else if (uiIdx > uiStartPos)
+		{
+			break;
+		}
+		uiIdx++;
+	}
+	return true;
+}
+void IntraPrediction::reorderPLT(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+
+	uint32_t       reusePLTSizetmp = 0;
+	uint32_t       PLTSizetmp = 0;
+	Pel            curPLTtmp[MAX_NUM_COMPONENT][MAXPLTSIZE];
+	bool           curPLTpred[MAXPLTPREDSIZE];
+
+	for (int idx = 0; idx < MAXPLTPREDSIZE; idx++)
+	{
+		curPLTpred[idx] = false;
+		cu.reuseflag[compBegin][idx] = false;
+	}
+	for (int idx = 0; idx < MAXPLTSIZE; idx++)
+	{
+		curPLTpred[idx] = false;
+	}
+
+	for (int predidx = 0; predidx < cs.prevPLT.curPLTSize[compBegin]; predidx++)
+	{
+		bool match = false;
+		int curidx = 0;
+
+		for (curidx = 0; curidx < cu.curPLTSize[compBegin]; curidx++)
+		{
+			bool matchTmp = true;
+			for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+			{
+				matchTmp = matchTmp && (cu.curPLT[comp][curidx] == cs.prevPLT.curPLT[comp][predidx]);
+			}
+			if (matchTmp)
+			{
+				match = true;
+				break;
+			}
+		}
+
+		if (match)
+		{
+			cu.reuseflag[compBegin][predidx] = true;
+			curPLTpred[curidx] = true;
+			for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+			{
+				curPLTtmp[comp][reusePLTSizetmp] = cs.prevPLT.curPLT[comp][predidx];
+			}
+			reusePLTSizetmp++;
+			PLTSizetmp++;
+		}
+	}
+	cu.reusePLTSize[compBegin] = reusePLTSizetmp;
+	for (int curidx = 0; curidx < cu.curPLTSize[compBegin]; curidx++)
+	{
+		if (!curPLTpred[curidx])
+		{
+			for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+			{
+				curPLTtmp[comp][PLTSizetmp] = cu.curPLT[comp][curidx];
+			}
+			PLTSizetmp++;
+		}
+	}
+	assert(PLTSizetmp == cu.curPLTSize[compBegin]);
+	for (int curidx = 0; curidx < cu.curPLTSize[compBegin]; curidx++)
+	{
+		for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+		{
+			cu.curPLT[comp][curidx] = curPLTtmp[comp][curidx];
+		}
+	}
+}
+#endif
+
 //! \}
diff --git a/source/Lib/CommonLib/IntraPrediction.h b/source/Lib/CommonLib/IntraPrediction.h
index 901eff09510182201e29f9b11ad7836403f65ee6..ede6cf18a12dcc71d09654398ed628bc04a90ba3 100644
--- a/source/Lib/CommonLib/IntraPrediction.h
+++ b/source/Lib/CommonLib/IntraPrediction.h
@@ -108,12 +108,23 @@ private:
   Pel* m_pMdlmTemp; // for MDLM mode
   MatrixIntraPrediction m_matrixIntraPred;
 
-protected:
 
+
+protected:
   ChromaFormat  m_currChromaFormat;
 
   int m_topRefLength;
   int m_leftRefLength;
+#if JVET_O0119_BASE_PALETTE_444
+  ScanElement*          m_puiScanOrder;
+  bool					m_bBestScanRotationMode;
+  Ctx					m_storeCtx_Run;
+  Ctx					m_storeCtx_RunIndex;
+  Ctx					m_storeCtx_RunCopy; 
+  Ctx					m_orgCtxRD;
+  bool					*m_runTypeRD;
+  Pel					*m_runLengthRD;
+#endif
   // prediction
   void xPredIntraPlanar           ( const CPelBuf &pSrc, PelBuf &pDst );
   void xPredIntraDc               ( const CPelBuf &pSrc, PelBuf &pDst, const ChannelType channelType, const bool enableBoundaryFilter = true );
@@ -163,6 +174,11 @@ public:
   Pel* getPredictorPtr2           (const ComponentID compID, uint32_t idx) { return m_yuvExt2[compID][idx]; }
   void switchBuffer               (const PredictionUnit &pu, ComponentID compID, PelBuf srcBuff, Pel *dst);
   void geneIntrainterPred         (const CodingUnit &cu);
+#if JVET_O0119_BASE_PALETTE_444
+  void       reorderPLT(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp);
+  bool       calCopyRun(CodingStructure &cs, Partitioner& partitioner, uint32_t uiStartPos, uint32_t uiTotal, uint32_t &uiRun, ComponentID compBegin);
+  bool       calIndexRun(CodingStructure &cs, Partitioner& partitioner, uint32_t uiStartPos, uint32_t uiTotal, uint32_t &uiRun, ComponentID compBegin);
+#endif
 };
 
 //! \}
diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp
index e0e76f57c977f463054b9be4c9efd407cf5ee075..1355384d2f20c7f011a7141bbc244004f04bfc4e 100644
--- a/source/Lib/CommonLib/LoopFilter.cpp
+++ b/source/Lib/CommonLib/LoopFilter.cpp
@@ -821,6 +821,9 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg
   const SPS     &sps      = *(cu.cs->sps);
   const Slice   &slice    = *(cu.slice);
   const bool    ppsTransquantBypassEnabledFlag = pps.getTransquantBypassEnabledFlag();
+#if JVET_O0119_BASE_PALETTE_444
+  const bool    spsPaletteEnabledFlag = sps.getPLTMode();
+#endif
   const int     bitDepthLuma                   = sps.getBitDepth(CHANNEL_TYPE_LUMA);
   const ClpRng& clpRng( cu.cs->slice->clpRng(COMPONENT_Y) );
 
@@ -984,6 +987,14 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg
             bPartPNoFilter = bPartPNoFilter || cuP.transQuantBypass;
             bPartQNoFilter = bPartQNoFilter || cuQ.transQuantBypass;
           }
+#if JVET_O0119_BASE_PALETTE_444
+		  if (spsPaletteEnabledFlag)
+		  {
+			// check if each of PUs is palette coded
+			bPartPNoFilter = bPartPNoFilter || CU::isPLT(cuP);
+			bPartQNoFilter = bPartQNoFilter || CU::isPLT(cuQ);
+		  }
+#endif
 
           if (dL < iBeta)
           {
@@ -1029,6 +1040,14 @@ void LoopFilter::xEdgeFilterLuma( const CodingUnit& cu, const DeblockEdgeDir edg
           bPartPNoFilter = bPartPNoFilter || cuP.transQuantBypass;
           bPartQNoFilter = bPartQNoFilter || cuQ.transQuantBypass;
         }
+#if JVET_O0119_BASE_PALETTE_444
+		if ( spsPaletteEnabledFlag)
+		{
+		  // check if each of PUs is palette coded
+		  bPartPNoFilter = bPartPNoFilter || CU::isPLT(cuP);
+		  bPartQNoFilter = bPartQNoFilter || CU::isPLT(cuQ);
+		}
+#endif
 
         if( d < iBeta )
         {
@@ -1169,6 +1188,14 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed
         bPartPNoFilter = bPartPNoFilter || cuP.transQuantBypass;
         bPartQNoFilter = bPartQNoFilter || cuQ.transQuantBypass;
       }
+#if JVET_O0119_BASE_PALETTE_444
+	  if ( sps.getPLTMode())
+	  {
+		// check if each of PUs is palette coded
+	    bPartPNoFilter = bPartPNoFilter || CU::isPLT(cuP);
+		bPartQNoFilter = bPartQNoFilter || CU::isPLT(cuQ);
+	  }
+#endif
 
       const int maxFilterLengthP = m_maxFilterLengthP[COMPONENT_Cb][(pos.x-m_ctuXLumaSamples)>>m_shiftHor][(pos.y-m_ctuYLumaSamples)>>m_shiftVer];
       const int maxFilterLengthQ = m_maxFilterLengthQ[COMPONENT_Cb][(pos.x-m_ctuXLumaSamples)>>m_shiftHor][(pos.y-m_ctuYLumaSamples)>>m_shiftVer];
diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp
index b3e3d9f9b588d2d0366592c1a5dc553c4b3977ae..d13e022a680be6e6401cab48c7aece9a110bfbed 100644
--- a/source/Lib/CommonLib/Picture.cpp
+++ b/source/Lib/CommonLib/Picture.cpp
@@ -932,6 +932,9 @@ void Picture::finalInit(const SPS& sps, const PPS& pps, APS** alfApss, APS& lmcs
   }
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+bool doPlt = true;
+#endif
 void Picture::allocateNewSlice()
 {
   slices.push_back(new Slice);
diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp
index e32c236eafd10652f87536d1831ca1c2808d9077..dc2339c545a5333500c9d5f217979bd0474f7519 100644
--- a/source/Lib/CommonLib/Rom.cpp
+++ b/source/Lib/CommonLib/Rom.cpp
@@ -53,7 +53,9 @@ CDTrace *g_trace_ctx = NULL;
 #endif
 bool g_mctsDecCheckEnabled = false;
 
-
+#if JVET_O0119_BASE_PALETTE_444
+static void g_initMsbP1IdxLut();
+#endif
 //! \ingroup CommonLib
 //! \{
 
@@ -129,7 +131,53 @@ public:
           m_line--;
         }
         break;
-
+#if JVET_O0119_BASE_PALETTE_444
+	  case SCAN_TRAV_HOR:
+	  {
+		  if (m_line % 2 == 0)
+		  {
+			  if (m_column == (m_blockWidth - 1))
+			  {
+				  m_line++;
+				  m_column = m_blockWidth - 1;
+			  }
+			  else m_column++;
+		  }
+		  else
+		  {
+			  if (m_column == 0)
+			  {
+				  m_line++;
+				  m_column = 0;
+			  }
+			  else m_column--;
+		  }
+	  }
+	  break;
+	  //------------------------------------------------
+	  case SCAN_TRAV_VER:
+	  {
+		  if (m_column % 2 == 0)
+		  {
+			  if (m_line == (m_blockHeight - 1))
+			  {
+				  m_column++;
+				  m_line = m_blockHeight - 1;
+			  }
+			  else m_line++;
+		  }
+		  else
+		  {
+			  if (m_line == 0)
+			  {
+				  m_column++;
+				  m_line = 0;
+			  }
+			  else m_line--;
+		  }
+	  }
+	  break;
+#endif
       //------------------------------------------------
 
       default:
@@ -222,6 +270,9 @@ void initROM()
 {
   int c;
 
+#if JVET_O0119_BASE_PALETTE_444
+  g_initMsbP1IdxLut();
+#endif
   // g_aucConvertToBit[ x ]: log2(x/4), if x=4 -> 0, x=8 -> 1, x=16 -> 2, ...
   // g_aucLog2[ x ]: log2(x), if x=1 -> 0, x=2 -> 1, x=4 -> 2, x=8 -> 3, x=16 -> 4, ...
   ::memset(g_aucLog2, 0, sizeof(g_aucLog2));
@@ -762,4 +813,33 @@ Mv   g_reusedUniMVs[32][32][8][8][2][33];
 bool g_isReusedUniMVsFilled[32][32][8][8];
 #endif
 
+#if JVET_O0119_BASE_PALETTE_444
+const uint8_t g_uhPLTQuant[52] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 24, 23, 25, 26, 28, 29, 31, 32, 34, 36, 37, 39, 41, 42, 45 };
+uint8_t g_ucRunTopLut[5] = { 0, 1, 1, 2, 2 };
+uint8_t g_ucRunLeftLut[5] = { 0, 3, 3, 4, 4 };
+uint8_t g_ucMsbP1Idx[256];
+static void g_initMsbP1IdxLut()
+{
+	g_ucMsbP1Idx[0] = 0; g_ucMsbP1Idx[1] = 1;
+	uint32_t val = 2;
+	for (uint32_t idx = 2; idx <= 8; idx++)
+	{
+		for (int i = val - 1; i >= 0; i--)
+		{
+			g_ucMsbP1Idx[val++] = idx;
+		}
+	}
+}
+
+uint8_t g_getMsbP1Idx(uint32_t uiVal)
+{
+	uint8_t idx = 0;
+	while (uiVal > 255)
+	{
+		uiVal >>= 8;
+		idx += 8;
+	}
+	return idx + g_ucMsbP1Idx[uiVal];
+}
+#endif
 //! \}
diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h
index 877b947d770bd924ac19bc529bd2c5bef5b89cde..a11618016ebc0347d7d136db2e9cbe63b078706c 100644
--- a/source/Lib/CommonLib/Rom.h
+++ b/source/Lib/CommonLib/Rom.h
@@ -59,6 +59,7 @@ void         destroyROM();
 // Data structure related table & variable
 // ====================================================================================================================
 
+
 // flexible conversion from relative to absolute index
 struct ScanElement
 {
@@ -232,5 +233,13 @@ extern Mv   g_reusedUniMVs[32][32][8][8][2][33];
 extern bool g_isReusedUniMVsFilled[32][32][8][8];
 #endif
 
+#if JVET_O0119_BASE_PALETTE_444
+extern const uint8_t g_uhPLTQuant[52];
+extern uint8_t g_ucRunTopLut[5];
+extern uint8_t g_ucRunLeftLut[5];
+extern uint8_t g_ucMsbP1Idx[256];
+extern uint8_t g_getMsbP1Idx(uint32_t uiVal);
+#endif
+
 #endif  //__TCOMROM__
 
diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
index febb1dde94239ecd9d12f3f8493eda293b852e62..dc836d3306d5eac0375ae7162e586c1df0495023 100644
--- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
+++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp
@@ -728,8 +728,13 @@ void SampleAdaptiveOffset::xPCMCURestoration(CodingStructure& cs, const UnitArea
 
 void SampleAdaptiveOffset::xPCMSampleRestoration(CodingUnit& cu, const ComponentID compID)
 {
+#if JVET_O0119_BASE_PALETTE_444
+  if (CU::isPLT(cu))
+  {
+	  return;
+  }
+#endif
   const CompArea& ca = cu.block(compID);
-
   if( CU::isLosslessCoded( cu ) && !cu.ipcm )
   {
     for( auto &currTU : CU::traverseTUs( cu ) )
diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp
index f5001fbc74512227e1bfe5590dbea59f7011a629..589656199dfde2a51ead0b90337b2c8f6172d634 100644
--- a/source/Lib/CommonLib/Slice.cpp
+++ b/source/Lib/CommonLib/Slice.cpp
@@ -1428,6 +1428,9 @@ SPS::SPS()
 , m_wrapAroundEnabledFlag     (false)
 , m_wrapAroundOffset          (  0)
 , m_IBCFlag                   (  0)
+#if JVET_O0119_BASE_PALETTE_444
+, m_PLTMode                   (  0)
+#endif
 , m_lumaReshapeEnable         (false)
 , m_AMVREnabledFlag                       ( false )
 , m_LMChroma                  ( false )
diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h
index 19d77128a931869d30df3c57696e21ac7a0f6d3d..a113db8460238523bd59b2c003d84fb6e4ac7f50 100644
--- a/source/Lib/CommonLib/Slice.h
+++ b/source/Lib/CommonLib/Slice.h
@@ -47,7 +47,9 @@
 #include "ChromaFormat.h"
 #include "Common.h"
 #include "HRD.h"
-
+#if JVET_O0119_BASE_PALETTE_444
+#include <unordered_map>
+#endif
 //! \ingroup CommonLib
 //! \{
 #include "CommonLib/MotionInfo.h"
@@ -780,6 +782,9 @@ private:
   bool              m_wrapAroundEnabledFlag;
   unsigned          m_wrapAroundOffset;
   unsigned          m_IBCFlag;
+#if JVET_O0119_BASE_PALETTE_444
+  unsigned			m_PLTMode;
+#endif
 
   bool              m_lumaReshapeEnable;
   bool              m_AMVREnabledFlag;
@@ -998,6 +1003,10 @@ public:
   bool                    getUseReshaper() const                                                          { return m_lumaReshapeEnable;                                                }
   void                    setIBCFlag(unsigned IBCFlag)                                                    { m_IBCFlag = IBCFlag; }
   unsigned                getIBCFlag() const                                                              { return m_IBCFlag; }
+#if JVET_O0119_BASE_PALETTE_444
+  void					  setPLTMode(unsigned PLTMode)													  { m_PLTMode = PLTMode; }
+  unsigned				  getPLTMode() const															  { return m_PLTMode; }
+#endif
   void                    setUseSBT( bool b )                                                             { m_SBT = b; }
   bool                    getUseSBT() const                                                               { return m_SBT; }
   void                    setUseISP( bool b )                                                             { m_ISP = b; }
@@ -1849,6 +1858,11 @@ public:
 protected:
   Picture*              xGetRefPic        (PicList& rcListPic, int poc);
   Picture*              xGetLongTermRefPic(PicList& rcListPic, int poc, bool pocHasMsb);
+#if JVET_O0119_BASE_PALETTE_444
+public:
+	std::unordered_map< Position, std::unordered_map< Size, double> > m_mapPltCost;
+private:
+#endif
 };// END CLASS DEFINITION Slice
 
 void calculateParameterSetChangedFlag(bool &bChanged, const std::vector<uint8_t> *pOldData, const std::vector<uint8_t> *pNewData);
diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h
index 5cbc8d6a413b0a7bc4b86707191964ba206a6d1c..16c693db3896dcd6e513cdcc45c959d01a86cce1 100644
--- a/source/Lib/CommonLib/TypeDef.h
+++ b/source/Lib/CommonLib/TypeDef.h
@@ -50,6 +50,8 @@
 #include <assert.h>
 #include <cassert>
 
+#define JVET_O0119_BASE_PALETTE_444                       1 // JVET-O0119: Palette mode in HEVC and palette mode signaling in JVET-N0258. Only enabled for YUV444.    
+
 #define JVET_O1136_TS_BDPCM_SIGNALLING                    1 // JVET-O1136: Unified syntax for JVET-O0165/O0200/O0783 on TS and BDPCM signalling
 
 #define JVET_O0219_LFNST_TRANSFORM_SET_FOR_LMCMODE        1
@@ -552,7 +554,12 @@ enum PredMode
   MODE_INTER                 = 0,     ///< inter-prediction mode
   MODE_INTRA                 = 1,     ///< intra-prediction mode
   MODE_IBC                   = 2,     ///< ibc-prediction mode
+#if JVET_O0119_BASE_PALETTE_444
+  MODE_PLT = 3,     ///< plt-prediction mode
+  NUMBER_OF_PREDICTION_MODES = 4,
+#else
   NUMBER_OF_PREDICTION_MODES = 3,
+#endif
 };
 
 /// reference list index
@@ -678,6 +685,10 @@ enum MESearchMethod
 enum CoeffScanType
 {
   SCAN_DIAG = 0,        ///< up-right diagonal scan
+#if JVET_O0119_BASE_PALETTE_444
+  SCAN_TRAV_HOR = 1,
+  SCAN_TRAV_VER = 2,
+#endif
   SCAN_NUMBER_OF_TYPES
 };
 
@@ -999,6 +1010,110 @@ struct BitDepths
   int recon[MAX_NUM_CHANNEL_TYPE]; ///< the bit depth as indicated in the SPS
 };
 
+#if JVET_O0119_BASE_PALETTE_444
+#define PLT_ENCBITDEPTH  8
+enum PLTRunMode
+{
+	PLT_RUN_INDEX = 0,
+	PLT_RUN_COPY = 1,
+	NUM_PLT_RUN = 2
+};
+enum PLTScanMode
+{
+	PLT_SCAN_HORTRAV = 0,
+	PLT_SCAN_VERTRAV = 1,
+	NUM_PLT_SCAN = 2
+};
+class SortingElement
+{
+public:
+	uint32_t uiCnt;
+	int uiData[3];
+	int uiShift, uiLastCnt, uiSumData[3];
+	inline bool operator<(const SortingElement &other) const
+	{
+		return uiCnt > other.uiCnt;
+	}
+	SortingElement() {
+		uiCnt = uiShift = uiLastCnt = 0;
+		uiData[0] = uiData[1] = uiData[2] = 0;
+		uiSumData[0] = uiSumData[1] = uiSumData[2] = 0;
+	}
+	void resetAll(ComponentID compBegin, uint32_t NumComp) {
+		uiShift = uiLastCnt = 0;
+		for (int ch = compBegin; ch < (compBegin + NumComp); ch++)
+		{
+			uiData[ch] = 0;
+			uiSumData[ch] = 0;
+		}
+	}
+	void setAll(uint32_t* ui, ComponentID compBegin, uint32_t NumComp) {
+		for (int ch = compBegin; ch < (compBegin + NumComp); ch++)
+		{
+			uiData[ch] = ui[ch];
+		}
+	}
+	bool almostEqualData(SortingElement sElement, int iErrorLimit, const BitDepths& bitDepths, ComponentID compBegin, uint32_t NumComp)
+	{
+		bool bAlmostEqual = true;
+		for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+		{		
+			ChannelType chType = (comp > 0) ? CHANNEL_TYPE_CHROMA : CHANNEL_TYPE_LUMA;
+			if ((std::abs(uiData[comp] - sElement.uiData[comp]) >> (bitDepths.recon[chType] - PLT_ENCBITDEPTH)) > iErrorLimit)
+			{
+				bAlmostEqual = false;
+				break;
+			}
+		}
+		return bAlmostEqual;
+	}
+	uint32_t getSAD(SortingElement sElement, const BitDepths& bitDepths, ComponentID compBegin, uint32_t NumComp)
+	{
+		uint32_t uiSAD = 0;
+		for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+		{		
+			ChannelType chType = (comp > 0) ? CHANNEL_TYPE_CHROMA : CHANNEL_TYPE_LUMA;
+			uiSAD += (std::abs(uiData[comp] - sElement.uiData[comp]) >> (bitDepths.recon[chType] - PLT_ENCBITDEPTH));
+		}
+		return uiSAD;
+	}
+	void copyDataFrom(SortingElement sElement, ComponentID compBegin, uint32_t NumComp) {
+		for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+		{
+			uiData[comp] = sElement.uiData[comp];
+			uiSumData[comp] = uiData[comp];
+		}
+		uiShift = 0; uiLastCnt = 1;
+	}
+	void copyAllFrom(SortingElement sElement, ComponentID compBegin, uint32_t NumComp) {
+		copyDataFrom(sElement, compBegin, NumComp);
+		uiCnt = sElement.uiCnt;
+		for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+		{
+			uiSumData[comp] = sElement.uiSumData[comp];
+		}
+		uiLastCnt = sElement.uiLastCnt; uiShift = sElement.uiShift;
+	}
+	void addElement(const SortingElement& sElement, ComponentID compBegin, uint32_t NumComp)
+	{
+		uiCnt++;
+		for (int i = compBegin; i<(compBegin + NumComp); i++)
+		{
+			uiSumData[i] += sElement.uiData[i];
+		}
+		if (uiCnt>1 && uiCnt == 2 * uiLastCnt)
+		{
+			uint32_t uiRnd = 1 << uiShift;
+			uiShift++;
+			for (int i = compBegin; i<(compBegin + NumComp); i++)
+			{
+				uiData[i] = (uiSumData[i] + uiRnd) >> uiShift;
+			}
+			uiLastCnt = uiCnt;
+		}
+	}
+};
+#endif
 /// parameters for deblocking filter
 struct LFCUParam
 {
diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp
index 74a3cc0ec6952f1ad9fffc7a7190dcd94d78d326..bfa6cd283c093cf590a7c3b251d67d9b3948ad4d 100644
--- a/source/Lib/CommonLib/Unit.cpp
+++ b/source/Lib/CommonLib/Unit.cpp
@@ -287,7 +287,18 @@ CodingUnit& CodingUnit::operator=( const CodingUnit& other )
   smvdMode        = other.smvdMode;
   ispMode           = other.ispMode;
   mipFlag           = other.mipFlag;
-
+#if JVET_O0119_BASE_PALETTE_444
+  for (int idx = 0; idx < MAX_NUM_COMPONENT; idx++)
+  {
+	  curPLTSize[idx] = other.curPLTSize[idx];
+	  useEscape[idx] = other.useEscape[idx];
+	  useRotation[idx] = other.useRotation[idx];
+	  reusePLTSize[idx] = other.reusePLTSize[idx];
+	  lastPLTSize[idx] = other.lastPLTSize[idx];
+	  memcpy(curPLT[idx], other.curPLT[idx], MAXPLTSIZE * sizeof(Pel));
+	  memcpy(reuseflag[idx], other.reuseflag[idx], MAXPLTPREDSIZE * sizeof(bool));
+  }
+#endif
   return *this;
 }
 
@@ -325,6 +336,18 @@ void CodingUnit::initData()
   smvdMode        = 0;
   ispMode           = 0;
   mipFlag           = false;
+#if JVET_O0119_BASE_PALETTE_444
+  for (int idx = 0; idx < MAX_NUM_COMPONENT; idx++)
+  {
+	  curPLTSize[idx] = 0;
+	  reusePLTSize[idx] = 0;
+	  lastPLTSize[idx] = 0;
+	  useEscape[idx] = false;
+	  useRotation[idx] = false;
+	  memset(curPLT[idx], 0, MAXPLTSIZE * sizeof(Pel));
+	  memset(reuseflag[idx], false, MAXPLTPREDSIZE * sizeof(bool));
+  }
+#endif
 }
 
 #if JVET_O1124_ALLOW_CCLM_COND
@@ -409,7 +432,11 @@ const uint8_t CodingUnit::checkAllowedSbt() const
   }
 
   //check on prediction mode
+#if JVET_O0119_BASE_PALETTE_444
+  if (predMode == MODE_INTRA || predMode == MODE_IBC || predMode == MODE_PLT) //intra, palette or IBC
+#else
   if( predMode == MODE_INTRA || predMode == MODE_IBC ) //intra or IBC
+#endif
   {
     return 0;
   }
@@ -667,6 +694,10 @@ TransformUnit::TransformUnit(const UnitArea& unit) : UnitArea(unit), cu(nullptr)
   {
     m_coeffs[i] = nullptr;
     m_pcmbuf[i] = nullptr;
+#if JVET_O0119_BASE_PALETTE_444
+	m_runType[i] = nullptr;
+	m_runLength[i] = nullptr;
+#endif
   }
 
   initData();
@@ -678,6 +709,10 @@ TransformUnit::TransformUnit(const ChromaFormat _chromaFormat, const Area &_area
   {
     m_coeffs[i] = nullptr;
     m_pcmbuf[i] = nullptr;
+#if JVET_O0119_BASE_PALETTE_444
+	m_runType[i] = nullptr;
+	m_runLength[i] = nullptr;
+#endif
   }
 
   initData();
@@ -698,7 +733,11 @@ void TransformUnit::initData()
   m_chromaResScaleInv = 0;
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+void TransformUnit::init(TCoeff **coeffs, Pel **pcmbuf, Pel **runLength, bool **runType)
+#else
 void TransformUnit::init(TCoeff **coeffs, Pel **pcmbuf)
+#endif
 {
   uint32_t numBlocks = getNumberValidTBlocks(*cs->pcv);
 
@@ -706,6 +745,10 @@ void TransformUnit::init(TCoeff **coeffs, Pel **pcmbuf)
   {
     m_coeffs[i] = coeffs[i];
     m_pcmbuf[i] = pcmbuf[i];
+#if JVET_O0119_BASE_PALETTE_444
+	m_runType[i] = runType[i];
+	m_runLength[i] = runLength[i];
+#endif
   }
 }
 
@@ -722,6 +765,10 @@ TransformUnit& TransformUnit::operator=(const TransformUnit& other)
 
     if (m_coeffs[i] && other.m_coeffs[i] && m_coeffs[i] != other.m_coeffs[i]) memcpy(m_coeffs[i], other.m_coeffs[i], sizeof(TCoeff) * area);
     if (m_pcmbuf[i] && other.m_pcmbuf[i] && m_pcmbuf[i] != other.m_pcmbuf[i]) memcpy(m_pcmbuf[i], other.m_pcmbuf[i], sizeof(Pel   ) * area);
+#if JVET_O0119_BASE_PALETTE_444
+	if (m_runType[i] && other.m_runType[i] && m_runType[i] != other.m_runType[i])	memcpy(m_runType[i], other.m_runType[i], sizeof(bool) * area);
+	if (m_runLength[i] && other.m_runLength[i] && m_runLength[i] != other.m_runLength[i])   memcpy(m_runLength[i], other.m_runLength[i], sizeof(Pel) * area);
+#endif
 
     cbf[i]           = other.cbf[i];
     rdpcm[i]         = other.rdpcm[i];
@@ -744,6 +791,10 @@ void TransformUnit::copyComponentFrom(const TransformUnit& other, const Componen
 
   if (m_coeffs[i] && other.m_coeffs[i] && m_coeffs[i] != other.m_coeffs[i]) memcpy(m_coeffs[i], other.m_coeffs[i], sizeof(TCoeff) * area);
   if (m_pcmbuf[i] && other.m_pcmbuf[i] && m_pcmbuf[i] != other.m_pcmbuf[i]) memcpy(m_pcmbuf[i], other.m_pcmbuf[i], sizeof(Pel   ) * area);
+#if JVET_O0119_BASE_PALETTE_444
+  if (m_runType[i] && other.m_runType[i] && m_runType[i] != other.m_runType[i]) memcpy(m_runType[i], other.m_runType[i], sizeof(bool) * area);
+  if (m_runLength[i] && other.m_runLength[i] && m_runLength[i] != other.m_runLength[i]) memcpy(m_runLength[i], other.m_runLength[i], sizeof(Pel) * area);
+#endif
 
   cbf[i]           = other.cbf[i];
   rdpcm[i]         = other.rdpcm[i];
@@ -761,6 +812,24 @@ const CCoeffBuf TransformUnit::getCoeffs(const ComponentID id) const { return CC
        PelBuf   TransformUnit::getPcmbuf(const ComponentID id)       { return  PelBuf  (m_pcmbuf[id], blocks[id]); }
 const CPelBuf   TransformUnit::getPcmbuf(const ComponentID id) const { return CPelBuf  (m_pcmbuf[id], blocks[id]); }
 
+#if JVET_O0119_BASE_PALETTE_444
+		PelBuf		TransformUnit::getcurPLTIdx(const ComponentID id) { return  PelBuf(m_pcmbuf[id], blocks[id]); }
+ const CPelBuf		TransformUnit::getcurPLTIdx(const ComponentID id)   const { return CPelBuf(m_pcmbuf[id], blocks[id]); }
+
+		PelBuf		TransformUnit::getrunLength(const ComponentID id) { return  PelBuf(m_runLength[id], blocks[id]); }
+ const CPelBuf		TransformUnit::getrunLength(const ComponentID id)	 const { return CPelBuf(m_runLength[id], blocks[id]); }
+
+		PLTtypeBuf  TransformUnit::getrunType(const ComponentID id) { return  PLTtypeBuf(m_runType[id], blocks[id]); }
+ const CPLTtypeBuf  TransformUnit::getrunType(const ComponentID id)   const { return CPLTtypeBuf(m_runType[id], blocks[id]); }
+
+		PLTescapeBuf   TransformUnit::getescapeValue(const ComponentID id) { return  PLTescapeBuf(m_coeffs[id], blocks[id]); }
+ const CPLTescapeBuf   TransformUnit::getescapeValue(const ComponentID id)  const { return CPLTescapeBuf(m_coeffs[id], blocks[id]); }
+
+		Pel*  TransformUnit::get_vPLTIdx(const ComponentID id) { return  m_pcmbuf[id]; }
+		Pel*  TransformUnit::get_vRunLength(const ComponentID id) { return  m_runLength[id]; }
+		bool*  TransformUnit::get_vRunType(const ComponentID id) { return  m_runType[id]; }
+#endif
+
 void TransformUnit::checkTuNoResidual( unsigned idx )
 {
   if( CU::getSbtIdx( cu->sbtInfo ) == SBT_OFF_DCT )
diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h
index 16645400555f2678b53607cf743124a64b2d5c1a..d9be95f775c5f5ad1e203fcc2ffa88533bc4ef55 100644
--- a/source/Lib/CommonLib/Unit.h
+++ b/source/Lib/CommonLib/Unit.h
@@ -48,7 +48,12 @@
 // ---------------------------------------------------------------------------
 // tools
 // ---------------------------------------------------------------------------
-
+#if JVET_O0119_BASE_PALETTE_444
+struct PLTBuf {
+	uint32_t       curPLTSize[MAX_NUM_COMPONENT];
+	Pel            curPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE];
+};
+#endif
 inline Position recalcPosition(const ChromaFormat _cf, const ComponentID srcCId, const ComponentID dstCId, const Position &pos)
 {
   if( toChannelType( srcCId ) == toChannelType( dstCId ) )
@@ -322,6 +327,15 @@ struct CodingUnit : public UnitArea
   Size           shareParentSize;
   uint8_t          smvdMode;
   uint8_t        ispMode;
+#if JVET_O0119_BASE_PALETTE_444
+  bool           useEscape[MAX_NUM_COMPONENT];
+  bool			 useRotation[MAX_NUM_COMPONENT];
+  bool           reuseflag[MAX_NUM_COMPONENT][MAXPLTPREDSIZE];
+  uint32_t       lastPLTSize[MAX_NUM_COMPONENT];
+  uint32_t       reusePLTSize[MAX_NUM_COMPONENT];
+  uint32_t       curPLTSize[MAX_NUM_COMPONENT];
+  Pel            curPLT[MAX_NUM_COMPONENT][MAXPLTSIZE];
+#endif
 
   CodingUnit() : chType( CH_L ) { }
   CodingUnit(const UnitArea &unit);
@@ -461,7 +475,11 @@ struct TransformUnit : public UnitArea
   TransformUnit *next;
   TransformUnit *prev;
 
+#if JVET_O0119_BASE_PALETTE_444
+  void init(TCoeff **coeffs, Pel **pcmbuf, Pel **runLength, bool **runType);
+#else
   void init(TCoeff **coeffs, Pel **pcmbuf);
+#endif
 
   TransformUnit& operator=(const TransformUnit& other);
   void copyComponentFrom  (const TransformUnit& other, const ComponentID compID);
@@ -476,6 +494,19 @@ struct TransformUnit : public UnitArea
   const CPelBuf   getPcmbuf(const ComponentID id) const;
         int       getChromaAdj( )                 const;
         void      setChromaAdj(int i);
+#if JVET_O0119_BASE_PALETTE_444
+		 PelBuf			getcurPLTIdx(const ComponentID id);
+  const CPelBuf			getcurPLTIdx(const ComponentID id) const;
+		 PelBuf			getrunLength(const ComponentID id);
+  const CPelBuf			getrunLength(const ComponentID id) const;
+		 PLTtypeBuf		getrunType(const ComponentID id);
+  const CPLTtypeBuf		getrunType(const ComponentID id) const;
+		 PLTescapeBuf	getescapeValue(const ComponentID id);
+  const CPLTescapeBuf   getescapeValue(const ComponentID id) const;
+		Pel*  get_vPLTIdx(const ComponentID id);
+		Pel*  get_vRunLength(const ComponentID id);
+		bool* get_vRunType(const ComponentID id);
+#endif
 
 #if ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
   int64_t cacheId;
@@ -485,6 +516,10 @@ struct TransformUnit : public UnitArea
 private:
   TCoeff *m_coeffs[ MAX_NUM_TBLOCKS ];
   Pel    *m_pcmbuf[ MAX_NUM_TBLOCKS ];
+#if JVET_O0119_BASE_PALETTE_444
+  bool   *m_runType[MAX_NUM_TBLOCKS];
+  Pel    *m_runLength[MAX_NUM_TBLOCKS];
+#endif
 };
 
 // ---------------------------------------------------------------------------
diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp
index 3aec86d1c7ecd686ae3016706a192622e5ba08ab..92d465ac909e40cde5b390863303cb923a440248 100644
--- a/source/Lib/CommonLib/UnitTools.cpp
+++ b/source/Lib/CommonLib/UnitTools.cpp
@@ -115,6 +115,13 @@ bool CU::isIBC(const CodingUnit &cu)
   return cu.predMode == MODE_IBC;
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+bool CU::isPLT(const CodingUnit &cu)
+{
+  return cu.predMode == MODE_PLT;
+}
+#endif
+
 bool CU::isRDPCMEnabled(const CodingUnit& cu)
 {
   return cu.cs->sps->getSpsRangeExtension().getRdpcmEnabledFlag(cu.predMode == MODE_INTRA ? RDPCM_SIGNAL_IMPLICIT : RDPCM_SIGNAL_EXPLICIT);
diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h
index 4423e858dd4b5a70a93fc0c4473909a679954872..97ac2972e4c123ad869ea576035e6fa24332195b 100644
--- a/source/Lib/CommonLib/UnitTools.h
+++ b/source/Lib/CommonLib/UnitTools.h
@@ -59,6 +59,9 @@ namespace CU
   bool isIntra                        (const CodingUnit &cu);
   bool isInter                        (const CodingUnit &cu);
   bool isIBC                          (const CodingUnit &cu);
+#if JVET_O0119_BASE_PALETTE_444
+  bool isPLT						  (const CodingUnit &cu);
+#endif
   bool isRDPCMEnabled                 (const CodingUnit &cu);
   bool isLosslessCoded                (const CodingUnit &cu);
   uint32_t getIntraSizeIdx                (const CodingUnit &cu);
diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp
index ec56ab3e564a02fdfbb05529dbe4e622e59ddc15..62467bd579ee52d6f1e51d77b2ca919e5ddb98e2 100644
--- a/source/Lib/DecoderLib/CABACReader.cpp
+++ b/source/Lib/DecoderLib/CABACReader.cpp
@@ -602,6 +602,34 @@ bool CABACReader::coding_tree( CodingStructure& cs, Partitioner& partitioner, CU
 
   bool isLastCtu = coding_unit( cu, partitioner, cuCtx );
 
+#if JVET_O0119_BASE_PALETTE_444
+  uint32_t compBegin;
+  uint32_t NumComp;
+  bool jointPLT = false;
+  if (CS::isDualITree(*cu.cs))
+  {
+	  if (isLuma(partitioner.chType))
+	  {
+		  compBegin = COMPONENT_Y;
+		  NumComp = 1;
+	  }
+	  else
+	  {
+		  compBegin = COMPONENT_Cb;
+		  NumComp = 2;
+	  }
+  }
+  else
+  {
+	  compBegin = COMPONENT_Y;
+	  NumComp = 3;
+	  jointPLT = true;
+  }
+  if (CU::isPLT(cu))
+  {
+	  cs.reorderPrevPLT(cs.prevPLT, cu.curPLTSize, cu.curPLT, cu.reuseflag, compBegin, NumComp, jointPLT);
+  }
+#endif
   DTRACE( g_trace_ctx, D_QP, "x=%d, y=%d, w=%d, h=%d, qp=%d\n", cu.Y().x, cu.Y().y, cu.Y().width, cu.Y().height, cu.qp );
   if (startShareThisLevel == 1)
     shareStateDec = NO_SHARE;
@@ -724,6 +752,28 @@ bool CABACReader::coding_unit( CodingUnit &cu, Partitioner &partitioner, CUCtx&
 
   // prediction mode and partitioning data
   pred_mode ( cu );
+#if JVET_O0119_BASE_PALETTE_444
+  if (CU::isPLT(cu))
+  {
+	  cs.addTU(cu, partitioner.chType);
+	  if (CS::isDualITree(*cu.cs))
+	  {
+		  if (isLuma(partitioner.chType))
+		  {
+			  cu_palette_info(cu, COMPONENT_Y, 1, cuCtx);
+		  }
+		  if (cu.chromaFormat != CHROMA_400 && (partitioner.chType == CHANNEL_TYPE_CHROMA))
+		  {
+			  cu_palette_info(cu, COMPONENT_Cb, 2, cuCtx);
+		  }
+	  }
+	  else
+	  {
+		  cu_palette_info(cu, COMPONENT_Y, 3, cuCtx);
+	  }
+	  return end_of_ctu(cu, cuCtx);
+  }
+#endif
   bdpcm_mode( cu, ComponentID( partitioner.chType ) );
 
   // --> create PUs
@@ -976,12 +1026,30 @@ void CABACReader::pred_mode( CodingUnit& cu )
         cu.predMode = MODE_IBC;
       }
       }
+#if JVET_O0119_BASE_PALETTE_444
+	  if (!CU::isIBC(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+	  {
+		  if (m_BinDecoder.decodeBin(Ctx::PLTFlag(0)))
+		  {
+			  cu.predMode = MODE_PLT;
+		  }
+	  }
+#endif
     }
     else
     {
       if (m_BinDecoder.decodeBin(Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))))
       {
         cu.predMode = MODE_INTRA;
+#if JVET_O0119_BASE_PALETTE_444
+		if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+		{
+			if (m_BinDecoder.decodeBin(Ctx::PLTFlag(0)))
+			{
+				cu.predMode = MODE_PLT;
+			}
+		}
+#endif
       }
       else
       {
@@ -1003,6 +1071,30 @@ void CABACReader::pred_mode( CodingUnit& cu )
   }
   else
   {
+#if JVET_O0119_BASE_PALETTE_444
+	  if ( cu.cs->slice->isIntra() || (cu.lwidth() == 4 && cu.lheight() == 4) )
+	  {
+		cu.predMode = MODE_INTRA;
+		if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+		{
+			if (m_BinDecoder.decodeBin(Ctx::PLTFlag(0)))
+			{
+				  cu.predMode = MODE_PLT;
+			}
+		}
+	  }
+	  else
+	  {
+		cu.predMode = m_BinDecoder.decodeBin(Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu))) ? MODE_INTRA : MODE_INTER;
+		if (!CU::isIntra(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+		{
+			if (m_BinDecoder.decodeBin(Ctx::PLTFlag(0)))
+			{
+				  cu.predMode = MODE_PLT;
+			}
+		}
+	  }
+#else
     if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || m_BinDecoder.decodeBin( Ctx::PredMode( DeriveCtx::CtxPredModeFlag( cu ) ) ) )
     {
       cu.predMode = MODE_INTRA;
@@ -1011,6 +1103,7 @@ void CABACReader::pred_mode( CodingUnit& cu )
     {
       cu.predMode = MODE_INTER;
     }
+#endif
   }
 }
 void CABACReader::bdpcm_mode( CodingUnit& cu, const ComponentID compID )
@@ -1505,6 +1598,408 @@ bool CABACReader::end_of_ctu( CodingUnit& cu, CUCtx& cuCtx )
   return false;
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+void CABACReader::cu_palette_info(CodingUnit& cu, ComponentID compBegin, uint32_t NumComp, CUCtx& cuCtx)
+{
+	const SPS&        sps = *(cu.cs->sps);
+	TransformUnit&   tu = *cu.firstTU;
+	int curPLTidx = 0;
+
+	cu.lastPLTSize[compBegin] = cu.cs->prevPLT.curPLTSize[compBegin];
+
+	if (cu.lastPLTSize[compBegin])
+	{
+		xDecodePLTPredIndicator(cu, MAXPLTSIZE, compBegin);
+	}
+
+	for (int idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
+	{
+		if (cu.reuseflag[compBegin][idx])
+		{
+			for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+			{
+				cu.curPLT[comp][curPLTidx] = cu.cs->prevPLT.curPLT[comp][idx];
+			}
+			curPLTidx++;
+		}
+	}
+
+	uint32_t recievedPLTnum = 0;
+
+	if (curPLTidx < MAXPLTSIZE)
+	{
+		recievedPLTnum = exp_golomb_eqprob(0);
+	}
+
+	cu.curPLTSize[compBegin] = curPLTidx + recievedPLTnum;
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		for (int idx = curPLTidx; idx < cu.curPLTSize[compBegin]; idx++)
+		{
+			ComponentID compID = (ComponentID)comp;
+			const int  channelBitDepth = sps.getBitDepth(toChannelType(compID));
+			cu.curPLT[compID][idx] = m_BinDecoder.decodeBinsEP(channelBitDepth);
+		}
+	}
+	cu.useEscape[compBegin] = true; // JC 
+	if (cu.curPLTSize[compBegin] > 0)
+	{
+		uint32_t uiCode = 0;
+		uiCode = m_BinDecoder.decodeBinEP();
+		cu.useEscape[compBegin] = (uiCode != 0);
+	}
+	uint32_t indexMaxSize = cu.useEscape[compBegin] ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin];
+	//encode index map
+	PLTtypeBuf    runType = tu.getrunType(compBegin);
+	PelBuf    runLength = tu.getrunLength(compBegin);
+	PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
+	uint32_t  uiHeight = cu.block(compBegin).height;
+	uint32_t  uiWidth = cu.block(compBegin).width;
+
+	int iNumCopyIndexRuns = -1;
+	bool lastRunType = 0;
+	uint32_t uiNumIndices = 0;
+	uint32_t uiAdjust = 0;
+	uint32_t symbol = 0;
+	std::list<int> lParsedIdxList;
+	if (indexMaxSize > 1)
+	{
+		uint32_t currParam = 3 + ((indexMaxSize) >> 3);
+		uiNumIndices = m_BinDecoder.decodeRemAbsEP(currParam, false, MAX_NUM_CHANNEL_TYPE); // JC: number of indices (INDEX RUN)
+		uiNumIndices++;
+		iNumCopyIndexRuns = uiNumIndices;
+		while (uiNumIndices--)
+		{
+			xReadTruncBinCode(symbol, indexMaxSize - uiAdjust);
+			uiAdjust = 1;
+			lParsedIdxList.push_back(symbol);
+		}
+		lastRunType = m_BinDecoder.decodeBin(Ctx::RunTypeFlag());
+		parseScanRotationModeFlag(cu, compBegin);
+		uiAdjust = 0;
+	}
+	else
+	{
+		cu.useRotation[compBegin] = false;
+	}
+
+	if (cu.useEscape[compBegin] && cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded)
+	{
+		if (!CS::isDualITree(*tu.cs) || isLuma(tu.chType))
+		{
+			cu_qp_delta(cu, cuCtx.qp, cu.qp);
+			cuCtx.qp = cu.qp;
+			cuCtx.isDQPCoded = true;
+		}
+	}
+#if JVET_O1168_CU_CHROMA_QP_OFFSET
+	if (cu.useEscape[compBegin] && cu.cs->slice->getUseChromaQpAdj() && !cuCtx.isChromaQpAdjCoded)
+#else
+	if (cu.cs->slice->getUseChromaQpAdj() && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded)
+#endif
+	{
+		if (!CS::isDualITree(*tu.cs) || isChroma(tu.chType))
+		{
+			cu_chroma_qp_offset(cu);
+			cuCtx.isChromaQpAdjCoded = true;
+		}
+	}
+
+
+	m_puiScanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(uiWidth)][gp_sizeIdxInfo->idxFrom(uiHeight)];
+	uint32_t strPos = 0;
+	uint32_t endPos = uiHeight * uiWidth;
+	while (strPos < endPos)
+	{
+		uint32_t posy = m_puiScanOrder[strPos].y;
+		uint32_t posx = m_puiScanOrder[strPos].x;
+		uint32_t posyprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].y;
+		uint32_t posxprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].x;
+
+		if (indexMaxSize > 1)
+		{
+			if (((posy == 0) && !cu.useRotation[compBegin]) || ((posx == 0) && cu.useRotation[compBegin]))
+			{
+				runType.at(posx, posy) = PLT_RUN_INDEX;
+			}
+			else if (strPos != 0 && runType.at(posxprev, posyprev) == PLT_RUN_COPY)
+			{
+				runType.at(posx, posy) = PLT_RUN_INDEX;
+			}
+			else
+			{
+				if (iNumCopyIndexRuns && strPos < endPos - 1) // JC: if uiNumIndices (decoder will know this value) == 0 - > only CopyAbove, if strPos == endPos - 1, the last RunType was already coded
+				{
+					runType.at(posx, posy) = (m_BinDecoder.decodeBin(Ctx::RunTypeFlag()));
+				}
+				else
+				{
+					if (strPos == endPos - 1 && iNumCopyIndexRuns)
+					{
+						runType.at(posx, posy) = PLT_RUN_INDEX;
+					}
+					else
+					{
+						runType.at(posx, posy) = PLT_RUN_COPY;
+					}
+				}
+			}
+		}
+		else
+		{
+			runType.at(posx, posy) = PLT_RUN_INDEX;
+		}
+
+		Pel siCurLevel = 0;
+		if (runType.at(posx, posy) == PLT_RUN_INDEX)
+		{
+			if (!lParsedIdxList.empty())
+			{
+				siCurLevel = lParsedIdxList.front();
+				lParsedIdxList.pop_front();
+			}
+			else
+			{
+				siCurLevel = 0;
+			}
+			xAdjustPLTIndex(cu, siCurLevel, strPos, curPLTIdx, runType, indexMaxSize, compBegin);
+		}
+
+		if (indexMaxSize > 1)
+		{
+			bool bLastRun;
+			iNumCopyIndexRuns -= (runType.at(posx, posy) == PLT_RUN_INDEX);
+			bLastRun = iNumCopyIndexRuns == 0 && runType.at(posx, posy) == lastRunType;
+			if (!bLastRun)
+			{
+				runLength.at(posx, posy) = cu_run_val((PLTRunMode)runType.at(posx, posy), siCurLevel, endPos - strPos - iNumCopyIndexRuns - 1 - lastRunType) + 1;
+			}
+			else
+			{
+				runLength.at(posx, posy) = endPos - strPos;
+			}
+
+		}
+		else
+		{
+			runLength.at(posx, posy) = endPos - strPos;
+		}
+
+		//assign run information
+		for (int runidx = 1; runidx < runLength.at(posx, posy); runidx++)
+		{
+			int PosYrun, PosXrun;
+			PosYrun = m_puiScanOrder[strPos + runidx].y;
+			PosXrun = m_puiScanOrder[strPos + runidx].x;
+			runType.at(PosXrun, PosYrun) = runType.at(posx, posy);
+			runLength.at(PosXrun, PosYrun) = runLength.at(posx, posy);
+		}
+
+		uint32_t PosYrun;
+		uint32_t PosXrun;
+		if (runType.at(posx, posy) == PLT_RUN_INDEX)
+		{
+			for (uint32_t idx = 1; idx < runLength.at(posx, posy); idx++)
+			{
+				PosYrun = m_puiScanOrder[strPos + idx].y;
+				PosXrun = m_puiScanOrder[strPos + idx].x;
+				curPLTIdx.at(PosXrun, PosYrun) = curPLTIdx.at(posx, posy);
+			}
+		}
+		else if (runType.at(posx, posy) == PLT_RUN_COPY)
+		{
+			for (uint32_t idx = 0; idx < runLength.at(posx, posy); idx++)
+			{
+				PosYrun = m_puiScanOrder[strPos + idx].y;
+				PosXrun = m_puiScanOrder[strPos + idx].x;
+				curPLTIdx.at(PosXrun, PosYrun) = (cu.useRotation[compBegin]) ? curPLTIdx.at(PosXrun - 1, PosYrun) : curPLTIdx.at(PosXrun, PosYrun - 1);
+			}
+		}
+		strPos += (runLength.at(posx, posy));
+	}
+	assert(strPos == endPos);
+
+	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, sps.getChromaFormatIdc());
+	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, sps.getChromaFormatIdc());
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		ComponentID compID = (ComponentID)comp;
+		for (strPos = 0; strPos < endPos; strPos++)
+		{
+			uint32_t posy = m_puiScanOrder[strPos].y;
+			uint32_t posx = m_puiScanOrder[strPos].x;
+			if (curPLTIdx.at(posx, posy) == cu.curPLTSize[compBegin])
+			{
+				{
+					PLTescapeBuf    escapeValue = tu.getescapeValue((ComponentID)comp);
+					if (compID == COMPONENT_Y || compBegin != COMPONENT_Y)
+					{
+						escapeValue.at(posx, posy) = exp_golomb_eqprob(3);
+						assert(escapeValue.at(posx, posy) < (1 << (cu.cs->sps->getBitDepth(toChannelType((ComponentID)comp)) + 1)));
+					}
+					if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && posy % (1 << scaleY) == 0 && posx % (1 << scaleX) == 0)
+					{
+						uint32_t posxC = posx >> scaleX;
+						uint32_t posyC = posy >> scaleY;
+						escapeValue.at(posxC, posyC) = exp_golomb_eqprob(3);
+						assert(escapeValue.at(posxC, posyC) < (1 << (cu.cs->sps->getBitDepth(toChannelType(compID)) + 1)));
+					}
+				}
+			}
+		}
+	}
+
+}
+void CABACReader::parseScanRotationModeFlag(CodingUnit& cu, ComponentID compBegin)
+{
+	cu.useRotation[compBegin] = m_BinDecoder.decodeBin(Ctx::RotationFlag());
+}
+void CABACReader::xDecodePLTPredIndicator(CodingUnit& cu, uint32_t uiMaxPLTSize, ComponentID compBegin)
+{
+	uint32_t uiSymbol, uiNumPLTPredicted = 0, idx = 0;
+
+	uiSymbol = exp_golomb_eqprob(0);
+
+	if (uiSymbol != 1)
+	{
+		while (idx < cu.lastPLTSize[compBegin] && uiNumPLTPredicted < uiMaxPLTSize)
+		{
+			if (idx > 0)
+			{
+				uiSymbol = exp_golomb_eqprob(0);
+			}
+			if (uiSymbol == 1)
+			{
+				break;
+			}
+
+			if (uiSymbol)
+			{
+				idx += uiSymbol - 1;
+			}
+			cu.reuseflag[compBegin][idx] = 1;
+			uiNumPLTPredicted++;
+			idx++;
+		}
+	}
+}
+void CABACReader::xAdjustPLTIndex(CodingUnit& cu, Pel siCurLevel, uint32_t idx, PelBuf& PLTIdx, PLTtypeBuf& PLTrunType, int maxSymbol, ComponentID compBegin)
+{
+	uint32_t uiSymbol;
+	int iRefLevel = MAX_INT;
+	uint32_t posy = m_puiScanOrder[idx].y;
+	uint32_t posx = m_puiScanOrder[idx].x;
+	if (idx)
+	{
+		uint32_t prevposy = m_puiScanOrder[idx - 1].y;
+		uint32_t prevposx = m_puiScanOrder[idx - 1].x;
+		if (PLTrunType.at(prevposx, prevposy) == PLT_RUN_INDEX)
+		{
+			iRefLevel = PLTIdx.at(prevposx, prevposy);
+			if (PLTIdx.at(prevposx, prevposy) == cu.curPLTSize[compBegin]) // escape
+			{
+				iRefLevel = maxSymbol - 1;
+			}
+		}
+		else
+		{
+			if (cu.useRotation[compBegin])
+			{
+				assert(prevposx > 0);
+				iRefLevel = PLTIdx.at(posx - 1, posy);
+				if (PLTIdx.at(posx - 1, posy) == cu.curPLTSize[compBegin]) // escape mode
+				{
+					iRefLevel = maxSymbol - 1;
+				}
+			}
+			else
+			{
+				assert(prevposy > 0);
+				iRefLevel = PLTIdx.at(posx, posy - 1);
+				if (PLTIdx.at(posx, posy - 1) == cu.curPLTSize[compBegin]) // escape mode
+				{
+					iRefLevel = maxSymbol - 1;
+				}
+			}
+		}
+		maxSymbol--;
+	}
+	uiSymbol = siCurLevel;
+	if (siCurLevel >= iRefLevel) // include escape mode 
+	{
+		uiSymbol++;
+	}
+	PLTIdx.at(posx, posy) = uiSymbol;
+}
+uint32_t  CABACReader::cu_run_val(PLTRunMode runtype, const uint32_t uiPltIdx, const uint32_t uiMaxRun)
+{
+	uint32_t ruiSymbol = 0;
+	if (runtype == PLT_RUN_COPY)
+	{
+	}
+	else
+	{
+		g_ucRunLeftLut[0] = (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2));
+	}
+	ruiSymbol = xReadTruncMsbP1RefinementBits(runtype, uiMaxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE);
+	return ruiSymbol;
+}
+uint32_t CABACReader::xReadTruncUnarySymbol(PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
+{
+	if (uiMax == 0)
+		return 0;
+
+	uint8_t *ucCtxLut;
+	ucCtxLut = (runtype == PLT_RUN_INDEX) ? g_ucRunLeftLut : g_ucRunTopLut;
+	uint32_t uiBin, uiIdx = 0;
+	do
+	{
+		if (uiIdx > uiCtxT)
+			uiBin = m_BinDecoder.decodeBinEP();
+		else
+		{
+			uiBin = m_BinDecoder.decodeBin(
+				(uiIdx <= uiCtxT)
+				? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiIdx]) : Ctx::CopyRunModel(ucCtxLut[uiIdx]))
+				: ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiCtxT]) : Ctx::CopyRunModel(ucCtxLut[uiCtxT])));
+			//        uiIdx <= uiCtxT? pcSCModel[ucCtxLut[uiIdx]] : pcSCModel[ucCtxLut[uiCtxT]] RExt__DECODER_DEBUG_BIT_STATISTICS_PASS_OPT_ARG(whichStat) );
+		}
+		uiIdx++;
+	} while (uiBin && uiIdx < uiMax);
+
+	return (uiBin && uiIdx == uiMax) ? uiMax : uiIdx - 1;
+}
+uint32_t CABACReader::xReadTruncMsbP1RefinementBits(PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
+{
+	if (uiMax == 0)
+	{
+		return 0;
+	}
+	uint32_t uiSymbol;
+	uint32_t uiMsbP1 = xReadTruncUnarySymbol(runtype, g_getMsbP1Idx(uiMax), uiCtxT);
+	if (uiMsbP1 > 1)
+	{
+		uint32_t uiNumBins = g_getMsbP1Idx(uiMax);
+		if (uiMsbP1 < uiNumBins)
+		{
+			uint32_t uiBits = uiMsbP1 - 1;
+			uiSymbol = m_BinDecoder.decodeBinsEP(uiBits);
+			uiSymbol |= (1 << uiBits);
+		}
+		else
+		{
+			uint32_t curValue = 1 << (uiNumBins - 1);
+			xReadTruncBinCode(uiSymbol, uiMax + 1 - curValue);
+			uiSymbol += curValue;
+		}
+	}
+	else
+		uiSymbol = uiMsbP1;
+
+	return uiSymbol;
+}
+#endif
+
 //================================================================================
 //  clause 7.3.8.6
 //--------------------------------------------------------------------------------
diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h
index 2f86875b4176884a1f3dde68729c7a229309e310..74cfd1ca73ae50eea86e33937e622ff31ebe4e49 100644
--- a/source/Lib/DecoderLib/CABACReader.h
+++ b/source/Lib/DecoderLib/CABACReader.h
@@ -95,6 +95,9 @@ public:
   void        mip_flag                  ( CodingUnit&                   cu );
   void        mip_pred_modes            ( CodingUnit&                   cu );
   void        mip_pred_mode             ( PredictionUnit&               pu );
+#if JVET_O0119_BASE_PALETTE_444  
+  void        cu_palette_info			( CodingUnit& cu, ComponentID compBegin, uint32_t NumComp, CUCtx& cuCtx);
+#endif
 
   // prediction unit (clause 7.3.8.6)
   void        prediction_unit           ( PredictionUnit&               pu,     MergeCtx&       mrgCtx );
@@ -171,6 +174,14 @@ private:
   unsigned    code_unary_fixed          ( unsigned ctxId, unsigned unary_max, unsigned fixed );
 
   void        xReadTruncBinCode(uint32_t& symbol, uint32_t maxSymbol);
+#if JVET_O0119_BASE_PALETTE_444
+  void		  parseScanRotationModeFlag	( CodingUnit& cu, ComponentID compBegin);
+  void        xDecodePLTPredIndicator	( CodingUnit& cu, uint32_t uiMaxPLTSize, ComponentID compBegin);
+  void        xAdjustPLTIndex			( CodingUnit& cu, Pel siCurLevel, uint32_t idx, PelBuf& PLTIdx, PLTtypeBuf& PLTrunType, int maxSymbol, ComponentID compBegin);
+  uint32_t    cu_run_val				( PLTRunMode runtype, const uint32_t uiPltIdx, const uint32_t uiMaxRun);
+  uint32_t    xReadTruncUnarySymbol		( PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT);
+  uint32_t    xReadTruncMsbP1RefinementBits( PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT);
+#endif
 public:
   int         shareStateDec;
   Position    shareParentPos;
@@ -178,6 +189,9 @@ public:
 private:
   BinDecoderBase& m_BinDecoder;
   InputBitstream* m_Bitstream;
+#if JVET_O0119_BASE_PALETTE_444
+  ScanElement*    m_puiScanOrder;
+#endif
 };
 
 
diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp
index 13367e597e1da487143a8b5295d23d99bbe1eac2..fcc66922703b4febdd7684b621875f0923f4877c 100644
--- a/source/Lib/DecoderLib/DecCu.cpp
+++ b/source/Lib/DecoderLib/DecCu.cpp
@@ -133,8 +133,12 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea )
         }
         prevTmpPos = currCU.shareParentPos;
       }
+#if JVET_O0119_BASE_PALETTE_444
+	  if (currCU.predMode != MODE_INTRA && currCU.predMode != MODE_PLT && currCU.Y().valid())
+#else
       if (currCU.predMode != MODE_INTRA && currCU.Y().valid())
-      {
+#endif
+	  {
         xDeriveCUMV(currCU);
       }
       switch( currCU.predMode )
@@ -143,6 +147,9 @@ void DecCu::decompressCtu( CodingStructure& cs, const UnitArea& ctuArea )
       case MODE_IBC:
         xReconInter( currCU );
         break;
+#if JVET_O0119_BASE_PALETTE_444
+	  case MODE_PLT:
+#endif
       case MODE_INTRA:
         xReconIntraQT( currCU );
         break;
@@ -360,6 +367,27 @@ void DecCu::xReconIntraQT( CodingUnit &cu )
     return;
   }
 
+#if JVET_O0119_BASE_PALETTE_444
+  if (CU::isPLT(cu))
+  {
+	  if (CS::isDualITree(*cu.cs))
+	  {
+		  if (cu.chType == CHANNEL_TYPE_LUMA)
+		  {
+			  xReconPLT(cu, COMPONENT_Y, 1);
+		  }
+		  if (cu.chromaFormat != CHROMA_400 && (cu.chType == CHANNEL_TYPE_CHROMA))
+		  {
+			  xReconPLT(cu, COMPONENT_Cb, 2);
+		  }
+	  }
+	  else
+	  {
+		  xReconPLT(cu, COMPONENT_Y, 3);
+	  }
+	  return;
+  }
+#endif
   const uint32_t numChType = ::getNumberValidChannels( cu.chromaFormat );
 
   for( uint32_t chType = CHANNEL_TYPE_LUMA; chType < numChType; chType++ )
@@ -371,6 +399,84 @@ void DecCu::xReconIntraQT( CodingUnit &cu )
   }
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+void DecCu::xReconPLT(CodingUnit &cu, ComponentID compBegin, uint32_t NumComp)
+{
+	const SPS&        sps = *(cu.cs->sps);
+	TransformUnit&   tu = *cu.firstTU;
+	PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
+
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+
+	//recon. pixels
+	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, sps.getChromaFormatIdc());
+	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, sps.getChromaFormatIdc());
+	for (uint32_t uiY = 0; uiY < uiHeight; uiY++)
+	{
+		for (uint32_t uiX = 0; uiX < uiWidth; uiX++)
+		{
+			for (uint32_t compID = compBegin; compID < (compBegin + NumComp); compID++)
+			{
+				const int  channelBitDepth = cu.cs->sps->getBitDepth(toChannelType((ComponentID)compID));
+				const CompArea &area = cu.blocks[compID];
+
+				PelBuf piPicReco = cu.cs->getRecoBuf(area);
+				PLTescapeBuf    escapeValue = tu.getescapeValue((ComponentID)compID);
+				if (curPLTIdx.at(uiX, uiY) == cu.curPLTSize[compBegin])
+				{
+					Pel iValue;
+					QpParam cQP(tu, (ComponentID)compID);
+
+					int iQP = cQP.Qp;
+					int iQPrem = iQP % 6;
+					int iQPper = iQP / 6;
+					if (compBegin != COMPONENT_Y || compID == COMPONENT_Y)
+					{
+						int InvquantiserRightShift = IQUANT_SHIFT;
+						int iAdd = 1 << (InvquantiserRightShift - 1);
+						iValue = ((((escapeValue.at(uiX, uiY)*g_invQuantScales[0][iQPrem]) << iQPper) + iAdd) >> InvquantiserRightShift);
+						iValue = Pel(ClipBD<int>(iValue, channelBitDepth));
+						piPicReco.at(uiX, uiY) = iValue;
+					}
+					else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && uiY % (1 << scaleY) == 0 && uiX % (1 << scaleX) == 0)
+					{
+						uint32_t PosYC = uiY >> scaleY;
+						uint32_t PosXC = uiX >> scaleX;
+						int InvquantiserRightShift = IQUANT_SHIFT;
+						int iAdd = 1 << (InvquantiserRightShift - 1);
+						iValue = ((((escapeValue.at(PosXC, PosYC)*g_invQuantScales[0][iQPrem]) << iQPper) + iAdd) >> InvquantiserRightShift);
+						iValue = Pel(ClipBD<int>(iValue, channelBitDepth));
+						piPicReco.at(PosXC, PosYC) = iValue;
+
+					}
+				}
+				else
+				{
+					uint32_t curIdx = curPLTIdx.at(uiX, uiY);
+					if (compBegin != COMPONENT_Y || compID == COMPONENT_Y)
+					{
+						piPicReco.at(uiX, uiY) = cu.curPLT[compID][curIdx];
+					}
+					else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && uiY % (1 << scaleY) == 0 && uiX % (1 << scaleX) == 0)
+					{
+						uint32_t PosYC = uiY >> scaleY;
+						uint32_t PosXC = uiX >> scaleX;
+						piPicReco.at(PosXC, PosYC) = cu.curPLT[compID][curIdx];
+					}
+				}
+			}
+		}
+	}
+	for (uint32_t compID = compBegin; compID < (compBegin + NumComp); compID++)
+	{
+		const CompArea &area = cu.blocks[compID];
+		PelBuf piPicReco = cu.cs->getRecoBuf(area);
+		cu.cs->picture->getRecoBuf(area).copyFrom(piPicReco);
+		cu.cs->setDecomp(area);
+	}
+}
+#endif
 /** Function for deriving reconstructed luma/chroma samples of a PCM mode CU.
 * \param pcCU pointer to current CU
 * \param uiPartIdx part index
diff --git a/source/Lib/DecoderLib/DecCu.h b/source/Lib/DecoderLib/DecCu.h
index 8d70b5f06275284f8d0ba6b91b8726e262c17fbf..4bdacd20dd312017d1b89fcd35a4d1718e52a7e1 100644
--- a/source/Lib/DecoderLib/DecCu.h
+++ b/source/Lib/DecoderLib/DecCu.h
@@ -92,6 +92,9 @@ protected:
   void xDecodeInterTU     ( TransformUnit&   tu, const ComponentID compID );
 
   void xDeriveCUMV        ( CodingUnit&      cu );
+#if JVET_O0119_BASE_PALETTE_444
+  void xReconPLT		  ( CodingUnit &cu, ComponentID compBegin, uint32_t NumComp);
+#endif
   PelStorage        *m_tmpStorageLCU;
 private:
   TrQuant*          m_pcTrQuant;
diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp
index 1da86e80022a9934be94379e57652b229858578d..c19bf0e41ca2e221a1c4a5b1942caf978781f51d 100644
--- a/source/Lib/DecoderLib/DecSlice.cpp
+++ b/source/Lib/DecoderLib/DecSlice.cpp
@@ -94,6 +94,10 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
 
   cs.picture->resizeSAO(cs.pcv->sizeInCtus, 0);
 
+#if JVET_O0119_BASE_PALETTE_444
+  cs.resetPrevPLT(cs.prevPLT);
+#endif
+
   if (slice->getSliceCurStartCtuTsAddr() == 0)
   {
     cs.picture->resizeAlfCtuEnableFlag( cs.pcv->sizeInCtus );
@@ -160,6 +164,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
       if( ctuTsAddr != startCtuTsAddr ) // if it is the first CTU, then the entropy coder has already been reset
       {
         cabacReader.initCtxModels( *slice );
+#if JVET_O0119_BASE_PALETTE_444
+		cs.resetPrevPLT(cs.prevPLT);
+#endif
       }
       pic->m_prevQP[0] = pic->m_prevQP[1] = slice->getSliceQp();
     }
@@ -169,6 +176,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb
       if( ctuTsAddr != startCtuTsAddr ) // if it is the first CTU, then the entropy coder has already been reset
       {
         cabacReader.initCtxModels( *slice );
+#if JVET_O0119_BASE_PALETTE_444
+		cs.resetPrevPLT(cs.prevPLT);
+#endif
       }
       if( cs.getCURestricted( pos.offset(0, -1), pos, slice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) )
       {
diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp
index 1a8ecc240ce99ccff93803610af269b32335afc3..594991085dcf479cfa04a49a9bfe9a30dfd3e6dc 100644
--- a/source/Lib/DecoderLib/VLCReader.cpp
+++ b/source/Lib/DecoderLib/VLCReader.cpp
@@ -1019,258 +1019,268 @@ void HLSyntaxReader::parseHrdParameters(HRDParameters *hrd, bool commonInfPresen
 
 void HLSyntaxReader::parseSPS(SPS* pcSPS)
 {
-  uint32_t  uiCode;
+	uint32_t  uiCode;
 
 #if ENABLE_TRACING
-  xTraceSPSHeader ();
-#endif
-  READ_CODE( 4,  uiCode, "sps_decoding_parameter_set_id");       pcSPS->setDecodingParameterSetId( uiCode );
-  READ_CODE(3, uiCode, "sps_max_sub_layers_minus1");          pcSPS->setMaxTLayers   (uiCode + 1);
-  CHECK(uiCode > 6, "Invalid maximum number of T-layer signalled");
-  READ_CODE(5, uiCode, "sps_reserved_zero_5bits");
-  CHECK(uiCode != 0, "sps_reserved_zero_5bits not equal to zero");
-
-  parseProfileTierLevel(pcSPS->getProfileTierLevel(), pcSPS->getMaxTLayers() - 1);
-
-  READ_UVLC(uiCode, "sps_seq_parameter_set_id");           pcSPS->setSPSId(uiCode);
-
-  READ_UVLC(     uiCode, "chroma_format_idc" );                  pcSPS->setChromaFormatIdc( ChromaFormat(uiCode) );
-  CHECK(uiCode > 3, "Invalid chroma format signalled");
-
-
-
-  if( pcSPS->getChromaFormatIdc() == CHROMA_444 )
-  {
-    READ_FLAG(     uiCode, "separate_colour_plane_flag");        CHECK(uiCode != 0, "Invalid code");
-  }
-
-  READ_UVLC (    uiCode, "pic_width_in_luma_samples" );          pcSPS->setPicWidthInLumaSamples ( uiCode    );
-  READ_UVLC (    uiCode, "pic_height_in_luma_samples" );         pcSPS->setPicHeightInLumaSamples( uiCode    );
-
-  // KJS: not removing yet
-  READ_FLAG(     uiCode, "conformance_window_flag");
-  if (uiCode != 0)
-  {
-    Window &conf = pcSPS->getConformanceWindow();
-    READ_UVLC(   uiCode, "conf_win_left_offset" );               conf.setWindowLeftOffset  ( uiCode * SPS::getWinUnitX( pcSPS->getChromaFormatIdc() ) );
-    READ_UVLC(   uiCode, "conf_win_right_offset" );              conf.setWindowRightOffset ( uiCode * SPS::getWinUnitX( pcSPS->getChromaFormatIdc() ) );
-    READ_UVLC(   uiCode, "conf_win_top_offset" );                conf.setWindowTopOffset   ( uiCode * SPS::getWinUnitY( pcSPS->getChromaFormatIdc() ) );
-    READ_UVLC(   uiCode, "conf_win_bottom_offset" );             conf.setWindowBottomOffset( uiCode * SPS::getWinUnitY( pcSPS->getChromaFormatIdc() ) );
-  }
-
-  READ_UVLC(     uiCode, "bit_depth_luma_minus8" );
-  CHECK(uiCode > 8, "Invalid luma bit depth signalled");
-  pcSPS->setBitDepth(CHANNEL_TYPE_LUMA, 8 + uiCode);
-
-  pcSPS->setQpBDOffset(CHANNEL_TYPE_LUMA, (int) (6*uiCode) );
-
-  READ_UVLC( uiCode,    "bit_depth_chroma_minus8" );
-  CHECK(uiCode > 8, "Invalid chroma bit depth signalled");
-  pcSPS->setBitDepth(CHANNEL_TYPE_CHROMA, 8 + uiCode);
-  pcSPS->setQpBDOffset(CHANNEL_TYPE_CHROMA,  (int) (6*uiCode) );
-
-  READ_UVLC( uiCode,    "log2_max_pic_order_cnt_lsb_minus4" );   pcSPS->setBitsForPOC( 4 + uiCode );
-  CHECK(uiCode > 12, "Invalid code");
-  READ_FLAG( uiCode, "sps_idr_rpl_present_flag" ); pcSPS->setIDRRefParamListPresent( (bool) uiCode);                 
-  // KJS: Marakech decision: sub-layers added back
-  uint32_t subLayerOrderingInfoPresentFlag;
-  READ_FLAG(subLayerOrderingInfoPresentFlag, "sps_sub_layer_ordering_info_present_flag");
-
-  for(uint32_t i=0; i <= pcSPS->getMaxTLayers()-1; i++)
-  {
-    READ_UVLC ( uiCode, "sps_max_dec_pic_buffering_minus1[i]");
-    pcSPS->setMaxDecPicBuffering( uiCode + 1, i);
-    READ_UVLC ( uiCode, "sps_max_num_reorder_pics[i]" );
-    pcSPS->setNumReorderPics(uiCode, i);
-    READ_UVLC ( uiCode, "sps_max_latency_increase_plus1[i]");
-    pcSPS->setMaxLatencyIncreasePlus1( uiCode, i );
-
-    if (!subLayerOrderingInfoPresentFlag)
-    {
-      for (i++; i <= pcSPS->getMaxTLayers()-1; i++)
-      {
-        pcSPS->setMaxDecPicBuffering(pcSPS->getMaxDecPicBuffering(0), i);
-        pcSPS->setNumReorderPics(pcSPS->getNumReorderPics(0), i);
-        pcSPS->setMaxLatencyIncreasePlus1(pcSPS->getMaxLatencyIncreasePlus1(0), i);
-      }
-      break;
-    }
-  }
-
-  READ_FLAG(uiCode, "long_term_ref_pics_flag");          pcSPS->setLongTermRefsPresent(uiCode);
-  READ_FLAG(uiCode, "rpl1_copy_from_rpl0_flag");
-  pcSPS->setRPL1CopyFromRPL0Flag(uiCode);
-
-  //Read candidate for List0
-  READ_UVLC(uiCode, "num_ref_pic_lists_in_sps[0]");
-  uint32_t numberOfRPL = uiCode;
-  pcSPS->createRPLList0(numberOfRPL);
-  RPLList* rplList = pcSPS->getRPLList0();
-  ReferencePictureList* rpl;
-  for (uint32_t ii = 0; ii < numberOfRPL; ii++)
-  {
-    rpl = rplList->getReferencePictureList(ii);
-    parseRefPicList(pcSPS, rpl);
-  }
-
-  //Read candidate for List1
-  if (!pcSPS->getRPL1CopyFromRPL0Flag())
-  {
-    READ_UVLC(uiCode, "num_ref_pic_lists_in_sps[1]");
-    numberOfRPL = uiCode;
-    pcSPS->createRPLList1(numberOfRPL);
-    rplList = pcSPS->getRPLList1();
-    for (uint32_t ii = 0; ii < numberOfRPL; ii++)
-    {
-      rpl = rplList->getReferencePictureList(ii);
-      parseRefPicList(pcSPS, rpl);
-    }
-  }
-  else
-  {
-    numberOfRPL = pcSPS->getNumRPL0();
-    pcSPS->createRPLList1(numberOfRPL);
-    RPLList* rplListSource = pcSPS->getRPLList0();
-    RPLList* rplListDest = pcSPS->getRPLList1();
-    for (uint32_t ii = 0; ii < numberOfRPL; ii++)
-      copyRefPicList(pcSPS, rplListSource->getReferencePictureList(ii), rplListDest->getReferencePictureList(ii));
-  }
-
-  unsigned  minQT[3] = { 0, 0, 0 };
-  unsigned  maxBTD[3] = { 0, 0, 0 };
-
-  unsigned  maxBTSize[3] = { 0, 0, 0 };
-  unsigned  maxTTSize[3] = { 0, 0, 0 };
-  READ_FLAG(uiCode, "qtbtt_dual_tree_intra_flag");             pcSPS->setUseDualITree(uiCode);
-  READ_UVLC(uiCode, "log2_ctu_size_minus2");                   pcSPS->setCTUSize(1 << (uiCode + 2));
-  pcSPS->setMaxCodingDepth(uiCode);
-  pcSPS->setLog2DiffMaxMinCodingBlockSize(uiCode);
-  pcSPS->setMaxCUWidth(pcSPS->getCTUSize());
-  pcSPS->setMaxCUHeight(pcSPS->getCTUSize());
-
-  READ_UVLC(uiCode, "log2_min_luma_coding_block_size_minus2");
-  int log2MinCUSize = uiCode + 2;
-  pcSPS->setLog2MinCodingBlockSize(log2MinCUSize);
-  READ_FLAG(uiCode, "partition_constraints_override_enabled_flag"); pcSPS->setSplitConsOverrideEnabledFlag(uiCode);
-  READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_tile_group_luma");      minQT[0] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
-  READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_tile_group");      minQT[1] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
-  READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_tile_group");     maxBTD[1] = uiCode;
-  READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_tile_group_luma");     maxBTD[0] = uiCode;
-
-  maxTTSize[0] = maxBTSize[0] = minQT[0];
-  if (maxBTD[0] != 0)
-  {
-    READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_tile_group_luma");     maxBTSize[0] <<= uiCode;
-    READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_tile_group_luma");     maxTTSize[0] <<= uiCode;
-  }
-  maxTTSize[1] = maxBTSize[1] = minQT[1];
-  if (maxBTD[1] != 0)
-  {
-    READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_inter_tile_group");     maxBTSize[1] <<= uiCode;
-    READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_inter_tile_group");     maxTTSize[1] <<= uiCode;
-  }
-  if (pcSPS->getUseDualITree())
-  {
-    READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_tile_group_chroma"); minQT[2] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
-    READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_tile_group_chroma"); maxBTD[2] = uiCode;
-    maxTTSize[2] = maxBTSize[2] = minQT[2];
-    if (maxBTD[2] != 0)
-    {
-      READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_tile_group_chroma");       maxBTSize[2] <<= uiCode;
-      READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_tile_group_chroma");       maxTTSize[2] <<= uiCode;
-    }
-}
-
-  pcSPS->setMinQTSizes(minQT);
-  pcSPS->setMaxBTDepth(maxBTD[1], maxBTD[0], maxBTD[2]);
-  pcSPS->setMaxBTSize(maxBTSize[1], maxBTSize[0], maxBTSize[2]);
-  pcSPS->setMaxTTSize(maxTTSize[1], maxTTSize[0], maxTTSize[2]);
+	xTraceSPSHeader();
+#endif
+	READ_CODE(4, uiCode, "sps_decoding_parameter_set_id");       pcSPS->setDecodingParameterSetId(uiCode);
+	READ_CODE(3, uiCode, "sps_max_sub_layers_minus1");          pcSPS->setMaxTLayers(uiCode + 1);
+	CHECK(uiCode > 6, "Invalid maximum number of T-layer signalled");
+	READ_CODE(5, uiCode, "sps_reserved_zero_5bits");
+	CHECK(uiCode != 0, "sps_reserved_zero_5bits not equal to zero");
+
+	parseProfileTierLevel(pcSPS->getProfileTierLevel(), pcSPS->getMaxTLayers() - 1);
+
+	READ_UVLC(uiCode, "sps_seq_parameter_set_id");           pcSPS->setSPSId(uiCode);
+
+	READ_UVLC(uiCode, "chroma_format_idc");                  pcSPS->setChromaFormatIdc(ChromaFormat(uiCode));
+	CHECK(uiCode > 3, "Invalid chroma format signalled");
+
+
+
+	if (pcSPS->getChromaFormatIdc() == CHROMA_444)
+	{
+		READ_FLAG(uiCode, "separate_colour_plane_flag");        CHECK(uiCode != 0, "Invalid code");
+	}
+
+	READ_UVLC(uiCode, "pic_width_in_luma_samples");          pcSPS->setPicWidthInLumaSamples(uiCode);
+	READ_UVLC(uiCode, "pic_height_in_luma_samples");         pcSPS->setPicHeightInLumaSamples(uiCode);
+
+	// KJS: not removing yet
+	READ_FLAG(uiCode, "conformance_window_flag");
+	if (uiCode != 0)
+	{
+		Window &conf = pcSPS->getConformanceWindow();
+		READ_UVLC(uiCode, "conf_win_left_offset");               conf.setWindowLeftOffset(uiCode * SPS::getWinUnitX(pcSPS->getChromaFormatIdc()));
+		READ_UVLC(uiCode, "conf_win_right_offset");              conf.setWindowRightOffset(uiCode * SPS::getWinUnitX(pcSPS->getChromaFormatIdc()));
+		READ_UVLC(uiCode, "conf_win_top_offset");                conf.setWindowTopOffset(uiCode * SPS::getWinUnitY(pcSPS->getChromaFormatIdc()));
+		READ_UVLC(uiCode, "conf_win_bottom_offset");             conf.setWindowBottomOffset(uiCode * SPS::getWinUnitY(pcSPS->getChromaFormatIdc()));
+	}
+
+	READ_UVLC(uiCode, "bit_depth_luma_minus8");
+	CHECK(uiCode > 8, "Invalid luma bit depth signalled");
+	pcSPS->setBitDepth(CHANNEL_TYPE_LUMA, 8 + uiCode);
+
+	pcSPS->setQpBDOffset(CHANNEL_TYPE_LUMA, (int)(6 * uiCode));
+
+	READ_UVLC(uiCode, "bit_depth_chroma_minus8");
+	CHECK(uiCode > 8, "Invalid chroma bit depth signalled");
+	pcSPS->setBitDepth(CHANNEL_TYPE_CHROMA, 8 + uiCode);
+	pcSPS->setQpBDOffset(CHANNEL_TYPE_CHROMA, (int)(6 * uiCode));
+
+	READ_UVLC(uiCode, "log2_max_pic_order_cnt_lsb_minus4");   pcSPS->setBitsForPOC(4 + uiCode);
+	CHECK(uiCode > 12, "Invalid code");
+	READ_FLAG(uiCode, "sps_idr_rpl_present_flag"); pcSPS->setIDRRefParamListPresent((bool)uiCode);
+	// KJS: Marakech decision: sub-layers added back
+	uint32_t subLayerOrderingInfoPresentFlag;
+	READ_FLAG(subLayerOrderingInfoPresentFlag, "sps_sub_layer_ordering_info_present_flag");
+
+	for (uint32_t i = 0; i <= pcSPS->getMaxTLayers() - 1; i++)
+	{
+		READ_UVLC(uiCode, "sps_max_dec_pic_buffering_minus1[i]");
+		pcSPS->setMaxDecPicBuffering(uiCode + 1, i);
+		READ_UVLC(uiCode, "sps_max_num_reorder_pics[i]");
+		pcSPS->setNumReorderPics(uiCode, i);
+		READ_UVLC(uiCode, "sps_max_latency_increase_plus1[i]");
+		pcSPS->setMaxLatencyIncreasePlus1(uiCode, i);
+
+		if (!subLayerOrderingInfoPresentFlag)
+		{
+			for (i++; i <= pcSPS->getMaxTLayers() - 1; i++)
+			{
+				pcSPS->setMaxDecPicBuffering(pcSPS->getMaxDecPicBuffering(0), i);
+				pcSPS->setNumReorderPics(pcSPS->getNumReorderPics(0), i);
+				pcSPS->setMaxLatencyIncreasePlus1(pcSPS->getMaxLatencyIncreasePlus1(0), i);
+			}
+			break;
+		}
+	}
+
+	READ_FLAG(uiCode, "long_term_ref_pics_flag");          pcSPS->setLongTermRefsPresent(uiCode);
+	READ_FLAG(uiCode, "rpl1_copy_from_rpl0_flag");
+	pcSPS->setRPL1CopyFromRPL0Flag(uiCode);
+
+	//Read candidate for List0
+	READ_UVLC(uiCode, "num_ref_pic_lists_in_sps[0]");
+	uint32_t numberOfRPL = uiCode;
+	pcSPS->createRPLList0(numberOfRPL);
+	RPLList* rplList = pcSPS->getRPLList0();
+	ReferencePictureList* rpl;
+	for (uint32_t ii = 0; ii < numberOfRPL; ii++)
+	{
+		rpl = rplList->getReferencePictureList(ii);
+		parseRefPicList(pcSPS, rpl);
+	}
+
+	//Read candidate for List1
+	if (!pcSPS->getRPL1CopyFromRPL0Flag())
+	{
+		READ_UVLC(uiCode, "num_ref_pic_lists_in_sps[1]");
+		numberOfRPL = uiCode;
+		pcSPS->createRPLList1(numberOfRPL);
+		rplList = pcSPS->getRPLList1();
+		for (uint32_t ii = 0; ii < numberOfRPL; ii++)
+		{
+			rpl = rplList->getReferencePictureList(ii);
+			parseRefPicList(pcSPS, rpl);
+		}
+	}
+	else
+	{
+		numberOfRPL = pcSPS->getNumRPL0();
+		pcSPS->createRPLList1(numberOfRPL);
+		RPLList* rplListSource = pcSPS->getRPLList0();
+		RPLList* rplListDest = pcSPS->getRPLList1();
+		for (uint32_t ii = 0; ii < numberOfRPL; ii++)
+			copyRefPicList(pcSPS, rplListSource->getReferencePictureList(ii), rplListDest->getReferencePictureList(ii));
+	}
+
+	unsigned  minQT[3] = { 0, 0, 0 };
+	unsigned  maxBTD[3] = { 0, 0, 0 };
+
+	unsigned  maxBTSize[3] = { 0, 0, 0 };
+	unsigned  maxTTSize[3] = { 0, 0, 0 };
+	READ_FLAG(uiCode, "qtbtt_dual_tree_intra_flag");             pcSPS->setUseDualITree(uiCode);
+	READ_UVLC(uiCode, "log2_ctu_size_minus2");                   pcSPS->setCTUSize(1 << (uiCode + 2));
+	pcSPS->setMaxCodingDepth(uiCode);
+	pcSPS->setLog2DiffMaxMinCodingBlockSize(uiCode);
+	pcSPS->setMaxCUWidth(pcSPS->getCTUSize());
+	pcSPS->setMaxCUHeight(pcSPS->getCTUSize());
+
+	READ_UVLC(uiCode, "log2_min_luma_coding_block_size_minus2");
+	int log2MinCUSize = uiCode + 2;
+	pcSPS->setLog2MinCodingBlockSize(log2MinCUSize);
+	READ_FLAG(uiCode, "partition_constraints_override_enabled_flag"); pcSPS->setSplitConsOverrideEnabledFlag(uiCode);
+	READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_tile_group_luma");      minQT[0] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
+	READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_tile_group");      minQT[1] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
+	READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_tile_group");     maxBTD[1] = uiCode;
+	READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_tile_group_luma");     maxBTD[0] = uiCode;
+
+	maxTTSize[0] = maxBTSize[0] = minQT[0];
+	if (maxBTD[0] != 0)
+	{
+		READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_tile_group_luma");     maxBTSize[0] <<= uiCode;
+		READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_tile_group_luma");     maxTTSize[0] <<= uiCode;
+	}
+	maxTTSize[1] = maxBTSize[1] = minQT[1];
+	if (maxBTD[1] != 0)
+	{
+		READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_inter_tile_group");     maxBTSize[1] <<= uiCode;
+		READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_inter_tile_group");     maxTTSize[1] <<= uiCode;
+	}
+	if (pcSPS->getUseDualITree())
+	{
+		READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_tile_group_chroma"); minQT[2] = 1 << (uiCode + pcSPS->getLog2MinCodingBlockSize());
+		READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_tile_group_chroma"); maxBTD[2] = uiCode;
+		maxTTSize[2] = maxBTSize[2] = minQT[2];
+		if (maxBTD[2] != 0)
+		{
+			READ_UVLC(uiCode, "sps_log2_diff_max_bt_min_qt_intra_tile_group_chroma");       maxBTSize[2] <<= uiCode;
+			READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_tile_group_chroma");       maxTTSize[2] <<= uiCode;
+		}
+	}
+
+	pcSPS->setMinQTSizes(minQT);
+	pcSPS->setMaxBTDepth(maxBTD[1], maxBTD[0], maxBTD[2]);
+	pcSPS->setMaxBTSize(maxBTSize[1], maxBTSize[0], maxBTSize[2]);
+	pcSPS->setMaxTTSize(maxTTSize[1], maxTTSize[0], maxTTSize[2]);
 
 
 #if MAX_TB_SIZE_SIGNALLING
-  // KJS: Not in syntax
-  READ_UVLC( uiCode, "log2_max_luma_transform_block_size_minus2" ); pcSPS->setLog2MaxTbSize( uiCode + 2 );
-#endif
-  READ_FLAG( uiCode, "sps_sao_enabled_flag" );                      pcSPS->setSAOEnabledFlag ( uiCode ? true : false );
-  READ_FLAG( uiCode, "sps_alf_enabled_flag" );                      pcSPS->setALFEnabledFlag ( uiCode ? true : false );
-
-  READ_FLAG( uiCode, "sps_pcm_enabled_flag" );                          pcSPS->setPCMEnabledFlag( uiCode ? true : false );
-  if( pcSPS->getPCMEnabledFlag() )
-  {
-    READ_CODE( 4, uiCode, "pcm_sample_bit_depth_luma_minus1" );          pcSPS->setPCMBitDepth    ( CHANNEL_TYPE_LUMA, 1 + uiCode );
-    READ_CODE( 4, uiCode, "pcm_sample_bit_depth_chroma_minus1" );        pcSPS->setPCMBitDepth    ( CHANNEL_TYPE_CHROMA, 1 + uiCode );
-    READ_UVLC( uiCode, "log2_min_pcm_luma_coding_block_size_minus3" );   pcSPS->setPCMLog2MinSize ( uiCode+3 );
-    READ_UVLC( uiCode, "log2_diff_max_min_pcm_luma_coding_block_size" ); pcSPS->setPCMLog2MaxSize ( uiCode+pcSPS->getPCMLog2MinSize() );
-    READ_FLAG( uiCode, "pcm_loop_filter_disable_flag" );                 pcSPS->setPCMFilterDisableFlag ( uiCode ? true : false );
-  }
+	// KJS: Not in syntax
+	READ_UVLC(uiCode, "log2_max_luma_transform_block_size_minus2"); pcSPS->setLog2MaxTbSize(uiCode + 2);
+#endif
+	READ_FLAG(uiCode, "sps_sao_enabled_flag");                      pcSPS->setSAOEnabledFlag(uiCode ? true : false);
+	READ_FLAG(uiCode, "sps_alf_enabled_flag");                      pcSPS->setALFEnabledFlag(uiCode ? true : false);
+
+	READ_FLAG(uiCode, "sps_pcm_enabled_flag");                          pcSPS->setPCMEnabledFlag(uiCode ? true : false);
+	if (pcSPS->getPCMEnabledFlag())
+	{
+		READ_CODE(4, uiCode, "pcm_sample_bit_depth_luma_minus1");          pcSPS->setPCMBitDepth(CHANNEL_TYPE_LUMA, 1 + uiCode);
+		READ_CODE(4, uiCode, "pcm_sample_bit_depth_chroma_minus1");        pcSPS->setPCMBitDepth(CHANNEL_TYPE_CHROMA, 1 + uiCode);
+		READ_UVLC(uiCode, "log2_min_pcm_luma_coding_block_size_minus3");   pcSPS->setPCMLog2MinSize(uiCode + 3);
+		READ_UVLC(uiCode, "log2_diff_max_min_pcm_luma_coding_block_size"); pcSPS->setPCMLog2MaxSize(uiCode + pcSPS->getPCMLog2MinSize());
+		READ_FLAG(uiCode, "pcm_loop_filter_disable_flag");                 pcSPS->setPCMFilterDisableFlag(uiCode ? true : false);
+	}
 
 #if JVET_O1136_TS_BDPCM_SIGNALLING
-  READ_FLAG(uiCode, "sps_transform_skip_enabled_flag"); pcSPS->setTransformSkipEnabledFlag(uiCode ? true : false);
-  if (pcSPS->getTransformSkipEnabledFlag())
-  {
-    READ_FLAG(uiCode, "sps_bdpcm_enabled_flag"); pcSPS->setBDPCMEnabledFlag(uiCode ? true : false);
-  }
-#endif
-
-  if( pcSPS->getCTUSize() + 2*(1 << pcSPS->getLog2MinCodingBlockSize()) <= pcSPS->getPicWidthInLumaSamples() )
-  {    
-  READ_FLAG(uiCode, "sps_ref_wraparound_enabled_flag");                  pcSPS->setWrapAroundEnabledFlag( uiCode ? true : false );
-
-  if (pcSPS->getWrapAroundEnabledFlag())
-  {
-    READ_UVLC(uiCode, "sps_ref_wraparound_offset_minus1");               pcSPS->setWrapAroundOffset( (uiCode+1)*(1 <<  pcSPS->getLog2MinCodingBlockSize()));
-  }
-  }
-  else 
-  {
-    pcSPS->setWrapAroundEnabledFlag(0);
-  }
-
-
-  READ_FLAG( uiCode, "sps_temporal_mvp_enabled_flag" );                  pcSPS->setSPSTemporalMVPEnabledFlag(uiCode);
-
-  if ( pcSPS->getSPSTemporalMVPEnabledFlag() )
-  {
-    READ_FLAG( uiCode,    "sps_sbtmvp_enabled_flag" );                   pcSPS->setSBTMVPEnabledFlag      ( uiCode != 0 );
-  }
-  else
-  {
-    pcSPS->setSBTMVPEnabledFlag(false);
-  }
-
-  READ_FLAG( uiCode,  "sps_amvr_enabled_flag" );                     pcSPS->setAMVREnabledFlag ( uiCode != 0 );
-
-  READ_FLAG( uiCode, "sps_bdof_enabled_flag" );                      pcSPS->setBDOFEnabledFlag ( uiCode != 0 );
+	READ_FLAG(uiCode, "sps_transform_skip_enabled_flag"); pcSPS->setTransformSkipEnabledFlag(uiCode ? true : false);
+	if (pcSPS->getTransformSkipEnabledFlag())
+	{
+		READ_FLAG(uiCode, "sps_bdpcm_enabled_flag"); pcSPS->setBDPCMEnabledFlag(uiCode ? true : false);
+	}
+#endif
+
+	if (pcSPS->getCTUSize() + 2 * (1 << pcSPS->getLog2MinCodingBlockSize()) <= pcSPS->getPicWidthInLumaSamples())
+	{
+		READ_FLAG(uiCode, "sps_ref_wraparound_enabled_flag");                  pcSPS->setWrapAroundEnabledFlag(uiCode ? true : false);
+
+		if (pcSPS->getWrapAroundEnabledFlag())
+		{
+			READ_UVLC(uiCode, "sps_ref_wraparound_offset_minus1");               pcSPS->setWrapAroundOffset((uiCode + 1)*(1 << pcSPS->getLog2MinCodingBlockSize()));
+		}
+	}
+	else
+	{
+		pcSPS->setWrapAroundEnabledFlag(0);
+	}
+
+
+	READ_FLAG(uiCode, "sps_temporal_mvp_enabled_flag");                  pcSPS->setSPSTemporalMVPEnabledFlag(uiCode);
+
+	if (pcSPS->getSPSTemporalMVPEnabledFlag())
+	{
+		READ_FLAG(uiCode, "sps_sbtmvp_enabled_flag");                   pcSPS->setSBTMVPEnabledFlag(uiCode != 0);
+	}
+	else
+	{
+		pcSPS->setSBTMVPEnabledFlag(false);
+	}
+
+	READ_FLAG(uiCode, "sps_amvr_enabled_flag");                     pcSPS->setAMVREnabledFlag(uiCode != 0);
+
+	READ_FLAG(uiCode, "sps_bdof_enabled_flag");                      pcSPS->setBDOFEnabledFlag(uiCode != 0);
 #if !JVET_O0438_SPS_AFFINE_AMVR_FLAG
-  READ_FLAG( uiCode,  "sps_affine_amvr_enabled_flag" );             pcSPS->setAffineAmvrEnabledFlag ( uiCode != 0 );
-#endif
-  READ_FLAG(uiCode, "sps_dmvr_enable_flag");                        pcSPS->setUseDMVR(uiCode != 0);
-  READ_FLAG(uiCode, "sps_mmvd_enable_flag");                        pcSPS->setUseMMVD(uiCode != 0);
-  // KJS: sps_cclm_enabled_flag
-  READ_FLAG( uiCode,    "lm_chroma_enabled_flag" );                 pcSPS->setUseLMChroma            ( uiCode != 0 );
-  if ( pcSPS->getUseLMChroma() && pcSPS->getChromaFormatIdc() == CHROMA_420 )
-  {
-    READ_FLAG( uiCode,  "sps_cclm_collocated_chroma_flag" );        pcSPS->setCclmCollocatedChromaFlag( uiCode != 0 );
-  }
-
-  READ_FLAG( uiCode,    "mts_enabled_flag" );                       pcSPS->setUseMTS                 ( uiCode != 0 );
-  if ( pcSPS->getUseMTS() )
-  {
-    READ_FLAG( uiCode,    "mts_intra_enabled_flag" );               pcSPS->setUseIntraMTS            ( uiCode != 0 );
-    READ_FLAG( uiCode,    "mts_inter_enabled_flag" );               pcSPS->setUseInterMTS            ( uiCode != 0 );
-  }
-  READ_FLAG( uiCode, "lfnst_enabled_flag" );                        pcSPS->setUseLFNST               ( uiCode != 0 );
-  READ_FLAG(uiCode, "smvd_flag");                                   pcSPS->setUseSMVD                ( uiCode != 0 );
-  // KJS: sps_affine_enabled_flag
-  READ_FLAG( uiCode,    "affine_flag" );                            pcSPS->setUseAffine              ( uiCode != 0 );
-  if ( pcSPS->getUseAffine() )
-  {
-    READ_FLAG( uiCode,  "affine_type_flag" );                       pcSPS->setUseAffineType          ( uiCode != 0 );
+	READ_FLAG(uiCode, "sps_affine_amvr_enabled_flag");             pcSPS->setAffineAmvrEnabledFlag(uiCode != 0);
+#endif
+	READ_FLAG(uiCode, "sps_dmvr_enable_flag");                        pcSPS->setUseDMVR(uiCode != 0);
+	READ_FLAG(uiCode, "sps_mmvd_enable_flag");                        pcSPS->setUseMMVD(uiCode != 0);
+	// KJS: sps_cclm_enabled_flag
+	READ_FLAG(uiCode, "lm_chroma_enabled_flag");                 pcSPS->setUseLMChroma(uiCode != 0);
+	if (pcSPS->getUseLMChroma() && pcSPS->getChromaFormatIdc() == CHROMA_420)
+	{
+		READ_FLAG(uiCode, "sps_cclm_collocated_chroma_flag");        pcSPS->setCclmCollocatedChromaFlag(uiCode != 0);
+	}
+
+	READ_FLAG(uiCode, "mts_enabled_flag");                       pcSPS->setUseMTS(uiCode != 0);
+	if (pcSPS->getUseMTS())
+	{
+		READ_FLAG(uiCode, "mts_intra_enabled_flag");               pcSPS->setUseIntraMTS(uiCode != 0);
+		READ_FLAG(uiCode, "mts_inter_enabled_flag");               pcSPS->setUseInterMTS(uiCode != 0);
+	}
+	READ_FLAG(uiCode, "lfnst_enabled_flag");                        pcSPS->setUseLFNST(uiCode != 0);
+	READ_FLAG(uiCode, "smvd_flag");                                   pcSPS->setUseSMVD(uiCode != 0);
+	// KJS: sps_affine_enabled_flag
+	READ_FLAG(uiCode, "affine_flag");                            pcSPS->setUseAffine(uiCode != 0);
+	if (pcSPS->getUseAffine())
+	{
+		READ_FLAG(uiCode, "affine_type_flag");                       pcSPS->setUseAffineType(uiCode != 0);
 #if JVET_O0438_SPS_AFFINE_AMVR_FLAG
-    READ_FLAG( uiCode,  "sps_affine_amvr_enabled_flag" );           pcSPS->setAffineAmvrEnabledFlag  ( uiCode != 0 );
+		READ_FLAG(uiCode, "sps_affine_amvr_enabled_flag");           pcSPS->setAffineAmvrEnabledFlag(uiCode != 0);
+#endif
+	}
+	READ_FLAG(uiCode, "gbi_flag");                               pcSPS->setUseGBi(uiCode != 0);
+#if JVET_O0119_BASE_PALETTE_444
+	if (pcSPS->getChromaFormatIdc() == CHROMA_444)
+	{
+		READ_FLAG(uiCode, "plt_flag");                                    pcSPS->setPLTMode(uiCode != 0);
+	}
+	else
+	{
+		pcSPS->setPLTMode(false);
+	}
 #endif
-  }
-  READ_FLAG( uiCode,    "gbi_flag" );                               pcSPS->setUseGBi                 ( uiCode != 0 );
   READ_FLAG(uiCode, "ibc_flag");                                    pcSPS->setIBCFlag(uiCode);
   // KJS: sps_ciip_enabled_flag
   READ_FLAG( uiCode,     "mhintra_flag" );                           pcSPS->setUseMHIntra             ( uiCode != 0 );
diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp
index 636f6f0ab05e82cadd472379d5d70c8d0e5f117b..8251289c7d39574bf406a1ce2d736aabf9622921 100644
--- a/source/Lib/EncoderLib/CABACWriter.cpp
+++ b/source/Lib/EncoderLib/CABACWriter.cpp
@@ -602,6 +602,28 @@ void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, C
 
   // prediction mode and partitioning data
   pred_mode ( cu );
+#if JVET_O0119_BASE_PALETTE_444
+  if (CU::isPLT(cu))
+  {
+	  if (CS::isDualITree(*cu.cs))
+	  {
+		  if (isLuma(partitioner.chType))
+		  {
+			  cu_palette_info(cu, COMPONENT_Y, 1, cuCtx);
+		  }
+		  if (cu.chromaFormat != CHROMA_400 && (partitioner.chType == CHANNEL_TYPE_CHROMA))
+		  {
+			  cu_palette_info(cu, COMPONENT_Cb, 2, cuCtx);
+		  }
+	  }
+	  else
+	  {
+		  cu_palette_info(cu, COMPONENT_Y, 3, cuCtx);
+	  }
+	  end_of_ctu(cu, cuCtx);
+	  return;
+  }
+#endif
   bdpcm_mode( cu, ComponentID( partitioner.chType ) );
 
 #if FIX_PCM
@@ -747,12 +769,29 @@ void CABACWriter::pred_mode( const CodingUnit& cu )
       unsigned ctxidx = DeriveCtx::CtxIBCFlag(cu);
       m_BinEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx));
       }
+#if JVET_O0119_BASE_PALETTE_444
+	  if (!CU::isIBC(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+	  {
+		  m_BinEncoder.encodeBin(CU::isPLT(cu), Ctx::PLTFlag(0));
+	  }
+#endif
     }
     else
     {
+#if JVET_O0119_BASE_PALETTE_444
+	  m_BinEncoder.encodeBin((CU::isIntra(cu) || CU::isPLT(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
+	  if (CU::isIntra(cu) || CU::isPLT(cu))
+	  {
+		  if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+		  m_BinEncoder.encodeBin(CU::isPLT(cu), Ctx::PLTFlag(0));
+	  }
+	  else
+	  {
+#else
       m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
       if (!CU::isIntra(cu))
       {
+#endif
 #if JVET_O1161_IBC_MAX_SIZE
         if (cu.lwidth() < 128 && cu.lheight() < 128) // disable IBC mode larger than 64x64
 #else
@@ -769,9 +808,19 @@ void CABACWriter::pred_mode( const CodingUnit& cu )
   {
     if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) )
     {
+#if JVET_O0119_BASE_PALETTE_444
+	  if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+		  m_BinEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));
+#endif
       return;
     }
     m_BinEncoder.encodeBin((CU::isIntra(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
+#if JVET_O0119_BASE_PALETTE_444
+	if (!CU::isIntra(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64)
+	{
+		m_BinEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));
+	}
+#endif
   }
 }
 void CABACWriter::bdpcm_mode( const CodingUnit& cu, const ComponentID compID )
@@ -1404,9 +1453,404 @@ void CABACWriter::end_of_ctu( const CodingUnit& cu, CUCtx& cuCtx )
   }
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+void CABACWriter::cu_palette_info(const CodingUnit& cu, ComponentID compBegin, uint32_t NumComp, CUCtx& cuCtx)
+{
+	const SPS&        sps = *(cu.cs->sps);
+	TransformUnit&   tu = *cu.firstTU;
+
+	uint32_t indexMaxSize = cu.useEscape[compBegin] ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin];
+
+
+	if (cu.lastPLTSize[compBegin])
+	{
+		xEncodePLTPredIndicator(cu, MAXPLTSIZE, compBegin);
+	}
+
+	uint32_t reusedPLTnum = 0;
+	for (int idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
+	{
+		if (cu.reuseflag[compBegin][idx])
+			reusedPLTnum++;
+	}
+
+	if (reusedPLTnum < MAXPLTSIZE)
+	{
+		exp_golomb_eqprob(cu.curPLTSize[compBegin] - reusedPLTnum, 0);
+	}
+
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		for (int idx = cu.reusePLTSize[compBegin]; idx < cu.curPLTSize[compBegin]; idx++)
+		{
+			ComponentID compID = (ComponentID)comp;
+			const int  channelBitDepth = sps.getBitDepth(toChannelType(compID));
+			m_BinEncoder.encodeBinsEP(cu.curPLT[comp][idx], channelBitDepth);
+		}
+	}
+	uint32_t signalEscape = (cu.useEscape[compBegin]) ? 1 : 0;
+	if (cu.curPLTSize[compBegin] > 0)
+	{
+		m_BinEncoder.encodeBinEP(signalEscape);
+	}
+	//encode index map
+	PLTtypeBuf    runType = tu.getrunType(compBegin);
+	PelBuf    runLength = tu.getrunLength(compBegin);
+	PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+
+	m_puiScanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(uiWidth)][gp_sizeIdxInfo->idxFrom(uiHeight)];
+
+	uint32_t total = uiHeight * uiWidth;
+
+	int iLastRunPos = -1;
+	uint32_t lastRunType = 0;
+	uint32_t uiNumIndices = 0;
+	std::vector<int> vIdxPos, vParsedIdx;
+	vIdxPos.reserve(total);
+	vParsedIdx.reserve(total);
+	if (indexMaxSize > 1)
+	{
+		int idx = 0, run = 0;
+		while (idx < total)
+		{
+			uint32_t posy = m_puiScanOrder[idx].y;
+			uint32_t posx = m_puiScanOrder[idx].x;
+			if (runType.at(posx, posy) == PLT_RUN_INDEX)
+			{
+				vIdxPos.push_back(idx);
+				uiNumIndices++;
+			}
+			lastRunType = runType.at(posx, posy);
+			iLastRunPos = idx;
+			run = runLength.at(posx, posy);
+			idx += run;
+		}
+		uint32_t currParam = 3 + ((indexMaxSize) >> 3);
+		uint32_t uiMappedValue;
+		assert(uiNumIndices);
+		assert(uiNumIndices > 0);
+		uiMappedValue = uiNumIndices - 1;
+		m_BinEncoder.encodeRemAbsEP(uiMappedValue, currParam, false, MAX_NUM_CHANNEL_TYPE); // JC: code number of indices (PLT_RUN_INDEX)
+		auto vIdxPosEnd = vIdxPos.end();
+		for (auto iter = vIdxPos.begin(); iter != vIdxPosEnd; ++iter)
+		{
+			vParsedIdx.push_back( writePLTIndex(cu, *iter, curPLTIdx, runType, indexMaxSize, compBegin));
+		}
+		m_BinEncoder.encodeBin(lastRunType, Ctx::RunTypeFlag());
+		codeScanRotationModeFlag(cu, compBegin);
+	}
+	else
+	{
+		assert(!cu.useRotation[compBegin]);
+	}
+
+	if (cu.useEscape[compBegin] && cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded)
+	{
+		if (!CS::isDualITree(*tu.cs) || isLuma(tu.chType))
+		{
+			cu_qp_delta(cu, cuCtx.qp, cu.qp);
+			cuCtx.qp = cu.qp;
+			cuCtx.isDQPCoded = true;
+		}
+	}
+#if JVET_O1168_CU_CHROMA_QP_OFFSET
+	if ( cu.useEscape[compBegin] && cu.cs->slice->getUseChromaQpAdj() && !cuCtx.isChromaQpAdjCoded)
+#else
+	if (cu.cs->slice->getUseChromaQpAdj() && !cu.transQuantBypass && !cuCtx.isChromaQpAdjCoded)
+#endif
+	{
+		if (!CS::isDualITree(*tu.cs) || isChroma(tu.chType))
+		{
+			cu_chroma_qp_offset(cu);
+			cuCtx.isChromaQpAdjCoded = true;
+		}
+	}
+
+	uint32_t strPos = 0;
+	uint32_t endPos = uiHeight * uiWidth;
+	auto vParsedIdxEnd = vParsedIdx.end();
+	auto vParsedIdxIter = vParsedIdx.begin();
+	while (strPos < endPos)
+	{
+		uint32_t posy = m_puiScanOrder[strPos].y;
+		uint32_t posx = m_puiScanOrder[strPos].x;
+		uint32_t posyprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].y;
+		uint32_t posxprev = strPos == 0 ? 0 : m_puiScanOrder[strPos - 1].x;
+
+		if (indexMaxSize > 1)
+		{
+			if (((posy == 0) && !cu.useRotation[compBegin]) || ((posx == 0) && cu.useRotation[compBegin]))
+
+			{
+				assert(runType.at(posx, posy) == PLT_RUN_INDEX);
+			}
+			else if (strPos != 0 && runType.at(posxprev, posyprev) == PLT_RUN_COPY)
+			{
+				assert(runType.at(posx, posy) == PLT_RUN_INDEX);
+			}
+			else
+			{
+				if (uiNumIndices && strPos < endPos - 1) // if uiNumIndices (decoder will know this value) == 0 - > only CopyAbove, if strPos == endPos - 1, the last RunType was already coded
+				{
+					m_BinEncoder.encodeBin((runType.at(posx, posy)), Ctx::RunTypeFlag());
+				}
+			}
+		}
+
+		Pel siCurLevel = 0;
+		if (runType.at(posx, posy) == PLT_RUN_INDEX)
+		{
+			if (vParsedIdxIter != vParsedIdxEnd)
+			{
+				siCurLevel = *vParsedIdxIter++;
+			}
+			else
+			{
+				siCurLevel = 0;
+			}
+		}
+
+		if (indexMaxSize > 1)
+		{
+			if (iLastRunPos != strPos)
+			{
+				uiNumIndices -= (runType.at(posx, posy) == PLT_RUN_INDEX);
+				cu_run_val(runLength.at(posx, posy) - 1, (PLTRunMode)runType.at(posx, posy), siCurLevel, endPos - strPos - uiNumIndices - 1 - lastRunType);
+			}
+
+		}
+
+		strPos += (runLength.at(posx, posy));
+	}
+	assert(strPos == endPos);
+
+	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, sps.getChromaFormatIdc());
+	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, sps.getChromaFormatIdc());
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		ComponentID compID = (ComponentID)comp;
+		for (strPos = 0; strPos < endPos; strPos++)
+		{
+			uint32_t posy = m_puiScanOrder[strPos].y;
+			uint32_t posx = m_puiScanOrder[strPos].x;
+			if (curPLTIdx.at(posx, posy) == cu.curPLTSize[compBegin])
+			{
+				{
+					PLTescapeBuf    escapeValue = tu.getescapeValue((ComponentID)comp);
+					if (compID == COMPONENT_Y || compBegin != COMPONENT_Y)
+					{
+						exp_golomb_eqprob((unsigned)escapeValue.at(posx, posy), 3);
+					}
+					if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && posy % (1 << scaleY) == 0 && posx % (1 << scaleX) == 0)
+					{
+						uint32_t posxC = posx >> scaleX;
+						uint32_t posyC = posy >> scaleY;
+						exp_golomb_eqprob((unsigned)escapeValue.at(posxC, posyC), 3);
+					}
+				}
+			}
+		}
+	}
+
+}
+void CABACWriter::codeScanRotationModeFlag(const CodingUnit& cu, ComponentID compBegin)
+{
+	m_BinEncoder.encodeBin((cu.useRotation[compBegin]), Ctx::RotationFlag());
+}
+void CABACWriter::xEncodePLTPredIndicator(const CodingUnit& cu, uint32_t uiMaxPLTSize, ComponentID compBegin)
+{
+	int lastPredIdx = -1;
+	uint32_t run = 0;
+	uint32_t uiNumPLTPredicted = 0;
+	for (uint32_t idx = 0; idx < cu.lastPLTSize[compBegin]; idx++)
+	{
+		if (cu.reuseflag[compBegin][idx])
+		{
+			uiNumPLTPredicted++;
+			lastPredIdx = idx;
+		}
+	}
+
+	int idx = 0;
+	while (idx <= lastPredIdx)
+	{
+		if (cu.reuseflag[compBegin][idx])
+		{
+			exp_golomb_eqprob(run ? run + 1 : run, 0);
+			run = 0;
+		}
+		else
+		{
+			run++;
+		}
+		idx++;
+	}
+	if ((uiNumPLTPredicted < uiMaxPLTSize && lastPredIdx + 1 < cu.lastPLTSize[compBegin]) || !uiNumPLTPredicted)
+	{
+		exp_golomb_eqprob(1, 0);
+	}
+}
+Pel CABACWriter::writePLTIndex(const CodingUnit& cu, uint32_t idx, PelBuf& PLTIdx, PLTtypeBuf& PLTrunType, int maxSymbol, ComponentID compBegin)
+{
+	uint32_t posy = m_puiScanOrder[idx].y;
+	uint32_t posx = m_puiScanOrder[idx].x;
+	Pel siCurLevel = (PLTIdx.at(posx, posy) == cu.curPLTSize[compBegin]) ? (maxSymbol - 1) : PLTIdx.at(posx, posy);
+	if (idx) // R0348: remove index redundancy
+	{
+		uint32_t prevposy = m_puiScanOrder[idx - 1].y;
+		uint32_t prevposx = m_puiScanOrder[idx - 1].x;
+		if (PLTrunType.at(prevposx, prevposy) == PLT_RUN_INDEX)
+		{
+			Pel siLeftLevel = PLTIdx.at(prevposx, prevposy); // left index
+			if (siLeftLevel == cu.curPLTSize[compBegin]) // escape mode
+			{
+				siLeftLevel = maxSymbol - 1;
+			}
+			assert(siLeftLevel != siCurLevel);
+			if (siCurLevel > siLeftLevel)
+			{
+				siCurLevel--;
+			}
+		}
+		else
+		{
+			Pel siAboveLevel;
+			if (cu.useRotation[compBegin])
+			{
+				assert(prevposx > 0);
+				siAboveLevel = PLTIdx.at(posx - 1, posy);
+				if (PLTIdx.at(posx - 1, posy) == cu.curPLTSize[compBegin]) // escape mode
+				{
+					siAboveLevel = maxSymbol - 1;
+				}
+			}
+			else
+			{
+				assert(prevposy > 0);
+				siAboveLevel = PLTIdx.at(posx, posy - 1);
+				if (PLTIdx.at(posx, posy - 1) == cu.curPLTSize[compBegin]) // escape mode
+				{
+					siAboveLevel = maxSymbol - 1;
+				}
+			}
+			assert(siCurLevel != siAboveLevel);
+			if (siCurLevel > siAboveLevel)
+			{
+				siCurLevel--;
+			}
+		}
+		maxSymbol--;
+	}
+	assert(maxSymbol > 0);
+	assert(siCurLevel >= 0);
+	assert(maxSymbol > siCurLevel);
+	if (maxSymbol > 1)
+	{
+		xWriteTruncBinCode(siCurLevel, maxSymbol);
+	}
+	return siCurLevel;
+}
+
+void CABACWriter::encodeRunType(const CodingUnit&  cu, PLTtypeBuf& runType, uint32_t idx, ScanElement *refScanOrder, ComponentID compBegin)
+{
+	if (refScanOrder)
+	{
+		m_puiScanOrder = refScanOrder;
+	}
+	uint32_t posy = m_puiScanOrder[idx].y;
+	uint32_t posx = m_puiScanOrder[idx].x;
+	uint32_t posyprev = (idx == 0) ? 0 : m_puiScanOrder[idx - 1].y;
+	uint32_t posxprev = (idx == 0) ? 0 : m_puiScanOrder[idx - 1].x;
+
+	if (((posy == 0) && !cu.useRotation[compBegin]) || ((posx == 0) && cu.useRotation[compBegin]))
+	{
+		assert(runType.at(posx, posy) == PLT_RUN_INDEX);
+	}
+	else if (idx != 0 && runType.at(posxprev, posyprev) == PLT_RUN_COPY)
+	{
+		assert(runType.at(posx, posy) == PLT_RUN_INDEX);
+	}
+	else
+	{
+		m_BinEncoder.encodeBin((runType.at(posx, posy)), Ctx::RunTypeFlag());
+	}
+}
+
+void CABACWriter::cu_run_val(uint32_t uiRun, PLTRunMode runtype, const uint32_t uiPltIdx, const uint32_t uiMaxRun)
+{
+	if (runtype == PLT_RUN_COPY)
+	{
+	}
+	else
+	{
+		g_ucRunLeftLut[0] = (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (uiPltIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2));
+	}
+	xWriteTruncMsbP1RefinementBits(uiRun, runtype, uiMaxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE);
+}
+uint32_t CABACWriter::xWriteTruncMsbP1(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
+{
+	if (uiMax == 0)
+		return 0;
+
+	uint8_t *ucCtxLut;
+	ucCtxLut = (runtype == PLT_RUN_INDEX) ? g_ucRunLeftLut : g_ucRunTopLut;
+
+	uint32_t uiMsbP1;
+	for (uiMsbP1 = 0; uiSymbol > 0; uiMsbP1++)
+	{
+		uiSymbol >>= 1;
+		if (uiMsbP1 > uiCtxT)
+		{
+			m_BinEncoder.encodeBinEP(1);
+		}
+		else
+			m_BinEncoder.encodeBin(1, (uiMsbP1 <= uiCtxT)
+				? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiMsbP1]) : Ctx::CopyRunModel(ucCtxLut[uiMsbP1]))
+				: ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiCtxT]) : Ctx::CopyRunModel(ucCtxLut[uiCtxT])));
+	}
+	assert(uiMsbP1 <= uiMax);
+	if (uiMsbP1 < uiMax)
+	{
+		if (uiMsbP1 > uiCtxT)
+		{
+			m_BinEncoder.encodeBinEP(0);
+		}
+		else
+			m_BinEncoder.encodeBin(0, uiMsbP1 <= uiCtxT
+				? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiMsbP1]) : Ctx::CopyRunModel(ucCtxLut[uiMsbP1]))
+				: ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ucCtxLut[uiCtxT]) : Ctx::CopyRunModel(ucCtxLut[uiCtxT])));
+
+		//m_pcBinIf->encodeBin(0, uiMsbP1 <= uiCtxT? pcSCModel[ucCtxLut[uiMsbP1]] : pcSCModel[ucCtxLut[uiCtxT]]);
+	}
+	return uiMsbP1;
+}
+
+void CABACWriter::xWriteTruncMsbP1RefinementBits(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT)
+{
+	if (uiMax == 0)
+		return;
+
+	uint32_t uiMsbP1 = xWriteTruncMsbP1(uiSymbol, runtype, g_getMsbP1Idx(uiMax), uiCtxT);
+	if (uiMsbP1 > 1)
+	{
+		uint32_t uiNumBins = g_getMsbP1Idx(uiMax);
+		if (uiMsbP1 < uiNumBins)
+		{
+
+			uint32_t uiBits = uiMsbP1 - 1;
+			m_BinEncoder.encodeBinsEP(uiSymbol & ((1 << uiBits) - 1), uiBits);
+		}
+		else
+		{
+			uint32_t curValue = 1 << (uiNumBins - 1);
+			xWriteTruncBinCode(uiSymbol - curValue, uiMax + 1 - curValue);
+		}
+	}
+}
 
-
-
+#endif
 
 //================================================================================
 //  clause 7.3.8.6
diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h
index 46cc2b033c282c4af99f658ba6e1e8da72709bb5..7401783f0706027d391023cbe26e480a3cd4504d 100644
--- a/source/Lib/EncoderLib/CABACWriter.h
+++ b/source/Lib/EncoderLib/CABACWriter.h
@@ -90,6 +90,7 @@ public:
   void        cu_skip_flag              ( const CodingUnit&             cu );
   void        pred_mode                 ( const CodingUnit&             cu );
   void        bdpcm_mode                ( const CodingUnit&             cu,       const ComponentID compID );
+  
   void        pcm_data                  ( const CodingUnit&             cu,       Partitioner&      pm );
   void        pcm_flag                  ( const CodingUnit&             cu,       Partitioner&      pm );
   void        cu_pred_data              ( const CodingUnit&             cu );
@@ -108,7 +109,12 @@ public:
   void        mip_flag                  ( const CodingUnit&             cu );
   void        mip_pred_modes            ( const CodingUnit&             cu );
   void        mip_pred_mode             ( const PredictionUnit&         pu );
-
+#if JVET_O0119_BASE_PALETTE_444
+  void        cu_palette_info			( const CodingUnit& cu, ComponentID compBegin, uint32_t NumComp, CUCtx& cuCtx);
+  void        cu_run_val				( uint32_t uiRun, PLTRunMode runtype, const uint32_t uiPltIdx, const uint32_t uiMaxRun);
+  void        encodeRunType				( const CodingUnit&  cu, PLTtypeBuf& runType, uint32_t idx, ScanElement *refScanOrder, ComponentID compBegin);
+  Pel         writePLTIndex			( const CodingUnit& cu, uint32_t idx, PelBuf& PLTIdx, PLTtypeBuf& PLTrunType, int maxSymbol, ComponentID compBegin);
+#endif
   // prediction unit (clause 7.3.8.6)
   void        prediction_unit           ( const PredictionUnit&         pu );
   void        merge_flag                ( const PredictionUnit&         pu );
@@ -186,12 +192,20 @@ private:
   unsigned    get_num_written_bits()    { return m_BinEncoder.getNumWrittenBits(); }
 
   void  xWriteTruncBinCode(uint32_t uiSymbol, uint32_t uiMaxSymbol);
-
+#if JVET_O0119_BASE_PALETTE_444
+  void		  codeScanRotationModeFlag	(const CodingUnit& cu, ComponentID compBegin);
+  void        xEncodePLTPredIndicator	(const CodingUnit& cu, uint32_t uiMaxPLTSize, ComponentID compBegin);
+  uint32_t	  xWriteTruncMsbP1			(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT);
+  void        xWriteTruncMsbP1RefinementBits(uint32_t uiSymbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT);
+#endif
 private:
   BinEncIf&         m_BinEncoder;
   OutputBitstream*  m_Bitstream;
   Ctx               m_TestCtx;
   EncCu*            m_EncCu;
+#if JVET_O0119_BASE_PALETTE_444
+  ScanElement*      m_puiScanOrder;
+#endif
 };
 
 
diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h
index df9f1d2a620e05d9e0441bb38a6f449a97760010..e0b4acdcc0170ed506730e3e70da6db4e7349d54 100644
--- a/source/Lib/EncoderLib/EncCfg.h
+++ b/source/Lib/EncoderLib/EncCfg.h
@@ -299,6 +299,9 @@ protected:
   bool      m_MMVD;
   int       m_MmvdDisNum;
   bool      m_RdpcmMode;
+#if JVET_O0119_BASE_PALETTE_444
+  unsigned  m_PLTMode;
+#endif
   unsigned  m_IBCMode;
   unsigned  m_IBCLocalSearchRangeX;
   unsigned  m_IBCLocalSearchRangeY;
@@ -870,6 +873,10 @@ public:
   int       getMmvdDisNum                   ()         const { return m_MmvdDisNum; }
   void      setRDPCM                     ( bool b )       { m_RdpcmMode = b; }
   bool      getRDPCM                     ()         const { return m_RdpcmMode; }
+#if JVET_O0119_BASE_PALETTE_444
+  void      setPLTMode					 ( unsigned n)	  { m_PLTMode = n; }
+  unsigned  getPLTMode					 ()		    const { return m_PLTMode; }
+#endif
   void      setIBCMode                      (unsigned n)     { m_IBCMode = n; }
   unsigned  getIBCMode                      ()         const { return m_IBCMode; }
   void      setIBCLocalSearchRangeX         (unsigned n)     { m_IBCLocalSearchRangeX = n; }
diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp
index 920639e84e3cdeca4df4199424c3236e0fcab6c0..f5d3d86ffad300530b62becaf97bcbfa92eed7c8 100644
--- a/source/Lib/EncoderLib/EncCu.cpp
+++ b/source/Lib/EncoderLib/EncCu.cpp
@@ -57,8 +57,6 @@
 extern std::recursive_mutex g_cache_mutex;
 #endif
 
-
-
 //! \ingroup EncoderLib
 //! \{
 
@@ -290,7 +288,9 @@ void EncCu::init( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int tId ) )
 void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsigned ctuRsAddr, const int prevQP[], const int currQP[] )
 {
   m_modeCtrl->initCTUEncoding( *cs.slice );
-
+#if JVET_O0119_BASE_PALETTE_444
+  cs.slice->m_mapPltCost.clear();
+#endif
 #if ENABLE_SPLIT_PARALLELISM
   if( m_pcEncCfg->getNumSplitThreads() > 1 )
   {
@@ -364,7 +364,9 @@ void EncCu::compressCtu( CodingStructure& cs, const UnitArea& area, const unsign
   tempCS->prevQP[CH_L] = bestCS->prevQP[CH_L] = prevQP[CH_L];
 
   xCompressCU( tempCS, bestCS, *partitioner );
-
+#if JVET_O0119_BASE_PALETTE_444
+  cs.slice->m_mapPltCost.clear();
+#endif
   // all signals were already copied during compression if the CTU was split - at this point only the structures are copied to the top level CS
   const bool copyUnsplitCTUSignals = bestCS->cus.size() == 1;
   cs.useSubStructure( *bestCS, partitioner->chType, CS::getArea( *bestCS, area, partitioner->chType ), copyUnsplitCTUSignals, false, false, copyUnsplitCTUSignals );
@@ -596,6 +598,42 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
     }
   }
 
+#endif
+#if JVET_O0119_BASE_PALETTE_444
+  uint32_t compBegin;
+  uint32_t NumComp;
+  bool jointPLT = false;
+  if (CS::isDualITree(*bestCS))
+  {
+	  if (isLuma(partitioner.chType))
+	  {
+		  compBegin = COMPONENT_Y;
+		  NumComp = 1;
+	  }
+	  else
+	  {
+		  compBegin = COMPONENT_Cb;
+		  NumComp = 2;
+	  }
+  }
+  else
+  {
+	  compBegin = COMPONENT_Y;
+	  NumComp = 3;
+	  jointPLT = true;
+  }
+  SplitSeries splitmode = -1;
+  uint32_t	bestLastPLTSize[MAX_NUM_COMPONENT];
+  Pel		bestLastPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE]; // store LastPLT for partition
+  uint32_t	curLastPLTSize[MAX_NUM_COMPONENT];
+  Pel		curLastPLT[MAX_NUM_COMPONENT][MAXPLTPREDSIZE]; // store LastPLT if no partition
+  for (int i = compBegin; i < (compBegin + NumComp); i++)
+  {
+	  ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+	  bestLastPLTSize[comID] = 0;
+	  curLastPLTSize[comID] = tempCS->prevPLT.curPLTSize[comID];
+	  memcpy(curLastPLT[i], tempCS->prevPLT.curPLT[i], tempCS->prevPLT.curPLTSize[comID] * sizeof(Pel));
+  }
 #endif
 
   Slice&   slice      = *tempCS->slice;
@@ -656,6 +694,14 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
 
   do
   {
+#if JVET_O0119_BASE_PALETTE_444
+	for (int i = compBegin; i < (compBegin + NumComp); i++)
+	{
+		ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+		tempCS->prevPLT.curPLTSize[comID] = curLastPLTSize[comID];
+		memcpy(tempCS->prevPLT.curPLT[i], curLastPLT[i], curLastPLTSize[comID] * sizeof(Pel));
+	}
+#endif
     EncTestMode currTestMode = m_modeCtrl->currTestMode();
 
     if (pps.getUseDQP() && CS::isDualITree(*tempCS) && isChroma(partitioner.chType))
@@ -742,6 +788,12 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
     {
       xCheckIntraPCM( tempCS, bestCS, partitioner, currTestMode );
     }
+#if JVET_O0119_BASE_PALETTE_444
+	else if (currTestMode.type == ETM_PALETTE)
+	{
+	  xCheckPLT( tempCS, bestCS, partitioner, currTestMode );
+	}
+#endif
     else if (currTestMode.type == ETM_IBC)
     {
       xCheckRDCostIBCMode(tempCS, bestCS, partitioner, currTestMode);
@@ -752,9 +804,28 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
     }
     else if( isModeSplit( currTestMode ) )
     {
-
+#if JVET_O0119_BASE_PALETTE_444
+		if (bestCS->cus.size() != 0)
+		{
+			splitmode = bestCS->cus[0]->splitSeries;
+		}
+#endif
       xCheckModeSplit( tempCS, bestCS, partitioner, currTestMode );
-    }
+#if JVET_O0119_BASE_PALETTE_444
+	  if (splitmode != bestCS->cus[0]->splitSeries)
+	  {
+		  splitmode = bestCS->cus[0]->splitSeries;
+		  const CodingUnit&     cu = *bestCS->cus.front();
+		  cu.cs->prevPLT = bestCS->prevPLT;
+		  for (int i = compBegin; i < (compBegin + NumComp); i++)
+		  {
+			  ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+			  bestLastPLTSize[comID] = bestCS->cus[0]->cs->prevPLT.curPLTSize[comID];
+			  memcpy(bestLastPLT[i], bestCS->cus[0]->cs->prevPLT.curPLT[i], bestCS->cus[0]->cs->prevPLT.curPLTSize[comID] * sizeof(Pel));
+		  }
+	  }
+#endif
+	}
     else
     {
       THROW( "Don't know how to handle mode: type = " << currTestMode.type << ", options = " << currTestMode.opts );
@@ -817,6 +888,41 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
     tempCS->picture->finishParallelPart( currCsArea );
   }
 
+#endif
+#if JVET_O0119_BASE_PALETTE_444
+  if (bestCS->cus.size() == 1) // no partition
+  {
+	  if (bestCS->cus[0]->predMode == MODE_PLT)
+	  {
+		  for (int i = compBegin; i < (compBegin + NumComp); i++)
+		  {
+			  ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+			  bestCS->prevPLT.curPLTSize[comID] = curLastPLTSize[comID];
+			  memcpy(bestCS->prevPLT.curPLT[i], curLastPLT[i], curLastPLTSize[comID] * sizeof(Pel));
+		  }
+		  bestCS->reorderPrevPLT(bestCS->prevPLT, bestCS->cus[0]->curPLTSize, bestCS->cus[0]->curPLT, bestCS->cus[0]->reuseflag, compBegin, NumComp, jointPLT);
+	  }
+	  else
+	  {
+		  for (int i = compBegin; i<(compBegin + NumComp); i++)
+		  {
+			  ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+			  bestCS->prevPLT.curPLTSize[comID] = curLastPLTSize[comID];
+			  memcpy(bestCS->prevPLT.curPLT[i], curLastPLT[i], bestCS->prevPLT.curPLTSize[comID] * sizeof(Pel));
+		  }
+	  }
+  }
+  else
+  {
+	  for (int i = compBegin; i<(compBegin + NumComp); i++)
+	  {
+		  ComponentID comID = jointPLT ? (ComponentID)compBegin : ((i > 0) ? COMPONENT_Cb : COMPONENT_Y);
+		  bestCS->prevPLT.curPLTSize[comID] = bestLastPLTSize[comID];
+		  memcpy(bestCS->prevPLT.curPLT[i], bestLastPLT[i], bestCS->prevPLT.curPLTSize[comID] * sizeof(Pel));
+	  }
+  }
+  const CodingUnit&     cu = *bestCS->cus.front();
+  cu.cs->prevPLT = bestCS->prevPLT;
 #endif
   // Assert if Best prediction mode is NONE
   // Selected mode's RD-cost must be not MAX_DOUBLE.
@@ -1106,6 +1212,9 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
   const PPS &pps              = *tempCS->pps;
   const uint32_t currDepth    = partitioner.currDepth;
 #endif
+#if JVET_O0119_BASE_PALETTE_444
+  const auto oldPLT = tempCS->prevPLT;
+#endif
 
   const PartSplit split = getPartSplit( encTestMode );
 
@@ -1345,6 +1454,10 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS,
 
   tempCS->motionLut = oldMotionLut;
 
+#if JVET_O0119_BASE_PALETTE_444
+  tempCS->prevPLT = oldPLT;
+#endif
+
   tempCS->releaseIntermediateData();
 
   tempCS->prevQP[partitioner.chType] = oldPrevQp;
@@ -1701,6 +1814,97 @@ void EncCu::xCheckIntraPCM(CodingStructure *&tempCS, CodingStructure *&bestCS, P
   xCheckBestMode( tempCS, bestCS, partitioner, encTestMode );
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+void EncCu::xCheckPLT(CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode)
+{
+	tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
+	CodingUnit &cu = tempCS->addCU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType);
+	partitioner.setCUData(cu);
+	cu.slice = tempCS->slice;
+	cu.tileIdx = tempCS->picture->brickMap->getBrickIdxRsMap(tempCS->area.lumaPos());
+	cu.skip = false;
+	cu.mmvdSkip = false;
+	cu.predMode = MODE_PLT;
+
+	cu.transQuantBypass = encTestMode.lossless;
+	cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
+	cu.qp = encTestMode.qp;
+	cu.ipcm = false;
+	cu.bdpcmMode = 0;
+
+	tempCS->addPU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType);
+	tempCS->addTU(CS::getArea(*tempCS, tempCS->area, partitioner.chType), partitioner.chType);
+	// Search
+	tempCS->dist = 0;	
+	if (CS::isDualITree(*tempCS))
+	{
+		if (isLuma(partitioner.chType))
+		{
+			m_pcIntraSearch->PLTSearch(*tempCS, partitioner, COMPONENT_Y, 1);
+		}
+		if (tempCS->area.chromaFormat != CHROMA_400 && (partitioner.chType == CHANNEL_TYPE_CHROMA))
+		{
+			m_pcIntraSearch->PLTSearch(*tempCS, partitioner, COMPONENT_Cb, 2);
+		}
+	}
+	else
+	{
+		m_pcIntraSearch->PLTSearch(*tempCS, partitioner, COMPONENT_Y, 3);
+	}
+
+
+	m_CABACEstimator->getCtx() = m_CurrCtx->start;
+	m_CABACEstimator->resetBits();
+	if (tempCS->pps->getTransquantBypassEnabledFlag())
+	{
+		m_CABACEstimator->cu_transquant_bypass_flag(cu);
+	}
+
+	if ((!cu.cs->slice->isIntra() || cu.cs->slice->getSPS()->getIBCFlag())
+		&& cu.Y().valid())
+	{
+		m_CABACEstimator->cu_skip_flag(cu);
+	}
+	m_CABACEstimator->pred_mode(cu);
+
+	// signaling
+	CUCtx cuCtx;
+	cuCtx.isDQPCoded = true;
+	cuCtx.isChromaQpAdjCoded = true;
+	if (CS::isDualITree(*tempCS))
+	{
+		if (isLuma(partitioner.chType))
+		{
+			m_CABACEstimator->cu_palette_info(cu, COMPONENT_Y, 1, cuCtx);
+		}
+		if (tempCS->area.chromaFormat != CHROMA_400 && (partitioner.chType == CHANNEL_TYPE_CHROMA))
+		{
+			m_CABACEstimator->cu_palette_info(cu, COMPONENT_Cb, 2, cuCtx);
+		}
+	}
+	else
+	{
+		m_CABACEstimator->cu_palette_info(cu, COMPONENT_Y, 3, cuCtx);
+	}
+	tempCS->fracBits = m_CABACEstimator->getEstFracBits();
+	tempCS->cost = m_pcRdCost->calcRdCost(tempCS->fracBits, tempCS->dist);
+
+	xEncodeDontSplit(*tempCS, partitioner);
+	xCheckDQP(*tempCS, partitioner);
+	xCalDebCost(*tempCS, partitioner);
+	tempCS->useDbCost = m_pcEncCfg->getUseEncDbOpt();
+
+	const Area curr_cu_area = cu.block(getFirstComponentOfChannel(partitioner.chType));
+	cu.slice->m_mapPltCost[curr_cu_area.pos()][curr_cu_area.size()] = tempCS->cost;
+#if WCG_EXT
+	DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda(true));
+#else
+	DTRACE_MODE_COST(*tempCS, m_pcRdCost->getLambda());
+#endif
+	xCheckBestMode(tempCS, bestCS, partitioner, encTestMode);
+}
+#endif
+
 void EncCu::xCheckDQP( CodingStructure& cs, Partitioner& partitioner, bool bKeepCtx )
 {
   CHECK( bKeepCtx && cs.cus.size() <= 1 && partitioner.getImplicitSplit( cs ) == CU_DONT_SPLIT, "bKeepCtx should only be set in split case" );
@@ -4312,7 +4516,11 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best
     cu.shareParentSize = tempCS->sharedBndSize;
     partitioner.setCUData( cu );
 
-    if( CU::isIntra( cu ) )
+    if( CU::isIntra( cu ) 
+#if JVET_O0119_BASE_PALETTE_444
+	|| CU::isPLT(cu)
+#endif
+	)
     {
       xReconIntraQT( cu );
     }
diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h
index 67ef7f05fe518c8696cd083004a1919fccc4e2c9..85eae09df486c21212329c30d285f8385d3a4b7e 100644
--- a/source/Lib/EncoderLib/EncCu.h
+++ b/source/Lib/EncoderLib/EncCu.h
@@ -143,10 +143,10 @@ private:
   void    updateLambda      ( Slice* slice, const int dQP, const bool updateRdCostLambda );
 #endif
   double                m_sbtCostSave[2];
-
 public:
   /// copy parameters from encoder class
   void  init                ( EncLib* pcEncLib, const SPS& sps PARL_PARAM( const int jId = 0 ) );
+
   void setDecCuReshaperInEncCU(EncReshape* pcReshape, ChromaFormat chromaFormatIDC) { initDecCuReshaper((Reshape*) pcReshape, chromaFormatIDC); }
   /// create internal buffers
   void  create              ( EncCfg* encCfg );
@@ -227,6 +227,10 @@ protected:
   }
   void xCheckRDCostIBCMode    ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
   void xCheckRDCostIBCModeMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode );
+
+#if JVET_O0119_BASE_PALETTE_444
+  void       xCheckPLT	( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode);
+#endif
 };
 
 //! \}
diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp
index ce97ff3119d935a3e1285c6efe55d32a056a4ef0..ff8bc8fc7765660852a2d4ea1db9f64d090b92d5 100644
--- a/source/Lib/EncoderLib/EncLib.cpp
+++ b/source/Lib/EncoderLib/EncLib.cpp
@@ -338,7 +338,11 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf )
     m_cInterSearch[jId].setTempBuffers( m_cIntraSearch[jId].getSplitCSBuf(), m_cIntraSearch[jId].getFullCSBuf(), m_cIntraSearch[jId].getSaveCSBuf() );
   }
 #else  // ENABLE_SPLIT_PARALLELISM || ENABLE_WPP_PARALLELISM
-  m_cCuEncoder.   init( this, sps0 );
+  m_cCuEncoder.   init( this, sps0 
+#if JVET_O0119_BASE_PALETTE_444
+	  , &m_cReshaper
+#endif
+  );
 
   // initialize transform & quantization class
   m_cTrQuant.init( nullptr,
@@ -939,7 +943,9 @@ void EncLib::xInitSPS(SPS &sps)
 #endif
   sps.setAffineAmvrEnabledFlag              ( m_AffineAmvr );
   sps.setUseDMVR                            ( m_DMVR );
-
+#if JVET_O0119_BASE_PALETTE_444
+  sps.setPLTMode							( m_PLTMode);
+#endif
   sps.setIBCFlag                            ( m_IBCMode);
   sps.setWrapAroundEnabledFlag                      ( m_wrapAround );
   sps.setWrapAroundOffset                   ( m_wrapAroundOffset );
diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp
index e59cca54ea2c5c10aaeff097391aad3904be5e53..31608c48bcfa74b1326aef5b601839833cf471c8 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.cpp
+++ b/source/Lib/EncoderLib/EncModeCtrl.cpp
@@ -768,13 +768,25 @@ void BestEncInfoCache::init( const Slice &slice )
 #if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS
   m_pCoeff  = new TCoeff[numCoeff*MAX_NUM_TUS];
   m_pPcmBuf = new Pel   [numCoeff*MAX_NUM_TUS];
+#if JVET_O0119_BASE_PALETTE_444
+  m_runType   = new bool[numCoeff*MAX_NUM_TUS];
+  m_runLength = new Pel [numCoeff*MAX_NUM_TUS];
+#endif
 #else
   m_pCoeff  = new TCoeff[numCoeff];
   m_pPcmBuf = new Pel   [numCoeff];
+#if JVET_O0119_BASE_PALETTE_444
+  m_runType   = new bool[numCoeff];
+  m_runLength = new Pel [numCoeff];
+#endif
 #endif
 
   TCoeff *coeffPtr = m_pCoeff;
   Pel    *pcmPtr   = m_pPcmBuf;
+#if JVET_O0119_BASE_PALETTE_444
+  bool   *runTypePtr   = m_runType;
+  Pel    *runLengthPtr = m_runLength;
+#endif
 
   m_dummyCS.pcv = m_slice_bencinf->getPPS()->pcv;
 
@@ -790,6 +802,10 @@ void BestEncInfoCache::init( const Slice &slice )
           {
             TCoeff *coeff[MAX_NUM_TBLOCKS] = { 0, };
             Pel    *pcmbf[MAX_NUM_TBLOCKS] = { 0, };
+#if JVET_O0119_BASE_PALETTE_444
+			bool   *runType[MAX_NUM_TBLOCKS]   = { 0, };
+			Pel    *runLength[MAX_NUM_TBLOCKS] = { 0, };
+#endif
 
 #if REUSE_CU_RESULTS_WITH_MULTIPLE_TUS
             for( int i = 0; i < MAX_NUM_TUS; i++ )
@@ -801,10 +817,18 @@ void BestEncInfoCache::init( const Slice &slice )
               {
                 coeff[i] = coeffPtr; coeffPtr += area.blocks[i].area();
                 pcmbf[i] = pcmPtr;   pcmPtr += area.blocks[i].area();
-              }
+#if JVET_O0119_BASE_PALETTE_444
+				runType[i]   = runTypePtr;	 runTypePtr += area.blocks[i].area();
+				runLength[i] = runLengthPtr; runLengthPtr += area.blocks[i].area();
+#endif
+			  }
 
               tu.cs = &m_dummyCS;
+#if JVET_O0119_BASE_PALETTE_444
+			  tu.init(coeff, pcmbf, runLength, runType);
+#else
               tu.init(coeff, pcmbf);
+#endif
             }
 #else
             const UnitArea &area = m_bestEncInfo[x][y][wIdx][hIdx]->tu;
@@ -813,10 +837,18 @@ void BestEncInfoCache::init( const Slice &slice )
             {
               coeff[i] = coeffPtr; coeffPtr += area.blocks[i].area();
               pcmbf[i] =   pcmPtr;   pcmPtr += area.blocks[i].area();
-            }
+#if JVET_O0119_BASE_PALETTE_444
+			  runType[i] = runTypePtr;     runTypePtr += area.blocks[i].area();
+			  runLength[i] = runLengthPtr; runLengthPtr += area.blocks[i].area();
+#endif
+			}
 
             m_bestEncInfo[x][y][wIdx][hIdx]->tu.cs = &m_dummyCS;
+#if JVET_O0119_BASE_PALETTE_444
+			m_bestEncInfo[x][y][wIdx][hIdx]->tu.init(coeff, pcmbf, runLength, runType);
+#else
             m_bestEncInfo[x][y][wIdx][hIdx]->tu.init( coeff, pcmbf );
+#endif
 #endif
           }
         }
@@ -1083,7 +1115,9 @@ void EncModeCtrlMTnoRQT::initCTUEncoding( const Slice &slice )
   }
 }
 
-
+#if JVET_O0119_BASE_PALETTE_444
+extern bool doPlt;
+#endif
 void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStructure& cs )
 {
   // Min/max depth
@@ -1311,8 +1345,20 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru
 #endif
     // add intra modes
     m_ComprCUCtxList.back().testModes.push_back( { ETM_IPCM,  ETO_STANDARD, qp, lossless } );
-    m_ComprCUCtxList.back().testModes.push_back( { ETM_INTRA, ETO_STANDARD, qp, lossless } );
-    // add ibc mode to intra path
+#if JVET_O0119_BASE_PALETTE_444
+	if (cs.slice->getSPS()->getPLTMode() && cs.slice->isIRAP() && doPlt)
+	{
+		m_ComprCUCtxList.back().testModes.push_back({ ETM_PALETTE, ETO_STANDARD, qp, lossless });
+	}
+#endif
+	m_ComprCUCtxList.back().testModes.push_back( { ETM_INTRA, ETO_STANDARD, qp, lossless } );
+#if JVET_O0119_BASE_PALETTE_444
+	if (cs.slice->getSPS()->getPLTMode() && !cs.slice->isIRAP() && doPlt)
+	{
+		m_ComprCUCtxList.back().testModes.push_back({ ETM_PALETTE,  ETO_STANDARD, qp, lossless });
+	}
+#endif	
+	// add ibc mode to intra path
     if (cs.sps->getIBCFlag() && checkIbc)
     {
       m_ComprCUCtxList.back().testModes.push_back({ ETM_IBC,         ETO_STANDARD,  qp, lossless });
@@ -1526,9 +1572,37 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
         }
       }
     }
-
+#if JVET_O0119_BASE_PALETTE_444
+	if (bestMode.type == ETM_PALETTE && !slice.isIRAP()) // inter slice
+	{
+		return false;
+	}
+#endif
     return true;
   }
+#if JVET_O0119_BASE_PALETTE_444
+  else if (encTestmode.type == ETM_PALETTE)
+  {
+	  if (partitioner.currArea().lumaSize().width > 64 || partitioner.currArea().lumaSize().height > 64)
+	  {
+		  return false;
+	  }
+	  const Area curr_cu = CS::getArea(cs, cs.area, partitioner.chType).blocks[getFirstComponentOfChannel(partitioner.chType)];
+	  try
+	  {
+		  double stored_cost = slice.m_mapPltCost.at(curr_cu.pos()).at(curr_cu.size());
+		  if (bestMode.type != ETM_INVALID && stored_cost > cuECtx.bestCS->cost)
+		  {
+			  return false;
+		  }
+	  }
+	  catch (const std::out_of_range &)
+	  {
+		  // do nothing if no stored cost value was found.
+	  }
+	  return true;
+  }
+#endif
   else if( encTestmode.type == ETM_IPCM )
   {
     if( getFastDeltaQp() )
diff --git a/source/Lib/EncoderLib/EncModeCtrl.h b/source/Lib/EncoderLib/EncModeCtrl.h
index d29d095c48ae7ee756f981d7b83d533d168b06c4..db4c14e7eea799e429a14119ff6eca6c2d5f34e9 100644
--- a/source/Lib/EncoderLib/EncModeCtrl.h
+++ b/source/Lib/EncoderLib/EncModeCtrl.h
@@ -64,6 +64,9 @@ enum EncTestModeType
   ETM_MERGE_TRIANGLE,
   ETM_INTRA,
   ETM_IPCM,
+#if JVET_O0119_BASE_PALETTE_444
+  ETM_PALETTE,  
+#endif
   ETM_SPLIT_QT,
   ETM_SPLIT_BT_H,
   ETM_SPLIT_BT_V,
@@ -465,6 +468,10 @@ private:
   BestEncodingInfo ***m_bestEncInfo[MAX_CU_SIZE >> MIN_CU_LOG2][MAX_CU_SIZE >> MIN_CU_LOG2];
   TCoeff             *m_pCoeff;
   Pel                *m_pPcmBuf;
+#if JVET_O0119_BASE_PALETTE_444
+  bool               *m_runType;
+  Pel                *m_runLength;
+#endif
   CodingStructure     m_dummyCS;
   XUCache             m_dummyCache;
 #if ENABLE_SPLIT_PARALLELISM
diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp
index 1e75780bbd9b591b0458bf9c8f06a95d8b1aa350..3309cc1b7cb8c023220f6d4d84324292dad665cb 100644
--- a/source/Lib/EncoderLib/EncSlice.cpp
+++ b/source/Lib/EncoderLib/EncSlice.cpp
@@ -329,6 +329,9 @@ void EncSlice::initEncSlice(Picture* pcPic, const int pocLast, const int pocCurr
 {
   double dQP;
   double dLambda;
+#if JVET_O0119_BASE_PALETTE_444
+  pcPic->cs->resetPrevPLT(pcPic->cs->prevPLT);
+#endif
 
   rpcSlice = pcPic->slices[0];
   rpcSlice->setSliceBits(0);
@@ -1284,6 +1287,9 @@ void EncSlice::calCostSliceI(Picture* pcPic) // TODO: this only analyses the fir
 
 /** \param pcPic   picture class
  */
+#if JVET_O0119_BASE_PALETTE_444
+extern bool doPlt;
+#endif
 void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP )
 {
   // if bCompressEntireSlice is true, then the entire slice (not slice segment) is compressed,
@@ -1385,6 +1391,14 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c
   }
 #endif // ENABLE_QPA
 
+#if JVET_O0119_BASE_PALETTE_444
+  bool bCheckPLTRatio = m_pcCfg->getIntraPeriod() != 1 && pcSlice->isIRAP();
+  if (bCheckPLTRatio)
+  {
+	  doPlt = true;
+  }
+#endif
+
 #if ENABLE_WPP_PARALLELISM
   bool bUseThreads = m_pcCfg->getNumWppThreads() > 1;
   if( bUseThreads )
@@ -1419,8 +1433,32 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c
   m_pcInterSearch->resetUniMvList();
 #endif 
   encodeCtus( pcPic, bCompressEntireSlice, bFastDeltaQP, startCtuTsAddr, boundingCtuTsAddr, m_pcLib );
-
-
+#if JVET_O0119_BASE_PALETTE_444
+  if (bCheckPLTRatio)
+  {
+	  int total_area = 0;
+	  int plt_area = 0;
+	  for (auto apu : pcPic->cs->pus)
+	  {
+		  for (int i = 0; i < MAX_NUM_TBLOCKS; ++i)
+		  {
+			  int pu_area = apu->blocks[i].width * apu->blocks[i].height;
+			  if (apu->blocks[i].width > 0 && apu->blocks[i].height > 0)
+			  {
+				  total_area += pu_area;
+				  if (CU::isPLT(*apu->cu) || CU::isIBC(*apu->cu))
+				  {
+					  plt_area += pu_area;
+				  }
+				  break;
+			  }
+
+		  }
+	  }
+	  if (plt_area * PLT_FAST_RATIO < total_area)
+		  doPlt = false;
+  }
+#endif
 }
 
 void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr )
@@ -1597,12 +1635,18 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons
     if (ctuRsAddr == firstCtuRsAddrOfTile)
     {
       pCABACWriter->initCtxModels( *pcSlice );
+#if JVET_O0119_BASE_PALETTE_444
+	  cs.resetPrevPLT(cs.prevPLT);
+#endif
       prevQP[0] = prevQP[1] = pcSlice->getSliceQp();
     }
     else if (ctuXPosInCtus == tileXPosInCtus && pEncLib->getEntropyCodingSyncEnabledFlag())
     {
       // reset and then update contexts to the state at the end of the top-right CTU (if within current slice and tile).
       pCABACWriter->initCtxModels( *pcSlice );
+#if JVET_O0119_BASE_PALETTE_444
+	  cs.resetPrevPLT(cs.prevPLT);
+#endif
       if( cs.getCURestricted( pos.offset(0, -1), pos, pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) )
       {
         // Top-right is available, we use it.
@@ -1887,6 +1931,9 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
       if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset
       {
         m_CABACWriter->initCtxModels( *pcSlice );
+#if JVET_O0119_BASE_PALETTE_444
+		cs.resetPrevPLT(cs.prevPLT);
+#endif
       }
     }
     else if (ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled)
@@ -1895,6 +1942,9 @@ void EncSlice::encodeSlice   ( Picture* pcPic, OutputBitstream* pcSubstreams, ui
       if (ctuTsAddr != startCtuTsAddr) // if it is the first CTU, then the entropy coder has already been reset
       {
         m_CABACWriter->initCtxModels( *pcSlice );
+#if	JVET_O0119_BASE_PALETTE_444		
+		cs.resetPrevPLT(cs.prevPLT);
+#endif
       }
       if( cs.getCURestricted( pos.offset( 0, -1 ), pos, pcSlice->getIndependentSliceIdx(), tileMap.getBrickIdxRsMap( pos ), CH_L ) )
       {
diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp
index 9f501fe5b2eab56103500b47daf0a6907f0ac431..17f11a0bd86ce29430612cae7fa1f0f5b2b70228 100644
--- a/source/Lib/EncoderLib/IntraSearch.cpp
+++ b/source/Lib/EncoderLib/IntraSearch.cpp
@@ -49,10 +49,11 @@
 
 #include <math.h>
 #include <limits>
-
  //! \ingroup EncoderLib
  //! \{
-
+#if JVET_O0119_BASE_PALETTE_444
+#define PLTCtx(c) SubCtx( Ctx::Palette, c )
+#endif
 IntraSearch::IntraSearch()
   : m_pSplitCS      (nullptr)
   , m_pFullCS       (nullptr)
@@ -1460,6 +1461,583 @@ void IntraSearch::xEncPCM(CodingStructure &cs, Partitioner& partitioner, const C
   }
 }
 
+#if JVET_O0119_BASE_PALETTE_444
+void IntraSearch::PLTSearch(CodingStructure &cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+	TransformUnit &tu = *cs.getTU(partitioner.chType);
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+	m_orgCtxRD = PLTCtx(m_CABACEstimator->getCtx());
+
+	if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
+	{
+		cs.getPredBuf().copyFrom(cs.getOrgBuf());
+		cs.getPredBuf().Y().rspSignal(m_pcReshape->getFwdLUT());
+	}
+
+	Pel *pRunLength = tu.get_vRunLength(compBegin);
+	bool *pRunType = tu.get_vRunType(compBegin);
+	cu.lastPLTSize[compBegin] = cs.prevPLT.curPLTSize[compBegin];
+	//derive palette
+	derivePLTLossy(cs, partitioner, compBegin, NumComp);
+	reorderPLT(cs, partitioner, compBegin, NumComp);
+
+	//calculate palette index
+	preCalcPLTIndex(cs, partitioner, compBegin, NumComp);
+	//derive run
+	uint64_t uiBits = MAX_UINT;
+	deriveRunAndCalcBits(cs, partitioner, compBegin, NumComp, PLT_SCAN_HORTRAV, uiBits);
+	if ((cu.curPLTSize[compBegin] + cu.useEscape[compBegin]) > 1)
+	{
+		deriveRunAndCalcBits(cs, partitioner, compBegin, NumComp, PLT_SCAN_VERTRAV, uiBits);
+	}
+	cu.useRotation[compBegin] = m_bBestScanRotationMode;
+	memcpy(pRunType, m_runTypeRD, sizeof(bool)*uiWidth*uiHeight);
+	memcpy(pRunLength, m_runLengthRD, sizeof(Pel)*uiWidth*uiHeight);
+	//reconstruct pixel
+	PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
+	for (uint32_t uiY = 0; uiY < uiHeight; uiY++)
+	{
+		for (uint32_t uiX = 0; uiX < uiWidth; uiX++)
+		{
+			if (curPLTIdx.at(uiX, uiY) == cu.curPLTSize[compBegin])
+			{
+
+			}
+			else
+			{
+				for (uint32_t compID = compBegin; compID < (compBegin + NumComp); compID++)
+				{
+					CompArea  area = cu.blocks[compID];
+					PelBuf    recBuf = cs.getRecoBuf(area);
+					uint32_t scaleX = getComponentScaleX((ComponentID)COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+					uint32_t scaleY = getComponentScaleY((ComponentID)COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+					if (compBegin != COMPONENT_Y || compID == COMPONENT_Y)
+					{
+						recBuf.at(uiX, uiY) = cu.curPLT[compID][curPLTIdx.at(uiX, uiY)];
+					}
+					else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && uiY % (1 << scaleY) == 0 && uiX % (1 << scaleX) == 0)
+					{
+						CompArea  area = cu.blocks[compID];
+						PelBuf    recBuf = cs.getRecoBuf(area);
+						recBuf.at(uiX >> scaleX, uiY >> scaleY) = cu.curPLT[compID][curPLTIdx.at(uiX, uiY)];
+					}
+				}
+			}
+		}
+	}
+
+	cs.getPredBuf().fill(0);
+	cs.getResiBuf().fill(0);
+	cs.getOrgResiBuf().fill(0);
+
+	cs.fracBits = MAX_UINT;
+	cs.cost = MAX_DOUBLE;
+	Distortion distortion = 0;
+	for (uint32_t comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		const ComponentID compID = ComponentID(comp);
+		CPelBuf reco = cs.getRecoBuf(compID);
+		CPelBuf org = cs.getOrgBuf(compID);
+#if WCG_EXT
+		if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (
+			m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag())))
+		{
+			const CPelBuf orgLuma = cs.getOrgBuf(cs.area.blocks[COMPONENT_Y]);
+
+			if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled()))
+			{
+				const CompArea &areaY = cu.Y();
+				CompArea      tmpArea1(COMPONENT_Y, areaY.chromaFormat, Position(0, 0), areaY.size());
+				PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1);
+				tmpRecLuma.copyFrom(reco);
+				tmpRecLuma.rspSignal(m_pcReshape->getInvLUT());
+				distortion += m_pcRdCost->getDistPart(org, tmpRecLuma, cs.sps->getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
+			}
+			else
+			{
+				distortion += m_pcRdCost->getDistPart(org, reco, cs.sps->getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma);
+			}
+		}
+		else
+#endif
+			distortion += m_pcRdCost->getDistPart(org, reco, cs.sps->getBitDepth(toChannelType(compID)), compID, DF_SSE);
+	}
+
+	cs.dist += distortion;
+	const CompArea &area = cu.blocks[compBegin];
+	cs.setDecomp(area);
+	cs.picture->getRecoBuf(area).copyFrom(cs.getRecoBuf(area));
+}
+void IntraSearch::deriveRunAndCalcBits(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp, PLTScanMode pltScanMode, uint64_t& uiMinBits)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+	TransformUnit &tu = *cs.getTU(partitioner.chType);
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+	Pel *pRunLength = tu.get_vRunLength(compBegin);
+	bool *pRunType = tu.get_vRunType(compBegin);
+
+	cu.useRotation[compBegin] = (pltScanMode == PLT_SCAN_VERTRAV); // JC: rotate
+
+	m_puiScanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(uiWidth)][gp_sizeIdxInfo->idxFrom(uiHeight)];
+	deriveRun(cs, partitioner, compBegin, NumComp);
+
+	m_CABACEstimator->getCtx() = PLTCtx(m_orgCtxRD);
+	m_CABACEstimator->resetBits();
+
+	CUCtx cuCtx;
+	cuCtx.isDQPCoded = true;
+	cuCtx.isChromaQpAdjCoded = true;
+	m_CABACEstimator->cu_palette_info(cu, compBegin, NumComp, cuCtx);
+	uint64_t nBitsTemp = m_CABACEstimator->getEstFracBits();
+	if (uiMinBits > nBitsTemp)
+	{
+		m_bBestScanRotationMode = pltScanMode;
+		memcpy(m_runTypeRD, pRunType, sizeof(bool)*uiWidth*uiHeight);
+		memcpy(m_runLengthRD, pRunLength, sizeof(Pel)*uiWidth*uiHeight);
+		uiMinBits = nBitsTemp;
+	}
+}
+void IntraSearch::deriveRun(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+	TransformUnit &tu = *cs.getTU(partitioner.chType);
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+	uint32_t uiTotal = uiHeight * uiWidth, uiIdx = 0;
+	uint32_t uiStartPos = 0;
+	uint64_t indexBits = 0, runBitsIndex = 0, runBitsCopy = 0;
+	m_storeCtx_Run = PLTCtx(m_orgCtxRD);
+
+	PLTtypeBuf    runType = tu.getrunType(compBegin);
+	PelBuf    runLength = tu.getrunLength(compBegin);
+	while (uiIdx < uiTotal)
+	{
+		uiStartPos = uiIdx;
+		double dAveBitsPerPix[NUM_PLT_RUN];
+
+		uint32_t uiIndexRun = 0;
+		bool RunValid = calIndexRun(cs, partitioner, uiStartPos, uiTotal, uiIndexRun, compBegin);
+		m_CABACEstimator->getCtx() = PLTCtx(m_storeCtx_Run);
+		dAveBitsPerPix[PLT_RUN_INDEX] = RunValid ? getRunBits(cu, uiIndexRun, uiStartPos, PLT_RUN_INDEX, &indexBits, &runBitsIndex, compBegin) : MAX_DOUBLE;
+		m_storeCtx_RunIndex = PLTCtx(m_CABACEstimator->getCtx());
+
+		uint32_t uiCopyRun = 0;
+		bool CopyValid = calCopyRun(cs, partitioner, uiStartPos, uiTotal, uiCopyRun, compBegin);
+		m_CABACEstimator->getCtx() = PLTCtx(m_storeCtx_Run);
+		dAveBitsPerPix[PLT_RUN_COPY] = CopyValid ? getRunBits(cu, uiCopyRun, uiStartPos, PLT_RUN_COPY, &indexBits, &runBitsCopy, compBegin) : MAX_DOUBLE;
+		m_storeCtx_RunCopy = PLTCtx(m_CABACEstimator->getCtx());
+
+		if (CopyValid == 0 && RunValid == 0)
+		{
+			assert(0);
+		}
+		else
+		{
+			if (dAveBitsPerPix[PLT_RUN_COPY] <= dAveBitsPerPix[PLT_RUN_INDEX])
+			{
+				for (int runidx = 0; runidx <uiCopyRun; runidx++)
+				{
+					uint32_t posy = m_puiScanOrder[uiIdx + runidx].y;
+					uint32_t posx = m_puiScanOrder[uiIdx + runidx].x;
+					runType.at(posx, posy) = PLT_RUN_COPY;
+					runLength.at(posx, posy) = uiCopyRun;
+				}
+				uiIdx += uiCopyRun;
+				m_storeCtx_Run = PLTCtx(m_storeCtx_RunCopy);
+
+			}
+			else
+			{
+				for (int runidx = 0; runidx <uiIndexRun; runidx++)
+				{
+					uint32_t posy = m_puiScanOrder[uiIdx + runidx].y;
+					uint32_t posx = m_puiScanOrder[uiIdx + runidx].x;
+					runType.at(posx, posy) = PLT_RUN_INDEX;
+					runLength.at(posx, posy) = uiIndexRun;
+				}
+				uiIdx += uiIndexRun;
+				m_storeCtx_Run = PLTCtx(m_storeCtx_RunIndex);
+
+			}
+		}
+	}
+	assert(uiIdx == uiTotal);
+}
+double IntraSearch::getRunBits(const CodingUnit&  cu, uint32_t run, uint32_t strPos, PLTRunMode PaletteRunMode, uint64_t* indexBits, uint64_t* runBits, ComponentID compBegin)
+{
+	TransformUnit&   tu = *cu.firstTU;
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+	uint32_t endPos = uiHeight*uiWidth;
+	PLTtypeBuf   runType = tu.getrunType(compBegin);
+	PelBuf   curPLTIdx = tu.getcurPLTIdx(compBegin);
+	uint32_t uiIndexMaxSize = (cu.useEscape[compBegin]) ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin];
+
+	m_CABACEstimator->resetBits();
+	///////////////// encode Run Type
+	m_CABACEstimator->encodeRunType(cu, runType, strPos, m_puiScanOrder, compBegin);
+	uint64_t RunTypeBits = m_CABACEstimator->getEstFracBits();
+	uint32_t curLevel = 0;
+	switch (PaletteRunMode)
+	{
+	case PLT_RUN_INDEX:
+		curLevel = m_CABACEstimator->writePLTIndex(cu, strPos, curPLTIdx, runType, uiIndexMaxSize, compBegin);
+		*indexBits = m_CABACEstimator->getEstFracBits() - RunTypeBits;
+		m_CABACEstimator->cu_run_val(run - 1, PLT_RUN_INDEX, curLevel, endPos - strPos - 1);
+		*runBits = m_CABACEstimator->getEstFracBits() - RunTypeBits - (*indexBits);
+		break;
+	case PLT_RUN_COPY:
+		m_CABACEstimator->cu_run_val(run - 1, PLT_RUN_COPY, curLevel, endPos - strPos - 1);
+		*runBits = m_CABACEstimator->getEstFracBits() - RunTypeBits;
+		break;
+	default:
+		assert(0);
+	}
+	assert(run >= 1);
+	double dCostPerPixel = (double)m_CABACEstimator->getEstFracBits() / (double)run;
+	return dCostPerPixel;
+}
+void IntraSearch::preCalcPLTIndex(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+	TransformUnit &tu = *cs.getTU(partitioner.chType);
+	const int  channelBitDepth_L = cs.sps->getBitDepth(CHANNEL_TYPE_LUMA);
+	const int  channelBitDepth_C = cs.sps->getBitDepth(CHANNEL_TYPE_CHROMA);
+	const int  pcmShiftRight_L = (channelBitDepth_L - PLT_ENCBITDEPTH);
+	const int  pcmShiftRight_C = (channelBitDepth_C - PLT_ENCBITDEPTH);
+
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+
+	CPelBuf   orgBuf[3];
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		CompArea  area = cu.blocks[comp];
+		if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
+		{
+			orgBuf[comp] = cs.getPredBuf(area);
+		}
+		else
+		{
+			orgBuf[comp] = cs.getOrgBuf(area);
+		}
+	}
+
+	PelBuf    curPLTIdx = tu.getcurPLTIdx(compBegin);
+	int iErrorLimit = NumComp * g_uhPLTQuant[cu.qp];
+
+	uint32_t uiBestIdx = 0;
+
+
+	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+	for (uint32_t uiY = 0; uiY < uiHeight; uiY++)
+	{
+		for (uint32_t uiX = 0; uiX < uiWidth; uiX++)
+		{
+			uint32_t uiPLTIdx = 0;
+			uint32_t uiMinError = MAX_UINT;
+			while (uiPLTIdx < cu.curPLTSize[compBegin])
+			{
+				uint32_t uiAbsError = 0, pX, pY;
+				for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+				{
+					pX = (comp > 0 && compBegin == COMPONENT_Y) ? (uiX >> scaleX) : uiX;
+					pY = (comp > 0 && compBegin == COMPONENT_Y) ? (uiY >> scaleY) : uiY;
+					int shift = (comp > 0) ? pcmShiftRight_C : pcmShiftRight_L;
+					uiAbsError += abs(cu.curPLT[comp][uiPLTIdx] - orgBuf[comp].at(pX, pY)) >> shift;
+				}
+
+				if (uiAbsError < uiMinError)
+				{
+					uiBestIdx = uiPLTIdx;
+					uiMinError = uiAbsError;
+					if (uiMinError == 0)
+					{
+						break;
+					}
+				}
+				uiPLTIdx++;
+			}
+			curPLTIdx.at(uiX, uiY) = uiBestIdx;
+
+			if (uiMinError > iErrorLimit)
+			{
+				curPLTIdx.at(uiX, uiY) = cu.curPLTSize[compBegin];
+				cu.useEscape[compBegin] = true;
+				calcPixelPred(cs, partitioner, uiY, uiX, compBegin, NumComp);
+			}
+
+		}
+	}
+}
+void IntraSearch::calcPixelPred(CodingStructure& cs, Partitioner& partitioner, uint32_t uiY, uint32_t uiX, ComponentID compBegin, uint32_t NumComp)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+	TransformUnit &tu = *cs.getTU(partitioner.chType);
+
+	CPelBuf   orgBuf[3];
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		CompArea  area = cu.blocks[comp];
+		if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
+		{
+			orgBuf[comp] = cs.getPredBuf(area);
+		}
+		else
+		{
+			orgBuf[comp] = cs.getOrgBuf(area);
+		}
+	}
+
+	int iQP[3];
+	int iQPrem[3];
+	int iQPper[3];
+	int quantiserScale[3];
+	int quantiserRightShift[3];
+	int rightShiftOffset[3];
+	int InvquantiserRightShift[3];
+	int iAdd[3];
+	for (uint32_t ch = compBegin; ch < (compBegin + NumComp); ch++)
+	{
+		QpParam cQP(tu, ComponentID(ch));
+		iQP[ch] = cQP.Qp;
+		iQPrem[ch] = iQP[ch] % 6;
+		iQPper[ch] = iQP[ch] / 6;
+		quantiserScale[ch] = g_quantScales[0][iQPrem[ch]];
+		quantiserRightShift[ch] = QUANT_SHIFT + iQPper[ch];
+		rightShiftOffset[ch] = 1 << (quantiserRightShift[ch] - 1);
+		InvquantiserRightShift[ch] = IQUANT_SHIFT;
+		iAdd[ch] = 1 << (InvquantiserRightShift[ch] - 1);
+	}
+
+	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+
+	for (uint32_t ch = compBegin; ch < (compBegin + NumComp); ch++)
+	{
+		const int  channelBitDepth = cu.cs->sps->getBitDepth(toChannelType((ComponentID)ch));
+		CompArea  area = cu.blocks[ch];
+		PelBuf    recBuf = cs.getRecoBuf(area);
+		PLTescapeBuf    escapeValue = tu.getescapeValue((ComponentID)ch);
+		if (compBegin != COMPONENT_Y || ch == 0)
+		{
+			escapeValue.at(uiX, uiY) = TCoeff(std::max<int>(0, ((orgBuf[ch].at(uiX, uiY) * quantiserScale[ch] + rightShiftOffset[ch]) >> quantiserRightShift[ch])));
+			assert(escapeValue.at(uiX, uiY) < (1 << (channelBitDepth + 1)));
+			recBuf.at(uiX, uiY) = (((escapeValue.at(uiX, uiY)*g_invQuantScales[0][iQPrem[ch]]) << iQPper[ch]) + iAdd[ch]) >> InvquantiserRightShift[ch];
+			recBuf.at(uiX, uiY) = Pel(ClipBD<int>(recBuf.at(uiX, uiY), channelBitDepth));//to be checked
+		}
+		else if (compBegin == COMPONENT_Y && ch > 0 && uiY % (1 << scaleY) == 0 && uiX % (1 << scaleX) == 0)
+		{
+			uint32_t uiYC = uiY >> scaleY;
+			uint32_t uiXC = uiX >> scaleX;
+			escapeValue.at(uiXC, uiYC) = TCoeff(std::max<int>(0, ((orgBuf[ch].at(uiXC, uiYC) * quantiserScale[ch] + rightShiftOffset[ch]) >> quantiserRightShift[ch])));
+			assert(escapeValue.at(uiXC, uiYC) < (1 << (channelBitDepth + 1)));
+			recBuf.at(uiXC, uiYC) = (((escapeValue.at(uiXC, uiYC)*g_invQuantScales[0][iQPrem[ch]]) << iQPper[ch]) + iAdd[ch]) >> InvquantiserRightShift[ch];
+			recBuf.at(uiXC, uiYC) = Pel(ClipBD<int>(recBuf.at(uiXC, uiYC), channelBitDepth));//to be checked
+		}
+	}
+}
+void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp)
+{
+	CodingUnit &cu = *cs.getCU(partitioner.chType);
+	const int  channelBitDepth_L = cs.sps->getBitDepth(CHANNEL_TYPE_LUMA);
+	const int  channelBitDepth_C = cs.sps->getBitDepth(CHANNEL_TYPE_CHROMA);
+	const int pcmShiftRight_L = (channelBitDepth_L - PLT_ENCBITDEPTH);
+	const int pcmShiftRight_C = (channelBitDepth_C - PLT_ENCBITDEPTH);
+
+	uint32_t uiHeight = cu.block(compBegin).height;
+	uint32_t uiWidth = cu.block(compBegin).width;
+
+	CPelBuf   orgBuf[3];
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		CompArea  area = cu.blocks[comp];
+		if (m_pcEncCfg->getReshaper() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))
+		{
+			orgBuf[comp] = cs.getPredBuf(area);
+		}
+		else
+		{
+			orgBuf[comp] = cs.getOrgBuf(area);
+		}
+	}
+
+	int iErrorLimit = g_uhPLTQuant[cu.qp];
+
+	uint32_t uiTotalSize = uiHeight*uiWidth;
+	SortingElement *psList = new SortingElement[uiTotalSize];
+	SortingElement sElement;
+	uint32_t uiDictMaxSize = MAXPLTSIZE;
+	SortingElement *pListSort = new SortingElement[MAXPLTSIZE + 1];
+	uint32_t uiIdx = 0;
+	int last = -1;
+
+	uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+	uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, cs.sps->getChromaFormatIdc());
+	for (uint32_t uiY = 0; uiY < uiHeight; uiY++)
+	{
+		for (uint32_t uiX = 0; uiX < uiWidth; uiX++)
+		{
+			uint32_t paOrig[3], pX, pY;
+			for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+			{
+				pX = (comp > 0 && compBegin == COMPONENT_Y) ? (uiX >> scaleX) : uiX;
+				pY = (comp > 0 && compBegin == COMPONENT_Y) ? (uiY >> scaleY) : uiY;
+				paOrig[comp] = orgBuf[comp].at(pX, pY);
+			}
+			sElement.setAll(paOrig, compBegin, NumComp);
+			int besti = last, bestSAD = (last == -1) ? MAX_UINT : psList[last].getSAD(sElement, cs.sps->getBitDepths(), compBegin, NumComp);
+			if (bestSAD)
+			{
+				for (int i = uiIdx - 1; i >= 0; i--)
+				{
+					uint32_t sad = psList[i].getSAD(sElement, cs.sps->getBitDepths(), compBegin, NumComp);
+					if (sad < bestSAD)
+					{
+						bestSAD = sad;
+						besti = i;
+						if (!sad) break;
+					}
+				}
+			}
+			if (besti >= 0 && psList[besti].almostEqualData(sElement, iErrorLimit, cs.sps->getBitDepths(), compBegin, NumComp))
+			{
+				psList[besti].addElement(sElement, compBegin, NumComp);
+				last = besti;
+			}
+			else
+			{
+				psList[uiIdx].copyDataFrom(sElement, compBegin, NumComp);
+				psList[uiIdx].uiCnt = 1;
+				last = uiIdx;
+				uiIdx++;
+			}
+		}
+	}
+
+	for (int i = 0; i < uiDictMaxSize; i++)
+	{
+		pListSort[i].uiCnt = 0;
+		pListSort[i].resetAll(compBegin, NumComp);
+	}
+
+	//bubble sorting
+	uiDictMaxSize = 1;
+	for (int i = 0; i < uiIdx; i++)
+	{
+		if (psList[i].uiCnt > pListSort[uiDictMaxSize - 1].uiCnt)
+		{
+			int j;
+			for (j = uiDictMaxSize; j > 0; j--)
+			{
+				if (psList[i].uiCnt > pListSort[j - 1].uiCnt)
+				{
+					pListSort[j].copyAllFrom(pListSort[j - 1], compBegin, NumComp);
+					uiDictMaxSize = std::min(uiDictMaxSize + 1, (uint32_t)MAXPLTSIZE);
+				}
+				else
+				{
+					break;
+				}
+			}
+			pListSort[j].copyAllFrom(psList[i], compBegin, NumComp);
+		}
+	}
+
+	uint32_t uiPLTSize = 0;
+	uint64_t numColorBits = 0;
+	for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+	{
+		numColorBits += (comp > 0) ? channelBitDepth_C : channelBitDepth_L;
+	}
+
+	double bitCost = m_pcRdCost->getLambda()*numColorBits;
+	for (int i = 0; i < MAXPLTSIZE; i++)
+	{
+		if (pListSort[i].uiCnt)
+		{
+			int iHalf = pListSort[i].uiCnt >> 1;
+			for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+			{
+				cu.curPLT[comp][uiPLTSize] = (pListSort[i].uiSumData[comp] + iHalf) / pListSort[i].uiCnt;
+			}
+
+			int best = -1;
+			if (iErrorLimit)
+			{
+				double pal[MAX_NUM_COMPONENT], err = 0.0, bestCost = 0.0;
+				for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+				{
+					const int shift = (comp > 0) ? pcmShiftRight_C : pcmShiftRight_L;
+					pal[comp] = pListSort[i].uiSumData[comp] / (double)pListSort[i].uiCnt;
+					err = pal[comp] - cu.curPLT[comp][uiPLTSize];
+					bestCost += (err*err) / (1 << (2 * shift));
+				}
+				bestCost = bestCost * pListSort[i].uiCnt + bitCost;
+
+				for (int t = 0; t < cs.prevPLT.curPLTSize[compBegin]; t++)
+				{
+					double cost = 0.0;
+					for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+					{
+						const int shift = (comp > 0) ? pcmShiftRight_C : pcmShiftRight_L;
+						err = pal[comp] - cs.prevPLT.curPLT[comp][t];
+						cost += (err*err) / (1 << (2 * shift));
+					}
+					cost *= pListSort[i].uiCnt;
+					if (cost < bestCost)
+					{
+						best = t;
+						bestCost = cost;
+					}
+				}
+				if (best != -1)
+				{
+					for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+					{
+						cu.curPLT[comp][uiPLTSize] = cs.prevPLT.curPLT[comp][best];
+					}
+				}
+			}
+
+			bool bDuplicate = false;
+			if (pListSort[i].uiCnt == 1 && best == -1)
+			{
+				bDuplicate = true;
+			}
+			else
+			{
+				for (int t = 0; t<uiPLTSize; t++)
+				{
+					bool bDuplicateTmp = true;
+					for (int comp = compBegin; comp < (compBegin + NumComp); comp++)
+					{
+						bDuplicateTmp = bDuplicateTmp && (cu.curPLT[comp][uiPLTSize] == cu.curPLT[comp][t]);
+					}
+					if (bDuplicateTmp)
+					{
+						bDuplicate = true;
+						break;
+					}
+				}
+			}
+			if (!bDuplicate) uiPLTSize++;
+		}
+		else
+		{
+			break;
+		}
+	}
+	cu.curPLTSize[compBegin] = uiPLTSize;
+
+	delete[] psList;
+	delete[] pListSort;
+}
+#endif
 // -------------------------------------------------------------------------------------------------------------------
 // Intra search
 // -------------------------------------------------------------------------------------------------------------------
@@ -1475,9 +2053,15 @@ void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner
     // CU header
     if( isFirst )
     {
+#if JVET_O0119_BASE_PALETTE_444
+	  if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag() || cs.slice->getSPS()->getPLTMode())
+		&& cu.Y().valid()
+		)
+#else
       if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag())
         && cu.Y().valid()
         )
+#endif
       {
         if( cs.pps->getTransquantBypassEnabledFlag() )
         {
@@ -1486,6 +2070,12 @@ void IntraSearch::xEncIntraHeader( CodingStructure &cs, Partitioner &partitioner
         m_CABACEstimator->cu_skip_flag( cu );
         m_CABACEstimator->pred_mode   ( cu );
       }
+#if JVET_O0119_BASE_PALETTE_444
+	  if (CU::isPLT(cu))
+	  {
+		  return;
+	  }
+#endif
       m_CABACEstimator->bdpcm_mode  ( cu, ComponentID(partitioner.chType) );
       if( CU::isIntra(cu) )
       {
diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h
index fd005a552ead9996a21f1d8143bb667e5b50b7ad..866e30969cca2a8051b12222e6bb6892e1867b7a 100644
--- a/source/Lib/EncoderLib/IntraSearch.h
+++ b/source/Lib/EncoderLib/IntraSearch.h
@@ -153,6 +153,10 @@ public:
   bool estIntraPredLumaQT         ( CodingUnit &cu, Partitioner& pm, const double bestCostSoFar  = MAX_DOUBLE, bool mtsCheckRangeFlag = false, int mtsFirstCheckId = 0, int mtsLastCheckId = 0, bool moreProbMTSIdxFirst = false );
   void estIntraPredChromaQT       ( CodingUnit &cu, Partitioner& pm, const double maxCostAllowed = MAX_DOUBLE );
   void IPCMSearch                 (CodingStructure &cs, Partitioner& partitioner);
+#if JVET_O0119_BASE_PALETTE_444
+  void PLTSearch				  ( CodingStructure &cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp);
+  void deriveRunAndCalcBits		  ( CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp, PLTScanMode pltScanMode, uint64_t& uiBits);
+#endif
   uint64_t xFracModeBitsIntra     (PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &compID);
 
 protected:
@@ -189,6 +193,13 @@ protected:
   void reduceHadCandList(static_vector<T, N>& candModeList, static_vector<double, N>& candCostList, int& numModesForFullRD, const double thresholdHadCost, const double thresholdHadCostConv);
 
   double m_bestCostNonMip;
+#if JVET_O0119_BASE_PALETTE_444
+  void   deriveRun(CodingStructure &cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp);
+  double getRunBits(const CodingUnit&  cu, uint32_t run, uint32_t strPos, PLTRunMode PaletteRunMode, uint64_t* indexBits, uint64_t* runBits, ComponentID compBegin);
+  void       derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp);
+  void       calcPixelPred(CodingStructure& cs, Partitioner& partitioner, uint32_t uiY, uint32_t uiX, ComponentID compBegin, uint32_t NumComp);
+  void       preCalcPLTIndex(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t NumComp);
+#endif
 };// END CLASS DEFINITION EncSearch
 
 //! \}
diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp
index 76fedd8078b7e7967309bbc696dff6e02fd9783d..6884bc2fdc9f1bacbcbc17495dc674162b477ee2 100644
--- a/source/Lib/EncoderLib/VLCWriter.cpp
+++ b/source/Lib/EncoderLib/VLCWriter.cpp
@@ -863,6 +863,12 @@ void HLSWriter::codeSPS( const SPS* pcSPS )
 #endif
   }
   WRITE_FLAG( pcSPS->getUseGBi() ? 1 : 0,                                                      "gbi_flag" );
+#if JVET_O0119_BASE_PALETTE_444
+  if (pcSPS->getChromaFormatIdc() == CHROMA_444)
+  {
+	  WRITE_FLAG(pcSPS->getPLTMode() ? 1 : 0, "plt_flag");
+  }
+#endif
   WRITE_FLAG(pcSPS->getIBCFlag() ? 1 : 0,                                                      "ibc_flag");
 
   // KJS: sps_ciip_enabled_flag