diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index 5f8019a304be09840c4b98ffdc10f31d6d6f0a72..7bd1333159a6690ae84778fda2ff9d2832488fe0 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -452,6 +452,18 @@ void initROM() #endif ::memset(g_isReusedUniMVsFilled, 0, sizeof(g_isReusedUniMVsFilled)); + +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + for (int qp = 0; qp < 57; qp++) + { + int qpRem = (qp + 12) % 6; + int qpPer = (qp + 12) / 6; + int quantiserScale = g_quantScales[0][qpRem]; + int quantiserRightShift = QUANT_SHIFT + qpPer; + double threshQP = ((double)(1 << quantiserRightShift)) / quantiserScale; + g_paletteQuant[qp] = (int)(threshQP*0.16 + 0.5); + } +#endif } void destroyROM() @@ -736,7 +748,11 @@ int16_t *g_triangleWeights[TRIANGLE_DIR_NUM][MAX_CU_DEPTH - MIN_CU_LOG2 + 2][MAX Mv g_reusedUniMVs[32][32][8][8][2][33]; bool g_isReusedUniMVsFilled[32][32][8][8]; +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX +uint16_t g_paletteQuant[57]; +#else const uint8_t g_paletteQuant[52] = { 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 8, 9, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 22, 24, 23, 25, 26, 28, 29, 31, 32, 34, 36, 37, 39, 41, 42, 45 }; +#endif uint8_t g_paletteRunTopLut [5] = { 0, 1, 1, 2, 2 }; uint8_t g_paletteRunLeftLut[5] = { 0, 1, 2, 3, 4 }; diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index 010891cb10e6a2d66619e56e53c7b60f22ca088e..ecdbdd9bc79e9645352fc21264fa241d8685064a 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -217,7 +217,11 @@ class Mv; extern Mv g_reusedUniMVs[32][32][8][8][2][33]; extern bool g_isReusedUniMVsFilled[32][32][8][8]; +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX +extern uint16_t g_paletteQuant[57]; +#else extern const uint8_t g_paletteQuant[52]; +#endif extern uint8_t g_paletteRunTopLut[5]; extern uint8_t g_paletteRunLeftLut[5]; diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index a52e8adf728f143ba2f908b11bccbeaf9d75f2e2..eb177f29110352577600b4e93965964fc619220f 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -64,6 +64,8 @@ #define JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU 1 // JVET-Q0501: Initialize palette predictor from above CTU row in WPP +#define JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX 1 // JVET-Q0503/Q0712: Platte encoder improvement/bugfix + #define JVET_Q0819_PH_CHANGES 1 // JVET-Q0819: Combination of PH related syntax changes #define JVET_Q0481_PARTITION_CONSTRAINTS_ORDER 1 // JVET-Q0481: Ordering of partition constraints syntax elements in the SPS diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 5ee8d0ee19ec6d5b677ef1ebf56d425d22c76f58..01aefd05cfdfc5b0cafe6142340bf9e5604b67db 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -1567,13 +1567,83 @@ void IntraSearch::PLTSearch(CodingStructure &cs, Partitioner& partitioner, Compo derivePLTLossy(cs, partitioner, compBegin, numComp); reorderPLT(cs, partitioner, compBegin, numComp); +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + bool idxExist[MAXPLTSIZE + 1] = { false }; +#endif preCalcPLTIndexRD(cs, partitioner, compBegin, numComp); // Pre-calculate distortions for each pixel double rdCost = MAX_DOUBLE; +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_HORTRAV, rdCost, idxExist); // Optimize palette index map (horizontal scan) +#else deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_HORTRAV, rdCost); // Optimize palette index map (horizontal scan) +#endif if ((cu.curPLTSize[compBegin] + cu.useEscape[compBegin]) > 1) { +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_VERTRAV, rdCost, idxExist); // Optimize palette index map (vertical scan) +#else deriveIndexMap(cs, partitioner, compBegin, numComp, PLT_SCAN_VERTRAV, rdCost); // Optimize palette index map (vertical scan) +#endif + } +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + // Remove unused palette entries + uint8_t newPLTSize = 0; + int idxMapping[MAXPLTSIZE + 1]; + memset(idxMapping, -1, sizeof(int) * (MAXPLTSIZE + 1)); + for (int i = 0; i < cu.curPLTSize[compBegin]; i++) + { + if (idxExist[i]) + { + idxMapping[i] = newPLTSize; + newPLTSize++; + } + } + idxMapping[cu.curPLTSize[compBegin]] = cu.useEscape[compBegin]? newPLTSize: -1; + if (newPLTSize != cu.curPLTSize[compBegin]) // there exist unused palette entries + { // update palette table and reuseflag + Pel curPLTtmp[MAX_NUM_COMPONENT][MAXPLTSIZE]; + int reuseFlagIdx = 0, curPLTtmpIdx = 0, reuseEntrySize = 0; + memset(cu.reuseflag[compBegin], false, sizeof(bool) * MAXPLTPREDSIZE); + for (int curIdx = 0; curIdx < cu.curPLTSize[compBegin]; curIdx++) + { + if (idxExist[curIdx]) + { + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + curPLTtmp[comp][curPLTtmpIdx] = cu.curPLT[comp][curIdx]; + + // Update reuse flags + if (curIdx < cu.reusePLTSize[compBegin]) + { + bool match = false; + for (; reuseFlagIdx < cs.prevPLT.curPLTSize[compBegin]; reuseFlagIdx++) + { + bool matchTmp = true; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + { + matchTmp = matchTmp && (curPLTtmp[comp][curPLTtmpIdx] == cs.prevPLT.curPLT[comp][reuseFlagIdx]); + } + if (matchTmp) + { + match = true; + break; + } + } + if (match) + { + cu.reuseflag[compBegin][reuseFlagIdx] = true; + reuseEntrySize++; + } + } + curPLTtmpIdx++; + } + } + cu.reusePLTSize[compBegin] = reuseEntrySize; + // update palette table + cu.curPLTSize[compBegin] = newPLTSize; + for (int comp = compBegin; comp < (compBegin + numComp); comp++) + memcpy( cu.curPLT[comp], curPLTtmp[comp], sizeof(Pel)*cu.curPLTSize[compBegin]); } +#endif cu.useRotation[compBegin] = m_bestScanRotationMode; int indexMaxSize = cu.useEscape[compBegin] ? (cu.curPLTSize[compBegin] + 1) : cu.curPLTSize[compBegin]; if (indexMaxSize <= 1) @@ -1586,6 +1656,9 @@ void IntraSearch::PLTSearch(CodingStructure &cs, Partitioner& partitioner, Compo { for (uint32_t x = 0; x < width; x++) { +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + curPLTIdx.at(x, y) = idxMapping[curPLTIdx.at(x, y)]; +#endif if (curPLTIdx.at(x, y) == cu.curPLTSize[compBegin]) { calcPixelPred(cs, partitioner, y, x, compBegin, numComp); @@ -1782,7 +1855,11 @@ void IntraSearch::preCalcPLTIndexRD(CodingStructure& cs, Partitioner& partitione } } +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX +void IntraSearch::deriveIndexMap(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dMinCost, bool* idxExist) +#else void IntraSearch::deriveIndexMap(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dMinCost) +#endif { CodingUnit &cu = *cs.getCU(partitioner.chType); TransformUnit &tu = *cs.getTU(partitioner.chType); @@ -1905,10 +1982,16 @@ void IntraSearch::deriveIndexMap(CodingStructure& cs, Partitioner& partitioner, { cu.useEscape[compBegin] = m_bestEscape; m_bestScanRotationMode = pltScanMode; +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + memset(idxExist, false, sizeof(bool) * (MAXPLTSIZE + 1)); +#endif for (int pos = 0; pos < (width*height); pos++) { runIndex[pos] = checkIndexTable[pos]; runType[pos] = checkRunTable[pos]; +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + idxExist[checkIndexTable[pos]] = true; +#endif } dMinCost = sumRdCost; } @@ -2072,16 +2155,32 @@ double IntraSearch::rateDistOptPLT( rdCost = MAX_DOUBLE; return rdCost; } +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + rdCost += m_pcRdCost->getLambda()*(m_truncBinBits[(runIndex > refIndex) ? runIndex - 1 : runIndex][(scanPos == 0) ? (indexMaxValue + 1) : indexMaxValue] << SCALE_BITS); +#else rdCost += m_pcRdCost->getLambda()*m_truncBinBits[(runIndex > refIndex) ? runIndex - 1 : runIndex][(scanPos == 0) ? (indexMaxValue + 1) : indexMaxValue]; +#endif } +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + rdCost += m_indexError[runIndex][m_scanOrder[scanPos].idx] * (1 << SCALE_BITS); +#else rdCost += m_indexError[runIndex][m_scanOrder[scanPos].idx]; +#endif if (scanPos > 0) { +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + rdCost += m_pcRdCost->getLambda()*( identityFlag ? (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[1]) : (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[0] ) ); +#else rdCost += m_pcRdCost->getLambda()*( identityFlag ? (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[1] >> SCALE_BITS) : (IndexfracBits[(dist < RUN_IDX_THRE) ? dist : RUN_IDX_THRE].intBits[0] >> SCALE_BITS)); +#endif } if ( !identityFlag && scanPos >= width && prevRunType != PLT_RUN_COPY ) { +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + rdCost += m_pcRdCost->getLambda()*TypefracBits.intBits[runType]; +#else rdCost += m_pcRdCost->getLambda()*(TypefracBits.intBits[runType] >> SCALE_BITS); +#endif } if (!identityFlag || scanPos == 0) { @@ -2251,7 +2350,15 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, } } +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + TransformUnit &tu = *cs.getTU(partitioner.chType); + QpParam cQP(tu, compBegin); + int qp = cQP.Qp(true) - 12; + qp = (qp < 0) ? 0 : ((qp > 56) ? 56 : qp); + int errorLimit = g_paletteQuant[qp]; +#else int errorLimit = g_paletteQuant[cu.qp]; +#endif uint32_t totalSize = height*width; SortingElement *pelList = new SortingElement[totalSize]; SortingElement element; @@ -2340,6 +2447,11 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, } const int plt_lambda_shift = (compBegin > 0) ? pcmShiftRight_C : pcmShiftRight_L; double bitCost = m_pcRdCost->getLambda() / (double) (1 << (2 * plt_lambda_shift)) * numColorBits; +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + bool reuseflag[MAXPLTPREDSIZE] = { false }; + int run; + double reuseflagCost; +#endif for (int i = 0; i < MAXPLTSIZE; i++) { if (pelListSort[i].getCnt()) @@ -2385,6 +2497,22 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, } } cost *= pelListSort[i].getCnt(); +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + run = 0; + for (int t2 = t-1; t2 >= 0; t2--) + { + if (!reuseflag[t2]) + { + run++; + } + else + { + break; + } + } + reuseflagCost = m_pcRdCost->getLambda() / (double)(1 << (2 * plt_lambda_shift)) * getEpExGolombNumBins(run ? run + 1 : run, 0); + cost += reuseflagCost; +#endif if (cost < bestCost) { best = t; @@ -2397,6 +2525,9 @@ void IntraSearch::derivePLTLossy(CodingStructure& cs, Partitioner& partitioner, { cu.curPLT[comp][paletteSize] = cs.prevPLT.curPLT[comp][best]; } +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + reuseflag[best] = true; +#endif } } diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 72ccaa02148956bceded9d45694cbe2c7c58baf5..9370c143072ad7548d439be5a43bf1270c020143 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -453,7 +453,11 @@ protected: void calcPixelPred ( CodingStructure& cs, Partitioner& partitioner, uint32_t yPos, uint32_t xPos, ComponentID compBegin, uint32_t numComp); void preCalcPLTIndexRD (CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp); void calcPixelPredRD (CodingStructure& cs, Partitioner& partitioner, Pel* orgBuf, Pel* pixelValue, Pel* recoValue, ComponentID compBegin, uint32_t numComp); +#if JVET_Q0503_Q0712_PLT_ENCODER_IMPROV_BUGFIX + void deriveIndexMap (CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dCost, bool* idxExist); +#else void deriveIndexMap (CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, uint32_t numComp, PLTScanMode pltScanMode, double& dCost); +#endif bool deriveSubblockIndexMap(CodingStructure& cs, Partitioner& partitioner, ComponentID compBegin, PLTScanMode pltScanMode, int minSubPos, int maxSubPos, const BinFracBits& fracBitsPltRunType, const BinFracBits* fracBitsPltIndexINDEX, const BinFracBits* fracBitsPltIndexCOPY, const double minCost, bool useRotate); double rateDistOptPLT (bool RunType, uint8_t RunIndex, bool prevRunType, uint8_t prevRunIndex, uint8_t aboveRunIndex, bool& prevCodedRunType, int& prevCodedRunPos, int scanPos, uint32_t width, int dist, int indexMaxValue, const BinFracBits* IndexfracBits, const BinFracBits& TypefracBits); void initTBCTable (int bitDepth);