diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 2a7209a9fc1f45f96a6708024d81bcb7bee4c55c..9e6bfb2080662d270dc587e2c5dbc4a870578761 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -299,7 +299,10 @@ void EncApp::xInitLibCfg() m_cEncLib.setDMVR ( m_DMVR ); m_cEncLib.setMMVD ( m_MMVD ); m_cEncLib.setMmvdDisNum (m_MmvdDisNum); - m_cEncLib.setRDPCM ( m_RdpcmMode ); + m_cEncLib.setRDPCM ( m_RdpcmMode ); +#if JVET_O0119_BASE_PALETTE_444 + m_cEncLib.setPLTMode ( m_PLTMode); +#endif #if JVET_O0376_SPS_JOINTCBCR_FLAG m_cEncLib.setJointCbCr ( m_JointCbCrMode ); #endif diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 18029650b91a96a3eb6b6476480c840e708bd1d8..3294ed5253356d84a9d0718de870fb3ab3cfeabc 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -916,7 +916,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 #if JVET_O0376_SPS_JOINTCBCR_FLAG ("JointCbCr", m_JointCbCrMode, false, "Enable joint coding of chroma residuals (JointCbCr, 0:off, 1:on)") #endif @@ -2273,6 +2276,9 @@ bool EncAppCfg::xCheckParameter() #endif xConfirmPara( m_LMChroma, "LMChroma only allowed with NEXT profile" ); xConfirmPara( m_ImvMode, "IMV is 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" ); @@ -3503,6 +3509,10 @@ void EncAppCfg::xPrintParameter() msg(VERBOSE, "JointCbCr:%d ", m_JointCbCrMode); #endif } +#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 3607774397de63d901792cd21af28c803c20fb39..ebfc9e723a501e0d4ab3d4a79f75449e885a2f7e 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -293,6 +293,9 @@ protected: bool m_MMVD; int m_MmvdDisNum; bool m_RdpcmMode; +#if JVET_O0119_BASE_PALETTE_444 + unsigned m_PLTMode; +#endif #if JVET_O0376_SPS_JOINTCBCR_FLAG bool m_JointCbCrMode; #endif diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h index ba0486194797f3106fdee651ff9bd6bc28b7892e..d04861d65f7c10eb9dab65bdbec515c30f745963 100644 --- a/source/Lib/CommonLib/Buffer.h +++ b/source/Lib/CommonLib/Buffer.h @@ -173,6 +173,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 71b0c4ce17c710cd2907479ca59f0995b40815ae..c7f0b3458ab97d674a17ce33ed9eab6e47f0be1f 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -78,6 +78,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; } @@ -507,6 +511,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 ); @@ -543,12 +551,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; } @@ -711,6 +727,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" ); @@ -738,6 +812,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 } } @@ -747,6 +825,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 } } @@ -790,6 +872,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 ) @@ -851,6 +937,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 ) @@ -1033,6 +1123,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 8589a75a78e47024d8e7fdadc2982458059a6700..f641a2ba230b4de66e34caceb67199e6c895f3a6 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -201,6 +201,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 @@ -228,7 +233,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 bf963649cbaa536890f3cf8e7d88d98a1d40f6fd..daf78d6ff822b7d7dd250fba507518018256bba9 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -507,6 +507,15 @@ 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_ENCBITDEPTH = 8; +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 8903da8fae4c4653fdab9fbff1ff9bb953a7b9ad..3b4a41b797ffb60b605e4956638a855b614729ce 100755 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -761,6 +761,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, }, @@ -1014,6 +1056,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 }; #if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h old mode 100755 new mode 100644 index 7ed83c7b74622ea55cb004876696035b10a7bd18..529d4a7a08644d6e2d29eece642f5d38ca0f705a --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -251,6 +251,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; @@ -285,6 +292,9 @@ public: #if JVET_O0090_ALF_CHROMA_FILTER_ALTERNATIVES_CTB static const CtxSet Alf; #endif +#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 337dcac80c107ac2eb928b4057c7a1e378e63f34..3ae05f29d10c46ac7552891769e16920b175b3ce 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) @@ -230,6 +234,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 } // ==================================================================================================================== @@ -2169,4 +2177,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 startPos, uint32_t total, uint32_t &run, 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 idx = startPos; + uint32_t xPos; + uint32_t yPos; + bool valid = false; + run = 0; + while (idx < total) + { + xPos = m_scanOrder[idx].x; + yPos = m_scanOrder[idx].y; + runType.at(xPos, yPos) = PLT_RUN_COPY; + + if (yPos == 0 && !cu.useRotation[compBegin]) + { + return false; + } + if (xPos == 0 && cu.useRotation[compBegin]) + { + return false; + } + if (!cu.useRotation[compBegin] && curPLTIdx.at(xPos, yPos) == curPLTIdx.at(xPos, yPos - 1)) + { + run++; + valid = true; + } + else if (cu.useRotation[compBegin] && curPLTIdx.at(xPos, yPos) == curPLTIdx.at(xPos - 1, yPos)) + { + run++; + valid = true; + } + else + { + break; + } + idx++; + } + return valid; +} +bool IntraPrediction::calIndexRun(CodingStructure &cs, Partitioner& partitioner, uint32_t startPos, uint32_t total, uint32_t &run, ComponentID compBegin) +{ + TransformUnit &tu = *cs.getTU(partitioner.chType); + PelBuf curPLTIdx = tu.getcurPLTIdx(compBegin); + PLTtypeBuf runType = tu.getrunType(compBegin); + + run = 1; + uint32_t idx = startPos; + while (idx < total) + { + uint32_t xPos = m_scanOrder[idx].x; + uint32_t yPos = m_scanOrder[idx].y; + runType.at(xPos, yPos) = PLT_RUN_INDEX; + + uint32_t xPrev = idx == 0 ? 0 : m_scanOrder[idx - 1].x; + uint32_t yPrev = idx == 0 ? 0 : m_scanOrder[idx - 1].y; + if (idx > startPos && curPLTIdx.at(xPos, yPos) == curPLTIdx.at(xPrev, yPrev)) + { + run++; + } + else if (idx > startPos) + { + break; + } + idx++; + } + 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 a942a13d58471a82528f3fc45bd6a0f191275d25..29ccc472f74c33e190f19c10ad4e397a2e2ad66a 100644 --- a/source/Lib/CommonLib/IntraPrediction.h +++ b/source/Lib/CommonLib/IntraPrediction.h @@ -123,12 +123,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_scanOrder; + bool m_bestScanRotationMode; + Ctx m_storeCtxRun; + Ctx m_storeCtxRunIndex; + Ctx m_storeCtxRunCopy; + 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 ); @@ -185,6 +196,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 startPos, uint32_t total, uint32_t &run, ComponentID compBegin); + bool calIndexRun(CodingStructure &cs, Partitioner& partitioner, uint32_t startPos, uint32_t total, uint32_t &run, ComponentID compBegin); +#endif }; //! \} diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index eb210178dbeb5763759fc5f288dbdbb95fbef93a..8ce43b547e7458e737df6e740bc0aaee895a5e2b 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -878,6 +878,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) ); @@ -1056,6 +1059,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) { @@ -1101,6 +1112,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 ) { @@ -1251,6 +1270,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/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index 721e683b24a53970d6854862703be200a83a6fca..c6895b6e2d611312566f195431651cd9b980147e 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -53,7 +53,6 @@ CDTrace *g_trace_ctx = NULL; #endif bool g_mctsDecCheckEnabled = false; - //! \ingroup CommonLib //! \{ @@ -130,6 +129,53 @@ public: } 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: @@ -762,4 +808,9 @@ 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_paletteQuant[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_paletteRunTopLut [5] = { 0, 1, 1, 2, 2 }; +uint8_t g_paletteRunLeftLut[5] = { 0, 3, 3, 4, 4 }; +#endif //! \} diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index 3bfe26e204d0077aabff6b31ca36553d5a40f5dd..1dc86ce08a62f22a60a4ed7e612b547a6e415ddb 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,11 @@ 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_paletteQuant[52]; +extern uint8_t g_paletteRunTopLut[5]; +extern uint8_t g_paletteRunLeftLut[5]; +#endif + #endif //__TCOMROM__ diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp index febb1dde94239ecd9d12f3f8493eda293b852e62..e007ff97ff6e0400ee938a76d9ab2ed58eb4ac19 100644 --- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp +++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp @@ -729,7 +729,6 @@ void SampleAdaptiveOffset::xPCMCURestoration(CodingStructure& cs, const UnitArea void SampleAdaptiveOffset::xPCMSampleRestoration(CodingUnit& cu, const ComponentID compID) { 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 7e22942a87dc1c00776106d21e2dccc264109cbb..2404f16821df58912232b775e2dd1a19a4a8b6dc 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1447,6 +1447,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 9f1206a5d46d3bfc160158f66e2d1f2437a0f2ac..bf8fa59fd884f8ffdcff9dffe16b26f7b4e71862 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -47,6 +47,9 @@ #include "ChromaFormat.h" #include "Common.h" #include "HRD.h" +#if JVET_O0119_BASE_PALETTE_444 +#include <unordered_map> +#endif #include "AlfParameters.h" //! \ingroup CommonLib @@ -835,6 +838,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; @@ -1066,6 +1072,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; } @@ -1945,6 +1955,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 c84ded510d3345fd7c48085b7b210602236b0157..2f47b2e91688c2b3651f58d05c0d5cf89e1fc96b 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,6 +50,9 @@ #include <assert.h> #include <cassert> + +#define JVET_O0119_BASE_PALETTE_444 1 // JVET-O0119: Palette mode in HEVC and palette mode signaling in JVET-N0258. Only enabled for YUV444. + #define JVET_O0304_SIMPLIFIED_BDOF 1 // JVET-O0304: Reduction of number of multiplications in BDOF #define JVET_O0455_IBC_MAX_MERGE_NUM 1 // JVET-O0455: Control the max number of IBC merge candidates independently from regular merge candidates @@ -629,7 +632,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 @@ -755,6 +763,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 }; @@ -1082,6 +1094,14 @@ struct BitDepths int recon[MAX_NUM_CHANNEL_TYPE]; ///< the bit depth as indicated in the SPS }; +#if JVET_O0119_BASE_PALETTE_444 +enum PLTRunMode +{ + PLT_RUN_INDEX = 0, + PLT_RUN_COPY = 1, + NUM_PLT_RUN = 2 +}; +#endif /// parameters for deblocking filter struct LFCUParam { diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index 74a3cc0ec6952f1ad9fffc7a7190dcd94d78d326..b3c80a04e638f066b2346c92249318f7117d9704 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::getPLTIndex(const ComponentID id) { return m_pcmbuf[id]; } +Pel* TransformUnit::getRunLens (const ComponentID id) { return m_runLength[id]; } +bool* TransformUnit::getRunTypes(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..df7b398a98d270ff2360f58013e5f313f0825306 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* getPLTIndex(const ComponentID id); + Pel* getRunLens(const ComponentID id); + bool* getRunTypes(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 ec14d617025c822dce3cf110722fa740f184d5c1..55da1ffc2535c31f9fa55ffab3d6bbe13b58da8e 100755 --- 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 db9e6a99ccc29aa389522771c215557157ce0766..0530ae2dbb4e6348bb7e98e7cd58140e62fe1e72 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 4b10f5c300de874f78e67f61ac7a392a5478dc36..ca63508c569648ad3d13229120c5022a75c68af0 100755 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -620,6 +620,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; @@ -742,6 +770,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 @@ -1015,12 +1065,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 { @@ -1042,6 +1110,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; @@ -1050,6 +1142,7 @@ void CABACReader::pred_mode( CodingUnit& cu ) { cu.predMode = MODE_INTER; } +#endif } } void CABACReader::bdpcm_mode( CodingUnit& cu, const ComponentID compID ) @@ -1607,6 +1700,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 escCode = 0; + escCode = m_BinDecoder.decodeBinEP(); + cu.useEscape[compBegin] = (escCode != 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 height = cu.block(compBegin).height; + uint32_t width = cu.block(compBegin).width; + + int numCopyIndexRuns = -1; + bool lastRunType = 0; + uint32_t numIndices = 0; + uint32_t adjust = 0; + uint32_t symbol = 0; + std::list<int> parsedIdxList; + if (indexMaxSize > 1) + { + uint32_t currParam = 3 + ((indexMaxSize) >> 3); + numIndices = m_BinDecoder.decodeRemAbsEP(currParam, false, MAX_NUM_CHANNEL_TYPE); // JC: number of indices (INDEX RUN) + numIndices++; + numCopyIndexRuns = numIndices; + while (numIndices--) + { + xReadTruncBinCode(symbol, indexMaxSize - adjust); + adjust = 1; + parsedIdxList.push_back(symbol); + } + lastRunType = m_BinDecoder.decodeBin(Ctx::RunTypeFlag()); + parseScanRotationModeFlag(cu, compBegin); + adjust = 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_scanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(width)][gp_sizeIdxInfo->idxFrom(height)]; + uint32_t strPos = 0; + uint32_t endPos = height * width; + while (strPos < endPos) + { + uint32_t posy = m_scanOrder[strPos].y; + uint32_t posx = m_scanOrder[strPos].x; + uint32_t posyprev = strPos == 0 ? 0 : m_scanOrder[strPos - 1].y; + uint32_t posxprev = strPos == 0 ? 0 : m_scanOrder[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 (numCopyIndexRuns && strPos < endPos - 1) // JC: if numIndices (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 && numCopyIndexRuns) + { + runType.at(posx, posy) = PLT_RUN_INDEX; + } + else + { + runType.at(posx, posy) = PLT_RUN_COPY; + } + } + } + } + else + { + runType.at(posx, posy) = PLT_RUN_INDEX; + } + + Pel curLevel = 0; + if (runType.at(posx, posy) == PLT_RUN_INDEX) + { + if (!parsedIdxList.empty()) + { + curLevel = parsedIdxList.front(); + parsedIdxList.pop_front(); + } + else + { + curLevel = 0; + } + xAdjustPLTIndex(cu, curLevel, strPos, curPLTIdx, runType, indexMaxSize, compBegin); + } + + if (indexMaxSize > 1) + { + bool lastRun; + numCopyIndexRuns -= (runType.at(posx, posy) == PLT_RUN_INDEX); + lastRun = numCopyIndexRuns == 0 && runType.at(posx, posy) == lastRunType; + if (!lastRun) + { + runLength.at(posx, posy) = cu_run_val((PLTRunMode)runType.at(posx, posy), curLevel, endPos - strPos - numCopyIndexRuns - 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_scanOrder[strPos + runidx].y; + posXrun = m_scanOrder[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_scanOrder[strPos + idx].y; + posXrun = m_scanOrder[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_scanOrder[strPos + idx].y; + posXrun = m_scanOrder[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_scanOrder[strPos].y; + uint32_t posx = m_scanOrder[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 maxPLTSize, ComponentID compBegin) +{ + uint32_t symbol, numPltPredicted = 0, idx = 0; + + symbol = exp_golomb_eqprob(0); + + if (symbol != 1) + { + while (idx < cu.lastPLTSize[compBegin] && numPltPredicted < maxPLTSize) + { + if (idx > 0) + { + symbol = exp_golomb_eqprob(0); + } + if (symbol == 1) + { + break; + } + + if (symbol) + { + idx += symbol - 1; + } + cu.reuseflag[compBegin][idx] = 1; + numPltPredicted++; + idx++; + } + } +} +void CABACReader::xAdjustPLTIndex(CodingUnit& cu, Pel curLevel, uint32_t idx, PelBuf& paletteIdx, PLTtypeBuf& paletteRunType, int maxSymbol, ComponentID compBegin) +{ + uint32_t symbol; + int refLevel = MAX_INT; + uint32_t posy = m_scanOrder[idx].y; + uint32_t posx = m_scanOrder[idx].x; + if (idx) + { + uint32_t prevposy = m_scanOrder[idx - 1].y; + uint32_t prevposx = m_scanOrder[idx - 1].x; + if (paletteRunType.at(prevposx, prevposy) == PLT_RUN_INDEX) + { + refLevel = paletteIdx.at(prevposx, prevposy); + if (paletteIdx.at(prevposx, prevposy) == cu.curPLTSize[compBegin]) // escape + { + refLevel = maxSymbol - 1; + } + } + else + { + if (cu.useRotation[compBegin]) + { + assert(prevposx > 0); + refLevel = paletteIdx.at(posx - 1, posy); + if (paletteIdx.at(posx - 1, posy) == cu.curPLTSize[compBegin]) // escape mode + { + refLevel = maxSymbol - 1; + } + } + else + { + assert(prevposy > 0); + refLevel = paletteIdx.at(posx, posy - 1); + if (paletteIdx.at(posx, posy - 1) == cu.curPLTSize[compBegin]) // escape mode + { + refLevel = maxSymbol - 1; + } + } + } + maxSymbol--; + } + symbol = curLevel; + if (curLevel >= refLevel) // include escape mode + { + symbol++; + } + paletteIdx.at(posx, posy) = symbol; +} +uint32_t CABACReader::cu_run_val(PLTRunMode runtype, const uint32_t paletteIdx, const uint32_t maxRun) +{ + uint32_t symbol = 0; + if (runtype == PLT_RUN_COPY) + { + } + else + { + g_paletteRunLeftLut[0] = (paletteIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (paletteIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2)); + } + symbol = xReadTruncMsbP1RefinementBits(runtype, maxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE); + return symbol; +} +uint32_t CABACReader::xReadTruncUnarySymbol(PLTRunMode runtype, uint32_t maxVal, uint32_t ctxT) +{ + if (maxVal == 0) + return 0; + + uint8_t *ctxLut; + ctxLut = (runtype == PLT_RUN_INDEX) ? g_paletteRunLeftLut : g_paletteRunTopLut; + uint32_t bin, idx = 0; + do + { + if (idx > ctxT) + bin = m_BinDecoder.decodeBinEP(); + else + { + bin = m_BinDecoder.decodeBin( + (idx <= ctxT) + ? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[idx]) : Ctx::CopyRunModel(ctxLut[idx])) + : ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[ctxT]) : Ctx::CopyRunModel(ctxLut[ctxT]))); + // idx <= ctxT? pcSCModel[ctxLut[idx]] : pcSCModel[ctxLut[ctxT]] RExt__DECODER_DEBUG_BIT_STATISTICS_PASS_OPT_ARG(whichStat) ); + } + idx++; + } while (bin && idx < maxVal); + + return (bin && idx == maxVal) ? maxVal : idx - 1; +} +uint32_t CABACReader::xReadTruncMsbP1RefinementBits(PLTRunMode runtype, uint32_t maxVal, uint32_t ctxT) +{ + if (maxVal == 0) + { + return 0; + } + uint32_t symbol; + uint32_t msbP1 = xReadTruncUnarySymbol(runtype, floorLog2(maxVal) + 1, ctxT); + if (msbP1 > 1) + { + uint32_t numBins = floorLog2(maxVal) + 1; + if (msbP1 < numBins) + { + uint32_t bits = msbP1 - 1; + symbol = m_BinDecoder.decodeBinsEP(bits); + symbol |= (1 << bits); + } + else + { + uint32_t curValue = 1 << (numBins - 1); + xReadTruncBinCode(symbol, maxVal + 1 - curValue); + symbol += curValue; + } + } + else + symbol = msbP1; + + return symbol; +} +#endif + //================================================================================ // clause 7.3.8.6 //-------------------------------------------------------------------------------- diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index c6e2afa9040b42f2e0081123e512cdfa708cdf53..2908269819ab33a859d18319f17b9157425e9a93 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 maxPLTSize, ComponentID compBegin); + void xAdjustPLTIndex ( CodingUnit& cu, Pel curLevel, uint32_t idx, PelBuf& paletteIdx, PLTtypeBuf& paletteRunType, int maxSymbol, ComponentID compBegin); + uint32_t cu_run_val ( PLTRunMode runtype, const uint32_t pltIdx, const uint32_t maxRun); + uint32_t xReadTruncUnarySymbol ( PLTRunMode runtype, uint32_t maxVal, uint32_t ctxT); + uint32_t xReadTruncMsbP1RefinementBits( PLTRunMode runtype, uint32_t maxVal, uint32_t ctxT); +#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_scanOrder; +#endif }; diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 998eb33946df0adef109be77c15c01456c404a1a..5ae1d31d1cf367047c219a18196c530ee65e3b06 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -150,7 +150,11 @@ 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); } @@ -160,6 +164,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; @@ -414,6 +421,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++ ) @@ -425,6 +453,88 @@ 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 height = cu.block(compBegin).height; + uint32_t width = 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 y = 0; y < height; y++) + { + for (uint32_t x = 0; x < width; x++) + { + 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 picReco = cu.cs->getRecoBuf(area); + PLTescapeBuf escapeValue = tu.getescapeValue((ComponentID)compID); + if (curPLTIdx.at(x, y) == cu.curPLTSize[compBegin]) + { + Pel value; + QpParam cQP(tu, (ComponentID)compID); + +#if JVET_O0919_TS_MIN_QP + int qp = cQP.Qp(false); +#else + int qp = cQP.Qp; +#endif + int qpRem = qp % 6; + int qpPer = qp / 6; + if (compBegin != COMPONENT_Y || compID == COMPONENT_Y) + { + int invquantiserRightShift = IQUANT_SHIFT; + int add = 1 << (invquantiserRightShift - 1); + value = ((((escapeValue.at(x, y)*g_invQuantScales[0][qpRem]) << qpPer) + add) >> invquantiserRightShift); + value = Pel(ClipBD<int>(value, channelBitDepth)); + picReco.at(x, y) = value; + } + else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && y % (1 << scaleY) == 0 && x % (1 << scaleX) == 0) + { + uint32_t posYC = y >> scaleY; + uint32_t posXC = x >> scaleX; + int invquantiserRightShift = IQUANT_SHIFT; + int add = 1 << (invquantiserRightShift - 1); + value = ((((escapeValue.at(posXC, posYC)*g_invQuantScales[0][qpRem]) << qpPer) + add) >> invquantiserRightShift); + value = Pel(ClipBD<int>(value, channelBitDepth)); + picReco.at(posXC, posYC) = value; + + } + } + else + { + uint32_t curIdx = curPLTIdx.at(x, y); + if (compBegin != COMPONENT_Y || compID == COMPONENT_Y) + { + picReco.at(x, y) = cu.curPLT[compID][curIdx]; + } + else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && y % (1 << scaleY) == 0 && x % (1 << scaleX) == 0) + { + uint32_t posYC = y >> scaleY; + uint32_t posXC = x >> scaleX; + picReco.at(posXC, posYC) = cu.curPLT[compID][curIdx]; + } + } + } + } + } + for (uint32_t compID = compBegin; compID < (compBegin + numComp); compID++) + { + const CompArea &area = cu.blocks[compID]; + PelBuf picReco = cu.cs->getRecoBuf(area); + cu.cs->picture->getRecoBuf(area).copyFrom(picReco); + 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..06b3aab0b12c9ab7621f5949f775a848ebda1dd1 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 2c6b68b2e4e351f5ff0af7ac971636dab5bdd45d..42b66acdaef5f78b5aca6c35bfe210f8a1bd60ce 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 ); @@ -163,6 +167,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(); } @@ -172,6 +179,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 3cc22c22b1f37e707a0c6c275ce6fda6a79cb6dd..7e5b0c48a79db3abc46c7e3c8786565bc02bb004 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -1353,6 +1353,16 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) #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, "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 ca67320344946cf1f1c15df4ffddb412b81aa9a9..d6b0d3ad2cf356cb0f4350f59dec0012b92f81a9 100755 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -612,6 +612,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 @@ -761,12 +783,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 @@ -783,9 +822,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 ) @@ -1500,9 +1549,400 @@ 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 height = cu.block(compBegin).height; + uint32_t width = cu.block(compBegin).width; + + m_scanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(width)][gp_sizeIdxInfo->idxFrom(height)]; + uint32_t total = height * width; + int lastRunPos = -1; + uint32_t lastRunType = 0; + uint32_t numIndices = 0; + std::vector<int> idxPos, parsedIdx; + idxPos.reserve(total); + parsedIdx.reserve(total); + if (indexMaxSize > 1) + { + int idx = 0, run = 0; + while (idx < total) + { + uint32_t posy = m_scanOrder[idx].y; + uint32_t posx = m_scanOrder[idx].x; + if (runType.at(posx, posy) == PLT_RUN_INDEX) + { + idxPos.push_back(idx); + numIndices++; + } + lastRunType = runType.at(posx, posy); + lastRunPos = idx; + run = runLength.at(posx, posy); + idx += run; + } + uint32_t currParam = 3 + ((indexMaxSize) >> 3); + uint32_t mappedValue; + assert(numIndices); + assert(numIndices > 0); + mappedValue = numIndices - 1; + m_BinEncoder.encodeRemAbsEP(mappedValue, currParam, false, MAX_NUM_CHANNEL_TYPE); // JC: code number of indices (PLT_RUN_INDEX) + auto idxPosEnd = idxPos.end(); + for (auto iter = idxPos.begin(); iter != idxPosEnd; ++iter) + { + parsedIdx.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 = height * width; + auto parsedIdxEnd = parsedIdx.end(); + auto parsedIdxIter = parsedIdx.begin(); + while (strPos < endPos) + { + uint32_t posy = m_scanOrder[strPos].y; + uint32_t posx = m_scanOrder[strPos].x; + uint32_t posyprev = strPos == 0 ? 0 : m_scanOrder[strPos - 1].y; + uint32_t posxprev = strPos == 0 ? 0 : m_scanOrder[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 (numIndices && strPos < endPos - 1) // if numIndices (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 curLevel = 0; + if (runType.at(posx, posy) == PLT_RUN_INDEX) + { + if (parsedIdxIter != parsedIdxEnd) + { + curLevel = *parsedIdxIter++; + } + else + { + curLevel = 0; + } + } + + if (indexMaxSize > 1) + { + if (lastRunPos != strPos) + { + numIndices -= (runType.at(posx, posy) == PLT_RUN_INDEX); + cu_run_val(runLength.at(posx, posy) - 1, (PLTRunMode)runType.at(posx, posy), curLevel, endPos - strPos - numIndices - 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_scanOrder[strPos].y; + uint32_t posx = m_scanOrder[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 maxPLTSize, ComponentID compBegin) +{ + int lastPredIdx = -1; + uint32_t run = 0; + uint32_t numPLTPredicted = 0; + for (uint32_t idx = 0; idx < cu.lastPLTSize[compBegin]; idx++) + { + if (cu.reuseflag[compBegin][idx]) + { + numPLTPredicted++; + 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 ((numPLTPredicted < maxPLTSize && lastPredIdx + 1 < cu.lastPLTSize[compBegin]) || !numPLTPredicted) + { + exp_golomb_eqprob(1, 0); + } +} +Pel CABACWriter::writePLTIndex(const CodingUnit& cu, uint32_t idx, PelBuf& paletteIdx, PLTtypeBuf& paletteRunType, int maxSymbol, ComponentID compBegin) +{ + uint32_t posy = m_scanOrder[idx].y; + uint32_t posx = m_scanOrder[idx].x; + Pel curLevel = (paletteIdx.at(posx, posy) == cu.curPLTSize[compBegin]) ? (maxSymbol - 1) : paletteIdx.at(posx, posy); + if (idx) // R0348: remove index redundancy + { + uint32_t prevposy = m_scanOrder[idx - 1].y; + uint32_t prevposx = m_scanOrder[idx - 1].x; + if (paletteRunType.at(prevposx, prevposy) == PLT_RUN_INDEX) + { + Pel leftLevel = paletteIdx.at(prevposx, prevposy); // left index + if (leftLevel == cu.curPLTSize[compBegin]) // escape mode + { + leftLevel = maxSymbol - 1; + } + assert(leftLevel != curLevel); + if (curLevel > leftLevel) + { + curLevel--; + } + } + else + { + Pel aboveLevel; + if (cu.useRotation[compBegin]) + { + assert(prevposx > 0); + aboveLevel = paletteIdx.at(posx - 1, posy); + if (paletteIdx.at(posx - 1, posy) == cu.curPLTSize[compBegin]) // escape mode + { + aboveLevel = maxSymbol - 1; + } + } + else + { + assert(prevposy > 0); + aboveLevel = paletteIdx.at(posx, posy - 1); + if (paletteIdx.at(posx, posy - 1) == cu.curPLTSize[compBegin]) // escape mode + { + aboveLevel = maxSymbol - 1; + } + } + assert(curLevel != aboveLevel); + if (curLevel > aboveLevel) + { + curLevel--; + } + } + maxSymbol--; + } + assert(maxSymbol > 0); + assert(curLevel >= 0); + assert(maxSymbol > curLevel); + if (maxSymbol > 1) + { + xWriteTruncBinCode(curLevel, maxSymbol); + } + return curLevel; +} + +void CABACWriter::encodeRunType(const CodingUnit& cu, PLTtypeBuf& runType, uint32_t idx, ScanElement *refScanOrder, ComponentID compBegin) +{ + if (refScanOrder) + { + m_scanOrder = refScanOrder; + } + uint32_t posy = m_scanOrder[idx].y; + uint32_t posx = m_scanOrder[idx].x; + uint32_t posyprev = (idx == 0) ? 0 : m_scanOrder[idx - 1].y; + uint32_t posxprev = (idx == 0) ? 0 : m_scanOrder[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 run, PLTRunMode runtype, const uint32_t paletteIdx, const uint32_t maxRun) +{ + if (runtype == PLT_RUN_COPY) + { + } + else + { + g_paletteRunLeftLut[0] = (paletteIdx < PLT_RUN_MSB_IDX_CTX_T1 ? 0 : (paletteIdx < PLT_RUN_MSB_IDX_CTX_T2 ? 1 : 2)); + } + xWriteTruncMsbP1RefinementBits(run, runtype, maxRun, PLT_RUN_MSB_IDX_CABAC_BYPASS_THRE); +} +uint32_t CABACWriter::xWriteTruncMsbP1(uint32_t symbol, PLTRunMode runtype, uint32_t uiMax, uint32_t uiCtxT) +{ + if (uiMax == 0) + return 0; + + uint8_t *ctxLut; + ctxLut = (runtype == PLT_RUN_INDEX) ? g_paletteRunLeftLut : g_paletteRunTopLut; + + uint32_t msbP1; + for (msbP1 = 0; symbol > 0; msbP1++) + { + symbol >>= 1; + if (msbP1 > uiCtxT) + { + m_BinEncoder.encodeBinEP(1); + } + else + m_BinEncoder.encodeBin(1, (msbP1 <= uiCtxT) + ? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[msbP1]) : Ctx::CopyRunModel(ctxLut[msbP1])) + : ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[uiCtxT]) : Ctx::CopyRunModel(ctxLut[uiCtxT]))); + } + assert(msbP1 <= uiMax); + if (msbP1 < uiMax) + { + if (msbP1 > uiCtxT) + { + m_BinEncoder.encodeBinEP(0); + } + else + m_BinEncoder.encodeBin(0, msbP1 <= uiCtxT + ? ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[msbP1]) : Ctx::CopyRunModel(ctxLut[msbP1])) + : ((runtype == PLT_RUN_INDEX) ? Ctx::IdxRunModel(ctxLut[uiCtxT]) : Ctx::CopyRunModel(ctxLut[uiCtxT]))); + + //m_pcBinIf->encodeBin(0, msbP1 <= uiCtxT? pcSCModel[ctxLut[msbP1]] : pcSCModel[ctxLut[uiCtxT]]); + } + return msbP1; +} + +void CABACWriter::xWriteTruncMsbP1RefinementBits(uint32_t symbol, PLTRunMode runtype, uint32_t maxVal, uint32_t uiCtxT) +{ + if (maxVal == 0) + return; + + uint32_t msbP1 = xWriteTruncMsbP1(symbol, runtype, floorLog2(maxVal) + 1, uiCtxT); + if (msbP1 > 1) + { + uint32_t numBins = floorLog2(maxVal) + 1; + if (msbP1 < numBins) + { + + uint32_t bits = msbP1 - 1; + m_BinEncoder.encodeBinsEP(symbol & ((1 << bits) - 1), bits); + } + else + { + uint32_t curValue = 1 << (numBins - 1); + xWriteTruncBinCode(symbol - curValue, maxVal + 1 - curValue); + } + } +} + +#endif //================================================================================ // clause 7.3.8.6 diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 32691e0388f9bfb4f166da80fc9d0f0b0238635f..3ac03b4e775f3fcfb64bec79a751e4f734a6cd58 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 run, PLTRunMode runtype, const uint32_t paletteIdx, const uint32_t maxRun); + void encodeRunType ( const CodingUnit& cu, PLTtypeBuf& runType, uint32_t idx, ScanElement *refScanOrder, ComponentID compBegin); + Pel writePLTIndex ( const CodingUnit& cu, uint32_t idx, PelBuf& paletteIdx, PLTtypeBuf& paletteRunType, int maxSymbol, ComponentID compBegin); +#endif // prediction unit (clause 7.3.8.6) void prediction_unit ( const PredictionUnit& pu ); void merge_flag ( const PredictionUnit& pu ); @@ -195,12 +201,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 maxPltSize, ComponentID compBegin); + uint32_t xWriteTruncMsbP1 ( uint32_t symbol, PLTRunMode runtype, uint32_t maxVal, uint32_t ctxT); + void xWriteTruncMsbP1RefinementBits ( uint32_t symbol, PLTRunMode runtype, uint32_t maxVal, uint32_t ctxT); +#endif private: BinEncIf& m_BinEncoder; OutputBitstream* m_Bitstream; Ctx m_TestCtx; EncCu* m_EncCu; +#if JVET_O0119_BASE_PALETTE_444 + ScanElement* m_scanOrder; +#endif }; diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 49be1d6dc07d90f1a91bd434b5edaa104c89028e..03d0d061258b58838dcdf60b04d67c7932b6bbfa 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -308,6 +308,9 @@ protected: bool m_MMVD; int m_MmvdDisNum; bool m_RdpcmMode; +#if JVET_O0119_BASE_PALETTE_444 + unsigned m_PLTMode; +#endif #if JVET_O0376_SPS_JOINTCBCR_FLAG bool m_JointCbCrMode; #endif @@ -900,6 +903,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 #if JVET_O0376_SPS_JOINTCBCR_FLAG void setJointCbCr ( bool b ) { m_JointCbCrMode = b; } bool getJointCbCr () const { return m_JointCbCrMode; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index bd6f75647d85c88011e7ec33f1aad21ac98cc85b..65c1dc2377942c42eb720b730644a2b75cba939e 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 ); @@ -603,6 +605,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; @@ -666,6 +704,14 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par #endif 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 JVET_O0502_ISP_CLEANUP currTestMode.maxCostAllowed = maxCostAllowed; @@ -767,6 +813,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); @@ -777,9 +829,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 ); @@ -842,6 +913,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. @@ -1131,6 +1237,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 ); @@ -1382,6 +1491,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; @@ -1777,6 +1890,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 currCuArea = cu.block(getFirstComponentOfChannel(partitioner.chType)); + cu.slice->m_mapPltCost[currCuArea.pos()][currCuArea.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" ); @@ -4449,7 +4653,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 9ea4376c59f36d45e4adde91438d27200eaf2a42..82bc30422d8ee48587975dc213a98e57757633fd 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 ); @@ -235,6 +235,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 3504d6fd32235bdad327fab0e444e6544b13fe1c..daca183e0847f7c4fdb8d19e513339d9a697d83f 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -66,6 +66,9 @@ EncLib::EncLib() , m_cacheModel() #endif , m_lmcsAPS(nullptr) +#if JVET_O0119_BASE_PALETTE_444 + , m_doPlt( true ) +#endif { m_iPOCLast = -1; m_iNumPicRcvd = 0; @@ -949,7 +952,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 ); @@ -1716,6 +1721,39 @@ bool EncLib::SPSNeedsWriting(int spsId) return bChanged; } +#if JVET_O0119_BASE_PALETTE_444 +void EncLib::checkPltStats( Picture* pic ) +{ + int totalArea = 0; + int pltArea = 0; + for (auto apu : pic->cs->pus) + { + for (int i = 0; i < MAX_NUM_TBLOCKS; ++i) + { + int puArea = apu->blocks[i].width * apu->blocks[i].height; + if (apu->blocks[i].width > 0 && apu->blocks[i].height > 0) + { + totalArea += puArea; + if (CU::isPLT(*apu->cu) || CU::isIBC(*apu->cu)) + { + pltArea += puArea; + } + break; + } + + } + } + if (pltArea * PLT_FAST_RATIO < totalArea) + { + m_doPlt = false; + } + else + { + m_doPlt = true; + } +} +#endif + #if X0038_LAMBDA_FROM_QP_CAPABILITY int EncCfg::getQPForPicture(const uint32_t gopIndex, const Slice *pSlice) const { @@ -1787,4 +1825,5 @@ int EncCfg::getQPForPicture(const uint32_t gopIndex, const Slice *pSlice) const } #endif + //! \} diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index 71bcf0d1b5abc5faa62e6359660f179ffc9b0ef7..09eaa50d4d436359042ec64f3002938493a4b37f 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -148,6 +148,10 @@ private: EncHRD m_encHRD; +#if JVET_O0119_BASE_PALETTE_444 + bool m_doPlt; +#endif + public: Ctx m_entropyCodingSyncContextState; ///< leave in addition to vector for compatibility #if ENABLE_WPP_PARALLELISM @@ -241,6 +245,11 @@ public: #endif ParameterSetMap<APS>* getApsMap() { return &m_apsMap; } + +#if JVET_O0119_BASE_PALETTE_444 + bool getPltEnc() const { return m_doPlt; } + void checkPltStats( Picture* pic ); +#endif // ------------------------------------------------------------------------------------------------------------------- // encoder function // ------------------------------------------------------------------------------------------------------------------- diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index acfb5f43ad30f8f93bb5d7b29ca9fba51a7aedcc..194b94f624edf803c35d0d7b0d9657de5f49d903 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,6 @@ void EncModeCtrlMTnoRQT::initCTUEncoding( const Slice &slice ) } } - void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStructure& cs ) { // Min/max depth @@ -1311,8 +1342,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() || (cs.area.lwidth() == 4 && cs.area.lheight() == 4) ) && getPltEnc() ) + { + 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() && !(cs.area.lwidth() == 4 && cs.area.lheight() == 4) && getPltEnc() ) + { + 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 }); @@ -1532,9 +1575,37 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt } } } - +#if JVET_O0119_BASE_PALETTE_444 + if (bestMode.type == ETM_PALETTE && !slice.isIRAP() && !( partitioner.currArea().lumaSize().width == 4 && partitioner.currArea().lumaSize().height == 4) ) // 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 a690dc538774af55c66f4bd6df999dbc9f6220ad..9cb8ce809b41cccbdb8eab23ed1bf5733b8ca22a 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, @@ -268,6 +271,10 @@ protected: InterSearch* m_pcInterSearch; #endif +#if JVET_O0119_BASE_PALETTE_444 + bool m_doPlt; +#endif + public: virtual ~EncModeCtrl () {} @@ -327,6 +334,10 @@ public: #if JVET_O0592_ENC_ME_IMP void setInterSearch (InterSearch* pcInterSearch) { m_pcInterSearch = pcInterSearch; } #endif +#if JVET_O0119_BASE_PALETTE_444 + void setPltEnc ( bool b ) { m_doPlt = b; } + bool getPltEnc() const { return m_doPlt; } +#endif protected: void xExtractFeatures ( const EncTestMode encTestmode, CodingStructure& cs ); @@ -468,6 +479,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 f8fa6876b20cce2d2312f8acf01f77c17590f974..349701bfa8041e81b363c87646fd66648e0b5797 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -337,6 +337,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); @@ -1396,6 +1399,19 @@ void EncSlice::compressSlice( Picture* pcPic, const bool bCompressEntireSlice, c } #endif // ENABLE_QPA +#if JVET_O0119_BASE_PALETTE_444 + bool checkPLTRatio = m_pcCfg->getIntraPeriod() != 1 && pcSlice->isIRAP(); + if (checkPLTRatio) + { + m_pcCuEncoder->getModeCtrl()->setPltEnc(true); + } + else + { + bool doPlt = m_pcLib->getPltEnc(); + m_pcCuEncoder->getModeCtrl()->setPltEnc(doPlt); + } +#endif + #if ENABLE_WPP_PARALLELISM bool bUseThreads = m_pcCfg->getNumWppThreads() > 1; if( bUseThreads ) @@ -1430,8 +1446,9 @@ 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 (checkPLTRatio) m_pcLib->checkPltStats( pcPic ); +#endif } void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr ) @@ -1615,12 +1632,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. @@ -1905,6 +1928,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) @@ -1913,6 +1939,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 05d5faabc95c8f620ce0084da90d524bec7b7b95..f5ac671a5d4635ae2280f13ea1c05cfa530d5b5a 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) @@ -1538,6 +1539,575 @@ 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 height = cu.block(compBegin).height; + uint32_t width = 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 *runLength = tu.getRunLens (compBegin); + bool *runType = tu.getRunTypes(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 bits = MAX_UINT; + deriveRunAndCalcBits(cs, partitioner, compBegin, numComp, PLT_SCAN_HORTRAV, bits); + if ((cu.curPLTSize[compBegin] + cu.useEscape[compBegin]) > 1) + { + deriveRunAndCalcBits(cs, partitioner, compBegin, numComp, PLT_SCAN_VERTRAV, bits); + } + cu.useRotation[compBegin] = m_bestScanRotationMode; + memcpy(runType, m_runTypeRD, sizeof(bool)*width*height); + memcpy(runLength, m_runLengthRD, sizeof(Pel)*width*height); + //reconstruct pixel + PelBuf curPLTIdx = tu.getcurPLTIdx(compBegin); + for (uint32_t y = 0; y < height; y++) + { + for (uint32_t x = 0; x < width; x++) + { + if (curPLTIdx.at(x, y) == 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(x, y) = cu.curPLT[compID][curPLTIdx.at(x, y)]; + } + else if (compBegin == COMPONENT_Y && compID != COMPONENT_Y && y % (1 << scaleY) == 0 && x % (1 << scaleX) == 0) + { + recBuf.at(x >> scaleX, y >> scaleY) = cu.curPLT[compID][curPLTIdx.at(x, y)]; + } + } + } + } + } + + 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& minBits) +{ + CodingUnit &cu = *cs.getCU(partitioner.chType); + TransformUnit &tu = *cs.getTU(partitioner.chType); + uint32_t height = cu.block(compBegin).height; + uint32_t width = cu.block(compBegin).width; + Pel *runLength = tu.getRunLens (compBegin); + bool *runType = tu.getRunTypes(compBegin); + + cu.useRotation[compBegin] = (pltScanMode == PLT_SCAN_VERTRAV); + m_scanOrder = g_scanOrder[SCAN_UNGROUPED][(cu.useRotation[compBegin]) ? SCAN_TRAV_VER : SCAN_TRAV_HOR][gp_sizeIdxInfo->idxFrom(width)][gp_sizeIdxInfo->idxFrom(height)]; + deriveRun(cs, partitioner, compBegin); + + 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 bitsTemp = m_CABACEstimator->getEstFracBits(); + if (minBits > bitsTemp) + { + m_bestScanRotationMode = pltScanMode; + memcpy(m_runTypeRD, runType, sizeof(bool)*width*height); + memcpy(m_runLengthRD, runLength, sizeof(Pel)*width*height); + minBits = bitsTemp; + } +} +void IntraSearch::deriveRun(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin) +{ + CodingUnit &cu = *cs.getCU(partitioner.chType); + TransformUnit &tu = *cs.getTU(partitioner.chType); + uint32_t height = cu.block(compBegin).height; + uint32_t width = cu.block(compBegin).width; + uint32_t total = height * width, idx = 0; + uint32_t startPos = 0; + uint64_t indexBits = 0, runBitsIndex = 0, runBitsCopy = 0; + m_storeCtxRun = PLTCtx(m_orgCtxRD); + + PLTtypeBuf runType = tu.getrunType(compBegin); + PelBuf runLength = tu.getrunLength(compBegin); + while (idx < total) + { + startPos = idx; + double aveBitsPerPix[NUM_PLT_RUN]; + uint32_t indexRun = 0; + bool runValid = calIndexRun(cs, partitioner, startPos, total, indexRun, compBegin); + m_CABACEstimator->getCtx() = PLTCtx(m_storeCtxRun); + aveBitsPerPix[PLT_RUN_INDEX] = runValid ? getRunBits(cu, indexRun, startPos, PLT_RUN_INDEX, &indexBits, &runBitsIndex, compBegin) : MAX_DOUBLE; + m_storeCtxRunIndex = PLTCtx(m_CABACEstimator->getCtx()); + + uint32_t copyRun = 0; + bool copyValid = calCopyRun(cs, partitioner, startPos, total, copyRun, compBegin); + m_CABACEstimator->getCtx() = PLTCtx(m_storeCtxRun); + aveBitsPerPix[PLT_RUN_COPY] = copyValid ? getRunBits(cu, copyRun, startPos, PLT_RUN_COPY, &indexBits, &runBitsCopy, compBegin) : MAX_DOUBLE; + m_storeCtxRunCopy = PLTCtx(m_CABACEstimator->getCtx()); + + if (copyValid == 0 && runValid == 0) + { + assert(0); + } + else + { + if (aveBitsPerPix[PLT_RUN_COPY] <= aveBitsPerPix[PLT_RUN_INDEX]) + { + for (int runidx = 0; runidx <copyRun; runidx++) + { + uint32_t posy = m_scanOrder[idx + runidx].y; + uint32_t posx = m_scanOrder[idx + runidx].x; + runType.at(posx, posy) = PLT_RUN_COPY; + runLength.at(posx, posy) = copyRun; + } + idx += copyRun; + m_storeCtxRun = PLTCtx(m_storeCtxRunCopy); + + } + else + { + for (int runidx = 0; runidx <indexRun; runidx++) + { + uint32_t posy = m_scanOrder[idx + runidx].y; + uint32_t posx = m_scanOrder[idx + runidx].x; + runType.at(posx, posy) = PLT_RUN_INDEX; + runLength.at(posx, posy) = indexRun; + } + idx += indexRun; + m_storeCtxRun = PLTCtx(m_storeCtxRunIndex); + + } + } + } + assert(idx == total); +} +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 height = cu.block(compBegin).height; + uint32_t width = cu.block(compBegin).width; + uint32_t endPos = height*width; + PLTtypeBuf runType = tu.getrunType(compBegin); + PelBuf curPLTIdx = tu.getcurPLTIdx(compBegin); + uint32_t indexMaxSize = (cu.useEscape[compBegin]) ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin]; + + m_CABACEstimator->resetBits(); + ///////////////// encode Run Type + m_CABACEstimator->encodeRunType(cu, runType, strPos, m_scanOrder, 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, indexMaxSize, 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 costPerPixel = (double)m_CABACEstimator->getEstFracBits() / (double)run; + return costPerPixel; +} +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 height = cu.block(compBegin).height; + uint32_t width = 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 errorLimit = numComp * g_paletteQuant[cu.qp]; + uint32_t bestIdx = 0; + uint32_t scaleX = getComponentScaleX(COMPONENT_Cb, cs.sps->getChromaFormatIdc()); + uint32_t scaleY = getComponentScaleY(COMPONENT_Cb, cs.sps->getChromaFormatIdc()); + for (uint32_t y = 0; y < height; y++) + { + for (uint32_t x = 0; x < width; x++) + { + uint32_t pltIdx = 0; + uint32_t minError = MAX_UINT; + while (pltIdx < cu.curPLTSize[compBegin]) + { + uint32_t absError = 0, pX, pY; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + pX = (comp > 0 && compBegin == COMPONENT_Y) ? (x >> scaleX) : x; + pY = (comp > 0 && compBegin == COMPONENT_Y) ? (y >> scaleY) : y; + int shift = (comp > 0) ? pcmShiftRight_C : pcmShiftRight_L; + absError += abs(cu.curPLT[comp][pltIdx] - orgBuf[comp].at(pX, pY)) >> shift; + } + + if (absError < minError) + { + bestIdx = pltIdx; + minError = absError; + if (minError == 0) + { + break; + } + } + pltIdx++; + } + curPLTIdx.at(x, y) = bestIdx; + if (minError > errorLimit) + { + curPLTIdx.at(x, y) = cu.curPLTSize[compBegin]; + cu.useEscape[compBegin] = true; + calcPixelPred(cs, partitioner, y, x, compBegin, numComp); + } + } + } +} +void IntraSearch::calcPixelPred(CodingStructure& cs, Partitioner& partitioner, uint32_t yPos, uint32_t xPos, 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 qp[3]; + int qpRem[3]; + int qpPer[3]; + int quantiserScale[3]; + int quantiserRightShift[3]; + int rightShiftOffset[3]; + int InvquantiserRightShift[3]; + int add[3]; + for (uint32_t ch = compBegin; ch < (compBegin + numComp); ch++) + { + QpParam cQP(tu, ComponentID(ch)); +#if JVET_O0919_TS_MIN_QP + qp[ch] = cQP.Qp(false); +#else + qp[ch] = cQP.Qp; +#endif + qpRem[ch] = qp[ch] % 6; + qpPer[ch] = qp[ch] / 6; + quantiserScale[ch] = g_quantScales[0][qpRem[ch]]; + quantiserRightShift[ch] = QUANT_SHIFT + qpPer[ch]; + rightShiftOffset[ch] = 1 << (quantiserRightShift[ch] - 1); + InvquantiserRightShift[ch] = IQUANT_SHIFT; + add[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(xPos, yPos) = TCoeff(std::max<int>(0, ((orgBuf[ch].at(xPos, yPos) * quantiserScale[ch] + rightShiftOffset[ch]) >> quantiserRightShift[ch]))); + assert(escapeValue.at(xPos, yPos) < (1 << (channelBitDepth + 1))); + recBuf.at(xPos, yPos) = (((escapeValue.at(xPos, yPos)*g_invQuantScales[0][qpRem[ch]]) << qpPer[ch]) + add[ch]) >> InvquantiserRightShift[ch]; + recBuf.at(xPos, yPos) = Pel(ClipBD<int>(recBuf.at(xPos, yPos), channelBitDepth));//to be checked + } + else if (compBegin == COMPONENT_Y && ch > 0 && yPos % (1 << scaleY) == 0 && xPos % (1 << scaleX) == 0) + { + uint32_t yPosC = yPos >> scaleY; + uint32_t xPosC = xPos >> scaleX; + escapeValue.at(xPosC, yPosC) = TCoeff(std::max<int>(0, ((orgBuf[ch].at(xPosC, yPosC) * quantiserScale[ch] + rightShiftOffset[ch]) >> quantiserRightShift[ch]))); + assert(escapeValue.at(xPosC, yPosC) < (1 << (channelBitDepth + 1))); + recBuf.at(xPosC, yPosC) = (((escapeValue.at(xPosC, yPosC)*g_invQuantScales[0][qpRem[ch]]) << qpPer[ch]) + add[ch]) >> InvquantiserRightShift[ch]; + recBuf.at(xPosC, yPosC) = Pel(ClipBD<int>(recBuf.at(xPosC, yPosC), 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 height = cu.block(compBegin).height; + uint32_t width = 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 errorLimit = g_paletteQuant[cu.qp]; + uint32_t totalSize = height*width; + SortingElement *pelList = new SortingElement[totalSize]; + SortingElement element; + SortingElement *pelListSort = new SortingElement[MAXPLTSIZE + 1]; + uint32_t dictMaxSize = MAXPLTSIZE; + uint32_t idx = 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 y = 0; y < height; y++) + { + for (uint32_t x = 0; x < width; x++) + { + uint32_t org[3], pX, pY; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + pX = (comp > 0 && compBegin == COMPONENT_Y) ? (x >> scaleX) : x; + pY = (comp > 0 && compBegin == COMPONENT_Y) ? (y >> scaleY) : y; + org[comp] = orgBuf[comp].at(pX, pY); + } + element.setAll(org, compBegin, numComp); + int besti = last, bestSAD = (last == -1) ? MAX_UINT : pelList[last].getSAD(element, cs.sps->getBitDepths(), compBegin, numComp); + if (bestSAD) + { + for (int i = idx - 1; i >= 0; i--) + { + uint32_t sad = pelList[i].getSAD(element, cs.sps->getBitDepths(), compBegin, numComp); + if (sad < bestSAD) + { + bestSAD = sad; + besti = i; + if (!sad) break; + } + } + } + if (besti >= 0 && pelList[besti].almostEqualData(element, errorLimit, cs.sps->getBitDepths(), compBegin, numComp)) + { + pelList[besti].addElement(element, compBegin, numComp); + last = besti; + } + else + { + pelList[idx].copyDataFrom(element, compBegin, numComp); + pelList[idx].setCnt(1); + last = idx; + idx++; + } + } + } + + for (int i = 0; i < dictMaxSize; i++) + { + pelListSort[i].setCnt(0); + pelListSort[i].resetAll(compBegin, numComp); + } + + //bubble sorting + dictMaxSize = 1; + for (int i = 0; i < idx; i++) + { + if (pelList[i].getCnt() > pelListSort[dictMaxSize - 1].getCnt()) + { + int j; + for (j = dictMaxSize; j > 0; j--) + { + if (pelList[i].getCnt() > pelListSort[j - 1].getCnt() ) + { + pelListSort[j].copyAllFrom(pelListSort[j - 1], compBegin, numComp); + dictMaxSize = std::min(dictMaxSize + 1, (uint32_t)MAXPLTSIZE); + } + else + { + break; + } + } + pelListSort[j].copyAllFrom(pelList[i], compBegin, numComp); + } + } + + uint32_t paletteSize = 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 (pelListSort[i].getCnt()) + { + int half = pelListSort[i].getCnt() >> 1; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + cu.curPLT[comp][paletteSize] = (pelListSort[i].getSumData(comp) + half) / pelListSort[i].getCnt(); + } + + int best = -1; + if (errorLimit) + { + 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] = pelListSort[i].getSumData(comp) / (double)pelListSort[i].getCnt(); + err = pal[comp] - cu.curPLT[comp][paletteSize]; + bestCost += (err*err) / (1 << (2 * shift)); + } + bestCost = bestCost * pelListSort[i].getCnt() + 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 *= pelListSort[i].getCnt(); + if (cost < bestCost) + { + best = t; + bestCost = cost; + } + } + if (best != -1) + { + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + cu.curPLT[comp][paletteSize] = cs.prevPLT.curPLT[comp][best]; + } + } + } + + bool duplicate = false; + if (pelListSort[i].getCnt() == 1 && best == -1) + { + duplicate = true; + } + else + { + for (int t = 0; t<paletteSize; t++) + { + bool duplicateTmp = true; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + duplicateTmp = duplicateTmp && (cu.curPLT[comp][paletteSize] == cu.curPLT[comp][t]); + } + if (duplicateTmp) + { + duplicate = true; + break; + } + } + } + if (!duplicate) paletteSize++; + } + else + { + break; + } + } + cu.curPLTSize[compBegin] = paletteSize; + + delete[] pelList; + delete[] pelListSort; +} +#endif // ------------------------------------------------------------------------------------------------------------------- // Intra search // ------------------------------------------------------------------------------------------------------------------- @@ -1553,9 +2123,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() ) { @@ -1564,6 +2140,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 ee90779e71b7f02e2c4775ea76a5e97d0688de27..86d2d5bbdf923233315b51596c6da1a5402ba356 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -56,9 +56,113 @@ // ==================================================================================================================== // Class definition // ==================================================================================================================== - class EncModeCtrl; +#if JVET_O0119_BASE_PALETTE_444 +enum PLTScanMode +{ + PLT_SCAN_HORTRAV = 0, + PLT_SCAN_VERTRAV = 1, + NUM_PLT_SCAN = 2 +}; +class SortingElement +{ +public: + inline bool operator<(const SortingElement &other) const + { + return cnt > other.cnt; + } + SortingElement() { + cnt = shift = lastCnt = 0; + data[0] = data[1] = data[2] = 0; + sumData[0] = sumData[1] = sumData[2] = 0; + } + uint32_t getCnt() const { return cnt; } + void setCnt(uint32_t val) { cnt = val; } + int getSumData (int id) const { return sumData[id]; } + + void resetAll(ComponentID compBegin, uint32_t numComp) + { + shift = lastCnt = 0; + for (int ch = compBegin; ch < (compBegin + numComp); ch++) + { + data[ch] = 0; + sumData[ch] = 0; + } + } + void setAll(uint32_t* ui, ComponentID compBegin, uint32_t numComp) + { + for (int ch = compBegin; ch < (compBegin + numComp); ch++) + { + data[ch] = ui[ch]; + } + } + bool almostEqualData(SortingElement element, int errorLimit, const BitDepths& bitDepths, ComponentID compBegin, uint32_t numComp) + { + bool almostEqual = true; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + ChannelType chType = (comp > 0) ? CHANNEL_TYPE_CHROMA : CHANNEL_TYPE_LUMA; + if ((std::abs(data[comp] - element.data[comp]) >> (bitDepths.recon[chType] - PLT_ENCBITDEPTH)) > errorLimit) + { + almostEqual = false; + break; + } + } + return almostEqual; + } + uint32_t getSAD(SortingElement element, const BitDepths& bitDepths, ComponentID compBegin, uint32_t numComp) + { + uint32_t sumAd = 0; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + ChannelType chType = (comp > 0) ? CHANNEL_TYPE_CHROMA : CHANNEL_TYPE_LUMA; + sumAd += (std::abs(data[comp] - element.data[comp]) >> (bitDepths.recon[chType] - PLT_ENCBITDEPTH)); + } + return sumAd; + } + void copyDataFrom(SortingElement element, ComponentID compBegin, uint32_t numComp) + { + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + data[comp] = element.data[comp]; + sumData[comp] = data[comp]; + } + shift = 0; lastCnt = 1; + } + void copyAllFrom(SortingElement element, ComponentID compBegin, uint32_t numComp) + { + copyDataFrom(element, compBegin, numComp); + cnt = element.cnt; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + sumData[comp] = element.sumData[comp]; + } + lastCnt = element.lastCnt; shift = element.shift; + } + void addElement(const SortingElement& element, ComponentID compBegin, uint32_t numComp) + { + cnt++; + for (int i = compBegin; i<(compBegin + numComp); i++) + { + sumData[i] += element.data[i]; + } + if (cnt>1 && cnt == 2 * lastCnt) + { + uint32_t rnd = 1 << shift; + shift++; + for (int i = compBegin; i<(compBegin + numComp); i++) + { + data[i] = (sumData[i] + rnd) >> shift; + } + lastCnt = cnt; + } + } +private: + uint32_t cnt; + int shift, lastCnt, data[3], sumData[3]; +}; +#endif /// encoder search class class IntraSearch : public IntraPrediction, CrossComponentPrediction { @@ -277,6 +381,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& bits); +#endif uint64_t xFracModeBitsIntra (PredictionUnit &pu, const uint32_t &uiMode, const ChannelType &compID); void invalidateBestModeCost () { for( int i = 0; i < NUM_LFNST_NUM_PER_SET; i++ ) m_bestModeCostValid[ i ] = false; }; @@ -316,7 +424,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); + 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 yPos, uint32_t xPos, ComponentID compBegin, uint32_t numComp); + void preCalcPLTIndex(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp); +#endif #if JVET_O0502_ISP_CLEANUP void xGetNextISPMode ( ModeInfo& modeInfo, const ModeInfo* lastMode, const Size cuSize ); void xFindAlreadyTestedNearbyIntraModes ( int currentIntraMode, int* leftIntraMode, int* rightIntraMode, ISPType ispOption, int windowSize ); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 181220a6452d95136b839c7b0b146e134b344022..5e6eaa0cc1b498ea19092b77ff2aaa69817c1e03 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -938,6 +938,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