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