diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index ca1fcc142b6294d867d4c49af4c2a63275dcc7ca..b678584b3ec2c3c2f9196b080459aa1b8a0c8019 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -818,6 +818,11 @@ void EncApp::xInitLibCfg() m_cEncLib.setBIFStrength ( m_BIFStrength ); m_cEncLib.setBIFQPOffset ( m_BIFQPOffset ); #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + m_cEncLib.setUseCBIF ( m_CBIF ); + m_cEncLib.setCBIFStrength ( m_CBIFStrength ); + m_cEncLib.setCBIFQPOffset ( m_CBIFQPOffset ); +#endif // ADD_NEW_TOOL : (encoder app) add setting of tool enabling flags and associated parameters here m_cEncLib.setVirtualBoundariesEnabledFlag ( m_virtualBoundariesEnabledFlag ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 06a822fda82092c00e699e35b977a36f9ba95d86..8112500c0320be6e81df91bd1ed267acf66b83c9 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1064,6 +1064,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("BIF", m_BIF, true, "bilateral filter (0: off, 1:on) [default: on]") ("BIFStrength", m_BIFStrength, 1u, "bilateral filter strength (0: half, 1: full, 2: double) [default: full]") ("BIFQPOffset", m_BIFQPOffset, 0, "bilateral filter QP offset (0: no offset) [default: 0]") +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + ("CBIF", m_CBIF, true, "chroma bilateral filter (0: off, 1:on) [default: on]") + ("CBIFStrength", m_CBIFStrength, 1u, "chroma bilateral filter strength (0: half, 1: full, 2: double) [default: full]") + ("CBIFQPOffset", m_CBIFQPOffset, 0, "chroma bilateral filter QP offset (0: no offset) [default: 0]") #endif // ADD_NEW_TOOL : (encoder app) add parsing parameters here ( "VirtualBoundariesPresentInSPSFlag", m_virtualBoundariesPresentFlag, true, "Virtual Boundary position information is signalled in SPS or PH (1:SPS, 0:PH) [default: on]" ) @@ -4361,6 +4366,11 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "BIF:%d ", m_BIF); msg( VERBOSE, "BIFStrength:%d ", m_BIFStrength); msg( VERBOSE, "BIFQPOffset:%d ", m_BIFQPOffset); +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + msg( VERBOSE, "CBIF:%d ", m_CBIF); + msg( VERBOSE, "CBIFStrength:%d ", m_CBIFStrength); + msg( VERBOSE, "CBIFQPOffset:%d ", m_CBIFQPOffset); #endif // ADD_NEW_TOOL (add some output indicating the usage of tools) msg( VERBOSE, "VirtualBoundariesEnabledFlag:%d ", m_virtualBoundariesEnabledFlag ); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 23b3207f30daafe08f032819e8a9fff6bf1f5842..45bd7a81cf9d066312e63877fb351902c30dc34c 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -432,6 +432,11 @@ protected: unsigned m_BIFStrength; /// Bilateral filter strength int m_BIFQPOffset; /// Bilateral QP offset #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + bool m_CBIF; + unsigned m_CBIFStrength; + int m_CBIFQPOffset; +#endif // ADD_NEW_TOOL : (encoder app) add tool enabling flags and associated parameters here bool m_virtualBoundariesEnabledFlag; diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index 5a32244555c875377e13691fae18594827e55880..35e34d36743fd6851877b0616c5cf8de6bb8794f 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -47,8 +47,16 @@ constexpr int AdaptiveLoopFilter::AlfNumClippingValues[]; AdaptiveLoopFilter::AdaptiveLoopFilter() +#if !JVET_X0071_ALF_BAND_CLASSIFIER : m_classifier( nullptr ) +#endif { +#if JVET_X0071_ALF_BAND_CLASSIFIER + for( int i = 0; i < ALF_NUM_CLASSIFIER; i++ ) + { + m_classifier[i] = nullptr; + } +#endif for (size_t i = 0; i < NUM_DIRECTIONS; i++) { m_laplacian[i] = m_laplacianPtr[i]; @@ -88,6 +96,9 @@ AdaptiveLoopFilter::AdaptiveLoopFilter() m_deriveClassificationLaplacianBig = deriveClassificationLaplacianBig; m_calcClass0 = calcClass; m_calcClass1 = calcClass; +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_calcClass2 = calcClassNew; +#endif m_fixFilterResult = nullptr; #else m_deriveClassificationBlk = deriveClassificationBlk; @@ -540,11 +551,15 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) const Area blkSrc( 0, 0, w, h ); const Area blkDst( xStart, yStart, w, h ); short filterSetIndex = alfCtuFilterIndex[ctuIdx]; +#if JVET_X0071_ALF_BAND_CLASSIFIER + deriveClassification( m_classifier, buf.get(COMPONENT_Y), blkDst, blkSrc, cs, filterSetIndex < NUM_FIXED_FILTER_SETS ? filterSetIndex : -1, filterSetIndex < NUM_FIXED_FILTER_SETS ? -1 : m_classifierIdxApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][m_ctuAlternative[COMPONENT_Y][ctuIdx]] ); +#else deriveClassification( m_classifier, buf.get( COMPONENT_Y ), blkDst, blkSrc #if ALF_IMPROVEMENT , cs, filterSetIndex < NUM_FIXED_FILTER_SETS ? filterSetIndex : -1 #endif ); +#endif short *coeff; #if JVET_R0351_HIGH_BIT_DEPTH_SUPPORT @@ -563,7 +578,12 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; AlfFilterType filterTypeCtb = m_filterTypeApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierIdxApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; + alfFiltering( m_classifier[classifierIdx], recYuv, buf, blkDst, blkSrc, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx ); +#else alfFiltering( m_classifier, recYuv, buf, blkDst, blkSrc, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx ); +#endif } #else if( filterSetIndex >= NUM_FIXED_FILTER_SETS ) @@ -592,7 +612,11 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) const Area blkDst( xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY ); uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx]; #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + alfFiltering( m_classifier[0], recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma, nullptr, -1 ); +#else alfFiltering( m_classifier, recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma, nullptr, -1 ); +#endif #else m_filter5x5Blk(m_classifier, recYuv, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight, m_alfVBChmaPos ); #endif @@ -629,11 +653,15 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) { Area blk( xPos, yPos, width, height ); short filterSetIndex = alfCtuFilterIndex[ctuIdx]; +#if JVET_X0071_ALF_BAND_CLASSIFIER + deriveClassification( m_classifier, tmpYuv.get(COMPONENT_Y), blk, blk, cs, filterSetIndex < NUM_FIXED_FILTER_SETS ? filterSetIndex : -1, filterSetIndex < NUM_FIXED_FILTER_SETS ? -1 : m_classifierIdxApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][m_ctuAlternative[COMPONENT_Y][ctuIdx]] ); +#else deriveClassification( m_classifier, tmpYuv.get( COMPONENT_Y ), blk, blk #if ALF_IMPROVEMENT , cs, filterSetIndex < NUM_FIXED_FILTER_SETS ? filterSetIndex : -1 #endif - ); + ); +#endif short *coeff; #if JVET_R0351_HIGH_BIT_DEPTH_SUPPORT Pel *clip; @@ -651,7 +679,12 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; AlfFilterType filterTypeCtb = m_filterTypeApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierIdxApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; + alfFiltering( m_classifier[classifierIdx], recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx ); +#else alfFiltering( m_classifier, recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx ); +#endif } #else if( filterSetIndex >= NUM_FIXED_FILTER_SETS ) @@ -680,7 +713,11 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx]; #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + alfFiltering( m_classifier[0], recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma , nullptr, -1 ); +#else alfFiltering( m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma , nullptr, -1 ); +#endif #else m_filter5x5Blk( m_classifier, recYuv, tmpYuv, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight, m_alfVBChmaPos ); #endif @@ -727,6 +764,9 @@ void AdaptiveLoopFilter::reconstructCoeffAPSs(CodingStructure& cs, bool luma, bo reconstructCoeff(alfParamTmp, CHANNEL_TYPE_LUMA, isRdo, true); memcpy(m_coeffApsLuma[i], m_coeffFinal, sizeof(m_coeffFinal)); memcpy(m_clippApsLuma[i], m_clippFinal, sizeof(m_clippFinal)); +#if JVET_X0071_ALF_BAND_CLASSIFIER + memcpy(m_classifierIdxApsLuma[i], m_classifierFinal, sizeof(m_classifierFinal)); +#endif #if ALF_IMPROVEMENT m_filterTypeApsLuma[i] = alfParamTmp.filterType[CHANNEL_TYPE_LUMA]; m_numLumaAltAps[i] = alfParamTmp.numAlternativesLuma; @@ -808,6 +848,9 @@ void AdaptiveLoopFilter::reconstructCoeff( AlfParam& alfParam, ChannelType chann m_chromaClippFinal[altIdx][numCoeffMinus1] = isRdo ? 0 : m_alfClippingValues[channel][0]; continue; } +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_classifierFinal[altIdx] = alfParam.lumaClassifierIdx[altIdx]; +#endif for( int classIdx = 0; classIdx < numClasses; classIdx++ ) { #if ALF_IMPROVEMENT @@ -965,6 +1008,21 @@ void AdaptiveLoopFilter::create(const int picWidth, const int picHeight, const C #endif // Classification +#if JVET_X0071_ALF_BAND_CLASSIFIER + for( int classifier = 0; classifier < ALF_NUM_CLASSIFIER; classifier++ ) + { + if( m_classifier[classifier] == nullptr ) + { + m_classifier[classifier] = new AlfClassifier*[picHeight]; + m_classifier[classifier][0] = new AlfClassifier[picWidth * picHeight]; + + for( int i = 1; i < picHeight; i++ ) + { + m_classifier[classifier][i] = m_classifier[classifier][0] + i * picWidth; + } + } + } +#else if ( m_classifier == nullptr ) { m_classifier = new AlfClassifier*[picHeight]; @@ -975,6 +1033,7 @@ void AdaptiveLoopFilter::create(const int picWidth, const int picHeight, const C m_classifier[i] = m_classifier[0] + i * picWidth; } } +#endif #if !ALF_IMPROVEMENT for (int filterSetIndex = 0; filterSetIndex < NUM_FIXED_FILTER_SETS; filterSetIndex++) { @@ -1006,12 +1065,24 @@ void AdaptiveLoopFilter::destroy() return; } +#if JVET_X0071_ALF_BAND_CLASSIFIER + for (int classifier = 0; classifier < ALF_NUM_CLASSIFIER; classifier++) + { + if (m_classifier[classifier]) + { + delete[] m_classifier[classifier][0]; + delete[] m_classifier[classifier]; + m_classifier[classifier] = nullptr; + } + } +#else if( m_classifier ) { delete[] m_classifier[0]; delete[] m_classifier; m_classifier = nullptr; } +#endif #if ALF_IMPROVEMENT if( m_fixFilterResult ) @@ -1113,11 +1184,15 @@ void AdaptiveLoopFilter::alfFiltering( AlfClassifier **classifier, const PelUni } #endif +#if JVET_X0071_ALF_BAND_CLASSIFIER +void AdaptiveLoopFilter::deriveClassification( AlfClassifier*** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk, CodingStructure &cs, const int classifierIdx, const int multipleClassifierIdx ) +#else void AdaptiveLoopFilter::deriveClassification( AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk #if ALF_IMPROVEMENT , CodingStructure &cs, const int classifierIdx #endif ) +#endif { #if ALF_IMPROVEMENT if( cs.slice->getCuQpDeltaSubdiv() ) @@ -1125,7 +1200,11 @@ void AdaptiveLoopFilter::deriveClassification( AlfClassifier** classifier, const UnitArea curArea( cs.area.chromaFormat, blkDst ); for( auto &currCU : cs.traverseCUs( curArea, CH_L ) ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + deriveClassificationAndFixFilterResultsBlk( classifier, m_fixFilterResult, srcLuma, Area(currCU.lumaPos().x, currCU.lumaPos().y, currCU.lwidth(), currCU.lheight()), Area(currCU.lumaPos().x, currCU.lumaPos().y, currCU.lwidth(), currCU.lheight()), m_inputBitDepth[CHANNEL_TYPE_LUMA], cs, m_clpRngs.comp[COMPONENT_Y], m_alfClippingValues[CHANNEL_TYPE_LUMA], currCU.qp, cs.slice->getTileGroupAlfFixedFilterSetIdx(), m_mappingDir, m_laplacian, classifierIdx, multipleClassifierIdx ); +#else deriveClassificationAndFixFilterResultsBlk( classifier, m_fixFilterResult, srcLuma, Area(currCU.lumaPos().x, currCU.lumaPos().y, currCU.lwidth(), currCU.lheight()), Area(currCU.lumaPos().x, currCU.lumaPos().y, currCU.lwidth(), currCU.lheight()), m_inputBitDepth[CHANNEL_TYPE_LUMA], cs, m_clpRngs.comp[COMPONENT_Y], m_alfClippingValues[CHANNEL_TYPE_LUMA], currCU.qp, cs.slice->getTileGroupAlfFixedFilterSetIdx(), m_mappingDir, m_laplacian, classifierIdx ); +#endif } } else @@ -1139,7 +1218,11 @@ void AdaptiveLoopFilter::deriveClassification( AlfClassifier** classifier, const for( int j = blk.pos().x; j < width; j += m_CLASSIFICATION_BLK_SIZE ) { int nWidth = std::min( j + m_CLASSIFICATION_BLK_SIZE, width ) - j; +#if JVET_X0071_ALF_BAND_CLASSIFIER + deriveClassificationAndFixFilterResultsBlk(classifier, m_fixFilterResult, srcLuma, Area(j - blk.pos().x + blkDst.pos().x, i - blk.pos().y + blkDst.pos().y, nWidth, nHeight), Area(j, i, nWidth, nHeight), m_inputBitDepth[CHANNEL_TYPE_LUMA], cs, m_clpRngs.comp[COMPONENT_Y], m_alfClippingValues[CHANNEL_TYPE_LUMA], cs.slice->getSliceQp(), cs.slice->getTileGroupAlfFixedFilterSetIdx(), m_mappingDir, m_laplacian, classifierIdx, multipleClassifierIdx ); +#else deriveClassificationAndFixFilterResultsBlk( classifier, m_fixFilterResult, srcLuma, Area(j - blk.pos().x + blkDst.pos().x, i - blk.pos().y + blkDst.pos().y, nWidth, nHeight), Area(j, i, nWidth, nHeight), m_inputBitDepth[CHANNEL_TYPE_LUMA], cs, m_clpRngs.comp[COMPONENT_Y], m_alfClippingValues[CHANNEL_TYPE_LUMA], cs.slice->getSliceQp(), cs.slice->getTileGroupAlfFixedFilterSetIdx(), m_mappingDir, m_laplacian, classifierIdx ); +#endif } } } @@ -1160,6 +1243,37 @@ void AdaptiveLoopFilter::deriveClassification( AlfClassifier** classifier, const #endif } +#if JVET_X0071_ALF_BAND_CLASSIFIER +void AdaptiveLoopFilter::calcClassNew( AlfClassifier **classifier, const Area &blkDst, const Area &curBlk, const CPelBuf& srcLuma, int subBlkSize, AlfClassifier **classifier0, int classifierIdx, int bitDepth ) +{ + const Pel* src = srcLuma.buf; + int stride = srcLuma.stride; + int yOffset = blkDst.pos().y * stride; + const Pel *src0 = &src[yOffset]; + const Pel *src1 = &src[yOffset + stride]; + int stride2 = 2 * stride; + for (int i = 0; i < blkDst.height; i += subBlkSize) + { + for (int j = 0; j < blkDst.width; j += subBlkSize) + { + int xOffset = blkDst.pos().x + j; + const Pel *pY0 = src0 + xOffset; + const Pel *pY1 = src1 + xOffset; + int sum = pY0[0] + pY0[1] + pY1[0] + pY1[1]; + int classIdx = (sum * ALF_NUM_CLASSES_CLASSIFIER[classifierIdx]) >> (bitDepth + 2); + for (int ii = curBlk.y + i; ii < curBlk.y + i + subBlkSize; ii++) + { + for (int jj = curBlk.x + j; jj < curBlk.x + j + subBlkSize; jj++) + { + classifier[ii][jj] = classIdx << 2; + } + } + } + src0 += stride2; + src1 += stride2; + } +} +#endif #if ALF_IMPROVEMENT int AdaptiveLoopFilter::assignAct( int avg_varPrec, int shift, int noAct ) { @@ -1255,7 +1369,11 @@ void AdaptiveLoopFilter::calcClass(AlfClassifier **classifier, const Area &blkDs if (noAct == 5) { const int th[] = { 0, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4 }; +#if JVET_X0071_ALF_BAND_CLASSIFIER + activity = th[std::min((mult * 3 * sum) >> shift, 15)]; +#else activity = th[std::min((mult * sum) >> shift, 15)]; +#endif } else { @@ -1592,7 +1710,11 @@ void AdaptiveLoopFilter::deriveClassificationLaplacian(const CPelBuf &srcLuma, c } } +#if JVET_X0071_ALF_BAND_CLASSIFIER +void AdaptiveLoopFilter::deriveClassificationAndFixFilterResultsBlk( AlfClassifier ***classifier, Pel ***fixedFilterResults, const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, const int bits, CodingStructure& cs, const ClpRng &clpRng, const Pel clippingValues[4], int qp, int fixedFilterSetIdx, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS], const int classifierIdx, const int multipleClassifierIdx ) +#else void AdaptiveLoopFilter::deriveClassificationAndFixFilterResultsBlk( AlfClassifier **classifier, Pel ***fixedFilterResults, const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, const int bits, CodingStructure& cs, const ClpRng &clpRng, const Pel clippingValues[4], int qp, int fixedFilterSetIdx, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS], const int classifierIdx ) +#endif { m_deriveClassificationLaplacian(srcLuma, blkDst, blk, laplacian); @@ -1628,12 +1750,20 @@ void AdaptiveLoopFilter::deriveClassificationAndFixFilterResultsBlk( AlfClassifi { m_deriveClassificationLaplacianBig(blkDst, laplacian); } +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_calcClass0(classifier[0], blkDst, blkDst, usedWindowIdx[dirWindSize], 1, NUM_DIR_FIX, NUM_ACT_FIX, bits, 2, mappingDir, laplacian); +#else m_calcClass0(classifier, blkDst, blkDst, usedWindowIdx[dirWindSize], 1, NUM_DIR_FIX, NUM_ACT_FIX, bits, 2, mappingDir, laplacian); +#endif reuse = true; } //fixed filtering +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_filter13x13Blk(classifier[0], srcLuma, blkDst, fixedFilterResults, m_picWidth, fixedFiltInd, m_classIdnFixedFilter[fixedFiltSetInd][dirWindSize], fixedFiltSetInd, dirWindSize, clpRng, clippingValues); +#else m_filter13x13Blk(classifier, srcLuma, blkDst, fixedFilterResults, m_picWidth, fixedFiltInd, m_classIdnFixedFilter[fixedFiltSetInd][dirWindSize], fixedFiltSetInd, dirWindSize, clpRng, clippingValues); +#endif } } fixedFiltInd++; @@ -1641,7 +1771,21 @@ void AdaptiveLoopFilter::deriveClassificationAndFixFilterResultsBlk( AlfClassifi } if( classifierIdx == -1 ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + if( multipleClassifierIdx == ALF_NUM_CLASSIFIER || multipleClassifierIdx == 0 || multipleClassifierIdx == 1 ) + { + m_calcClass1( classifier[0], blkDst, Area(blkDst.pos().x, blkDst.pos().y, blkDst.width, blkDst.height), 5, 0, 5, 5, bits, 2, mappingDir, laplacian ); + } + for( int curClassifierIdx = 1; curClassifierIdx < ALF_NUM_CLASSIFIER; curClassifierIdx++ ) + { + if( multipleClassifierIdx == ALF_NUM_CLASSIFIER || curClassifierIdx == multipleClassifierIdx ) + { + m_calcClass2( classifier[curClassifierIdx], blkDst, Area(blkDst.pos().x, blkDst.pos().y, blkDst.width, blkDst.height), srcLuma, 2, classifier[0], curClassifierIdx, bits); + } + } +#else m_calcClass1( classifier, blkDst, Area(blkDst.pos().x, blkDst.pos().y, blkDst.width, blkDst.height), 5, 0, 5, 5, bits, 2, mappingDir, laplacian ); +#endif } } #else @@ -2265,6 +2409,14 @@ void AdaptiveLoopFilter::filterBlkCcAlf(const PelBuf &dstBuf, const CPelUnitBuf int offset1 = lumaStride; int offset2 = -lumaStride; int offset3 = 2 * lumaStride; +#if JVET_X0071_LONGER_CCALF + int offset4 = -2 * lumaStride; + int offset5 = 3 * lumaStride; + int offset6 = -3 * lumaStride; + int offset7 = 4 * lumaStride; + int offset8 = -4 * lumaStride; +#endif + row <<= scaleY; col <<= scaleX; const Pel *srcCross = lumaPtr + col + row * lumaStride; @@ -2294,6 +2446,36 @@ void AdaptiveLoopFilter::filterBlkCcAlf(const PelBuf &dstBuf, const CPelUnitBuf int sum = 0; const Pel currSrcCross = srcCross[offset0 + jj2]; + +#if JVET_X0071_LONGER_CCALF + sum += filterCoeff[0] * (srcCross[offset8 + jj2] - currSrcCross); + sum += filterCoeff[1] * (srcCross[offset6 + jj2] - currSrcCross); + sum += filterCoeff[2] * (srcCross[offset4 + jj2] - currSrcCross); + sum += filterCoeff[3] * (srcCross[offset2 + jj2] - currSrcCross); + + sum += filterCoeff[4] * (srcCross[offset0 + jj2 - 4] - currSrcCross); + sum += filterCoeff[5] * (srcCross[offset0 + jj2 - 3] - currSrcCross); + sum += filterCoeff[6] * (srcCross[offset0 + jj2 - 2] - currSrcCross); + sum += filterCoeff[7] * (srcCross[offset0 + jj2 - 1] - currSrcCross); + sum += filterCoeff[8] * (srcCross[offset0 + jj2 + 1] - currSrcCross); + sum += filterCoeff[9] * (srcCross[offset0 + jj2 + 2] - currSrcCross); + sum += filterCoeff[10] * (srcCross[offset0 + jj2 + 3] - currSrcCross); + sum += filterCoeff[11] * (srcCross[offset0 + jj2 + 4] - currSrcCross); + + sum += filterCoeff[12] * (srcCross[offset1 + jj2 - 4] - currSrcCross); + sum += filterCoeff[13] * (srcCross[offset1 + jj2 - 3] - currSrcCross); + sum += filterCoeff[14] * (srcCross[offset1 + jj2 - 2] - currSrcCross); + sum += filterCoeff[15] * (srcCross[offset1 + jj2 - 1] - currSrcCross); + sum += filterCoeff[16] * (srcCross[offset1 + jj2 - 0] - currSrcCross); + sum += filterCoeff[17] * (srcCross[offset1 + jj2 + 1] - currSrcCross); + sum += filterCoeff[18] * (srcCross[offset1 + jj2 + 2] - currSrcCross); + sum += filterCoeff[19] * (srcCross[offset1 + jj2 + 3] - currSrcCross); + sum += filterCoeff[20] * (srcCross[offset1 + jj2 + 4] - currSrcCross); + + sum += filterCoeff[21] * (srcCross[offset3 + jj2] - currSrcCross); + sum += filterCoeff[22] * (srcCross[offset5 + jj2] - currSrcCross); + sum += filterCoeff[23] * (srcCross[offset7 + jj2] - currSrcCross); +#else sum += filterCoeff[0] * (srcCross[offset2 + jj2 ] - currSrcCross); sum += filterCoeff[1] * (srcCross[offset0 + jj2 - 1] - currSrcCross); sum += filterCoeff[2] * (srcCross[offset0 + jj2 + 1] - currSrcCross); @@ -2301,7 +2483,7 @@ void AdaptiveLoopFilter::filterBlkCcAlf(const PelBuf &dstBuf, const CPelUnitBuf sum += filterCoeff[4] * (srcCross[offset1 + jj2 ] - currSrcCross); sum += filterCoeff[5] * (srcCross[offset1 + jj2 + 1] - currSrcCross); sum += filterCoeff[6] * (srcCross[offset3 + jj2 ] - currSrcCross); - +#endif sum = (sum + ((1 << m_scaleBits ) >> 1)) >> m_scaleBits; const int offset = 1 << clpRngs.comp[compId].bd >> 1; sum = ClipPel(sum + offset, clpRngs.comp[compId]) - offset; diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.h b/source/Lib/CommonLib/AdaptiveLoopFilter.h index bdcf249ce3c5911589a3af4ff48f4c7132633422..d20285652010f29261f72c605471273cc3de4315 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.h +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.h @@ -120,20 +120,12 @@ public: static void calcClass(AlfClassifier **classifier, const Area &blkDst, const Area &cu, int dirWindSize, int classDir, int noDir, int noAct, int bitDepth, int subBlkSize, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS]); static void deriveClassificationLaplacianBig(const Area &curBlk, uint32_t **laplacian[NUM_DIRECTIONS]); static void deriveClassificationLaplacian(const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, uint32_t **laplacian[NUM_DIRECTIONS]); - void deriveClassificationAndFixFilterResultsBlk( - AlfClassifier **classifier, - Pel ***fixedFilterResults, - const CPelBuf &srcLuma, - const Area &blkDst, - const Area &blk, - const int bits, - CodingStructure& cs, - const ClpRng &clpRng, - const Pel clippingValues[4], - int qp, int qpIdx, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], - uint32_t **laplacian[NUM_DIRECTIONS], - const int classifierIdx - ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + void deriveClassificationAndFixFilterResultsBlk( AlfClassifier ***classifier, Pel ***fixedFilterResults, const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, const int bits, CodingStructure& cs, const ClpRng &clpRng, const Pel clippingValues[4], int qp, int qpIdx, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS], const int classifierIdx, const int multipleClassifierIdx ); + static void calcClassNew( AlfClassifier **classifier, const Area &blkDst, const Area &cu, const CPelBuf& srcLuma, int subBlkSize, AlfClassifier **classifier0, int classifierIdx, int bitDepth ); +#else + void deriveClassificationAndFixFilterResultsBlk( AlfClassifier **classifier, Pel ***fixedFilterResults, const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, const int bits, CodingStructure& cs, const ClpRng &clpRng, const Pel clippingValues[4], int qp, int qpIdx, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS], const int classifierIdx ); +#endif template<AlfFilterType filtTypeCcAlf> static void filterBlkCcAlf(const PelBuf& dstBuf, const CPelUnitBuf& recSrc, const Area& blkDst, const Area& blkSrc, const ComponentID compId, const int16_t* filterCoeff, const ClpRngs& clpRngs, CodingStructure& cs); #else @@ -141,15 +133,22 @@ public: template<AlfFilterType filtTypeCcAlf> static void filterBlkCcAlf(const PelBuf &dstBuf, const CPelUnitBuf &recSrc, const Area &blkDst, const Area &blkSrc, const ComponentID compId, const int16_t *filterCoeff, const ClpRngs &clpRngs, CodingStructure &cs, int vbCTUHeight, int vbPos); #endif +#if JVET_X0071_ALF_BAND_CLASSIFIER + void deriveClassification( AlfClassifier*** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk, CodingStructure &cs, const int classifierIdx, const int multipleClassifierIdx ); +#else void deriveClassification( AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk #if ALF_IMPROVEMENT , CodingStructure &cs, const int classifierIdx #endif ); +#endif #if ALF_IMPROVEMENT void(*m_calcClass0)(AlfClassifier **classifier, const Area &blkDst, const Area &cu, int dirWindSize, int classDir, int noDir, int noAct, int bitDepth, int subBlkSize, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS]); void(*m_calcClass1)(AlfClassifier **classifier, const Area &blkDst, const Area &cu, int dirWindSize, int classDir, int noDir, int noAct, int bitDepth, int subBlkSize, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS]); +#if JVET_X0071_ALF_BAND_CLASSIFIER + void(*m_calcClass2)(AlfClassifier **classifier, const Area &blkDst, const Area &cu, const CPelBuf& srcLuma, int subBlkSize, AlfClassifier **classifier0, int classifierIdx, int bitDepth); +#endif void(*m_deriveClassificationLaplacianBig)(const Area &curBlk, uint32_t **laplacian[NUM_DIRECTIONS]); void(*m_deriveClassificationLaplacian)(const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, uint32_t **laplacian[NUM_DIRECTIONS]); void(*m_filter13x13Blk)(AlfClassifier **classifier, const CPelBuf &srcLuma, const Area& curBlk, Pel ***fixedFilterResults, int picWidth, const int fixedFiltInd, const short classIndFixed[NUM_CLASSES_FIX], int fixedFiltQpInd, int dirWindSize, const ClpRng &clpRng, const Pel clippingValues[4]); @@ -235,7 +234,13 @@ protected: bool m_filterTypeTest[MAX_NUM_CHANNEL_TYPE][ALF_NUM_OF_FILTER_TYPES]; int m_filterTypeToStatIndex[MAX_NUM_CHANNEL_TYPE][ALF_NUM_OF_FILTER_TYPES]; #endif +#if JVET_X0071_ALF_BAND_CLASSIFIER + AlfClassifier** m_classifier[ALF_NUM_CLASSIFIER]; + char m_classifierIdxApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_ALTERNATIVES_LUMA]; + char m_classifierFinal[MAX_NUM_ALF_ALTERNATIVES_LUMA]; +#else AlfClassifier** m_classifier; +#endif #if ALF_IMPROVEMENT int m_numLumaAltAps[ALF_CTB_MAX_NUM_APS]; short m_coeffApsLuma[ALF_CTB_MAX_NUM_APS][MAX_NUM_ALF_ALTERNATIVES_LUMA][MAX_NUM_ALF_LUMA_COEFF * MAX_NUM_ALF_CLASSES]; diff --git a/source/Lib/CommonLib/AlfParameters.h b/source/Lib/CommonLib/AlfParameters.h index 883a31cabcae6770d6311ef4c67b3908638149e1..a45533c2b4085d974c9804676383a95cf1c0599b 100644 --- a/source/Lib/CommonLib/AlfParameters.h +++ b/source/Lib/CommonLib/AlfParameters.h @@ -195,9 +195,15 @@ struct AlfFilterShape else if( size == size_CC_ALF ) { size = 4; +#if JVET_X0071_LONGER_CCALF + filterLength = MAX_NUM_CC_ALF_CHROMA_COEFF; + numCoeff = MAX_NUM_CC_ALF_CHROMA_COEFF; + filterSize = MAX_NUM_CC_ALF_CHROMA_COEFF; +#else filterLength = 8; numCoeff = 8; filterSize = 8; +#endif filterType = CC_ALF; } else @@ -224,6 +230,9 @@ struct AlfParam { bool enabledFlag[MAX_NUM_COMPONENT]; // alf_slice_enable_flag, alf_chroma_idc #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + char lumaClassifierIdx[MAX_NUM_ALF_ALTERNATIVES_LUMA]; +#endif AlfFilterType filterType[MAX_NUM_CHANNEL_TYPE]; bool nonLinearFlag[MAX_NUM_CHANNEL_TYPE][32]; // alf_[luma/chroma]_clip_flag int numAlternativesLuma; @@ -267,6 +276,9 @@ struct AlfParam { std::memset( enabledFlag, false, sizeof( enabledFlag ) ); std::memset( nonLinearFlag, false, sizeof( nonLinearFlag ) ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + std::memset( lumaClassifierIdx, 0, sizeof( lumaClassifierIdx ) ); +#endif std::memset( lumaCoeff, 0, sizeof( lumaCoeff ) ); std::memset( lumaClipp, 0, sizeof( lumaClipp ) ); numAlternativesChroma = 1; @@ -292,6 +304,9 @@ struct AlfParam { std::memcpy( enabledFlag, src.enabledFlag, sizeof( enabledFlag ) ); std::memcpy( nonLinearFlag, src.nonLinearFlag, sizeof( nonLinearFlag ) ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + std::memcpy( lumaClassifierIdx, src.lumaClassifierIdx, sizeof( lumaClassifierIdx ) ); +#endif std::memcpy( lumaCoeff, src.lumaCoeff, sizeof( lumaCoeff ) ); std::memcpy( lumaClipp, src.lumaClipp, sizeof( lumaClipp ) ); numAlternativesChroma = src.numAlternativesChroma; @@ -327,6 +342,12 @@ struct AlfParam { return false; } +#if JVET_X0071_ALF_BAND_CLASSIFIER + if( memcmp( lumaClassifierIdx, other.lumaClassifierIdx, sizeof( lumaClassifierIdx ) ) ) + { + return false; + } +#endif #endif if( memcmp( lumaCoeff, other.lumaCoeff, sizeof( lumaCoeff ) ) ) { diff --git a/source/Lib/CommonLib/BilateralFilter.cpp b/source/Lib/CommonLib/BilateralFilter.cpp index 43f1268e10cca9e6ce8e851cbbce31b712d79e04..f36751c882e56124238b0ed118e94488b81b6d26 100755 --- a/source/Lib/CommonLib/BilateralFilter.cpp +++ b/source/Lib/CommonLib/BilateralFilter.cpp @@ -32,12 +32,12 @@ */ #include "BilateralFilter.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "Unit.h" #include "UnitTools.h" #endif -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include <tmmintrin.h> #include <smmintrin.h> #include <immintrin.h> @@ -55,7 +55,7 @@ BilateralFilter::BilateralFilter() m_bilateralFilterDiamond5x5NoClip = blockBilateralFilterDiamond5x5NoClip; #endif -#if ENABLE_SIMD_BILATERAL_FILTER +#if ENABLE_SIMD_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER_ENABLE_SIMD #ifdef TARGET_SIMD_X86 initBilateralFilterX86(); #endif @@ -73,7 +73,7 @@ void BilateralFilter::create() void BilateralFilter::destroy() { } - +#if JVET_V0094_BILATERAL_FILTER const char* BilateralFilter::getFilterLutParameters( const int size, const PredMode predMode, const int32_t qp, int& bfac ) { if( size <= 4 ) @@ -119,7 +119,7 @@ const char* BilateralFilter::getFilterLutParameters( const int size, const PredM return m_wBIF[sqp - 17]; } - +#endif #if JVET_W0066_CCSAO void BilateralFilter::blockBilateralFilterDiamond5x5NoClip(uint32_t uiWidth, uint32_t uiHeight, int16_t block[], int16_t blkFilt[], const ClpRng& clpRng, Pel* recPtr, int recStride, int iWidthExtSIMD, int bfac, int bif_round_add, int bif_round_shift, bool isRDO, const char* LUTrowPtr) { @@ -587,7 +587,7 @@ void BilateralFilter::blockBilateralFilterDiamond5x5( uint32_t uiWidth, uint32_t } } } - +#if JVET_V0094_BILATERAL_FILTER void BilateralFilter::bilateralFilterRDOdiamond5x5(PelBuf& resiBuf, const CPelBuf& predBuf, PelBuf& recoBuf, int32_t qp, const CPelBuf& recIPredBuf, const ClpRng& clpRng, TransformUnit & currTU, bool useReco, bool doReshape, std::vector<Pel>& pLUT) { const unsigned uiWidth = predBuf.width; @@ -796,8 +796,8 @@ void BilateralFilter::bilateralFilterRDOdiamond5x5(PelBuf& resiBuf, const CPelBu } } } - -#if JVET_W0066_CCSAO +#endif +#if JVET_W0066_CCSAO && JVET_V0094_BILATERAL_FILTER void BilateralFilter::bilateralFilterDiamond5x5NoClip(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit& currTU) { CompArea& compArea = currTU.block(COMPONENT_Y); @@ -1031,7 +1031,7 @@ void BilateralFilter::bilateralFilterDiamond5x5NoClip(const CPelUnitBuf& src, Pe m_bilateralFilterDiamond5x5NoClip(uiWidth, uiHeight, tempblock, tempblockFiltered, clpRng, recPtr, recStride, iWidthExtSIMD, bfac, bif_round_add, bif_round_shift, false, LUTrowPtr); } #endif - +#if JVET_V0094_BILATERAL_FILTER void BilateralFilter::bilateralFilterDiamond5x5(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit & currTU) { CompArea &compArea = currTU.block(COMPONENT_Y); @@ -1264,7 +1264,7 @@ void BilateralFilter::bilateralFilterDiamond5x5(const CPelUnitBuf& src, PelUnitB m_bilateralFilterDiamond5x5(uiWidth, uiHeight, tempblock, tempblockFiltered, clpRng, recPtr, recStride, iWidthExtSIMD, bfac, bif_round_add, bif_round_shift, false, LUTrowPtr ); } - +#endif void BilateralFilter::clipNotBilaterallyFilteredBlocks(const CPelUnitBuf& src, PelUnitBuf& rec, const ClpRng& clpRng, TransformUnit & currTU) { PelUnitBuf myRecBuf = currTU.cs->getRecoBuf(currTU); @@ -1335,7 +1335,7 @@ void copyBack(PelBuf &srcBuf, PelBuf &dstBuf) dstPtr += dstStride-srcBuf.width; } } - +#if JVET_V0094_BILATERAL_FILTER void BilateralFilter::bilateralFilterPicRDOperCTU(CodingStructure& cs, PelUnitBuf& src, BIFCabacEst* BifCABACEstimator) { // We must have already copied recobuf into src before running this @@ -1454,7 +1454,28 @@ void BilateralFilter::bilateralFilterPicRDOperCTU(CodingStructure& cs, PelUnitBu // If no CTUs should be BIF-filtered, we need to restore all CTUs. // Note that this test must be done last since it is destroying all // of our filtered data. +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + for (int y = 0; y < pcv.heightInCtus; y++) + { + for (int x = 0; x < pcv.widthInCtus; x++) + { + UnitArea ctuArea(pcv.chrFormat, Area(x << pcv.maxCUWidthLog2, y << pcv.maxCUHeightLog2, pcv.maxCUWidth, pcv.maxCUWidth)); + ctuArea = clipArea(ctuArea, *cs.slice->getPic()); + PelBuf piRec = rec.subBuf(ctuArea).Y(); + PelBuf piSrc = src.subBuf(ctuArea).Y(); + copyBack(piSrc, piRec); // Copy unfiltered samples back to rec + } + } + } + else + { + rec.copyFrom(src); + } +#else rec.copyFrom(src); +#endif } if( bifParams.frmOn == 0 ) @@ -1466,5 +1487,1037 @@ void BilateralFilter::bilateralFilterPicRDOperCTU(CodingStructure& cs, PelUnitBu std::fill( bifParams.ctuOn.begin(), bifParams.ctuOn.end(), 1 ); } } +#endif + +#if JVET_X0071_CHROMA_BILATERAL_FILTER +void BilateralFilter::bilateralFilterRDOdiamond5x5_chroma(PelBuf& resiBuf, const CPelBuf& predBuf, PelBuf& recoBuf, int32_t qp, const CPelBuf& recIPredBuf, const ClpRng& clpRng, TransformUnit & currTU, bool useReco, bool isCb) +{ + const unsigned uiWidth = predBuf.width; + const unsigned uiHeight = predBuf.height; + + int bfac = 1; + int bif_round_add = (BIF_ROUND_ADD) >> (currTU.cs->pps->getCBIFStrength()); + int bif_round_shift = ( BIF_ROUND_SHIFT ) -(currTU.cs->pps->getCBIFStrength()); + + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + int width_for_strength = currTU.blocks[compID].width; + int height_for_strength = currTU.blocks[compID].height; + + if(currTU.blocks[COMPONENT_Y].valid()) + { + width_for_strength = currTU.blocks[COMPONENT_Y].width; + height_for_strength = currTU.blocks[COMPONENT_Y].height; + } + + const char* LUTrowPtr = getFilterLutParameters_chroma( std::min( uiWidth, uiHeight ), currTU.cu->predMode, qp + currTU.cs->pps->getCBIFQPOffset(), bfac, width_for_strength, height_for_strength, currTU.blocks[COMPONENT_Y].valid()); + + const unsigned uiPredStride = predBuf.stride; + const unsigned uiStrideRes = resiBuf.stride; + const unsigned uiRecStride = recoBuf.stride; + const Pel *piPred = predBuf.buf; + Pel *piResi = resiBuf.buf; + Pel *piReco = recoBuf.buf; + + const Pel *piPredTemp = piPred; + Pel *piResiTemp = piResi; + Pel *piRecoTemp = piReco; + // Reco = Pred + Resi + + Pel *tempBlockPtr; + + uint32_t uiWidthExt = uiWidth + (NUMBER_PADDED_SAMPLES << 1); + uint32_t uiHeightExt = uiHeight + (NUMBER_PADDED_SAMPLES << 1); + + int iWidthExtSIMD = uiWidthExt; + if( uiWidth < 8 ) + { + iWidthExtSIMD = 8 + (NUMBER_PADDED_SAMPLES << 1); + } + + memset(tempblock, 0, iWidthExtSIMD*uiHeightExt * sizeof(short)); + tempBlockPtr = tempblock + (NUMBER_PADDED_SAMPLES)* iWidthExtSIMD + NUMBER_PADDED_SAMPLES; + + // Clip and move block to temporary block + if (useReco) + { + for (uint32_t uiY = 0; uiY < uiHeight; ++uiY) + { + std::memcpy(tempBlockPtr, piReco, uiWidth * sizeof(Pel)); + piReco += uiRecStride; + tempBlockPtr += iWidthExtSIMD; + } + piReco = piRecoTemp; + } + else + { + for (uint32_t uiY = 0; uiY < uiHeight; ++uiY) + { + for (uint32_t uiX = 0; uiX < uiWidth; ++uiX) + { + tempBlockPtr[uiX] = ClipPel(piPred[uiX] + piResi[uiX], clpRng); + } + piPred += uiPredStride; + piResi += uiStrideRes; + piReco += uiRecStride; + tempBlockPtr += iWidthExtSIMD; + } + } + + piPred = piPredTemp; + piResi = piResiTemp; + piReco = piRecoTemp; + + //USE chroma info to decided + const unsigned uiRecIPredStride = recIPredBuf.stride; + const Pel *piRecIPred = recIPredBuf.buf; + + for (int yy = 1; yy< uiHeightExt -1 ; yy++) + { + tempblock[yy*iWidthExtSIMD + 1] = tempblock[yy*iWidthExtSIMD + 2]; + tempblock[yy*iWidthExtSIMD + uiWidthExt - 2] = tempblock[yy*iWidthExtSIMD + uiWidthExt - 3]; + } + for (int xx = 1; xx< uiWidthExt - 1; xx++) + { + tempblock[1 * iWidthExtSIMD + xx] = tempblock[2 * iWidthExtSIMD + xx]; + tempblock[(uiHeightExt - 2)*iWidthExtSIMD + xx] = tempblock[(uiHeightExt - 3)*iWidthExtSIMD + xx]; + } + + bool subTuVer = currTU.chromaPos().x > currTU.cu->chromaPos().x ? true : false; + bool subTuHor = currTU.chromaPos().y > currTU.cu->chromaPos().y ? true : false; + + uint32_t CTUsize_chroma = currTU.cs->slice->getSPS()->getCTUSize() >> 1; + + bool isCTUboundary = currTU.chromaPos().y % CTUsize_chroma == 0; + + bool topAvailable = (currTU.chromaPos().y - 2 >= 0) && (currTU.chromaPos().y == currTU.cu->chromaPos().y); + + topAvailable &= !isCTUboundary; + + bool leftAvailable = (currTU.chromaPos().x - 2 >= 0) && (currTU.chromaPos().x == currTU.cu->chromaPos().x); + + //if not 420, then don't use rec for padding + if(currTU.cu->chromaFormat != CHROMA_420){ + subTuHor = false; + subTuVer = false; + leftAvailable = false; + topAvailable = false; + } + + if(topAvailable || leftAvailable || subTuHor || subTuVer) + { + const CompArea &area = isCb ? currTU.blocks[COMPONENT_Cb] : currTU.blocks[COMPONENT_Cr]; + CodingStructure &cs = *currTU.cs; + + if (topAvailable && leftAvailable) + { + // top left pixels + tempblock[iWidthExtSIMD + 1] = *(piRecIPred - (uiRecIPredStride)-1); + } + // top row + if (topAvailable) + { + for (int blockx = 0; blockx < area.width; blockx += 1) + { + // copy 4 pixels one line above block from block to blockx + 3 + std::copy(piRecIPred - (uiRecIPredStride)+blockx, piRecIPred - (uiRecIPredStride)+blockx + 1, tempblock + 2 + iWidthExtSIMD + blockx); + } + } + else if (subTuHor) + { + const CompArea &prevHalfArea = isCb ? currTU.prev->blocks[COMPONENT_Cb] : currTU.prev->blocks[COMPONENT_Cr]; + CPelBuf earlierHalfBuf = cs.getPredBuf(prevHalfArea); + earlierHalfBuf = cs.getRecoBuf(prevHalfArea); + const unsigned earlierStride = earlierHalfBuf.stride; + const Pel *earlierPel = earlierHalfBuf.buf + (currTU.prev->chromaSize().height - 1)*earlierStride; + std::copy(earlierPel, earlierPel + area.width, tempblock + 2 + iWidthExtSIMD); + std::copy(earlierPel - earlierStride, earlierPel - earlierStride + area.width, tempblock + 2); + } + // left column + if (leftAvailable) + { + for (int blocky = 0; blocky < area.height; blocky += 1) + { + tempblock[(iWidthExtSIMD << 1) + (blocky + 0) * iWidthExtSIMD + 1] = *(piRecIPred + (blocky + 0)*uiRecIPredStride - 1); // 1 pel out + } + } + else if (subTuVer) + { + const CompArea &prevHalfArea = isCb ? currTU.prev->blocks[COMPONENT_Cb] : currTU.prev->blocks[COMPONENT_Cr]; + CPelBuf earlierHalfBuf = cs.getPredBuf(prevHalfArea); + earlierHalfBuf = cs.getRecoBuf(prevHalfArea); + const unsigned earlierStride = earlierHalfBuf.stride; + const Pel *earlierPel = earlierHalfBuf.buf + (currTU.prev->chromaSize().width - 1); // second to last pixel of first row of previous block + for (int yy = 0; yy < area.height; yy++) + { + tempblock[(iWidthExtSIMD << 1) + yy * iWidthExtSIMD + 1] = *(earlierPel + yy*earlierStride + 0); + } + } + } + + // Sloppy copying of outer layer + for(int yy = 0; yy < uiHeight+2; yy++) + { + tempblock[iWidthExtSIMD + yy*iWidthExtSIMD] = tempblock[iWidthExtSIMD + yy*iWidthExtSIMD + 1]; + tempblock[iWidthExtSIMD + uiWidthExt - 1 + yy*iWidthExtSIMD] = tempblock[iWidthExtSIMD + uiWidthExt - 2 + yy*iWidthExtSIMD]; + } + std::copy(tempblock + iWidthExtSIMD, tempblock + iWidthExtSIMD + uiWidthExt, tempblock); + std::copy(tempblock + iWidthExtSIMD*(uiHeightExt-2), tempblock + iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt, tempblock + iWidthExtSIMD*(uiHeightExt-1)); + + m_bilateralFilterDiamond5x5(uiWidth, uiHeight, tempblock, tempblockFiltered, clpRng, piReco, uiRecStride, iWidthExtSIMD, bfac, bif_round_add, bif_round_shift, true, LUTrowPtr ); + + if (!useReco) + { + // need to be performed if residual is used + // Resi' = Reco' - Pred + for (uint32_t uiY = 0; uiY < uiHeight; ++uiY) + { + for (uint32_t uiX = 0; uiX < uiWidth; ++uiX) + { + piResi[uiX] = piReco[uiX] - piPred[uiX]; + } + piPred += uiPredStride; + piResi += uiStrideRes; + piReco += uiRecStride; + } + } +} + + + + +void BilateralFilter::bilateralFilterPicRDOperCTU_chroma(CodingStructure& cs, PelUnitBuf& src, CBIFCabacEst* CBifCABACEstimator, bool isCb) +{ + + // We must have already copied recobuf into src before running this + // such as src.copyFrom(rec); + const PreCalcValues& pcv = *cs.pcv; + + PelUnitBuf rec = cs.getRecoBuf(); + + double frameMSEnoBIF = 0; + double frameMSEallBIF = 0; + double frameMSEswitchBIF = 0; + CBifParams& CBifParams = cs.picture->getCBifParam(); + int ctuIdx = 0; + + for (int y = 0; y < pcv.heightInCtus; y++) + { + for (int x = 0; x < pcv.widthInCtus; x++) + { + UnitArea ctuArea(pcv.chrFormat, Area(x << pcv.maxCUWidthLog2, y << pcv.maxCUHeightLog2, pcv.maxCUWidth, pcv.maxCUWidth)); + + ctuArea = clipArea(ctuArea, *cs.slice->getPic()); + PelBuf piOrg = isCb ? cs.getOrgBuf(ctuArea).Cb() : cs.getOrgBuf(ctuArea).Cr(); + PelBuf piSrc = isCb ? src.subBuf(ctuArea).Cb() : src.subBuf(ctuArea).Cr(); + + double MSEnoBIF = getDist(piSrc, piOrg); + + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, ctuArea, CType), CType)) + { + bool chroma_valid = isCb ? currCU.Cb().valid() : currCU.Cr().valid(); + if(!chroma_valid){ + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = isCb ? currTU.blocks[COMPONENT_Cb].valid() : currTU.blocks[COMPONENT_Cr].valid(); + TU_CBF = false; + + if(TU_VALID) + { + TU_CBF = (isCb ? TU::getCbf(currTU, COMPONENT_Cb) : TU::getCbf(currTU, COMPONENT_Cr)); + } + BIF_chroma = ((TU_CBF || isInter == false) && (currTU.cu->qp > 17) && (TU_VALID)); + } + else + { + TU_CBF = (isCb ? TU::getCbf(currTU, COMPONENT_Cb) : TU::getCbf(currTU, COMPONENT_Cr)); + BIF_chroma = (TU_CBF || isInter == false) && (currTU.cu->qp > 17); + } + if(BIF_chroma) + { + bilateralFilterDiamond5x5_chroma(src, rec, currTU.cu->qp, isCb ? cs.slice->clpRng(COMPONENT_Cb) : cs.slice->clpRng(COMPONENT_Cr), currTU, isCb); + } + } + } + PelBuf piRec = isCb ? rec.subBuf(ctuArea).Cb() : rec.subBuf(ctuArea).Cr(); + double MSEafterBIF = getDist(piRec, piOrg); + frameMSEnoBIF += MSEnoBIF; + frameMSEallBIF += MSEafterBIF; + if(MSEnoBIF<MSEafterBIF) + { + frameMSEswitchBIF += MSEnoBIF; + if(isCb){ + CBifParams.ctuOn_Cb[ctuIdx] = 0; + } + else{ + CBifParams.ctuOn_Cr[ctuIdx] = 0; + } + } + else + { + frameMSEswitchBIF += MSEafterBIF; + if(isCb){ + CBifParams.ctuOn_Cb[ctuIdx] = 1; + } + else{ + CBifParams.ctuOn_Cr[ctuIdx] = 1; + } + } + ctuIdx++; + } + } + + double lambda = cs.picture->slices[0]->getLambdas()[isCb ? 1 : 2]; + double costAllCTUsBIF = frameMSEallBIF + lambda * 1; // To turn everything on, only slice_bif_all_ctb_enabled_flag = 1, so one bit. + double costNoCTUsBIF = frameMSEnoBIF + lambda * 2; // To turn everything off, slice_bif_all_ctb_enabled = 0 && slice_bif_enabled_flag = 0, so two bits. + double costSwitchCTUsBIF; + // Does CABAC estimation instead + + const double FracBitsScale = 1.0 / double(1 << SCALE_BITS); + if(isCb) + { + CBifParams.frmOn_Cb = 1; + } + else + { + CBifParams.frmOn_Cr = 1; + } + if(isCb) + { + CBifParams.allCtuOn_Cb = 0; + } + else{ + CBifParams.allCtuOn_Cr = 0; + } + double ctuSwitchBits = isCb ? FracBitsScale*CBifCABACEstimator->getBits_Cb(*cs.slice, CBifParams) : FracBitsScale*CBifCABACEstimator->getBits_Cr(*cs.slice, CBifParams); + costSwitchCTUsBIF = frameMSEswitchBIF + lambda * ctuSwitchBits; + + double bestCost = MAX_DOUBLE; + if (costAllCTUsBIF < bestCost) + { + // If everything should be BIF-filtered, we do not need to change any of the samples, + // since they are already filtered. + bestCost = costAllCTUsBIF; + if(isCb) + { + CBifParams.frmOn_Cb = 1; + } + else + { + CBifParams.frmOn_Cr = 1; + } + if(isCb) + { + CBifParams.allCtuOn_Cb = 1; + } + else{ + CBifParams.allCtuOn_Cr = 1; + } + } + if (costSwitchCTUsBIF < bestCost) + { + bestCost = costSwitchCTUsBIF; + if(isCb) + { + CBifParams.frmOn_Cb = 1; + } + else + { + CBifParams.frmOn_Cr = 1; + } + if(isCb) + { + CBifParams.allCtuOn_Cb = 0; + } + else{ + CBifParams.allCtuOn_Cr = 0; + } + // If only some CTUs should be BIF-filtered, we need to restore the ones + // that should not be filtered. This test must be done before the above one + // since it is partly destroying our filtered data. + ctuIdx = 0; + for (int y = 0; y < pcv.heightInCtus; y++) + { + for (int x = 0; x < pcv.widthInCtus; x++) + { + UnitArea ctuArea(pcv.chrFormat, Area(x << pcv.maxCUWidthLog2, y << pcv.maxCUHeightLog2, pcv.maxCUWidth, pcv.maxCUWidth)); + ctuArea = clipArea(ctuArea, *cs.slice->getPic()); + PelBuf piRec = isCb ? rec.subBuf(ctuArea).Cb() : rec.subBuf(ctuArea).Cr(); + PelBuf piSrc = isCb ? src.subBuf(ctuArea).Cb() : src.subBuf(ctuArea).Cr(); + bool isCTUon = isCb ? CBifParams.ctuOn_Cb[ctuIdx] : CBifParams.ctuOn_Cr[ctuIdx]; + if( isCTUon == 0){ + copyBack(piSrc, piRec); // Copy unfiltered samples back to rec + } + ctuIdx++; + } + } + } + + if (costNoCTUsBIF < bestCost) + { + bestCost = costNoCTUsBIF; + if(isCb) + { + CBifParams.frmOn_Cb = 0; + } + else + { + CBifParams.frmOn_Cr = 0; + } + if(isCb) + { + CBifParams.allCtuOn_Cb = 0; + } + else + { + CBifParams.allCtuOn_Cr = 0; + } + + for (int y = 0; y < pcv.heightInCtus; y++) + { + for (int x = 0; x < pcv.widthInCtus; x++) + { + UnitArea ctuArea(pcv.chrFormat, Area(x << pcv.maxCUWidthLog2, y << pcv.maxCUHeightLog2, pcv.maxCUWidth, pcv.maxCUWidth)); + ctuArea = clipArea(ctuArea, *cs.slice->getPic()); + PelBuf piRec = isCb ? rec.subBuf(ctuArea).Cb() : rec.subBuf(ctuArea).Cr(); + PelBuf piSrc = isCb ? src.subBuf(ctuArea).Cb() : src.subBuf(ctuArea).Cr(); + copyBack(piSrc, piRec); // Copy unfiltered samples back to rec + } + } + } + + if(isCb){ + if (CBifParams.frmOn_Cb == 0) + { + std::fill(CBifParams.ctuOn_Cb.begin(), CBifParams.ctuOn_Cb.end(), 0); + } + else if (CBifParams.allCtuOn_Cb) + { + std::fill(CBifParams.ctuOn_Cb.begin(), CBifParams.ctuOn_Cb.end(), 1); + } + } + else{ + if (CBifParams.frmOn_Cr == 0) + { + std::fill(CBifParams.ctuOn_Cr.begin(), CBifParams.ctuOn_Cr.end(), 0); + } + else if (CBifParams.allCtuOn_Cr) + { + std::fill(CBifParams.ctuOn_Cr.begin(), CBifParams.ctuOn_Cr.end(), 1); + } + } + +} + +#if JVET_W0066_CCSAO +void BilateralFilter::bilateralFilterDiamond5x5NoClip_chroma(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit & currTU, bool isCb) +{ + + ComponentID compID = isCb ? COMPONENT_Cb :COMPONENT_Cr; + CompArea &compArea = currTU.block(compID); + + const unsigned uiWidth = compArea.width; + const unsigned uiHeight = compArea.height; + + int srcStride = src.get(compID).stride; + const Pel *srcPtr = src.get(compID).bufAt(compArea); + const Pel *srcPtrTemp = srcPtr; + + int recStride = rec.get(compID).stride; + Pel *recPtr = rec.get(compID).bufAt(compArea); + + int bfac = 1; + int bif_round_add = (BIF_ROUND_ADD) >> (currTU.cs->pps->getCBIFStrength()); + int bif_round_shift = (BIF_ROUND_SHIFT) - (currTU.cs->pps->getCBIFStrength()); + + int width_for_strength = currTU.blocks[compID].width; + int height_for_strength = currTU.blocks[compID].height; + + if(currTU.blocks[COMPONENT_Y].valid()) + { + width_for_strength = currTU.blocks[COMPONENT_Y].width; + height_for_strength = currTU.blocks[COMPONENT_Y].height; + } + + const char* LUTrowPtr = getFilterLutParameters_chroma( std::min( uiWidth, uiHeight ), currTU.cu->predMode, qp + currTU.cs->pps->getCBIFQPOffset(), bfac, width_for_strength, height_for_strength, currTU.blocks[COMPONENT_Y].valid()); + + uint32_t uiWidthExt = uiWidth + (NUMBER_PADDED_SAMPLES << 1); + uint32_t uiHeightExt = uiHeight + (NUMBER_PADDED_SAMPLES << 1); + + int iWidthExtSIMD = uiWidthExt; + if( uiWidth < 8 ) + { + iWidthExtSIMD = 8 + (NUMBER_PADDED_SAMPLES << 1); + } + + Pel *tempBlockPtr; + + memset(tempblock, 0, iWidthExtSIMD*uiHeightExt * sizeof(short)); + + tempBlockPtr = tempblock + (NUMBER_PADDED_SAMPLES)* iWidthExtSIMD + NUMBER_PADDED_SAMPLES; + + //// Move block to temporary block + for (uint32_t uiY = 0; uiY < uiHeight; ++uiY) + { + std::memcpy(tempBlockPtr, srcPtr, uiWidth * sizeof(Pel)); + srcPtr += srcStride; + tempBlockPtr += iWidthExtSIMD; + } + srcPtr = srcPtrTemp; + + const CompArea &myArea = isCb ? currTU.blocks[COMPONENT_Cb] : currTU.blocks[COMPONENT_Cr]; + + bool topAltAvailable = myArea.y - 2 >= 0; + bool leftAltAvailable = myArea.x - 2 >= 0; + +// uint32_t chroma_pic_width = currTU.cu->slice->getSPS()->getMaxPicWidthInLumaSamples() >> 1; +// uint32_t chroma_pic_height = currTU.cu->slice->getSPS()->getMaxPicHeightInLumaSamples() >> 1; + int scaleX = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat); + int scaleY = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat); + uint32_t chroma_pic_width = currTU.cu->slice->getPPS()->getPicWidthInLumaSamples() >> scaleX; + uint32_t chroma_pic_height = currTU.cu->slice->getPPS()->getPicHeightInLumaSamples() >> scaleY; + + bool bottomAltAvailable = myArea.y + myArea.height + 1 < chroma_pic_height; + bool rightAltAvailable = myArea.x + myArea.width + 1 < chroma_pic_width; + + bool allAvail = topAltAvailable && bottomAltAvailable && leftAltAvailable && rightAltAvailable; + + //if not 420, then don't use rec for padding + if(currTU.cu->chromaFormat != CHROMA_420) + { + topAltAvailable = false; + bottomAltAvailable = false; + leftAltAvailable = false; + rightAltAvailable = false; + allAvail = false; + } + + if(allAvail) + { + // set pointer two rows up and two pixels to the left from the start of the block + tempBlockPtr = tempblock; + // same with image data + srcPtr = srcPtr - 2*srcStride - 2; + // Move block to temporary block + // Check if the block a the top block of a CTU. + uint32_t CTUsize_chroma = currTU.cs->slice->getSPS()->getCTUSize() >> 1; + bool isCTUboundary = myArea.y % CTUsize_chroma == 0; + + if(isCTUboundary) + { + // The samples two lines up are out of bounds. (One line above the CTU is OK, since SAO uses that line.) + // Hence the top line of tempblock is unavailable if the block is the top block of a CTU. + // Therefore, copy samples from one line up instead of from two lines up by updating srcPtr *before* copy. + srcPtr += srcStride; + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + } + else + { + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + srcPtr += srcStride; + } + tempBlockPtr += iWidthExtSIMD; + // Copy samples that are not out of bounds. + for (uint32_t uiY = 1; uiY < uiHeightExt-1; ++uiY) + { + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + srcPtr += srcStride; + tempBlockPtr += iWidthExtSIMD; + } + // Check if the block is a bottom block of a CTU. + isCTUboundary = (myArea.y + uiHeight) % CTUsize_chroma == 0; + if(isCTUboundary) + { + // The samples two lines down are out of bounds. (One line below the CTU is OK, since SAO uses that line.) + // Hence the bottom line of tempblock is unavailable if the block at the bottom of a CTU. + // Therefore, copy samples from the second to last line instead of the last line by subtracting srcPtr before copy. + srcPtr -= srcStride; + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + } + else + { + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + } + } + else + { + tempBlockPtr = tempblock + (NUMBER_PADDED_SAMPLES)* iWidthExtSIMD + NUMBER_PADDED_SAMPLES; + // Move block to temporary block + for (uint32_t uiY = 0; uiY < uiHeight; ++uiY) + { + std::memcpy(tempBlockPtr, srcPtr, uiWidth * sizeof(Pel)); + srcPtr += srcStride; + tempBlockPtr += iWidthExtSIMD; + } + srcPtr = srcPtrTemp; + if(topAltAvailable) + { + std::copy(srcPtr - 2*srcStride, srcPtr - 2*srcStride + uiWidth, tempblock + 2); + std::copy(srcPtr - srcStride, srcPtr - srcStride + uiWidth, tempblock + iWidthExtSIMD + 2); + } + if(bottomAltAvailable) + { + std::copy(srcPtr + (uiHeight+1)*srcStride, srcPtr +(uiHeight+1)*srcStride + uiWidth, tempblock + (uiHeightExt-1)*iWidthExtSIMD + 2); + std::copy(srcPtr + uiHeight*srcStride, srcPtr +uiHeight*srcStride + uiWidth, tempblock + (uiHeightExt-2)*iWidthExtSIMD + 2); + } + if(leftAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 0] = *(srcPtr + yy*srcStride -2); + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 1] = *(srcPtr + yy*srcStride -1); + } + } + if(rightAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-1 + yy*iWidthExtSIMD] = *(srcPtr + uiWidth + yy*srcStride + 1); + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD] = *(srcPtr + uiWidth + yy*srcStride); + } + } + // if not all available, copy from inside tempbuffer + if(!topAltAvailable) + { + std::copy(tempblock + iWidthExtSIMD*2 + 2, tempblock + iWidthExtSIMD*2 + 2 + uiWidth, tempblock + 2); + std::copy(tempblock + iWidthExtSIMD*2 + 2, tempblock + iWidthExtSIMD*2 + 2 + uiWidth, tempblock + iWidthExtSIMD + 2); + } + if(!bottomAltAvailable) + { + std::copy(tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2, tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2 + uiWidth, tempblock + (uiHeightExt-2)*iWidthExtSIMD + 2); + std::copy(tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2, tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2 + uiWidth, tempblock + (uiHeightExt-1)*iWidthExtSIMD + 2); + } + if(!leftAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 0] = tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 2]; + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 1] = tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 2]; + } + } + if(!rightAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD] = tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD - 1]; + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-1 + yy*iWidthExtSIMD] = tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD - 1]; + } + } + // All sides are available, easy to just copy corners also. + if(topAltAvailable && leftAltAvailable) + { + tempblock[0] = *(srcPtr - 2*srcStride -2); // a top left corner + tempblock[1] = *(srcPtr - 2*srcStride -1); // b a b|x x + tempblock[iWidthExtSIMD + 0] = *(srcPtr - srcStride -2); // c c d|x x + tempblock[iWidthExtSIMD + 1] = *(srcPtr - srcStride -1); // d ------- + } + else + { + tempblock[0] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + tempblock[1] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + tempblock[iWidthExtSIMD + 0] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + tempblock[iWidthExtSIMD + 1] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + } + if(topAltAvailable && rightAltAvailable) + { + tempblock[iWidthExtSIMD - 2] = *(srcPtr - 2*srcStride + uiWidth); // a + tempblock[iWidthExtSIMD - 1] = *(srcPtr - 2*srcStride + uiWidth + 1); // b + tempblock[iWidthExtSIMD + uiWidthExt - 2] = *(srcPtr - srcStride + uiWidth); // c + tempblock[iWidthExtSIMD + uiWidthExt - 1] = *(srcPtr - srcStride + uiWidth + 1); // d + } + else + { + tempblock[iWidthExtSIMD - 2] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + tempblock[iWidthExtSIMD - 1] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + tempblock[iWidthExtSIMD + uiWidthExt - 2] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + tempblock[iWidthExtSIMD + uiWidthExt - 1] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + } + if(bottomAltAvailable && leftAltAvailable) + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 0] = *(srcPtr + uiHeight*srcStride -2); // a + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 1] = *(srcPtr + uiHeight*srcStride -1); // b + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 0] = *(srcPtr + (uiHeight+1)*srcStride -2); // c + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 1] = *(srcPtr + (uiHeight+1)*srcStride -1); // d + } + else + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 0] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 0] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + } + if(bottomAltAvailable && rightAltAvailable) + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 2] = *(srcPtr + uiHeight*srcStride + uiWidth); // a + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 1] = *(srcPtr + uiHeight*srcStride + uiWidth + 1); // b + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 2] = *(srcPtr + (uiHeight+1)*srcStride + uiWidth); // c + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 1] = *(srcPtr + (uiHeight+1)*srcStride + uiWidth + 1); // d + } + else + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 2] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 2] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + } + } + + m_bilateralFilterDiamond5x5NoClip(uiWidth, uiHeight, tempblock, tempblockFiltered, clpRng, recPtr, recStride, iWidthExtSIMD, bfac, bif_round_add, bif_round_shift, false, LUTrowPtr ); +} +#endif //BIFchroma no clip + +void BilateralFilter::bilateralFilterDiamond5x5_chroma(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit & currTU, bool isCb) +{ + + ComponentID compID = isCb ? COMPONENT_Cb :COMPONENT_Cr; + CompArea &compArea = currTU.block(compID); + + const unsigned uiWidth = compArea.width; + const unsigned uiHeight = compArea.height; + + int srcStride = src.get(compID).stride; + const Pel *srcPtr = src.get(compID).bufAt(compArea); + const Pel *srcPtrTemp = srcPtr; + + int recStride = rec.get(compID).stride; + Pel *recPtr = rec.get(compID).bufAt(compArea); + + int bfac = 1; + int bif_round_add = (BIF_ROUND_ADD) >> (currTU.cs->pps->getCBIFStrength()); + int bif_round_shift = (BIF_ROUND_SHIFT) - (currTU.cs->pps->getCBIFStrength()); + + int width_for_strength = currTU.blocks[compID].width; + int height_for_strength = currTU.blocks[compID].height; + + if(currTU.blocks[COMPONENT_Y].valid()) + { + width_for_strength = currTU.blocks[COMPONENT_Y].width; + height_for_strength = currTU.blocks[COMPONENT_Y].height; + } + + const char* LUTrowPtr = getFilterLutParameters_chroma( std::min( uiWidth, uiHeight ), currTU.cu->predMode, qp + currTU.cs->pps->getCBIFQPOffset(), bfac, width_for_strength, height_for_strength, currTU.blocks[COMPONENT_Y].valid()); + + uint32_t uiWidthExt = uiWidth + (NUMBER_PADDED_SAMPLES << 1); + uint32_t uiHeightExt = uiHeight + (NUMBER_PADDED_SAMPLES << 1); + + int iWidthExtSIMD = uiWidthExt; + if( uiWidth < 8 ) + { + iWidthExtSIMD = 8 + (NUMBER_PADDED_SAMPLES << 1); + } + + Pel *tempBlockPtr; + + memset(tempblock, 0, iWidthExtSIMD*uiHeightExt * sizeof(short)); + + tempBlockPtr = tempblock + (NUMBER_PADDED_SAMPLES)* iWidthExtSIMD + NUMBER_PADDED_SAMPLES; + + // Move block to temporary block + for (uint32_t uiY = 0; uiY < uiHeight; ++uiY) + { + std::memcpy(tempBlockPtr, srcPtr, uiWidth * sizeof(Pel)); + srcPtr += srcStride; + tempBlockPtr += iWidthExtSIMD; + } + srcPtr = srcPtrTemp; + const CompArea &myArea = isCb ? currTU.blocks[COMPONENT_Cb] : currTU.blocks[COMPONENT_Cr]; + bool topAltAvailable = myArea.y - 2 >= 0; + bool leftAltAvailable = myArea.x - 2 >= 0; + +// uint32_t chroma_pic_width = currTU.cu->slice->getSPS()->getMaxPicWidthInLumaSamples() >> 1; +// uint32_t chroma_pic_height = currTU.cu->slice->getSPS()->getMaxPicHeightInLumaSamples() >> 1; + int scaleX = getComponentScaleX(compID, currTU.cu->cs->pcv->chrFormat); + int scaleY = getComponentScaleY(compID, currTU.cu->cs->pcv->chrFormat); + uint32_t chroma_pic_width = currTU.cu->slice->getPPS()->getPicWidthInLumaSamples() >> scaleX; + uint32_t chroma_pic_height = currTU.cu->slice->getPPS()->getPicHeightInLumaSamples() >> scaleY; + + bool bottomAltAvailable = myArea.y + myArea.height + 1 < chroma_pic_height; + bool rightAltAvailable = myArea.x + myArea.width + 1 < chroma_pic_width; + + bool allAvail = topAltAvailable && bottomAltAvailable && leftAltAvailable && rightAltAvailable; + + //if not 420, then don't use rec for padding + if(currTU.cu->chromaFormat != CHROMA_420){ + topAltAvailable = false; + bottomAltAvailable = false; + leftAltAvailable = false; + rightAltAvailable = false; + allAvail = false; + } + if(allAvail) + { + // set pointer two rows up and two pixels to the left from the start of the block + tempBlockPtr = tempblock; + // same with image data + srcPtr = srcPtr - 2*srcStride - 2; + // Move block to temporary block + // Check if the block a the top block of a CTU. + uint32_t CTUsize_chroma = currTU.cs->slice->getSPS()->getCTUSize() >> 1; + bool isCTUboundary = myArea.y % CTUsize_chroma == 0; + + if(isCTUboundary) + { + // The samples two lines up are out of bounds. (One line above the CTU is OK, since SAO uses that line.) + // Hence the top line of tempblock is unavailable if the block is the top block of a CTU. + // Therefore, copy samples from one line up instead of from two lines up by updating srcPtr *before* copy. + srcPtr += srcStride; + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + } + else + { + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + srcPtr += srcStride; + } + tempBlockPtr += iWidthExtSIMD; + // Copy samples that are not out of bounds. + for (uint32_t uiY = 1; uiY < uiHeightExt-1; ++uiY) + { + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + srcPtr += srcStride; + tempBlockPtr += iWidthExtSIMD; + } + // Check if the block is a bottom block of a CTU. + isCTUboundary = (myArea.y + uiHeight) % CTUsize_chroma == 0; + if(isCTUboundary) + { + // The samples two lines down are out of bounds. (One line below the CTU is OK, since SAO uses that line.) + // Hence the bottom line of tempblock is unavailable if the block at the bottom of a CTU. + // Therefore, copy samples from the second to last line instead of the last line by subtracting srcPtr before copy. + srcPtr -= srcStride; + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + } + else + { + std::memcpy(tempBlockPtr, srcPtr, (uiWidthExt) * sizeof(Pel)); + } + } + else + { + tempBlockPtr = tempblock + (NUMBER_PADDED_SAMPLES)* iWidthExtSIMD + NUMBER_PADDED_SAMPLES; + // Move block to temporary block + for (uint32_t uiY = 0; uiY < uiHeight; ++uiY) + { + std::memcpy(tempBlockPtr, srcPtr, uiWidth * sizeof(Pel)); + srcPtr += srcStride; + tempBlockPtr += iWidthExtSIMD; + } + srcPtr = srcPtrTemp; + if(topAltAvailable) + { + std::copy(srcPtr - 2*srcStride, srcPtr - 2*srcStride + uiWidth, tempblock + 2); + std::copy(srcPtr - srcStride, srcPtr - srcStride + uiWidth, tempblock + iWidthExtSIMD + 2); + } + if(bottomAltAvailable) + { + std::copy(srcPtr + (uiHeight+1)*srcStride, srcPtr +(uiHeight+1)*srcStride + uiWidth, tempblock + (uiHeightExt-1)*iWidthExtSIMD + 2); + std::copy(srcPtr + uiHeight*srcStride, srcPtr +uiHeight*srcStride + uiWidth, tempblock + (uiHeightExt-2)*iWidthExtSIMD + 2); + } + if(leftAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 0] = *(srcPtr + yy*srcStride -2); + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 1] = *(srcPtr + yy*srcStride -1); + } + } + if(rightAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-1 + yy*iWidthExtSIMD] = *(srcPtr + uiWidth + yy*srcStride + 1); + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD] = *(srcPtr + uiWidth + yy*srcStride); + } + } + // if not all available, copy from inside tempbuffer + if(!topAltAvailable) + { + std::copy(tempblock + iWidthExtSIMD*2 + 2, tempblock + iWidthExtSIMD*2 + 2 + uiWidth, tempblock + 2); + std::copy(tempblock + iWidthExtSIMD*2 + 2, tempblock + iWidthExtSIMD*2 + 2 + uiWidth, tempblock + iWidthExtSIMD + 2); + } + if(!bottomAltAvailable) + { + std::copy(tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2, tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2 + uiWidth, tempblock + (uiHeightExt-2)*iWidthExtSIMD + 2); + std::copy(tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2, tempblock + (uiHeightExt-3)*iWidthExtSIMD + 2 + uiWidth, tempblock + (uiHeightExt-1)*iWidthExtSIMD + 2); + } + if(!leftAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 0] = tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 2]; + tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 1] = tempblock[(iWidthExtSIMD<<1) + yy*iWidthExtSIMD + 2]; + } + } + if(!rightAltAvailable) + { + for(int yy = 0; yy<uiHeight; yy++) + { + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD] = tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD - 1]; + tempblock[(iWidthExtSIMD<<1) + uiWidthExt-1 + yy*iWidthExtSIMD] = tempblock[(iWidthExtSIMD<<1) + uiWidthExt-2 + yy*iWidthExtSIMD - 1]; + } + } + // All sides are available, easy to just copy corners also. + if(topAltAvailable && leftAltAvailable) + { + tempblock[0] = *(srcPtr - 2*srcStride -2); // a top left corner + tempblock[1] = *(srcPtr - 2*srcStride -1); // b a b|x x + tempblock[iWidthExtSIMD + 0] = *(srcPtr - srcStride -2); // c c d|x x + tempblock[iWidthExtSIMD + 1] = *(srcPtr - srcStride -1); // d ------- + } + else + { + tempblock[0] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + tempblock[1] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + tempblock[iWidthExtSIMD + 0] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + tempblock[iWidthExtSIMD + 1] = tempblock[iWidthExtSIMD*2 + 2]; // extend top left + } + if(topAltAvailable && rightAltAvailable) + { + tempblock[iWidthExtSIMD - 2] = *(srcPtr - 2*srcStride + uiWidth); // a + tempblock[iWidthExtSIMD - 1] = *(srcPtr - 2*srcStride + uiWidth + 1); // b + tempblock[iWidthExtSIMD + uiWidthExt - 2] = *(srcPtr - srcStride + uiWidth); // c + tempblock[iWidthExtSIMD + uiWidthExt - 1] = *(srcPtr - srcStride + uiWidth + 1); // d + } + else + { + tempblock[iWidthExtSIMD - 2] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + tempblock[iWidthExtSIMD - 1] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + tempblock[iWidthExtSIMD + uiWidthExt - 2] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + tempblock[iWidthExtSIMD + uiWidthExt - 1] = tempblock[iWidthExtSIMD*2 + uiWidthExt - 3]; // extend top right + } + if(bottomAltAvailable && leftAltAvailable) + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 0] = *(srcPtr + uiHeight*srcStride -2); // a + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 1] = *(srcPtr + uiHeight*srcStride -1); // b + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 0] = *(srcPtr + (uiHeight+1)*srcStride -2); // c + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 1] = *(srcPtr + (uiHeight+1)*srcStride -1); // d + } + else + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 0] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + tempblock[iWidthExtSIMD*(uiHeightExt-2) + 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 0] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + tempblock[iWidthExtSIMD*(uiHeightExt-1) + 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + 2]; // bot avail: mirror left/right + } + if(bottomAltAvailable && rightAltAvailable) + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 2] = *(srcPtr + uiHeight*srcStride + uiWidth); // a + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 1] = *(srcPtr + uiHeight*srcStride + uiWidth + 1); // b + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 2] = *(srcPtr + (uiHeight+1)*srcStride + uiWidth); // c + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 1] = *(srcPtr + (uiHeight+1)*srcStride + uiWidth + 1); // d + } + else + { + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 2] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + tempblock[iWidthExtSIMD*(uiHeightExt-2) + uiWidthExt - 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 2] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + tempblock[iWidthExtSIMD*(uiHeightExt-1) + uiWidthExt - 1] = tempblock[iWidthExtSIMD*(uiHeightExt-3) + uiWidthExt - 3]; + } + } + + m_bilateralFilterDiamond5x5(uiWidth, uiHeight, tempblock, tempblockFiltered, clpRng, recPtr, recStride, iWidthExtSIMD, bfac, bif_round_add, bif_round_shift, false, LUTrowPtr ); +} + +void BilateralFilter::clipNotBilaterallyFilteredBlocks_chroma(const CPelUnitBuf& src, PelUnitBuf& rec, const ClpRng& clpRng, TransformUnit & currTU, bool isCb) +{ + PelUnitBuf myRecBuf = currTU.cs->getRecoBuf(currTU); + int cid = isCb ? COMPONENT_Cb : COMPONENT_Cr; + if(myRecBuf.bufs[cid].width > 1) + { + // new result = old result (which is SAO-treated already) + diff due to bilateral filtering + myRecBuf.bufs[cid].copyClip(myRecBuf.bufs[cid], clpRng); + } + else + { + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + CompArea &compArea = currTU.block(compID); + const unsigned uiHeight = compArea.height; + int recStride = rec.get(compID).stride; + Pel *recPtr = rec.get(compID).bufAt(compArea); + + for(uint32_t yy = 0; yy < uiHeight; yy++){ + // new result = old result (which is SAO-treated already) + diff due to bilateral filtering + recPtr[0] = ClipPel<int>(recPtr[0], clpRng); + recPtr += recStride; + } + } +} + +const char* BilateralFilter::getFilterLutParameters_chroma( const int size, const PredMode predMode, const int32_t qp, int& bfac, int width_for_strength, int height_for_strength, bool isLumaValid) +{ + + int condition = std::min(width_for_strength, height_for_strength); + + int T1 = 4; + int T2 = 16; + if(!isLumaValid) + { + T1 = 128; + T2 = 256; + } + + if(predMode == MODE_INTER) + { + if(condition <= T1) + { + bfac = 2; + goto FINISH; + } + if (condition >= T2) + { + bfac = 1; + goto FINISH; + } + if(condition > T1 && condition < T2) + { + bfac = 2; + goto FINISH; + } + } + else{ + if(condition <= T1) + { + bfac = 3; + goto FINISH; + } + if(condition >= T2) + { + bfac = 1; + goto FINISH; + } + if(condition > T1 && condition < T2) + { + bfac = 2; + goto FINISH; + } + } + +FINISH: + int sqp = qp; + int qp_min = 17; + int qp_max = 42; + if( sqp < qp_min ) + { + sqp = qp_min; + } + if( sqp > qp_max ) + { + sqp = qp_max; + } + + return m_wBIF_chroma[sqp - 17]; + +} +#endif #endif diff --git a/source/Lib/CommonLib/BilateralFilter.h b/source/Lib/CommonLib/BilateralFilter.h index a77d6d62e9d085d5a39aa5514e1dbcad69d358c4..66b4ceb29fdabb20b8fb03322a45765c40263a60 100755 --- a/source/Lib/CommonLib/BilateralFilter.h +++ b/source/Lib/CommonLib/BilateralFilter.h @@ -35,21 +35,30 @@ #include "CommonDef.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "Unit.h" #include "Buffer.h" #include <tmmintrin.h> #include <smmintrin.h> #include <immintrin.h> - +#if JVET_V0094_BILATERAL_FILTER class BIFCabacEst { public: virtual ~BIFCabacEst() {}; virtual uint64_t getBits(const Slice& slice, const BifParams& htdfParams) = 0; }; - +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +class CBIFCabacEst +{ +public: + virtual ~CBIFCabacEst() {}; + virtual uint64_t getBits_Cb(const Slice& slice, const CBifParams& htdfParams) = 0; + virtual uint64_t getBits_Cr(const Slice& slice, const CBifParams& htdfParams) = 0; +}; +#endif class BilateralFilter { private: @@ -72,7 +81,7 @@ private: #if JVET_W0066_CCSAO static void blockBilateralFilterDiamond5x5NoClip(uint32_t uiWidth, uint32_t uiHeight, int16_t block[], int16_t blkFilt[], const ClpRng& clpRng, Pel* recPtr, int recStride, int iWidthExtSIMD, int bfac, int bif_round_add, int bif_round_shift, bool isRDO, const char* LUTrowPtr); #endif - +#if JVET_V0094_BILATERAL_FILTER char m_wBIF[26][16] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, { 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, @@ -101,14 +110,44 @@ private: { 0, 16, 23, 32, 36, 40, 43, 43, 44, 42, 39, 26, 21, 17, 15, -3, }, { 0, 17, 23, 33, 37, 41, 44, 44, 45, 44, 42, 27, 22, 17, 15, -3, }, }; - +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + char m_wBIF_chroma[26][16] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + { 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + { 0, 2, 2, 2, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, + { 0, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, -1, }, + { 0, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 1, 0, 1, 1, -1, }, + { 0, 3, 3, 3, 2, 2, 1, 2, 1, 1, 1, 1, 0, 1, 1, -1, }, + { 0, 4, 4, 4, 3, 2, 2, 2, 2, 2, 2, 1, 0, 1, 1, -1, }, + { 0, 5, 5, 5, 4, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, -1, }, + { 0, 5, 6, 6, 4, 3, 2, 2, 2, 2, 2, 2, 1, 2, 2, -2, }, + { 0, 5, 8, 8, 5, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, -2, }, + { 0, 6, 9, 9, 5, 4, 4, 3, 4, 3, 3, 2, 2, 2, 2, -2, }, + { 0, 6, 9, 10, 8, 6, 6, 5, 5, 5, 4, 2, 2, 2, 2, -2, }, + { 0, 6, 10, 11, 10, 9, 9, 6, 6, 5, 5, 4, 4, 3, 3, -2, }, + { 0, 7, 11, 12, 12, 12, 11, 9, 7, 7, 6, 5, 5, 4, 5, -2, }, + { 0, 7, 12, 13, 15, 15, 13, 10, 9, 8, 8, 6, 6, 5, 5, -2, }, + { 0, 7, 12, 15, 17, 17, 16, 12, 9, 9, 9, 7, 7, 5, 6, -2, }, + { 0, 8, 13, 16, 19, 20, 19, 16, 14, 13, 12, 9, 9, 7, 7, -2, }, + { 0, 8, 14, 18, 20, 22, 22, 20, 18, 17, 14, 11, 10, 9, 9, -2, }, + { 0, 9, 15, 19, 23, 23, 25, 23, 23, 20, 17, 13, 12, 10, 9, -2, }, + { 0, 9, 16, 20, 24, 26, 28, 27, 27, 24, 20, 15, 13, 12, 11, -2, }, + { 0, 9, 16, 22, 26, 28, 31, 31, 31, 28, 23, 17, 15, 13, 12, -2, }, + { 0, 10, 16, 23, 27, 29, 32, 32, 32, 30, 25, 18, 16, 13, 12, -2, }, + { 0, 11, 17, 23, 27, 30, 33, 33, 33, 30, 27, 19, 16, 13, 12, -2, }, + { 0, 12, 17, 24, 27, 30, 33, 33, 34, 32, 29, 20, 16, 13, 12, -2, }, + { 0, 12, 18, 25, 28, 31, 34, 34, 34, 33, 30, 20, 16, 13, 12, -2, }, + { 0, 13, 18, 26, 29, 32, 34, 34, 35, 34, 33, 21, 17, 13, 12, -2, }, + }; +#endif public: BilateralFilter(); ~BilateralFilter(); void create(); void destroy(); - +#if JVET_V0094_BILATERAL_FILTER void bilateralFilterRDOdiamond5x5(PelBuf& resiBuf, const CPelBuf& predBuf, PelBuf& recoBuf, int32_t qp, const CPelBuf& recIPredBuf, const ClpRng& clpRng, TransformUnit & currTU, bool useReco, bool doReshape, std::vector<Pel>& pLUT); void bilateralFilterPicRDOperCTU(CodingStructure& cs, PelUnitBuf& src,BIFCabacEst* BifCABACEstimator); @@ -116,12 +155,29 @@ public: void bilateralFilterDiamond5x5(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit & currTU); #if JVET_W0066_CCSAO void bilateralFilterDiamond5x5NoClip(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit& currTU); +#endif #endif void clipNotBilaterallyFilteredBlocks(const CPelUnitBuf& src, PelUnitBuf& rec, const ClpRng& clpRng, TransformUnit & currTU); - +#if JVET_V0094_BILATERAL_FILTER const char* getFilterLutParameters( const int size, const PredMode predMode, const int qp, int& bfac ); +#endif + +#if JVET_X0071_CHROMA_BILATERAL_FILTER + void bilateralFilterRDOdiamond5x5_chroma(PelBuf& resiBuf, const CPelBuf& predBuf, PelBuf& recoBuf, int32_t qp, const CPelBuf& recIPredBuf, const ClpRng& clpRng, TransformUnit & currTU, bool useReco, bool isCb); + + void bilateralFilterPicRDOperCTU_chroma(CodingStructure& cs, PelUnitBuf& src, CBIFCabacEst* CBifCABACEstimator, bool isCb); + + void bilateralFilterDiamond5x5_chroma(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit & currTU, bool isCb); + + void clipNotBilaterallyFilteredBlocks_chroma(const CPelUnitBuf& src, PelUnitBuf& rec, const ClpRng& clpRng, TransformUnit & currTU, bool isCb); + +#if JVET_W0066_CCSAO + void bilateralFilterDiamond5x5NoClip_chroma(const CPelUnitBuf& src, PelUnitBuf& rec, int32_t qp, const ClpRng& clpRng, TransformUnit & currTU, bool isCb); +#endif + const char* getFilterLutParameters_chroma( const int size, const PredMode predMode, const int qp, int& bfac, int width_for_strength, int height_for_strength, bool isLumaValid); +#endif -#if ENABLE_SIMD_BILATERAL_FILTER +#if ENABLE_SIMD_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER_ENABLE_SIMD #ifdef TARGET_SIMD_X86 template<X86_VEXT vext> static void simdFilterDiamond5x5( uint32_t uiWidth, uint32_t uiHeight, int16_t block[], int16_t blkFilt[], const ClpRng& clpRng, Pel* recPtr, int recStride, int iWidthExtSIMD, int bfac, int bif_round_add, int bif_round_shift, bool isRDO, const char* LUTrowPtr ); diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index 351a3f1bd92886805d98e45e8ae63b179c1159c9..ccad654c5f62b56c53eb64c8a2a011d280f64e35 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -124,7 +124,7 @@ static const int AFFINE_ME_LIST_SIZE = 4; static const int AFFINE_ME_LIST_SIZE_LD = 3; static const double AFFINE_ME_LIST_MVP_TH = 1.0; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER static const int32_t NUMBER_PADDED_SAMPLES = 2; static const int32_t BIF_ROUND_ADD = 32; static const int32_t BIF_ROUND_SHIFT = 6; @@ -237,8 +237,13 @@ static const int MAX_ALF_FILTER_LENGTH = 7; #endif static const int MAX_NUM_ALF_COEFF = MAX_ALF_FILTER_LENGTH * MAX_ALF_FILTER_LENGTH / 2 + 1; static const int MAX_ALF_PADDING_SIZE = 4; +#if JVET_X0071_LONGER_CCALF +#define MAX_NUM_CC_ALF_FILTERS 16 +static constexpr int MAX_NUM_CC_ALF_CHROMA_COEFF = 25; +#else #define MAX_NUM_CC_ALF_FILTERS 4 static constexpr int MAX_NUM_CC_ALF_CHROMA_COEFF = 8; +#endif static constexpr int CCALF_DYNAMIC_RANGE = 6; static constexpr int CCALF_BITS_PER_COEFF_LEVEL = 3; @@ -247,6 +252,11 @@ static const int ALF_CTB_MAX_NUM_APS = 8; #if ALF_IMPROVEMENT static const int ALF_ORDER = 4; static const int NUM_FIXED_FILTER_SETS = 2; +#if JVET_X0071_ALF_BAND_CLASSIFIER +static const int ALF_NUM_CLASSIFIER = 2; +static const int ALF_CLASSES_NEW = 25; +static const int ALF_NUM_CLASSES_CLASSIFIER[ALF_NUM_CLASSIFIER] = { MAX_NUM_ALF_CLASSES, ALF_CLASSES_NEW }; +#endif #else static const int NUM_FIXED_FILTER_SETS = 16; static const int NUM_TOTAL_FILTER_SETS = NUM_FIXED_FILTER_SETS + ALF_CTB_MAX_NUM_APS; diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 74b50910a5f2dd494c13e20323ed27d1e29d6efe..2be41cd7ca5d8b2310e78bba8a2bf740626cf303 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -1526,6 +1526,26 @@ const CtxSet ContextSetCfg::BifCtrlFlags = ContextSetCfg::addCtxSet { DWS } }); #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +const CtxSet ContextSetCfg::CBifCtrlFlags_Cb = ContextSetCfg::addCtxSet +({ + { 39 }, + { 39 }, + { 39 }, + { DWS }, + { DWS }, + { DWS } +}); +const CtxSet ContextSetCfg::CBifCtrlFlags_Cr = ContextSetCfg::addCtxSet +({ + { 39 }, + { 39 }, + { 39 }, + { DWS }, + { DWS }, + { DWS } +}); +#endif #if JVET_W0066_CCSAO const CtxSet ContextSetCfg::CcSaoControlIdc = ContextSetCfg::addCtxSet @@ -2599,6 +2619,22 @@ const CtxSet ContextSetCfg::BifCtrlFlags = ContextSetCfg::addCtxSet { DWS, }, }); #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +const CtxSet ContextSetCfg::CBifCtrlFlags_Cb = ContextSetCfg::addCtxSet +({ + { 39, }, + { 39, }, + { 39, }, + { DWS, }, +}); +const CtxSet ContextSetCfg::CBifCtrlFlags_Cr = ContextSetCfg::addCtxSet +({ + { 39, }, + { 39, }, + { 39, }, + { DWS, }, +}); +#endif #if JVET_W0066_CCSAO const CtxSet ContextSetCfg::CcSaoControlIdc = ContextSetCfg::addCtxSet diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index 3841a64a00256170e7dc0619b12a0576ff544772..fcfc81ab9ffa15a9d28fb5f286b0f0dbe72b43e3 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -304,6 +304,10 @@ public: #if JVET_V0094_BILATERAL_FILTER static const CtxSet BifCtrlFlags; #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + static const CtxSet CBifCtrlFlags_Cb; + static const CtxSet CBifCtrlFlags_Cr; +#endif #if JVET_W0066_CCSAO static const CtxSet CcSaoControlIdc; #endif diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index af2e04a61c09ffed5087ff1dd899a606269233de..6c8b18113365597fe9b436e6f9f95623801ec236 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -42,6 +42,9 @@ #if JVET_V0094_BILATERAL_FILTER BifParams Picture::m_BifParams; #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +CBifParams Picture::m_CBifParams; +#endif #if ENABLE_SPLIT_PARALLELISM diff --git a/source/Lib/CommonLib/Picture.h b/source/Lib/CommonLib/Picture.h index 26db42887758f7b8f95e24c711d809042803d534..1aa7a10a8b9ae34be81924080b630d522af7f377 100644 --- a/source/Lib/CommonLib/Picture.h +++ b/source/Lib/CommonLib/Picture.h @@ -314,7 +314,17 @@ public: std::fill(m_BifParams.ctuOn.begin(), m_BifParams.ctuOn.end(), 0); }; #endif - +#if JVET_X0071_CHROMA_BILATERAL_FILTER + CBifParams& getCBifParam() { return m_CBifParams; } + void resizeBIF_Chroma(unsigned numEntries) + { + m_CBifParams.numBlocks = numEntries; + m_CBifParams.ctuOn_Cb.resize(numEntries); + m_CBifParams.ctuOn_Cr.resize(numEntries); + std::fill(m_CBifParams.ctuOn_Cb.begin(), m_CBifParams.ctuOn_Cb.end(), 0); + std::fill(m_CBifParams.ctuOn_Cr.begin(), m_CBifParams.ctuOn_Cr.end(), 0); + } +#endif #if ENABLE_QPA std::vector<double> m_uEnerHpCtu; ///< CTU-wise L2 or squared L1 norm of high-passed luma input std::vector<Pel> m_iOffsetCtu; ///< CTU-wise DC offset (later QP index offset) of luma input @@ -327,7 +337,9 @@ public: #if JVET_V0094_BILATERAL_FILTER static BifParams m_BifParams; #endif - +#if JVET_X0071_CHROMA_BILATERAL_FILTER + static CBifParams m_CBifParams; +#endif std::vector<uint8_t> m_alfCtuEnableFlag[MAX_NUM_COMPONENT]; uint8_t* getAlfCtuEnableFlag( int compIdx ) { return m_alfCtuEnableFlag[compIdx].data(); } std::vector<uint8_t>* getAlfCtuEnableFlag() { return m_alfCtuEnableFlag; } diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp index 5ab4acb18f1b46a724ffcf7036e80ee757d3424e..1f7f3da409d2f37f19a987fa51bd743757274d59 100644 --- a/source/Lib/CommonLib/SampleAdaptiveOffset.cpp +++ b/source/Lib/CommonLib/SampleAdaptiveOffset.cpp @@ -595,7 +595,7 @@ void SampleAdaptiveOffset::offsetBlock(const int channelBitDepth, const ClpRng& } } -#if JVET_V0094_BILATERAL_FILTER || JVET_W0066_CCSAO +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER || JVET_W0066_CCSAO void SampleAdaptiveOffset::offsetBlockNoClip(const int channelBitDepth, const ClpRng& clpRng, int typeIdx, int* offset , const Pel* srcBlk, Pel* resBlk, int srcStride, int resStride, int width, int height , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail) @@ -884,7 +884,7 @@ void SampleAdaptiveOffset::offsetCTU( const UnitArea& area, const CPelUnitBuf& s } //compIdx } -#if JVET_V0094_BILATERAL_FILTER || JVET_W0066_CCSAO +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER || JVET_W0066_CCSAO void SampleAdaptiveOffset::offsetCTUnoClip( const UnitArea& area, const CPelUnitBuf& src, PelUnitBuf& res, SAOBlkParam& saoblkParam, CodingStructure& cs) { const uint32_t numberOfComponents = getNumberValidComponents( area.chromaFormat ); @@ -943,7 +943,7 @@ void SampleAdaptiveOffset::offsetCTUnoClip( const UnitArea& area, const CPelUnit verVirBndryPosComp[i] = (verVirBndryPos[i] >> ::getComponentScaleX(compID, area.chromaFormat)) - compArea.x; } #endif -#if JVET_W0066_CCSAO +#if JVET_W0066_CCSAO // Do not clip the final output for both luma and chroma. Clipping is done jontly for SAO/BIF/CCSAO. offsetBlockNoClip(cs.sps->getBitDepth(toChannelType(compID)), @@ -956,8 +956,12 @@ void SampleAdaptiveOffset::offsetCTUnoClip( const UnitArea& area, const CPelUnit , isBelowLeftAvail, isBelowRightAvail // , isCtuCrossedByVirtualBoundaries, horVirBndryPosComp, verVirBndryPosComp, numHorVirBndry, numVerVirBndry ); +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(isLuma(compID) || isChroma(compID)) #else if(compID == COMPONENT_Y) +#endif { // If it is luma we should not clip, since we will clip // after BIF has been added. @@ -996,12 +1000,11 @@ void SampleAdaptiveOffset::offsetCTUnoClip( const UnitArea& area, const CPelUnit } #endif -void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkParams - ) +void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkParams ) { CHECK(!saoBlkParams, "No parameters present"); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER // In code without BIF, SAOProcess would not be run if 'SAO=0'. // However, in the BIF-enabled code, we still might go here if 'SAO=0' and 'BIF=1'. // Hence we must check getSAOEnabledFlag() for some of the function calls. @@ -1015,7 +1018,7 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP const uint32_t numberOfComponents = getNumberValidComponents(cs.area.chromaFormat); bool bAllDisabled = true; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER // If 'SAO=0' we would not normally get here. However, now we might get // here if 'SAO=0' and 'BIF=1'. Hence we should only run this if // getSAOEnabledFlag() is true. Note that if getSAOEnabledFlag() is false, @@ -1031,21 +1034,32 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP bAllDisabled = false; } } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER } #endif if (bAllDisabled) { #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(!cs.pps->getUseBIF() && !cs.pps->getUseCBIF()) +#else // Even if we are not doing SAO we might still need to do BIF // so we cannot return even if SAO is never used. if(!cs.pps->getUseBIF()) +#endif { // However, if we are not doing BIF it is safe to return. return; } +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(!cs.pps->getUseCBIF()) + { + return; + } #else return; +#endif #endif } @@ -1068,7 +1082,6 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP { offsetCTUnoClip( area, m_tempBuf, rec, cs.picture->getSAO()[ctuRsAddr], cs ); } - #if JVET_V0094_BILATERAL_FILTER if (cs.pps->getUseBIF()) { @@ -1088,9 +1101,66 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP } } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + CBifParams& CBifParams = cs.picture->getCBifParam(); + + // And now we traverse the CTU to do BIF + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + BIF_chroma = false; + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && (( TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + m_bilateralFilter.bilateralFilterDiamond5x5NoClip_chroma(m_tempBuf, rec, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + } +#endif #else #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseBIF() || cs.pps->getUseCBIF()) +#else if(cs.pps->getUseBIF()) +#endif { // We are using BIF, so we run SAO without clipping // However, if 'SAO=0', bAllDisabled=true and we should not run offsetCTUnoClip. @@ -1105,6 +1175,22 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP bool clipLumaIfNoBilat = false; if(!bAllDisabled && myCtbOffset.modeIdc != SAO_MODE_OFF) clipLumaIfNoBilat = true; +#if JVET_X0071_CHROMA_BILATERAL_FILTER + SAOOffset& myCtbOffset_Cb = mySAOblkParam[1]; + SAOOffset& myCtbOffset_Cr = mySAOblkParam[2]; + CBifParams& CBifParams = cs.picture->getCBifParam(); + + bool clipChromaIfNoBilat_Cb = false; + bool clipChromaIfNoBilat_Cr = false; + + if(!bAllDisabled && myCtbOffset_Cb.modeIdc != SAO_MODE_OFF) + clipChromaIfNoBilat_Cb = true; + if(!bAllDisabled && myCtbOffset_Cr.modeIdc != SAO_MODE_OFF) + clipChromaIfNoBilat_Cr = true; + + if(cs.pps->getUseBIF()) + { +#endif // And now we traverse the CTU to do BIF for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) @@ -1125,15 +1211,235 @@ void SampleAdaptiveOffset::SAOProcess( CodingStructure& cs, SAOBlkParam* saoBlkP } } } +#if JVET_X0071_CHROMA_BILATERAL_FILTER + } // BIF LUMA is disabled + else + { + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) + { + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipLumaIfNoBilat) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks(m_tempBuf, rec, cs.slice->clpRng(COMPONENT_Y), currTU); + } + } + } + } + if(cs.pps->getUseCBIF()) + { + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + // And now we traverse the CTU to do BIF + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + if(TU_VALID) + { + TU_CBF =TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + + if(BIF_chroma) + { + m_bilateralFilter.bilateralFilterDiamond5x5_chroma(m_tempBuf, rec, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + else + { + bool use_clip = isCb ? clipChromaIfNoBilat_Cb : clipChromaIfNoBilat_Cr; + if(use_clip && currTU.blocks[compIdx].valid()) + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(m_tempBuf, rec, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + }// BIF chroma is disabled + else + { + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipChromaIfNoBilat_Cb && currTU.blocks[COMPONENT_Cb].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(m_tempBuf, rec, cs.slice->clpRng(COMPONENT_Cb), currTU, true); + } + if(clipChromaIfNoBilat_Cr && currTU.blocks[COMPONENT_Cr].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(m_tempBuf, rec, cs.slice->clpRng(COMPONENT_Cr), currTU, false); + } + } + } + } +#endif } else { // BIF is not used, use old SAO code offsetCTU( area, m_tempBuf, rec, cs.picture->getSAO()[ctuRsAddr], cs); } +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if( !bAllDisabled ) + { + offsetCTUnoClip( area, m_tempBuf, rec, cs.picture->getSAO()[ctuRsAddr], cs); + } + + SAOBlkParam mySAOblkParam = cs.picture->getSAO()[ctuRsAddr]; + SAOOffset& myCtbOffset = mySAOblkParam[0]; + + bool clipLumaIfNoBilat = false; + if(!bAllDisabled && myCtbOffset.modeIdc != SAO_MODE_OFF) + { + clipLumaIfNoBilat = true; + } + + SAOOffset& myCtbOffset_Cb = mySAOblkParam[1]; + SAOOffset& myCtbOffset_Cr = mySAOblkParam[2]; + CBifParams& CBifParams = cs.picture->getCBifParam(); + + bool clipChromaIfNoBilat_Cb = false; + bool clipChromaIfNoBilat_Cr = false; + + if(!bAllDisabled && myCtbOffset_Cb.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cb = true; + } + if(!bAllDisabled && myCtbOffset_Cr.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cr = true; + } + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) + { + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipLumaIfNoBilat) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks(m_tempBuf, rec, cs.slice->clpRng(COMPONENT_Y), currTU); + } + } + } + + if(cs.pps->getUseCBIF()) + { + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + // And now we traverse the CTU to do BIF + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + m_bilateralFilter.bilateralFilterDiamond5x5_chroma(m_tempBuf, rec, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + else + { + bool use_clip = isCb ? clipChromaIfNoBilat_Cb : clipChromaIfNoBilat_Cr; + if(use_clip && currTU.blocks[compIdx].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(m_tempBuf, rec, cs.slice->clpRng(compID), currTU, true); + } + } + } + } + } + }// BIF chroma off + else + { + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipChromaIfNoBilat_Cb && currTU.blocks[COMPONENT_Cb].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(m_tempBuf, rec, cs.slice->clpRng(COMPONENT_Cb), currTU, true); + } + if(clipChromaIfNoBilat_Cr && currTU.blocks[COMPONENT_Cr].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(m_tempBuf, rec, cs.slice->clpRng(COMPONENT_Cr), currTU, false); + } + } + } + } #else offsetCTU( area, m_tempBuf, rec, cs.picture->getSAO()[ctuRsAddr], cs); #endif +#endif #endif ctuRsAddr++; } @@ -1194,16 +1500,21 @@ void SampleAdaptiveOffset::applyCcSao(CodingStructure &cs, const PreCalcValues& void SampleAdaptiveOffset::jointClipSaoBifCcSao(CodingStructure& cs) { #if JVET_V0094_BILATERAL_FILTER - if( !cs.sps->getSAOEnabledFlag() && !cs.pps->getUseBIF() && !cs.sps->getCCSAOEnabledFlag() ) - { - return; - } +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (!cs.sps->getSAOEnabledFlag() && !cs.pps->getUseBIF() && !cs.pps->getUseCBIF() && !cs.sps->getCCSAOEnabledFlag()) +#else + if (!cs.sps->getSAOEnabledFlag() && !cs.pps->getUseBIF() && !cs.sps->getCCSAOEnabledFlag()) +#endif #else - if( !cs.sps->getSAOEnabledFlag() && !cs.sps->getCCSAOEnabledFlag() ) +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (!cs.sps->getSAOEnabledFlag() && !cs.sps->getCCSAOEnabledFlag() && !cs.pps->getUseCBIF()) +#else + if (!cs.sps->getSAOEnabledFlag() && !cs.sps->getCCSAOEnabledFlag()) +#endif +#endif { return; } -#endif const PreCalcValues& pcv = *cs.pcv; PelUnitBuf dstYuv = cs.getRecoBuf(); @@ -1263,6 +1574,60 @@ void SampleAdaptiveOffset::jointClipSaoBifCcSao(CodingStructure& cs) } } } +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + if(compIdx == COMPONENT_Cb || compIdx == COMPONENT_Cr) + { + CBifParams& CBifParams = cs.picture->getCBifParam(); + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + + bool TU_VALID = false; + bool TU_CBF = false; + bool CTU_ON = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + //Cb or Cr + BIF_chroma = false; + CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(m_tempBuf, dstYuv, cs.slice->clpRng(compID) , currTU, isCb); + } + } + } + } + } +#endif } #endif } diff --git a/source/Lib/CommonLib/SampleAdaptiveOffset.h b/source/Lib/CommonLib/SampleAdaptiveOffset.h index ff661085a99e94af76ede7543540a3632fb22922..d5ed6c1827c56c5ae2c77918be2d54579f5b87ef 100644 --- a/source/Lib/CommonLib/SampleAdaptiveOffset.h +++ b/source/Lib/CommonLib/SampleAdaptiveOffset.h @@ -41,7 +41,7 @@ #include "CommonDef.h" #include "Unit.h" #include "Reshape.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "BilateralFilter.h" #endif //! \ingroup CommonLib @@ -74,7 +74,7 @@ public: void destroy(); static int getMaxOffsetQVal(const int channelBitDepth) { return (1<<(std::min<int>(channelBitDepth,MAX_SAO_TRUNCATED_BITDEPTH)-5))-1; } //Table 9-32, inclusive void setReshaper(Reshape * p) { m_pcReshape = p; } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter m_bilateralFilter; #endif #if RPR_ENABLE @@ -103,7 +103,9 @@ protected: , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail , bool isCtuCrossedByVirtualBoundaries, int horVirBndryPos[], int verVirBndryPos[], int numHorVirBndry, int numVerVirBndry ); -#if JVET_V0094_BILATERAL_FILTER || JVET_W0066_CCSAO +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER || JVET_W0066_CCSAO + void offsetBlockBIFonly(const int channelBitDepth, const ClpRng& clpRng, int typeIdx, int* offset, const Pel* srcBlk, Pel* resBlk, int srcStride, int resStride, int width, int height + , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail, CodingStructure &cs, const UnitArea &area); void offsetBlockNoClip(const int channelBitDepth, const ClpRng& clpRng, int typeIdx, int* offset , const Pel* srcBlk, Pel* resBlk, int srcStride, int resStride, int width, int height , bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isBelowLeftAvail, bool isBelowRightAvail); @@ -112,7 +114,7 @@ protected: void reconstructBlkSAOParam(SAOBlkParam& recParam, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES]); int getMergeList(CodingStructure& cs, int ctuRsAddr, SAOBlkParam* blkParams, SAOBlkParam* mergeList[NUM_SAO_MERGE_TYPES]); void offsetCTU(const UnitArea& area, const CPelUnitBuf& src, PelUnitBuf& res, SAOBlkParam& saoblkParam, CodingStructure& cs); -#if JVET_V0094_BILATERAL_FILTER || JVET_W0066_CCSAO +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER || JVET_W0066_CCSAO void offsetCTUnoClip( const UnitArea& area, const CPelUnitBuf& src, PelUnitBuf& res, SAOBlkParam& saoblkParam, CodingStructure& cs); #endif #if JVET_W0066_CCSAO diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 9b0a36b9af18b9fefdb7c8ff663caea96b603b41..00892e59e3e83d4860c38db5ce977ba2966950a3 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -3396,6 +3396,11 @@ PPS::PPS() , m_BIFStrength (1) , m_BIFQPOffset (0) #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +, m_CBIF (false) +, m_CBIFStrength (1) +, m_CBIFQPOffset (0) +#endif , pcv (NULL) { m_ChromaQpAdjTableIncludingNullEntry[0].u.comp.CbOffset = 0; // Array includes entry [0] for the null offset used when cu_chroma_qp_offset_flag=0. This is initialised here and never subsequently changed. diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index b55d01a23d0c222acbdf3b2caaedbf07cf9b6575..2e0be241533702cfd5e3e938f55314981ac59790 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -2292,6 +2292,11 @@ private: int m_BIFStrength; int m_BIFQPOffset; #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + bool m_CBIF; + int m_CBIFStrength; + int m_CBIFQPOffset; +#endif public: PreCalcValues *pcv; @@ -2494,6 +2499,14 @@ public: int getBIFStrength() const { return m_BIFStrength; } void setBIFQPOffset( int val) { m_BIFQPOffset = val; } int getBIFQPOffset() const { return m_BIFQPOffset; } +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + void setUseCBIF( bool b) { m_CBIF = b; } + bool getUseCBIF() const { return m_CBIF; } + void setCBIFStrength( int val) { m_CBIFStrength = val; } + int getCBIFStrength() const { return m_CBIFStrength; } + void setCBIFQPOffset( int val) { m_CBIFQPOffset = val; } + int getCBIFQPOffset() const { return m_CBIFQPOffset; } #endif void setDeblockingFilterControlPresentFlag( bool val ) { m_deblockingFilterControlPresentFlag = val; } bool getDeblockingFilterControlPresentFlag() const { return m_deblockingFilterControlPresentFlag; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 1c0334629cfd35e5ce18037ed6f5ea9b8a37845f..2bdf812acbe04cba61aa4419651a11862a850247 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -1,4 +1,4 @@ -/* The copyright in this software is being made available under the BSD +/* The copyright in this software is being made available under the BSD * License, included below. This software may be subject to other third party * and contributor rights, including patent rights, and no such rights are * granted under this license. @@ -157,6 +157,9 @@ #define EMBEDDED_APS 1 // Embed APS into picture header #define JVET_V0094_BILATERAL_FILTER 1 // Bilateral filter #define JVET_W0066_CCSAO 1 // JVET-W0066: Cross-component sample adaptive offset +#define JVET_X0071_LONGER_CCALF 1 // JVET-X0071/JVET-X0045: Longer filter for CCALF +#define JVET_X0071_ALF_BAND_CLASSIFIER 1 // JVET-X0071/JVET-X0070: Alternative band classifier for ALF +#define JVET_X0071_CHROMA_BILATERAL_FILTER 1 // JVET-X0071/JVET-X0067: Chroma bilateral filter // SIMD optimizations #if IF_12TAP @@ -174,6 +177,9 @@ #if JVET_V0094_BILATERAL_FILTER #define ENABLE_SIMD_BILATERAL_FILTER 1 #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +#define JVET_X0071_CHROMA_BILATERAL_FILTER_ENABLE_SIMD 1 +#endif #endif // tools @@ -1215,6 +1221,19 @@ public: std::vector<int> ctuOn; // bif_ctb_flag[][] }; #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +class CBifParams +{ +public: + int frmOn_Cb; // slice_bif_enabled_flag for chroma + int frmOn_Cr; // slice_bif_enabled_flag for chroma + int allCtuOn_Cb; // slice_bif_all_ctb_enabled_flag for chroma + int allCtuOn_Cr; // slice_bif_all_ctb_enabled_flag for chroma + int numBlocks; + std::vector<int> ctuOn_Cb; // bif_ctb_flag[][] for chroma + std::vector<int> ctuOn_Cr; // bif_ctb_flag[][] for chroma +}; +#endif struct BitDepths diff --git a/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h b/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h index a0a4652532432a7a4ce50ab62db9aa2c1365396b..84eb1385d56df3325681338bc9f23068932fe6ad 100644 --- a/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h +++ b/source/Lib/CommonLib/x86/AdaptiveLoopFilterX86.h @@ -1942,7 +1942,11 @@ static void simdCalcClass0(AlfClassifier **classifier, const Area &blkDst, const static void simdCalcClass1(AlfClassifier **classifier, const Area &blkDst, const Area &curBlk, int dirWindSize, int classDir, int noDir, int noAct, int bitDepth, int subBlkSize, int mappingDir[NUM_DIR_FIX][NUM_DIR_FIX], uint32_t **laplacian[NUM_DIRECTIONS]) { const __m128i shift = _mm_cvtsi32_si128(9 + bitDepth); +#if JVET_X0071_ALF_BAND_CLASSIFIER + const int multTab[] = { 16884, 4221, 1872, 1053, 675, 468 }; +#else const int multTab[] = { 5628, 1407, 624, 351, 225, 156 }; +#endif const __m128i mult = _mm_set1_epi32(multTab[dirWindSize]); const __m128i scale = _mm_set1_epi32(15); diff --git a/source/Lib/CommonLib/x86/BilateralFilterX86.h b/source/Lib/CommonLib/x86/BilateralFilterX86.h index 7af1e6828bc63391de20274f0ecda1513d01549f..d31526e6cbf1f5d6699d6798e7769e21fe297a41 100644 --- a/source/Lib/CommonLib/x86/BilateralFilterX86.h +++ b/source/Lib/CommonLib/x86/BilateralFilterX86.h @@ -43,7 +43,7 @@ #include <x86intrin.h> #endif -#if ENABLE_SIMD_BILATERAL_FILTER +#if ENABLE_SIMD_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER_ENABLE_SIMD #if JVET_W0066_CCSAO template<X86_VEXT vext> void BilateralFilter::simdFilterDiamond5x5NoClip(uint32_t uiWidth, uint32_t uiHeight, int16_t block[], int16_t blkFilt[], const ClpRng& clpRng, Pel* recPtr, int recStride, int iWidthExtSIMD, int bfac, int bif_round_add, int bif_round_shift, bool isRDO, const char* LUTrowPtr) diff --git a/source/Lib/CommonLib/x86/InitX86.cpp b/source/Lib/CommonLib/x86/InitX86.cpp index aa4c474abc0ad75a2afa32bb494e28b7e9da75f2..e1280950883219a735656d522c6ff3427d94b704 100644 --- a/source/Lib/CommonLib/x86/InitX86.cpp +++ b/source/Lib/CommonLib/x86/InitX86.cpp @@ -53,7 +53,7 @@ #if ENABLE_SIMD_SIGN_PREDICTION || TRANSFORM_SIMD_OPT || ENABLE_SIMD_TMP #include "CommonLib/TrQuant.h" #endif -#if ENABLE_SIMD_BILATERAL_FILTER +#if ENABLE_SIMD_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER_ENABLE_SIMD #include "CommonLib/BilateralFilter.h" #endif @@ -216,7 +216,7 @@ void TrQuant::initTrQuantX86() } #endif -#if ENABLE_SIMD_BILATERAL_FILTER +#if ENABLE_SIMD_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER_ENABLE_SIMD void BilateralFilter::initBilateralFilterX86() { auto vext = read_x86_extension_flags(); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 5c27649f65470681c523ed7b1e914feabf6c4e05..2fedef749bca2d9aa5bf468db425be5b7969665c 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -327,11 +327,19 @@ void CABACReader::ccAlfFilterControlIdc(CodingStructure &cs, const ComponentID c if (leftAvail) { +#if JVET_X0071_LONGER_CCALF + ctxt += (filterControlIdc[curIdx - 1] != 1) ? 1 : 0; +#else ctxt += ( filterControlIdc[curIdx - 1] ) ? 1 : 0; +#endif } if (aboveAvail) { +#if JVET_X0071_LONGER_CCALF + ctxt += (filterControlIdc[curIdx - cs.pcv->widthInCtus] != 1) ? 1 : 0; +#else ctxt += ( filterControlIdc[curIdx - cs.pcv->widthInCtus] ) ? 1 : 0; +#endif } ctxt += ( compID == COMPONENT_Cr ) ? 3 : 0; @@ -343,6 +351,12 @@ void CABACReader::ccAlfFilterControlIdc(CodingStructure &cs, const ComponentID c idcVal++; } } + +#if JVET_X0071_LONGER_CCALF + int pos0 = 1; + idcVal = (idcVal == pos0 ? 0 : idcVal < pos0 ? idcVal + 1 : idcVal); +#endif + filterControlIdc[curIdx] = idcVal; DTRACE(g_trace_ctx, D_SYNTAX, "ccAlfFilterControlIdc() compID=%d pos=(%d,%d) ctxt=%d, filterCount=%d, idcVal=%d\n", @@ -360,13 +374,25 @@ void CABACReader::sao( CodingStructure& cs, unsigned ctuRsAddr ) const SPS& sps = *cs.sps; #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(!(cs.pps->getUseBIF() || cs.sps->getSAOEnabledFlag() || !(cs.pps->getUseCBIF()))) +#else // If neither BIF nor SAO is enabled, we can return. if(!(cs.pps->getUseBIF() || cs.sps->getSAOEnabledFlag())) +#endif { return; } // At least one is enabled, it is safe to assume we can do getSAO(). SAOBlkParam& sao_ctu_pars = cs.picture->getSAO()[ctuRsAddr]; +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(!(cs.pps->getUseCBIF() || cs.sps->getSAOEnabledFlag())) + { + return; + } + SAOBlkParam& sao_ctu_pars = cs.picture->getSAO()[ctuRsAddr]; +#endif #endif if( !sps.getSAOEnabledFlag() ) @@ -375,7 +401,7 @@ void CABACReader::sao( CodingStructure& cs, unsigned ctuRsAddr ) } const Slice& slice = *cs.slice; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER // The getSAO() function call has been moved up. #else SAOBlkParam& sao_ctu_pars = cs.picture->getSAO()[ctuRsAddr]; @@ -579,6 +605,139 @@ void CABACReader::bif(CodingStructure& cs, unsigned ctuRsAddr) } } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +void CABACReader::Cbif_Cb(CodingStructure& cs) +{ + int width = cs.picture->lwidth(); + int height = cs.picture->lheight(); + + int block_width = cs.pcv->maxCUWidth; + int block_height = cs.pcv->maxCUHeight; + + int width_in_blocks = width / block_width + (width % block_width != 0); + int height_in_blocks = height / block_height + (height % block_height != 0); + + for (int i = 0; i < width_in_blocks * height_in_blocks; i++) + { + Cbif_Cb(cs, i); + } +} + +void CABACReader::Cbif_Cb(CodingStructure& cs, unsigned ctuRsAddr) +{ + const PPS& pps = *cs.pps; + + if (!pps.getUseCBIF()) + { + return; + } + + CBifParams& CBifParams = cs.picture->getCBifParam(); + + if (ctuRsAddr == 0) + { + int width = cs.picture->lwidth(); + int height = cs.picture->lheight(); + int block_width = cs.pcv->maxCUWidth; + int block_height = cs.pcv->maxCUHeight; + + int width_in_blocks = width / block_width + (width % block_width != 0); + int height_in_blocks = height / block_height + (height % block_height != 0); + int num_blocks = width_in_blocks * height_in_blocks; + CBifParams.numBlocks = num_blocks; + CBifParams.ctuOn_Cb.resize(num_blocks); + std::fill(CBifParams.ctuOn_Cb.begin(), CBifParams.ctuOn_Cb.end(), 0); + } + if (ctuRsAddr == 0) + { + CBifParams.allCtuOn_Cb = m_BinDecoder.decodeBinEP(); + if (CBifParams.allCtuOn_Cb == 0) + CBifParams.frmOn_Cb = m_BinDecoder.decodeBinEP(); + } + int i = ctuRsAddr; + if (CBifParams.allCtuOn_Cb) + { + CBifParams.ctuOn_Cb[i] = 1; + } + else + { + if (CBifParams.frmOn_Cb) + { + CBifParams.ctuOn_Cb[i] = m_BinDecoder.decodeBin(Ctx::CBifCtrlFlags_Cb()); + } + else + { + CBifParams.ctuOn_Cb[i] = 0; + } + } +} + +void CABACReader::Cbif_Cr(CodingStructure& cs) +{ + int width = cs.picture->lwidth(); + int height = cs.picture->lheight(); + + int block_width = cs.pcv->maxCUWidth; + int block_height = cs.pcv->maxCUHeight; + + int width_in_blocks = width / block_width + (width % block_width != 0); + int height_in_blocks = height / block_height + (height % block_height != 0); + + for (int i = 0; i < width_in_blocks * height_in_blocks; i++) + { + Cbif_Cr(cs, i); + } +} + +void CABACReader::Cbif_Cr(CodingStructure& cs, unsigned ctuRsAddr) +{ + const PPS& pps = *cs.pps; + + if (!pps.getUseCBIF()) + { + return; + } + + CBifParams& CBifParams = cs.picture->getCBifParam(); + + if (ctuRsAddr == 0) + { + int width = cs.picture->lwidth(); + int height = cs.picture->lheight(); + int block_width = cs.pcv->maxCUWidth; + int block_height = cs.pcv->maxCUHeight; + + int width_in_blocks = width / block_width + (width % block_width != 0); + int height_in_blocks = height / block_height + (height % block_height != 0); + int num_blocks = width_in_blocks * height_in_blocks; + CBifParams.numBlocks = num_blocks; + CBifParams.ctuOn_Cr.resize(num_blocks); + std::fill(CBifParams.ctuOn_Cr.begin(), CBifParams.ctuOn_Cr.end(), 0); + } + if (ctuRsAddr == 0) + { + CBifParams.allCtuOn_Cr = m_BinDecoder.decodeBinEP(); + if (CBifParams.allCtuOn_Cr == 0) + CBifParams.frmOn_Cr = m_BinDecoder.decodeBinEP(); + } + int i = ctuRsAddr; + if (CBifParams.allCtuOn_Cr) + { + CBifParams.ctuOn_Cr[i] = 1; + } + else + { + if (CBifParams.frmOn_Cr) + { + CBifParams.ctuOn_Cr[i] = m_BinDecoder.decodeBin(Ctx::CBifCtrlFlags_Cr()); + } + else + { + CBifParams.ctuOn_Cr[i] = 0; + } + } +} +#endif #if JVET_W0066_CCSAO void CABACReader::ccSaoControlIdc(CodingStructure &cs, const ComponentID compID, const int curIdx, diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 479185d5ac0e0f54fa0122e4c265be2719edd40e..cc22363f7014cfc763f43cd2026286377a9f6b91 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -72,6 +72,12 @@ public: void bif (CodingStructure& cs); void bif (CodingStructure& cs, unsigned ctuRsAddr); #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + void Cbif_Cb (CodingStructure& cs); + void Cbif_Cb (CodingStructure& cs, unsigned ctuRsAddr); + void Cbif_Cr (CodingStructure& cs); + void Cbif_Cr (CodingStructure& cs, unsigned ctuRsAddr); +#endif #if JVET_W0066_CCSAO void ccSaoControlIdc ( CodingStructure &cs, const ComponentID compID, const int curIdx, uint8_t *controlIdc, Position lumaPos, int setNum ); diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 1a215327f017ae9325b02058890aeec63a92ea69..1cb97cdb728fef1111d6e477add049984bbf4265 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -193,11 +193,19 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri else { #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if ( pic->cs->sps->getSAOEnabledFlag() || pic->cs->pps->getUseBIF() || pic->cs->pps->getUseCBIF()) +#else // Since the per-CTU BIF parameter is stored in SAO, we need to // do this copy even if SAO=0, if BIF=1. if ( pic->cs->sps->getSAOEnabledFlag() || pic->cs->pps->getUseBIF() ) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if ( pic->cs->sps->getSAOEnabledFlag() || pic->cs->pps->getUseCBIF()) #else if ( pic->cs->sps->getSAOEnabledFlag() ) +#endif #endif { pcEncPic->copySAO( *pic, 0 ); @@ -252,11 +260,19 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri pcDecLib->executeLoopFilters(); #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if ( pic->cs->sps->getSAOEnabledFlag() || pic->cs->pps->getUseBIF() || pic->cs->pps->getUseCBIF()) +#else // Since the per-CTU BIF parameter is stored in SAO, we need to // do this copy even if SAO=0, if BIF=1. if ( pic->cs->sps->getSAOEnabledFlag() || pic->cs->pps->getUseBIF() ) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if ( pic->cs->sps->getSAOEnabledFlag() || pic->cs->pps->getUseCBIF()) #else if ( pic->cs->sps->getSAOEnabledFlag() ) +#endif #endif { pcEncPic->copySAO( *pic, 1 ); @@ -518,7 +534,7 @@ void DecLib::create() { m_apcSlicePilot = new Slice; m_uiSliceSegmentIdx = 0; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_cBilateralFilter.create(); #endif } @@ -535,7 +551,7 @@ void DecLib::destroy() } m_cSliceDecoder.destroy(); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_cBilateralFilter.destroy(); #endif } @@ -701,9 +717,17 @@ void DecLib::executeLoopFilters() #endif #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if( cs.sps->getSAOEnabledFlag() || cs.pps->getUseBIF() || cs.pps->getUseCBIF()) +#else if( cs.sps->getSAOEnabledFlag() || cs.pps->getUseBIF()) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if( cs.sps->getSAOEnabledFlag() || cs.pps->getUseCBIF()) #else if( cs.sps->getSAOEnabledFlag() ) +#endif #endif { m_cSAO.SAOProcess( cs, cs.picture->getSAO() ); diff --git a/source/Lib/DecoderLib/DecLib.h b/source/Lib/DecoderLib/DecLib.h index 4f27ca0e61ed9edb00d11e7e413c0ebec3b823d8..0e50dd28a7be1603761c2f58c561c29509d554c1 100644 --- a/source/Lib/DecoderLib/DecLib.h +++ b/source/Lib/DecoderLib/DecLib.h @@ -54,7 +54,7 @@ #include "CommonLib/SEI.h" #include "CommonLib/Unit.h" #include "CommonLib/Reshape.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "BilateralFilter.h" #endif @@ -100,7 +100,7 @@ private: SEIMessages m_SEIs; ///< List of SEI messages that have been received before the first slice and between slices, excluding prefix SEIs... -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter m_cBilateralFilter; #endif diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index 106ffb682e8a38c90050c54399c86b210cf704bb..cca8fdb9da3f7d158b34907b5585462d49442c27 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -242,6 +242,13 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb { cabacReader.bif(cs); } +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (ctuRsAddr == 0) + { + cabacReader.Cbif_Cb(cs); + cabacReader.Cbif_Cr(cs); + } #endif cabacReader.coding_tree_unit( cs, ctuArea, pic->m_prevQP, ctuRsAddr ); diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 4d372bd1681b308308d5b69216339afc33139470..a369af00e3dce06a2366d315caf0ec444941507d 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -810,6 +810,14 @@ void HLSyntaxReader::parsePPS( PPS* pcPPS ) READ_SVLC( iCode, "bilateral_filter_qp_offset" ); pcPPS->setBIFQPOffset( iCode); } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + READ_FLAG( uiCode, "chroma bilateral_filter_flag" ); pcPPS->setUseCBIF(uiCode != 0) ; + if(pcPPS->getUseCBIF()) + { + READ_CODE( 2, uiCode, "chroma bilateral_filter_strength" ); pcPPS->setCBIFStrength( uiCode); + READ_SVLC( iCode, "chroma bilateral_filter_qp_offset" ); pcPPS->setCBIFQPOffset( iCode); + } +#endif #if !JVET_S0132_HLS_REORDER READ_FLAG( uiCode, "weighted_pred_flag" ); // Use of Weighting Prediction (P_SLICE) @@ -1079,6 +1087,10 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) param.filterType[CHANNEL_TYPE_LUMA] = code ? ALF_FILTER_9_EXT : ALF_FILTER_EXT; for (int altIdx = 0; altIdx < param.numAlternativesLuma; ++altIdx) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + READ_FLAG(code, "alf_luma_classifier"); + param.lumaClassifierIdx[altIdx] = code; +#endif READ_FLAG(code, "alf_luma_clip"); param.nonLinearFlag[CHANNEL_TYPE_LUMA][altIdx] = code ? true : false; READ_UVLC(code, "alf_luma_num_filters_signalled_minus1"); @@ -1086,7 +1098,11 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) if (param.numLumaFilters[altIdx] > 1) { const int length = ceilLog2(param.numLumaFilters[altIdx]); +#if JVET_X0071_ALF_BAND_CLASSIFIER + for (int i = 0; i < ALF_NUM_CLASSES_CLASSIFIER[(int)param.lumaClassifierIdx[altIdx]]; i++) +#else for (int i = 0; i < MAX_NUM_ALF_CLASSES; i++) +#endif { READ_CODE(length, code, "alf_luma_coeff_delta_idx"); param.filterCoeffDeltaIdx[altIdx][i] = code; @@ -1188,7 +1204,7 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) short *coeff = ccAlfParam.ccAlfCoeff[ccIdx][filterIdx]; // Filter coefficients for (int i = 0; i < alfShape.numCoeff - 1; i++) - { + { READ_CODE(CCALF_BITS_PER_COEFF_LEVEL, code, ccIdx == 0 ? "alf_cc_cb_mapped_coeff_abs" : "alf_cc_cr_mapped_coeff_abs"); if (code == 0) @@ -4144,6 +4160,7 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par { READ_FLAG(uiCode, "slice_alf_enabled_flag"); pcSlice->setTileGroupAlfEnabledFlag(COMPONENT_Y, uiCode); + int alfCbEnabledFlag = 0; int alfCrEnabledFlag = 0; @@ -4199,6 +4216,7 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par { READ_FLAG(uiCode, "slice_cc_alf_cb_enabled_flag"); pcSlice->setTileGroupCcAlfCbEnabledFlag(uiCode); + filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] = (uiCode == 1) ? true : false; pcSlice->setTileGroupCcAlfCbApsId(-1); if (filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1]) diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 0400cd715f2daf2b2b08caf7454bfc052df3e5bf..f9c8e4e4244c917ee1554b38b81806d55a12bfe9 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -178,7 +178,69 @@ void CABACWriter::bif(const Slice& slice, const BifParams& bifParams, unsigned c } } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +void CABACWriter::Cbif_Cb(const Slice& slice, const CBifParams& CBifParams) +{ + for (int i = 0; i < CBifParams.numBlocks; ++i) + { + Cbif_Cb(slice, CBifParams, i); + } +} + +void CABACWriter::Cbif_Cb(const Slice& slice, const CBifParams& CBifParams, unsigned ctuRsAddr) +{ + const PPS& pps = *slice.getPPS(); + if (!pps.getUseCBIF()) + { + return; + } + + if (ctuRsAddr == 0) + { + m_BinEncoder.encodeBinEP(CBifParams.allCtuOn_Cb); + if (CBifParams.allCtuOn_Cb == 0) + { + m_BinEncoder.encodeBinEP(CBifParams.frmOn_Cb); + } + } + if (CBifParams.allCtuOn_Cb == 0 && CBifParams.frmOn_Cb) + { + int i = ctuRsAddr; + m_BinEncoder.encodeBin(CBifParams.ctuOn_Cb[i], Ctx::CBifCtrlFlags_Cb()); + } +} +void CABACWriter::Cbif_Cr(const Slice& slice, const CBifParams& CBifParams) +{ + for (int i = 0; i < CBifParams.numBlocks; ++i) + { + Cbif_Cr(slice, CBifParams, i); + } +} + +void CABACWriter::Cbif_Cr(const Slice& slice, const CBifParams& CBifParams, unsigned ctuRsAddr) +{ + const PPS& pps = *slice.getPPS(); + if (!pps.getUseCBIF()) + { + return; + } + + if (ctuRsAddr == 0) + { + m_BinEncoder.encodeBinEP(CBifParams.allCtuOn_Cr); + if (CBifParams.allCtuOn_Cr == 0) + { + m_BinEncoder.encodeBinEP(CBifParams.frmOn_Cr); + } + } + if (CBifParams.allCtuOn_Cr == 0 && CBifParams.frmOn_Cr) + { + int i = ctuRsAddr; + m_BinEncoder.encodeBin(CBifParams.ctuOn_Cr[i], Ctx::CBifCtrlFlags_Cr()); + } +} +#endif //================================================================================ // clause 7.3.8.2 @@ -4616,6 +4678,54 @@ void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr, } } + +#if JVET_X0071_LONGER_CCALF +void CABACWriter::codeCcAlfFilterControlIdc(uint8_t idcVal, CodingStructure &cs, const ComponentID compID, + const int curIdx, const uint8_t *filterControlIdc, Position lumaPos, + const int filterCount) +{ + CHECK(idcVal > filterCount, "Filter index is too large"); + + const uint32_t curSliceIdx = cs.slice->getIndependentSliceIdx(); + const uint32_t curTileIdx = cs.pps->getTileIdx(lumaPos); + Position leftLumaPos = lumaPos.offset(-(int)cs.pcv->maxCUWidth, 0); + Position aboveLumaPos = lumaPos.offset(0, -(int)cs.pcv->maxCUWidth); + bool leftAvail = cs.getCURestricted(leftLumaPos, lumaPos, curSliceIdx, curTileIdx, CH_L) ? true : false; + bool aboveAvail = cs.getCURestricted(aboveLumaPos, lumaPos, curSliceIdx, curTileIdx, CH_L) ? true : false; + int ctxt = 0; + + if (leftAvail) + { + ctxt += (filterControlIdc[curIdx - 1] != 1) ? 1 : 0; + } + if (aboveAvail) + { + ctxt += (filterControlIdc[curIdx - cs.pcv->widthInCtus] != 1) ? 1 : 0; + } + ctxt += (compID == COMPONENT_Cr) ? 3 : 0; + + int pos0 = 1; + unsigned mappedIdc = (idcVal == 0 ? pos0 : idcVal <= pos0 ? idcVal - 1 : idcVal); + + m_BinEncoder.encodeBin((mappedIdc == 0) ? 0 : 1, Ctx::CcAlfFilterControlFlag(ctxt)); // ON/OFF flag is context coded + if (mappedIdc > 0) + { + int val = (mappedIdc - 1); + while (val) + { + m_BinEncoder.encodeBinEP(1); + val--; + } + if (mappedIdc < filterCount) + { + m_BinEncoder.encodeBinEP(0); + } + } + DTRACE(g_trace_ctx, D_SYNTAX, "ccAlfFilterControlIdc() compID=%d pos=(%d,%d) ctxt=%d, filterCount=%d, idcVal=%d\n", compID, lumaPos.x, lumaPos.y, ctxt, filterCount, idcVal); +} + +#else + void CABACWriter::codeCcAlfFilterControlIdc(uint8_t idcVal, CodingStructure &cs, const ComponentID compID, const int curIdx, const uint8_t *filterControlIdc, Position lumaPos, const int filterCount) @@ -4657,6 +4767,10 @@ void CABACWriter::codeCcAlfFilterControlIdc(uint8_t idcVal, CodingStructure &cs, DTRACE( g_trace_ctx, D_SYNTAX, "ccAlfFilterControlIdc() compID=%d pos=(%d,%d) ctxt=%d, filterCount=%d, idcVal=%d\n", compID, lumaPos.x, lumaPos.y, ctxt, filterCount, idcVal ); } +#endif + + + void CABACWriter::code_unary_fixed( unsigned symbol, unsigned ctxId, unsigned unary_max, unsigned fixed ) { bool unary = (symbol <= unary_max); diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index 7222db36ecfa06a2c8ed56277e8d809101802712..1a2755e923370a4c98ad9fcd68beb19515d117c9 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -84,6 +84,12 @@ public: void bif (const Slice& slice, const BifParams& BifParams); void bif (const Slice& slice, const BifParams& BifParams, unsigned ctuRsAddr); #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + void Cbif_Cb (const Slice& slice, const CBifParams& CBifParams); + void Cbif_Cb (const Slice& slice, const CBifParams& CBifParams, unsigned ctuRsAddr); + void Cbif_Cr (const Slice& slice, const CBifParams& CBifParams); + void Cbif_Cr (const Slice& slice, const CBifParams& CBifParams, unsigned ctuRsAddr); +#endif #if JVET_W0066_CCSAO void codeCcSaoControlIdc ( uint8_t idcVal, CodingStructure &cs, const ComponentID compID, const int curIdx, const uint8_t *controlIdc, Position lumaPos, const int setNum ); diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index fdbb07c95dd89a17158f14cf009a581ed266b4da..b168a1e33f177bdafe045d0aa12d4c78fac7a646 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -509,8 +509,41 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co std::fill_n( m_ctuAlternativeTmp[compIdx], m_numCTUsInPic, 0 ); } ChannelType chType = toChannelType( ComponentID( compIdx ) ); +#if !JVET_X0071_ALF_BAND_CLASSIFIER int numClasses = compIdx ? 1 : MAX_NUM_ALF_CLASSES; +#endif #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + int numClassifier = compIdx ? 1 : ALF_NUM_CLASSIFIER; + m_alfCovariance[compIdx] = new AlfCovariance****[m_filterShapes[chType].size()]; + for( int i = 0; i != m_filterShapes[chType].size(); i++ ) + { + m_alfCovariance[compIdx][i] = nullptr; + if( m_filterTypeTest[chType][m_filterShapes[chType][i].filterType] == false ) + { + continue; + } + m_alfCovariance[compIdx][i] = new AlfCovariance***[m_numCTUsInPic]; + int numFixedFilterSets = ( m_filterShapes[chType][i].filterType == ALF_FILTER_EXT || m_filterShapes[chType][i].filterType == ALF_FILTER_9_EXT ) ? 2 : 1; + for( int j = 0; j < m_numCTUsInPic; j++ ) + { + m_alfCovariance[compIdx][i][j] = new AlfCovariance**[numFixedFilterSets]; + for( int fixedFilterSetIdx = 0; fixedFilterSetIdx < numFixedFilterSets; fixedFilterSetIdx++ ) + { + m_alfCovariance[compIdx][i][j][fixedFilterSetIdx] = new AlfCovariance*[numClassifier]; + for( int l = 0; l < numClassifier; l++ ) + { + int numClasses = compIdx ? 1 : ALF_NUM_CLASSES_CLASSIFIER[l]; + m_alfCovariance[compIdx][i][j][fixedFilterSetIdx][l] = new AlfCovariance[numClasses]; + for( int k = 0; k < numClasses; k++ ) + { + m_alfCovariance[compIdx][i][j][fixedFilterSetIdx][l][k].create(m_filterShapes[chType][i].numCoeff); + } + } + } + } + } +#else m_alfCovariance[compIdx] = new AlfCovariance***[m_filterShapes[chType].size()]; for( int i = 0; i != m_filterShapes[chType].size(); i++ ) { @@ -534,6 +567,7 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co } } } +#endif #else m_alfCovariance[compIdx] = new AlfCovariance**[m_filterShapes[chType].size()]; @@ -726,7 +760,9 @@ void EncAdaptiveLoopFilter::destroy() if( m_alfCovariance[compIdx] ) { ChannelType chType = toChannelType( ComponentID( compIdx ) ); +#if !JVET_X0071_ALF_BAND_CLASSIFIER int numClasses = compIdx ? 1 : MAX_NUM_ALF_CLASSES; +#endif for( int i = 0; i != m_filterShapes[chType].size(); i++ ) { @@ -740,6 +776,24 @@ void EncAdaptiveLoopFilter::destroy() for( int j = 0; j < m_numCTUsInPic; j++ ) { #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + int numClassifier = compIdx ? 1 : ALF_NUM_CLASSIFIER; + for( int fixedFilterSetIdx = 0; fixedFilterSetIdx < numFixedFilterSet; fixedFilterSetIdx++ ) + { + for( int l = 0; l < numClassifier; l++ ) + { + int numClasses = compIdx ? 1 : ALF_NUM_CLASSES_CLASSIFIER[l]; + for( int k = 0; k < numClasses; k++ ) + { + m_alfCovariance[compIdx][i][j][fixedFilterSetIdx][l][k].destroy(); + } + delete[] m_alfCovariance[compIdx][i][j][fixedFilterSetIdx][l]; + m_alfCovariance[compIdx][i][j][fixedFilterSetIdx][l] = nullptr; + } + delete[] m_alfCovariance[compIdx][i][j][fixedFilterSetIdx]; + m_alfCovariance[compIdx][i][j][fixedFilterSetIdx] = nullptr; + } +#else for( int fixedFilterSetIdx = 0; fixedFilterSetIdx < numFixedFilterSet; fixedFilterSetIdx++ ) { for( int k = 0; k < numClasses; k++ ) @@ -749,6 +803,7 @@ void EncAdaptiveLoopFilter::destroy() delete[] m_alfCovariance[compIdx][i][j][fixedFilterSetIdx]; m_alfCovariance[compIdx][i][j][fixedFilterSetIdx] = nullptr; } +#endif #else for( int k = 0; k < numClasses; k++ ) { @@ -1184,11 +1239,15 @@ void EncAdaptiveLoopFilter::ALFProcess( CodingStructure& cs, const double *lambd const Area blkSrc( 0, 0, w, h ); const Area blkDst( xStart, yStart, w, h ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + deriveClassification( m_classifier, buf.get( COMPONENT_Y ), blkDst, blkSrc, cs, -1, ALF_NUM_CLASSIFIER ); +#else deriveClassification( m_classifier, buf.get( COMPONENT_Y ), blkDst, blkSrc #if ALF_IMPROVEMENT , cs, -1 #endif ); +#endif xStart = xEnd; } @@ -1199,11 +1258,15 @@ void EncAdaptiveLoopFilter::ALFProcess( CodingStructure& cs, const double *lambd else { Area blk( xPos, yPos, width, height ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + deriveClassification( m_classifier, recLuma, blk, blk , cs, -1, ALF_NUM_CLASSIFIER ); +#else deriveClassification( m_classifier, recLuma, blk, blk #if ALF_IMPROVEMENT , cs, -1 #endif ); +#endif } } } @@ -1429,7 +1492,12 @@ double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, cons m_ctuAlternative[compID][ctuIdx] = altIdx; m_CABACEstimator->codeAlfCtuAlternative(cs, ctuIdx, compID, &m_alfParamTemp, numAlts); double r_altCost = ctuLambda * FRAC_BITS_SCALE * m_CABACEstimator->getEstFracBits(); +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierFinal[altIdx]; + double altDist = getFilteredDistortion(m_alfCovariance[compID][iShapeIdx][ctuIdx][fixedFilterSetIdx][classifierIdx], ALF_NUM_CLASSES_CLASSIFIER[classifierIdx], m_alfParamTemp.numLumaFilters[altIdx] - 1, numCoeff, altIdx); +#else double altDist = getFilteredDistortion(m_alfCovariance[compID][iShapeIdx][ctuIdx][fixedFilterSetIdx], numClasses, m_alfParamTemp.numLumaFilters[altIdx] - 1, numCoeff, altIdx); +#endif double altCost = altDist + r_altCost; if (altCost < bestAltCost) @@ -1464,7 +1532,11 @@ double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, cons double altDist = 0.; #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + altDist += m_alfCovariance[compID][iShapeIdx][ctuIdx][0][0][0].calcErrorForCoeffs( m_filterClippSet[altIdx], m_filterCoeffSet[altIdx], numCoeff, m_NUM_BITS ); +#else altDist += m_alfCovariance[compID][iShapeIdx][ctuIdx][0][0].calcErrorForCoeffs( m_filterClippSet[altIdx], m_filterCoeffSet[altIdx], numCoeff, m_NUM_BITS ); +#endif #else altDist += m_alfCovariance[compID][iShapeIdx][ctuIdx][0].calcErrorForCoeffs( m_filterClippSet[altIdx], m_filterCoeffSet[altIdx], numCoeff, m_NUM_BITS ); #endif @@ -1776,24 +1848,40 @@ double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double #if ALF_IMPROVEMENT for (int altIdx = 0; altIdx < m_alfParamTemp.numAlternativesLuma; ++altIdx) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + AlfParam bestSliceParam; + double bestCost = MAX_DOUBLE; + double bestDist = MAX_DOUBLE; + int bestCoeffBits = 0; + for( int classifierIdx = 0; classifierIdx < ALF_NUM_CLASSIFIER; classifierIdx++ ) + { +#endif //collect stat based on CTU decision if ( bReCollectStat ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + getFrameStats( channel, iShapeIdx, altIdx, fixedFilterSetIdx, classifierIdx ); +#else getFrameStats( channel, iShapeIdx, altIdx #if ALF_IMPROVEMENT , fixedFilterSetIdx #endif ); +#endif } assert(alfFilterShape.numCoeff == m_alfCovarianceFrame[channel][iShapeIdx][0].numCoeff); - +#if !JVET_X0071_ALF_BAND_CLASSIFIER AlfParam bestSliceParam; double bestCost = MAX_DOUBLE; double bestDist = MAX_DOUBLE; int bestCoeffBits = 0; +#endif const int nonLinearFlagMax = m_encCfg->getUseNonLinearAlfLuma() ? 2 : 1; for (int nonLinearFlag = 0; nonLinearFlag < nonLinearFlagMax; nonLinearFlag++) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_alfParamTemp.lumaClassifierIdx[altIdx] = classifierIdx; +#endif m_alfParamTemp.nonLinearFlag[channel][altIdx] = nonLinearFlag; std::fill_n(m_alfClipMerged[iShapeIdx][0][0], MAX_NUM_ALF_LUMA_COEFF*MAX_NUM_ALF_CLASSES*MAX_NUM_ALF_CLASSES, m_alfParamTemp.nonLinearFlag[channel][altIdx] ? AlfNumClippingValues[CHANNEL_TYPE_LUMA] / 2 : 0); @@ -1801,7 +1889,11 @@ double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double m_alfCovarianceMerged[iShapeIdx][MAX_NUM_ALF_CLASSES].reset(AlfNumClippingValues[channel]); m_alfCovarianceMerged[iShapeIdx][MAX_NUM_ALF_CLASSES + 1].reset(AlfNumClippingValues[channel]); int curCoeffBits; +#if JVET_X0071_ALF_BAND_CLASSIFIER + double curDist = mergeFiltersAndCost(m_alfParamTemp, alfFilterShape, m_alfCovarianceFrame[channel][iShapeIdx], m_alfCovarianceMerged[iShapeIdx], m_alfClipMerged[iShapeIdx], curCoeffBits, altIdx, classifierIdx, m_alfParamTemp.numLumaFilters[altIdx]); +#else double curDist = mergeFiltersAndCost(m_alfParamTemp, alfFilterShape, m_alfCovarianceFrame[channel][iShapeIdx], m_alfCovarianceMerged[iShapeIdx], m_alfClipMerged[iShapeIdx], curCoeffBits, altIdx); +#endif double cost = curDist + m_lambda[channel] * curCoeffBits; if (cost < bestCost) { @@ -1811,6 +1903,9 @@ double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double bestSliceParam = m_alfParamTemp; } }//for (int nonLinearFlag) +#if JVET_X0071_ALF_BAND_CLASSIFIER + }//for(int classifierIdx) +#endif uiCoeffBits += bestCoeffBits; dist += bestDist; m_alfParamTemp = bestSliceParam; @@ -1841,11 +1936,15 @@ double EncAdaptiveLoopFilter::getFilterCoeffAndCost( CodingStructure& cs, double //collect stat based on CTU decision if ( bReCollectStat ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + getFrameStats( channel, iShapeIdx, altIdx, fixedFilterSetIdx, 0 ); +#else getFrameStats( channel, iShapeIdx, altIdx #if ALF_IMPROVEMENT , fixedFilterSetIdx #endif ); +#endif } assert(alfFilterShape.numCoeff == m_alfCovarianceFrame[channel][iShapeIdx][0].numCoeff); @@ -2020,32 +2119,72 @@ double EncAdaptiveLoopFilter::getFilteredDistortion( AlfCovariance* cov, const i return dist; } +#if JVET_X0071_ALF_BAND_CLASSIFIER +double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfParam& alfParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits, int altIdx, int classifierIdx, int numFiltersLinear ) +#else double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfParam& alfParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits #if ALF_IMPROVEMENT , int altIdx #endif ) +#endif { int numFiltersBest = 0; +#if JVET_X0071_ALF_BAND_CLASSIFIER + int numFilters = ALF_NUM_CLASSES_CLASSIFIER[classifierIdx]; +#else int numFilters = MAX_NUM_ALF_CLASSES; +#endif bool codedVarBins[MAX_NUM_ALF_CLASSES]; double errorForce0CoeffTab[MAX_NUM_ALF_CLASSES][2]; double cost, cost0, dist, distForce0, costMin = MAX_DOUBLE; int coeffBits, coeffBitsForce0; - +#if JVET_X0071_ALF_BAND_CLASSIFIER + int maxNumFilters = m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][altIdx] ? std::min( numFiltersLinear + 3, numFilters ) : numFilters; + int bestCoeff[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF]; + int bestClipp[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF]; + double bestDist = 0; + int bestBits = 0; + bool bestCodedVarBins[MAX_NUM_ALF_CLASSES] = { false }; + bool bestAlfLumaCoeffDeltaFlag = false; + static int mergedPair[MAX_NUM_ALF_CLASSES][2] = { 0 }; + int mergedCoeff[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF] = { 0 }; + double mergedErr[MAX_NUM_ALF_CLASSES] = { 0 }; + if( m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][altIdx] == false ) + { + memset( mergedPair, 0, sizeof( mergedPair ) ); + mergeClasses( alfShape, covFrame, covMerged, clipMerged, numFilters, m_filterIndices, altIdx, mergedPair ); + } + else + { + for (int i = 0; i < numFilters; i++) + { + for (int j = 0; j < numFilters; j++) + { + std::fill_n(clipMerged[i][j], MAX_NUM_ALF_LUMA_COEFF, 2); + } + } + } + numFilters = maxNumFilters; +#else mergeClasses( alfShape, covFrame, covMerged, clipMerged, MAX_NUM_ALF_CLASSES, m_filterIndices #if ALF_IMPROVEMENT , altIdx #endif ); +#endif while( numFilters >= 1 ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + dist = deriveFilterCoeffs(covFrame, covMerged, clipMerged, alfShape, m_filterIndices[numFilters - 1], numFilters, errorForce0CoeffTab, alfParam, m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][altIdx], classifierIdx, numFilters == maxNumFilters ? true : false, mergedPair, mergedCoeff, mergedErr); +#else dist = deriveFilterCoeffs(covFrame, covMerged, clipMerged, alfShape, m_filterIndices[numFilters - 1], numFilters, errorForce0CoeffTab, alfParam #if ALF_IMPROVEMENT , m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][altIdx] #endif ); +#endif // filter coeffs are stored in m_filterCoeffSet distForce0 = getDistForce0( alfShape, numFilters, errorForce0CoeffTab, codedVarBins #if ALF_IMPROVEMENT @@ -2062,19 +2201,61 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfParam& alfParam, AlfFilter cost = dist + m_lambda[COMPONENT_Y] * coeffBits; cost0 = distForce0 + m_lambda[COMPONENT_Y] * coeffBitsForce0; +#if JVET_X0071_ALF_BAND_CLASSIFIER + bool cost0better = false; +#endif + if( cost0 < cost ) { cost = cost0; +#if JVET_X0071_ALF_BAND_CLASSIFIER + cost0better = true; +#endif } if( cost <= costMin ) { costMin = cost; numFiltersBest = numFilters; +#if JVET_X0071_ALF_BAND_CLASSIFIER + memcpy( bestCodedVarBins, codedVarBins, sizeof( codedVarBins ) ); + for( int varInd = 0; varInd < numFilters; varInd++ ) + { + if( cost0better && ( !bestCodedVarBins[varInd] ) ) + { + memset( bestCoeff[varInd], 0, sizeof(int)*MAX_NUM_ALF_LUMA_COEFF ); + memset( bestClipp[varInd], 0, sizeof(int)*MAX_NUM_ALF_LUMA_COEFF ); + } + else + { + memcpy( bestCoeff[varInd], m_filterCoeffSet[varInd], sizeof(int)*MAX_NUM_ALF_LUMA_COEFF ); + memcpy( bestClipp[varInd], m_filterClippSet[varInd], sizeof(int)*MAX_NUM_ALF_LUMA_COEFF ); + } + } + if( cost0better ) + { + bestDist = distForce0; + bestBits = coeffBitsForce0; + bestAlfLumaCoeffDeltaFlag = 1; + } + else + { + bestDist = dist; + bestBits = coeffBits; + bestAlfLumaCoeffDeltaFlag = 0; + } +#endif } numFilters--; } +#if JVET_X0071_ALF_BAND_CLASSIFIER + double distReturn = bestDist; + uiCoeffBits = bestBits; + alfParam.alfLumaCoeffDeltaFlag = bestAlfLumaCoeffDeltaFlag; + memcpy( alfParam.alfLumaCoeffFlag, bestCodedVarBins, sizeof( bestCodedVarBins ) ); + alfParam.numLumaFilters[altIdx] = numFiltersBest; +#else dist = deriveFilterCoeffs( covFrame, covMerged, clipMerged, alfShape, m_filterIndices[numFiltersBest - 1], numFiltersBest, errorForce0CoeffTab, alfParam #if ALF_IMPROVEMENT , m_alfParamTemp.nonLinearFlag[CHANNEL_TYPE_LUMA][altIdx] @@ -2122,17 +2303,27 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfParam& alfParam, AlfFilter } } } +#endif #if ALF_IMPROVEMENT for (int ind = 0; ind < alfParam.numLumaFilters[altIdx]; ++ind) { for (int i = 0; i < alfShape.numCoeff; i++) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + alfParam.lumaCoeff[altIdx][ind * MAX_NUM_ALF_LUMA_COEFF + i] = bestCoeff[ind][i]; + alfParam.lumaClipp[altIdx][ind * MAX_NUM_ALF_LUMA_COEFF + i] = bestClipp[ind][i]; +#else alfParam.lumaCoeff[altIdx][ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterCoeffSet[ind][i]; alfParam.lumaClipp[altIdx][ind * MAX_NUM_ALF_LUMA_COEFF + i] = m_filterClippSet[ind][i]; +#endif } } memcpy( alfParam.filterCoeffDeltaIdx[altIdx], m_filterIndices[numFiltersBest - 1], sizeof(short) * MAX_NUM_ALF_CLASSES ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + uiCoeffBits += getNonFilterCoeffRate(alfParam, altIdx, classifierIdx); +#else uiCoeffBits += getNonFilterCoeffRate(alfParam, altIdx); +#endif #else for( int ind = 0; ind < alfParam.numLumaFilters; ++ind ) { @@ -2149,11 +2340,15 @@ double EncAdaptiveLoopFilter::mergeFiltersAndCost( AlfParam& alfParam, AlfFilter return distReturn; } +#if JVET_X0071_ALF_BAND_CLASSIFIER +int EncAdaptiveLoopFilter::getNonFilterCoeffRate( AlfParam& alfParam, int altIdx, int classifierIdx ) +#else int EncAdaptiveLoopFilter::getNonFilterCoeffRate( AlfParam& alfParam #if ALF_IMPROVEMENT , int altIdx #endif ) +#endif { #if ALF_IMPROVEMENT CHECK( alfParam.numLumaFilters[altIdx] < 1, "Wrong number of alfParam.numLumaFilters[altIdx]" ); @@ -2175,11 +2370,18 @@ int EncAdaptiveLoopFilter::getNonFilterCoeffRate( AlfParam& alfParam { const int coeffLength = ceilLog2(alfParam.numLumaFilters); #endif +#if JVET_X0071_ALF_BAND_CLASSIFIER + for( int i = 0; i < ALF_NUM_CLASSES_CLASSIFIER[classifierIdx]; i++ ) +#else for( int i = 0; i < MAX_NUM_ALF_CLASSES; i++ ) +#endif { len += coeffLength; // alf_luma_coeff_delta_idx u(v) } } +#if JVET_X0071_ALF_BAND_CLASSIFIER + len++; +#endif return len; } @@ -2478,20 +2680,35 @@ int EncAdaptiveLoopFilter::lengthGolomb(int coeffVal, int k, bool signed_coeff) } #endif +#if JVET_X0071_ALF_BAND_CLASSIFIER +double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfParam& alfParam, bool nonLinear, int classifierIdx, bool isMaxNum, int mergedPair[MAX_NUM_ALF_CLASSES][2], int mergedCoeff[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], double mergedErr[MAX_NUM_ALF_CLASSES] ) +#else double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfParam& alfParam #if ALF_IMPROVEMENT , bool nonLinear #endif ) +#endif { double error = 0.0; AlfCovariance& tmpCov = covMerged[MAX_NUM_ALF_CLASSES]; - +#if JVET_X0071_ALF_BAND_CLASSIFIER + int changedClass = -1; + if( !isMaxNum ) + { + memcpy( clipMerged[numFilters - 1], clipMerged[numFilters], sizeof( int[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF] ) ); + } +#endif for( int filtIdx = 0; filtIdx < numFilters; filtIdx++ ) { tmpCov.reset(); bool found_clip = false; +#if JVET_X0071_ALF_BAND_CLASSIFIER + bool changedFilter = isMaxNum; + for( int classIdx = 0; classIdx < ALF_NUM_CLASSES_CLASSIFIER[classifierIdx]; classIdx++ ) +#else for( int classIdx = 0; classIdx < MAX_NUM_ALF_CLASSES; classIdx++ ) +#endif { if( filterIndices[classIdx] == filtIdx ) { @@ -2499,7 +2716,20 @@ double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovaria if( !found_clip ) { found_clip = true; // clip should be at the adress of shortest one - memcpy(m_filterClippSet[filtIdx], clipMerged[numFilters-1][classIdx], sizeof(int[MAX_NUM_ALF_LUMA_COEFF])); +#if JVET_X0071_ALF_BAND_CLASSIFIER + if( changedFilter == false && mergedPair[numFilters][0] == classIdx ) + { + changedFilter = true; + if( nonLinear ) + { + std::fill_n(clipMerged[numFilters - 1][classIdx], MAX_NUM_ALF_LUMA_COEFF, 2); + } + } + changedClass = classIdx; + memcpy( m_filterCoeffSet[filtIdx], mergedCoeff[classIdx], sizeof( int[MAX_NUM_ALF_LUMA_COEFF] ) ); + errorTabForce0Coeff[filtIdx][1] = mergedErr[classIdx]; +#endif + memcpy(m_filterClippSet[filtIdx], clipMerged[numFilters - 1][classIdx], sizeof(int[MAX_NUM_ALF_LUMA_COEFF])); } } } @@ -2507,7 +2737,20 @@ double EncAdaptiveLoopFilter::deriveFilterCoeffs( AlfCovariance* cov, AlfCovaria // Find coeffcients assert(alfShape.numCoeff == tmpCov.numCoeff); #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + if( changedFilter ) + { + errorTabForce0Coeff[filtIdx][1] = tmpCov.pixAcc + deriveCoeffQuant( m_filterClippSet[filtIdx], m_filterCoeffSet[filtIdx], tmpCov, alfShape, m_NUM_BITS, nonLinear ); + if( nonLinear ) + { + memcpy( clipMerged[numFilters - 1][changedClass], m_filterClippSet[filtIdx], sizeof( int[MAX_NUM_ALF_LUMA_COEFF] ) ); + } + memcpy( mergedCoeff[changedClass], m_filterCoeffSet[filtIdx], sizeof( int[MAX_NUM_ALF_LUMA_COEFF] ) ); + mergedErr[changedClass] = errorTabForce0Coeff[filtIdx][1]; + } +#else errorTabForce0Coeff[filtIdx][1] = tmpCov.pixAcc + deriveCoeffQuant( m_filterClippSet[filtIdx], m_filterCoeffSet[filtIdx], tmpCov, alfShape, m_NUM_BITS, nonLinear ); +#endif #else errorTabForce0Coeff[filtIdx][1] = tmpCov.pixAcc + deriveCoeffQuant( m_filterClippSet[filtIdx], m_filterCoeffSet[filtIdx], tmpCov, alfShape, m_NUM_BITS, false ); #endif @@ -2605,12 +2848,15 @@ void EncAdaptiveLoopFilter::roundFiltCoeffCCALF(int16_t *filterCoeffQuant, doubl filterCoeffQuant[i] = CCALF_SMALL_TAB[best_index] * sign; } } - +#if JVET_X0071_ALF_BAND_CLASSIFIER +void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], const int numClasses, short filterIndices[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES] , const int altIdx, int mergedPair[MAX_NUM_ALF_CLASSES][2] ) +#else void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], const int numClasses, short filterIndices[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES] #if ALF_IMPROVEMENT , const int altIdx #endif ) +#endif { int tmpClip[MAX_NUM_ALF_LUMA_COEFF]; int bestMergeClip[MAX_NUM_ALF_LUMA_COEFF]; @@ -2742,7 +2988,22 @@ void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCov classChanged[bestToMergeIdx1][i] = classChanged[i][bestToMergeIdx1] = true; } #endif - +#if JVET_X0071_ALF_BAND_CLASSIFIER + mergedPair[numRemaining - 1][0] = bestToMergeIdx1; + mergedPair[numRemaining - 1][1] = bestToMergeIdx2; + if( numRemaining == 2 ) + { + int ind = 0; + for (int i = 0; i < numClasses; i++) + { + if( availableClass[i] ) + { + mergedPair[numRemaining - 2][ind] = i; + ind++; + } + } + } +#endif for( int i = 0; i < numClasses; i++ ) { if( indexList[i] == bestToMergeIdx2 ) @@ -2787,14 +3048,21 @@ void EncAdaptiveLoopFilter::mergeClasses( const AlfFilterShape& alfShape, AlfCov } } } - +#if JVET_X0071_ALF_BAND_CLASSIFIER +void EncAdaptiveLoopFilter::getFrameStats( ChannelType channel, int iShapeIdx, int altIdx, int fixedFilterSetIdx, int classifierIdx ) +#else void EncAdaptiveLoopFilter::getFrameStats( ChannelType channel, int iShapeIdx, int altIdx #if ALF_IMPROVEMENT , int fixedFilterSetIdx #endif ) +#endif { +#if JVET_X0071_ALF_BAND_CLASSIFIER + int numClasses = isLuma(channel) ? ALF_NUM_CLASSES_CLASSIFIER[classifierIdx] : 1; +#else int numClasses = isLuma( channel ) ? MAX_NUM_ALF_CLASSES : 1; +#endif for (int i = 0; i < numClasses; i++) { @@ -2803,13 +3071,21 @@ void EncAdaptiveLoopFilter::getFrameStats( ChannelType channel, int iShapeIdx, i if (isLuma(channel)) { #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_LUMA][iShapeIdx], m_alfCovariance[COMPONENT_Y][iShapeIdx], m_ctuEnableFlag[COMPONENT_Y], m_ctuAlternative[COMPONENT_Y], numClasses, altIdx, fixedFilterSetIdx, classifierIdx ); +#else getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_LUMA][iShapeIdx], m_alfCovariance[COMPONENT_Y][iShapeIdx], m_ctuEnableFlag[COMPONENT_Y], m_ctuAlternative[COMPONENT_Y], numClasses, altIdx, fixedFilterSetIdx ); +#endif #else getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_LUMA][iShapeIdx], m_alfCovariance[COMPONENT_Y][iShapeIdx], m_ctuEnableFlag[COMPONENT_Y], nullptr, numClasses, altIdx ); #endif } else { +#if JVET_X0071_ALF_BAND_CLASSIFIER + getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][iShapeIdx], m_alfCovariance[COMPONENT_Cb][iShapeIdx], m_ctuEnableFlag[COMPONENT_Cb], m_ctuAlternative[COMPONENT_Cb], numClasses, altIdx, fixedFilterSetIdx, classifierIdx ); + getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][iShapeIdx], m_alfCovariance[COMPONENT_Cr][iShapeIdx], m_ctuEnableFlag[COMPONENT_Cr], m_ctuAlternative[COMPONENT_Cr], numClasses, altIdx, fixedFilterSetIdx, classifierIdx ); +#else getFrameStat( m_alfCovarianceFrame[CHANNEL_TYPE_CHROMA][iShapeIdx], m_alfCovariance[COMPONENT_Cb][iShapeIdx], m_ctuEnableFlag[COMPONENT_Cb], m_ctuAlternative[COMPONENT_Cb], numClasses, altIdx #if ALF_IMPROVEMENT , fixedFilterSetIdx @@ -2820,11 +3096,16 @@ void EncAdaptiveLoopFilter::getFrameStats( ChannelType channel, int iShapeIdx, i , fixedFilterSetIdx #endif ); +#endif } } #if ALF_IMPROVEMENT -void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance*** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx, int fixedFilterSetIdx) +#if JVET_X0071_ALF_BAND_CLASSIFIER +void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance**** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx, int fixedFilterSetIdx, int classifierIdx ) +#else +void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance*** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx, int fixedFilterSetIdx ) +#endif #else void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx ) #endif @@ -2841,7 +3122,11 @@ void EncAdaptiveLoopFilter::getFrameStat( AlfCovariance* frameCov, AlfCovariance #if ALF_IMPROVEMENT if (altIdx == ctbAltIdx[ctuIdx]) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + frameCov[classIdx] += ctbCov[ctuIdx][fixedFilterSetIdx][classifierIdx][classIdx]; +#else frameCov[classIdx] += ctbCov[ctuIdx][fixedFilterSetIdx][classIdx]; +#endif } #else if( isLuma( channel ) || altIdx == ctbAltIdx[ctuIdx] ) @@ -2864,7 +3149,13 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit for( int compIdx = 0; compIdx < numberOfComponents; compIdx++ ) { const ComponentID compID = ComponentID( compIdx ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + for( int classifierIdx = 0; classifierIdx < (isLuma(compID) ? ALF_NUM_CLASSIFIER : 1); classifierIdx++ ) + { + const int numClasses = isLuma(compID) ? ALF_NUM_CLASSES_CLASSIFIER[classifierIdx] : 1; +#else const int numClasses = isLuma( compID ) ? MAX_NUM_ALF_CLASSES : 1; +#endif for( int shape = 0; shape != m_filterShapes[toChannelType( compID )].size(); shape++ ) { @@ -2882,7 +3173,11 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit #if ALF_IMPROVEMENT for( int fixedFilterSetIdx = 0; fixedFilterSetIdx < numFixedFilterSet; fixedFilterSetIdx++ ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_alfCovariance[compIdx][shape][ctuIdx][fixedFilterSetIdx][classifierIdx][classIdx].reset( AlfNumClippingValues[toChannelType(compID)] ); +#else m_alfCovariance[compIdx][shape][ctuIdx][fixedFilterSetIdx][classIdx].reset(AlfNumClippingValues[toChannelType(compID)]); +#endif } #else m_alfCovariance[compIdx][shape][ctuIdx][classIdx].reset(AlfNumClippingValues[toChannelType( compID )]); @@ -2890,6 +3185,9 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit } } } +#if JVET_X0071_ALF_BAND_CLASSIFIER + } +#endif } // init Frame stats buffers @@ -2982,7 +3280,14 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit #if ALF_IMPROVEMENT for (int fixedFilterSetIdx = 0; fixedFilterSetIdx < ((m_filterShapes[chType][shape].filterType == ALF_FILTER_EXT || m_filterShapes[chType][shape].filterType == ALF_FILTER_9_EXT) ? 2 : 1); fixedFilterSetIdx++) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + for (int classifierIdx = 0; classifierIdx < (compIdx ? 1 : ALF_NUM_CLASSIFIER); classifierIdx++) + { + getBlkStats<alfWSSD>( m_alfCovariance[compIdx][shape][ctuRsAddr][fixedFilterSetIdx][classifierIdx], m_filterShapes[chType][shape], compIdx ? nullptr : m_classifier[classifierIdx], org, orgStride, rec, recStride, compAreaDst, compArea, chType, fixedFilterSetIdx, classifierIdx ); + } +#else getBlkStats<alfWSSD>( m_alfCovariance[compIdx][shape][ctuRsAddr][fixedFilterSetIdx], m_filterShapes[chType][shape], compIdx ? nullptr : m_classifier, org, orgStride, rec, recStride, compAreaDst, compArea, chType, fixedFilterSetIdx); +#endif } #else getBlkStats( m_alfCovariance[compIdx][shape][ctuRsAddr], m_filterShapes[chType][shape], compIdx ? nullptr : m_classifier, org, orgStride, rec, recStride, compAreaDst, compArea, chType, ((compIdx == 0) ? m_alfVBLumaCTUHeight : m_alfVBChmaCTUHeight), (compIdx == 0) ? m_alfVBLumaPos : m_alfVBChmaPos ); @@ -3009,7 +3314,11 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit for( int classIdx = 0; classIdx < numClasses; classIdx++ ) { #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][0][0][classIdx]; +#else m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][0][classIdx]; +#endif #else m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][classIdx]; #endif @@ -3043,8 +3352,16 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit continue; } for( int fixedFilterSetIdx = 0; fixedFilterSetIdx < ((m_filterShapes[chType][shape].filterType == ALF_FILTER_EXT || m_filterShapes[chType][shape].filterType == ALF_FILTER_9_EXT) ? 2 : 1); fixedFilterSetIdx++ ) + { - getBlkStats<alfWSSD>( m_alfCovariance[compIdx][shape][ctuRsAddr][fixedFilterSetIdx], m_filterShapes[chType][shape], compIdx ? nullptr : m_classifier, org, orgStride, rec, recStride, compArea, compArea, chType, fixedFilterSetIdx); +#if JVET_X0071_ALF_BAND_CLASSIFIER + for( int classifierIdx = 0; classifierIdx < (compIdx ? 1 : ALF_NUM_CLASSIFIER); classifierIdx++ ) + { + getBlkStats<alfWSSD>( m_alfCovariance[compIdx][shape][ctuRsAddr][fixedFilterSetIdx][classifierIdx], m_filterShapes[chType][shape], compIdx ? nullptr : m_classifier[classifierIdx], org, orgStride, rec, recStride, compArea, compArea, chType, fixedFilterSetIdx, classifierIdx ); + } +#else + getBlkStats<alfWSSD>( m_alfCovariance[compIdx][shape][ctuRsAddr][fixedFilterSetIdx], m_filterShapes[chType][shape], compIdx ? nullptr : m_classifier, org, orgStride, rec, recStride, compArea, compArea, chType, fixedFilterSetIdx ); +#endif } #else getBlkStats( m_alfCovariance[compIdx][shape][ctuRsAddr], m_filterShapes[chType][shape], compIdx ? nullptr : m_classifier, org, orgStride, rec, recStride, compArea, compArea, chType, ( ( compIdx == 0 ) ? m_alfVBLumaCTUHeight : m_alfVBChmaCTUHeight ), ( compIdx == 0 ) ? m_alfVBLumaPos : m_alfVBChmaPos ); @@ -3053,7 +3370,11 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit for( int classIdx = 0; classIdx < numClasses; classIdx++ ) { #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][0][0][classIdx]; +#else m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][0][classIdx]; +#endif #else m_alfCovarianceFrame[chType][shape][isLuma( compID ) ? classIdx : 0] += m_alfCovariance[compIdx][shape][ctuRsAddr][classIdx]; #endif @@ -3074,7 +3395,11 @@ void EncAdaptiveLoopFilter::deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnit #if ALF_IMPROVEMENT template<bool m_alfWSSD> +#if JVET_X0071_ALF_BAND_CLASSIFIER +void EncAdaptiveLoopFilter::getBlkStats( AlfCovariance* alfCovariance, const AlfFilterShape& shape, AlfClassifier** classifier, const Pel* org, const int orgStride, const Pel* rec, const int recStride, const CompArea& areaDst, const CompArea& area, const ChannelType channel, int fixedFilterSetIdx, int classifierIdx ) +#else void EncAdaptiveLoopFilter::getBlkStats( AlfCovariance* alfCovariance, const AlfFilterShape& shape, AlfClassifier** classifier, const Pel* org, const int orgStride, const Pel* rec, const int recStride, const CompArea& areaDst, const CompArea& area, const ChannelType channel, int fixedFilterSetIdx ) +#endif #else void EncAdaptiveLoopFilter::getBlkStats( AlfCovariance* alfCovariance, const AlfFilterShape& shape, AlfClassifier** classifier, Pel* org, const int orgStride, Pel* rec, const int recStride, const CompArea& areaDst, const CompArea& area, const ChannelType channel, int vbCTUHeight, int vbPos ) #endif @@ -3202,7 +3527,11 @@ void EncAdaptiveLoopFilter::getBlkStats( AlfCovariance* alfCovariance, const Alf rec += recStride; } +#if JVET_X0071_ALF_BAND_CLASSIFIER + int numClasses = classifier ? ALF_NUM_CLASSES_CLASSIFIER[classifierIdx] : 1; +#else int numClasses = classifier ? MAX_NUM_ALF_CLASSES : 1; +#endif for( classIdx = 0; classIdx < numClasses; classIdx++ ) { for( int k = 1; k < shape.numCoeff; k++ ) @@ -3525,7 +3854,11 @@ void EncAdaptiveLoopFilter::initDistortion( { if (m_filterTypeTest[toChannelType((ComponentID)comp)][m_filterShapes[toChannelType((ComponentID)comp)][shapeIdx].filterType]) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_ctbDistortionUnfilter[comp][ctbIdx] = getUnfilteredDistortion(m_alfCovariance[comp][shapeIdx][ctbIdx][0][0], comp == 0 ? MAX_NUM_ALF_CLASSES : 1); +#else m_ctbDistortionUnfilter[comp][ctbIdx] = getUnfilteredDistortion(m_alfCovariance[comp][shapeIdx][ctbIdx][0], comp == 0 ? MAX_NUM_ALF_CLASSES : 1); +#endif m_unFiltDistCompnent[comp] += m_ctbDistortionUnfilter[comp][ctbIdx]; break; } @@ -3607,7 +3940,12 @@ void EncAdaptiveLoopFilter::getDistNewFilter( AlfParam& alfParam ) int numFixedFilterSet = (filterTypeCtb == ALF_FILTER_EXT || filterTypeCtb == ALF_FILTER_9_EXT) ? 2 : 1; for( int altIdx = 0; altIdx < alfParam.numAlternativesLuma; altIdx++ ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierFinal[altIdx]; + for( int classIdx = 0; classIdx < ALF_NUM_CLASSES_CLASSIFIER[classifierIdx]; classIdx++ ) +#else for( int classIdx = 0; classIdx < MAX_NUM_ALF_CLASSES; classIdx++ ) +#endif { for( int coeff = 0; coeff < MAX_NUM_ALF_LUMA_COEFF; coeff++ ) { @@ -3622,7 +3960,11 @@ void EncAdaptiveLoopFilter::getDistNewFilter( AlfParam& alfParam ) { m_distCtbLumaNewFilt[altIdx][fixedFilterSetIdx][ctbIdx] = m_ctbDistortionUnfilter[COMPONENT_Y][ctbIdx]; } +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_distCtbLumaNewFilt[altIdx][fixedFilterSetIdx][ctbIdx] += m_alfCovariance[COMPONENT_Y][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]][ctbIdx][fixedFilterSetIdx][classifierIdx][classIdx].calcErrorForCoeffs( m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_LUMA][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]].numCoeff, m_NUM_BITS ); +#else m_distCtbLumaNewFilt[altIdx][fixedFilterSetIdx][ctbIdx] += m_alfCovariance[COMPONENT_Y][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]][ctbIdx][fixedFilterSetIdx][classIdx].calcErrorForCoeffs(m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_LUMA][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]].numCoeff, m_NUM_BITS); +#endif } } } @@ -3664,7 +4006,13 @@ void EncAdaptiveLoopFilter::getDistApsFilter( CodingStructure& cs, std::vector< int numFixedFilterSet = ( filterTypeCtb == ALF_FILTER_EXT || filterTypeCtb == ALF_FILTER_9_EXT ) ? 2 : 1; for( int altIdx = 0; altIdx < alfParamTmp.numAlternativesLuma; altIdx++ ) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierFinal[altIdx]; + m_classifierIdxApsLuma[apsIdx][altIdx] = classifierIdx; + for( int classIdx = 0; classIdx < ALF_NUM_CLASSES_CLASSIFIER[classifierIdx]; classIdx++ ) +#else for( int classIdx = 0; classIdx < MAX_NUM_ALF_CLASSES; classIdx++ ) +#endif { for ( int coeff = 0; coeff < MAX_NUM_ALF_LUMA_COEFF; coeff++ ) { @@ -3679,7 +4027,11 @@ void EncAdaptiveLoopFilter::getDistApsFilter( CodingStructure& cs, std::vector< { m_distCtbApsLuma[apsIdx][altIdx][fixedFilterSetIdx][ctbIdx] = m_ctbDistortionUnfilter[COMPONENT_Y][ctbIdx]; } +#if JVET_X0071_ALF_BAND_CLASSIFIER + m_distCtbApsLuma[apsIdx][altIdx][fixedFilterSetIdx][ctbIdx] += m_alfCovariance[COMPONENT_Y][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]][ctbIdx][fixedFilterSetIdx][classifierIdx][classIdx].calcErrorForCoeffs(m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_LUMA][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]].numCoeff, m_NUM_BITS); +#else m_distCtbApsLuma[apsIdx][altIdx][fixedFilterSetIdx][ctbIdx] += m_alfCovariance[COMPONENT_Y][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]][ctbIdx][fixedFilterSetIdx][classIdx].calcErrorForCoeffs(m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_LUMA][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeCtb]].numCoeff, m_NUM_BITS); +#endif } } } @@ -3802,7 +4154,12 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar int altIdx = m_ctuAlternative[COMPONENT_Y][ctbIdx]; #endif dDistOrgNewFilter += m_ctbDistortionUnfilter[COMPONENT_Y][ctbIdx]; +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierFinal[altIdx]; + for (int classIdx = 0; classIdx < ALF_NUM_CLASSES_CLASSIFIER[classifierIdx]; classIdx++) +#else for (int classIdx = 0; classIdx < MAX_NUM_ALF_CLASSES; classIdx++) +#endif { #if ALF_IMPROVEMENT short* pCoeff = m_coeffFinal[altIdx]; @@ -3825,7 +4182,11 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar m_clipTmp[i] = pClipp[classIdx * MAX_NUM_ALF_LUMA_COEFF + i]; } #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + dDistOrgNewFilter += m_alfCovariance[COMPONENT_Y][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeNewFilter]][ctbIdx][fixedFilterSetIdx][classifierIdx][classIdx].calcErrorForCoeffs(m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_LUMA][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeNewFilter]].numCoeff, m_NUM_BITS); +#else dDistOrgNewFilter += m_alfCovariance[COMPONENT_Y][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeNewFilter]][ctbIdx][fixedFilterSetIdx][classIdx].calcErrorForCoeffs(m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_LUMA][m_filterTypeToStatIndex[CHANNEL_TYPE_LUMA][filterTypeNewFilter]].numCoeff, m_NUM_BITS); +#endif #else dDistOrgNewFilter += m_alfCovariance[COMPONENT_Y][0][ctbIdx][classIdx].calcErrorForCoeffs(m_clipTmp, m_filterTmp, MAX_NUM_ALF_LUMA_COEFF, m_NUM_BITS); #endif @@ -4229,7 +4590,11 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar m_clipTmp[i] = m_chromaClippFinal[altIdx][i]; } #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + double altDist = m_alfCovariance[compId][m_filterTypeToStatIndex[CHANNEL_TYPE_CHROMA][filterTypeChroma]][ctbIdx][0][0][0].calcErrorForCoeffs( m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_CHROMA][m_filterTypeToStatIndex[CHANNEL_TYPE_CHROMA][filterTypeChroma]].numCoeff, m_NUM_BITS ); +#else double altDist = m_alfCovariance[compId][m_filterTypeToStatIndex[CHANNEL_TYPE_CHROMA][filterTypeChroma]][ctbIdx][0][0].calcErrorForCoeffs( m_clipTmp, m_filterTmp, m_filterShapes[CHANNEL_TYPE_CHROMA][m_filterTypeToStatIndex[CHANNEL_TYPE_CHROMA][filterTypeChroma]].numCoeff, m_NUM_BITS ); +#endif #else double altDist = m_alfCovariance[compId][0][ctbIdx][0].calcErrorForCoeffs( m_clipTmp, m_filterTmp, MAX_NUM_ALF_CHROMA_COEFF, m_NUM_BITS ); #endif @@ -4430,7 +4795,12 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; AlfFilterType filterTypeCtb = m_filterTypeApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierIdxApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; + alfFiltering( m_classifier[classifierIdx], recBuf, buf, blkDst, blkSrc, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx ); +#else alfFiltering( m_classifier, recBuf, buf, blkDst, blkSrc, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx ); +#endif } #else if( filterSetIndex >= NUM_FIXED_FILTER_SETS ) @@ -4458,7 +4828,12 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB const Area blkDst(xStart >> chromaScaleX, yStart >> chromaScaleY, w >> chromaScaleX, h >> chromaScaleY); const int alt_num = m_ctuAlternative[compID][ctuIdx]; #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + alfFiltering( m_classifier[0], recBuf, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma, nullptr, -1 ); +#else + alfFiltering( m_classifier, recBuf, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma, nullptr, -1 ); +#endif #else m_filter5x5Blk( m_classifier, recBuf, buf, blkDst, blkSrc, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight, m_alfVBChmaPos ); #endif @@ -4496,7 +4871,12 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; AlfFilterType filterTypeCtb = m_filterTypeApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; +#if JVET_X0071_ALF_BAND_CLASSIFIER + int classifierIdx = m_classifierIdxApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS][alt_num]; + alfFiltering(m_classifier[classifierIdx], recBuf, recExtBuf, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx); +#else alfFiltering(m_classifier, recBuf, recExtBuf, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs, filterTypeCtb, m_fixFilterResult, fixedFilterSetIdx); +#endif } #else if( filterSetIndex >= NUM_FIXED_FILTER_SETS ) @@ -4523,7 +4903,11 @@ void EncAdaptiveLoopFilter::alfReconstructor(CodingStructure& cs, const PelUnitB Area blk(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY); const int alt_num = m_ctuAlternative[compID][ctuIdx]; #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + alfFiltering( m_classifier[0], recBuf, recExtBuf, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma, nullptr, -1 ); +#else alfFiltering( m_classifier, recBuf, recExtBuf, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_filterTypeApsChroma, nullptr, -1 ); +#endif #else m_filter5x5Blk( m_classifier, recBuf, recExtBuf, blk, blk, compID, m_chromaCoeffFinal[alt_num], m_chromaClippFinal[alt_num], m_clpRngs.comp[compIdx], cs, m_alfVBChmaCTUHeight, m_alfVBChmaPos ); #endif @@ -4619,8 +5003,14 @@ void EncAdaptiveLoopFilter::deriveCcAlfFilterCoeff( ComponentID compID, const Pe forward_tab[CCALF_CANDS_COEFF_NR - 1 + i] = CCALF_SMALL_TAB[i]; forward_tab[CCALF_CANDS_COEFF_NR - 1 - i] = (-1) * CCALF_SMALL_TAB[i]; } + +#if JVET_X0071_LONGER_CCALF + using TE = double[MAX_NUM_CC_ALF_CHROMA_COEFF][MAX_NUM_CC_ALF_CHROMA_COEFF]; + using Ty = double[MAX_NUM_CC_ALF_CHROMA_COEFF]; +#else using TE = double[MAX_NUM_ALF_LUMA_COEFF][MAX_NUM_ALF_LUMA_COEFF]; using Ty = double[MAX_NUM_ALF_LUMA_COEFF]; +#endif double filterCoeffDbl[MAX_NUM_CC_ALF_CHROMA_COEFF]; int16_t filterCoeffInt[MAX_NUM_CC_ALF_CHROMA_COEFF]; @@ -4652,6 +5042,7 @@ void EncAdaptiveLoopFilter::deriveCcAlfFilterCoeff( ComponentID compID, const Pe // Refine quanitzation int modified = 1; double errRef = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].calcErrorForCcAlfCoeffs(filterCoeffInt, size, (m_scaleBits+1)); + while (modified) { modified = 0; @@ -4986,7 +5377,11 @@ void EncAdaptiveLoopFilter::deriveCcAlfFilter( CodingStructure& cs, ComponentID bool bestreuseTemporalFilterCoeff = false; std::vector<int> apsIds = getAvailableCcAlfApsIds(cs, compID); +#if JVET_X0071_LONGER_CCALF + for (int testFilterIdx = 0; testFilterIdx < (apsIds.size() + MAX_NUM_CC_ALF_FILTERS); testFilterIdx++) +#else for (int testFilterIdx = 0; testFilterIdx < ( apsIds.size() + 1 ); testFilterIdx++ ) +#endif { bool referencingExistingAps = (testFilterIdx < apsIds.size()) ? true : false; int maxNumberOfFiltersBeingTested = MAX_NUM_CC_ALF_FILTERS - (testFilterIdx - static_cast<int>(apsIds.size())); @@ -5520,6 +5915,13 @@ void EncAdaptiveLoopFilter::calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA const Pel *recY0 = rec; const Pel *recYP1 = rec + 1 * stride; const Pel *recYP2 = rec + 2 * stride; +#if JVET_X0071_LONGER_CCALF + const Pel *recYM2 = rec - 2 * stride; + const Pel *recYM3 = rec - 3 * stride; + const Pel *recYP3 = rec + 3 * stride; + const Pel *recYM4 = rec - 4 * stride; + const Pel *recYP4 = rec + 4 * stride; +#endif #if !ALF_IMPROVEMENT if (vbDistance == -2 || vbDistance == +1) @@ -5536,6 +5938,36 @@ void EncAdaptiveLoopFilter::calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA for (int b = 0; b < 1; b++) { const Pel centerValue = recY0[+0]; + +#if JVET_X0071_LONGER_CCALF + ELocal[0][b] += recYM4[+0] - centerValue; + ELocal[1][b] += recYM3[+0] - centerValue; + ELocal[2][b] += recYM2[+0] - centerValue; + ELocal[3][b] += recYM1[+0] - centerValue; + + ELocal[4][b] += recY0[-4] - centerValue; + ELocal[5][b] += recY0[-3] - centerValue; + ELocal[6][b] += recY0[-2] - centerValue; + ELocal[7][b] += recY0[-1] - centerValue; + ELocal[8][b] += recY0[+1] - centerValue; + ELocal[9][b] += recY0[+2] - centerValue; + ELocal[10][b] += recY0[+3] - centerValue; + ELocal[11][b] += recY0[+4] - centerValue; + + ELocal[12][b] += recYP1[-4] - centerValue; + ELocal[13][b] += recYP1[-3] - centerValue; + ELocal[14][b] += recYP1[-2] - centerValue; + ELocal[15][b] += recYP1[-1] - centerValue; + ELocal[16][b] += recYP1[+0] - centerValue; + ELocal[17][b] += recYP1[+1] - centerValue; + ELocal[18][b] += recYP1[+2] - centerValue; + ELocal[19][b] += recYP1[+3] - centerValue; + ELocal[20][b] += recYP1[+4] - centerValue; + + ELocal[21][b] += recYP2[+0] - centerValue; + ELocal[22][b] += recYP3[+0] - centerValue; + ELocal[23][b] += recYP4[+0] - centerValue; +#else ELocal[0][b] += recYM1[+0] - centerValue; ELocal[1][b] += recY0[-1] - centerValue; ELocal[2][b] += recY0[+1] - centerValue; @@ -5543,6 +5975,9 @@ void EncAdaptiveLoopFilter::calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA ELocal[4][b] += recYP1[+0] - centerValue; ELocal[5][b] += recYP1[+1] - centerValue; ELocal[6][b] += recYP2[+0] - centerValue; + +#endif + } } @@ -5550,10 +5985,14 @@ void EncAdaptiveLoopFilter::countLumaSwingGreaterThanThreshold(const Pel* luma, { const int lumaBitDepth = m_inputBitDepth[CH_L]; const int threshold = (1 << ( m_inputBitDepth[CH_L] - 2 )) - 1; - +#if JVET_X0071_LONGER_CCALF + int xSupport[] = { 0, 0, 0, 0, -4, -3, -2, -1, 0, +1, +2, +3, +4, -4, -3, -2, -1, 0, +1, +2, +3, +4, 0, 0, 0 }; + int ySupport[] = { -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, +1, +1, +1, +1, +1, +1, +1, +1, +1, +2, +3, +4 }; +#else // 3x4 Diamond int xSupport[] = { 0, -1, 0, 1, -1, 0, 1, 0 }; int ySupport[] = { -1, 0, 0, 0, 1, 1, 1, 2 }; +#endif for (int y = 0; y < height; y += (1 << log2BlockHeight)) { @@ -5565,14 +6004,22 @@ void EncAdaptiveLoopFilter::countLumaSwingGreaterThanThreshold(const Pel* luma, { for (int xOff = 0; xOff < (1 << log2BlockWidth); xOff++) { +#if JVET_X0071_LONGER_CCALF + if ((y + yOff) >= (height - 4) || (x + xOff) >= (width - 4) || (y + yOff) < 4 || (x + xOff) < 4) // only consider samples that are fully supported by picture +#else if ((y + yOff) >= (height - 2) || (x + xOff) >= (width - 1) || (y + yOff) < 1 || (x + xOff) < 1) // only consider samples that are fully supported by picture +#endif { continue; } int minVal = ((1 << lumaBitDepth) - 1); int maxVal = 0; +#if JVET_X0071_LONGER_CCALF + for (int i = 0; i < MAX_NUM_CC_ALF_CHROMA_COEFF; i++) +#else for (int i = 0; i < 8; i++) +#endif { Pel p = luma[(yOff + ySupport[i]) * lumaStride + x + xOff + xSupport[i]]; diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h index f970c20fb1ec0605774d793916f3c45772faebd2..7b738f6a4d7776c6994213884f1d1d33997250a8 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h @@ -47,8 +47,16 @@ struct AlfCovariance { static constexpr int MaxAlfNumClippingValues = AdaptiveLoopFilter::MaxAlfNumClippingValues; + +#if JVET_X0071_LONGER_CCALF + using TE = double[MAX_NUM_CC_ALF_CHROMA_COEFF][MAX_NUM_CC_ALF_CHROMA_COEFF]; + using Ty = double[MAX_NUM_CC_ALF_CHROMA_COEFF]; +#else using TE = double[MAX_NUM_ALF_LUMA_COEFF][MAX_NUM_ALF_LUMA_COEFF]; using Ty = double[MAX_NUM_ALF_LUMA_COEFF]; +#endif + + using TKE = TE[AdaptiveLoopFilter::MaxAlfNumClippingValues][AdaptiveLoopFilter::MaxAlfNumClippingValues]; using TKy = Ty[AdaptiveLoopFilter::MaxAlfNumClippingValues]; @@ -230,7 +238,11 @@ private: int m_alfWSSD; const EncCfg* m_encCfg; #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + AlfCovariance***** m_alfCovariance[MAX_NUM_COMPONENT]; // [compIdx][shapeIdx][ctbAddr][fixedFilterSetIdx][classifierInd][classIdx] +#else AlfCovariance**** m_alfCovariance[MAX_NUM_COMPONENT]; // [compIdx][shapeIdx][ctbAddr][fixedFilterSetIdx][classIdx] +#endif #else AlfCovariance*** m_alfCovariance[MAX_NUM_COMPONENT]; // [compIdx][shapeIdx][ctbAddr][classIdx] #endif @@ -337,19 +349,27 @@ private: ); void copyAlfParam( AlfParam& alfParamDst, AlfParam& alfParamSrc, ChannelType channel ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + double mergeFiltersAndCost( AlfParam& alfParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits, int altIdx, int classifierIdx, int numFiltersLinear ); + void getFrameStats( ChannelType channel, int iShapeIdx, int altIdx, int fixedFilterSetIdx, int classifierIdx ); +#else double mergeFiltersAndCost( AlfParam& alfParam, AlfFilterShape& alfShape, AlfCovariance* covFrame, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], int& uiCoeffBits #if ALF_IMPROVEMENT , int altIdx #endif ); - void getFrameStats( ChannelType channel, int iShapeIdx, int altIdx #if ALF_IMPROVEMENT , int fixedFilterSetIdx #endif ); +#endif #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + void getFrameStat( AlfCovariance* frameCov, AlfCovariance**** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx, int fixedFilterSetIdx, int classifierIdx ); +#else void getFrameStat( AlfCovariance* frameCov, AlfCovariance*** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx, int fixedFilterSetIdx); +#endif #else void getFrameStat( AlfCovariance* frameCov, AlfCovariance** ctbCov, uint8_t* ctbEnableFlags, uint8_t* ctbAltIdx, const int numClasses, int altIdx ); #endif @@ -358,7 +378,11 @@ private: #if ALF_IMPROVEMENT template<bool m_alfWSSD> +#if JVET_X0071_ALF_BAND_CLASSIFIER + void getBlkStats(AlfCovariance* alfCovariace, const AlfFilterShape& shape, AlfClassifier** classifier, const Pel* org, const int orgStride, const Pel* rec, const int recStride, const CompArea& areaDst, const CompArea& area, const ChannelType channel, int fixedFilterSetIdx, int classifierIdx); +#else void getBlkStats(AlfCovariance* alfCovariace, const AlfFilterShape& shape, AlfClassifier** classifier, const Pel* org, const int orgStride, const Pel* rec, const int recStride, const CompArea& areaDst, const CompArea& area, const ChannelType channel, int fixedFilterSetIdx); +#endif #if JVET_R0351_HIGH_BIT_DEPTH_SUPPORT void calcCovariance(Pel ELocal[MAX_NUM_ALF_LUMA_COEFF][MaxAlfNumClippingValues], const Pel *rec, const int stride, const AlfFilterShape& shape, const int transposeIdx, const ChannelType channel, Pel ***fixedFitlerResults, Position pos, int fixedFilterSetIdx); #else @@ -393,24 +417,30 @@ private: void calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA_COEFF][1], const Pel* rec, const int stride, const AlfFilterShape& shape, int vbDistance); #endif #endif - +#if JVET_X0071_ALF_BAND_CLASSIFIER + void mergeClasses(const AlfFilterShape& alfShape, AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], const int numClasses, short filterIndices[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES], const int altIdx, int mergedPair[MAX_NUM_ALF_CLASSES][2]); +#else void mergeClasses(const AlfFilterShape& alfShape, AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], const int numClasses, short filterIndices[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES] #if ALF_IMPROVEMENT , const int altIdx #endif ); - +#endif double getFilterCoeffAndCost( CodingStructure& cs, double distUnfilter, ChannelType channel, bool bReCollectStat, int iShapeIdx, int& uiCoeffBits, #if ALF_IMPROVEMENT int fixedFilterSetIdx, #endif bool onlyFilterCost = false ); +#if JVET_X0071_ALF_BAND_CLASSIFIER + double deriveFilterCoeffs(AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfParam& alfParam, bool nonLinear, int classifierIdx, bool isMaxNum, int mergedPair[MAX_NUM_ALF_CLASSES][2], int mergedCoeff[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], double mergedErr[MAX_NUM_ALF_CLASSES]); +#else double deriveFilterCoeffs(AlfCovariance* cov, AlfCovariance* covMerged, int clipMerged[MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_CLASSES][MAX_NUM_ALF_LUMA_COEFF], AlfFilterShape& alfShape, short* filterIndices, int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], AlfParam& alfParam #if ALF_IMPROVEMENT , bool nonLinear #endif ); +#endif int deriveFilterCoefficientsPredictionMode( AlfFilterShape& alfShape, int **filterSet, int** filterCoeffDiff, const int numFilters ); double deriveCoeffQuant( int *filterClipp, int *filterCoeffQuant, const AlfCovariance& cov, const AlfFilterShape& shape, const int bitDepth, const bool optimizeClip ); double deriveCtbAlfEnableFlags( CodingStructure& cs, const int iShapeIdx, ChannelType channel, @@ -428,7 +458,11 @@ private: double getDistCoeffForce0( bool* codedVarBins, double errorForce0CoeffTab[MAX_NUM_ALF_CLASSES][2], int* bitsVarBin, int zeroBitsVarBin, const int numFilters); int lengthUvlc( int uiCode ); #if ALF_IMPROVEMENT +#if JVET_X0071_ALF_BAND_CLASSIFIER + int getNonFilterCoeffRate( AlfParam& alfParam, int altIdx, int classifierIdx ); +#else int getNonFilterCoeffRate( AlfParam& alfParam, int altIdx ); +#endif int getCostFilterCoeffForce0( AlfFilterShape& alfShape, int **pDiffQFilterCoeffIntPP, const int numFilters, bool* codedVarBins, int altIdx); double getDistForce0( AlfFilterShape& alfShape, const int numFilters, double errorTabForce0Coeff[MAX_NUM_ALF_CLASSES][2], bool* codedVarBins, int altIdx); double getFilteredDistortion( AlfCovariance* cov, const int numClasses, const int numFiltersMinus1, const int numCoeff, int altIdx ); diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index 45863e593865c04182cbaff07b2d0c270f5a1cc6..d4d6ea185e2fb794c522d585d42529dfee112e2e 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -833,6 +833,11 @@ protected: int m_BIFStrength; int m_BIFQPOffset; #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + bool m_CBIF; + int m_CBIFStrength; + int m_CBIFQPOffset; +#endif bool m_ccalf; int m_ccalfQpThreshold; @@ -1335,6 +1340,14 @@ public: void setBIFQPOffset ( int val ) { m_BIFQPOffset = val; } int getBIFQPOffset () const { return m_BIFQPOffset; } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + void setUseCBIF ( bool b ) { m_CBIF = b; } + bool getUseCBIF () const { return m_CBIF; } + void setCBIFStrength ( int val ) { m_CBIFStrength = val; } + int getCBIFStrength () const { return m_CBIFStrength; } + void setCBIFQPOffset ( int val ) { m_CBIFQPOffset = val; } + int getCBIFQPOffset () const { return m_CBIFQPOffset; } +#endif #if MULTI_HYP_PRED void setNumMHPCandsToTest(int i) { m_numMHPCandsToTest = i; } int getNumMHPCandsToTest() { return m_numMHPCandsToTest; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 1dfb92b2de39984646ba50781dd1cf1cdbc9c997..4834044d527138d39bd8eca8056d81b9a05d0064 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -246,7 +246,7 @@ void EncCu::destroy() unsigned numWidths = gp_sizeIdxInfo->numWidths(); unsigned numHeights = gp_sizeIdxInfo->numHeights(); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER delete m_bilateralFilter; #endif @@ -8478,6 +8478,52 @@ void EncCu::xCalDebCost( CodingStructure &cs, Partitioner &partitioner, bool cal } } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()){ + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + bool chroma_valid = cu->Cb().valid() && cu->Cr().valid(); + bool BIF_chroma = false; + for (auto &currTU : CU::traverseTUs(*cu)) + { + bool isInter = (cu->predMode == MODE_INTER) ? true : false; + + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + + BIF_chroma = false; + if(!isDualTree && chroma_valid) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false; + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = ((TU_CBF || isInter == false) && (currTU.cu->qp > 17) && (TU_VALID)); + } + + if(isDualTree && chroma_valid) + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)); + } + + if (BIF_chroma) + { + CompArea &compArea = currTU.block(compID); + PelBuf recBuf = picDbBuf.getBuf(compArea); + PelBuf recIPredBuf = recBuf; + + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(recBuf, recBuf, recBuf, currTU.cu->qp, recIPredBuf, cs.slice->clpRng(compID), currTU, true, isCb); + } + } + } + } +#endif //deblock if ( leftEdgeAvai ) @@ -9103,6 +9149,59 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best } } } +#if JVET_X0071_CHROMA_BILATERAL_FILTER + const CompArea &area_chroma = cu.blocks[compID]; + CompArea tmpArea_chroma(compID, area_chroma.chromaFormat, Position(0, 0), area_chroma.size()); + PelBuf tmpRecChroma; + if(isChroma(compID)) + { + tmpRecChroma = m_tmpStorageLCU->getBuf(tmpArea_chroma); + tmpRecChroma.copyFrom(reco); + } + + if(tempCS->pps->getUseCBIF() && isChroma(compID) && (cu.qp > 17)) + { + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(*tempCS); + bool chroma_valid = cu.Cb().valid() && cu.Cr().valid(); + bool BIF_chroma = false; + + for (auto &currTU : CU::traverseTUs(cu)) + { + Position tuPosInCu = currTU.chromaPos() - cu.chromaPos(); + PelBuf tmpSubBuf = tmpRecChroma.subBuf(tuPosInCu, currTU.chromaSize()); + + bool isInter = (cu.predMode == MODE_INTER) ? true : false; + bool isCb = compID == COMPONENT_Cb ? true : false; + BIF_chroma = false; + if(!isDualTree && chroma_valid) + { + TU_VALID = currTU.blocks[compID].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (( TU_CBF || isInter == false) && (currTU.cu->qp > 17) && (TU_VALID)); + + } + + if(isDualTree && chroma_valid) + { + BIF_chroma = ((TU::getCbf(currTU, compID) || isInter == false) && (currTU.cu->qp > 17)); + } + + if(BIF_chroma) + { + CompArea compArea = currTU.blocks[compID]; + PelBuf recIPredBuf = tempCS->slice->getPic()->getRecoBuf(compArea); + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpSubBuf, tmpSubBuf, tmpSubBuf, currTU.cu->qp, recIPredBuf, tempCS->slice->clpRng(compID), currTU, true, isCb); + } + } + } +#endif #if WCG_EXT if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( @@ -9115,7 +9214,18 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best } else { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(isChroma(compID) && tempCS->pps->getUseCBIF()) + { + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecChroma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else + { + finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); + } +#else finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); +#endif } } else @@ -9124,6 +9234,56 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE ); } #else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + const CompArea &area_chroma = cu.blocks[compID]; + CompArea tmpArea_chroma(compID, area_chroma.chromaFormat, Position(0, 0), area_chroma.size()); + PelBuf tmpRecChroma; + if(isChroma(compID)) + { + tmpRecChroma = m_tmpStorageLCU->getBuf(tmpArea_chroma); + tmpRecChroma.copyFrom(reco); + } + + if(tempCS->pps->getUseCBIF() && isChroma(compID) && (cu.qp > 17)) + { + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(*tempCS); + bool chroma_valid = cu.Cb().valid() && cu.Cr().valid(); + bool BIF_chroma = false; + + for (auto &currTU : CU::traverseTUs(cu)) + { + Position tuPosInCu = currTU.chromaPos() - cu.chromaPos(); + PelBuf tmpSubBuf = tmpRecChroma.subBuf(tuPosInCu, currTU.chromaSize()); + + bool isInter = (cu.predMode == MODE_INTER) ? true : false; + bool isCb = compID == COMPONENT_Cb ? true : false; + BIF_chroma = false; + if(!isDualTree && chroma_valid) + { + TU_VALID = currTU.blocks[compID].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + + if(TU_VALID){ + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (( TU_CBF || isInter == false) && (currTU.cu->qp > 17) && (TU_VALID)); + } + + if(isDualTree && chroma_valid){ + BIF_chroma = ((TU::getCbf(currTU, compID) || isInter == false) && (currTU.cu->qp > 17)); + } + + if(BIF_chroma) + { + CompArea compArea = currTU.blocks[compID]; + PelBuf recIPredBuf = tempCS->slice->getPic()->getRecoBuf(compArea); + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpSubBuf, tmpSubBuf, tmpSubBuf, currTU.cu->qp, recIPredBuf, tempCS->slice->clpRng(compID), currTU, true, isCb); + } + } + } +#endif #if WCG_EXT if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getLmcs() && (tempCS->slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))) { @@ -9138,7 +9298,18 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best } else { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(isChroma(compID) && tempCS->pps->getUseCBIF()) + { + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecChroma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else + { + finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); + } +#else finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); +#endif } } else diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 2bef92f6e6020e046679d690d3cae26ead9b0580..649480272fef1e2b3cc0eb2ac292f8eeb9a95a04 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -46,7 +46,7 @@ #include "CommonLib/Unit.h" #include "CommonLib/UnitPartitioner.h" #include "CommonLib/IbcHashMap.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "CommonLib/BilateralFilter.h" #endif #include "CommonLib/LoopFilter.h" @@ -334,7 +334,7 @@ public: EncModeCtrl* getModeCtrl () { return m_modeCtrl; } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter *m_bilateralFilter = new BilateralFilter(); #endif diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index f89642786fd3509d4005e4cf48d5dd2dcb549838..c3494b17662062e06f56b55494ff4acc9561e8af 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -178,7 +178,7 @@ void EncGOP::create() { m_bLongtermTestPictureHasBeenCoded = 0; m_bLongtermTestPictureHasBeenCoded2 = 0; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_cBilateralFilter.create(); #endif } @@ -205,7 +205,7 @@ void EncGOP::destroy() delete m_picOrig; m_picOrig = NULL; } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_cBilateralFilter.destroy(); #endif } @@ -1968,7 +1968,31 @@ public: } }; #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER +class CBIFCabacEstImp : public CBIFCabacEst +{ + CABACWriter* CABACEstimator; +public: + CBIFCabacEstImp(CABACWriter* _CABACEstimator) : CABACEstimator(_CABACEstimator) {}; + virtual ~CBIFCabacEstImp() {}; + + virtual uint64_t getBits_Cb(const Slice& slice, const CBifParams& htdfParams) + { + CABACEstimator->initCtxModels(slice); + CABACEstimator->resetBits(); + CABACEstimator->Cbif_Cb(slice, htdfParams); + return CABACEstimator->getEstFracBits(); + } + virtual uint64_t getBits_Cr(const Slice& slice, const CBifParams& htdfParams) + { + CABACEstimator->initCtxModels(slice); + CABACEstimator->resetBits(); + CABACEstimator->Cbif_Cr(slice, htdfParams); + return CABACEstimator->getEstFracBits(); + } +}; +#endif // ==================================================================================================================== // Public member functions @@ -2786,11 +2810,19 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, #endif #endif #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (pcSlice->getSPS()->getSAOEnabledFlag() || pcSlice->getPPS()->getUseBIF() || pcSlice->getPPS()->getUseCBIF()) +#else // BIF happens in SAO code so this needs to be done // even if SAO=0 if BIF=1. if (pcSlice->getSPS()->getSAOEnabledFlag() || pcSlice->getPPS()->getUseBIF() ) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (pcSlice->getSPS()->getSAOEnabledFlag() || pcSlice->getPPS()->getUseCBIF()) #else if (pcSlice->getSPS()->getSAOEnabledFlag()) +#endif #endif { pcPic->resizeSAO( numberOfCtusInFrame, 0 ); @@ -3131,10 +3163,18 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, #endif #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if( pcSlice->getSPS()->getSAOEnabledFlag() || pcSlice->getPPS()->getUseBIF() || pcSlice->getPPS()->getUseCBIF()) +#else // We need to do this step if at least one of BIF or SAO are enabled. if( pcSlice->getSPS()->getSAOEnabledFlag() || pcSlice->getPPS()->getUseBIF()) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if( pcSlice->getSPS()->getSAOEnabledFlag() || pcSlice->getPPS()->getUseCBIF()) #else if( pcSlice->getSPS()->getSAOEnabledFlag() ) +#endif #endif { bool sliceEnabled[MAX_NUM_COMPONENT]; @@ -3142,6 +3182,9 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, #if JVET_V0094_BILATERAL_FILTER BIFCabacEstImp est(m_pcEncLib->getCABACEncoder()->getCABACEstimator(cs.slice->getSPS())); #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + CBIFCabacEstImp CBIF_est(m_pcEncLib->getCABACEncoder()->getCABACEstimator(cs.slice->getSPS())); +#endif m_pcSAO->SAOProcess( cs, sliceEnabled, pcSlice->getLambdas(), #if ENABLE_QPA @@ -3150,10 +3193,13 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, m_pcCfg->getTestSAODisableAtPictureLevel(), m_pcCfg->getSaoEncodingRate(), m_pcCfg->getSaoEncodingRateChroma(), m_pcCfg->getSaoCtuBoundary(), m_pcCfg->getSaoGreedyMergeEnc() #if JVET_V0094_BILATERAL_FILTER , &est +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + , &CBIF_est #endif ); //assign SAO slice header -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER if( pcSlice->getSPS()->getSAOEnabledFlag() ) { #endif @@ -3174,7 +3220,7 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, } } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER } #endif } diff --git a/source/Lib/EncoderLib/EncGOP.h b/source/Lib/EncoderLib/EncGOP.h index be9bbec3a72df5e941d74b6e0cf080dca9227fb5..c25ffdcd8ddbb53487a467cc434e82b756cc6d24 100644 --- a/source/Lib/EncoderLib/EncGOP.h +++ b/source/Lib/EncoderLib/EncGOP.h @@ -60,7 +60,7 @@ #include "Analyze.h" #include "RateCtrl.h" #include <vector> -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "BilateralFilter.h" #endif #include "EncHRD.h" @@ -140,7 +140,7 @@ private: PicList* m_pcListPic; HLSWriter* m_HLSWriter; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter m_cBilateralFilter; #endif LoopFilter* m_pcLoopFilter; diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 5060c6595f5cf9b7058967b82b2ddc84bda9317d..b40776947fb785a9c553814d73f13cd17396f81a 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -111,7 +111,7 @@ void EncLib::create( const int layerId ) m_cCuEncoder = new EncCu [m_numCuEncStacks]; m_cInterSearch = new InterSearch [m_numCuEncStacks]; m_cIntraSearch = new IntraSearch [m_numCuEncStacks]; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_bilateralFilter = new BilateralFilter [m_numCuEncStacks]; #endif m_cTrQuant = new TrQuant [m_numCuEncStacks]; @@ -122,14 +122,14 @@ void EncLib::create( const int layerId ) for( int jId = 0; jId < m_numCuEncStacks; jId++ ) { m_cCuEncoder[jId]. create( this ); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_bilateralFilter[jId]. create(); #endif } #else m_cCuEncoder. create( this ); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_bilateralFilter. create(); #endif #endif @@ -170,16 +170,32 @@ void EncLib::create( const int layerId ) } #if JVET_V0094_BILATERAL_FILTER #if JVET_W0066_CCSAO +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (m_bUseSAO || m_BIF || m_CCSAO || m_CBIF) +#else if (m_bUseSAO || m_BIF || m_CCSAO) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (m_bUseSAO || m_BIF || m_CBIF) #else if (m_bUseSAO || m_BIF) #endif +#endif #else #if JVET_W0066_CCSAO +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (m_bUseSAO || m_CCSAO || m_CBIF) +#else if (m_bUseSAO || m_CCSAO) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (m_bUseSAO || m_CBIF) #else if (m_bUseSAO) #endif +#endif #endif { const uint32_t widthInCtus = (m_iSourceWidth + m_maxCUWidth - 1) / m_maxCUWidth; @@ -224,14 +240,14 @@ void EncLib::destroy () { m_cInterSearch[jId]. destroy(); m_cIntraSearch[jId]. destroy(); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_bilateralFilter[jId].destroy(); #endif } #else m_cInterSearch. destroy(); m_cIntraSearch. destroy(); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_bilateralFilter. destroy(); #endif #endif @@ -240,7 +256,7 @@ void EncLib::destroy () delete[] m_cCuEncoder; delete[] m_cInterSearch; delete[] m_cIntraSearch; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER delete[] m_bilateralFilter; #endif delete[] m_cTrQuant; @@ -444,7 +460,7 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) // initialize encoder search class CABACWriter* cabacEstimator = m_CABACEncoder[jId].getCABACEstimator( &sps0 ); m_cIntraSearch[jId].init( this, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER &m_bilateralFilter[jId], #endif &m_cTrQuant[jId], @@ -455,7 +471,7 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) , sps0.getBitDepth(CHANNEL_TYPE_LUMA) ); m_cInterSearch[jId].init( this, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER &m_bilateralFilter[jId], #endif &m_cTrQuant[jId], @@ -487,7 +503,7 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) // initialize encoder search class CABACWriter* cabacEstimator = m_CABACEncoder.getCABACEstimator(&sps0); m_cIntraSearch.init( this, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER &m_bilateralFilter, #endif &m_cTrQuant, @@ -498,7 +514,7 @@ void EncLib::init( bool isFieldCoding, AUWriterIf* auWriterIf ) , sps0.getBitDepth(CHANNEL_TYPE_LUMA) ); m_cInterSearch.init( this, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER &m_bilateralFilter, #endif &m_cTrQuant, @@ -1926,6 +1942,11 @@ void EncLib::xInitPPS(PPS &pps, const SPS &sps) pps.setBIFStrength ( m_BIFStrength ); pps.setBIFQPOffset ( m_BIFQPOffset ); #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + pps.setUseCBIF ( m_CBIF ); + pps.setCBIFStrength ( m_CBIFStrength ); + pps.setCBIFQPOffset ( m_CBIFQPOffset ); +#endif if ( getDeblockingFilterMetric() ) { diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index f05898fa7d53d7b92c5f5f84b6b9d92497e373fd..25e7b28dd1812e4e5a2fd3f840ade317e33d6669 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -42,7 +42,7 @@ #include "CommonLib/TrQuant.h" #include "CommonLib/LoopFilter.h" #include "CommonLib/NAL.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "CommonLib/BilateralFilter.h" #endif @@ -91,12 +91,12 @@ private: #endif // coding tool #if ENABLE_SPLIT_PARALLELISM -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter *m_bilateralFilter; #endif TrQuant *m_cTrQuant; ///< transform & quantization class #else -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter m_bilateralFilter; #endif TrQuant m_cTrQuant; ///< transform & quantization class @@ -205,7 +205,7 @@ public: InterSearch* getInterSearch ( int jId = 0 ) { return &m_cInterSearch[jId]; } IntraSearch* getIntraSearch ( int jId = 0 ) { return &m_cIntraSearch[jId]; } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* getBilateralFilter ( int jId = 0 ) { return &m_bilateralFilter[jId]; } #endif TrQuant* getTrQuant ( int jId = 0 ) { return &m_cTrQuant[jId]; } @@ -213,7 +213,7 @@ public: InterSearch* getInterSearch () { return &m_cInterSearch; } IntraSearch* getIntraSearch () { return &m_cIntraSearch; } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* getBilateralFilter () { return &m_bilateralFilter; } #endif TrQuant* getTrQuant () { return &m_cTrQuant; } diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp index 019e5561be67111763b9440e06f3542073aa8bb0..5a5df72140281ad9e599b1b525e5a4d971cbebb8 100644 --- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp +++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.cpp @@ -41,7 +41,7 @@ #include "CommonLib/dtrace_codingstruct.h" #include "CommonLib/dtrace_buffer.h" #include "CommonLib/CodingStructure.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "CommonLib/BilateralFilter.h" #endif @@ -280,17 +280,20 @@ void EncSampleAdaptiveOffset::SAOProcess( CodingStructure& cs, bool* sliceEnable const bool bTestSAODisableAtPictureLevel, const double saoEncodingRate, const double saoEncodingRateChroma, const bool isPreDBFSamplesUsed, bool isGreedyMergeEncoding #if JVET_V0094_BILATERAL_FILTER ,BIFCabacEst* BifCABACEstimator +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + ,CBIFCabacEst* CBifCABACEstimator #endif ) { -#if ALF_SAO_TRUE_ORG && !JVET_V0094_BILATERAL_FILTER +#if ALF_SAO_TRUE_ORG && !JVET_V0094_BILATERAL_FILTER && !JVET_X0071_CHROMA_BILATERAL_FILTER PelUnitBuf org = cs.getTrueOrgBuf(); #else PelUnitBuf org = cs.getOrgBuf(); #endif PelUnitBuf res = cs.getRecoBuf(); PelUnitBuf src = m_tempBuf; -#if !JVET_V0094_BILATERAL_FILTER +#if !JVET_V0094_BILATERAL_FILTER && !JVET_X0071_CHROMA_BILATERAL_FILTER // Moved until after the bilateral filter has been initialized memcpy(m_lambda, lambdas, sizeof(m_lambda)); #endif @@ -327,8 +330,71 @@ void EncSampleAdaptiveOffset::SAOProcess( CodingStructure& cs, bool* sliceEnable //double MseFltDefSwitchFrame = 0; //int CtuIdx = 0; #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()){ + const PreCalcValues& pcv = *cs.pcv; + CBifParams& CBifParams = cs.picture->getCBifParam(); + int width = cs.picture->lwidth(); + int height = cs.picture->lheight(); + int block_width = pcv.maxCUWidth; + int block_height = pcv.maxCUHeight; + + int width_in_blocks = width / block_width + (width % block_width != 0); + int height_in_blocks = height / block_height + (height % block_height != 0); + + CBifParams.numBlocks = width_in_blocks * height_in_blocks; + + CBifParams.ctuOn_Cb.resize(CBifParams.numBlocks); + CBifParams.ctuOn_Cr.resize(CBifParams.numBlocks); + std::fill(CBifParams.ctuOn_Cb.begin(), CBifParams.ctuOn_Cb.end(), 0); + std::fill(CBifParams.ctuOn_Cr.begin(), CBifParams.ctuOn_Cr.end(), 0); + CBifParams.frmOn_Cb = 0; + CBifParams.frmOn_Cr = 0; + CBifParams.allCtuOn_Cb = 0; + CBifParams.allCtuOn_Cr = 0; + + if (CBifParams.frmOn_Cb == 0) + { + std::fill(CBifParams.ctuOn_Cb.begin(), CBifParams.ctuOn_Cb.end(), 0); + } + else if (CBifParams.allCtuOn_Cb) + { + std::fill(CBifParams.ctuOn_Cb.begin(), CBifParams.ctuOn_Cb.end(), 1); + } + + if (CBifParams.frmOn_Cr == 0) + { + std::fill(CBifParams.ctuOn_Cr.begin(), CBifParams.ctuOn_Cr.end(), 0); + } + else if (CBifParams.allCtuOn_Cr) + { + std::fill(CBifParams.ctuOn_Cr.begin(), CBifParams.ctuOn_Cr.end(), 1); + } + } +#endif #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + BilateralFilter bilateralFilter; + if(!cs.sps->getSAOEnabledFlag() && (cs.pps->getUseBIF() || cs.pps->getUseCBIF())) + { + bilateralFilter.create(); + if(cs.pps->getUseBIF()) + { + bilateralFilter.bilateralFilterPicRDOperCTU(cs, src, BifCABACEstimator); // Filters from src to res + } + if(cs.pps->getUseCBIF()) + { + //Cb + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, true); + //Cr + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, false); + } + bilateralFilter.destroy(); + return; + } + memcpy(m_lambda, lambdas, sizeof(m_lambda)); +#else BilateralFilter bilateralFilter; // Special case when SAO = 0 and BIF = 1. @@ -342,10 +408,51 @@ void EncSampleAdaptiveOffset::SAOProcess( CodingStructure& cs, bool* sliceEnable return; } memcpy(m_lambda, lambdas, sizeof(m_lambda)); +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + BilateralFilter bilateralFilter; + if(!cs.sps->getSAOEnabledFlag() && cs.pps->getUseCBIF()) + { + bilateralFilter.create(); + //Cb + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, true); + //Cr + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, false); + bilateralFilter.destroy(); + return; + } + memcpy(m_lambda, lambdas, sizeof(m_lambda)); +#else + //do nothing +#endif #endif //collect statistics #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseBIF() || cs.pps->getUseCBIF()) + { + bilateralFilter.create(); + if(cs.pps->getUseBIF()) + { + bilateralFilter.bilateralFilterPicRDOperCTU(cs, src, BifCABACEstimator); // Filters from src to res' + } + if(cs.pps->getUseCBIF()) + { + //Cb + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, true); + //Cr + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, false); + } + getStatistics(m_statData, org, src, res, cs); + bilateralFilter.destroy(); + } + else + { + getStatistics(m_statData, org, src, src, cs); + } +#else //apply BILAT to res if(cs.pps->getUseBIF()) { @@ -358,8 +465,26 @@ void EncSampleAdaptiveOffset::SAOProcess( CodingStructure& cs, bool* sliceEnable { getStatistics(m_statData, org, src, src, cs); } +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + bilateralFilter.create(); + //Cb + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, true); + //Cr + bilateralFilter.bilateralFilterPicRDOperCTU_chroma(cs, src, CBifCABACEstimator, false); + getStatistics(m_statData, org, src, res, cs); + bilateralFilter.destroy(); + } + else + { + getStatistics(m_statData, org, src, src, cs); + } #else getStatistics(m_statData, org, src, cs); +#endif #endif if(isPreDBFSamplesUsed) @@ -368,9 +493,25 @@ void EncSampleAdaptiveOffset::SAOProcess( CodingStructure& cs, bool* sliceEnable } #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseBIF() || cs.pps->getUseCBIF()) + { + res.copyFrom(src); + } +#else //undo BILAT on res if(cs.pps->getUseBIF()) res.copyFrom(src); +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + res.copyFrom(src); + } +#else + //do nothing +#endif #endif //slice on/off @@ -404,7 +545,7 @@ void EncSampleAdaptiveOffset::getPreDBFStatistics(CodingStructure& cs) #endif PelUnitBuf rec = cs.getRecoBuf(); getStatistics(m_preDBFstatData, org, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER rec, rec, #else rec, @@ -429,7 +570,7 @@ void EncSampleAdaptiveOffset::addPreDBFStatistics(std::vector<SAOStatData**>& bl } void EncSampleAdaptiveOffset::getStatistics(std::vector<SAOStatData**>& blkStats, PelUnitBuf& orgYuv, PelUnitBuf& srcYuv, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER PelUnitBuf& bifYuv, #endif CodingStructure& cs, bool isCalculatePreDeblockSamples) @@ -482,7 +623,7 @@ void EncSampleAdaptiveOffset::getStatistics(std::vector<SAOStatData**>& blkStats int orgStride = orgYuv.get(compID).stride; Pel* orgBlk = orgYuv.get(compID).bufAt( compArea ); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER int bifStride = bifYuv.get(compID).stride; Pel* bifBlk = bifYuv.get(compID).bufAt( compArea ); #endif @@ -498,7 +639,7 @@ void EncSampleAdaptiveOffset::getStatistics(std::vector<SAOStatData**>& blkStats getBlkStats(compID, cs.sps->getBitDepth(toChannelType(compID)), blkStats[ctuRsAddr][compID] , srcBlk, orgBlk, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifBlk, bifStride, #endif srcStride, orgStride, compArea.width, compArea.height @@ -960,7 +1101,7 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn { const PreCalcValues& pcv = *cs.pcv; bool allBlksDisabled = true; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER if(cs.sps->getSAOEnabledFlag()) { // If SAO is enabled, we should investigate the components. @@ -974,11 +1115,11 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn allBlksDisabled = false; } } -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER } #endif -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter bilateralFilter; bilateralFilter.create(); #endif @@ -1032,6 +1173,12 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn { codedParams[ctuRsAddr].reset(); #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(!cs.pps->getUseBIF() && !cs.pps->getUseCBIF()) + { + continue; + } +#else // In the combined filter, we cannot continue here, even if SAO is // turned off for all blocks, since we need to perform the bilateral // filter later on (see next JVET_V0094_BILATERAL_FILTER). @@ -1040,8 +1187,16 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn // Unless we are not using BIF. Then it is safe to continue. continue; } +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(!cs.pps->getUseCBIF()) + { + continue; + } #else continue; +#endif #endif } @@ -1246,9 +1401,64 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn } } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + CBifParams& CBifParams = cs.picture->getCBifParam(); + + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid){ + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + for(int compIdx = COMPONENT_Cb ; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb :COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + bilateralFilter.bilateralFilterDiamond5x5NoClip_chroma(srcYuv, resYuv, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + } +#endif #else #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseBIF() || cs.pps->getUseCBIF()) +#else if(cs.pps->getUseBIF()) +#endif { offsetCTUnoClip(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); // Avoid old slow code @@ -1263,6 +1473,25 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn bool clipLumaIfNoBilat = false; if(myCtbOffset.modeIdc != SAO_MODE_OFF) clipLumaIfNoBilat = true; +#if JVET_X0071_CHROMA_BILATERAL_FILTER + SAOOffset& myCtbOffset_Cb = mySAOblkParam[1]; + SAOOffset& myCtbOffset_Cr = mySAOblkParam[2]; + CBifParams& CBifParams = cs.picture->getCBifParam(); + + bool clipChromaIfNoBilat_Cb = false; + bool clipChromaIfNoBilat_Cr = false; + + if(myCtbOffset_Cb.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cb = true; + } + if(myCtbOffset_Cr.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cr = true; + } + if(cs.pps->getUseBIF()) + { +#endif for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) { @@ -1282,15 +1511,215 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn } } } +#if JVET_X0071_CHROMA_BILATERAL_FILTER + } // BIF LUMA is disabled + else{ + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) + { + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipLumaIfNoBilat) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Y), currTU); + } + } + } + } + if(cs.pps->getUseCBIF()) + { + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + m_bilateralFilter.bilateralFilterDiamond5x5_chroma(srcYuv, resYuv, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + else + { + bool use_clip = isCb ? clipChromaIfNoBilat_Cb : clipChromaIfNoBilat_Cr; + if(use_clip && currTU.blocks[compID].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + } + }// BIF chroma is disabled + else + { + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipChromaIfNoBilat_Cb && currTU.blocks[COMPONENT_Cb].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Cb), currTU, true); + } + if(clipChromaIfNoBilat_Cr && currTU.blocks[COMPONENT_Cr].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Cr), currTU, false); + } + } + } + } +#endif } else { // We do not do BIF for this sequence, so we can use the regular SAO function offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); } +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + offsetCTUnoClip(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); + + SAOBlkParam mySAOblkParam = cs.picture->getSAO()[ctuRsAddr]; + SAOOffset& myCtbOffset = mySAOblkParam[0]; + + bool clipLumaIfNoBilat = false; + if(myCtbOffset.modeIdc != SAO_MODE_OFF) + { + clipLumaIfNoBilat = true; + } + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) + { + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipLumaIfNoBilat) + bilateralFilter.clipNotBilaterallyFilteredBlocks(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Y), currTU); + } + } + + SAOOffset& myCtbOffset_Cb = mySAOblkParam[1]; + SAOOffset& myCtbOffset_Cr = mySAOblkParam[2]; + bool clipChromaIfNoBilat_Cb = false; + bool clipChromaIfNoBilat_Cr = false; + CBifParams& CBifParams = cs.picture->getCBifParam(); + + if(myCtbOffset_Cb.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cb = true; + } + if(myCtbOffset_Cr.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cr = true; + } + + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + + if(BIF_chroma) + { + m_bilateralFilter.bilateralFilterDiamond5x5_chroma(srcYuv, resYuv, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + else + { + bool use_clip = isCb ? clipChromaIfNoBilat_Cb : clipChromaIfNoBilat_Cr; + if(use_clip && currTU.blocks[compID].valid()) + { + m_bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + } + } + else + { + offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); + } #else offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); #endif +#endif #endif } @@ -1306,9 +1735,17 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn #endif //reconstruct #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (isGreedymergeEncoding || (cs.pps->getUseBIF() &&allBlksDisabled) || (cs.pps->getUseCBIF() &&allBlksDisabled)) +#else if (isGreedymergeEncoding || (cs.pps->getUseBIF() &&allBlksDisabled) ) +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (isGreedymergeEncoding || (cs.pps->getUseCBIF() &&allBlksDisabled) ) #else if (isGreedymergeEncoding) +#endif #endif { ctuRsAddr = 0; @@ -1336,6 +1773,27 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn myResBlk[yy*myResStride+xx] = mySrcBlk[yy*mySrcStride+xx]; } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()){ + for(int chroma_idx = COMPONENT_Cb; chroma_idx < MAX_NUM_COMPONENT; chroma_idx++){ + + bool isCb = chroma_idx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + + int myResStride_chroma = resYuv.get(compID).stride; + const CompArea& myCompArea_chroma = area.block(compID); + Pel* myResBlk_chroma = resYuv.get(compID).bufAt(myCompArea_chroma); + int mySrcStride_chroma = srcYuv.get(compID).stride; + Pel* mySrcBlk_chroma = srcYuv.get(compID).bufAt(myCompArea_chroma); + + for(int yy = 0; yy<area.chromaSize().height; yy++){ + for(int xx = 0; xx<area.chromaSize().width; xx++){ + myResBlk_chroma[yy*myResStride_chroma+xx] = mySrcBlk_chroma[yy*mySrcStride_chroma+xx]; + } + } + } + } +#endif #if JVET_W0066_CCSAO offsetCTUnoClip(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); @@ -1357,8 +1815,210 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn } } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + CBifParams& CBifParams = cs.picture->getCBifParam(); + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + bilateralFilter.bilateralFilterDiamond5x5NoClip_chroma(srcYuv, resYuv, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + } +#endif #else #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseBIF() || cs.pps->getUseCBIF()) + { + offsetCTUnoClip(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); + SAOBlkParam mySAOblkParam = cs.picture->getSAO()[ctuRsAddr]; + SAOOffset& myCtbOffset = mySAOblkParam[0]; + BifParams& bifParams = cs.picture->getBifParam(); + + bool clipLumaIfNoBilat = false; + if(myCtbOffset.modeIdc != SAO_MODE_OFF) + clipLumaIfNoBilat = true; + + CBifParams& CBifParams = cs.picture->getCBifParam(); + SAOOffset& myCtbOffset_Cb = mySAOblkParam[1]; + SAOOffset& myCtbOffset_Cr = mySAOblkParam[2]; + bool clipChromaIfNoBilat_Cb = false; + bool clipChromaIfNoBilat_Cr = false; + + if(myCtbOffset_Cb.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cb = true; + } + if(myCtbOffset_Cr.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cr = true; + } + if(cs.pps->getUseBIF()) + { + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) + { + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + if ( bifParams.ctuOn[ctuRsAddr] && ((TU::getCbf(currTU, COMPONENT_Y) || isInter == false) && (currTU.cu->qp > 17)) && (128 > std::max(currTU.lumaSize().width, currTU.lumaSize().height)) && ((isInter == false) || (32 > std::min(currTU.lumaSize().width, currTU.lumaSize().height)))) + { + bilateralFilter.bilateralFilterDiamond5x5(srcYuv, resYuv, currTU.cu->qp, cs.slice->clpRng(COMPONENT_Y), currTU); + } + else + { + // We don't need to clip if SAO was not performed on luma. + if(clipLumaIfNoBilat) + bilateralFilter.clipNotBilaterallyFilteredBlocks(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Y), currTU); + } + } + } + } + else + { + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) + { + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipLumaIfNoBilat) + bilateralFilter.clipNotBilaterallyFilteredBlocks(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Y), currTU); + } + } + } + + if(cs.pps->getUseCBIF()) + { + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && (( TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + bilateralFilter.bilateralFilterDiamond5x5_chroma(srcYuv, resYuv, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + else + { + bool use_clip = isCb ? clipChromaIfNoBilat_Cb : clipChromaIfNoBilat_Cr; + if(use_clip && currTU.blocks[compIdx].valid()) + { + bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + } + } + else + { + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipChromaIfNoBilat_Cb && currTU.blocks[COMPONENT_Cb].valid()) + { + bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Cb), currTU, true); + } + if(clipChromaIfNoBilat_Cr && currTU.blocks[COMPONENT_Cr].valid()) + { + bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Cr), currTU, false); + } + } + } + } + }//BIF = 1 OR CBIF = 1 + else + { + offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); + } +#else if(cs.pps->getUseBIF()) { offsetCTUnoClip(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); @@ -1400,17 +2060,131 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn // We do not use BIF so we can use the regular SAO function call offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); } +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(cs.pps->getUseCBIF()) + { + offsetCTUnoClip(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); + + SAOBlkParam mySAOblkParam = cs.picture->getSAO()[ctuRsAddr]; + CBifParams& CBifParams = cs.picture->getCBifParam(); + + SAOOffset& myCtbOffset = mySAOblkParam[0]; + bool clipLumaIfNoBilat = false; + if(myCtbOffset.modeIdc != SAO_MODE_OFF) + { + clipLumaIfNoBilat = true; + } + + SAOOffset& myCtbOffset_Cb = mySAOblkParam[1]; + SAOOffset& myCtbOffset_Cr = mySAOblkParam[2]; + bool clipChromaIfNoBilat_Cb = false; + bool clipChromaIfNoBilat_Cr = false; + + if(myCtbOffset_Cb.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cb = true; + } + if(myCtbOffset_Cr.modeIdc != SAO_MODE_OFF) + { + clipChromaIfNoBilat_Cr = true; + } + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CH_L), CH_L)) + { + for (auto &currTU : CU::traverseTUs(currCU)) + { + if(clipLumaIfNoBilat) + { + bilateralFilter.clipNotBilaterallyFilteredBlocks(srcYuv, resYuv, cs.slice->clpRng(COMPONENT_Y), currTU); + } + } + } + + bool TU_VALID = false; + bool TU_CBF = false; + bool isDualTree = CS::isDualITree(cs); + ChannelType CType = isDualTree ? CH_C : CH_L; + bool BIF_chroma = false; + + for (auto &currCU : cs.traverseCUs(CS::getArea(cs, area, CType), CType)) + { + bool chroma_valid = currCU.Cb().valid() && currCU.Cr().valid(); + if(!chroma_valid) + { + continue; + } + for (auto &currTU : CU::traverseTUs(currCU)) + { + bool isInter = (currCU.predMode == MODE_INTER) ? true : false; + + for(int compIdx = COMPONENT_Cb; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + bool isCb = compIdx == COMPONENT_Cb ? true : false; + ComponentID compID = isCb ? COMPONENT_Cb : COMPONENT_Cr; + bool CTU_ON = isCb ? CBifParams.ctuOn_Cb[ctuRsAddr] : CBifParams.ctuOn_Cr[ctuRsAddr]; + + BIF_chroma = false; + if(!isDualTree) + { + TU_VALID = currTU.blocks[compIdx].valid(); + TU_CBF = false;//if CHROMA TU is not vaild, CBF must be zero + if(TU_VALID) + { + TU_CBF = TU::getCbf(currTU, compID); + } + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17)) && (TU_VALID)); + } + else + { + TU_CBF = TU::getCbf(currTU, compID); + BIF_chroma = (CTU_ON && ((TU_CBF || isInter == false) && (currTU.cu->qp > 17))); + } + if(BIF_chroma) + { + bilateralFilter.bilateralFilterDiamond5x5_chroma(srcYuv, resYuv, currTU.cu->qp, cs.slice->clpRng(compID), currTU, isCb); + } + else + { + bool use_clip = isCb ? clipChromaIfNoBilat_Cb : clipChromaIfNoBilat_Cr; + if(use_clip && currTU.blocks[compIdx].valid()) + { + bilateralFilter.clipNotBilaterallyFilteredBlocks_chroma(srcYuv, resYuv, cs.slice->clpRng(compID), currTU, isCb); + } + } + } + } + } + } + else + { + offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); + } #else offsetCTU(area, srcYuv, resYuv, reconParams[ctuRsAddr], cs); #endif +#endif #endif ctuRsAddr++; } } //delete memory #if JVET_V0094_BILATERAL_FILTER +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(!(cs.pps->getUseBIF()) || !(cs.pps->getUseCBIF()) || !allBlksDisabled) + { +#else if (!(cs.pps->getUseBIF()) || !allBlksDisabled) { +#endif +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (!(cs.pps->getUseCBIF()) || !allBlksDisabled) + { +#else +// DO NOTHING +#endif #endif for (uint32_t i = 0; i< groupBlkStat.size(); i++) { @@ -1421,7 +2195,7 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn delete[] groupBlkStat[i]; } groupBlkStat.clear(); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER } #endif } @@ -1441,7 +2215,7 @@ void EncSampleAdaptiveOffset::decideBlkParams(CodingStructure& cs, bool* sliceEn EncSampleAdaptiveOffset::disabledRate( cs, reconParams, saoEncodingRate, saoEncodingRateChroma ); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bilateralFilter.destroy(); #endif } @@ -1482,7 +2256,7 @@ void EncSampleAdaptiveOffset::disabledRate( CodingStructure& cs, SAOBlkParam* re void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int channelBitDepth, SAOStatData* statsDataTypes , Pel* srcBlk, Pel* orgBlk, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER Pel* bifBlk, int bifStride, #endif int srcStride, int orgStride, int width, int height @@ -1495,7 +2269,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c int8_t signLeft, signRight, signDown; int64_t *diff, *count; Pel *srcLine, *orgLine; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER Pel *bifLine; #endif int* skipLinesR = m_skipLinesR[compIdx]; @@ -1508,7 +2282,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c srcLine = srcBlk; orgLine = orgBlk; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine = bifBlk; #endif diff = statsData.diff; @@ -1540,7 +2314,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c edgeType = signRight + signLeft; signLeft = -signRight; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1549,7 +2323,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1574,7 +2348,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c edgeType = signRight + signLeft; signLeft = -signRight; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1583,7 +2357,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1609,7 +2383,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c { srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1636,7 +2410,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c edgeType = signDown + signUpLine[x]; signUpLine[x]= -signDown; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1646,7 +2420,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1669,7 +2443,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c continue; } edgeType = sgn(srcLine[x] - srcLineBelow[x]) + sgn(srcLine[x] - srcLineAbove[x]); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1678,7 +2452,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1723,7 +2497,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c continue; } edgeType = sgn(srcLine[x] - srcLineAbove[x-1]) - signUpLine[x+1]; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1732,7 +2506,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif //middle lines @@ -1749,7 +2523,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c continue; } edgeType = signDown + signUpLine[x]; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1766,7 +2540,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1789,7 +2563,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c continue; } edgeType = sgn(srcLine[x] - srcLineBelow[x+1]) + sgn(srcLine[x] - srcLineAbove[x-1]); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1798,7 +2572,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1843,7 +2617,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c continue; } edgeType = sgn(srcLine[x] - srcLineAbove[x+1]) - signUpLine[x-1]; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1853,7 +2627,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif //middle lines @@ -1870,7 +2644,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c continue; } edgeType = signDown + signUpLine[x]; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1882,7 +2656,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c signUpLine[endX-1] = (int8_t)sgn(srcLineBelow[endX-1] - srcLine[endX]); srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1905,7 +2679,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c continue; } edgeType = sgn(srcLine[x] - srcLineBelow[x-1]) + sgn(srcLine[x] - srcLineAbove[x+1]); -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [edgeType] += (orgLine[x] - bifLine[x]); #else diff [edgeType] += (orgLine[x] - srcLine[x]); @@ -1914,7 +2688,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1938,7 +2712,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c { int bandIdx= srcLine[x] >> shiftBits; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [bandIdx] += (orgLine[x] - bifLine[x]); #else diff [bandIdx] += (orgLine[x] - srcLine[x]); @@ -1947,7 +2721,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } @@ -1963,7 +2737,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c for (x=startX; x< endX; x++) { int bandIdx= srcLine[x] >> shiftBits; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER diff [bandIdx] += (orgLine[x] - bifLine[x]); #else diff [bandIdx] += (orgLine[x] - srcLine[x]); @@ -1972,7 +2746,7 @@ void EncSampleAdaptiveOffset::getBlkStats(const ComponentID compIdx, const int c } srcLine += srcStride; orgLine += orgStride; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER bifLine += bifStride; #endif } diff --git a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h index 693ec51c38199b2976e98978f6e016c834545c3b..3ebfb14c0d5343a580393636fd124df1747e0293 100644 --- a/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h +++ b/source/Lib/EncoderLib/EncSampleAdaptiveOffset.h @@ -159,6 +159,9 @@ public: const bool bTestSAODisableAtPictureLevel, const double saoEncodingRate, const double saoEncodingRateChroma, const bool isPreDBFSamplesUsed, bool isGreedyMergeEncoding #if JVET_V0094_BILATERAL_FILTER ,BIFCabacEst* BifCABACEstimator +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + ,CBIFCabacEst* CBifCABACEstimator #endif ); #if JVET_W0066_CCSAO @@ -170,7 +173,7 @@ private: //methods void deriveLoopFilterBoundaryAvailibility(CodingStructure& cs, const Position &pos, bool& isLeftAvail, bool& isAboveAvail, bool& isAboveLeftAvail) const; void getStatistics(std::vector<SAOStatData**>& blkStats, PelUnitBuf& orgYuv, PelUnitBuf& srcYuv, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER PelUnitBuf& bifYuv, #endif CodingStructure& cs, bool isCalculatePreDeblockSamples = false); @@ -181,7 +184,7 @@ private: //methods #endif const double saoEncodingRate, const double saoEncodingRateChroma, const bool isGreedymergeEncoding ); void getBlkStats(const ComponentID compIdx, const int channelBitDepth, SAOStatData* statsDataTypes, Pel* srcBlk, Pel* orgBlk, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER Pel* bifBlk, int bifStride, #endif int srcStride, int orgStride, int width, int height, bool isLeftAvail, bool isRightAvail, bool isAboveAvail, bool isBelowAvail, bool isAboveLeftAvail, bool isAboveRightAvail, bool isCalculatePreDeblockSamples diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 3b84e46ed68e9a846f3a6a977be5c61059609594..13cb93d761e86bd12d34294ce360ace2f26a35cb 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1939,6 +1939,14 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui BifParams& bifParam = cs.picture->getBifParam(); m_CABACWriter->bif(*pcSlice, bifParam); } +#endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(ctuRsAddr == 0) + { + CBifParams& CBifParam = cs.picture->getCBifParam(); + m_CABACWriter->Cbif_Cb(*pcSlice, CBifParam); + m_CABACWriter->Cbif_Cr(*pcSlice, CBifParam); + } #endif m_CABACWriter->coding_tree_unit( cs, ctuArea, pcPic->m_prevQP, ctuRsAddr ); diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index cd00b85217c8ce4f9a3acac90d53e63e6f6c528d..c31b94a72eefc07b3637302c4ae93f9b7c8f682d 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -45,7 +45,7 @@ #include "CommonLib/UnitTools.h" #include "CommonLib/dtrace_next.h" #include "CommonLib/dtrace_buffer.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "CommonLib/BilateralFilter.h" #endif #include "CommonLib/MCTS.h" @@ -92,7 +92,7 @@ InterSearch::InterSearch() , m_pSplitCS (nullptr) , m_pFullCS (nullptr) , m_pcEncCfg (nullptr) -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER , m_bilateralFilter (nullptr) #endif , m_pcTrQuant (nullptr) @@ -213,7 +213,7 @@ InterSearch::~InterSearch() } void InterSearch::init( EncCfg* pcEncCfg, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* bilateralFilter, #endif TrQuant* pcTrQuant, @@ -238,7 +238,7 @@ void InterSearch::init( EncCfg* pcEncCfg, } m_defaultCachedBvs.currCnt = 0; m_pcEncCfg = pcEncCfg; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_bilateralFilter = bilateralFilter; #endif m_pcTrQuant = pcTrQuant; @@ -7724,11 +7724,66 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } else { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(isChroma(compID)) + { + if (cs.pps->getUseCBIF() && isChroma(compID) && (tu.cu->qp > 17)) + { + //chroma and bilateral + CompArea tmpArea1(compID, tu.chromaFormat, Position(0, 0), Size(resiBuf.width, resiBuf.height)); + PelBuf tmpRecChroma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecChroma.copyFrom(resiBuf); + + const CPelBuf predBuf = csFull->getPredBuf(compArea); + PelBuf recIPredBuf = csFull->slice->getPic()->getRecoBuf(compArea); + bool isCb = compID == COMPONENT_Cb ? true : false; + + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpRecChroma, predBuf, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, false, isCb); + + currCompDist = m_pcRdCost->getDistPart(orgResiBuf, tmpRecChroma, channelBitDepth, compID, DF_SSE); + } + else + { //chroma but not bilateral + currCompDist = m_pcRdCost->getDistPart(orgResiBuf, resiBuf, channelBitDepth, compID, DF_SSE); + } + } + else + { //luma but not bilateral + currCompDist = m_pcRdCost->getDistPart(orgResiBuf, resiBuf, channelBitDepth, compID, DF_SSE); + } +#else currCompDist = m_pcRdCost->getDistPart(orgResiBuf, resiBuf, channelBitDepth, compID, DF_SSE); +#endif + } +#else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(isChroma(compID)) + { + if(cs.pps->getUseCBIF() && isChroma(compID) && (tu.cu->qp > 17)){ + //chroma and bilateral + CompArea tmpArea1(compID, tu.chromaFormat, Position(0, 0), Size(resiBuf.width, resiBuf.height)); + PelBuf tmpRecChroma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecChroma.copyFrom(resiBuf); + + const CPelBuf predBuf = csFull->getPredBuf(compArea); + PelBuf recIPredBuf = csFull->slice->getPic()->getRecoBuf(compArea); + bool isCb = compID == COMPONENT_Cb ? true : false; + + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpRecChroma, predBuf, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, false, isCb); + + currCompDist = m_pcRdCost->getDistPart(orgResiBuf, tmpRecChroma, channelBitDepth, compID, DF_SSE); + } + else{//chroma but not bilateral + currCompDist = m_pcRdCost->getDistPart(orgResiBuf, resiBuf, channelBitDepth, compID, DF_SSE); + } + } + else{//luma but not bilateral + currCompDist = m_pcRdCost->getDistPart(orgResiBuf, resiBuf, channelBitDepth, compID, DF_SSE); } #else currCompDist = m_pcRdCost->getDistPart(orgResiBuf, resiBuf, channelBitDepth, compID, DF_SSE); #endif +#endif #if WCG_EXT currCompCost = m_pcRdCost->calcRdCost(currCompFracBits, currCompDist, false); @@ -8731,6 +8786,34 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa } } } +#if JVET_X0071_CHROMA_BILATERAL_FILTER + PelBuf tmpRecChroma; + if(isChroma(compID)){ + + bool isCb = compID == COMPONENT_Cb ? true : false; + const CompArea &areaUV = isCb ? cu.Cb() : cu.Cr(); + CompArea tmpArea2(isCb ? COMPONENT_Cb : COMPONENT_Cr, areaUV.chromaFormat, Position(0, 0), areaUV.size()); + tmpRecChroma = m_tmpStorageLCU.getBuf(tmpArea2); + tmpRecChroma.copyFrom(reco); + + if(cs.pps->getUseCBIF() && isChroma(compID) && (cu.qp > 17)) + { + for (auto &currTU : CU::traverseTUs(cu)) + { + Position tuPosInCu = currTU.chromaPos() - cu.chromaPos(); + PelBuf tmpSubBuf = tmpRecChroma.subBuf(tuPosInCu, currTU.chromaSize()); + bool isInter = (cu.predMode == MODE_INTER) ? true : false; + + if ((TU::getCbf(currTU, isCb ? COMPONENT_Cb : COMPONENT_Cr) || isInter == false)) + { + CompArea compArea = currTU.blocks[compID]; + PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea); + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpSubBuf, tmpSubBuf, tmpSubBuf, currTU.cu->qp, recIPredBuf, cs.slice->clpRng(compID), currTU, true, isCb); + } + } + } + } +#endif #if WCG_EXT if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || ( m_pcEncCfg->getLmcs() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))) @@ -8745,7 +8828,13 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa finalDistortion += m_pcRdCost->getDistPart(org, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); } else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + { + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecChroma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } +#else finalDistortion += m_pcRdCost->getDistPart(org, reco, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); +#endif } else #endif @@ -8756,10 +8845,43 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa } else { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + finalDistortion += m_pcRdCost->getDistPart( org, tmpRecChroma, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE ); +#else finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE ); +#endif } } #else +#if JVET_X0071_CHROMA_BILATERAL_FILTER + PelBuf tmpRecChroma; + if(isChroma(compID)) + { + bool isCb = compID == COMPONENT_Cb ? true : false; + const CompArea &areaUV = isCb ? cu.Cb() : cu.Cr(); + CompArea tmpArea2(isCb ? COMPONENT_Cb : COMPONENT_Cr, areaUV.chromaFormat, Position(0, 0), areaUV.size()); + tmpRecChroma = m_tmpStorageLCU.getBuf(tmpArea2); + tmpRecChroma.copyFrom(reco); + + if(cs.pps->getUseCBIF() && isChroma(compID) && (cu.qp > 17)) + { + + for (auto &currTU : CU::traverseTUs(cu)) + { + Position tuPosInCu = currTU.chromaPos() - cu.chromaPos(); + PelBuf tmpSubBuf = tmpRecChroma.subBuf(tuPosInCu, currTU.chromaSize()); + bool isInter = (cu.predMode == MODE_INTER) ? true : false; + + if ((TU::getCbf(currTU, isCb ? COMPONENT_Cb : COMPONENT_Cr) || isInter == false)) + { + CompArea compArea = currTU.blocks[compID]; + PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea); + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpSubBuf, tmpSubBuf, tmpSubBuf, currTU.cu->qp, recIPredBuf, cs.slice->clpRng(compID), currTU, true, isCb); + } + } + } + } +#endif #if WCG_EXT if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getLmcs() && (cs.slice->getLmcsEnabledFlag() && m_pcReshape->getCTUFlag()))) { @@ -8774,13 +8896,32 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa } else { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(isChroma(compID)){ + finalDistortion += m_pcRdCost->getDistPart(org, tmpRecChroma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else{ + finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); + } +#else finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE_WTD, &orgLuma ); +#endif } } else #endif { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(isChroma(compID)){ + finalDistortion += m_pcRdCost->getDistPart( org, tmpRecChroma, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE ); + } + else + { + finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE ); + } +#else finalDistortion += m_pcRdCost->getDistPart( org, reco, sps.getBitDepth( toChannelType( compID ) ), compID, DF_SSE ); +#endif } #endif } diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h index beee89f4936292a336fb1348a85304e1bfc80a97..e512139944d80399fa73c53dea3e81d2326411a6 100644 --- a/source/Lib/EncoderLib/InterSearch.h +++ b/source/Lib/EncoderLib/InterSearch.h @@ -48,7 +48,7 @@ #include "CommonLib/Unit.h" #include "CommonLib/UnitPartitioner.h" #include "CommonLib/RdCost.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "CommonLib/BilateralFilter.h" #endif @@ -312,7 +312,7 @@ protected: EncCfg* m_pcEncCfg; // interface to classes -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* m_bilateralFilter; #endif TrQuant* m_pcTrQuant; @@ -391,7 +391,7 @@ public: virtual ~InterSearch(); void init ( EncCfg* pcEncCfg, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* bilateralFilter, #endif TrQuant* pcTrQuant, diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index 770e6e2d413082f7cf43fc00ced523471f8b8bbb..e973656233027144567ca5ffca3ec63235802aad 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -43,7 +43,7 @@ #include "CommonLib/Rom.h" #include "CommonLib/Picture.h" #include "CommonLib/UnitTools.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "CommonLib/BilateralFilter.h" #endif @@ -60,7 +60,7 @@ IntraSearch::IntraSearch() , m_pFullCS (nullptr) , m_pBestCS (nullptr) , m_pcEncCfg (nullptr) -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER , m_bilateralFilter(nullptr) #endif , m_pcTrQuant (nullptr) @@ -216,7 +216,7 @@ IntraSearch::~IntraSearch() } void IntraSearch::init( EncCfg* pcEncCfg, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* bilateralFilter, #endif TrQuant* pcTrQuant, @@ -232,7 +232,7 @@ void IntraSearch::init( EncCfg* pcEncCfg, { CHECK(m_isInitialized, "Already initialized"); m_pcEncCfg = pcEncCfg; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER m_bilateralFilter = bilateralFilter; #endif m_pcTrQuant = pcTrQuant; @@ -3619,7 +3619,7 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp const CompArea &area = tu.blocks[compID]; const SPS &sps = *cs.sps; -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER const PPS &pps = *cs.pps; #endif @@ -3954,7 +3954,15 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); tmpRecLuma.copyFrom(piReco); } - +#if JVET_X0071_CHROMA_BILATERAL_FILTER + CompArea tmpArea2(compID, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpRecChroma; + if(isChroma(compID)) + { + tmpRecChroma = m_tmpStorageLCU.getBuf(tmpArea2); + tmpRecChroma.copyFrom(piReco); + } +#endif //===== update distortion ===== #if WCG_EXT @@ -3989,10 +3997,32 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } else { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(pps.getUseCBIF() && isChroma(compID) && (tu.cu->qp > 17)) + { + CompArea compArea = tu.blocks[compID]; + PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea); + bool isCb = compID == COMPONENT_Cb ? true : false; + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true, isCb); + } + ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecChroma, bitDepth, compID, DF_SSE_WTD, &orgLuma); +#else ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma); +#endif if( jointCbCr ) { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(compID == COMPONENT_Cr) + { + ruiDist += m_pcRdCost->getDistPart(crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma); + } + else + { + ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma); + } +#else ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma); +#endif } } } @@ -4013,16 +4043,120 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } else { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if (pps.getUseCBIF() && isChroma(compID) && (tu.cu->qp > 17)) + { + CompArea compArea = tu.blocks[compID]; + PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea); + bool isCb = compID == COMPONENT_Cb ? true : false; + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true, isCb); + } + ruiDist += m_pcRdCost->getDistPart( piOrg, tmpRecChroma, bitDepth, compID, DF_SSE ); +#else ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE ); +#endif if( jointCbCr ) { +#if JVET_X0071_CHROMA_BILATERAL_FILTER + if(compID == COMPONENT_Cr) + { + ruiDist += m_pcRdCost->getDistPart( crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE ); + } + else{ + ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE ); + } +#else ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE ); +#endif } } } #else //===== update distortion ===== +#if JVET_X0071_CHROMA_BILATERAL_FILTER + CompArea tmpArea2(compID, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpRecChroma; + if(isChroma(compID)) + { + tmpRecChroma = m_tmpStorageLCU.getBuf(tmpArea2); + tmpRecChroma.copyFrom(piReco); + } +#if WCG_EXT + if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getLmcs() && slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD())))) + { + const CPelBuf orgLuma = cs.getOrgBuf( cs.area.blocks[COMPONENT_Y] ); + if(isLuma(compID)) + { + if (compID == COMPONENT_Y && !(m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled())) + { + CompArea tmpArea1(COMPONENT_Y, area.chromaFormat, Position(0, 0), area.size()); + PelBuf tmpRecLuma = m_tmpStorageLCU.getBuf(tmpArea1); + tmpRecLuma.rspSignal( piReco, m_pcReshape->getInvLUT() ); + ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); + } + else + { + ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma); + if( jointCbCr ) + { + ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma); + } + } + } + else + { + if(pps.getUseCBIF() && isChroma(compID) && (tu.cu->qp > 17)) + { + CompArea compArea = tu.blocks[compID]; + PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea); + bool isCb = compID == COMPONENT_Cb ? true : false; + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true, isCb); + } + ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecChroma, bitDepth, compID, DF_SSE_WTD, &orgLuma); + + if( jointCbCr ) + { + if(compID == COMPONENT_Cr) + { + ruiDist += m_pcRdCost->getDistPart(crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma); + } + else + { + ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma); + } + } + } + } + else +#endif + { + if(isLuma(compID)) + { + ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE ); + } + else{ + if (pps.getUseCBIF() && isChroma(compID) && (tu.cu->qp > 17)) + { + CompArea compArea = tu.blocks[compID]; + PelBuf recIPredBuf = cs.slice->getPic()->getRecoBuf(compArea); + bool isCb = compID == COMPONENT_Cb ? true : false; + m_bilateralFilter->bilateralFilterRDOdiamond5x5_chroma(tmpRecChroma, tmpRecChroma, tmpRecChroma, tu.cu->qp, recIPredBuf, cs.slice->clpRng(compID), tu, true, isCb); + } + ruiDist += m_pcRdCost->getDistPart( piOrg, tmpRecChroma, bitDepth, compID, DF_SSE ); + } + if( jointCbCr ) + { + if(compID == COMPONENT_Cr) + { + ruiDist += m_pcRdCost->getDistPart( crOrg, tmpRecChroma, bitDepth, COMPONENT_Cr, DF_SSE ); + } + else{ + ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE ); + } + } + } +#else #if WCG_EXT if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || (m_pcEncCfg->getLmcs() && slice.getLmcsEnabledFlag() && (m_pcReshape->getCTUFlag() || (isChroma(compID) && m_pcEncCfg->getReshapeIntraCMD())))) @@ -4054,6 +4188,7 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } } #endif +#endif } void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &compID, Distortion& ruiDist, std::vector<TrMode>* trModes, const bool loadTr) diff --git a/source/Lib/EncoderLib/IntraSearch.h b/source/Lib/EncoderLib/IntraSearch.h index 1d874aa7061039dcb83a74393af85a5a0ffc247b..be55616aa4f875e8329185a6f6ff91f5124fe117 100644 --- a/source/Lib/EncoderLib/IntraSearch.h +++ b/source/Lib/EncoderLib/IntraSearch.h @@ -47,7 +47,7 @@ #include "CommonLib/TrQuant.h" #include "CommonLib/Unit.h" #include "CommonLib/RdCost.h" -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER #include "CommonLib/BilateralFilter.h" #endif #include "EncReshape.h" @@ -404,7 +404,7 @@ protected: EncCfg* m_pcEncCfg; // interface to classes -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* m_bilateralFilter; #endif TrQuant* m_pcTrQuant; @@ -434,7 +434,7 @@ public: ~IntraSearch(); void init ( EncCfg* pcEncCfg, -#if JVET_V0094_BILATERAL_FILTER +#if JVET_V0094_BILATERAL_FILTER || JVET_X0071_CHROMA_BILATERAL_FILTER BilateralFilter* bilateralFilter, #endif TrQuant* pcTrQuant, diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 42fc01cd0736bc0a0b916f9d76639676ad200a8f..d142ffb9211ce8b669c2b1629f5d9e6459787014 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -462,6 +462,14 @@ void HLSWriter::codePPS( const PPS* pcPPS ) WRITE_SVLC( pcPPS->getBIFQPOffset(), "bilateral_filter_qp_offset"); } #endif +#if JVET_X0071_CHROMA_BILATERAL_FILTER + WRITE_FLAG(pcPPS->getUseCBIF() ? 1 : 0, "chroma bilateral_filter_flag" ); + if(pcPPS->getUseCBIF()) + { + WRITE_CODE( pcPPS->getCBIFStrength(), 2, "chroma bilateral_filter_strength"); + WRITE_SVLC( pcPPS->getCBIFQPOffset(), "chroma bilateral_filter_qp_offset"); + } +#endif #if !JVET_S0132_HLS_REORDER WRITE_FLAG( pcPPS->getUseWP() ? 1 : 0, "weighted_pred_flag" ); // Use of Weighting Prediction (P_SLICE) WRITE_FLAG( pcPPS->getWPBiPred() ? 1 : 0, "weighted_bipred_flag" ); // Use of Weighting Bi-Prediction (B_SLICE) @@ -617,12 +625,19 @@ void HLSWriter::codeAlfAps( APS* pcAPS ) WRITE_FLAG( param.filterType[CHANNEL_TYPE_LUMA] == ALF_FILTER_9_EXT ? 1 : 0, "alf_luma_ext" ); for (int altIdx = 0; altIdx < param.numAlternativesLuma; ++altIdx) { +#if JVET_X0071_ALF_BAND_CLASSIFIER + WRITE_FLAG( param.lumaClassifierIdx[altIdx], "alf_luma_classifier" ); +#endif WRITE_FLAG( param.nonLinearFlag[CHANNEL_TYPE_LUMA][altIdx], "alf_luma_clip" ); WRITE_UVLC( param.numLumaFilters[altIdx] - 1, "alf_luma_num_filters_signalled_minus1" ); if ( param.numLumaFilters[altIdx] > 1 ) { const int length = ceilLog2(param.numLumaFilters[altIdx]); +#if JVET_X0071_ALF_BAND_CLASSIFIER + for( int i = 0; i < ALF_NUM_CLASSES_CLASSIFIER[(int)param.lumaClassifierIdx[altIdx]]; i++ ) +#else for( int i = 0; i < MAX_NUM_ALF_CLASSES; i++ ) +#endif { WRITE_CODE( param.filterCoeffDeltaIdx[altIdx][i], length, "alf_luma_coeff_delta_idx" ); }