diff --git a/doc/software-manual.tex b/doc/software-manual.tex index 582dcbe4f6685daedad9b725df548eabd84be4b5..3b71317ac238fe468bfca2a594682e1bae4d997f 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -856,6 +856,12 @@ Enables harmonization of Gop first field couple. Add Access Unit Delimiter NAL units between all Access Units. \\ +\Option{EnablePictureHeaderInSliceHeader} & +%\ShortOption{\None} & +\Default{1} & +Enable Picture Header to be signalled in Slice Header when encoding with single slice per picture. +\\ + \Option{ScalingRatioHor} & %\ShortOption{\None} & \Default{1.0} & @@ -1277,6 +1283,12 @@ $} \end{displaymath} \\ +\Option{Log2ParallelMergeLevel} & +%\ShortOption{\None} & +\Default{2} & +Defines the SPS-derived Log2ParallelMergeLevel variable. +\\ + \Option{MaxNumMergeCand} & %\ShortOption{\None} & \Default{5} & @@ -2233,6 +2245,18 @@ switched at CTB level. Set to 1 to disable alternative chroma filters. Value shall be in the range 1..8. \\ +\Option{CCALF} & +%\ShortOption{\None} & +\Default{true} & +Enables cross-component ALF. +\\ + +\Option{CCALFQpTh} & +%\ShortOption{\None} & +\Default{37} & +QP threshold above which the encoder reduces cross-component ALF usage. +\\ + \Option{SMVD} & %\ShortOption{\None} & \Default{false} & diff --git a/source/App/DecoderApp/DecApp.cpp b/source/App/DecoderApp/DecApp.cpp index 69d4b1f7c4d22bd4d197ee0aeccda4890f1b4a79..b6584f0754dd08616524ea3096dae8904859a3eb 100644 --- a/source/App/DecoderApp/DecApp.cpp +++ b/source/App/DecoderApp/DecApp.cpp @@ -282,6 +282,12 @@ uint32_t DecApp::decode() bool DecApp::deriveOutputLayerSet() { int vps_max_layers_minus1 = m_cDecLib.getVPS()->getMaxLayers() - 1; + if(m_iTargetOLS == - 1 || vps_max_layers_minus1 == 0) + { + m_targetDecLayerIdSet.clear(); + return true; + } + int TotalNumOlss = 0; int each_layer_is_an_ols_flag = m_cDecLib.getVPS()->getEachLayerIsAnOlsFlag(); int ols_mode_idc = m_cDecLib.getVPS()->getOlsModeIdc(); @@ -492,8 +498,12 @@ bool DecApp::isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytest ret = true; finished = true; break; - + +#if JVET_Q0775_PH_IN_SH + // NUT that may be the start of a new picture - check first bit in slice header +#else // NUT that are not the start of a new picture +#endif case NAL_UNIT_CODED_SLICE_TRAIL: case NAL_UNIT_CODED_SLICE_STSA: case NAL_UNIT_CODED_SLICE_RASL: @@ -507,6 +517,13 @@ bool DecApp::isNewPicture(ifstream *bitstreamFile, class InputByteStream *bytest case NAL_UNIT_CODED_SLICE_GDR: case NAL_UNIT_RESERVED_IRAP_VCL_11: case NAL_UNIT_RESERVED_IRAP_VCL_12: +#if JVET_Q0775_PH_IN_SH + ret = checkPictureHeaderInSliceHeaderFlag(nalu); + finished = true; + break; + + // NUT that are not the start of a new picture +#endif case NAL_UNIT_EOS: case NAL_UNIT_EOB: case NAL_UNIT_SUFFIX_APS: diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 77f765178b1b70b789850c6e9c59035a7721233f..f66a4fb1273339cee97d5608d522d50dec4ebb82 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -212,6 +212,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setNoPartitionConstraintsOverrideConstraintFlag ( !m_SplitConsOverrideEnabledFlag ); m_cEncLib.setNoSaoConstraintFlag ( !m_bUseSAO ); m_cEncLib.setNoAlfConstraintFlag ( !m_alf ); +#if JVET_Q0795_CCALF + m_cEncLib.setNoAlfConstraintFlag ( !m_ccalf ); +#endif m_cEncLib.setNoRefWraparoundConstraintFlag ( m_bNoRefWraparoundConstraintFlag ); m_cEncLib.setNoTemporalMvpConstraintFlag ( m_TMVPModeId ? false : true ); m_cEncLib.setNoSbtmvpConstraintFlag ( m_SubPuMvpMode ? false : true ); @@ -277,6 +280,9 @@ void EncApp::xInitLibCfg() m_cEncLib.setPad ( m_aiPad ); m_cEncLib.setAccessUnitDelimiter ( m_AccessUnitDelimiter ); +#if JVET_Q0775_PH_IN_SH + m_cEncLib.setEnablePictureHeaderInSliceHeader ( m_enablePictureHeaderInSliceHeader ); +#endif m_cEncLib.setMaxTempLayer ( m_maxTempLayer ); @@ -517,6 +523,11 @@ void EncApp::xInitLibCfg() m_cEncLib.setUseWP ( m_useWeightedPred ); m_cEncLib.setWPBiPred ( m_useWeightedBiPred ); +#if JVET_Q0297_MER + //====== Parallel Merge Estimation ======== + m_cEncLib.setLog2ParallelMergeLevelMinus2(m_log2ParallelMergeLevel - 2); +#endif + //====== Tiles and Slices ======== m_cEncLib.setNoPicPartitionFlag( !m_picPartitionFlag ); if( m_picPartitionFlag ) @@ -755,6 +766,10 @@ void EncApp::xInitLibCfg() m_cEncLib.setForceSingleSplitThread ( m_forceSplitSequential ); #endif m_cEncLib.setUseALF ( m_alf ); +#if JVET_Q0795_CCALF + m_cEncLib.setUseCCALF ( m_ccalf ); + m_cEncLib.setCCALFQpThreshold ( m_ccalfQpThreshold ); +#endif m_cEncLib.setLmcs ( m_lmcsEnabled ); m_cEncLib.setReshapeSignalType ( m_reshapeSignalType ); m_cEncLib.setReshapeIntraCMD ( m_intraCMD ); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index cdad7cff4d66dfd3bc7e3c999f4ffeb9b2a050e5..19e2ed64d039068ce96a2f1eca9a9daae5b618cb 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -87,6 +87,9 @@ EncAppCfg::EncAppCfg() , m_noPartitionConstraintsOverrideConstraintFlag(false) , m_bNoSaoConstraintFlag(false) , m_bNoAlfConstraintFlag(false) +#if JVET_Q0795_CCALF +, m_noCCAlfConstraintFlag(false) +#endif , m_bNoRefWraparoundConstraintFlag(false) , m_bNoTemporalMvpConstraintFlag(false) , m_bNoSbtmvpConstraintFlag(false) @@ -804,6 +807,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("ConfWinTop", m_confWinTop, 0, "Top offset for window conformance mode 3") ("ConfWinBottom", m_confWinBottom, 0, "Bottom offset for window conformance mode 3") ("AccessUnitDelimiter", m_AccessUnitDelimiter, false, "Enable Access Unit Delimiter NALUs") +#if JVET_Q0775_PH_IN_SH + ("EnablePictureHeaderInSliceHeader", m_enablePictureHeaderInSliceHeader, true, "Enable Picture Header in Slice Header") +#endif ("FrameRate,-fr", m_iFrameRate, 0, "Frame rate") ("FrameSkip,-fs", m_FrameSkip, 0u, "Number of frames to skip at start of input YUV") ("TemporalSubsampleRatio,-ts", m_temporalSubsampleRatio, 1u, "Temporal sub-sample ratio when reading input YUV") @@ -1130,6 +1136,9 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("WeightedPredP,-wpP", m_useWeightedPred, false, "Use weighted prediction in P slices") ("WeightedPredB,-wpB", m_useWeightedBiPred, false, "Use weighted (bidirectional) prediction in B slices") ("WeightedPredMethod,-wpM", tmpWeightedPredictionMethod, int(WP_PER_PICTURE_WITH_SIMPLE_DC_COMBINED_COMPONENT), "Weighted prediction method") +#if JVET_Q0297_MER + ("Log2ParallelMergeLevel", m_log2ParallelMergeLevel, 2u, "Parallel merge estimation region") +#endif ("WaveFrontSynchro", m_entropyCodingSyncEnabledFlag, false, "0: entropy coding sync disabled; 1 entropy coding sync enabled") ("ScalingList", m_useScalingListId, SCALING_LIST_OFF, "0/off: no scaling list, 1/default: default scaling lists, 2/file: scaling lists specified in ScalingListFile") ("ScalingListFile", m_scalingListFileName, string(""), "Scaling list file name. Use an empty string to produce help.") @@ -1357,7 +1366,11 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ("NumWppExtraLines", m_numWppExtraLines, 0, "Number of additional wpp lines to switch when threads are blocked") ("DebugCTU", m_debugCTU, -1, "If DebugBitstream is present, load frames up to this POC from this bitstream. Starting with DebugPOC-frame at CTUline containin debug CTU.") ("EnsureWppBitEqual", m_ensureWppBitEqual, false, "Ensure the results are equal to results with WPP-style parallelism, even if WPP is off") - ( "ALF", m_alf, true, "Adpative Loop Filter\n" ) + ( "ALF", m_alf, true, "Adaptive Loop Filter\n" ) +#if JVET_Q0795_CCALF + ( "CCALF", m_ccalf, true, "Cross-component Adaptive Loop Filter" ) + ( "CCALFQpTh", m_ccalfQpThreshold, 37, "QP threshold above which encoder reduces CCALF usage") +#endif ( "ScalingRatioHor", m_scalingRatioHor, 1.0, "Scaling ratio in hor direction" ) ( "ScalingRatioVer", m_scalingRatioVer, 1.0, "Scaling ratio in ver direction" ) ( "FractionNumFrames", m_fractionOfFrames, 1.0, "Encode a fraction of the specified in FramesToBeEncoded frames" ) @@ -2533,6 +2546,12 @@ bool EncAppCfg::xCheckParameter() } +#if JVET_Q0795_CCALF + if (!m_alf) + { + xConfirmPara( m_ccalf, "CCALF cannot be enabled when ALF is disabled" ); + } +#endif xConfirmPara( m_iSourceWidth % SPS::getWinUnitX(m_chromaFormatIDC) != 0, "Picture width must be an integer multiple of the specified chroma subsampling"); @@ -3405,7 +3424,9 @@ bool EncAppCfg::xCheckParameter() xConfirmPara( m_gcmpSEIGuardBandSamplesMinus1 < 0 || m_gcmpSEIGuardBandSamplesMinus1 > 15, "SEIGcmpGuardBandSamplesMinus1 must be in the range of 0 to 15"); } } - +#if JVET_Q0297_MER + xConfirmPara(m_log2ParallelMergeLevel < 2, "Log2ParallelMergeLevel should be larger than or equal to 2"); +#endif #if U0033_ALTERNATIVE_TRANSFER_CHARACTERISTICS_SEI xConfirmPara(m_preferredTransferCharacteristics > 255, "transfer_characteristics_idc should not be greater than 255."); #endif @@ -3422,6 +3443,9 @@ bool EncAppCfg::xCheckParameter() #endif xConfirmPara(m_useBDPCM < 0 || m_useBDPCM > 2, "BDPCM must be in range 0..2"); +#if JVET_Q0820_ACT + xConfirmPara(m_useColorTrans && (m_log2MaxTbSize == 6), "Log2MaxTbSize must be less than 6 when ACT is enabled, otherwise ACT needs to be disabled"); +#endif #undef xConfirmPara return check_failed; @@ -3604,9 +3628,15 @@ void EncAppCfg::xPrintParameter() msg( VERBOSE, "MCTS:%d ", m_MCTSEncConstraint ); msg( VERBOSE, "SAO:%d ", (m_bUseSAO)?(1):(0)); msg( VERBOSE, "ALF:%d ", m_alf ? 1 : 0 ); +#if JVET_Q0795_CCALF + msg( VERBOSE, "CCALF:%d ", m_ccalf ? 1 : 0 ); +#endif msg( VERBOSE, "WPP:%d ", (int)m_useWeightedPred); msg( VERBOSE, "WPB:%d ", (int)m_useWeightedBiPred); +#if JVET_Q0297_MER + msg( VERBOSE, "PME:%d ", m_log2ParallelMergeLevel); +#endif const int iWaveFrontSubstreams = m_entropyCodingSyncEnabledFlag ? (m_iSourceHeight + m_uiMaxCUHeight - 1) / m_uiMaxCUHeight : 1; msg( VERBOSE, " WaveFrontSynchro:%d WaveFrontSubstreams:%d", m_entropyCodingSyncEnabledFlag?1:0, iWaveFrontSubstreams); msg( VERBOSE, " ScalingList:%d ", m_useScalingListId ); @@ -3654,7 +3684,11 @@ void EncAppCfg::xPrintParameter() msg(VERBOSE, "MmvdDisNum:%d ", m_MmvdDisNum); msg(VERBOSE, "JointCbCr:%d ", m_JointCbCrMode); } +#if JVET_Q0820_ACT + m_useColorTrans = (m_chromaFormatIDC == CHROMA_444) ? m_useColorTrans : 0u; +#else m_useColorTrans = (m_chromaFormatIDC == CHROMA_444 && m_costMode != COST_LOSSLESS_CODING) ? m_useColorTrans : 0u; +#endif msg(VERBOSE, "ACT:%d ", m_useColorTrans); m_PLTMode = ( m_chromaFormatIDC == CHROMA_444) ? m_PLTMode : 0u; msg(VERBOSE, "PLT:%d ", m_PLTMode); diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 4ce37e402f737e4f6cecb69d29b34f4c1b5b426d..ead8d9d727e78d39b471bb8158bd101ff5321d21 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -115,6 +115,9 @@ protected: int m_framesToBeEncoded; ///< number of encoded frames int m_aiPad[2]; ///< number of padded pixels for width and height bool m_AccessUnitDelimiter; ///< add Access Unit Delimiter NAL units +#if JVET_Q0775_PH_IN_SH + bool m_enablePictureHeaderInSliceHeader; ///< Enable Picture Header in Slice Header +#endif InputColourSpaceConversion m_inputColourSpaceConvert; ///< colour space conversion to apply to input video bool m_snrInternalColourSpace; ///< if true, then no colour space conversion is applied for snr calculation, otherwise inverse of input is applied. bool m_outputInternalColourSpace; ///< if true, then no colour space conversion is applied for reconstructed video, otherwise inverse of input is applied. @@ -137,6 +140,9 @@ protected: bool m_noPartitionConstraintsOverrideConstraintFlag; bool m_bNoSaoConstraintFlag; bool m_bNoAlfConstraintFlag; +#if JVET_Q0795_CCALF + bool m_noCCAlfConstraintFlag; +#endif bool m_bNoRefWraparoundConstraintFlag; bool m_bNoTemporalMvpConstraintFlag; bool m_bNoSbtmvpConstraintFlag; @@ -581,6 +587,9 @@ protected: bool m_useWeightedBiPred; ///< Use of bi-directional weighted prediction in B slices WeightedPredictionMethod m_weightedPredictionMethod; +#if JVET_Q0297_MER + uint32_t m_log2ParallelMergeLevel; ///< Parallel merge estimation region +#endif uint32_t m_maxNumMergeCand; ///< Max number of merge candidates uint32_t m_maxNumAffineMergeCand; ///< Max number of affine merge candidates uint32_t m_maxNumTriangleCand; @@ -664,6 +673,10 @@ protected: bool m_forceDecodeBitstream1; bool m_alf; ///< Adaptive Loop Filter +#if JVET_Q0795_CCALF + bool m_ccalf; + int m_ccalfQpThreshold; +#endif double m_scalingRatioHor; double m_scalingRatioVer; diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp index 998041f9ca20acb7d7fec5f48a9f287a365765f6..b1ef4b056c62ed8c62b353fd8829ad0cf7703eeb 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.cpp +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.cpp @@ -63,6 +63,9 @@ AdaptiveLoopFilter::AdaptiveLoopFilter() } m_deriveClassificationBlk = deriveClassificationBlk; +#if JVET_Q0795_CCALF + m_filterCcAlf = filterBlkCcAlf<CC_ALF>; +#endif m_filter5x5Blk = filterBlk<ALF_FILTER_5>; m_filter7x7Blk = filterBlk<ALF_FILTER_7>; @@ -285,6 +288,47 @@ const int AdaptiveLoopFilter::m_classToFilterMapping[NUM_FIXED_FILTER_SETS][MAX_ { 16, 31, 32, 15, 60, 30, 4, 17, 19, 25, 22, 20, 4, 53, 19, 21, 22, 46, 25, 55, 26, 48, 63, 58, 55 }, }; +#if JVET_Q0795_CCALF +void AdaptiveLoopFilter::applyCcAlfFilter(CodingStructure &cs, ComponentID compID, const PelBuf &dstBuf, + const PelUnitBuf &recYuvExt, uint8_t *filterControl, + const short filterSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], + const int selectedFilterIdx) +{ + int ctuIdx = 0; + for( int yPos = 0; yPos < m_picHeight; yPos += m_maxCUHeight ) + { + for( int xPos = 0; xPos < m_picWidth; xPos += m_maxCUWidth ) + { + const int width = ( xPos + m_maxCUWidth > m_picWidth ) ? ( m_picWidth - xPos ) : m_maxCUWidth; + const int height = ( yPos + m_maxCUHeight > m_picHeight ) ? ( m_picHeight - yPos ) : m_maxCUHeight; + const UnitArea area( m_chromaFormat, Area( xPos, yPos, width, height ) ); + const int chromaScaleX = getComponentScaleX( compID, m_chromaFormat ); + const int chromaScaleY = getComponentScaleY( compID, m_chromaFormat ); + + Area blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY); + Area blkSrc(xPos, yPos, width, height); + + int filterIdx = + (filterControl == nullptr) + ? selectedFilterIdx + : filterControl[(yPos >> cs.pcv->maxCUHeightLog2) * cs.pcv->widthInCtus + (xPos >> cs.pcv->maxCUWidthLog2)]; + bool skipFiltering = (filterControl != nullptr && filterIdx == 0) ? true : false; + if (!skipFiltering) + { + if (filterControl != nullptr) + filterIdx--; + + const int16_t *filterCoeff = filterSet[filterIdx]; + + m_filterCcAlf(dstBuf, recYuvExt, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, m_alfVBLumaCTUHeight, + m_alfVBLumaPos); + } + ctuIdx++; + } + } +} +#endif + void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) { @@ -342,6 +386,12 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ ) { ctuEnableFlag |= m_ctuEnableFlag[compIdx][ctuIdx] > 0; +#if JVET_Q0795_CCALF + if (cu->slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1]) + { + ctuEnableFlag |= m_ccAlfFilterControl[compIdx - 1][ctuIdx] > 0; + } +#endif } int rasterSliceAlfPad = 0; if( ctuEnableFlag && isCrossedByVirtualBoundaries( cs, xPos, yPos, width, height, clipTop, clipBottom, clipLeft, clipRight, numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos, rasterSliceAlfPad ) ) @@ -417,6 +467,24 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) , m_alfVBChmaCTUHeight , m_alfVBChmaPos ); } +#if JVET_Q0795_CCALF + if (cu->slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1]) + { + const int filterIdx = m_ccAlfFilterControl[compIdx - 1][ctuIdx]; + + if (filterIdx != 0) + { + const Area blkSrc(0, 0, w >> chromaScaleX, h >> chromaScaleY); + Area blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, + height >> chromaScaleY); + + const int16_t *filterCoeff = m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1][filterIdx - 1]; + + m_filterCcAlf(recYuv.get(compID), tmpYuv, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, + m_alfVBLumaCTUHeight, m_alfVBLumaPos); + } + } +#endif } xStart = xEnd; @@ -427,46 +495,63 @@ void AdaptiveLoopFilter::ALFProcess(CodingStructure& cs) } else { - const UnitArea area( cs.area.chromaFormat, Area( xPos, yPos, width, height ) ); - if( m_ctuEnableFlag[COMPONENT_Y][ctuIdx] ) - { - Area blk( xPos, yPos, width, height ); - deriveClassification( m_classifier, tmpYuv.get( COMPONENT_Y ), blk, blk ); - short filterSetIndex = alfCtuFilterIndex[ctuIdx]; - short *coeff; - short *clip; - if (filterSetIndex >= NUM_FIXED_FILTER_SETS) + const UnitArea area( cs.area.chromaFormat, Area( xPos, yPos, width, height ) ); + if( m_ctuEnableFlag[COMPONENT_Y][ctuIdx] ) { - coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; - clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; + Area blk( xPos, yPos, width, height ); + deriveClassification( m_classifier, tmpYuv.get( COMPONENT_Y ), blk, blk ); + short filterSetIndex = alfCtuFilterIndex[ctuIdx]; + short *coeff; + short *clip; + if (filterSetIndex >= NUM_FIXED_FILTER_SETS) + { + coeff = m_coeffApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; + clip = m_clippApsLuma[filterSetIndex - NUM_FIXED_FILTER_SETS]; + } + else + { + coeff = m_fixedFilterSetCoeffDec[filterSetIndex]; + clip = m_clipDefault; + } + m_filter7x7Blk(m_classifier, recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs + , m_alfVBLumaCTUHeight + , m_alfVBLumaPos + ); } - else + + for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ ) { - coeff = m_fixedFilterSetCoeffDec[filterSetIndex]; - clip = m_clipDefault; - } - m_filter7x7Blk(m_classifier, recYuv, tmpYuv, blk, blk, COMPONENT_Y, coeff, clip, m_clpRngs.comp[COMPONENT_Y], cs - , m_alfVBLumaCTUHeight - , m_alfVBLumaPos - ); - } + ComponentID compID = ComponentID( compIdx ); + const int chromaScaleX = getComponentScaleX( compID, tmpYuv.chromaFormat ); + const int chromaScaleY = getComponentScaleY( compID, tmpYuv.chromaFormat ); - for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ ) - { - ComponentID compID = ComponentID( compIdx ); - const int chromaScaleX = getComponentScaleX( compID, tmpYuv.chromaFormat ); - const int chromaScaleY = getComponentScaleY( compID, tmpYuv.chromaFormat ); + if (m_ctuEnableFlag[compIdx][ctuIdx]) + { + Area blk(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY); + uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx]; + 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); + } +#if JVET_Q0795_CCALF + if (cu->slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1]) + { + const int filterIdx = m_ccAlfFilterControl[compIdx - 1][ctuIdx]; - if( m_ctuEnableFlag[compIdx][ctuIdx] ) - { - Area blk( xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY ); - uint8_t alt_num = m_ctuAlternative[compIdx][ctuIdx]; - 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); + if (filterIdx != 0) + { + Area blkDst(xPos >> chromaScaleX, yPos >> chromaScaleY, width >> chromaScaleX, height >> chromaScaleY); + Area blkSrc(xPos, yPos, width, height); + + const int16_t *filterCoeff = m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1][filterIdx - 1]; + + m_filterCcAlf(recYuv.get(compID), tmpYuv, blkDst, blkSrc, compID, filterCoeff, m_clpRngs, cs, + m_alfVBLumaCTUHeight, m_alfVBLumaPos); + } + } +#endif } } - } ctuIdx++; } } @@ -581,6 +666,10 @@ void AdaptiveLoopFilter::create( const int picWidth, const int picHeight, const m_numCTUsInWidth = ( m_picWidth / m_maxCUWidth ) + ( ( m_picWidth % m_maxCUWidth ) ? 1 : 0 ); m_numCTUsInHeight = ( m_picHeight / m_maxCUHeight ) + ( ( m_picHeight % m_maxCUHeight ) ? 1 : 0 ); m_numCTUsInPic = m_numCTUsInHeight * m_numCTUsInWidth; +#if JVET_Q0795_CCALF + m_filterShapesCcAlf[0].push_back(AlfFilterShape(size_CC_ALF)); + m_filterShapesCcAlf[1].push_back(AlfFilterShape(size_CC_ALF)); +#endif m_filterShapes[CHANNEL_TYPE_LUMA].push_back( AlfFilterShape( 7 ) ); m_filterShapes[CHANNEL_TYPE_CHROMA].push_back( AlfFilterShape( 5 ) ); m_alfVBLumaPos = m_maxCUHeight - ALF_VB_POS_ABOVE_CTUROW_LUMA; @@ -657,6 +746,11 @@ void AdaptiveLoopFilter::create( const int picWidth, const int picHeight, const m_clipDefault[i] = m_alfClippingValues[CHANNEL_TYPE_LUMA][0]; } m_created = true; + +#if JVET_Q0795_CCALF + m_ccAlfFilterControl[0] = new uint8_t[m_numCTUsInPic]; + m_ccAlfFilterControl[1] = new uint8_t[m_numCTUsInPic]; +#endif } void AdaptiveLoopFilter::destroy() @@ -678,6 +772,22 @@ void AdaptiveLoopFilter::destroy() m_filterShapes[CHANNEL_TYPE_LUMA].clear(); m_filterShapes[CHANNEL_TYPE_CHROMA].clear(); m_created = false; + +#if JVET_Q0795_CCALF + m_filterShapesCcAlf[0].clear(); + m_filterShapesCcAlf[1].clear(); + if ( m_ccAlfFilterControl[0] ) + { + delete [] m_ccAlfFilterControl[0]; + m_ccAlfFilterControl[0] = nullptr; + } + + if ( m_ccAlfFilterControl[1] ) + { + delete [] m_ccAlfFilterControl[1]; + m_ccAlfFilterControl[1] = nullptr; + } +#endif } void AdaptiveLoopFilter::deriveClassification( AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk ) @@ -1152,3 +1262,96 @@ void AdaptiveLoopFilter::filterBlk(AlfClassifier **classifier, const PelUnitBuf pImgYPad6 += srcStride2; } } + +#if JVET_Q0795_CCALF +template<AlfFilterType filtTypeCcAlf> +void AdaptiveLoopFilter::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) +{ + CHECK(1 << floorLog2(vbCTUHeight) != vbCTUHeight, "Not a power of 2"); + + CHECK(!isChroma(compId), "Must be chroma"); + + const SPS* sps = cs.slice->getSPS(); + ChromaFormat nChromaFormat = sps->getChromaFormatIdc(); + const int clsSizeY = 4; + const int clsSizeX = 4; + const int startHeight = blkDst.y; + const int endHeight = blkDst.y + blkDst.height; + const int startWidth = blkDst.x; + const int endWidth = blkDst.x + blkDst.width; + const int scaleX = getComponentScaleX(compId, nChromaFormat); + const int scaleY = getComponentScaleY(compId, nChromaFormat); + + CHECK( startHeight % clsSizeY, "Wrong startHeight in filtering" ); + CHECK( startWidth % clsSizeX, "Wrong startWidth in filtering" ); + CHECK( ( endHeight - startHeight ) % clsSizeY, "Wrong endHeight in filtering" ); + CHECK( ( endWidth - startWidth ) % clsSizeX, "Wrong endWidth in filtering" ); + + CPelBuf srcBuf = recSrc.get(COMPONENT_Y); + const int lumaStride = srcBuf.stride; + const Pel * lumaPtr = srcBuf.buf + blkSrc.y * lumaStride + blkSrc.x; + + const int chromaStride = dstBuf.stride; + Pel * chromaPtr = dstBuf.buf + blkDst.y * chromaStride + blkDst.x; + + for( int i = 0; i < endHeight - startHeight; i += clsSizeY ) + { + for( int j = 0; j < endWidth - startWidth; j += clsSizeX ) + { + for( int ii = 0; ii < clsSizeY; ii++ ) + { + int row = ii; + int col = j; + Pel *srcSelf = chromaPtr + col + row * chromaStride; + + int offset1 = lumaStride; + int offset2 = -lumaStride; + int offset3 = 2 * lumaStride; + row <<= scaleY; + col <<= scaleX; + const Pel *srcCross = lumaPtr + col + row * lumaStride; + + int pos = ((startHeight + i + ii) << scaleY) & (vbCTUHeight - 1); + if (pos == (vbPos - 2) || pos == (vbPos + 1)) + { + offset3 = offset1; + } + else if (pos == (vbPos - 1) || pos == vbPos) + { + offset1 = 0; + offset2 = 0; + offset3 = 0; + } + + for (int jj = 0; jj < clsSizeX; jj++) + { + const int jj2 = (jj << scaleX); + const int offset0 = 0; + + int sum = 0; + const Pel currSrcCross = srcCross[offset0 + jj2]; + sum += filterCoeff[0] * (srcCross[offset2 + jj2 ] - currSrcCross); + sum += filterCoeff[1] * (srcCross[offset0 + jj2 - 1] - currSrcCross); + sum += filterCoeff[2] * (srcCross[offset0 + jj2 + 1] - currSrcCross); + sum += filterCoeff[3] * (srcCross[offset1 + jj2 - 1] - currSrcCross); + sum += filterCoeff[4] * (srcCross[offset1 + jj2 ] - currSrcCross); + sum += filterCoeff[5] * (srcCross[offset1 + jj2 + 1] - currSrcCross); + sum += filterCoeff[6] * (srcCross[offset3 + jj2 ] - currSrcCross); + + 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; + sum += srcSelf[jj]; + srcSelf[jj] = ClipPel(sum, clpRngs.comp[compId]); + } + } + } + + chromaPtr += chromaStride * clsSizeY; + + lumaPtr += lumaStride * clsSizeY << getComponentScaleY(compId, nChromaFormat); + } +} +#endif diff --git a/source/Lib/CommonLib/AdaptiveLoopFilter.h b/source/Lib/CommonLib/AdaptiveLoopFilter.h index f93fd8e6c72fb1a6fc1b391c4da527acf33945cd..39d1731146ded03a37db884b96724846ba77b4ac 100644 --- a/source/Lib/CommonLib/AdaptiveLoopFilter.h +++ b/source/Lib/CommonLib/AdaptiveLoopFilter.h @@ -91,6 +91,13 @@ public: const CPelBuf &srcLuma, const Area &blkDst, const Area &blk, const int shift, const int vbCTUHeight, int vbPos); void deriveClassification( AlfClassifier** classifier, const CPelBuf& srcLuma, const Area& blkDst, const Area& blk ); +#if JVET_Q0795_CCALF + 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 + template<AlfFilterType filtType> static void filterBlk(AlfClassifier **classifier, const PelUnitBuf &recDst, const CPelUnitBuf &recSrc, const Area &blkDst, const Area &blk, const ComponentID compId, const short *filterSet, @@ -100,6 +107,17 @@ public: const Area &blkDst, const Area &blk, const int shift, const int vbCTUHeight, int vbPos); +#if JVET_Q0795_CCALF + void (*m_filterCcAlf)(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); + void applyCcAlfFilter(CodingStructure &cs, ComponentID compID, const PelBuf &dstBuf, const PelUnitBuf &recYuvExt, + uint8_t * filterControl, + const short filterSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], + const int selectedFilterIdx); + CcAlfFilterParam &getCcAlfFilterParam() { return m_ccAlfFilterParam; } + uint8_t* getCcAlfControlIdc(const ComponentID compID) { return m_ccAlfFilterControl[compID-1]; } +#endif void (*m_filter5x5Blk)(AlfClassifier **classifier, const PelUnitBuf &recDst, const CPelUnitBuf &recSrc, const Area &blkDst, const Area &blk, const ComponentID compId, const short *filterSet, const short *fClipSet, const ClpRng &clpRng, CodingStructure &cs, const int vbCTUHeight, @@ -117,6 +135,11 @@ public: protected: bool isCrossedByVirtualBoundaries( const CodingStructure& cs, const int xPos, const int yPos, const int width, const int height, bool& clipTop, bool& clipBottom, bool& clipLeft, bool& clipRight, int& numHorVirBndry, int& numVerVirBndry, int horVirBndryPos[], int verVirBndryPos[], int& rasterSliceAlfPad ); +#if JVET_Q0795_CCALF + static constexpr int m_scaleBits = 7; // 8-bits + CcAlfFilterParam m_ccAlfFilterParam; + uint8_t* m_ccAlfFilterControl[2]; +#endif static const int m_classToFilterMapping[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES]; static const int m_fixedFilterSetCoeff[ALF_FIXED_FILTER_NUM][MAX_NUM_ALF_LUMA_COEFF]; short m_fixedFilterSetCoeffDec[NUM_FIXED_FILTER_SETS][MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; @@ -127,6 +150,9 @@ protected: short m_chromaCoeffFinal[MAX_NUM_ALF_ALTERNATIVES_CHROMA][MAX_NUM_ALF_CHROMA_COEFF]; AlfParam* m_alfParamChroma; Pel m_alfClippingValues[MAX_NUM_CHANNEL_TYPE][MaxAlfNumClippingValues]; +#if JVET_Q0795_CCALF + std::vector<AlfFilterShape> m_filterShapesCcAlf[2]; +#endif std::vector<AlfFilterShape> m_filterShapes[MAX_NUM_CHANNEL_TYPE]; AlfClassifier** m_classifier; short m_coeffFinal[MAX_NUM_ALF_CLASSES * MAX_NUM_ALF_LUMA_COEFF]; diff --git a/source/Lib/CommonLib/AlfParameters.h b/source/Lib/CommonLib/AlfParameters.h index abaef3a4968ab6d5dd6535656592652056abe129..45fa9b275ddc919a153392eff223b38aa0d7c6d4 100644 --- a/source/Lib/CommonLib/AlfParameters.h +++ b/source/Lib/CommonLib/AlfParameters.h @@ -48,9 +48,17 @@ enum AlfFilterType { ALF_FILTER_5, ALF_FILTER_7, +#if JVET_Q0795_CCALF + CC_ALF, +#endif ALF_NUM_OF_FILTER_TYPES }; + +#if JVET_Q0795_CCALF +static const int size_CC_ALF = -1; +#endif + struct AlfFilterShape { AlfFilterShape( int size ) @@ -97,6 +105,16 @@ struct AlfFilterShape filterType = ALF_FILTER_7; } +#if JVET_Q0795_CCALF + else if (size == size_CC_ALF) + { + size = 4; + filterLength = 8; + numCoeff = 8; + filterSize = 8; + filterType = CC_ALF; + } +#endif else { filterType = ALF_NUM_OF_FILTER_TYPES; @@ -231,6 +249,43 @@ struct AlfParam } }; +#if JVET_Q0795_CCALF +struct CcAlfFilterParam +{ + bool ccAlfFilterEnabled[2]; + bool ccAlfFilterIdxEnabled[2][MAX_NUM_CC_ALF_FILTERS]; + uint8_t ccAlfFilterCount[2]; + short ccAlfCoeff[2][MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF]; + int newCcAlfFilter[2]; + int numberValidComponents; + CcAlfFilterParam() + { + reset(); + } + void reset() + { + std::memset( ccAlfFilterEnabled, false, sizeof( ccAlfFilterEnabled ) ); + std::memset( ccAlfFilterIdxEnabled, false, sizeof( ccAlfFilterIdxEnabled ) ); + std::memset( ccAlfCoeff, 0, sizeof( ccAlfCoeff ) ); + ccAlfFilterCount[0] = ccAlfFilterCount[1] = MAX_NUM_CC_ALF_FILTERS; + numberValidComponents = 3; + newCcAlfFilter[0] = newCcAlfFilter[1] = 0; + } + const CcAlfFilterParam& operator = ( const CcAlfFilterParam& src ) + { + std::memcpy( ccAlfFilterEnabled, src.ccAlfFilterEnabled, sizeof( ccAlfFilterEnabled ) ); + std::memcpy( ccAlfFilterIdxEnabled, src.ccAlfFilterIdxEnabled, sizeof( ccAlfFilterIdxEnabled ) ); + std::memcpy( ccAlfCoeff, src.ccAlfCoeff, sizeof( ccAlfCoeff ) ); + ccAlfFilterCount[0] = src.ccAlfFilterCount[0]; + ccAlfFilterCount[1] = src.ccAlfFilterCount[1]; + numberValidComponents = src.numberValidComponents; + newCcAlfFilter[0] = src.newCcAlfFilter[0]; + newCcAlfFilter[1] = src.newCcAlfFilter[1]; + + return *this; + } +}; +#endif //! \} #endif // end of #ifndef __ALFPARAMETERS__ diff --git a/source/Lib/CommonLib/Buffer.cpp b/source/Lib/CommonLib/Buffer.cpp index e1f967f14fef717a85f2c5904e8cc6377feb69eb..8320dbe7c8ae76e93689d0b7b581b5681bd9696d 100644 --- a/source/Lib/CommonLib/Buffer.cpp +++ b/source/Lib/CommonLib/Buffer.cpp @@ -779,7 +779,11 @@ const CPelUnitBuf PelStorage::getBuf( const UnitArea &unit ) const } template<> +#if JVET_Q0820_ACT +void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward, const ClpRng& clpRng) +#else void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward) +#endif { const Pel* pOrg0 = bufs[COMPONENT_Y].buf; const Pel* pOrg1 = bufs[COMPONENT_Cb].buf; @@ -793,6 +797,9 @@ void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forwa int width = bufs[COMPONENT_Y].width; int height = bufs[COMPONENT_Y].height; +#if JVET_Q0820_ACT + int maxAbsclipBD = (1 << (clpRng.bd + 1)) - 1; +#endif int r, g, b; int y0, cg, co; @@ -810,12 +817,21 @@ void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forwa g = pOrg0[x]; b = pOrg1[x]; +#if JVET_Q0820_ACT + co = r - b; + int t = b + (co >> 1); + cg = g - t; + pDst0[x] = t + (cg >> 1); + pDst1[x] = cg; + pDst2[x] = co; +#else pDst0[x] = (g << 1) + r + b; pDst1[x] = (g << 1) - r - b; pDst2[x] = ((r - b) << 1); pDst0[x] = (pDst0[x] + 2) >> 2; pDst1[x] = (pDst1[x] + 2) >> 2; pDst2[x] = (pDst2[x] + 2) >> 2; +#endif } pOrg0 += strideOrg; pOrg1 += strideOrg; @@ -835,9 +851,20 @@ void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forwa cg = pOrg1[x]; co = pOrg2[x]; +#if JVET_Q0820_ACT + y0 = Clip3((-maxAbsclipBD - 1), maxAbsclipBD, y0); + cg = Clip3((-maxAbsclipBD - 1), maxAbsclipBD, cg); + co = Clip3((-maxAbsclipBD - 1), maxAbsclipBD, co); + + int t = y0 - (cg >> 1); + pDst0[x] = cg + t; + pDst1[x] = t - (co >> 1); + pDst2[x] = co + pDst1[x]; +#else pDst0[x] = (y0 + cg); pDst1[x] = (y0 - cg - co); pDst2[x] = (y0 - cg + co); +#endif } pOrg0 += strideOrg; diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h index 9b461389d48aa12dc181aa7d4dac732a7caca5c2..0fbd97a5edcceb94333a08174c9ad91a48e0a555 100644 --- a/source/Lib/CommonLib/Buffer.h +++ b/source/Lib/CommonLib/Buffer.h @@ -779,7 +779,11 @@ struct UnitBuf UnitBuf< T> subBuf (const UnitArea& subArea); const UnitBuf<const T> subBuf (const UnitArea& subArea) const; +#if JVET_Q0820_ACT + void colorSpaceConvert(const UnitBuf<T> &other, const bool forward, const ClpRng& clpRng); +#else void colorSpaceConvert(const UnitBuf<T> &other, const bool forward); +#endif }; typedef UnitBuf< Pel> PelUnitBuf; @@ -880,13 +884,21 @@ void UnitBuf<T>::addAvg(const UnitBuf<const T> &other1, const UnitBuf<const T> & } template<typename T> +#if JVET_Q0820_ACT +void UnitBuf<T>::colorSpaceConvert(const UnitBuf<T> &other, const bool forward, const ClpRng& clpRng) +#else void UnitBuf<T>::colorSpaceConvert(const UnitBuf<T> &other, const bool forward) +#endif { THROW("Type not supported"); } template<> +#if JVET_Q0820_ACT +void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward, const ClpRng& clpRng); +#else void UnitBuf<Pel>::colorSpaceConvert(const UnitBuf<Pel> &other, const bool forward); +#endif template<typename T> void UnitBuf<T>::extendSingleBorderPel() diff --git a/source/Lib/CommonLib/CodingStatistics.h b/source/Lib/CommonLib/CodingStatistics.h index 375ed6ec212e215c9472c0daca7185bde3b8a6f7..59b610717e1fd61074fa6cb2c88217775b98f38b 100644 --- a/source/Lib/CommonLib/CodingStatistics.h +++ b/source/Lib/CommonLib/CodingStatistics.h @@ -117,6 +117,9 @@ enum CodingStatisticsType STATS__CABAC_BITS__MULTI_REF_LINE, STATS__CABAC_BITS__SYMMVD_FLAG, STATS__CABAC_BITS__BDPCM_MODE, +#if JVET_Q0795_CCALF + STATS__CABAC_BITS__CROSS_COMPONENT_ALF_BLOCK_LEVEL_IDC, +#endif STATS__TOOL_TOTAL_FRAME,// This is a special case and is not included in the report. STATS__TOOL_AFF, STATS__TOOL_EMT, @@ -209,6 +212,9 @@ static inline const char* getName(CodingStatisticsType name) "CABAC_BITS__MULTI_REF_LINE", "CABAC_BITS__SYMMVD_FLAG", "CABAC_BITS__BDPCM_MODE", +#if JVET_Q0795_CCALF + "CABAC_BITS__CROSS_COMPONENT_ALF_BLOCK_LEVEL_IDC", +#endif "TOOL_FRAME", "TOOL_AFFINE", "TOOL_EMT", diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index 336daef4fdb05d365d34eff86c583b47ac09e3c8..b9282a2e30d3d9393430d87f96d3e6e166b54300 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -908,6 +908,31 @@ void CodingStructure::reorderPrevPLT(PLTBuf& prevPLT, uint8_t curPLTSize[MAX_NUM } } +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU +void CodingStructure::setPrevPLT(PLTBuf predictor) +{ + for (int comp = 0; comp < MAX_NUM_CHANNEL_TYPE; comp++) + { + prevPLT.curPLTSize[comp] = predictor.curPLTSize[comp]; + } + for (int comp = 0; comp < MAX_NUM_COMPONENT; comp++) + { + memcpy(prevPLT.curPLT[comp], predictor.curPLT[comp], MAXPLTPREDSIZE * sizeof(Pel)); + } +} +void CodingStructure::storePrevPLT(PLTBuf& predictor) +{ + for (int comp = 0; comp < MAX_NUM_CHANNEL_TYPE; comp++) + { + predictor.curPLTSize[comp] = prevPLT.curPLTSize[comp]; + } + for (int comp = 0; comp < MAX_NUM_COMPONENT; comp++) + { + memcpy(predictor.curPLT[comp], prevPLT.curPLT[comp], MAXPLTPREDSIZE * sizeof(Pel)); + } +} +#endif + void CodingStructure::rebindPicBufs() { CHECK( parent, "rebindPicBufs can only be used for the top level CodingStructure" ); diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index 317e330ba33e86f62432527e1ab5182a0c0ad072..227a90d21933e8d575862c3da3e295f0b4ac9f70 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -202,7 +202,10 @@ public: PLTBuf prevPLT; void resetPrevPLT(PLTBuf& prevPLT); void reorderPrevPLT(PLTBuf& prevPLT, uint8_t curPLTSize[MAX_NUM_CHANNEL_TYPE], Pel curPLT[MAX_NUM_COMPONENT][MAXPLTSIZE], bool reuseflag[MAX_NUM_CHANNEL_TYPE][MAXPLTPREDSIZE], uint32_t compBegin, uint32_t numComp, bool jointPLT); - +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + void setPrevPLT(PLTBuf predictor); + void storePrevPLT(PLTBuf& predictor); +#endif private: // needed for TU encoding diff --git a/source/Lib/CommonLib/CommonDef.h b/source/Lib/CommonLib/CommonDef.h index f24085c106c07b6c6028cd2bd81a9fcccf32d1f8..fb83cf5b8b4b13bc96acbccc099206c2aa30b324 100644 --- a/source/Lib/CommonLib/CommonDef.h +++ b/source/Lib/CommonLib/CommonDef.h @@ -187,6 +187,12 @@ static const int MAX_NUM_ALF_CHROMA_COEFF = 7; static const int MAX_ALF_FILTER_LENGTH = 7; 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_Q0795_CCALF +#define MAX_NUM_CC_ALF_FILTERS 4 +static constexpr int MAX_NUM_CC_ALF_CHROMA_COEFF = 8; +static constexpr int CCALF_DYNAMIC_RANGE = 6; +static constexpr int CCALF_BITS_PER_COEFF_LEVEL = 3; +#endif static const int ALF_FIXED_FILTER_NUM = 64; static const int ALF_CTB_MAX_NUM_APS = 8; @@ -479,8 +485,12 @@ static const int ENC_PPS_ID_RPR = 3; static const int SCALE_RATIO_BITS = 14; static const int MAX_SCALING_RATIO = 2; // max downsampling ratio for RPR static const std::pair<int, int> SCALE_1X = std::pair<int, int>( 1 << SCALE_RATIO_BITS, 1 << SCALE_RATIO_BITS ); // scale ratio 1x +#if JVET_Q0820_ACT +static const int DELTA_QP_ACT[4] = { -5, 1, 3, 1 }; +#else static const int DELTA_QP_FOR_Y_Cg = -5; static const int DELTA_QP_FOR_Co = -3; +#endif // ==================================================================================================================== // Macro functions @@ -700,6 +710,11 @@ static inline int ceilLog2(uint32_t x) #define PARL_PARAM0(DEF) #endif +#if JVET_Q0795_CCALF +static const uint32_t CCALF_CANDS_COEFF_NR = 8; +static const int CCALF_SMALL_TAB[CCALF_CANDS_COEFF_NR] = { 0, 1, 2, 4, 8, 16, 32, 64 }; +#endif + //! \} #endif // end of #ifndef __COMMONDEF__ diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 749b8673911c7b3ddbd2404daa1bcc53481c306c..840e718022d7fe96554c26ba30c06e479855d9e6 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -825,6 +825,16 @@ const CtxSet ContextSetCfg::AlfUseTemporalFilt = ContextSetCfg::addCtxSet { 0, }, }); +#if JVET_Q0795_CCALF +const CtxSet ContextSetCfg::CcAlfFilterControlFlag = ContextSetCfg::addCtxSet +({ + { 35, 35, 35, 35, 35, 35 }, + { 35, 35, 35, 35, 35, 35 }, + { 35, 35, 35, 35, 35, 35 }, + { DWS, DWS, DWS, DWS, DWS, DWS }, +}); +#endif + const CtxSet ContextSetCfg::CiipFlag = ContextSetCfg::addCtxSet ({ { 50, }, diff --git a/source/Lib/CommonLib/Contexts.h b/source/Lib/CommonLib/Contexts.h index e831206ce0d8cb2ab264fcfc706bff726236383e..d17ce051c9c97dda638745f13f97ae85fb3c35a9 100644 --- a/source/Lib/CommonLib/Contexts.h +++ b/source/Lib/CommonLib/Contexts.h @@ -263,6 +263,9 @@ public: static const CtxSet ctbAlfFlag; static const CtxSet ctbAlfAlternative; static const CtxSet AlfUseTemporalFilt; +#if JVET_Q0795_CCALF + static const CtxSet CcAlfFilterControlFlag; +#endif static const CtxSet CiipFlag; static const CtxSet SmvdFlag; static const CtxSet IBCFlag; diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index f2ca851eae904fbfd67aee1d9ff870f6a0b0566f..5ab5c8486362ccb84df10cf2020324d8627c5f32 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -1227,8 +1227,13 @@ void LoopFilter::xEdgeFilterChroma(const CodingUnit& cu, const DeblockEdgeDir ed const TransformUnit& tuQ = *cuQ.cs->getTU(posQ, cuQ.chType); const TransformUnit& tuP = *cuP.cs->getTU(posP, cuP.chType); +#if JVET_Q0820_ACT + const QpParam cQP(tuP, ComponentID(chromaIdx + 1), -MAX_INT, false); + const QpParam cQQ(tuQ, ComponentID(chromaIdx + 1), -MAX_INT, false); +#else const QpParam cQP(tuP, ComponentID(chromaIdx + 1)); const QpParam cQQ(tuQ, ComponentID(chromaIdx + 1)); +#endif const int qpBdOffset = tuP.cs->sps->getQpBDOffset(toChannelType(ComponentID(chromaIdx + 1))); int baseQp_P = cQP.Qp(0) - qpBdOffset; int baseQp_Q = cQQ.Qp(0) - qpBdOffset; diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp index f30351c8ece34e456fd51111ed6408b4044da9f6..90c526ab907779ec1df3ccfa90596db7ce9370e7 100644 --- a/source/Lib/CommonLib/Quant.cpp +++ b/source/Lib/CommonLib/Quant.cpp @@ -70,6 +70,9 @@ QpParam::QpParam(const int qpy, const ChromaFormat chFmt, const int dqp , const SPS *sps +#if JVET_Q0820_ACT + , const bool applyACTQpoffset +#endif ) { int baseQp; @@ -84,6 +87,12 @@ QpParam::QpParam(const int qpy, baseQp = Clip3(-qpBdOffset, MAX_QP, baseQp + chromaQPOffset) + qpBdOffset; } +#if JVET_Q0820_ACT + if (applyACTQpoffset) + { + baseQp += DELTA_QP_ACT[compID]; + } +#endif baseQp = Clip3( 0, MAX_QP+qpBdOffset, baseQp + dqp ); Qps[0] =baseQp; @@ -98,7 +107,11 @@ QpParam::QpParam(const int qpy, rems[1] = baseQpTS % 6; } +#if JVET_Q0820_ACT +QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int QP /*= -MAX_INT*/, const bool allowACTQpoffset /*= true*/) +#else QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int QP /*= -MAX_INT*/) +#endif { int chromaQpOffset = 0; ComponentID compID = MAP_CHROMA(compIDX); @@ -116,7 +129,12 @@ QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int int dqp = 0; const bool useJQP = isChroma(compID) && (abs(TU::getICTMode(tu)) == 2); +#if JVET_Q0820_ACT + bool applyACTQpoffset = tu.cu->colorTransform && allowACTQpoffset; + *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, useJQP ? JOINT_CbCr : compID, tu.cs->sps->getQpBDOffset(toChannelType(compID)), tu.cs->sps->getMinQpPrimeTsMinus4(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp, tu.cs->sps, applyACTQpoffset); +#else *this = QpParam(QP <= -MAX_INT ? tu.cu->qp : QP, useJQP ? JOINT_CbCr : compID, tu.cs->sps->getQpBDOffset(toChannelType(compID)), tu.cs->sps->getMinQpPrimeTsMinus4(toChannelType(compID)), chromaQpOffset, tu.chromaFormat, dqp, tu.cs->sps); +#endif } @@ -1255,7 +1273,11 @@ void Quant::lambdaAdjustColorTrans(bool forward) for (uint8_t component = 0; component < MAX_NUM_COMPONENT; component++) { ComponentID compID = (ComponentID)component; +#if JVET_Q0820_ACT + int delta_QP = DELTA_QP_ACT[compID]; +#else int delta_QP = (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg); +#endif double lamdbaAdjustRate = pow(2.0, delta_QP / 3.0); m_lambdasStore[0][component] = m_lambdas[component]; diff --git a/source/Lib/CommonLib/Quant.h b/source/Lib/CommonLib/Quant.h index d2ffa8bbf336cd14f2ccbaf77ccd0ca0813bf71c..c5c638a8acabe25cacce59033d5ca8627acc4e05 100644 --- a/source/Lib/CommonLib/Quant.h +++ b/source/Lib/CommonLib/Quant.h @@ -82,11 +82,18 @@ private: const ChromaFormat chFmt, const int dqp , const SPS *sps +#if JVET_Q0820_ACT + , const bool applyACTQpoffset +#endif ); public: +#if JVET_Q0820_ACT + QpParam(const TransformUnit& tu, const ComponentID &compID, const int QP = -MAX_INT, const bool allowACTQpoffset = true); +#else QpParam(const TransformUnit& tu, const ComponentID &compID, const int QP = -MAX_INT); +#endif int Qp ( const bool ts ) const { return Qps [ts?1:0]; } int per( const bool ts ) const { return pers[ts?1:0]; } diff --git a/source/Lib/CommonLib/RdCost.cpp b/source/Lib/CommonLib/RdCost.cpp index 7f48f5d5ea9fca804b4e8de7f230cb99dec5add3..7c0960cb71eade8f2df88a1b26038d034d460c63 100644 --- a/source/Lib/CommonLib/RdCost.cpp +++ b/source/Lib/CommonLib/RdCost.cpp @@ -92,7 +92,11 @@ void RdCost::lambdaAdjustColorTrans(bool forward, ComponentID componentID) for (uint8_t component = 0; component < MAX_NUM_COMPONENT; component++) { ComponentID compID = (ComponentID)component; +#if JVET_Q0820_ACT + int delta_QP = DELTA_QP_ACT[compID]; +#else int delta_QP = (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg); +#endif double lamdbaAdjustRate = pow(2.0, delta_QP / 3.0); m_lambdaStore[0][component] = m_dLambda; diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 9602f7e4804a846b02be53a810130281b6ab20df..d779e5c594f970f46ea64de41ba8dda599f4aaa4 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -53,7 +53,13 @@ Slice::Slice() , m_iAssociatedIRAPType ( NAL_UNIT_INVALID ) , m_rpl0Idx ( -1 ) , m_rpl1Idx ( -1 ) +#if JVET_Q0155_COLOUR_ID +, m_colourPlaneId ( 0 ) +#endif , m_eNalUnitType ( NAL_UNIT_CODED_SLICE_IDR_W_RADL ) +#if JVET_Q0775_PH_IN_SH +, m_pictureHeaderInSliceHeader ( false ) +#endif , m_eSliceType ( I_SLICE ) , m_iSliceQp ( 0 ) , m_ChromaQpAdjEnabled ( false ) @@ -128,6 +134,12 @@ Slice::Slice() } memset(m_alfApss, 0, sizeof(m_alfApss)); +#if JVET_Q0795_CCALF + m_ccAlfFilterParam.reset(); + resetTileGroupAlfEnabledFlag(); + resetTileGroupCcAlCbfEnabledFlag(); + resetTileGroupCcAlCrfEnabledFlag(); +#endif m_sliceMap.initSliceMap(); } @@ -145,7 +157,9 @@ void Slice::initSlice() m_aiNumRefIdx[i] = 0; } m_colFromL0Flag = true; - +#if JVET_Q0155_COLOUR_ID + m_colourPlaneId = 0; +#endif m_colRefIdx = 0; initEqualRef(); @@ -171,6 +185,13 @@ void Slice::initSlice() m_isDRAP = false; m_latestDRAPPOC = MAX_INT; resetTileGroupAlfEnabledFlag(); +#if JVET_Q0795_CCALF + m_ccAlfFilterParam.reset(); + m_tileGroupCcAlfCbEnabledFlag = 0; + m_tileGroupCcAlfCrEnabledFlag = 0; + m_tileGroupCcAlfCbApsId = -1; + m_tileGroupCcAlfCrApsId = -1; +#endif } void Slice::inheritFromPicHeader( PicHeader *picHeader, const PPS *pps, const SPS *sps ) @@ -212,7 +233,15 @@ void Slice::inheritFromPicHeader( PicHeader *picHeader, const PPS *pps, const SP setTileGroupAlfEnabledFlag(COMPONENT_Cr, picHeader->getAlfEnabledFlag(COMPONENT_Cr)); setTileGroupNumAps(picHeader->getNumAlfAps()); setAlfAPSs(picHeader->getAlfAPSs()); - setTileGroupApsIdChroma(picHeader->getAlfApsIdChroma()); + setTileGroupApsIdChroma(picHeader->getAlfApsIdChroma()); +#if JVET_Q0795_CCALF + setTileGroupCcAlfCbEnabledFlag(picHeader->getCcAlfEnabledFlag(COMPONENT_Cb)); + setTileGroupCcAlfCrEnabledFlag(picHeader->getCcAlfEnabledFlag(COMPONENT_Cr)); + setTileGroupCcAlfCbApsId(picHeader->getCcAlfCbApsId()); + setTileGroupCcAlfCrApsId(picHeader->getCcAlfCrApsId()); + m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] = picHeader->getCcAlfEnabledFlag(COMPONENT_Cb); + m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] = picHeader->getCcAlfEnabledFlag(COMPONENT_Cr); +#endif } void Slice::setNumEntryPoints( const PPS *pps ) @@ -814,6 +843,15 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll) m_scalingRatio[i][j] = pSrc->m_scalingRatio[i][j]; } } +#if JVET_Q0795_CCALF + m_ccAlfFilterParam = pSrc->m_ccAlfFilterParam; + m_ccAlfFilterControl[0] = pSrc->m_ccAlfFilterControl[0]; + m_ccAlfFilterControl[1] = pSrc->m_ccAlfFilterControl[1]; + m_tileGroupCcAlfCbEnabledFlag = pSrc->m_tileGroupCcAlfCbEnabledFlag; + m_tileGroupCcAlfCrEnabledFlag = pSrc->m_tileGroupCcAlfCrEnabledFlag; + m_tileGroupCcAlfCbApsId = pSrc->m_tileGroupCcAlfCbApsId; + m_tileGroupCcAlfCrApsId = pSrc->m_tileGroupCcAlfCrApsId; +#endif } @@ -1563,7 +1601,9 @@ PicHeader::PicHeader() , m_loopFilterAcrossVirtualBoundariesDisabledFlag ( 0 ) , m_numVerVirtualBoundaries ( 0 ) , m_numHorVirtualBoundaries ( 0 ) +#if !JVET_Q0155_COLOUR_ID , m_colourPlaneId ( 0 ) +#endif , m_picOutputFlag ( true ) , m_picRplPresentFlag ( 0 ) , m_pRPL0 ( 0 ) @@ -1653,7 +1693,9 @@ void PicHeader::initPicHeader() m_loopFilterAcrossVirtualBoundariesDisabledFlag = 0; m_numVerVirtualBoundaries = 0; m_numHorVirtualBoundaries = 0; +#if !JVET_Q0155_COLOUR_ID m_colourPlaneId = 0; +#endif m_picOutputFlag = true; m_picRplPresentFlag = 0; m_pRPL0 = 0; @@ -1747,7 +1789,7 @@ SPS::SPS() , m_SBT ( false ) , m_ISP ( false ) , m_chromaFormatIdc (CHROMA_420) -, m_separateColourPlaneFlag(0) +, m_separateColourPlaneFlag ( 0 ) , m_uiMaxTLayers ( 1) // Structure , m_maxWidthInLumaSamples (352) diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index b9548511340b5066a17fc95c00f5d225ebad1ee2..fc5bfaf13377f04c14ded8c19120f2d63183a45d 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -242,6 +242,9 @@ class ConstraintInfo bool m_noPartitionConstraintsOverrideConstraintFlag; bool m_noSaoConstraintFlag; bool m_noAlfConstraintFlag; +#if JVET_Q0795_CCALF + bool m_noCCAlfConstraintFlag; +#endif bool m_noRefWraparoundConstraintFlag; bool m_noTemporalMvpConstraintFlag; bool m_noSbtmvpConstraintFlag; @@ -286,6 +289,9 @@ public: , m_noPartitionConstraintsOverrideConstraintFlag(false) , m_noSaoConstraintFlag (false) , m_noAlfConstraintFlag (false) +#if JVET_Q0795_CCALF + , m_noCCAlfConstraintFlag (false) +#endif , m_noRefWraparoundConstraintFlag(false) , m_noTemporalMvpConstraintFlag(false) , m_noSbtmvpConstraintFlag (false) @@ -353,6 +359,10 @@ public: void setNoSaoConstraintFlag(bool bVal) { m_noSaoConstraintFlag = bVal; } bool getNoAlfConstraintFlag() const { return m_noAlfConstraintFlag; } void setNoAlfConstraintFlag(bool bVal) { m_noAlfConstraintFlag = bVal; } +#if JVET_Q0795_CCALF + bool getNoCCAlfConstraintFlag() const { return m_noCCAlfConstraintFlag; } + void setNoCCAlfConstraintFlag(bool val) { m_noCCAlfConstraintFlag = val; } +#endif bool getNoJointCbCrConstraintFlag() const { return m_noJointCbCrConstraintFlag; } void setNoJointCbCrConstraintFlag(bool bVal) { m_noJointCbCrConstraintFlag = bVal; } bool getNoRefWraparoundConstraintFlag() const { return m_noRefWraparoundConstraintFlag; } @@ -1128,7 +1138,9 @@ private: ProfileTierLevel m_profileTierLevel; bool m_alfEnabledFlag; - +#if JVET_Q0795_CCALF + bool m_ccalfEnabledFlag; +#endif bool m_wrapAroundEnabledFlag; unsigned m_wrapAroundOffset; unsigned m_IBCFlag; @@ -1166,6 +1178,10 @@ private: bool m_rprEnabledFlag; bool m_interLayerPresentFlag; +#if JVET_Q0297_MER + uint32_t m_log2ParallelMergeLevelMinus2; +#endif + public: SPS(); @@ -1323,6 +1339,10 @@ public: bool getALFEnabledFlag() const { return m_alfEnabledFlag; } void setALFEnabledFlag( bool b ) { m_alfEnabledFlag = b; } +#if JVET_Q0795_CCALF +bool getCCALFEnabledFlag() const { return m_ccalfEnabledFlag; } +void setCCALFEnabledFlag( bool b ) { m_ccalfEnabledFlag = b; } +#endif void setJointCbCrEnabledFlag(bool bVal) { m_JointCbCrEnabledFlag = bVal; } bool getJointCbCrEnabledFlag() const { return m_JointCbCrEnabledFlag; } @@ -1470,6 +1490,10 @@ public: bool getInterLayerPresentFlag() const { return m_interLayerPresentFlag; } void setInterLayerPresentFlag( bool b ) { m_interLayerPresentFlag = b; } +#if JVET_Q0297_MER + uint32_t getLog2ParallelMergeLevelMinus2() const { return m_log2ParallelMergeLevelMinus2; } + void setLog2ParallelMergeLevelMinus2(uint32_t mrgLevel) { m_log2ParallelMergeLevelMinus2 = mrgLevel; } +#endif }; @@ -1835,6 +1859,9 @@ private: AlfParam m_alfAPSParam; SliceReshapeInfo m_reshapeAPSInfo; ScalingList m_scalingListApsInfo; +#if JVET_Q0795_CCALF + CcAlfFilterParam m_ccAlfAPSParam; +#endif public: APS(); @@ -1857,6 +1884,10 @@ public: SliceReshapeInfo& getReshaperAPSInfo() { return m_reshapeAPSInfo; } void setScalingList( ScalingList& scalingListAPSInfo ) { m_scalingListApsInfo = scalingListAPSInfo; } ScalingList& getScalingList() { return m_scalingListApsInfo; } +#if JVET_Q0795_CCALF + void setCcAlfAPSParam(CcAlfFilterParam& ccAlfAPSParam) { m_ccAlfAPSParam = ccAlfAPSParam; } + CcAlfFilterParam& getCcAlfAPSParam() { return m_ccAlfAPSParam; } +#endif }; struct WPScalingParam { @@ -1901,7 +1932,9 @@ private: unsigned m_numHorVirtualBoundaries; //!< number of horizontal virtual boundaries unsigned m_virtualBoundariesPosX[3]; //!< horizontal virtual boundary positions unsigned m_virtualBoundariesPosY[3]; //!< vertical virtual boundary positions +#if !JVET_Q0155_COLOUR_ID unsigned m_colourPlaneId; //!< 4:4:4 colour plane ID +#endif bool m_picOutputFlag; //!< picture output flag bool m_picRplPresentFlag; //!< reference lists present in picture header or not const ReferencePictureList* m_pRPL0; //!< pointer to RPL for L0, either in the SPS or the local RPS in the picture header @@ -1933,6 +1966,11 @@ private: int m_numAlfAps; //!< number of alf aps active for the picture std::vector<int> m_alfApsId; //!< list of alf aps for the picture int m_alfChromaApsId; //!< chroma alf aps ID +#if JVET_Q0795_CCALF + bool m_ccalfEnabledFlag[MAX_NUM_COMPONENT]; + int m_ccalfCbApsId; + int m_ccalfCrApsId; +#endif bool m_depQuantEnabledFlag; //!< dependent quantization enabled flag bool m_signDataHidingEnabledFlag; //!< sign data hiding enabled flag bool m_deblockingFilterOverridePresentFlag; //!< deblocking filter override controls present in picture header @@ -1989,8 +2027,10 @@ public: unsigned getVirtualBoundariesPosX(unsigned idx) const { CHECK( idx >= 3, "boundary index exceeds valid range" ); return m_virtualBoundariesPosX[idx];} void setVirtualBoundariesPosY(unsigned u, unsigned idx) { CHECK( idx >= 3, "boundary index exceeds valid range" ); m_virtualBoundariesPosY[idx] = u; } unsigned getVirtualBoundariesPosY(unsigned idx) const { CHECK( idx >= 3, "boundary index exceeds valid range" ); return m_virtualBoundariesPosY[idx];} +#if !JVET_Q0155_COLOUR_ID void setColourPlaneId(unsigned u) { m_colourPlaneId = u; } unsigned getColourPlaneId() const { return m_colourPlaneId; } +#endif void setPicOutputFlag( bool b ) { m_picOutputFlag = b; } bool getPicOutputFlag() const { return m_picOutputFlag; } void setPicRplPresentFlag( bool b ) { m_picRplPresentFlag = b; } @@ -2053,7 +2093,16 @@ public: void setNumAlfAps(int i) { m_numAlfAps = i; } int getNumAlfAps() const { return m_numAlfAps; } void setAlfApsIdChroma(int i) { m_alfChromaApsId = i; } - int getAlfApsIdChroma() const { return m_alfChromaApsId; } + int getAlfApsIdChroma() const { return m_alfChromaApsId; } +#if JVET_Q0795_CCALF + void setCcAlfEnabledFlag(ComponentID compId, bool b) { m_ccalfEnabledFlag[compId] = b; } + bool getCcAlfEnabledFlag(ComponentID compId) const { return m_ccalfEnabledFlag[compId]; } + + void setCcAlfCbApsId(int i) { m_ccalfCbApsId = i; } + int getCcAlfCbApsId() const { return m_ccalfCbApsId; } + void setCcAlfCrApsId(int i) { m_ccalfCrApsId = i; } + int getCcAlfCrApsId() const { return m_ccalfCrApsId; } +#endif void setDepQuantEnabledFlag( bool b ) { m_depQuantEnabledFlag = b; } bool getDepQuantEnabledFlag() const { return m_depQuantEnabledFlag; } void setSignDataHidingEnabledFlag( bool b ) { m_signDataHidingEnabledFlag = b; } @@ -2142,7 +2191,13 @@ private: ReferencePictureList m_localRPL1; //< RPL for L1 when present in slice header int m_rpl0Idx; //< index of used RPL in the SPS or -1 for local RPL in the slice header int m_rpl1Idx; //< index of used RPL in the SPS or -1 for local RPL in the slice header +#if JVET_Q0155_COLOUR_ID + int m_colourPlaneId; //!< 4:4:4 colour plane ID +#endif NalUnitType m_eNalUnitType; ///< Nal unit type for the slice +#if JVET_Q0775_PH_IN_SH + bool m_pictureHeaderInSliceHeader; +#endif SliceType m_eSliceType; int m_iSliceQp; int m_iSliceQpBase; @@ -2225,6 +2280,12 @@ private: int m_tileGroupNumAps; std::vector<int> m_tileGroupLumaApsId; int m_tileGroupChromaApsId; +#if JVET_Q0795_CCALF + bool m_tileGroupCcAlfCbEnabledFlag; + bool m_tileGroupCcAlfCrEnabledFlag; + int m_tileGroupCcAlfCbApsId; + int m_tileGroupCcAlfCrApsId; +#endif bool m_disableSATDForRd; public: Slice(); @@ -2286,13 +2347,17 @@ public: int getRefPOC( RefPicList e, int iRefIdx) const { return m_aiRefPOCList[e][iRefIdx]; } int getDepth() const { return m_iDepth; } bool getColFromL0Flag() const { return m_colFromL0Flag; } - uint32_t getColRefIdx() const { return m_colRefIdx; } + uint32_t getColRefIdx() const { return m_colRefIdx; } void checkColRefIdx(uint32_t curSliceSegmentIdx, const Picture* pic); bool getIsUsedAsLongTerm(int i, int j) const { return m_bIsUsedAsLongTerm[i][j]; } void setIsUsedAsLongTerm(int i, int j, bool value) { m_bIsUsedAsLongTerm[i][j] = value; } bool getCheckLDC() const { return m_bCheckLDC; } int getList1IdxToList0Idx( int list1Idx ) const { return m_list1IdxToList0Idx[list1Idx]; } void setPOC( int i ) { m_iPOC = i; } +#if JVET_Q0775_PH_IN_SH + bool getPictureHeaderInSliceHeader() const { return m_pictureHeaderInSliceHeader; } + void setPictureHeaderInSliceHeader( bool e ) { m_pictureHeaderInSliceHeader = e; } +#endif void setNalUnitType( NalUnitType e ) { m_eNalUnitType = e; } NalUnitType getNalUnitType() const { return m_eNalUnitType; } bool getRapPicFlag() const; @@ -2343,6 +2408,10 @@ public: bool isPocRestrictedByDRAP( int poc, bool precedingDRAPinDecodingOrder ); bool isPOCInRefPicList( const ReferencePictureList *rpl, int poc ); void checkConformanceForDRAP( uint32_t temporalId ); +#if JVET_Q0155_COLOUR_ID + void setColourPlaneId( int id ) { m_colourPlaneId = id; } + int getColourPlaneId() const { return m_colourPlaneId; } +#endif void setLambdas( const double lambdas[MAX_NUM_COMPONENT] ) { for (int component = 0; component < MAX_NUM_COMPONENT; component++) m_lambdas[component] = lambdas[component]; } const double* getLambdas() const { return m_lambdas; } @@ -2468,6 +2537,20 @@ public: m_tileGroupLumaApsId[i] = ApsIDs[i]; } } +#if JVET_Q0795_CCALF + void resetTileGroupCcAlCbfEnabledFlag() { m_tileGroupCcAlfCbEnabledFlag = 0; } + void resetTileGroupCcAlCrfEnabledFlag() { m_tileGroupCcAlfCrEnabledFlag = 0; } + + void setTileGroupCcAlfCbEnabledFlag(bool b) { m_tileGroupCcAlfCbEnabledFlag = b; } + void setTileGroupCcAlfCrEnabledFlag(bool b) { m_tileGroupCcAlfCrEnabledFlag = b; } + void setTileGroupCcAlfCbApsId(int i) { m_tileGroupCcAlfCbApsId = i; } + void setTileGroupCcAlfCrApsId(int i) { m_tileGroupCcAlfCrApsId = i; } + + bool getTileGroupCcAlfCbEnabledFlag() { return m_tileGroupCcAlfCbEnabledFlag; } + bool getTileGroupCcAlfCrEnabledFlag() { return m_tileGroupCcAlfCrEnabledFlag; } + int getTileGroupCcAlfCbApsId() { return m_tileGroupCcAlfCbApsId; } + int getTileGroupCcAlfCrApsId() { return m_tileGroupCcAlfCrApsId; } +#endif void setDisableSATDForRD(bool b) { m_disableSATDForRd = b; } bool getDisableSATDForRD() { return m_disableSATDForRd; } void scaleRefPicList( Picture *scaledRefPic[ ], PicHeader *picHeader, APS** apss, APS* lmcsAps, APS* scalingListAps, const bool isDecoder ); @@ -2477,6 +2560,11 @@ public: void setNumEntryPoints( const PPS *pps ); uint32_t getNumEntryPoints( ) const { return m_numEntryPoints; } +#if JVET_Q0795_CCALF + CcAlfFilterParam m_ccAlfFilterParam; + uint8_t* m_ccAlfFilterControl[2]; +#endif + protected: Picture* xGetRefPic( PicList& rcListPic, int poc, const int layerId ); Picture* xGetLongTermRefPic( PicList& rcListPic, int poc, bool pocHasMsb, const int layerId ); diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index 892d1e776441b4bae9309af02d249fa3d85e0d55..e3ed2531e86f3fcd314042a821565d6978c54e63 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -50,12 +50,26 @@ #include <assert.h> #include <cassert> + +#define JVET_Q0820_ACT 1 // JVET-Q0820: ACT bug fixes and reversible ACT transform + +#define JVET_Q0353_ACT_SW_FIX 1 // JVET-Q0353: Bug fix of ACT + +#define JVET_Q0695_CHROMA_TS_JCCR 1 // JVET-Q0695: Enabling the RD checking of chroma transform-skip mode for JCCR at encoder #define JVET_Q0500_CCLM_REF_PADDING 1 // JVET-Q0500: Reference samples padding for CCLM #define JVET_Q0128_DMVR_BDOF_ENABLING_CONDITION 1 // JVET-Q0128: Cleanup of enabling condition for DMVR and BDOF #define JVET_Q0784_LFNST_COMBINATION 1 // lfnst signaling, latency reduction and a bugfix for scaling from Q0106, Q0686, Q0133 +#define JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU 1 // JVET-Q0501: Initialize palette predictor from above CTU row in WPP + +#define JVET_Q0819_PH_CHANGES 1 // JVET-Q0819: Combination of PH related syntax changes + +#define JVET_Q0481_PARTITION_CONSTRAINTS_ORDER 1 // JVET-Q0481: Ordering of partition constraints syntax elements in the SPS + +#define JVET_Q0155_COLOUR_ID 1 // JVET-Q0155: move colour_plane_id from PH to SH + #define JVET_Q0147_JCCR_SIGNALLING 1 // JVET-Q0147: Conditional signaling of sps_joint_cbcr_enabled_flag based on ChromaArrayType #define JVET_Q0267_RESET_CHROMA_QP_OFFSET 1 // JVET-Q0267: Reset chroma QP offsets at the start of each chroma QP offset group @@ -75,6 +89,9 @@ #define JVET_Q0249_ALF_CHROMA_CLIPFLAG 1 // JVET-Q0249: Cleanup of chroma clipping flags for ALF #define JVET_Q0150 1 // fix for ALF virtual horizontal CTU boundary processing #define JVET_Q0054 1 // fix for long luma deblocking decision +#define JVET_Q0795_CCALF 1 // Cross-component ALF + +#define JVET_Q0297_MER 1 // JVET_Q0297: Merge estimation region #define JVET_Q0483_CLIP_TMVP 1 // JVET-Q0483: Clip TMVP when no scaling is applied @@ -82,6 +99,7 @@ #define JVET_Q0055_MTS_SIGNALLING 1 // JVET-Q0055: Check for transform coefficients outside the 16x16 area #define JVET_Q0480_RASTER_RECT_SLICES 1 // JVET-Q0480: Eliminate redundant slice height syntax when in raster rectangular slice mode (tile_idx_delta_present_flag == 0) +#define JVET_Q0775_PH_IN_SH 1 // JVET-Q0755: Allow picture header in slice header #define JVET_Q0433_MODIFIED_CHROMA_DIST_WEIGHT 1 // modification of chroma distortion weight (as agreed during presentation of JVET-Q0433) diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index 95e59ed1e139622e863bbd98a1355c0cc2079fe7..7dae6ae23dc5e80a70fa1075dc85359a119c1ee8 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -250,6 +250,14 @@ void CU::saveMotionInHMVP( const CodingUnit& cu, const bool isToBeDone ) mi.BcwIdx = (mi.interDir == 3) ? cu.BcwIdx : BCW_DEFAULT; +#if JVET_Q0297_MER + const unsigned log2ParallelMergeLevel = (pu.cs->sps->getLog2ParallelMergeLevelMinus2() + 2); + const unsigned xBr = pu.cu->Y().width + pu.cu->Y().x; + const unsigned yBr = pu.cu->Y().height + pu.cu->Y().y; + bool enableHmvp = ((xBr >> log2ParallelMergeLevel) > (pu.cu->Y().x >> log2ParallelMergeLevel)) && ((yBr >> log2ParallelMergeLevel) > (pu.cu->Y().y >> log2ParallelMergeLevel)); + bool enableInsertion = CU::isIBC(cu) || enableHmvp; + if (enableInsertion) +#endif cu.cs->addMiToLut(CU::isIBC(cu) ? cu.cs->motionLut.lutIbc : cu.cs->motionLut.lut, mi); } } @@ -744,7 +752,11 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const //left const PredictionUnit* puLeft = cs.getPURestricted(posLB.offset(-1, 0), pu, pu.chType); bool isGt4x4 = pu.lwidth() * pu.lheight() > 16; +#if JVET_Q0297_MER + const bool isAvailableA1 = puLeft && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu); +#else const bool isAvailableA1 = puLeft && isDiffMER(pu, *puLeft) && pu.cu != puLeft->cu && CU::isIBC(*puLeft->cu); +#endif if (isGt4x4 && isAvailableA1) { miLeft = puLeft->getMotionInfo(posLB.offset(-1, 0)); @@ -768,7 +780,11 @@ void PU::getIBCMergeCandidates(const PredictionUnit &pu, MergeCtx& mrgCtx, const // above const PredictionUnit *puAbove = cs.getPURestricted(posRT.offset(0, -1), pu, pu.chType); +#if JVET_Q0297_MER + bool isAvailableB1 = puAbove && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu); +#else bool isAvailableB1 = puAbove && isDiffMER(pu, *puAbove) && pu.cu != puAbove->cu && CU::isIBC(*puAbove->cu); +#endif if (isGt4x4 && isAvailableB1) { miAbove = puAbove->getMotionInfo(posRT.offset(0, -1)); @@ -1490,6 +1506,19 @@ bool PU::isDiffMER(const PredictionUnit &pu1, const PredictionUnit &pu2) const unsigned xP = pu2.lumaPos().x; const unsigned yP = pu2.lumaPos().y; +#if JVET_Q0297_MER + unsigned plevel = pu1.cs->sps->getLog2ParallelMergeLevelMinus2() + 2; + + if ((xN >> plevel) != (xP >> plevel)) + { + return true; + } + + if ((yN >> plevel) != (yP >> plevel)) + { + return true; +} +#else if ((xN >> 2) != (xP >> 2)) { return true; @@ -1499,6 +1528,7 @@ bool PU::isDiffMER(const PredictionUnit &pu1, const PredictionUnit &pu2) { return true; } +#endif return false; } @@ -2355,6 +2385,9 @@ const int getAvailableAffineNeighboursForLeftPredictor( const PredictionUnit &pu const PredictionUnit *puLeftBottom = pu.cs->getPURestricted( posLB.offset( -1, 1 ), pu, pu.chType ); if ( puLeftBottom && puLeftBottom->cu->affine && puLeftBottom->mergeType == MRG_TYPE_DEFAULT_N +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puLeftBottom) +#endif ) { npu[num++] = puLeftBottom; @@ -2364,6 +2397,9 @@ const int getAvailableAffineNeighboursForLeftPredictor( const PredictionUnit &pu const PredictionUnit* puLeft = pu.cs->getPURestricted( posLB.offset( -1, 0 ), pu, pu.chType ); if ( puLeft && puLeft->cu->affine && puLeft->mergeType == MRG_TYPE_DEFAULT_N +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puLeft) +#endif ) { npu[num++] = puLeft; @@ -2382,6 +2418,9 @@ const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &p const PredictionUnit* puAboveRight = pu.cs->getPURestricted( posRT.offset( 1, -1 ), pu, pu.chType ); if ( puAboveRight && puAboveRight->cu->affine && puAboveRight->mergeType == MRG_TYPE_DEFAULT_N +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puAboveRight) +#endif ) { npu[num++] = puAboveRight; @@ -2391,6 +2430,9 @@ const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &p const PredictionUnit* puAbove = pu.cs->getPURestricted( posRT.offset( 0, -1 ), pu, pu.chType ); if ( puAbove && puAbove->cu->affine && puAbove->mergeType == MRG_TYPE_DEFAULT_N +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puAbove) +#endif ) { npu[num++] = puAbove; @@ -2400,6 +2442,9 @@ const int getAvailableAffineNeighboursForAbovePredictor( const PredictionUnit &p const PredictionUnit *puAboveLeft = pu.cs->getPURestricted( posLT.offset( -1, -1 ), pu, pu.chType ); if ( puAboveLeft && puAboveLeft->cu->affine && puAboveLeft->mergeType == MRG_TYPE_DEFAULT_N +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puAboveLeft) +#endif ) { npu[num++] = puAboveLeft; @@ -2557,6 +2602,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx const PredictionUnit* puNeigh = cs.getPURestricted( pos, pu, pu.chType ); if ( puNeigh && CU::isInter( *puNeigh->cu ) +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puNeigh) +#endif ) { isAvailable[0] = true; @@ -2575,6 +2623,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx if ( puNeigh && CU::isInter( *puNeigh->cu ) +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puNeigh) +#endif ) { isAvailable[1] = true; @@ -2593,6 +2644,9 @@ void PU::getAffineMergeCand( const PredictionUnit &pu, AffineMergeCtx& affMrgCtx if ( puNeigh && CU::isInter( *puNeigh->cu ) +#if JVET_Q0297_MER + && PU::isDiffMER(pu, *puNeigh) +#endif ) { isAvailable[2] = true; @@ -3623,7 +3677,11 @@ bool CU::bdpcmAllowed( const CodingUnit& cu, const ComponentID compID ) if (isLuma(compID)) bdpcmAllowed &= (cu.lwidth() <= transformSkipMaxSize && cu.lheight() <= transformSkipMaxSize); else +#if JVET_Q0353_ACT_SW_FIX + bdpcmAllowed &= (cu.chromaSize().width <= transformSkipMaxSize && cu.chromaSize().height <= transformSkipMaxSize) && !cu.colorTransform; +#else bdpcmAllowed &= (cu.chromaSize().width <= transformSkipMaxSize && cu.chromaSize().height <= transformSkipMaxSize); +#endif return bdpcmAllowed; } diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 2b6e0688128e89e513a2b6886e71e9ec9375ee92..b8f20a7dee8845906193124edffe83d6e396f1a1 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -194,6 +194,25 @@ void CABACReader::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i } } } +#if JVET_Q0795_CCALF + if (cs.sps->getCCALFEnabledFlag()) + { + for ( int compIdx = 1; compIdx < getNumberValidComponents( cs.pcv->chrFormat ); compIdx++ ) + { + if (cs.slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1]) + { + const int filterCount = cs.slice->m_ccAlfFilterParam.ccAlfFilterCount[compIdx - 1]; + + const int ry = ctuRsAddr / cs.pcv->widthInCtus; + const int rx = ctuRsAddr % cs.pcv->widthInCtus; + const Position lumaPos(rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight); + + ccAlfFilterControlIdc(cs, ComponentID(compIdx), ctuRsAddr, cs.slice->m_ccAlfFilterControl[compIdx - 1], lumaPos, + filterCount); + } + } + } +#endif if ( CS::isDualITree(cs) && cs.pcv->chrFormat != CHROMA_400 && cs.pcv->maxCUWidth > 64 ) @@ -251,6 +270,45 @@ void CABACReader::readAlfCtuFilterIndex(CodingStructure& cs, unsigned ctuRsAddr) } alfCtbFilterSetIndex[ctuRsAddr] = filtIndex; } +#if JVET_Q0795_CCALF +void CABACReader::ccAlfFilterControlIdc(CodingStructure &cs, const ComponentID compID, const int curIdx, + uint8_t *filterControlIdc, Position lumaPos, int filterCount) +{ + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET( STATS__CABAC_BITS__CROSS_COMPONENT_ALF_BLOCK_LEVEL_IDC ); + + Position leftLumaPos = lumaPos.offset(-(int)cs.pcv->maxCUWidth, 0); + Position aboveLumaPos = lumaPos.offset(0, -(int)cs.pcv->maxCUWidth); + const uint32_t curSliceIdx = cs.slice->getIndependentSliceIdx(); + const uint32_t curTileIdx = cs.pps->getTileIdx( lumaPos ); + 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 : 0; + } + if (aboveAvail) + { + ctxt += ( filterControlIdc[curIdx - cs.pcv->widthInCtus] ) ? 1 : 0; + } + ctxt += ( compID == COMPONENT_Cr ) ? 3 : 0; + + int idcVal = m_BinDecoder.decodeBin( Ctx::CcAlfFilterControlFlag( ctxt ) ); + if ( idcVal ) + { + while ( ( idcVal != filterCount ) && m_BinDecoder.decodeBinEP() ) + { + idcVal++; + } + } + filterControlIdc[curIdx] = idcVal; + + 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 + //================================================================================ // clause 7.3.8.3 //-------------------------------------------------------------------------------- diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 132c50232a229395cbcde5d257acb71b7f99eec0..e1b33238b52ff4a9db971d2a50615dc0cb8be9f2 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -70,6 +70,11 @@ public: void readAlfCtuFilterIndex(CodingStructure& cs, unsigned ctuRsAddr); +#if JVET_Q0795_CCALF + void ccAlfFilterControlIdc(CodingStructure &cs, const ComponentID compID, const int curIdx, uint8_t *filterControlIdc, + Position lumaPos, int filterCount); +#endif + // coding (quad)tree (clause 7.3.8.4) void coding_tree ( CodingStructure& cs, Partitioner& pm, CUCtx& cuCtx, Partitioner* pPartitionerChroma = nullptr, CUCtx* pCuCtxChroma = nullptr); PartSplit split_cu_mode ( CodingStructure& cs, Partitioner& pm ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index 3b96128195c8623b5fff067cdcecb0486b61cb18..88b6a9cd3d8bbfdba72c701d9968aa716927c4d7 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -369,12 +369,14 @@ void DecCu::xIntraRecACTBlk(TransformUnit& tu) PelBuf piResi = cs.getResiBuf(area); QpParam cQP(tu, compID); +#if !JVET_Q0820_ACT for (int qpIdx = 0; qpIdx < 2; qpIdx++) { cQP.Qps[qpIdx] = cQP.Qps[qpIdx] + (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg); cQP.pers[qpIdx] = cQP.Qps[qpIdx] / 6; cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6; } +#endif if (tu.jointCbCr && isChroma(compID)) { @@ -388,12 +390,14 @@ void DecCu::xIntraRecACTBlk(TransformUnit& tu) else { QpParam qpCr(tu, COMPONENT_Cr); +#if !JVET_Q0820_ACT for (int qpIdx = 0; qpIdx < 2; qpIdx++) { qpCr.Qps[qpIdx] = qpCr.Qps[qpIdx] + DELTA_QP_FOR_Co; qpCr.pers[qpIdx] = qpCr.Qps[qpIdx] / 6; qpCr.rems[qpIdx] = qpCr.Qps[qpIdx] % 6; } +#endif m_pcTrQuant->invTransformNxN(tu, COMPONENT_Cr, resiCr, qpCr); } @@ -421,7 +425,11 @@ void DecCu::xIntraRecACTBlk(TransformUnit& tu) cs.setDecomp(area); } +#if JVET_Q0820_ACT + cs.getResiBuf(tu).colorSpaceConvert(cs.getResiBuf(tu), false, tu.cu->cs->slice->clpRng(COMPONENT_Y)); +#else cs.getResiBuf(tu).colorSpaceConvert(cs.getResiBuf(tu), false); +#endif for (int i = 0; i < getNumberValidComponents(tu.chromaFormat); i++) { @@ -697,7 +705,11 @@ void DecCu::xReconInter(CodingUnit &cu) { if (cu.colorTransform) { +#if JVET_Q0820_ACT + cs.getResiBuf(cu).colorSpaceConvert(cs.getResiBuf(cu), false, cu.cs->slice->clpRng(COMPONENT_Y)); +#else cs.getResiBuf(cu).colorSpaceConvert(cs.getResiBuf(cu), false); +#endif } #if REUSE_CU_RESULTS const CompArea &area = cu.blocks[COMPONENT_Y]; @@ -759,6 +771,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) PelBuf resiBuf = cs.getResiBuf(area); QpParam cQP(currTU, compID); +#if !JVET_Q0820_ACT if (currTU.cu->colorTransform) { for (int qpIdx = 0; qpIdx < 2; qpIdx++) @@ -768,6 +781,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6; } } +#endif if( currTU.jointCbCr && isChroma(compID) ) { @@ -781,6 +795,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) else { QpParam qpCr(currTU, COMPONENT_Cr); +#if !JVET_Q0820_ACT if (currTU.cu->colorTransform) { for (int qpIdx = 0; qpIdx < 2; qpIdx++) @@ -790,6 +805,7 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) qpCr.rems[qpIdx] = qpCr.Qps[qpIdx] % 6; } } +#endif m_pcTrQuant->invTransformNxN( currTU, COMPONENT_Cr, resiCr, qpCr ); } m_pcTrQuant->invTransformICT( currTU, resiBuf, resiCr ); diff --git a/source/Lib/DecoderLib/DecLib.cpp b/source/Lib/DecoderLib/DecLib.cpp index 3d87a2be860352a36a51de8389008bf5a03f91a9..253f8dda0fe8f61ccb9047c3aa08fc5663c731fd 100644 --- a/source/Lib/DecoderLib/DecLib.cpp +++ b/source/Lib/DecoderLib/DecLib.cpp @@ -222,6 +222,12 @@ bool tryDecodePicture( Picture* pcEncPic, const int expectedPoc, const std::stri pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Y, pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Y)); pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Cb, pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Cb)); pcEncPic->slices[i]->setTileGroupAlfEnabledFlag(COMPONENT_Cr, pic->slices[i]->getTileGroupAlfEnabledFlag(COMPONENT_Cr)); +#if JVET_Q0795_CCALF + pcEncPic->slices[i]->setTileGroupCcAlfCbApsId(pic->slices[i]->getTileGroupCcAlfCbApsId()); + pcEncPic->slices[i]->setTileGroupCcAlfCbEnabledFlag(pic->slices[i]->getTileGroupCcAlfCbEnabledFlag()); + pcEncPic->slices[i]->setTileGroupCcAlfCrApsId(pic->slices[i]->getTileGroupCcAlfCrApsId()); + pcEncPic->slices[i]->setTileGroupCcAlfCrEnabledFlag(pic->slices[i]->getTileGroupCcAlfCrEnabledFlag()); +#endif } } @@ -579,11 +585,13 @@ void DecLib::executeLoopFilters() if( cs.sps->getALFEnabledFlag() ) { - // ALF decodes the differentially coded coefficients and stores them in the parameters structure. - // Code could be restructured to do directly after parsing. So far we just pass a fresh non-const - // copy in case the APS gets used more than once. - m_cALF.ALFProcess(cs); - +#if JVET_Q0795_CCALF + m_cALF.getCcAlfFilterParam() = cs.slice->m_ccAlfFilterParam; +#endif + // ALF decodes the differentially coded coefficients and stores them in the parameters structure. + // Code could be restructured to do directly after parsing. So far we just pass a fresh non-const + // copy in case the APS gets used more than once. + m_cALF.ALFProcess(cs); } #if SUBPIC_DECCHECK @@ -916,6 +924,66 @@ void activateAPS(PicHeader* picHeader, Slice* pSlice, ParameterSetManager& param } } +#if JVET_Q0795_CCALF + CcAlfFilterParam &filterParam = pSlice->m_ccAlfFilterParam; + // cleanup before copying + for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + memset( filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], 0, sizeof(filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx]) ); + memset( filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], 0, sizeof(filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx]) ); + } + memset( filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1], false, sizeof(filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1]) ); + memset( filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1], false, sizeof(filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1]) ); + + if(pSlice->getTileGroupCcAlfCbEnabledFlag()) + { + int apsId = pSlice->getTileGroupCcAlfCbApsId(); + APS *aps = parameterSetManager.getAPS(apsId, ALF_APS); + if(aps) + { + apss[apsId] = aps; + if (false == parameterSetManager.activateAPS(apsId, ALF_APS)) + { + THROW("APS activation failed!"); + } + + CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" ); + //ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it. + + filterParam.ccAlfFilterCount[COMPONENT_Cb - 1] = aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cb - 1]; + for (int filterIdx=0; filterIdx < filterParam.ccAlfFilterCount[COMPONENT_Cb - 1]; filterIdx++ ) + { + filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx] = aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx]; + memcpy(filterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], sizeof(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx])); + } + } + } + + if(pSlice->getTileGroupCcAlfCrEnabledFlag()) + { + int apsId = pSlice->getTileGroupCcAlfCrApsId(); + APS *aps = parameterSetManager.getAPS(apsId, ALF_APS); + if(aps) + { + apss[apsId] = aps; + if (false == parameterSetManager.activateAPS(apsId, ALF_APS)) + { + THROW("APS activation failed!"); + } + + CHECK( aps->getTemporalId() > pSlice->getTLayer(), "TemporalId shall be less than or equal to the TemporalId of the coded slice NAL unit" ); + //ToDO: APS NAL unit containing the APS RBSP shall have nuh_layer_id either equal to the nuh_layer_id of a coded slice NAL unit that referrs it, or equal to the nuh_layer_id of a direct dependent layer of the layer containing a coded slice NAL unit that referrs it. + + filterParam.ccAlfFilterCount[COMPONENT_Cr - 1] = aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cr - 1]; + for (int filterIdx=0; filterIdx < filterParam.ccAlfFilterCount[COMPONENT_Cr - 1]; filterIdx++ ) + { + filterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx] = aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx]; + memcpy(filterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], sizeof(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx])); + } + } + } +#endif + if (picHeader->getLmcsEnabledFlag() && lmcsAPS == nullptr) { lmcsAPS = parameterSetManager.getAPS(picHeader->getLmcsAPSId(), LMCS_APS); @@ -1082,6 +1150,10 @@ void DecLib::xActivateParameterSets( const int layerId ) { m_cALF.create( pps->getPicWidthInLumaSamples(), pps->getPicHeightInLumaSamples(), sps->getChromaFormatIdc(), sps->getMaxCUWidth(), sps->getMaxCUHeight(), sps->getMaxCodingDepth(), sps->getBitDepths().recon ); } +#if JVET_Q0795_CCALF + pSlice->m_ccAlfFilterControl[0] = m_cALF.getCcAlfControlIdc(COMPONENT_Cb); + pSlice->m_ccAlfFilterControl[1] = m_cALF.getCcAlfControlIdc(COMPONENT_Cr); +#endif } else { @@ -1211,15 +1283,21 @@ void DecLib::xParsePrefixSEImessages() void DecLib::xDecodePicHeader( InputNALUnit& nalu ) { m_HLSReader.setBitstream( &nalu.getBitstream() ); +#if JVET_Q0775_PH_IN_SH + m_HLSReader.parsePictureHeader( &m_picHeader, &m_parameterSetManager, true ); +#else m_HLSReader.parsePictureHeader( &m_picHeader, &m_parameterSetManager); +#endif m_picHeader.setValid(); } bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDisplay ) { +#if !JVET_Q0775_PH_IN_SH if(m_picHeader.isValid() == false) { return false; } +#endif m_apcSlicePilot->setPicHeader( &m_picHeader ); m_apcSlicePilot->initSlice(); // the slice pilot is an object to prepare for a new slice // it is not associated with picture, sps or pps structures. @@ -1255,6 +1333,9 @@ bool DecLib::xDecodeSlice(InputNALUnit &nalu, int &iSkipFrame, int iPOCLastDispl CHECK(nalu.m_temporalId != 0, "Current GDR picture has TemporalId not equal to 0"); m_HLSReader.setBitstream( &nalu.getBitstream() ); +#if JVET_Q0795_CCALF + m_apcSlicePilot->m_ccAlfFilterParam = m_cALF.getCcAlfFilterParam(); +#endif m_HLSReader.parseSliceHeader( m_apcSlicePilot, &m_picHeader, &m_parameterSetManager, m_prevTid0POC ); // update independent slice index diff --git a/source/Lib/DecoderLib/DecSlice.cpp b/source/Lib/DecoderLib/DecSlice.cpp index 8adadb3a22e641dc8db273f76428105e7b0f7380..9e4d1360f7ecba1201d193cf282e85e70cf90cac 100644 --- a/source/Lib/DecoderLib/DecSlice.cpp +++ b/source/Lib/DecoderLib/DecSlice.cpp @@ -170,6 +170,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb { // Top is available, so use it. cabacReader.getCtx() = m_entropyCodingSyncContextState; +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + cs.setPrevPLT(m_palettePredictorSyncState); +#endif } pic->m_prevQP[0] = pic->m_prevQP[1] = slice->getSliceQp(); } @@ -203,6 +206,9 @@ void DecSlice::decompressSlice( Slice* slice, InputBitstream* bitstream, int deb if( ctuXPosInCtus == tileXPosInCtus && wavefrontsEnabled ) { m_entropyCodingSyncContextState = cabacReader.getCtx(); +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + cs.storePrevPLT(m_palettePredictorSyncState); +#endif } diff --git a/source/Lib/DecoderLib/DecSlice.h b/source/Lib/DecoderLib/DecSlice.h index 1ff2a2282be31abb227e326a9167d515ffffe64d..cd918ed76d3fe28fab725c5efd40965359a4af74 100644 --- a/source/Lib/DecoderLib/DecSlice.h +++ b/source/Lib/DecoderLib/DecSlice.h @@ -63,6 +63,9 @@ private: DecCu* m_pcCuDecoder; Ctx m_entropyCodingSyncContextState; ///< context storage for state of contexts at the wavefront/WPP/entropy-coding-sync second CTU of tile-row +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + PLTBuf m_palettePredictorSyncState; /// palette predictor storage at wavefront/WPP +#endif public: DecSlice(); diff --git a/source/Lib/DecoderLib/NALread.cpp b/source/Lib/DecoderLib/NALread.cpp index 07dddd03f67e8834f26b88a790f14d2d247b4b5b..819bcc25180de163afd088f8e2ff0f93e26f2484 100644 --- a/source/Lib/DecoderLib/NALread.cpp +++ b/source/Lib/DecoderLib/NALread.cpp @@ -167,4 +167,12 @@ void read(InputNALUnit& nalu) bitstream.resetToStart(); readNalUnitHeader(nalu); } +#if JVET_Q0775_PH_IN_SH +bool checkPictureHeaderInSliceHeaderFlag(InputNALUnit& nalu) +{ + InputBitstream& bitstream = nalu.getBitstream(); + CHECK(bitstream.getByteLocation() != 2, "The picture_header_in_slice_header_flag is the first bit after the NAL unit header"); + return (bool)bitstream.read(1); +} +#endif //! \} diff --git a/source/Lib/DecoderLib/NALread.h b/source/Lib/DecoderLib/NALread.h index 1778dc5055e3013313ed48bd88c6cc9bacad224f..f807fbed75608d03e84197ae2f75534585c8d47b 100644 --- a/source/Lib/DecoderLib/NALread.h +++ b/source/Lib/DecoderLib/NALread.h @@ -67,7 +67,9 @@ class InputNALUnit : public NALUnit void read(InputNALUnit& nalu); void readNalUnitHeader(InputNALUnit& nalu); - +#if JVET_Q0775_PH_IN_SH +bool checkPictureHeaderInSliceHeaderFlag(InputNALUnit & nalu); +#endif //! \} #endif diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index fd516bb03df6123e3e66fb94fbef8c56de7d964e..68d4bdba0d209c2cc817d7c8d129be65ee6c6015 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -825,8 +825,17 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) READ_FLAG(code, "alf_chroma_new_filter"); param.newFilterFlag[CHANNEL_TYPE_CHROMA] = code; - CHECK(param.newFilterFlag[CHANNEL_TYPE_LUMA] == 0 && param.newFilterFlag[CHANNEL_TYPE_CHROMA] == 0, - "bitstream conformance error, alf_luma_filter_signal_flag and alf_chroma_filter_signal_flag shall not equal to zero at the same time"); +#if JVET_Q0795_CCALF + CcAlfFilterParam ccAlfParam = aps->getCcAlfAPSParam(); + READ_FLAG(code, "alf_cc_cb_filter_signal_flag"); + ccAlfParam.newCcAlfFilter[COMPONENT_Cb - 1] = code; + READ_FLAG(code, "alf_cc_cr_filter_signal_flag"); + ccAlfParam.newCcAlfFilter[COMPONENT_Cr - 1] = code; + CHECK(param.newFilterFlag[CHANNEL_TYPE_LUMA] == 0 && param.newFilterFlag[CHANNEL_TYPE_CHROMA] == 0 + && ccAlfParam.newCcAlfFilter[COMPONENT_Cb - 1] == 0 && ccAlfParam.newCcAlfFilter[COMPONENT_Cr - 1] == 0, + "bitstream conformance error: one of alf_luma_filter_signal_flag, alf_chroma_filter_signal_flag, " + "alf_cross_component_cb_filter_signal_flag, and alf_cross_component_cr_filter_signal_flag shall be nonzero"); +#endif if (param.newFilterFlag[CHANNEL_TYPE_LUMA]) { @@ -876,6 +885,62 @@ void HLSyntaxReader::parseAlfAps( APS* aps ) alfFilter( param, true, altIdx ); } } + +#if JVET_Q0795_CCALF + for (int ccIdx = 0; ccIdx < 2; ccIdx++) + { + if (ccAlfParam.newCcAlfFilter[ccIdx]) + { + if (MAX_NUM_CC_ALF_FILTERS > 1) + { + READ_UVLC(code, ccIdx == 0 ? "alf_cc_cb_filters_signalled_minus1" : "alf_cc_cr_filters_signalled_minus1"); + } + else + { + code = 0; + } + ccAlfParam.ccAlfFilterCount[ccIdx] = code + 1; + + for (int filterIdx = 0; filterIdx < ccAlfParam.ccAlfFilterCount[ccIdx]; filterIdx++) + { + ccAlfParam.ccAlfFilterIdxEnabled[ccIdx][filterIdx] = true; + AlfFilterShape alfShape(size_CC_ALF); + + 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) + { + coeff[i] = 0; + } + else + { + coeff[i] = 1 << (code - 1); + READ_FLAG(code, ccIdx == 0 ? "alf_cc_cb_coeff_sign" : "alf_cc_cr_coeff_sign"); + coeff[i] *= 1 - 2 * code; + } + } + + DTRACE(g_trace_ctx, D_SYNTAX, "%s coeff filterIdx %d: ", ccIdx == 0 ? "Cb" : "Cr", filterIdx); + for (int i = 0; i < alfShape.numCoeff; i++) + { + DTRACE(g_trace_ctx, D_SYNTAX, "%d ", coeff[i]); + } + DTRACE(g_trace_ctx, D_SYNTAX, "\n"); + } + + for (int filterIdx = ccAlfParam.ccAlfFilterCount[ccIdx]; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++) + { + ccAlfParam.ccAlfFilterIdxEnabled[ccIdx][filterIdx] = false; + } + } + } + aps->setCcAlfAPSParam(ccAlfParam); +#endif + aps->setAlfAPSParam(param); } @@ -1115,6 +1180,15 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) pcSPS->setLoopFilterAcrossSubpicEnabledFlag(picIdx, uiCode); } } + else + { + pcSPS->setNumSubPics(1); + pcSPS->setSubPicCtuTopLeftX(0, 0); + pcSPS->setSubPicCtuTopLeftY(0, 0); + pcSPS->setSubPicWidth(0, (pcSPS->getMaxPicWidthInLumaSamples() + pcSPS->getCTUSize() - 1) >> floorLog2(pcSPS->getCTUSize())); + pcSPS->setSubPicHeight(0, (pcSPS->getMaxPicHeightInLumaSamples() + pcSPS->getCTUSize() - 1) >> floorLog2(pcSPS->getCTUSize())); + } + READ_FLAG(uiCode, "sps_subpic_id_present_flag"); pcSPS->setSubPicIdPresentFlag( uiCode != 0 ); if( pcSPS->getSubPicIdPresentFlag() ) { @@ -1253,11 +1327,13 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_intra_slice_luma"); unsigned minQtLog2SizeIntraY = uiCode + pcSPS->getLog2MinCodingBlockSize(); minQT[0] = 1 << minQtLog2SizeIntraY; +#if !JVET_Q0481_PARTITION_CONSTRAINTS_ORDER READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_slice"); unsigned minQtLog2SizeInterY = uiCode + pcSPS->getLog2MinCodingBlockSize(); minQT[1] = 1 << minQtLog2SizeInterY; READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_slice"); maxBTD[1] = uiCode; CHECK(uiCode > 2*(ctbLog2SizeY - log2MinCUSize), "sps_max_mtt_hierarchy_depth_inter_slice shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)"); +#endif READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_intra_slice_luma"); maxBTD[0] = uiCode; CHECK(uiCode > 2 * (ctbLog2SizeY - log2MinCUSize), "sps_max_mtt_hierarchy_depth_intra_slice_luma shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)"); @@ -1269,6 +1345,13 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_UVLC(uiCode, "sps_log2_diff_max_tt_min_qt_intra_slice_luma"); maxTTSize[0] <<= uiCode; CHECK(uiCode > ctbLog2SizeY - minQtLog2SizeIntraY, "Invalid code"); } +#if JVET_Q0481_PARTITION_CONSTRAINTS_ORDER + READ_UVLC(uiCode, "sps_log2_diff_min_qt_min_cb_inter_slice"); + unsigned minQtLog2SizeInterY = uiCode + pcSPS->getLog2MinCodingBlockSize(); + minQT[1] = 1 << minQtLog2SizeInterY; + READ_UVLC(uiCode, "sps_max_mtt_hierarchy_depth_inter_slice"); maxBTD[1] = uiCode; + CHECK(uiCode > 2*(ctbLog2SizeY - log2MinCUSize), "sps_max_mtt_hierarchy_depth_inter_slice shall be in the range 0 to 2*(ctbLog2SizeY - log2MinCUSize)"); +#endif maxTTSize[1] = maxBTSize[1] = minQT[1]; if (maxBTD[1] != 0) { @@ -1334,6 +1417,16 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) READ_FLAG( uiCode, "sps_sao_enabled_flag" ); pcSPS->setSAOEnabledFlag ( uiCode ? true : false ); READ_FLAG( uiCode, "sps_alf_enabled_flag" ); pcSPS->setALFEnabledFlag ( uiCode ? true : false ); +#if JVET_Q0795_CCALF + if (pcSPS->getALFEnabledFlag() && pcSPS->getChromaFormatIdc() != CHROMA_400) + { + READ_FLAG( uiCode, "sps_ccalf_enabled_flag" ); pcSPS->setCCALFEnabledFlag ( uiCode ? true : false ); + } + else + { + pcSPS->setCCALFEnabledFlag(false); + } +#endif READ_FLAG(uiCode, "sps_transform_skip_enabled_flag"); pcSPS->setTransformSkipEnabledFlag(uiCode ? true : false); if (pcSPS->getTransformSkipEnabledFlag()) @@ -1425,7 +1518,14 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) } if (pcSPS->getChromaFormatIdc() == CHROMA_444) { +#if JVET_Q0820_ACT + if (pcSPS->getLog2MaxTbSize() != 6) + { + READ_FLAG(uiCode, "sps_act_enabled_flag"); pcSPS->setUseColorTrans(uiCode != 0); + } +#else READ_FLAG(uiCode, "sps_act_enabled_flag"); pcSPS->setUseColorTrans(uiCode != 0); +#endif } else { @@ -1470,6 +1570,11 @@ void HLSyntaxReader::parseSPS(SPS* pcSPS) } #endif +#if JVET_Q0297_MER + READ_UVLC(uiCode, "log2_parallel_merge_level_minus2"); + pcSPS->setLog2ParallelMergeLevelMinus2(uiCode); +#endif + // KJS: reference picture sets to be replaced // KJS: not found in draft -> does not exist @@ -1721,7 +1826,11 @@ void HLSyntaxReader::parseVPS(VPS* pcVPS) xReadRbspTrailingBits(); } +#if JVET_Q0775_PH_IN_SH +void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManager *parameterSetManager, bool readRbspTrailingBits ) +#else void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManager *parameterSetManager ) +#endif { uint32_t uiCode; int iCode; @@ -1853,6 +1962,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag } } +#if !JVET_Q0155_COLOUR_ID // 4:4:4 colour plane ID if( sps->getSeparateColourPlaneFlag() ) { @@ -1863,6 +1973,7 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag { picHeader->setColourPlaneId( 0 ); } +#endif // picture output flag if( pps->getOutputFlagPresentFlag() ) @@ -1976,10 +2087,12 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag READ_UVLC(uiCode, "pic_log2_diff_min_qt_min_cb_intra_slice_luma"); unsigned minQtLog2SizeIntraY = uiCode + sps->getLog2MinCodingBlockSize(); minQT[0] = 1 << minQtLog2SizeIntraY; +#if !JVET_Q0819_PH_CHANGES READ_UVLC(uiCode, "pic_log2_diff_min_qt_min_cb_inter_slice"); unsigned minQtLog2SizeInterY = uiCode + sps->getLog2MinCodingBlockSize(); minQT[1] = 1 << minQtLog2SizeInterY; READ_UVLC(uiCode, "pic_max_mtt_hierarchy_depth_inter_slice"); maxBTD[1] = uiCode; +#endif READ_UVLC(uiCode, "pic_max_mtt_hierarchy_depth_intra_slice_luma"); maxBTD[0] = uiCode; maxTTSize[0] = maxBTSize[0] = minQT[0]; @@ -1990,6 +2103,12 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag READ_UVLC(uiCode, "pic_log2_diff_max_tt_min_qt_intra_slice_luma"); maxTTSize[0] <<= uiCode; CHECK(uiCode > ctbLog2SizeY - minQtLog2SizeIntraY, "Invalid code"); } +#if JVET_Q0819_PH_CHANGES + READ_UVLC(uiCode, "pic_log2_diff_min_qt_min_cb_inter_slice"); + unsigned minQtLog2SizeInterY = uiCode + sps->getLog2MinCodingBlockSize(); + minQT[1] = 1 << minQtLog2SizeInterY; + READ_UVLC(uiCode, "pic_max_mtt_hierarchy_depth_inter_slice"); maxBTD[1] = uiCode; +#endif maxTTSize[1] = maxBTSize[1] = minQT[1]; if (maxBTD[1] != 0) { @@ -2211,6 +2330,10 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag } // alf enable flags and aps IDs +#if JVET_Q0795_CCALF + picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, false); + picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, false); +#endif if( sps->getALFEnabledFlag() ) { READ_FLAG(uiCode, "pic_alf_enabled_present_flag"); @@ -2250,6 +2373,30 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag READ_CODE(3, uiCode, "pic_alf_aps_id_chroma"); picHeader->setAlfApsIdChroma(uiCode); } +#if JVET_Q0795_CCALF + if (sps->getCCALFEnabledFlag()) + { + READ_FLAG(uiCode, "ph_cc_alf_cb_enabled_flag"); + picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, uiCode != 0); + picHeader->setCcAlfCbApsId(-1); + if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cb)) + { + // parse APS ID + READ_CODE(3, uiCode, "ph_cc_alf_cb_aps_id"); + picHeader->setCcAlfCbApsId(uiCode); + } + // Cr + READ_FLAG(uiCode, "ph_cc_alf_cr_enabled_flag"); + picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, uiCode != 0); + picHeader->setCcAlfCrApsId(-1); + if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cr)) + { + // parse APS ID + READ_CODE(3, uiCode, "ph_cc_alf_cr_aps_id"); + picHeader->setCcAlfCrApsId(uiCode); + } + } +#endif } else { @@ -2404,7 +2551,14 @@ void HLSyntaxReader::parsePictureHeader( PicHeader* picHeader, ParameterSetManag } } +#if JVET_Q0775_PH_IN_SH + if( readRbspTrailingBits ) + { + xReadRbspTrailingBits(); + } +#else xReadRbspTrailingBits(); +#endif } void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC) @@ -2417,7 +2571,15 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par #endif PPS* pps = NULL; SPS* sps = NULL; - +#if JVET_Q0775_PH_IN_SH + READ_FLAG(uiCode, "picture_header_in_slice_header_flag"); + if (uiCode) + { + pcSlice->setPictureHeaderInSliceHeader(true); + parsePictureHeader(picHeader, parameterSetManager, false); + picHeader->setValid(); + } +#endif CHECK(picHeader==0, "Invalid Picture Header"); CHECK(picHeader->isValid()==false, "Invalid Picture Header"); pps = parameterSetManager->getPPS( picHeader->getPPSId() ); @@ -2534,11 +2696,23 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par READ_UVLC ( uiCode, "slice_type" ); pcSlice->setSliceType((SliceType)uiCode); +#if JVET_Q0155_COLOUR_ID + // 4:4:4 colour plane ID + if( sps->getSeparateColourPlaneFlag() ) + { + READ_CODE( 2, uiCode, "colour_plane_id" ); pcSlice->setColourPlaneId( uiCode ); + CHECK( uiCode > 2, "colour_plane_id exceeds valid range" ); + } + else + { + pcSlice->setColourPlaneId( 0 ); + } +#endif + // inherit values from picture header // set default values in case slice overrides are disabled pcSlice->inheritFromPicHeader( picHeader, pps, sps ); - if( picHeader->getPicRplPresentFlag() ) { pcSlice->setRPL0(picHeader->getRPL0()); @@ -2951,6 +3125,41 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, PicHeader* picHeader, Par } pcSlice->setTileGroupAlfEnabledFlag(COMPONENT_Cb, alfChromaIdc & 1); pcSlice->setTileGroupAlfEnabledFlag(COMPONENT_Cr, alfChromaIdc >> 1); + +#if JVET_Q0795_CCALF + CcAlfFilterParam &filterParam = pcSlice->m_ccAlfFilterParam; + if (sps->getCCALFEnabledFlag() && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y)) + { + 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]) + { + // parse APS ID + READ_CODE(3, uiCode, "slice_cc_alf_cb_aps_id"); + pcSlice->setTileGroupCcAlfCbApsId(uiCode); + } + // Cr + READ_FLAG(uiCode, "slice_cc_alf_cr_enabled_flag"); + pcSlice->setTileGroupCcAlfCrEnabledFlag(uiCode); + filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] = (uiCode == 1) ? true : false; + pcSlice->setTileGroupCcAlfCrApsId(-1); + if (filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1]) + { + // parse APS ID + READ_CODE(3, uiCode, "slice_cc_alf_cr_aps_id"); + pcSlice->setTileGroupCcAlfCrApsId(uiCode); + } + } + else + { + filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] = false; + filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] = false; + pcSlice->setTileGroupCcAlfCbApsId(-1); + pcSlice->setTileGroupCcAlfCrApsId(-1); + } +#endif } @@ -3130,6 +3339,9 @@ void HLSyntaxReader::parseConstraintInfo(ConstraintInfo *cinfo) READ_FLAG(symbol, "no_partition_constraints_override_constraint_flag"); cinfo->setNoPartitionConstraintsOverrideConstraintFlag(symbol > 0 ? true : false); READ_FLAG(symbol, "no_sao_constraint_flag"); cinfo->setNoSaoConstraintFlag(symbol > 0 ? true : false); READ_FLAG(symbol, "no_alf_constraint_flag"); cinfo->setNoAlfConstraintFlag(symbol > 0 ? true : false); +#if JVET_Q0795_CCALF + READ_FLAG(symbol, "no_ccalf_constraint_flag"); cinfo->setNoCCAlfConstraintFlag(symbol > 0 ? true : false); +#endif READ_FLAG(symbol, "no_joint_cbcr_constraint_flag"); cinfo->setNoJointCbCrConstraintFlag(symbol > 0 ? true : false); READ_FLAG(symbol, "no_ref_wraparound_constraint_flag"); cinfo->setNoRefWraparoundConstraintFlag(symbol > 0 ? true : false); diff --git a/source/Lib/DecoderLib/VLCReader.h b/source/Lib/DecoderLib/VLCReader.h index 69e3f479ca770b34ac1efdb3ebb54d0bb22d7ad3..01cad942a0c463a1e98052e0bfffb28dda663a25 100644 --- a/source/Lib/DecoderLib/VLCReader.h +++ b/source/Lib/DecoderLib/VLCReader.h @@ -167,7 +167,11 @@ public: void parseConstraintInfo (ConstraintInfo *cinfo); void parseProfileTierLevel ( ProfileTierLevel *ptl, int maxNumSubLayersMinus1); void parseHrdParameters ( HRDParameters *hrd, uint32_t firstSubLayer, uint32_t tempLevelHigh ); +#if JVET_Q0775_PH_IN_SH + void parsePictureHeader ( PicHeader* picHeader, ParameterSetManager *parameterSetManager, bool readRbspTrailingBits ); +#else void parsePictureHeader ( PicHeader* picHeader, ParameterSetManager *parameterSetManager ); +#endif void parseSliceHeader ( Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC ); void parseSliceHeaderToPoc ( Slice* pcSlice, PicHeader* picHeader, ParameterSetManager *parameterSetManager, const int prevTid0POC ); void parseTerminatingBit ( uint32_t& ruiBit ); @@ -178,6 +182,9 @@ public: void decodeScalingList ( ScalingList *scalingList, uint32_t scalingListId, bool isPredictor); void parseReshaper ( SliceReshapeInfo& sliceReshaperInfo, const SPS* pcSPS, const bool isIntra ); void alfFilter( AlfParam& alfParam, const bool isChroma, const int altIdx ); +#if JVET_Q0795_CCALF + void ccAlfFilter( Slice *pcSlice ); +#endif private: int alfGolombDecode( const int k, const bool signed_val=true ); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index c814c521abbd7ecf4bbcf7ab531873b0b10a268f..4044ba80eece7c7925d054bb2c5bf9381686fc5a 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -187,6 +187,26 @@ void CABACWriter::coding_tree_unit( CodingStructure& cs, const UnitArea& area, i } } +#if JVET_Q0795_CCALF + if ( !skipAlf ) + { + for ( int compIdx = 1; compIdx < getNumberValidComponents( cs.pcv->chrFormat ); compIdx++ ) + { + if (cs.slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1]) + { + const int filterCount = cs.slice->m_ccAlfFilterParam.ccAlfFilterCount[compIdx - 1]; + + const int ry = ctuRsAddr / cs.pcv->widthInCtus; + const int rx = ctuRsAddr % cs.pcv->widthInCtus; + const Position lumaPos(rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight); + + codeCcAlfFilterControlIdc(cs.slice->m_ccAlfFilterControl[compIdx - 1][ctuRsAddr], cs, ComponentID(compIdx), + ctuRsAddr, cs.slice->m_ccAlfFilterControl[compIdx - 1], lumaPos, filterCount); + } + } + } +#endif + if ( CS::isDualITree(cs) && cs.pcv->chrFormat != CHROMA_400 && cs.pcv->maxCUWidth > 64 ) { CUCtx chromaCuCtx(qps[CH_C]); @@ -3351,6 +3371,49 @@ void CABACWriter::codeAlfCtuEnableFlag( CodingStructure& cs, uint32_t ctuRsAddr, } } +#if JVET_Q0795_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 : 0; + } + if (aboveAvail) + { + ctxt += (filterControlIdc[curIdx - cs.pcv->widthInCtus]) ? 1 : 0; + } + ctxt += ( compID == COMPONENT_Cr ) ? 3 : 0; + + m_BinEncoder.encodeBin( ( idcVal == 0 ) ? 0 : 1, Ctx::CcAlfFilterControlFlag( ctxt ) ); // ON/OFF flag is context coded + if ( idcVal > 0 ) + { + int val = (idcVal - 1); + while ( val ) + { + m_BinEncoder.encodeBinEP( 1 ); + val--; + } + if ( idcVal < 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 ); +} +#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 940fa4c22be37adc3cf9c970d17187ee34b4dca9..8f2124456874fb612b18025a44150acf086681ab 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -164,6 +164,10 @@ public: void codeAlfCtuAlternatives ( CodingStructure& cs, ChannelType channel, AlfParam* alfParam); void codeAlfCtuAlternatives ( CodingStructure& cs, ComponentID compID, AlfParam* alfParam); void codeAlfCtuAlternative ( CodingStructure& cs, uint32_t ctuRsAddr, const int compIdx, const AlfParam* alfParam = NULL ); +#if JVET_Q0795_CCALF + void codeCcAlfFilterControlIdc(uint8_t idcVal, CodingStructure &cs, const ComponentID compID, const int curIdx, + const uint8_t *filterControlIdc, Position lumaPos, const int filterCount); +#endif private: void unary_max_symbol ( unsigned symbol, unsigned ctxId0, unsigned ctxIdN, unsigned maxSymbol ); diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp index 6de3317a96841f45a070bbe482aac24164d9fed8..252cea9d5bd56f04beaf784fb88c2f9b69846e29 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.cpp @@ -42,6 +42,20 @@ #define AlfCtx(c) SubCtx( Ctx::Alf, c) std::vector<double> EncAdaptiveLoopFilter::m_lumaLevelToWeightPLUT; +#if JVET_Q0795_CCALF +#include <algorithm> + +#if MAX_NUM_CC_ALF_FILTERS>1 +struct FilterIdxCount +{ + uint64_t count; + uint8_t filterIdx; +}; + +bool compareCounts(FilterIdxCount a, FilterIdxCount b) { return a.count > b.count; } +#endif +#endif + void AlfCovariance::getClipMax(const AlfFilterShape& alfShape, int *clip_max) const { for( int k = 0; k < numCoeff-1; ++k ) @@ -241,6 +255,27 @@ double AlfCovariance::calcErrorForCoeffs( const int *clip, const int *coeff, con return error / factor; } +#if JVET_Q0795_CCALF +double AlfCovariance::calcErrorForCcAlfCoeffs(const int* coeff, const int numCoeff, const int bitDepth) const +{ + double factor = 1 << (bitDepth - 1); + double error = 0; + + for (int i = 0; i < numCoeff; i++) // diagonal + { + double sum = 0; + for (int j = i + 1; j < numCoeff; j++) + { + // E[j][i] = E[i][j], sum will be multiplied by 2 later + sum += E[0][0][i][j] * coeff[j]; + } + error += ((E[0][0][i][i] * coeff[i] + sum * 2) / factor - 2 * y[0][i]) * coeff[i]; + } + + return error / factor; +} +#endif + double AlfCovariance::calculateError( const int *clip, const double *coeff, const int numCoeff ) const { double sum = 0; @@ -417,6 +452,13 @@ EncAdaptiveLoopFilter::EncAdaptiveLoopFilter( int& apsIdStart ) m_diffFilterCoeff = nullptr; m_alfWSSD = 0; + +#if JVET_Q0795_CCALF + m_alfCovarianceCcAlf[0] = nullptr; + m_alfCovarianceCcAlf[1] = nullptr; + m_alfCovarianceFrameCcAlf[0] = nullptr; + m_alfCovarianceFrameCcAlf[1] = nullptr; +#endif } void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, const int picHeight, const ChromaFormat chromaFormatIDC, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE], const int internalBitDepth[MAX_NUM_CHANNEL_TYPE] ) @@ -499,6 +541,51 @@ void EncAdaptiveLoopFilter::create( const EncCfg* encCfg, const int picWidth, co } m_alfCtbFilterSetIndexTmp.resize(m_numCTUsInPic); memset(m_clipDefaultEnc, 0, sizeof(m_clipDefaultEnc)); +#if JVET_Q0795_CCALF + m_apsIdCcAlfStart[0] = (int) MAX_NUM_APS; + m_apsIdCcAlfStart[1] = (int) MAX_NUM_APS; + for( int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++ ) + { + int numFilters = MAX_NUM_CC_ALF_FILTERS; + m_alfCovarianceCcAlf[compIdx-1] = new AlfCovariance**[m_filterShapesCcAlf[compIdx-1].size()]; + m_alfCovarianceFrameCcAlf[compIdx-1] = new AlfCovariance*[m_filterShapesCcAlf[compIdx-1].size()]; + for( int i = 0; i != m_filterShapesCcAlf[compIdx-1].size(); i++ ) + { + m_alfCovarianceFrameCcAlf[compIdx - 1][i] = new AlfCovariance[numFilters]; + for (int k = 0; k < numFilters; k++) + { + m_alfCovarianceFrameCcAlf[compIdx - 1][i][k].create(m_filterShapesCcAlf[compIdx - 1][i].numCoeff); + } + + m_alfCovarianceCcAlf[compIdx - 1][i] = new AlfCovariance *[numFilters]; + for (int j = 0; j < numFilters; j++) + { + m_alfCovarianceCcAlf[compIdx - 1][i][j] = new AlfCovariance[m_numCTUsInPic]; + for (int k = 0; k < m_numCTUsInPic; k++) + { + m_alfCovarianceCcAlf[compIdx - 1][i][j][k].create(m_filterShapesCcAlf[compIdx - 1][i].numCoeff); + } + } + } + } + m_trainingCovControl = new uint8_t[m_numCTUsInPic]; + m_unfilteredDistortion = new uint64_t *[1]; + for (int i = 0; i < 1; i++) + { + m_unfilteredDistortion[i] = new uint64_t[m_numCTUsInPic]; + } + for ( int i = 0; i < MAX_NUM_CC_ALF_FILTERS; i++ ) + { + m_trainingDistortion[i] = new uint64_t[m_numCTUsInPic]; + } + m_filterControl = new uint8_t[m_numCTUsInPic]; + m_bestFilterControl = new uint8_t[m_numCTUsInPic]; + uint32_t area = (picWidth >> getComponentScaleX(COMPONENT_Cb,chromaFormatIDC))*(picHeight >> getComponentScaleY(COMPONENT_Cb,chromaFormatIDC)); + m_bufOrigin = ( Pel* ) xMalloc( Pel, area ); + m_buf = new PelBuf( m_bufOrigin, picWidth >> getComponentScaleX(COMPONENT_Cb,chromaFormatIDC), picWidth >> getComponentScaleX(COMPONENT_Cb,chromaFormatIDC), picHeight >> getComponentScaleY(COMPONENT_Cb,chromaFormatIDC) ); + m_lumaSwingGreaterThanThresholdCount = new uint64_t[m_numCTUsInPic]; + m_chromaSampleCountNearMidPoint = new uint64_t[m_numCTUsInPic]; +#endif } void EncAdaptiveLoopFilter::destroy() @@ -622,6 +709,106 @@ void EncAdaptiveLoopFilter::destroy() delete[] m_ctbDistortionUnfilter[comp]; m_ctbDistortionUnfilter[comp] = nullptr; } + +#if JVET_Q0795_CCALF + for (int compIdx = 1; compIdx < MAX_NUM_COMPONENT; compIdx++) + { + int numFilters = MAX_NUM_CC_ALF_FILTERS; + if (m_alfCovarianceFrameCcAlf[compIdx - 1]) + { + for (int i = 0; i != m_filterShapesCcAlf[compIdx - 1].size(); i++) + { + for (int k = 0; k < numFilters; k++) + { + m_alfCovarianceFrameCcAlf[compIdx - 1][i][k].destroy(); + } + delete[] m_alfCovarianceFrameCcAlf[compIdx - 1][i]; + } + delete[] m_alfCovarianceFrameCcAlf[compIdx - 1]; + m_alfCovarianceFrameCcAlf[compIdx - 1] = nullptr; + } + + if (m_alfCovarianceCcAlf[compIdx - 1]) + { + for (int i = 0; i != m_filterShapesCcAlf[compIdx - 1].size(); i++) + { + for (int j = 0; j < numFilters; j++) + { + for (int k = 0; k < m_numCTUsInPic; k++) + { + m_alfCovarianceCcAlf[compIdx - 1][i][j][k].destroy(); + } + delete[] m_alfCovarianceCcAlf[compIdx - 1][i][j]; + } + delete[] m_alfCovarianceCcAlf[compIdx - 1][i]; + } + delete[] m_alfCovarianceCcAlf[compIdx - 1]; + m_alfCovarianceCcAlf[compIdx - 1] = nullptr; + } + } + + if (m_trainingCovControl) + { + delete[] m_trainingCovControl; + m_trainingCovControl = nullptr; + } + + for (int i = 0; i < 1; i++) + { + if (m_unfilteredDistortion[i]) + { + delete[] m_unfilteredDistortion[i]; + m_unfilteredDistortion[i] = nullptr; + } + } + delete[] m_unfilteredDistortion; + m_unfilteredDistortion = nullptr; + + for ( int i = 0; i < MAX_NUM_CC_ALF_FILTERS; i++ ) + { + if (m_trainingDistortion[i]) + { + delete[] m_trainingDistortion[i]; + m_trainingDistortion[i] = nullptr; + } + } + + if (m_filterControl) + { + delete[] m_filterControl; + m_filterControl = nullptr; + } + + if (m_bestFilterControl) + { + delete[] m_bestFilterControl; + m_bestFilterControl = nullptr; + } + + if (m_bufOrigin) + { + xFree(m_bufOrigin); + m_bufOrigin = nullptr; + } + + if (m_buf) + { + delete m_buf; + m_buf = nullptr; + } + + if (m_lumaSwingGreaterThanThresholdCount) + { + delete[] m_lumaSwingGreaterThanThresholdCount; + m_lumaSwingGreaterThanThresholdCount = nullptr; + } + if (m_chromaSampleCountNearMidPoint) + { + delete[] m_chromaSampleCountNearMidPoint; + m_chromaSampleCountNearMidPoint = nullptr; + } +#endif + AdaptiveLoopFilter::destroy(); } void EncAdaptiveLoopFilter::initCABACEstimator( CABACEncoder* cabacEncoder, CtxCache* ctxCache, Slice* pcSlice @@ -634,6 +821,76 @@ void EncAdaptiveLoopFilter::initCABACEstimator( CABACEncoder* cabacEncoder, CtxC m_CABACEstimator->resetBits(); } +#if JVET_Q0795_CCALF +void EncAdaptiveLoopFilter::xSetupCcAlfAPS( CodingStructure &cs ) +{ + if (m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1]) + { + int ccAlfCbApsId = cs.slice->getTileGroupCcAlfCbApsId(); + APS* aps = m_apsMap->getPS((cs.slice->getTileGroupCcAlfCbApsId() << NUM_APS_TYPE_LEN) + ALF_APS); + if (aps == NULL) + { + aps = m_apsMap->allocatePS((ccAlfCbApsId << NUM_APS_TYPE_LEN) + ALF_APS); + aps->setTemporalId(cs.slice->getTLayer()); + } + aps->getCcAlfAPSParam().ccAlfFilterEnabled[COMPONENT_Cb - 1] = 1; + aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cb - 1] = m_ccAlfFilterParam.ccAlfFilterCount[COMPONENT_Cb - 1]; + for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx] = + m_ccAlfFilterParam.ccAlfFilterIdxEnabled[COMPONENT_Cb - 1][filterIdx]; + memcpy(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], + m_ccAlfFilterParam.ccAlfCoeff[COMPONENT_Cb - 1][filterIdx], sizeof(short) * MAX_NUM_CC_ALF_CHROMA_COEFF); + } + aps->setAPSId(ccAlfCbApsId); + aps->setAPSType(ALF_APS); + if (m_reuseApsId[COMPONENT_Cb - 1] < 0) + { + aps->getCcAlfAPSParam().newCcAlfFilter[COMPONENT_Cb - 1] = 1; + m_apsMap->setChangedFlag((ccAlfCbApsId << NUM_APS_TYPE_LEN) + ALF_APS, true); + aps->setTemporalId(cs.slice->getTLayer()); + } + cs.slice->setTileGroupCcAlfCbEnabledFlag(true); + } + else + { + cs.slice->setTileGroupCcAlfCbEnabledFlag(false); + } + if (m_ccAlfFilterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1]) + { + int ccAlfCrApsId = cs.slice->getTileGroupCcAlfCrApsId(); + APS* aps = m_apsMap->getPS((cs.slice->getTileGroupCcAlfCrApsId() << NUM_APS_TYPE_LEN) + ALF_APS); + if (aps == NULL) + { + aps = m_apsMap->allocatePS((ccAlfCrApsId << NUM_APS_TYPE_LEN) + ALF_APS); + aps->setTemporalId(cs.slice->getTLayer()); + } + aps->getCcAlfAPSParam().ccAlfFilterEnabled[COMPONENT_Cr - 1] = 1; + aps->getCcAlfAPSParam().ccAlfFilterCount[COMPONENT_Cr - 1] = m_ccAlfFilterParam.ccAlfFilterCount[COMPONENT_Cr - 1]; + for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + aps->getCcAlfAPSParam().ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx] = + m_ccAlfFilterParam.ccAlfFilterIdxEnabled[COMPONENT_Cr - 1][filterIdx]; + memcpy(aps->getCcAlfAPSParam().ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], + m_ccAlfFilterParam.ccAlfCoeff[COMPONENT_Cr - 1][filterIdx], sizeof(short) * MAX_NUM_CC_ALF_CHROMA_COEFF); + } + aps->setAPSId(ccAlfCrApsId); + if (m_reuseApsId[COMPONENT_Cr - 1] < 0) + { + aps->getCcAlfAPSParam().newCcAlfFilter[COMPONENT_Cr - 1] = 1; + m_apsMap->setChangedFlag((ccAlfCrApsId << NUM_APS_TYPE_LEN) + ALF_APS, true); + aps->setTemporalId(cs.slice->getTLayer()); + } + aps->setAPSType(ALF_APS); + cs.slice->setTileGroupCcAlfCrEnabledFlag(true); + } + else + { + cs.slice->setTileGroupCcAlfCrEnabledFlag(false); + } +} +#endif + void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambdas #if ENABLE_QPA , const double lambdaChromaWeight @@ -656,6 +913,9 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda if (alfAPS) { alfAPS->getAlfAPSParam().reset(); +#if JVET_Q0795_CCALF + alfAPS->getCcAlfAPSParam().reset(); +#endif alfAPS = nullptr; } } @@ -663,6 +923,11 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda AlfParam alfParam; alfParam.reset(); const TempCtx ctxStart(m_CtxCache, AlfCtx(m_CABACEstimator->getCtx())); + +#if JVET_Q0795_CCALF + const TempCtx ctxStartCcAlf(m_CtxCache, SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx())); +#endif + // set available filter shapes alfParam.filterShapes = m_filterShapes; @@ -796,6 +1061,55 @@ void EncAdaptiveLoopFilter::ALFProcess(CodingStructure& cs, const double *lambda ); alfReconstructor(cs, recYuv); + +#if JVET_Q0795_CCALF + // Do not transmit CC ALF if it is unchanged + if (cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y)) + { + for (int32_t lumaAlfApsId : cs.slice->getTileGroupApsIdLuma()) + { + APS* aps = (lumaAlfApsId >= 0) ? m_apsMap->getPS((lumaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS) : nullptr; + if (aps && m_apsMap->getChangedFlag((lumaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS)) + { + aps->getCcAlfAPSParam().newCcAlfFilter[0] = false; + aps->getCcAlfAPSParam().newCcAlfFilter[1] = false; + } + } + } + int chromaAlfApsId = ( cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cb) || cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Cr) ) ? cs.slice->getTileGroupApsIdChroma() : -1; + APS* aps = (chromaAlfApsId >= 0) ? m_apsMap->getPS((chromaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS) : nullptr; + if (aps && m_apsMap->getChangedFlag((chromaAlfApsId << NUM_APS_TYPE_LEN) + ALF_APS)) + { + aps->getCcAlfAPSParam().newCcAlfFilter[0] = false; + aps->getCcAlfAPSParam().newCcAlfFilter[1] = false; + } + + if (!cs.slice->getSPS()->getCCALFEnabledFlag()) + { + return; + } + + m_tempBuf.get(COMPONENT_Cb).copyFrom(cs.getRecoBuf().get(COMPONENT_Cb)); + m_tempBuf.get(COMPONENT_Cr).copyFrom(cs.getRecoBuf().get(COMPONENT_Cr)); + recYuv = m_tempBuf.getBuf(cs.area); + recYuv.extendBorderPel(MAX_ALF_FILTER_LENGTH >> 1); + m_CABACEstimator->getCtx() = SubCtx(Ctx::CcAlfFilterControlFlag, ctxStartCcAlf); + deriveCcAlfFilter(cs, COMPONENT_Cb, orgYuv, recYuv, cs.getRecoBuf()); + m_CABACEstimator->getCtx() = SubCtx(Ctx::CcAlfFilterControlFlag, ctxStartCcAlf); + deriveCcAlfFilter(cs, COMPONENT_Cr, orgYuv, recYuv, cs.getRecoBuf()); + + xSetupCcAlfAPS(cs); + + for (int compIdx = 1; compIdx < getNumberValidComponents(cs.pcv->chrFormat); compIdx++) + { + ComponentID compID = ComponentID(compIdx); + if (m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1]) + { + applyCcAlfFilter(cs, compID, cs.getRecoBuf().get(compID), recYuv, m_ccAlfFilterControl[compIdx - 1], + m_ccAlfFilterParam.ccAlfCoeff[compIdx - 1], -1); + } + } +#endif } double EncAdaptiveLoopFilter::deriveCtbAlfEnableFlags( CodingStructure& cs, const int iShapeIdx, ChannelType channel, @@ -1604,6 +1918,29 @@ void EncAdaptiveLoopFilter::roundFiltCoeff( int *filterCoeffQuant, double *filte } } +#if JVET_Q0795_CCALF +void EncAdaptiveLoopFilter::roundFiltCoeffCCALF( int *filterCoeffQuant, double *filterCoeff, const int numCoeff, const int factor ) +{ + for( int i = 0; i < numCoeff; i++ ) + { + int sign = filterCoeff[i] > 0 ? 1 : -1; + double best_err = 128.0*128.0; + int best_index = 0; + for(int k = 0; k < CCALF_CANDS_COEFF_NR; k++) + { + double err = (filterCoeff[i] * sign * factor - CCALF_SMALL_TAB[k]); + err = err*err; + if(err < best_err) + { + best_err = err; + best_index = k; + } + } + filterCoeffQuant[i] = CCALF_SMALL_TAB[best_index] * sign; + } +} +#endif + 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] ) { static int tmpClip[MAX_NUM_ALF_LUMA_COEFF]; @@ -2538,6 +2875,11 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar }// for (int numTemporalAps = 0; numTemporalAps < apsIds.size(); numTemporalAps++) }//for (int useNewFilter = 0; useNewFilter <= 1; useNewFilter++) +#if JVET_Q0795_CCALF + cs.slice->setTileGroupCcAlfCbApsId(newApsId); + cs.slice->setTileGroupCcAlfCrApsId(newApsId); +#endif + if (costOff <= costMin) { cs.slice->resetTileGroupAlfEnabledFlag(); @@ -2735,6 +3077,14 @@ void EncAdaptiveLoopFilter::alfEncoderCtb(CodingStructure& cs, AlfParam& alfPar copyCtuAlternativeChroma(m_ctuAlternativeTmp, m_ctuAlternative); } } + +#if JVET_Q0795_CCALF + if (newApsIdChroma >= 0) + { + cs.slice->setTileGroupCcAlfCbApsId(newApsIdChroma); + cs.slice->setTileGroupCcAlfCrApsId(newApsIdChroma); + } +#endif if (costOff < costMin) { cs.slice->setTileGroupAlfEnabledFlag(COMPONENT_Cb, false); @@ -2971,3 +3321,999 @@ int EncAdaptiveLoopFilter::getMaxNumAlternativesChroma( ) { return std::min<int>( m_numCTUsInPic * 2, m_encCfg->getMaxNumAlfAlternativesChroma() ); } + +#if JVET_Q0795_CCALF +int EncAdaptiveLoopFilter::getCoeffRateCcAlf(short chromaCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], bool filterEnabled[MAX_NUM_CC_ALF_FILTERS], uint8_t filterCount, ComponentID compID) +{ + int bits = 0; + + if ( filterCount > 0 ) + { + bits += lengthUvlc(filterCount - 1); + int signaledFilterCount = 0; + for ( int filterIdx=0; filterIdx<MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + if (filterEnabled[filterIdx]) + { + AlfFilterShape alfShape(size_CC_ALF); + // Filter coefficients + for (int i = 0; i < alfShape.numCoeff - 1; i++) + { + bits += CCALF_BITS_PER_COEFF_LEVEL + (chromaCoeff[filterIdx][i] == 0 ? 0 : 1); + } + + signaledFilterCount++; + } + } + CHECK(signaledFilterCount != filterCount, "Number of filter signaled not same as indicated"); + } + + return bits; +} + +void EncAdaptiveLoopFilter::deriveCcAlfFilterCoeff( ComponentID compID, const PelUnitBuf& recYuv, const PelUnitBuf& recYuvExt, short filterCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], const uint8_t filterIdx ) +{ + int forward_tab[CCALF_CANDS_COEFF_NR * 2 - 1] = {0}; + for (int i = 0; i < CCALF_CANDS_COEFF_NR; i++) + { + 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]; + } + using TE = double[MAX_NUM_ALF_LUMA_COEFF][MAX_NUM_ALF_LUMA_COEFF]; + using Ty = double[MAX_NUM_ALF_LUMA_COEFF]; + + static double filterCoeffDbl[MAX_NUM_CC_ALF_CHROMA_COEFF]; + static int filterCoeffInt[MAX_NUM_CC_ALF_CHROMA_COEFF]; + + TE kE; + Ty ky; + const int size = m_filterShapesCcAlf[compID - 1][0].numCoeff - 1; + + for (int k = 0; k < size; k++) + { + ky[k] = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].y[0][k]; + for (int l = 0; l < size; l++) + { + kE[k][l] = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].E[0][0][k][l]; + } + } + + m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].gnsSolveByChol(kE, ky, filterCoeffDbl, size); + roundFiltCoeffCCALF(filterCoeffInt, filterCoeffDbl, size, (1 << m_scaleBits)); + + for (int k = 0; k < size; k++) + { + CHECK( filterCoeffInt[k] < -(1 << CCALF_DYNAMIC_RANGE), "this is not possible: filterCoeffInt[k] < -(1 << CCALF_DYNAMIC_RANGE)"); + CHECK( filterCoeffInt[k] > (1 << CCALF_DYNAMIC_RANGE), "this is not possible: filterCoeffInt[k] > (1 << CCALF_DYNAMIC_RANGE)"); + } + + // Refine quanitzation + int modified = 1; + double errRef = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].calcErrorForCcAlfCoeffs(filterCoeffInt, size, (m_scaleBits+1)); + while (modified) + { + modified = 0; + for (int delta : { 1, -1 }) + { + double errMin = MAX_DOUBLE; + int idxMin = -1; + int minIndex = -1; + + for (int k = 0; k < size; k++) + { + int org_idx = -1; + for (int i = 0; i < CCALF_CANDS_COEFF_NR * 2 - 1; i++) + { + if (forward_tab[i] == filterCoeffInt[k]) + { + org_idx = i; + break; + } + } + CHECK( org_idx < 0, "this is wrong, does not find coeff from forward_tab"); + if ( (org_idx - delta < 0) || (org_idx - delta >= CCALF_CANDS_COEFF_NR * 2 - 1) ) + continue; + + filterCoeffInt[k] = forward_tab[org_idx - delta]; + double error = m_alfCovarianceFrameCcAlf[compID - 1][0][filterIdx].calcErrorForCcAlfCoeffs(filterCoeffInt, size, (m_scaleBits+1)); + if( error < errMin ) + { + errMin = error; + idxMin = k; + minIndex = org_idx; + } + filterCoeffInt[k] = forward_tab[org_idx]; + } + if (errMin < errRef) + { + minIndex -= delta; + CHECK( minIndex < 0, "this is wrong, index - delta < 0"); + CHECK( minIndex >= CCALF_CANDS_COEFF_NR * 2 - 1, "this is wrong, index - delta >= CCALF_CANDS_COEFF_NR * 2 - 1"); + filterCoeffInt[idxMin] = forward_tab[minIndex]; + modified++; + errRef = errMin; + } + } + } + + + for (int k = 0; k < (size + 1); k++) + { + CHECK((filterCoeffInt[k] < -(1 << CCALF_DYNAMIC_RANGE)) || (filterCoeffInt[k] > (1 << CCALF_DYNAMIC_RANGE)), "Exceeded valid range for CC ALF coefficient"); + filterCoeff[filterIdx][k] = filterCoeffInt[k]; + } +} + + +void EncAdaptiveLoopFilter::computeLog2BlockSizeDistortion(const Pel *org, int orgStride, const Pel *dec, int decStride, + int height, int width, uint64_t *distortionBuf, + int distortionBufStride, int log2BlockWidth, + int log2BlockHeight, uint64_t& totalDistortion) +{ + totalDistortion = 0; + for (int y = 0; y < height; y += (1 << log2BlockHeight)) + { + for (int x = 0; x < width; x += (1 << log2BlockWidth)) + { + int err; + uint64_t ssd = 0; + + for (int yOff = 0; yOff < (1 << log2BlockHeight); yOff++) + { + for (int xOff = 0; xOff < (1 << log2BlockWidth); xOff++) + { + if ((y + yOff) >= height || (x + xOff) >= width) + { + continue; + } + + err = org[yOff * orgStride + x + xOff] - dec[yOff * decStride + x + xOff]; + ssd += err * err; + } + } + + distortionBuf[(y >> log2BlockHeight) * distortionBufStride + (x >> log2BlockWidth)] = ssd; + totalDistortion += ssd; + } + org += (orgStride << log2BlockHeight); + dec += (decStride << log2BlockHeight); + } +} + +void EncAdaptiveLoopFilter::determineControlIdcValues(CodingStructure &cs, const ComponentID compID, const PelBuf *buf, + const int ctuWidthC, const int ctuHeightC, const int picWidthC, + const int picHeightC, uint64_t **unfilteredDistortion, + uint64_t *trainingDistortion[MAX_NUM_CC_ALF_FILTERS], + uint64_t *lumaSwingGreaterThanThresholdCount, + uint64_t *chromaSampleCountNearMidPoint, + bool reuseTemporalFilterCoeff, uint8_t *trainingCovControl, + uint8_t *filterControl, uint64_t &curTotalDistortion, + double &curTotalRate, bool filterEnabled[MAX_NUM_CC_ALF_FILTERS], + uint8_t mapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS + 1], + uint8_t &ccAlfFilterCount) +{ + bool curFilterEnabled[MAX_NUM_CC_ALF_FILTERS]; + std::fill_n(curFilterEnabled, MAX_NUM_CC_ALF_FILTERS, false); + +#if MAX_NUM_CC_ALF_FILTERS>1 + FilterIdxCount filterIdxCount[MAX_NUM_CC_ALF_FILTERS]; + for (int i = 0; i < MAX_NUM_CC_ALF_FILTERS; i++) + { + filterIdxCount[i].count = 0; + filterIdxCount[i].filterIdx = i; + } + + double prevRate = curTotalRate; +#endif + + TempCtx ctxInitial(m_CtxCache); + TempCtx ctxBest(m_CtxCache); + TempCtx ctxStart(m_CtxCache); + ctxInitial = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx()); + ctxBest = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx()); + + int ctuIdx = 0; + for (int yCtu = 0; yCtu < buf->height; yCtu += ctuHeightC) + { + for (int xCtu = 0; xCtu < buf->width; xCtu += ctuWidthC) + { + uint64_t ssd; + double rate; + double cost; + + uint64_t bestSSD = MAX_UINT64; + double bestRate = MAX_DOUBLE; + double bestCost = MAX_DOUBLE; + uint8_t bestFilterIdc = 0; + uint8_t bestFilterIdx = 0; + const uint32_t thresholdS = std::min<int>(buf->height - yCtu, ctuHeightC) << getComponentScaleY(COMPONENT_Cb, m_chromaFormat); + const uint32_t numberOfChromaSamples = std::min<int>(buf->height - yCtu, ctuHeightC) * std::min<int>(buf->width - xCtu, ctuWidthC); + const uint32_t thresholdC = (numberOfChromaSamples >> 2); + + m_CABACEstimator->getCtx() = ctxBest; + ctxStart = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx()); + + for (int filterIdx = 0; filterIdx <= MAX_NUM_CC_ALF_FILTERS; filterIdx++) + { + uint8_t filterIdc = mapFilterIdxToFilterIdc[filterIdx]; + if (filterIdx < MAX_NUM_CC_ALF_FILTERS && !filterEnabled[filterIdx]) + { + continue; + } + + if (filterIdx == MAX_NUM_CC_ALF_FILTERS) + { + ssd = unfilteredDistortion[0][ctuIdx]; // restore saved distortion computation + } + else + { + ssd = trainingDistortion[filterIdx][ctuIdx]; + } + m_CABACEstimator->getCtx() = ctxStart; + m_CABACEstimator->resetBits(); + const Position lumaPos = Position({ xCtu << getComponentScaleX(compID, cs.pcv->chrFormat), + yCtu << getComponentScaleY(compID, cs.pcv->chrFormat) }); + m_CABACEstimator->codeCcAlfFilterControlIdc(filterIdc, cs, compID, ctuIdx, filterControl, lumaPos, + ccAlfFilterCount); + rate = FRAC_BITS_SCALE * m_CABACEstimator->getEstFracBits(); + cost = rate * m_lambda[compID] + ssd; + + bool limitationExceeded = false; + if (m_limitCcAlf && filterIdx < MAX_NUM_CC_ALF_FILTERS) + { + limitationExceeded = limitationExceeded || (lumaSwingGreaterThanThresholdCount[ctuIdx] >= thresholdS); + limitationExceeded = limitationExceeded || (chromaSampleCountNearMidPoint[ctuIdx] >= thresholdC); + } + if (cost < bestCost && !limitationExceeded) + { + bestCost = cost; + bestRate = rate; + bestSSD = ssd; + bestFilterIdc = filterIdc; + bestFilterIdx = filterIdx; + + ctxBest = SubCtx(Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx()); + + trainingCovControl[ctuIdx] = (filterIdx == MAX_NUM_CC_ALF_FILTERS) ? 0 : (filterIdx + 1); + filterControl[ctuIdx] = (filterIdx == MAX_NUM_CC_ALF_FILTERS) ? 0 : (filterIdx + 1); + } + } + if (bestFilterIdc != 0) + { + curFilterEnabled[bestFilterIdx] = true; +#if MAX_NUM_CC_ALF_FILTERS>1 + filterIdxCount[bestFilterIdx].count++; +#endif + } + curTotalRate += bestRate; + curTotalDistortion += bestSSD; + ctuIdx++; + } + } + +#if MAX_NUM_CC_ALF_FILTERS>1 + if (!reuseTemporalFilterCoeff) + { + std::copy_n(curFilterEnabled, MAX_NUM_CC_ALF_FILTERS, filterEnabled); + + std::sort(filterIdxCount, filterIdxCount + MAX_NUM_CC_ALF_FILTERS, compareCounts); + + int filterIdc = 1; + ccAlfFilterCount = 0; + for ( FilterIdxCount &s : filterIdxCount ) + { + const int filterIdx = s.filterIdx; + if (filterEnabled[filterIdx]) + { + mapFilterIdxToFilterIdc[filterIdx] = filterIdc; + filterIdc++; + ccAlfFilterCount++; + } + } + + curTotalRate = prevRate; + m_CABACEstimator->getCtx() = ctxInitial; + m_CABACEstimator->resetBits(); + int ctuIdx = 0; + for (int y = 0; y < buf->height; y += ctuHeightC) + { + for (int x = 0; x < buf->width; x += ctuWidthC) + { + const int filterIdxPlus1 = filterControl[ctuIdx]; + + const Position lumaPos = Position( + { x << getComponentScaleX(compID, cs.pcv->chrFormat), y << getComponentScaleY(compID, cs.pcv->chrFormat) }); + + m_CABACEstimator->codeCcAlfFilterControlIdc(filterIdxPlus1 == 0 ? 0 + : mapFilterIdxToFilterIdc[filterIdxPlus1 - 1], + cs, compID, ctuIdx, filterControl, lumaPos, ccAlfFilterCount); + + ctuIdx++; + } + } + curTotalRate += FRAC_BITS_SCALE*m_CABACEstimator->getEstFracBits(); + } +#endif + + // restore for next iteration + m_CABACEstimator->getCtx() = ctxInitial; +} + +std::vector<int> EncAdaptiveLoopFilter::getAvailableCcAlfApsIds(CodingStructure& cs, ComponentID compID) +{ + APS** apss = cs.slice->getAlfAPSs(); + for (int i = 0; i < ALF_CTB_MAX_NUM_APS; i++) + { + apss[i] = m_apsMap->getPS((i << NUM_APS_TYPE_LEN) + ALF_APS); + } + + std::vector<int> result; + int apsIdChecked = 0, curApsId = m_apsIdStart; + if (curApsId < ALF_CTB_MAX_NUM_APS) + { + while (apsIdChecked < ALF_CTB_MAX_NUM_APS && !cs.slice->isIntra() && result.size() < ALF_CTB_MAX_NUM_APS && !cs.slice->getPendingRasInit() && !cs.slice->isIDRorBLA()) + { + APS* curAPS = cs.slice->getAlfAPSs()[curApsId]; + if (curAPS && curAPS->getTemporalId() <= cs.slice->getTLayer() && curAPS->getCcAlfAPSParam().newCcAlfFilter[compID - 1]) + { + result.push_back(curApsId); + } + apsIdChecked++; + curApsId = (curApsId + 1) % ALF_CTB_MAX_NUM_APS; + } + } + return result; +} + +void EncAdaptiveLoopFilter::deriveCcAlfFilter( CodingStructure& cs, ComponentID compID, const PelUnitBuf& orgYuv, const PelUnitBuf& tempDecYuvBuf, const PelUnitBuf& dstYuv ) +{ + if (!cs.slice->getTileGroupAlfEnabledFlag(COMPONENT_Y)) + { + m_ccAlfFilterParam.ccAlfFilterEnabled[compID - 1] = false; + return; + } + + m_limitCcAlf = m_encCfg->getBaseQP() >= m_encCfg->getCCALFQpThreshold(); + if (m_limitCcAlf && cs.slice->getSliceQp() <= m_encCfg->getBaseQP() + 1) + { + m_ccAlfFilterParam.ccAlfFilterEnabled[compID - 1] = false; + return; + } + + uint8_t bestMapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS+1]; + const int scaleX = getComponentScaleX(compID, cs.pcv->chrFormat); + const int scaleY = getComponentScaleY(compID, cs.pcv->chrFormat); + const int ctuWidthC = cs.pcv->maxCUWidth >> scaleX; + const int ctuHeightC = cs.pcv->maxCUHeight >> scaleY; + const int picWidthC = cs.pcv->lumaWidth >> scaleX; + const int picHeightC = cs.pcv->lumaHeight >> scaleY; + const int maxTrainingIterCount = 15; + + if (m_limitCcAlf) + { + countLumaSwingGreaterThanThreshold(dstYuv.get(COMPONENT_Y).bufAt(0, 0), dstYuv.get(COMPONENT_Y).stride, dstYuv.get(COMPONENT_Y).height, dstYuv.get(COMPONENT_Y).width, cs.pcv->maxCUWidthLog2, cs.pcv->maxCUHeightLog2, m_lumaSwingGreaterThanThresholdCount, m_numCTUsInWidth); + } + if (m_limitCcAlf) + { + countChromaSampleValueNearMidPoint(dstYuv.get(compID).bufAt(0, 0), dstYuv.get(compID).stride, dstYuv.get(compID).height, dstYuv.get(compID).width, cs.pcv->maxCUWidthLog2 - scaleX, cs.pcv->maxCUHeightLog2 - scaleY, m_chromaSampleCountNearMidPoint, m_numCTUsInWidth); + } + + for ( int filterIdx = 0; filterIdx <= MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + if ( filterIdx < MAX_NUM_CC_ALF_FILTERS) + { + memset( m_bestFilterCoeffSet[filterIdx], 0, sizeof(m_bestFilterCoeffSet[filterIdx]) ); + bestMapFilterIdxToFilterIdc[filterIdx] = filterIdx + 1; + } + else + { + bestMapFilterIdxToFilterIdc[filterIdx] = 0; + } + } + memset(m_bestFilterControl, 0, sizeof(uint8_t) * m_numCTUsInPic); + int ccalfReuseApsId = -1; + m_reuseApsId[compID - 1] = -1; + + const TempCtx ctxStartCcAlfFilterControlFlag ( m_CtxCache, SubCtx( Ctx::CcAlfFilterControlFlag, m_CABACEstimator->getCtx() ) ); + + // compute cost of not filtering + const Pel *org = orgYuv.get( compID ).bufAt(0,0); + const Pel *unfiltered = dstYuv.get( compID ).bufAt(0,0); + const int orgStride = orgYuv.get( compID ).stride; + const int unfilteredStride = dstYuv.get( compID ).stride; + const Pel *filtered = m_buf->bufAt(0,0); + const int filteredStride = m_buf->stride; + uint64_t unfilteredDistortion = 0; + computeLog2BlockSizeDistortion(org, orgStride, unfiltered, unfilteredStride, m_buf->height, m_buf->width, + m_unfilteredDistortion[0], m_numCTUsInWidth, cs.pcv->maxCUWidthLog2 - scaleX, + cs.pcv->maxCUHeightLog2 - scaleY, unfilteredDistortion); + double bestUnfilteredTotalCost = 1 * m_lambda[compID] + unfilteredDistortion; // 1 bit is for gating flag + + static bool ccAlfFilterIdxEnabled[MAX_NUM_CC_ALF_FILTERS]; + static short ccAlfFilterCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF]; + static uint8_t ccAlfFilterCount = MAX_NUM_CC_ALF_FILTERS; + double bestFilteredTotalCost = MAX_DOUBLE; + bool bestreuseTemporalFilterCoeff = false; + std::vector<int> apsIds = getAvailableCcAlfApsIds(cs, compID); + + for (int testFilterIdx = 0; testFilterIdx < ( apsIds.size() + 1 ); testFilterIdx++ ) + { + bool referencingExistingAps = (testFilterIdx < apsIds.size()) ? true : false; + int maxNumberOfFiltersBeingTested = MAX_NUM_CC_ALF_FILTERS - (testFilterIdx - static_cast<int>(apsIds.size())); + + if (maxNumberOfFiltersBeingTested < 0) + { + maxNumberOfFiltersBeingTested = 1; + } + + { + // Instead of rewriting the control buffer for every training iteration just keep a mapping from filterIdx to filterIdc + uint8_t mapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS + 1]; + for (int filterIdx = 0; filterIdx <= MAX_NUM_CC_ALF_FILTERS; filterIdx++) + { + if (filterIdx == MAX_NUM_CC_ALF_FILTERS) + { + mapFilterIdxToFilterIdc[filterIdx] = 0; + } + else + { + mapFilterIdxToFilterIdc[filterIdx] = filterIdx + 1; + } + } + + // initialize filters + for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + ccAlfFilterIdxEnabled[filterIdx] = false; + memset(ccAlfFilterCoeff[filterIdx], 0, sizeof(ccAlfFilterCoeff[filterIdx])); + } + if ( referencingExistingAps ) + { + maxNumberOfFiltersBeingTested = m_apsMap->getPS((apsIds[testFilterIdx] << NUM_APS_TYPE_LEN) + ALF_APS)->getCcAlfAPSParam().ccAlfFilterCount[compID - 1]; + ccAlfFilterCount = maxNumberOfFiltersBeingTested; + for (int filterIdx = 0; filterIdx < maxNumberOfFiltersBeingTested; filterIdx++) + { + ccAlfFilterIdxEnabled[filterIdx] = true; + memcpy(ccAlfFilterCoeff[filterIdx], m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx], + sizeof(ccAlfFilterCoeff[filterIdx])); + } + memcpy( ccAlfFilterCoeff, m_apsMap->getPS((apsIds[testFilterIdx] << NUM_APS_TYPE_LEN) + ALF_APS)->getCcAlfAPSParam().ccAlfCoeff[compID - 1], sizeof(ccAlfFilterCoeff) ); + } + else + { + for (int i = 0; i < maxNumberOfFiltersBeingTested; i++) + { + ccAlfFilterIdxEnabled[i] = true; + } + ccAlfFilterCount = maxNumberOfFiltersBeingTested; + } + + // initialize + int controlIdx = 0; + const int columnSize = ( m_buf->width / maxNumberOfFiltersBeingTested); + for (int y = 0; y < m_buf->height; y += ctuHeightC) + { + for (int x = 0; x < m_buf->width; x += ctuWidthC) + { + m_trainingCovControl[controlIdx] = ( x / columnSize ) + 1; + controlIdx++; + } + } + + // compute cost of filtering + int trainingIterCount = 0; + bool keepTraining = true; + bool improvement = false; + double prevTotalCost = MAX_DOUBLE; + while (keepTraining) + { + improvement = false; + for (int filterIdx = 0; filterIdx < maxNumberOfFiltersBeingTested; filterIdx++) + { + if (ccAlfFilterIdxEnabled[filterIdx]) + { + if (!referencingExistingAps) + { + deriveStatsForCcAlfFiltering(orgYuv, tempDecYuvBuf, compID, m_numCTUsInWidth, (filterIdx + 1), cs); + deriveCcAlfFilterCoeff(compID, dstYuv, tempDecYuvBuf, ccAlfFilterCoeff, filterIdx); + } + m_buf->copyFrom(dstYuv.get(compID)); + applyCcAlfFilter(cs, compID, *m_buf, tempDecYuvBuf, nullptr, ccAlfFilterCoeff, filterIdx); + + uint64_t distortion = 0; + computeLog2BlockSizeDistortion( + org, orgStride, filtered, filteredStride, m_buf->height, m_buf->width, m_trainingDistortion[filterIdx], + m_numCTUsInWidth, cs.pcv->maxCUWidthLog2 - scaleX, cs.pcv->maxCUHeightLog2 - scaleY, distortion); + } + } + + m_CABACEstimator->getCtx() = ctxStartCcAlfFilterControlFlag; + + uint64_t curTotalDistortion = 0; + double curTotalRate = 0; + determineControlIdcValues(cs, compID, m_buf, ctuWidthC, ctuHeightC, picWidthC, picHeightC, + m_unfilteredDistortion, m_trainingDistortion, + m_lumaSwingGreaterThanThresholdCount, + m_chromaSampleCountNearMidPoint, + (referencingExistingAps == true), + m_trainingCovControl, m_filterControl, curTotalDistortion, curTotalRate, + ccAlfFilterIdxEnabled, mapFilterIdxToFilterIdc, ccAlfFilterCount); + + // compute coefficient coding bit cost + if (ccAlfFilterCount > 0) + { + if (referencingExistingAps) + { + curTotalRate += 1 + 3 + lengthUvlc(ccAlfFilterCount - 1); // +1 for enable flag, +3 APS ID in slice header + } + else + { + curTotalRate += getCoeffRateCcAlf(ccAlfFilterCoeff, ccAlfFilterIdxEnabled, ccAlfFilterCount, compID) + 1 + lengthUvlc(ccAlfFilterCount - 1) + + 7; // +1 for the enable flag, +7 two 3-bit APS ID, one in slice header/one in APS, a 1-bit + // new filter flags (ignore shared cost such as other new-filter flags/NALU header/RBSP + // terminating bit/byte alignment bits) + } + + double curTotalCost = curTotalRate * m_lambda[compID] + curTotalDistortion; + + if (curTotalCost < prevTotalCost) + { + prevTotalCost = curTotalCost; + improvement = true; + } + + if (curTotalCost < bestFilteredTotalCost) + { + bestFilteredTotalCost = curTotalCost; + memcpy(m_bestFilterIdxEnabled, ccAlfFilterIdxEnabled, sizeof(ccAlfFilterIdxEnabled)); + memcpy(m_bestFilterCoeffSet, ccAlfFilterCoeff, sizeof(ccAlfFilterCoeff)); + memcpy(m_bestFilterControl, m_filterControl, sizeof(uint8_t) * m_numCTUsInPic); + m_bestFilterCount = ccAlfFilterCount; + ccalfReuseApsId = referencingExistingAps ? apsIds[testFilterIdx] : -1; + memcpy(bestMapFilterIdxToFilterIdc, mapFilterIdxToFilterIdc, sizeof(mapFilterIdxToFilterIdc)); + } + } + + trainingIterCount++; + if (!improvement || trainingIterCount > maxTrainingIterCount || referencingExistingAps) + { + keepTraining = false; + } + } + } + } + + if (bestUnfilteredTotalCost < bestFilteredTotalCost) + { + memset(m_bestFilterControl, 0, sizeof(uint8_t) * m_numCTUsInPic); + } + + // save best coeff and control + bool atleastOneBlockUndergoesFitlering = false; + for (int controlIdx = 0; m_bestFilterCount > 0 && controlIdx < m_numCTUsInPic; controlIdx++) + { + if (m_bestFilterControl[controlIdx]) + { + atleastOneBlockUndergoesFitlering = true; + break; + } + } + m_ccAlfFilterParam.numberValidComponents = getNumberValidComponents(m_chromaFormat); + m_ccAlfFilterParam.ccAlfFilterEnabled[compID - 1] = atleastOneBlockUndergoesFitlering; + if (atleastOneBlockUndergoesFitlering) + { + // update the filter control indicators + if (bestreuseTemporalFilterCoeff!=1) + { + short storedBestFilterCoeffSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF]; + for (int filterIdx=0; filterIdx<MAX_NUM_CC_ALF_FILTERS; filterIdx++) + { + memcpy(storedBestFilterCoeffSet[filterIdx], m_bestFilterCoeffSet[filterIdx], sizeof(m_bestFilterCoeffSet[filterIdx])); + } + memcpy(m_filterControl, m_bestFilterControl, sizeof(uint8_t) * m_numCTUsInPic); + + int filterCount = 0; + for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + uint8_t curFilterIdc = bestMapFilterIdxToFilterIdc[filterIdx]; + if (m_bestFilterIdxEnabled[filterIdx]) + { + for (int controlIdx = 0; controlIdx < m_numCTUsInPic; controlIdx++) + { + if (m_filterControl[controlIdx] == (filterIdx+1) ) + { + m_bestFilterControl[controlIdx] = curFilterIdc; + } + } + memcpy( m_bestFilterCoeffSet[curFilterIdc-1], storedBestFilterCoeffSet[filterIdx], sizeof(storedBestFilterCoeffSet[filterIdx]) ); + filterCount++; + } + m_bestFilterIdxEnabled[filterIdx] = ( filterIdx < m_bestFilterCount ) ? true : false; + } + CHECK( filterCount != m_bestFilterCount, "Number of filters enabled did not match the filter count"); + } + + m_ccAlfFilterParam.ccAlfFilterCount[compID - 1] = m_bestFilterCount; + // cleanup before copying + memset(m_ccAlfFilterControl[compID - 1], 0, sizeof(uint8_t) * m_numCTUsInPic); + for ( int filterIdx = 0; filterIdx < MAX_NUM_CC_ALF_FILTERS; filterIdx++ ) + { + memset(m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx], 0, + sizeof(m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx])); + } + memset(m_ccAlfFilterParam.ccAlfFilterIdxEnabled[compID - 1], false, + sizeof(m_ccAlfFilterParam.ccAlfFilterIdxEnabled[compID - 1])); + for ( int filterIdx = 0; filterIdx < m_bestFilterCount; filterIdx++ ) + { + m_ccAlfFilterParam.ccAlfFilterIdxEnabled[compID - 1][filterIdx] = m_bestFilterIdxEnabled[filterIdx]; + memcpy(m_ccAlfFilterParam.ccAlfCoeff[compID - 1][filterIdx], m_bestFilterCoeffSet[filterIdx], + sizeof(m_bestFilterCoeffSet[filterIdx])); + } + memcpy(m_ccAlfFilterControl[compID - 1], m_bestFilterControl, sizeof(uint8_t) * m_numCTUsInPic); + if ( ccalfReuseApsId >= 0 ) + { + m_reuseApsId[compID - 1] = ccalfReuseApsId; + if (compID == COMPONENT_Cb) + { + cs.slice->setTileGroupCcAlfCbApsId(ccalfReuseApsId); + } + else + { + cs.slice->setTileGroupCcAlfCrApsId(ccalfReuseApsId); + } + } + } +} + +void EncAdaptiveLoopFilter::deriveStatsForCcAlfFiltering(const PelUnitBuf &orgYuv, const PelUnitBuf &recYuv, + const int compIdx, const int maskStride, + const uint8_t filterIdc, CodingStructure &cs) +{ + const int filterIdx = filterIdc - 1; + + // init CTU stats buffers + for( int shape = 0; shape != m_filterShapesCcAlf[compIdx-1].size(); shape++ ) + { + for (int ctuIdx = 0; ctuIdx < m_numCTUsInPic; ctuIdx++) + { + m_alfCovarianceCcAlf[compIdx - 1][shape][filterIdx][ctuIdx].reset(); + } + } + + // init Frame stats buffers + for (int shape = 0; shape != m_filterShapesCcAlf[compIdx - 1].size(); shape++) + { + m_alfCovarianceFrameCcAlf[compIdx - 1][shape][filterIdx].reset(); + } + + int ctuRsAddr = 0; + const PreCalcValues &pcv = *cs.pcv; + bool clipTop = false, clipBottom = false, clipLeft = false, clipRight = false; + int numHorVirBndry = 0, numVerVirBndry = 0; + int horVirBndryPos[] = { 0, 0, 0 }; + int verVirBndryPos[] = { 0, 0, 0 }; + + for (int yPos = 0; yPos < m_picHeight; yPos += m_maxCUHeight) + { + for (int xPos = 0; xPos < m_picWidth; xPos += m_maxCUWidth) + { + if (m_trainingCovControl[ctuRsAddr] == filterIdc) + { + const int width = (xPos + m_maxCUWidth > m_picWidth) ? (m_picWidth - xPos) : m_maxCUWidth; + const int height = (yPos + m_maxCUHeight > m_picHeight) ? (m_picHeight - yPos) : m_maxCUHeight; + int rasterSliceAlfPad = 0; + if (isCrossedByVirtualBoundaries(cs, xPos, yPos, width, height, clipTop, clipBottom, clipLeft, clipRight, + numHorVirBndry, numVerVirBndry, horVirBndryPos, verVirBndryPos, + rasterSliceAlfPad)) + { + int yStart = yPos; + for (int i = 0; i <= numHorVirBndry; i++) + { + const int yEnd = i == numHorVirBndry ? yPos + height : horVirBndryPos[i]; + const int h = yEnd - yStart; + const bool clipT = (i == 0 && clipTop) || (i > 0) || (yStart == 0); + const bool clipB = (i == numHorVirBndry && clipBottom) || (i < numHorVirBndry) || (yEnd == pcv.lumaHeight); + int xStart = xPos; + for (int j = 0; j <= numVerVirBndry; j++) + { + const int xEnd = j == numVerVirBndry ? xPos + width : verVirBndryPos[j]; + const int w = xEnd - xStart; + const bool clipL = (j == 0 && clipLeft) || (j > 0) || (xStart == 0); + const bool clipR = (j == numVerVirBndry && clipRight) || (j < numVerVirBndry) || (xEnd == pcv.lumaWidth); + const int wBuf = w + (clipL ? 0 : MAX_ALF_PADDING_SIZE) + (clipR ? 0 : MAX_ALF_PADDING_SIZE); + const int hBuf = h + (clipT ? 0 : MAX_ALF_PADDING_SIZE) + (clipB ? 0 : MAX_ALF_PADDING_SIZE); + PelUnitBuf recBuf = m_tempBuf2.subBuf(UnitArea(cs.area.chromaFormat, Area(0, 0, wBuf, hBuf))); + recBuf.copyFrom(recYuv.subBuf( + UnitArea(cs.area.chromaFormat, Area(xStart - (clipL ? 0 : MAX_ALF_PADDING_SIZE), + yStart - (clipT ? 0 : MAX_ALF_PADDING_SIZE), wBuf, hBuf)))); + // pad top-left unavailable samples for raster slice + if (xStart == xPos && yStart == yPos && (rasterSliceAlfPad & 1)) + { + recBuf.padBorderPel(MAX_ALF_PADDING_SIZE, 1); + } + + // pad bottom-right unavailable samples for raster slice + if (xEnd == xPos + width && yEnd == yPos + height && (rasterSliceAlfPad & 2)) + { + recBuf.padBorderPel(MAX_ALF_PADDING_SIZE, 2); + } + recBuf.extendBorderPel(MAX_ALF_PADDING_SIZE); + recBuf = recBuf.subBuf(UnitArea( + cs.area.chromaFormat, Area(clipL ? 0 : MAX_ALF_PADDING_SIZE, clipT ? 0 : MAX_ALF_PADDING_SIZE, w, h))); + + const UnitArea area(m_chromaFormat, Area(0, 0, w, h)); + const UnitArea areaDst(m_chromaFormat, Area(xStart, yStart, w, h)); + + const ComponentID compID = ComponentID(compIdx); + + for (int shape = 0; shape != m_filterShapesCcAlf[compIdx - 1].size(); shape++) + { + getBlkStatsCcAlf(m_alfCovarianceCcAlf[compIdx - 1][0][filterIdx][ctuRsAddr], + m_filterShapesCcAlf[compIdx - 1][shape], orgYuv, recBuf, areaDst, area, compID, yPos); + m_alfCovarianceFrameCcAlf[compIdx - 1][shape][filterIdx] += + m_alfCovarianceCcAlf[compIdx - 1][shape][filterIdx][ctuRsAddr]; + } + + xStart = xEnd; + } + + yStart = yEnd; + } + } + else + { + const UnitArea area(m_chromaFormat, Area(xPos, yPos, width, height)); + + const ComponentID compID = ComponentID(compIdx); + + for (int shape = 0; shape != m_filterShapesCcAlf[compIdx - 1].size(); shape++) + { + getBlkStatsCcAlf(m_alfCovarianceCcAlf[compIdx - 1][0][filterIdx][ctuRsAddr], + m_filterShapesCcAlf[compIdx - 1][shape], orgYuv, recYuv, area, area, compID, yPos); + m_alfCovarianceFrameCcAlf[compIdx - 1][shape][filterIdx] += + m_alfCovarianceCcAlf[compIdx - 1][shape][filterIdx][ctuRsAddr]; + } + } + } + ctuRsAddr++; + } + } +} + +void EncAdaptiveLoopFilter::getBlkStatsCcAlf(AlfCovariance &alfCovariance, const AlfFilterShape &shape, + const PelUnitBuf &orgYuv, const PelUnitBuf &recYuv, + const UnitArea &areaDst, const UnitArea &area, const ComponentID compID, + const int yPos) +{ + const int numberOfComponents = getNumberValidComponents( m_chromaFormat ); + const CompArea &compArea = areaDst.block(compID); + int recStride[MAX_NUM_COMPONENT]; + const Pel* rec[MAX_NUM_COMPONENT]; + for ( int cIdx = 0; cIdx < numberOfComponents; cIdx++ ) + { + recStride[cIdx] = recYuv.get(ComponentID(cIdx)).stride; + rec[cIdx] = recYuv.get(ComponentID(cIdx)).bufAt(isLuma(ComponentID(cIdx)) ? area.lumaPos() : area.chromaPos()); + } + + int orgStride = orgYuv.get(compID).stride; + const Pel *org = orgYuv.get(compID).bufAt(compArea); + const int numBins = 1; + + int vbCTUHeight = m_alfVBLumaCTUHeight; + int vbPos = m_alfVBLumaPos; + if ((yPos + m_maxCUHeight) >= m_picHeight) + { + vbPos = m_picHeight; + } + + int ELocal[MAX_NUM_CC_ALF_CHROMA_COEFF][1]; + + for (int i = 0; i < compArea.height; i++) + { + int vbDistance = ((i << getComponentScaleX(compID, m_chromaFormat)) % vbCTUHeight) - vbPos; + for (int j = 0; j < compArea.width; j++) + { + std::memset(ELocal, 0, sizeof(ELocal)); + + double weight = 1.0; + if (m_alfWSSD) + { + weight = m_lumaLevelToWeightPLUT[org[j]]; + } + + int yLocal = org[j] - rec[compID][j]; + + calcCovarianceCcAlf( ELocal, rec[COMPONENT_Y] + ( j << getComponentScaleX(compID, m_chromaFormat)), recStride[COMPONENT_Y], shape, vbDistance ); + + for( int k = 0; k < (shape.numCoeff - 1); k++ ) + { + for( int l = k; l < (shape.numCoeff - 1); l++ ) + { + for( int b0 = 0; b0 < numBins; b0++ ) + { + for (int b1 = 0; b1 < numBins; b1++) + { + if (m_alfWSSD) + { + alfCovariance.E[b0][b1][k][l] += weight * (double) (ELocal[k][b0] * ELocal[l][b1]); + } + else + { + alfCovariance.E[b0][b1][k][l] += ELocal[k][b0] * ELocal[l][b1]; + } + } + } + } + for (int b = 0; b < numBins; b++) + { + if (m_alfWSSD) + { + alfCovariance.y[b][k] += weight * (double) (ELocal[k][b] * yLocal); + } + else + { + alfCovariance.y[b][k] += ELocal[k][b] * yLocal; + } + } + } + if (m_alfWSSD) + { + alfCovariance.pixAcc += weight * (double) (yLocal * yLocal); + } + else + { + alfCovariance.pixAcc += yLocal * yLocal; + } + } + org += orgStride; + for (int srcCIdx = 0; srcCIdx < numberOfComponents; srcCIdx++) + { + ComponentID srcCompID = ComponentID(srcCIdx); + if (toChannelType(srcCompID) == toChannelType(compID)) + { + rec[srcCIdx] += recStride[srcCIdx]; + } + else + { + if (isLuma(compID)) + { + rec[srcCIdx] += (recStride[srcCIdx] >> getComponentScaleY(srcCompID, m_chromaFormat)); + } + else + { + rec[srcCIdx] += (recStride[srcCIdx] << getComponentScaleY(compID, m_chromaFormat)); + } + } + } + } + + for (int k = 1; k < (MAX_NUM_CC_ALF_CHROMA_COEFF - 1); k++) + { + for (int l = 0; l < k; l++) + { + for (int b0 = 0; b0 < numBins; b0++) + { + for (int b1 = 0; b1 < numBins; b1++) + { + alfCovariance.E[b0][b1][k][l] = alfCovariance.E[b1][b0][l][k]; + } + } + } + } +} + +void EncAdaptiveLoopFilter::calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA_COEFF][1], const Pel *rec, const int stride, const AlfFilterShape& shape, int vbDistance) +{ + CHECK(shape.filterType != CC_ALF, "Bad CC ALF shape"); + + const Pel *recYM1 = rec - 1 * stride; + const Pel *recY0 = rec; + const Pel *recYP1 = rec + 1 * stride; + const Pel *recYP2 = rec + 2 * stride; + + if (vbDistance == -2 || vbDistance == +1) + { + recYP2 = recYP1; + } + else if (vbDistance == -1 || vbDistance == 0) + { + recYM1 = recY0; + recYP2 = recYP1 = recY0; + } + + for (int b = 0; b < 1; b++) + { + const Pel centerValue = recY0[+0]; + ELocal[0][b] += recYM1[+0] - centerValue; + ELocal[1][b] += recY0[-1] - centerValue; + ELocal[2][b] += recY0[+1] - centerValue; + ELocal[3][b] += recYP1[-1] - centerValue; + ELocal[4][b] += recYP1[+0] - centerValue; + ELocal[5][b] += recYP1[+1] - centerValue; + ELocal[6][b] += recYP2[+0] - centerValue; + } +} + +void EncAdaptiveLoopFilter::countLumaSwingGreaterThanThreshold(const Pel* luma, int lumaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* lumaSwingGreaterThanThresholdCount, int lumaCountStride) +{ + const int lumaBitDepth = m_inputBitDepth[CH_L]; + const int threshold = (1 << ( m_inputBitDepth[CH_L] - 2 )) - 1; + + // 3x4 Diamond + int xSupport[] = { 0, -1, 0, 1, -1, 0, 1, 0 }; + int ySupport[] = { -1, 0, 0, 0, 1, 1, 1, 2 }; + + for (int y = 0; y < height; y += (1 << log2BlockHeight)) + { + for (int x = 0; x < width; x += (1 << log2BlockWidth)) + { + lumaSwingGreaterThanThresholdCount[(y >> log2BlockHeight) * lumaCountStride + (x >> log2BlockWidth)] = 0; + + for (int yOff = 0; yOff < (1 << log2BlockHeight); yOff++) + { + for (int xOff = 0; xOff < (1 << log2BlockWidth); xOff++) + { + if ((y + yOff) >= (height - 2) || (x + xOff) >= (width - 1) || (y + yOff) < 1 || (x + xOff) < 1) // only consider samples that are fully supported by picture + { + continue; + } + + int minVal = ((1 << lumaBitDepth) - 1); + int maxVal = 0; + for (int i = 0; i < 8; i++) + { + Pel p = luma[(yOff + ySupport[i]) * lumaStride + x + xOff + xSupport[i]]; + + if ( p < minVal ) + { + minVal = p; + } + if ( p > maxVal ) + { + maxVal = p; + } + } + + if ((maxVal - minVal) > threshold) + { + lumaSwingGreaterThanThresholdCount[(y >> log2BlockHeight) * lumaCountStride + (x >> log2BlockWidth)]++; + } + } + } + } + luma += (lumaStride << log2BlockHeight); + } +} + +void EncAdaptiveLoopFilter::countChromaSampleValueNearMidPoint(const Pel* chroma, int chromaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* chromaSampleCountNearMidPoint, int chromaSampleCountNearMidPointStride) +{ + const int midPoint = (1 << m_inputBitDepth[CH_C]) >> 1; + const int threshold = 16; + + for (int y = 0; y < height; y += (1 << log2BlockHeight)) + { + for (int x = 0; x < width; x += (1 << log2BlockWidth)) + { + chromaSampleCountNearMidPoint[(y >> log2BlockHeight)* chromaSampleCountNearMidPointStride + (x >> log2BlockWidth)] = 0; + + for (int yOff = 0; yOff < (1 << log2BlockHeight); yOff++) + { + for (int xOff = 0; xOff < (1 << log2BlockWidth); xOff++) + { + if ((y + yOff) >= height || (x + xOff) >= width) + { + continue; + } + + int distanceToMidPoint = abs(chroma[yOff * chromaStride + x + xOff] - midPoint); + if (distanceToMidPoint < threshold) + { + chromaSampleCountNearMidPoint[(y >> log2BlockHeight)* chromaSampleCountNearMidPointStride + (x >> log2BlockWidth)]++; + } + } + } + } + chroma += (chromaStride << log2BlockHeight); + } +} +#endif diff --git a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h index d2ceb026fe13f0c41ea4a5ec403b568965120afb..5c620b053c1cb0eaa42b79c06d7b5674dda76e5e 100644 --- a/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h +++ b/source/Lib/EncoderLib/EncAdaptiveLoopFilter.h @@ -202,15 +202,24 @@ struct AlfCovariance double calculateError( const int *clip, const double *coeff ) const { return calculateError(clip, coeff, numCoeff); } double calculateError( const int *clip, const double *coeff, const int numCoeff ) const; double calcErrorForCoeffs( const int *clip, const int *coeff, const int numCoeff, const int bitDepth ) const; +#if JVET_Q0795_CCALF + double calcErrorForCcAlfCoeffs(const int* coeff, const int numCoeff, const int bitDepth) const; +#endif void getClipMax(const AlfFilterShape& alfShape, int *clip_max) const; void reduceClipCost(const AlfFilterShape& alfShape, int *clip) const; +#if JVET_Q0795_CCALF + int gnsSolveByChol( TE LHS, double* rhs, double *x, int numEq ) const; +#endif + private: // Cholesky decomposition int gnsSolveByChol( const int *clip, double *x, int numEq ) const; +#if !JVET_Q0795_CCALF int gnsSolveByChol( TE LHS, double* rhs, double *x, int numEq ) const; +#endif void gnsBacksubstitution( TE R, double* z, int size, double* A ) const; void gnsTransposeBacksubstitution( TE U, double* rhs, double* x, int order ) const; int gnsCholeskyDec( TE inpMatr, TE outMatr, int numEq ) const; @@ -231,6 +240,10 @@ private: uint8_t* m_ctuEnableFlagTmp[MAX_NUM_COMPONENT]; uint8_t* m_ctuEnableFlagTmp2[MAX_NUM_COMPONENT]; uint8_t* m_ctuAlternativeTmp[MAX_NUM_COMPONENT]; +#if JVET_Q0795_CCALF + AlfCovariance*** m_alfCovarianceCcAlf[2]; // [compIdx-1][shapeIdx][ctbAddr][filterIdx] + AlfCovariance** m_alfCovarianceFrameCcAlf[2]; // [compIdx-1][shapeIdx][filterIdx] +#endif //for RDO AlfParam m_alfParamTemp; @@ -255,6 +268,25 @@ private: int m_filterTmp[MAX_NUM_ALF_LUMA_COEFF]; int m_clipTmp[MAX_NUM_ALF_LUMA_COEFF]; +#if JVET_Q0795_CCALF + int m_apsIdCcAlfStart[2]; + + short m_bestFilterCoeffSet[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF]; + bool m_bestFilterIdxEnabled[MAX_NUM_CC_ALF_FILTERS]; + uint8_t m_bestFilterCount; + uint8_t* m_trainingCovControl; + Pel* m_bufOrigin; + PelBuf* m_buf; + uint64_t** m_unfilteredDistortion; // for different block size + uint64_t* m_trainingDistortion[MAX_NUM_CC_ALF_FILTERS]; // for current block size + uint64_t* m_lumaSwingGreaterThanThresholdCount; + uint64_t* m_chromaSampleCountNearMidPoint; + uint8_t* m_filterControl; // current iterations filter control + uint8_t* m_bestFilterControl; // best saved filter control + int m_reuseApsId[2]; + bool m_limitCcAlf; +#endif + public: EncAdaptiveLoopFilter( int& apsIdStart ); virtual ~EncAdaptiveLoopFilter() {} @@ -271,6 +303,9 @@ public: , const double lambdaChromaWeight #endif ); +#if JVET_Q0795_CCALF + int getNewCcAlfApsId(CodingStructure &cs, int cIdx); +#endif void initCABACEstimator( CABACEncoder* cabacEncoder, CtxCache* ctxCache, Slice* pcSlice, ParameterSetMap<APS>* apsMap ); void create( const EncCfg* encCfg, const int picWidth, const int picHeight, const ChromaFormat chromaFormatIDC, const int maxCUWidth, const int maxCUHeight, const int maxCUDepth, const int inputBitDepth[MAX_NUM_CHANNEL_TYPE], const int internalBitDepth[MAX_NUM_CHANNEL_TYPE] ); void destroy(); @@ -292,6 +327,14 @@ private: void deriveStatsForFiltering( PelUnitBuf& orgYuv, PelUnitBuf& recYuv, CodingStructure& cs ); void getBlkStats(AlfCovariance* alfCovariace, 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); void calcCovariance(int ELocal[MAX_NUM_ALF_LUMA_COEFF][MaxAlfNumClippingValues], const Pel *rec, const int stride, const AlfFilterShape& shape, const int transposeIdx, const ChannelType channel, int vbDistance); +#if JVET_Q0795_CCALF + void deriveStatsForCcAlfFiltering(const PelUnitBuf &orgYuv, const PelUnitBuf &recYuv, const int compIdx, + const int maskStride, const uint8_t filterIdc, CodingStructure &cs); + void getBlkStatsCcAlf(AlfCovariance &alfCovariance, const AlfFilterShape &shape, const PelUnitBuf &orgYuv, + const PelUnitBuf &recYuv, const UnitArea &areaDst, const UnitArea &area, + const ComponentID compID, const int yPos); + void calcCovarianceCcAlf(int ELocal[MAX_NUM_CC_ALF_CHROMA_COEFF][1], const Pel* rec, const int stride, const AlfFilterShape& shape, int vbDistance); +#endif 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]); @@ -305,6 +348,9 @@ private: #endif const int numClasses, const int numCoeff, double& distUnfilter ); void roundFiltCoeff( int *filterCoeffQuant, double *filterCoeff, const int numCoeff, const int factor ); +#if JVET_Q0795_CCALF + void roundFiltCoeffCCALF( int *filterCoeffQuant, double *filterCoeff, const int numCoeff, const int factor ); +#endif double getDistCoeffForce0( bool* codedVarBins, double errorForce0CoeffTab[MAX_NUM_ALF_CLASSES][2], int* bitsVarBin, int zeroBitsVarBin, const int numFilters); int lengthUvlc( int uiCode ); @@ -329,6 +375,28 @@ private: void setCtuAlternativeChroma( uint8_t* ctuAlts[MAX_NUM_COMPONENT], uint8_t val ); void copyCtuAlternativeChroma( uint8_t* ctuAltsDst[MAX_NUM_COMPONENT], uint8_t* ctuAltsSrc[MAX_NUM_COMPONENT] ); int getMaxNumAlternativesChroma( ); +#if JVET_Q0795_CCALF + int getCoeffRateCcAlf(short chromaCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], bool filterEnabled[MAX_NUM_CC_ALF_FILTERS], uint8_t filterCount, ComponentID compID); + void deriveCcAlfFilterCoeff( ComponentID compID, const PelUnitBuf& recYuv, const PelUnitBuf& recYuvExt, short filterCoeff[MAX_NUM_CC_ALF_FILTERS][MAX_NUM_CC_ALF_CHROMA_COEFF], const uint8_t filterIdx ); + void computeLog2BlockSizeDistortion(const Pel *org, int orgStride, const Pel *dec, int decStride, int height, + int width, uint64_t *distortionBuf, int distortionBufStride, int log2BlockWidth, + int log2BlockHeight, uint64_t &totalDistortion); + void determineControlIdcValues(CodingStructure &cs, const ComponentID compID, const PelBuf *buf, const int ctuWidthC, + const int ctuHeightC, const int picWidthC, const int picHeightC, + uint64_t **unfilteredDistortion, uint64_t *trainingDistortion[MAX_NUM_CC_ALF_FILTERS], + uint64_t *lumaSwingGreaterThanThresholdCount, + uint64_t *chromaSampleCountNearMidPoint, + bool reuseFilterCoeff, uint8_t *trainingCovControl, uint8_t *filterControl, + uint64_t &curTotalDistortion, double &curTotalRate, + bool filterEnabled[MAX_NUM_CC_ALF_FILTERS], + uint8_t mapFilterIdxToFilterIdc[MAX_NUM_CC_ALF_FILTERS + 1], + uint8_t &ccAlfFilterCount); + void deriveCcAlfFilter( CodingStructure& cs, ComponentID compID, const PelUnitBuf& orgYuv, const PelUnitBuf& tempDecYuvBuf, const PelUnitBuf& dstYuv ); + std::vector<int> getAvailableCcAlfApsIds(CodingStructure& cs, ComponentID compID); + void xSetupCcAlfAPS( CodingStructure& cs ); + void countLumaSwingGreaterThanThreshold(const Pel* luma, int lumaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* lumaSwingGreaterThanThresholdCount, int lumaCountStride); + void countChromaSampleValueNearMidPoint(const Pel* chroma, int chromaStride, int height, int width, int log2BlockWidth, int log2BlockHeight, uint64_t* chromaSampleCountNearMidPoint, int chromaSampleCountNearMidPointStride); +#endif }; diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index f27bb3c1001942819569517a46d851507e6be885..077dfd54ff71be8acebd5a47bca935b8d49e31fa 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -171,6 +171,9 @@ protected: bool m_noPartitionConstraintsOverrideConstraintFlag; bool m_bNoSaoConstraintFlag; bool m_bNoAlfConstraintFlag; +#if JVET_Q0795_CCALF + bool m_noCCAlfConstraintFlag; +#endif bool m_bNoRefWraparoundConstraintFlag; bool m_bNoTemporalMvpConstraintFlag; bool m_bNoSbtmvpConstraintFlag; @@ -238,6 +241,9 @@ protected: int m_aiPad[2]; bool m_AccessUnitDelimiter; ///< add Access Unit Delimiter NAL units +#if JVET_Q0775_PH_IN_SH + bool m_enablePictureHeaderInSliceHeader; ///< Enable Picture Header in Slice Header +#endif int m_iMaxRefPicNum; ///< this is used to mimic the sliding mechanism used by the decoder // TODO: We need to have a common sliding mechanism used by both the encoder and decoder @@ -592,6 +598,9 @@ protected: bool m_useWeightedPred; //< Use of Weighting Prediction (P_SLICE) bool m_useWeightedBiPred; //< Use of Bi-directional Weighting Prediction (B_SLICE) WeightedPredictionMethod m_weightedPredictionMethod; +#if JVET_Q0297_MER + uint32_t m_log2ParallelMergeLevelMinus2; ///< Parallel merge estimation region +#endif uint32_t m_maxNumMergeCand; ///< Maximum number of merge candidates uint32_t m_maxNumAffineMergeCand; ///< Maximum number of affine merge candidates uint32_t m_maxNumTriangleCand; @@ -683,6 +692,10 @@ protected: #endif bool m_alf; ///< Adaptive Loop Filter +#if JVET_Q0795_CCALF + bool m_ccalf; + int m_ccalfQpThreshold; +#endif #if JVET_O0756_CALCULATE_HDRMETRICS double m_whitePointDeltaE[hdrtoolslib::NB_REF_WHITE]; double m_maxSampleValue; @@ -732,6 +745,10 @@ public: void setNoSaoConstraintFlag(bool bVal) { m_bNoSaoConstraintFlag = bVal; } bool getNoAlfConstraintFlag() const { return m_bNoAlfConstraintFlag; } void setNoAlfConstraintFlag(bool bVal) { m_bNoAlfConstraintFlag = bVal; } +#if JVET_Q0795_CCALF + bool getNoCCAlfConstraintFlag() const { return m_noCCAlfConstraintFlag; } + void setNoCCAlfConstraintFlag(bool bVal) { m_noCCAlfConstraintFlag = bVal; } +#endif bool getNoRefWraparoundConstraintFlag() const { return m_bNoRefWraparoundConstraintFlag; } void setNoRefWraparoundConstraintFlag(bool bVal) { m_bNoRefWraparoundConstraintFlag = bVal; } bool getNoTemporalMvpConstraintFlag() const { return m_bNoTemporalMvpConstraintFlag; } @@ -1183,6 +1200,10 @@ public: bool getAccessUnitDelimiter() const { return m_AccessUnitDelimiter; } void setAccessUnitDelimiter(bool val){ m_AccessUnitDelimiter = val; } +#if JVET_Q0775_PH_IN_SH + bool getEnablePictureHeaderInSliceHeader() const { return m_enablePictureHeaderInSliceHeader; } + void setEnablePictureHeaderInSliceHeader(bool val) { m_enablePictureHeaderInSliceHeader = val; } +#endif //==== Loop/Deblock Filter ======== bool getLoopFilterDisable () { return m_bLoopFilterDisable; } @@ -1581,6 +1602,10 @@ public: void setWPBiPred ( bool b ) { m_useWeightedBiPred = b; } bool getUseWP () { return m_useWeightedPred; } bool getWPBiPred () { return m_useWeightedBiPred; } +#if JVET_Q0297_MER + void setLog2ParallelMergeLevelMinus2(uint32_t u) { m_log2ParallelMergeLevelMinus2 = u; } + uint32_t getLog2ParallelMergeLevelMinus2() { return m_log2ParallelMergeLevelMinus2; } +#endif void setMaxNumMergeCand ( uint32_t u ) { m_maxNumMergeCand = u; } uint32_t getMaxNumMergeCand () { return m_maxNumMergeCand; } void setMaxNumAffineMergeCand ( uint32_t u ) { m_maxNumAffineMergeCand = u; } @@ -1770,7 +1795,12 @@ public: #endif void setUseALF( bool b ) { m_alf = b; } bool getUseALF() const { return m_alf; } - +#if JVET_Q0795_CCALF + void setUseCCALF( bool b ) { m_ccalf = b; } + bool getUseCCALF() const { return m_ccalf; } + void setCCALFQpThreshold( int b ) { m_ccalfQpThreshold = b; } + int getCCALFQpThreshold() const { return m_ccalfQpThreshold; } +#endif #if JVET_O0756_CALCULATE_HDRMETRICS void setWhitePointDeltaE( uint32_t index, double value ) { m_whitePointDeltaE[ index ] = value; } double getWhitePointDeltaE( uint32_t index ) const { return m_whitePointDeltaE[ index ]; } diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 664375b9067a73c1ed886417616ec5762d6b9fd7..e33e976488c070a10814dff2fac039994f5890c7 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -800,7 +800,12 @@ void EncCu::xCompressCU( CodingStructure*& tempCS, CodingStructure*& bestCS, Par { bool skipSecColorSpace = false; skipSecColorSpace = xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? true : false)); - +#if JVET_Q0820_ACT + if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) && !m_pcEncCfg->getRGBFormatFlag()) + { + skipSecColorSpace = true; + } +#endif if (!skipSecColorSpace && !tempCS->firstColorSpaceTestOnly) { xCheckRDCostIntra(tempCS, bestCS, partitioner, currTestMode, (m_pcEncCfg->getRGBFormatFlag() ? false : true)); diff --git a/source/Lib/EncoderLib/EncGOP.cpp b/source/Lib/EncoderLib/EncGOP.cpp index 797cd27d26f593d816aa52b7335783dac66d3d05..7e0843829922394be2b7228cf2ba7c13d87e5310 100644 --- a/source/Lib/EncoderLib/EncGOP.cpp +++ b/source/Lib/EncoderLib/EncGOP.cpp @@ -401,7 +401,11 @@ int EncGOP::xWritePicHeader( AccessUnit &accessUnit, PicHeader *picHeader ) m_HLSWriter->setBitstream( &nalu.m_Bitstream ); nalu.m_temporalId = accessUnit.temporalId; nalu.m_nuhLayerId = m_pcEncLib->getLayerId(); +#if JVET_Q0775_PH_IN_SH + m_HLSWriter->codePictureHeader( picHeader, true ); +#else m_HLSWriter->codePictureHeader( picHeader ); +#endif accessUnit.push_back(new NALUnitEBSP(nalu)); return (int)(accessUnit.back()->m_nalUnitData.str().size()) * 8; } @@ -2790,7 +2794,9 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, m_pcLoopFilter->loopFilterPic( cs ); CS::setRefinedMotionField(cs); +#if !JVET_Q0795_CCALF DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) ); +#endif if( pcSlice->getSPS()->getSAOEnabledFlag() ) { @@ -2844,8 +2850,15 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, } pcPic->slices[s]->setAlfAPSs(cs.slice->getAlfAPSs()); pcPic->slices[s]->setTileGroupApsIdChroma(cs.slice->getTileGroupApsIdChroma()); +#if JVET_Q0795_CCALF + pcPic->slices[s]->setTileGroupCcAlfCbApsId(cs.slice->getTileGroupCcAlfCbApsId()); + pcPic->slices[s]->setTileGroupCcAlfCrApsId(cs.slice->getTileGroupCcAlfCrApsId()); +#endif } } +#if JVET_Q0795_CCALF + DTRACE_UPDATE( g_trace_ctx, ( std::make_pair( "final", 1 ) ) ); +#endif if (m_pcCfg->getUseCompositeRef() && getPrepareLTRef()) { updateCompositeReference(pcSlice, rcListPic, pocCurr); @@ -2951,7 +2964,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, } } +#if JVET_Q0795_CCALF + if (pcSlice->getSPS()->getALFEnabledFlag() && (pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y) || pcSlice->getTileGroupCcAlfCbEnabledFlag() || pcSlice->getTileGroupCcAlfCrEnabledFlag())) +#else if (pcSlice->getSPS()->getALFEnabledFlag() && pcSlice->getTileGroupAlfEnabledFlag(COMPONENT_Y)) +#endif { for (int apsId = 0; apsId < ALF_CTB_MAX_NUM_APS; apsId++) { @@ -2966,12 +2983,28 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, *apsMap->allocatePS(apsId) = *aps; //allocate and cpy m_pcALF->setApsIdStart( apsId ); } +#if JVET_Q0795_CCALF + else if (pcSlice->getTileGroupCcAlfCbEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCbApsId()) + { + writeAPS = true; + aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCbApsId() << NUM_APS_TYPE_LEN) + ALF_APS); + } + else if (pcSlice->getTileGroupCcAlfCrEnabledFlag() && !aps && apsId == pcSlice->getTileGroupCcAlfCrApsId()) + { + writeAPS = true; + aps = apsMap->getPS((pcSlice->getTileGroupCcAlfCrApsId() << NUM_APS_TYPE_LEN) + ALF_APS); + } +#endif if (writeAPS ) { actualTotalBits += xWriteAPS( accessUnit, aps, m_pcEncLib->getLayerId(), true ); apsMap->clearChangedFlag((apsId << NUM_APS_TYPE_LEN) + ALF_APS); +#if JVET_Q0795_CCALF + CHECK(aps != pcSlice->getAlfAPSs()[apsId] && apsId != pcSlice->getTileGroupCcAlfCbApsId() && apsId != pcSlice->getTileGroupCcAlfCrApsId(), "Wrong APS pointer in compressGOP"); +#else CHECK(aps != pcSlice->getAlfAPSs()[apsId], "Wrong APS pointer in compressGOP"); +#endif } } } @@ -3069,6 +3102,12 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, picHeader->setNumAlfAps(pcSlice->getTileGroupNumAps()); picHeader->setAlfAPSs(pcSlice->getTileGroupApsIdLuma()); picHeader->setAlfApsIdChroma(pcSlice->getTileGroupApsIdChroma()); +#if JVET_Q0795_CCALF + picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, pcSlice->getTileGroupCcAlfCbEnabledFlag()); + picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, pcSlice->getTileGroupCcAlfCrEnabledFlag()); + picHeader->setCcAlfCbApsId(pcSlice->getTileGroupCcAlfCbApsId()); + picHeader->setCcAlfCrApsId(pcSlice->getTileGroupCcAlfCrApsId()); +#endif } else { picHeader->setAlfEnabledPresentFlag( false ); @@ -3076,7 +3115,19 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, pcPic->cs->picHeader->setPic(pcPic); pcPic->cs->picHeader->setValid(); +#if JVET_Q0775_PH_IN_SH + if (pcPic->cs->pps->getNumSlicesInPic() > 1 || m_pcCfg->getEnablePictureHeaderInSliceHeader()) + { + pcSlice->setPictureHeaderInSliceHeader(false); + actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader); + } + else + { + pcSlice->setPictureHeaderInSliceHeader(true); + } +#else actualTotalBits += xWritePicHeader(accessUnit, pcPic->cs->picHeader); +#endif } pcSlice->setPicHeader( pcPic->cs->picHeader ); @@ -3091,6 +3142,11 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic, tmpBitsBeforeWriting = m_HLSWriter->getNumberOfWrittenBits(); +#if JVET_Q0795_CCALF + pcSlice->m_ccAlfFilterParam = m_pcALF->getCcAlfFilterParam(); + pcSlice->m_ccAlfFilterControl[0] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cb); + pcSlice->m_ccAlfFilterControl[1] = m_pcALF->getCcAlfControlIdc(COMPONENT_Cr); +#endif m_HLSWriter->codeSliceHeader( pcSlice ); actualHeadBits += ( m_HLSWriter->getNumberOfWrittenBits() - tmpBitsBeforeWriting ); diff --git a/source/Lib/EncoderLib/EncLib.cpp b/source/Lib/EncoderLib/EncLib.cpp index 3eb5c084637d789d323407f37aee8067091a4c43..ce012c6701bde75ce6c7dc2dfcf4b7072f6b3ed8 100644 --- a/source/Lib/EncoderLib/EncLib.cpp +++ b/source/Lib/EncoderLib/EncLib.cpp @@ -976,6 +976,9 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps ) cinfo->setNoPartitionConstraintsOverrideConstraintFlag(m_noPartitionConstraintsOverrideConstraintFlag); cinfo->setNoSaoConstraintFlag(m_bNoSaoConstraintFlag); cinfo->setNoAlfConstraintFlag(m_bNoAlfConstraintFlag); +#if JVET_Q0795_CCALF + cinfo->setNoCCAlfConstraintFlag(m_noCCAlfConstraintFlag); +#endif cinfo->setNoRefWraparoundConstraintFlag(m_bNoRefWraparoundConstraintFlag); cinfo->setNoTemporalMvpConstraintFlag(m_bNoTemporalMvpConstraintFlag); cinfo->setNoSbtmvpConstraintFlag(m_bNoSbtmvpConstraintFlag); @@ -1146,6 +1149,9 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps ) sps.setScalingListFlag ( (m_useScalingListId == SCALING_LIST_OFF) ? 0 : 1 ); sps.setALFEnabledFlag( m_alf ); +#if JVET_Q0795_CCALF + sps.setCCALFEnabledFlag( m_ccalf ); +#endif sps.setVuiParametersPresentFlag(getVuiParametersPresentFlag()); if (sps.getVuiParametersPresentFlag()) @@ -1260,6 +1266,10 @@ void EncLib::xInitSPS( SPS& sps, VPS& vps ) } sps.setRprEnabledFlag( m_rprEnabled || sps.getInterLayerPresentFlag() ); + +#if JVET_Q0297_MER + sps.setLog2ParallelMergeLevelMinus2( m_log2ParallelMergeLevelMinus2 ); +#endif } void EncLib::xInitHrdParameters(SPS &sps) diff --git a/source/Lib/EncoderLib/EncLib.h b/source/Lib/EncoderLib/EncLib.h index f9b13233e597e85169e374573f23fea701a2e419..2a6d82cadb4c0b1e17ffda28b8bb323dfb2b0925 100644 --- a/source/Lib/EncoderLib/EncLib.h +++ b/source/Lib/EncoderLib/EncLib.h @@ -159,6 +159,9 @@ public: SPS* getSPS( int spsId ) { return m_spsMap.getPS( spsId ); }; APS** getApss() { return m_apss; } Ctx m_entropyCodingSyncContextState; ///< leave in addition to vector for compatibility +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + PLTBuf m_palettePredictorSyncState; +#endif protected: void xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Picture*& rpcPic, int ppsId ); ///< get picture buffer which will be processed. If ppsId<0, then the ppsMap will be queried for the first match. diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 922835d58ac9ce7643923b6436c7b5e87d726262..833986d556bfcc41d0d55384bb98477efd857666 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -1830,6 +1830,20 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt } if( split == CU_QUAD_SPLIT ) cuECtx.set( DID_QUAD_SPLIT, true ); +#if JVET_Q0297_MER + if (cs.sps->getLog2ParallelMergeLevelMinus2()) + { + const CompArea& area = partitioner.currArea().Y(); + const SizeType size = 1 << (cs.sps->getLog2ParallelMergeLevelMinus2() + 2); + if (!cs.slice->isIntra() && (area.width > size || area.height > size)) + { + if (area.height <= size && split == CU_HORZ_SPLIT) return false; + if (area.width <= size && split == CU_VERT_SPLIT) return false; + if (area.height <= 2 * size && split == CU_TRIH_SPLIT) return false; + if (area.width <= 2 * size && split == CU_TRIV_SPLIT) return false; + } + } +#endif return true; } else diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index ab194d148c76b8c169a871d9d2cf7335eb4fe844..8e54f7b2873ad0e0d612c07b72eb13a36786a869 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1444,6 +1444,9 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons { // Top is available, we use it. pCABACWriter->getCtx() = pEncLib->m_entropyCodingSyncContextState; +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + cs.setPrevPLT(pEncLib->m_palettePredictorSyncState); +#endif } prevQP[0] = prevQP[1] = pcSlice->getSliceQp(); } @@ -1566,6 +1569,9 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons if( cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && pEncLib->getEntropyCodingSyncEnabledFlag() ) { pEncLib->m_entropyCodingSyncContextState = pCABACWriter->getCtx(); +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + cs.storePrevPLT(pEncLib->m_palettePredictorSyncState); +#endif } int actualBits = int(cs.fracBits >> SCALE_BITS); @@ -1683,6 +1689,9 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui { // Top is available, so use it. m_CABACWriter->getCtx() = m_entropyCodingSyncContextState; +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + cs.setPrevPLT(m_palettePredictorSyncState); +#endif } } @@ -1698,6 +1707,9 @@ void EncSlice::encodeSlice ( Picture* pcPic, OutputBitstream* pcSubstreams, ui if( cs.pps->ctuIsTileColBd( ctuXPosInCtus ) && wavefrontsEnabled ) { m_entropyCodingSyncContextState = m_CABACWriter->getCtx(); +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + cs.storePrevPLT(m_palettePredictorSyncState); +#endif } // terminate the sub-stream, if required (end of slice-segment, end of tile, end of wavefront-CTU-row): diff --git a/source/Lib/EncoderLib/EncSlice.h b/source/Lib/EncoderLib/EncSlice.h index ed88068075c5a87db40fb86e6750f62e394f6937..6c633aa055bdf8f82315e8157820725cf9b059c0 100644 --- a/source/Lib/EncoderLib/EncSlice.h +++ b/source/Lib/EncoderLib/EncSlice.h @@ -92,6 +92,9 @@ private: uint32_t m_uiSliceSegmentIdx; Ctx m_entropyCodingSyncContextState; ///< context storage for state of contexts at the wavefront/WPP/entropy-coding-sync second CTU of tile-row SliceType m_encCABACTableIdx; +#if JVET_Q0501_PALETTE_WPP_INIT_ABOVECTU + PLTBuf m_palettePredictorSyncState; +#endif #if SHARP_LUMA_DELTA_QP || ENABLE_QPA_SUB_CTU int m_gopID; #endif diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index ff5ae6e104bb6162beec220bde5f07cba0b431e6..5cb2192760e3cbd490b12f46305f48ab6c66c381 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -6548,8 +6548,19 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par uint8_t nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests std::vector<TrMode> trModes; +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) + { + nNumTransformCands = 0; + } + else + { +#endif trModes.push_back( TrMode( 0, true ) ); //DCT2 nNumTransformCands = 1; +#if JVET_Q0820_ACT + } +#endif //for a SBT-no-residual TU, the RDO process should be called once, in order to get the RD cost if( tsAllowed && !tu.noResidual ) { @@ -6579,7 +6590,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } } +#if JVET_Q0820_ACT + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#else if (colorTransFlag) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(true); m_pcRdCost->lambdaAdjustColorTrans(true, compID); @@ -6587,15 +6602,19 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par const int crossCPredictionModesToTest = preCalcAlpha != 0 ? 2 : 1; const int numTransformCandidates = nNumTransformCands; +#if !JVET_Q0695_CHROMA_TS_JCCR const bool isOneMode = crossCPredictionModesToTest == 1 && numTransformCandidates == 1; bool isLastBest = isOneMode; +#endif for( int transformMode = 0; transformMode < numTransformCandidates; transformMode++ ) { for( int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++ ) { const bool isFirstMode = transformMode == 0 && crossCPredictionModeId == 0; +#if !JVET_Q0695_CHROMA_TS_JCCR const bool isLastMode = ( transformMode + 1 ) == numTransformCandidates && ( crossCPredictionModeId + 1 ) == crossCPredictionModesToTest; +#endif const bool bUseCrossCPrediction = crossCPredictionModeId != 0; // copy the original residual into the residual buffer @@ -6625,6 +6644,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par tu.compAlpha[compID] = bUseCrossCPrediction ? preCalcAlpha : 0; QpParam cQP(tu, compID); // note: uses tu.transformSkip[compID] +#if !JVET_Q0820_ACT if (colorTransFlag) { for (int qpIdx = 0; qpIdx < 2; qpIdx++) @@ -6634,6 +6654,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6; } } +#endif #if RDOQ_CHROMA_LAMBDA m_pcTrQuant->selectLambda(compID); @@ -6853,13 +6874,17 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } } +#if !JVET_Q0695_CHROMA_TS_JCCR if( !isLastMode || (compID != COMPONENT_Y && !tu.noResidual) ) { +#endif bestTU.copyComponentFrom( tu, compID ); saveCS.getResiBuf( compArea ).copyFrom( csFull->getResiBuf( compArea ) ); +#if !JVET_Q0695_CHROMA_TS_JCCR } isLastBest = isLastMode; +#endif } if( tu.noResidual ) { @@ -6868,14 +6893,22 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } } +#if !JVET_Q0695_CHROMA_TS_JCCR if( !isLastBest ) { +#endif // copy component tu.copyComponentFrom( bestTU, compID ); csFull->getResiBuf( compArea ).copyFrom( saveCS.getResiBuf( compArea ) ); +#if !JVET_Q0695_CHROMA_TS_JCCR } +#endif +#if JVET_Q0820_ACT + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#else if (colorTransFlag) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(false); m_pcRdCost->lambdaAdjustColorTrans(false, compID); @@ -6887,7 +6920,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { PelUnitBuf orgResidual = orgResi->subBuf(relativeUnitArea); PelUnitBuf invColorTransResidual = m_colorTransResiBuf[2].getBuf(relativeUnitArea); +#if JVET_Q0820_ACT + csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false, slice.clpRng(COMPONENT_Y)); +#else csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false); +#endif for (uint32_t c = 0; c < numTBlocks; c++) { @@ -6902,6 +6939,15 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par const CompArea& cbArea = tu.blocks[COMPONENT_Cb]; const CompArea& crArea = tu.blocks[COMPONENT_Cr]; bool checkJointCbCr = (sps.getJointCbCrEnabledFlag()) && (!tu.noResidual) && (TU::getCbf(tu, COMPONENT_Cb) || TU::getCbf(tu, COMPONENT_Cr)); +#if JVET_Q0695_CHROMA_TS_JCCR + bool checkDCTOnly = (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && !TU::getCbf(tu, COMPONENT_Cr)) || + (TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2 && !TU::getCbf(tu, COMPONENT_Cb)) || + (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2); + + bool checkTSOnly = (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_SKIP && !TU::getCbf(tu, COMPONENT_Cr)) || + (TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_SKIP && !TU::getCbf(tu, COMPONENT_Cb)) || + (TU::getCbf(tu, COMPONENT_Cb) && tu.mtsIdx[COMPONENT_Cb] == MTS_SKIP && TU::getCbf(tu, COMPONENT_Cr) && tu.mtsIdx[COMPONENT_Cr] == MTS_SKIP); +#endif const int channelBitDepth = sps.getBitDepth(toChannelType(COMPONENT_Cb)); bool reshape = slice.getPicHeader()->getLmcsEnabledFlag() && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && tu.blocks[COMPONENT_Cb].width * tu.blocks[COMPONENT_Cb].height > 4; @@ -6910,7 +6956,9 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { minCostCbCr += minCost[COMPONENT_Y]; // ACT should consider three-component cost } +#if !JVET_Q0695_CHROMA_TS_JCCR bool isLastBest = false; +#endif CompStorage orgResiCb[4], orgResiCr[4]; // 0:std, 1-3:jointCbCr std::vector<int> jointCbfMasksToTest; @@ -6930,6 +6978,38 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par for (int cbfMask: jointCbfMasksToTest) { +#if JVET_Q0695_CHROMA_TS_JCCR + ComponentID codeCompId = (cbfMask >> 1 ? COMPONENT_Cb : COMPONENT_Cr); + ComponentID otherCompId = (codeCompId == COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr); + bool tsAllowed = TU::isTSAllowed(tu, codeCompId) && (m_pcEncCfg->getUseChromaTS()); + uint8_t numTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests + bool cbfDCT2 = true; + + std::vector<TrMode> trModes; + if (checkDCTOnly || checkTSOnly) + { + numTransformCands = 1; + } + + if (!checkTSOnly) + { + trModes.push_back(TrMode(0, true)); // DCT2 + } + if (tsAllowed && !checkDCTOnly) + { + trModes.push_back(TrMode(1, true));//TS + } + for (int modeId = 0; modeId < numTransformCands; modeId++) + { + if (modeId && !cbfDCT2) + { + continue; + } + if (!trModes[modeId].second) + { + continue; + } +#endif TCoeff currAbsSum = 0; uint64_t currCompFracBits = 0; Distortion currCompDistCb = 0; @@ -6939,12 +7019,23 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par tu.jointCbCr = (uint8_t) cbfMask; tu.compAlpha[COMPONENT_Cb] = tu.compAlpha[COMPONENT_Cr] = 0; // encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode. +#if JVET_Q0695_CHROMA_TS_JCCR + tu.mtsIdx[codeCompId] = trModes[modeId].first; + tu.mtsIdx[otherCompId] = MTS_DCT2_DCT2; +#else tu.mtsIdx[COMPONENT_Cb] = tu.mtsIdx[COMPONENT_Cr] = MTS_DCT2_DCT2; +#endif int codedCbfMask = 0; +#if !JVET_Q0695_CHROMA_TS_JCCR ComponentID codeCompId = (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr); ComponentID otherCompId = (codeCompId == COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr); +#endif +#if JVET_Q0820_ACT + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#else if (colorTransFlag) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(true); m_pcTrQuant->selectLambda(codeCompId); @@ -6978,6 +7069,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par Distortion currCompDistY = MAX_UINT64; QpParam qpCbCr(tu, codeCompId); +#if !JVET_Q0820_ACT if (colorTransFlag) { for (int qpIdx = 0; qpIdx < 2; qpIdx++) @@ -6987,12 +7079,26 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par qpCbCr.rems[qpIdx] = qpCbCr.Qps[qpIdx] % 6; } } +#endif tu.getCoeffs(otherCompId).fill(0); // do we need that? TU::setCbfAtDepth(tu, otherCompId, tu.depth, false); PelBuf &codeResi = (codeCompId == COMPONENT_Cr ? crResi : cbResi); TCoeff compAbsSum = 0; +#if JVET_Q0695_CHROMA_TS_JCCR + if (numTransformCands > 1) + { + if (modeId == 0) + { + m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, &trModes, m_pcEncCfg->getMTSInterMaxCand()); + tu.mtsIdx[codeCompId] = trModes[modeId].first; + tu.mtsIdx[otherCompId] = MTS_DCT2_DCT2; + } + m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, compAbsSum, m_CABACEstimator->getCtx(), true); + } + else +#endif m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, compAbsSum, m_CABACEstimator->getCtx()); if (compAbsSum > 0) { @@ -7015,6 +7121,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } currAbsSum = codedCbfMask; +#if JVET_Q0695_CHROMA_TS_JCCR + if (!tu.mtsIdx[codeCompId]) + { + cbfDCT2 = (currAbsSum > 0); + } +#endif if (currAbsSum > 0) { m_CABACEstimator->cbf_comp(cs, codedCbfMask >> 1, cbArea, currDepth, false); @@ -7037,7 +7149,11 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par { PelUnitBuf orgResidual = orgResi->subBuf(relativeUnitArea); PelUnitBuf invColorTransResidual = m_colorTransResiBuf[2].getBuf(relativeUnitArea); +#if JVET_Q0820_ACT + csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false, slice.clpRng(COMPONENT_Y)); +#else csFull->getResiBuf(currArea).colorSpaceConvert(invColorTransResidual, false); +#endif currCompDistY = m_pcRdCost->getDistPart(orgResidual.bufs[COMPONENT_Y], invColorTransResidual.bufs[COMPONENT_Y], sps.getBitDepth(toChannelType(COMPONENT_Y)), COMPONENT_Y, DF_SSE); currCompDistCb = m_pcRdCost->getDistPart(orgResidual.bufs[COMPONENT_Cb], invColorTransResidual.bufs[COMPONENT_Cb], sps.getBitDepth(toChannelType(COMPONENT_Cb)), COMPONENT_Cb, DF_SSE); @@ -7070,8 +7186,10 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par uiSingleDistComp[COMPONENT_Y] = currCompDistY; } minCostCbCr = currCompCost; +#if !JVET_Q0695_CHROMA_TS_JCCR isLastBest = (cbfMask == jointCbfMasksToTest.back()); if (!isLastBest) +#endif { bestTU.copyComponentFrom(tu, COMPONENT_Cb); bestTU.copyComponentFrom(tu, COMPONENT_Cr); @@ -7080,6 +7198,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par } } +#if !JVET_Q0695_CHROMA_TS_JCCR if( !isLastBest ) { // copy component @@ -7088,11 +7207,27 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par csFull->getResiBuf( cbArea ).copyFrom( saveCS.getResiBuf( cbArea ) ); csFull->getResiBuf( crArea ).copyFrom( saveCS.getResiBuf( crArea ) ); } +#endif + +#if JVET_Q0820_ACT + if (colorTransFlag && (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING)) +#else if (colorTransFlag) +#endif { m_pcTrQuant->lambdaAdjustColorTrans(false); } +#if JVET_Q0695_CHROMA_TS_JCCR + } +#endif } +#if JVET_Q0695_CHROMA_TS_JCCR + // copy component + tu.copyComponentFrom(bestTU, COMPONENT_Cb); + tu.copyComponentFrom(bestTU, COMPONENT_Cr); + csFull->getResiBuf(cbArea).copyFrom(saveCS.getResiBuf(cbArea)); + csFull->getResiBuf(crArea).copyFrom(saveCS.getResiBuf(crArea)); +#endif } m_CABACEstimator->getCtx() = ctxStart; @@ -7393,7 +7528,11 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa orgResidual.copyFrom(cs.getResiBuf()); if (colorTransAllowed) { +#if JVET_Q0820_ACT + cs.getResiBuf().colorSpaceConvert(colorTransResidual, true, cu.cs->slice->clpRng(COMPONENT_Y)); +#else cs.getResiBuf().colorSpaceConvert(colorTransResidual, true); +#endif } const TempCtx ctxStart(m_CtxCache, m_CABACEstimator->getCtx()); @@ -7549,7 +7688,11 @@ void InterSearch::encodeResAndCalcRdInterCU(CodingStructure &cs, Partitioner &pa bestIter = iter; if (cu.rootCbf && cu.colorTransform) { +#if JVET_Q0820_ACT + cs.getResiBuf(curUnitArea).colorSpaceConvert(cs.getResiBuf(curUnitArea), false, cu.cs->slice->clpRng(COMPONENT_Y)); +#else cs.getResiBuf(curUnitArea).colorSpaceConvert(cs.getResiBuf(curUnitArea), false); +#endif } if (iter != (numAllowedColorSpace - 1)) diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index dd6f112b301ba4d98a1f72878fa01b6266bbf721..5ee8d0ee19ec6d5b677ef1ebf56d425d22c76f58 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -2784,7 +2784,11 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp CHECK( tu.jointCbCr && compID == COMPONENT_Cr, "wrong combination of compID and jointCbCr" ); bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb; +#if JVET_Q0695_CHROMA_TS_JCCR || JVET_Q0820_ACT + if (compID == COMPONENT_Y) +#else if (compID == COMPONENT_Y || (isChroma(compID) && tu.cu->bdpcmModeChroma)) +#endif { PelBuf sharedPredTS( m_pSharedPredTransformSkip[compID], area ); if( default0Save1Load2 != 2 ) @@ -2989,8 +2993,17 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp if (trModes) { +#if JVET_Q0695_CHROMA_TS_JCCR + m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand()); + tu.mtsIdx[codeCompId] = trModes->at(0).first; + if (tu.jointCbCr) + { + tu.mtsIdx[(codeCompId == COMPONENT_Cr) ? COMPONENT_Cb : COMPONENT_Cr] = MTS_DCT2_DCT2; + } +#else m_pcTrQuant->transformNxN(tu, compID, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand()); tu.mtsIdx[compID] = trModes->at(0).first; +#endif } // encoder bugfix: Set loadTr to aovid redundant transform process #if JVET_AHG14_LOSSLESS @@ -3132,6 +3145,9 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c m_pcRdCost->setChromaFormat(cs.sps->getChromaFormatIdc()); +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcTrQuant->lambdaAdjustColorTrans(true); if (jointCbCr) @@ -3167,19 +3183,32 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c if (isLuma(compID)) { QpParam cQP(tu, compID); +#if !JVET_Q0820_ACT for (int qpIdx = 0; qpIdx < 2; qpIdx++) { cQP.Qps[qpIdx] = cQP.Qps[qpIdx] + (compID == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg); cQP.pers[qpIdx] = cQP.Qps[qpIdx] / 6; cQP.rems[qpIdx] = cQP.Qps[qpIdx] % 6; } +#endif if (trModes) { m_pcTrQuant->transformNxN(tu, compID, cQP, trModes, m_pcEncCfg->getMTSIntraMaxCand()); tu.mtsIdx[compID] = trModes->at(0).first; } +#if JVET_Q0820_ACT + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) || tu.cu->bdpcmMode != 0) +#endif m_pcTrQuant->transformNxN(tu, compID, cQP, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); +#if JVET_Q0820_ACT + if ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[compID] == 0) && tu.cu->bdpcmMode == 0) + { + uiAbsSum = 0; + tu.getCoeffs(compID).fill(0); + TU::setCbfAtDepth(tu, compID, tu.depth, 0); + } +#endif if (uiAbsSum > 0) { @@ -3195,12 +3224,14 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c int codedCbfMask = 0; ComponentID codeCompId = (tu.jointCbCr ? (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr) : compID); QpParam qpCbCr(tu, codeCompId); +#if !JVET_Q0820_ACT for (int qpIdx = 0; qpIdx < 2; qpIdx++) { qpCbCr.Qps[qpIdx] = qpCbCr.Qps[qpIdx] + (codeCompId == COMPONENT_Cr ? DELTA_QP_FOR_Co : DELTA_QP_FOR_Y_Cg); qpCbCr.pers[qpIdx] = qpCbCr.Qps[qpIdx] / 6; qpCbCr.rems[qpIdx] = qpCbCr.Qps[qpIdx] % 6; } +#endif if (tu.jointCbCr) { @@ -3211,7 +3242,23 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c PelBuf& codeResi = (codeCompId == COMPONENT_Cr ? crResi : piResi); uiAbsSum = 0; +#if JVET_Q0820_ACT + if (trModes) + { + m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, trModes, m_pcEncCfg->getMTSIntraMaxCand()); + tu.mtsIdx[codeCompId] = trModes->at(0).first; + if (tu.jointCbCr) + { + tu.mtsIdx[(codeCompId == COMPONENT_Cr) ? COMPONENT_Cb : COMPONENT_Cr] = MTS_DCT2_DCT2; + } + } + if (!(m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING && tu.mtsIdx[codeCompId] == 0) || tu.cu->bdpcmModeChroma != 0) + { + m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx(), loadTr); + } +#else m_pcTrQuant->transformNxN(tu, codeCompId, qpCbCr, uiAbsSum, m_CABACEstimator->getCtx()); +#endif if (uiAbsSum > 0) { m_pcTrQuant->invTransformNxN(tu, codeCompId, codeResi, qpCbCr); @@ -3232,6 +3279,9 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c if (tu.jointCbCr != codedCbfMask) { ruiDist = std::numeric_limits<Distortion>::max(); +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcTrQuant->lambdaAdjustColorTrans(false); return; } @@ -3249,6 +3299,9 @@ void IntraSearch::xIntraCodingACTTUBlock(TransformUnit &tu, const ComponentID &c } } +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcTrQuant->lambdaAdjustColorTrans(false); ruiDist += m_pcRdCost->getDistPart(piOrgResi, piResi, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE); @@ -3449,6 +3502,23 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par { nNumTransformCands = 1 + ( tsAllowed ? 1 : 0 ) + ( mtsAllowed ? 4 : 0 ); // DCT + TS + 4 MTS = 6 tests +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) + { + nNumTransformCands = 1; + CHECK(!tsAllowed && !cu.bdpcmMode, "transform skip should be enabled for LS"); + if (cu.bdpcmMode) + { + trModes.push_back(TrMode(0, true)); + } + else + { + trModes.push_back(TrMode(1, true)); + } + } + else + { +#endif trModes.push_back( TrMode( 0, true ) ); //DCT2 if( tsAllowed ) { @@ -3461,6 +3531,9 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par trModes.push_back( TrMode( i, true ) ); } } +#if JVET_Q0820_ACT + } +#endif } CHECK( !tu.Y().valid(), "Invalid TU" ); @@ -3644,7 +3717,17 @@ bool IntraSearch::xRecurIntraCodingLumaQT( CodingStructure &cs, Partitioner &par if( ( sps.getUseLFNST() ? ( modeId == lastCheckId && modeId != 0 && checkTransformSkip ) : ( trModes[ modeId ].first != 0 ) ) && !TU::getCbfAtDepth( tu, COMPONENT_Y, currDepth ) ) { //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif singleCostTmp = MAX_DOUBLE; +#if JVET_Q0820_ACT + else + { + singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, subTuCounter, ispType, &cuCtx); + singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma); + } +#endif } else { @@ -3964,7 +4047,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti piResi.subtract(piPred); } +#if JVET_Q0820_ACT + resiBuf.colorSpaceConvert(orgResiBuf, true, cs.slice->clpRng(COMPONENT_Y)); +#else resiBuf.colorSpaceConvert(orgResiBuf, true); +#endif // 2. luma residual optimization double dSingleCostLuma = MAX_DOUBLE; @@ -3991,6 +4078,23 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti } else { +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) + { + nNumTransformCands = 1; + CHECK(!tsAllowed && !cu.bdpcmMode, "transform skip should be enabled for LS"); + if (cu.bdpcmMode) + { + trModes.push_back(TrMode(0, true)); + } + else + { + trModes.push_back(TrMode(1, true)); + } + } + else + { +#endif nNumTransformCands = 1 + (tsAllowed ? 1 : 0) + (mtsAllowed ? 4 : 0); // DCT + TS + 4 MTS = 6 tests trModes.push_back(TrMode(0, true)); //DCT2 @@ -4005,6 +4109,9 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti trModes.push_back(TrMode(i, true)); } } +#if JVET_Q0820_ACT + } +#endif } CodingStructure &saveLumaCS = *m_pSaveCS[0]; @@ -4029,9 +4136,16 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti bool cbfBestModeValid = false; bool cbfDCT2 = true; +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcRdCost->lambdaAdjustColorTrans(true, COMPONENT_Y); +#if JVET_Q0820_ACT + for (int modeId = firstCheckId; modeId <= ((m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) ? (nNumTransformCands - 1) : lastCheckId); modeId++) +#else for (int modeId = firstCheckId; modeId <= lastCheckId; modeId++) +#endif { uint8_t transformIndex = modeId; csFull->getResiBuf(tu.Y()).copyFrom(csFull->getOrgResiBuf(tu.Y())); @@ -4152,7 +4266,17 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti if ((sps.getUseLFNST() ? (modeId == lastCheckId && modeId != 0 && checkTransformSkip) : (trModes[modeId].first != 0)) && !TU::getCbfAtDepth(tu, COMPONENT_Y, currDepth)) { //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif singleCostTmp = MAX_DOUBLE; +#if JVET_Q0820_ACT + else + { + singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, -1, TU_NO_ISP); + singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma, false); + } +#endif } else { @@ -4167,14 +4291,22 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti } else { +#if JVET_Q0820_ACT + singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma, false); +#else singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma); +#endif } } else #else singleTmpFracBits = xGetIntraFracBitsQT(*csFull, partitioner, true, false, -1, TU_NO_ISP); #endif +#if JVET_Q0820_ACT + singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma, false); +#else singleCostTmp = m_pcRdCost->calcRdCost(singleTmpFracBits, singleDistTmpLuma); +#endif } if (singleCostTmp < dSingleCostLuma) @@ -4206,6 +4338,9 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti } } +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif m_pcRdCost->lambdaAdjustColorTrans(false, COMPONENT_Y); if (sps.getUseLFNST()) @@ -4242,8 +4377,10 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti CompArea& cbArea = tu.blocks[COMPONENT_Cb]; CompArea& crArea = tu.blocks[COMPONENT_Cr]; +#if !JVET_Q0820_ACT ctxStart = m_CABACEstimator->getCtx(); m_CABACEstimator->resetBits(); +#endif tu.jointCbCr = 0; bool doReshaping = (slice.getPicHeader()->getLmcsEnabledFlag() && slice.getPicHeader()->getLmcsChromaResidualScaleFlag() && (slice.isIntra() || m_pcReshape->getCTUFlag()) && (cbArea.width * cbArea.height > 4)); @@ -4274,16 +4411,120 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti for (uint32_t c = COMPONENT_Cb; c < ::getNumberValidTBlocks(*csFull->pcv); c++) { const ComponentID compID = ComponentID(c); +#if JVET_Q0820_ACT + double dSingleBestCostChroma = MAX_DOUBLE; + int bestModeId = -1; +#if JVET_Q0784_LFNST_COMBINATION + bool tsAllowed = TU::isTSAllowed(tu, compID) && (m_pcEncCfg->getUseChromaTS()) && !cu.lfnstIdx; +#else + bool tsAllowed = TU::isTSAllowed(tu, compID) && (m_pcEncCfg->getUseChromaTS()); +#endif + uint8_t numTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests + bool cbfDCT2 = true; + + trModes.clear(); + + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) + { + numTransformCands = 1; + CHECK(!tsAllowed && !cu.bdpcmModeChroma, "transform skip should be enabled for LS"); + if (cu.bdpcmModeChroma) + { + trModes.push_back(TrMode(0, true)); + } + else + { + trModes.push_back(TrMode(1, true)); + } + } + else + { + trModes.push_back(TrMode(0, true)); // DCT + if (tsAllowed) + { + trModes.push_back(TrMode(1, true)); // TS + } + } + + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) + m_pcRdCost->lambdaAdjustColorTrans(true, compID); + + TempCtx ctxBegin(m_CtxCache); + ctxBegin = m_CABACEstimator->getCtx(); + + for (int modeId = 0; modeId < numTransformCands; modeId++) + { + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) + { + if (modeId && !cbfDCT2) + { + continue; + } + if (!trModes[modeId].second) + { + continue; + } + } + + if (modeId > 0) + { + m_CABACEstimator->getCtx() = ctxBegin; + } + + tu.mtsIdx[compID] = trModes[modeId].first; +#endif Distortion singleDistChroma = 0; +#if JVET_Q0820_ACT + if (numTransformCands > 1) + { + xIntraCodingACTTUBlock(tu, compID, singleDistChroma, modeId == 0 ? &trModes : nullptr, true); + } + else +#endif xIntraCodingACTTUBlock(tu, compID, singleDistChroma); +#if JVET_Q0820_ACT + if (!tu.mtsIdx[compID]) + { + cbfDCT2 = TU::getCbfAtDepth(tu, compID, currDepth); + } + uint64_t fracBitChroma = xGetIntraFracBitsQTChroma(tu, compID); + double dSingleCostChroma = m_pcRdCost->calcRdCost(fracBitChroma, singleDistChroma, false); + if (dSingleCostChroma < dSingleBestCostChroma) + { + dSingleBestCostChroma = dSingleCostChroma; + bestModeId = modeId; + if (bestModeId != (numTransformCands - 1)) + { + saveChromaCS.getResiBuf(tu.blocks[compID]).copyFrom(csFull->getResiBuf(tu.blocks[compID])); + tmpTU->copyComponentFrom(tu, compID); + ctxBest = m_CABACEstimator->getCtx(); + } + } + } + + if (bestModeId != (numTransformCands - 1)) + { + csFull->getResiBuf(tu.blocks[compID]).copyFrom(saveChromaCS.getResiBuf(tu.blocks[compID])); + tu.copyComponentFrom(*tmpTU, compID); + m_CABACEstimator->getCtx() = ctxBest; + } + + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) + m_pcRdCost->lambdaAdjustColorTrans(false, compID); +#else xGetIntraFracBitsQTChroma(tu, compID); +#endif } Position tuPos = tu.Y(); tuPos.relativeTo(cu.Y()); const UnitArea relativeUnitArea(tu.chromaFormat, Area(tuPos, tu.Y().size())); PelUnitBuf invColorTransResidual = m_colorTransResiBuf.getBuf(relativeUnitArea); +#if JVET_Q0820_ACT + csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false, cs.slice->clpRng(COMPONENT_Y)); +#else csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false); +#endif Distortion totalDist = 0; for (uint32_t c = COMPONENT_Y; c < ::getNumberValidTBlocks(*csFull->pcv); c++) @@ -4360,7 +4601,11 @@ bool IntraSearch::xRecurIntraCodingACTQT(CodingStructure &cs, Partitioner &parti uint64_t bitsTmp = 0; if (distTmp < std::numeric_limits<Distortion>::max()) { +#if JVET_Q0820_ACT + csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false, csFull->slice->clpRng(COMPONENT_Y)); +#else csFull->getResiBuf(tu).colorSpaceConvert(invColorTransResidual, false); +#endif distTmp = 0; for (uint32_t c = COMPONENT_Y; c < ::getNumberValidTBlocks(*csFull->pcv); c++) { @@ -4666,12 +4911,32 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio #endif uint8_t nNumTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests std::vector<TrMode> trModes; +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING) + { + nNumTransformCands = 1; + CHECK(!tsAllowed && !currTU.cu->bdpcmModeChroma, "transform skip should be enabled for LS"); + if (currTU.cu->bdpcmModeChroma) + { + trModes.push_back(TrMode(0, true)); + } + else + { + trModes.push_back(TrMode(1, true)); + } + } + else + { +#endif trModes.push_back(TrMode(0, true)); // DCT2 if (tsAllowed) { trModes.push_back(TrMode(1, true));//TS } +#if JVET_Q0820_ACT + } +#endif CHECK(!currTU.Cb().valid(), "Invalid TU"); const int totalModesToTest = crossCPredictionModesToTest * nNumTransformCands; @@ -4739,7 +5004,17 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio if (((crossCPredictionModeId == 1) && (currTU.compAlpha[compID] == 0)) || ((currTU.mtsIdx[compID] == MTS_SKIP && !currTU.cu->bdpcmModeChroma) && !TU::getCbf(currTU, compID))) //In order not to code TS flag when cbf is zero, the case for TS with cbf being zero is forbidden. { +#if JVET_Q0820_ACT + if (m_pcEncCfg->getCostMode() != COST_LOSSLESS_CODING) +#endif singleCostTmp = MAX_DOUBLE; +#if JVET_Q0820_ACT + else + { + uint64_t fracBitsTmp = xGetIntraFracBitsQTChroma(currTU, compID); + singleCostTmp = m_pcRdCost->calcRdCost(fracBitsTmp, singleDistCTmp); + } +#endif } else if( lumaUsesISP && bestCostSoFar != MAX_DOUBLE && c == COMPONENT_Cb ) { @@ -4809,7 +5084,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio } // Done with one component of separate coding of Cr and Cb, just switch to the best Cb contexts if Cr coding is still to be done +#if JVET_Q0820_ACT + if ((c == COMPONENT_Cb && bestModeId < totalModesToTest) || (c == COMPONENT_Cb && m_pcEncCfg->getCostMode() == COST_LOSSLESS_CODING)) +#else if ( c == COMPONENT_Cb && bestModeId < totalModesToTest) +#endif { m_CABACEstimator->getCtx() = ctxBest; @@ -4823,25 +5102,90 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio double bestCostCbCr = bestCostCb + bestCostCr; Distortion bestDistCbCr = bestDistCb + bestDistCr; int bestJointCbCr = 0; +#if !JVET_Q0695_CHROMA_TS_JCCR bool lastIsBest = false; +#endif std::vector<int> jointCbfMasksToTest; if ( cs.sps->getJointCbCrEnabledFlag() && (TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr))) { jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(currTU, orgResiCb, orgResiCr); } +#if JVET_Q0695_CHROMA_TS_JCCR + bool checkDCTOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cr)) || + (TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2 && !TU::getCbf(tmpTU, COMPONENT_Cb)) || + (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_DCT2_DCT2 && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_DCT2_DCT2); + + bool checkTSOnly = (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cr)) || + (TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP && !TU::getCbf(tmpTU, COMPONENT_Cb)) || + (TU::getCbf(tmpTU, COMPONENT_Cb) && tmpTU.mtsIdx[COMPONENT_Cb] == MTS_SKIP && TU::getCbf(tmpTU, COMPONENT_Cr) && tmpTU.mtsIdx[COMPONENT_Cr] == MTS_SKIP); + + if (jointCbfMasksToTest.size() && currTU.cu->bdpcmModeChroma) + { + CHECK(!checkTSOnly || checkDCTOnly, "bdpcm only allows transform skip"); + } +#endif for( int cbfMask : jointCbfMasksToTest ) { +#if !JVET_Q0695_CHROMA_TS_JCCR Distortion distTmp = 0; +#endif currTU.jointCbCr = (uint8_t)cbfMask; currTU.compAlpha[COMPONENT_Cb] = 0; currTU.compAlpha[COMPONENT_Cr] = 0; +#if JVET_Q0695_CHROMA_TS_JCCR + ComponentID codeCompId = ((currTU.jointCbCr >> 1) ? COMPONENT_Cb : COMPONENT_Cr); + ComponentID otherCompId = ((codeCompId == COMPONENT_Cb) ? COMPONENT_Cr : COMPONENT_Cb); +#if JVET_Q0784_LFNST_COMBINATION + bool tsAllowed = TU::isTSAllowed(currTU, codeCompId) && (m_pcEncCfg->getUseChromaTS()) && !currTU.cu->lfnstIdx; +#else + bool tsAllowed = TU::isTSAllowed(currTU, codeCompId) && (m_pcEncCfg->getUseChromaTS()); +#endif + uint8_t numTransformCands = 1 + (tsAllowed ? 1 : 0); // DCT + TS = 2 tests + bool cbfDCT2 = true; + + std::vector<TrMode> trModes; + if (checkDCTOnly || checkTSOnly) + { + numTransformCands = 1; + } + + if (!checkTSOnly || currTU.cu->bdpcmModeChroma) + { + trModes.push_back(TrMode(0, true)); // DCT2 + } + if (tsAllowed && !checkDCTOnly) + { + trModes.push_back(TrMode(1, true));//TS + } + for (int modeId = 0; modeId < numTransformCands; modeId++) + { + if (modeId && !cbfDCT2) + { + continue; + } + if (!trModes[modeId].second) + { + continue; + } + Distortion distTmp = 0; + currTU.mtsIdx[codeCompId] = currTU.cu->bdpcmModeChroma ? MTS_SKIP : trModes[modeId].first; + currTU.mtsIdx[otherCompId] = MTS_DCT2_DCT2; +#else // encoder bugfix: initialize mtsIdx for chroma under JointCbCrMode. currTU.mtsIdx[COMPONENT_Cb] = currTU.mtsIdx[COMPONENT_Cr] = MTS_DCT2_DCT2; +#endif m_CABACEstimator->getCtx() = ctxStartTU; resiCb.copyFrom( orgResiCb[cbfMask] ); resiCr.copyFrom( orgResiCr[cbfMask] ); +#if JVET_Q0695_CHROMA_TS_JCCR + if (numTransformCands > 1) + { + xIntraCodingTUBlock(currTU, COMPONENT_Cb, false, distTmp, 0, nullptr, modeId == 0 ? &trModes : nullptr, true); + } + else +#endif xIntraCodingTUBlock( currTU, COMPONENT_Cb, false, distTmp, 0 ); double costTmp = std::numeric_limits<double>::max(); @@ -4849,7 +5193,19 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio { uint64_t bits = xGetIntraFracBitsQTChroma( currTU, COMPONENT_Cb ); costTmp = m_pcRdCost->calcRdCost( bits, distTmp ); +#if JVET_Q0695_CHROMA_TS_JCCR + if (!currTU.mtsIdx[codeCompId]) + { + cbfDCT2 = true; + } +#endif } +#if JVET_Q0695_CHROMA_TS_JCCR + else if (!currTU.mtsIdx[codeCompId]) + { + cbfDCT2 = false; + } +#endif if( costTmp < bestCostCbCr ) { @@ -4858,7 +5214,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio bestJointCbCr = currTU.jointCbCr; // store data +#if !JVET_Q0695_CHROMA_TS_JCCR if( cbfMask != jointCbfMasksToTest.back() ) +#endif { #if KEEP_PRED_AND_RESI_SIGNALS saveCS.getOrgResiBuf(cbArea).copyFrom(cs.getOrgResiBuf(cbArea)); @@ -4879,15 +5237,22 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio ctxBest = m_CABACEstimator->getCtx(); } +#if !JVET_Q0695_CHROMA_TS_JCCR else { lastIsBest = true; } +#endif + } +#if JVET_Q0695_CHROMA_TS_JCCR } +#endif } // Retrieve the best CU data (unless it was the very last one tested) +#if !JVET_Q0695_CHROMA_TS_JCCR if ( !( maxModesTested == 1 && jointCbfMasksToTest.empty() ) && !lastIsBest ) +#endif { #if KEEP_PRED_AND_RESI_SIGNALS cs.getPredBuf (cbArea).copyFrom(saveCS.getPredBuf (cbArea)); diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index 4a1fdcc80c3cd856dbec58dbba76fd90eb0290d4..2b34e2daea798f8c82ac97500dfe0aa049363f21 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -515,6 +515,12 @@ void HLSWriter::codeAlfAps( APS* pcAPS ) WRITE_FLAG(param.newFilterFlag[CHANNEL_TYPE_LUMA], "alf_luma_new_filter"); WRITE_FLAG(param.newFilterFlag[CHANNEL_TYPE_CHROMA], "alf_chroma_new_filter"); +#if JVET_Q0795_CCALF + CcAlfFilterParam paramCcAlf = pcAPS->getCcAlfAPSParam(); + WRITE_FLAG(paramCcAlf.newCcAlfFilter[COMPONENT_Cb - 1], "alf_cc_cb_filter_signal_flag"); + WRITE_FLAG(paramCcAlf.newCcAlfFilter[COMPONENT_Cr - 1], "alf_cc_cr_filter_signal_flag"); +#endif + if (param.newFilterFlag[CHANNEL_TYPE_LUMA]) { #if JVET_Q0249_ALF_CHROMA_CLIPFLAG @@ -550,6 +556,52 @@ void HLSWriter::codeAlfAps( APS* pcAPS ) alfFilter(param, true, altIdx); } } +#if JVET_Q0795_CCALF + for (int ccIdx = 0; ccIdx < 2; ccIdx++) + { + if (paramCcAlf.newCcAlfFilter[ccIdx]) + { + const int filterCount = paramCcAlf.ccAlfFilterCount[ccIdx]; + CHECK(filterCount > MAX_NUM_CC_ALF_FILTERS, "CC ALF Filter count is too large"); + CHECK(filterCount == 0, "CC ALF Filter count is too small"); + + if (MAX_NUM_CC_ALF_FILTERS > 1) + { + WRITE_UVLC(filterCount - 1, + ccIdx == 0 ? "alf_cc_cb_filters_signalled_minus1" : "alf_cc_cr_filters_signalled_minus1"); + } + + for (int filterIdx = 0; filterIdx < filterCount; filterIdx++) + { + AlfFilterShape alfShape(size_CC_ALF); + + const short *coeff = paramCcAlf.ccAlfCoeff[ccIdx][filterIdx]; + // Filter coefficients + for (int i = 0; i < alfShape.numCoeff - 1; i++) + { + if (coeff[i] == 0) + { + WRITE_CODE(0, CCALF_BITS_PER_COEFF_LEVEL, + ccIdx == 0 ? "alf_cc_cb_mapped_coeff_abs" : "alf_cc_cr_mapped_coeff_abs"); + } + else + { + WRITE_CODE(1 + floorLog2(abs(coeff[i])), CCALF_BITS_PER_COEFF_LEVEL, + ccIdx == 0 ? "alf_cc_cb_mapped_coeff_abs" : "alf_cc_cr_mapped_coeff_abs"); + WRITE_FLAG(coeff[i] < 0 ? 1 : 0, ccIdx == 0 ? "alf_cc_cb_coeff_sign" : "alf_cc_cr_coeff_sign"); + } + } + + DTRACE(g_trace_ctx, D_SYNTAX, "%s coeff filterIdx %d: ", ccIdx == 0 ? "Cb" : "Cr", filterIdx); + for (int i = 0; i < alfShape.numCoeff; i++) + { + DTRACE(g_trace_ctx, D_SYNTAX, "%d ", coeff[i]); + } + DTRACE(g_trace_ctx, D_SYNTAX, "\n"); + } + } + } +#endif } void HLSWriter::codeLmcsAps( APS* pcAPS ) @@ -809,14 +861,20 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) WRITE_UVLC(pcSPS->getLog2MinCodingBlockSize() - 2, "log2_min_luma_coding_block_size_minus2"); WRITE_FLAG(pcSPS->getSplitConsOverrideEnabledFlag(), "partition_constraints_override_enabled_flag"); WRITE_UVLC(floorLog2(pcSPS->getMinQTSize(I_SLICE)) - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_intra_slice_luma"); +#if !JVET_Q0481_PARTITION_CONSTRAINTS_ORDER WRITE_UVLC(floorLog2(pcSPS->getMinQTSize(B_SLICE)) - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_inter_slice"); WRITE_UVLC(pcSPS->getMaxMTTHierarchyDepth(), "sps_max_mtt_hierarchy_depth_inter_slice"); +#endif WRITE_UVLC(pcSPS->getMaxMTTHierarchyDepthI(), "sps_max_mtt_hierarchy_depth_intra_slice_luma"); if (pcSPS->getMaxMTTHierarchyDepthI() != 0) { WRITE_UVLC(floorLog2(pcSPS->getMaxBTSizeI()) - floorLog2(pcSPS->getMinQTSize(I_SLICE)), "sps_log2_diff_max_bt_min_qt_intra_slice_luma"); WRITE_UVLC(floorLog2(pcSPS->getMaxTTSizeI()) - floorLog2(pcSPS->getMinQTSize(I_SLICE)), "sps_log2_diff_max_tt_min_qt_intra_slice_luma"); } +#if JVET_Q0481_PARTITION_CONSTRAINTS_ORDER + WRITE_UVLC(floorLog2(pcSPS->getMinQTSize(B_SLICE)) - pcSPS->getLog2MinCodingBlockSize(), "sps_log2_diff_min_qt_min_cb_inter_slice"); + WRITE_UVLC(pcSPS->getMaxMTTHierarchyDepth(), "sps_max_mtt_hierarchy_depth_inter_slice"); +#endif if (pcSPS->getMaxMTTHierarchyDepth() != 0) { WRITE_UVLC(floorLog2(pcSPS->getMaxBTSize()) - floorLog2(pcSPS->getMinQTSize(B_SLICE)), "sps_log2_diff_max_bt_min_qt_inter_slice"); @@ -864,6 +922,12 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) WRITE_FLAG( pcSPS->getSAOEnabledFlag(), "sps_sao_enabled_flag"); WRITE_FLAG( pcSPS->getALFEnabledFlag(), "sps_alf_enabled_flag" ); +#if JVET_Q0795_CCALF + if (pcSPS->getALFEnabledFlag() && pcSPS->getChromaFormatIdc() != CHROMA_400) + { + WRITE_FLAG( pcSPS->getCCALFEnabledFlag(), "sps_ccalf_enabled_flag" ); + } +#endif WRITE_FLAG(pcSPS->getTransformSkipEnabledFlag() ? 1 : 0, "sps_transform_skip_enabled_flag"); if (pcSPS->getTransformSkipEnabledFlag()) @@ -943,7 +1007,14 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) } if (pcSPS->getChromaFormatIdc() == CHROMA_444) { +#if JVET_Q0820_ACT + if (pcSPS->getLog2MaxTbSize() != 6) + { + WRITE_FLAG(pcSPS->getUseColorTrans() ? 1 : 0, "sps_act_enabled_flag"); + } +#else WRITE_FLAG(pcSPS->getUseColorTrans() ? 1 : 0, "sps_act_enabled_flag"); +#endif } if (pcSPS->getChromaFormatIdc() == CHROMA_444) { @@ -977,6 +1048,9 @@ void HLSWriter::codeSPS( const SPS* pcSPS ) } } #endif +#if JVET_Q0297_MER + WRITE_UVLC(pcSPS->getLog2ParallelMergeLevelMinus2(), "log2_parallel_merge_level_minus2"); +#endif // KJS: reference picture sets to be replaced @@ -1168,7 +1242,11 @@ void HLSWriter::codeVPS(const VPS* pcVPS) xWriteRbspTrailingBits(); } +#if JVET_Q0775_PH_IN_SH +void HLSWriter::codePictureHeader( PicHeader* picHeader, bool writeRbspTrailingBits ) +#else void HLSWriter::codePictureHeader( PicHeader* picHeader ) +#endif { const PPS* pps = NULL; const SPS* sps = NULL; @@ -1272,6 +1350,7 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader ) } } +#if !JVET_Q0155_COLOUR_ID // 4:4:4 colour plane ID if( sps->getSeparateColourPlaneFlag() ) { @@ -1281,6 +1360,7 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader ) { picHeader->setColourPlaneId( 0 ); } +#endif // picture output flag if( pps->getOutputFlagPresentFlag() ) @@ -1374,14 +1454,20 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader ) if (picHeader->getSplitConsOverrideFlag()) { WRITE_UVLC(floorLog2(picHeader->getMinQTSize(I_SLICE)) - sps->getLog2MinCodingBlockSize(), "pic_log2_diff_min_qt_min_cb_intra_slice_luma"); +#if !JVET_Q0819_PH_CHANGES WRITE_UVLC(floorLog2(picHeader->getMinQTSize(P_SLICE)) - sps->getLog2MinCodingBlockSize(), "pic_log2_diff_min_qt_min_cb_inter_slice"); WRITE_UVLC(picHeader->getMaxMTTHierarchyDepth(P_SLICE), "pic_max_mtt_hierarchy_depth_inter_slice"); +#endif WRITE_UVLC(picHeader->getMaxMTTHierarchyDepth(I_SLICE), "pic_max_mtt_hierarchy_depth_intra_slice_luma"); if (picHeader->getMaxMTTHierarchyDepth(I_SLICE) != 0) { WRITE_UVLC(floorLog2(picHeader->getMaxBTSize(I_SLICE)) - floorLog2(picHeader->getMinQTSize(I_SLICE)), "pic_log2_diff_max_bt_min_qt_intra_slice_luma"); WRITE_UVLC(floorLog2(picHeader->getMaxTTSize(I_SLICE)) - floorLog2(picHeader->getMinQTSize(I_SLICE)), "pic_log2_diff_max_tt_min_qt_intra_slice_luma"); } +#if JVET_Q0819_PH_CHANGES + WRITE_UVLC(floorLog2(picHeader->getMinQTSize(P_SLICE)) - sps->getLog2MinCodingBlockSize(), "pic_log2_diff_min_qt_min_cb_inter_slice"); + WRITE_UVLC(picHeader->getMaxMTTHierarchyDepth(P_SLICE), "pic_max_mtt_hierarchy_depth_inter_slice"); +#endif if (picHeader->getMaxMTTHierarchyDepth(P_SLICE) != 0) { WRITE_UVLC(floorLog2(picHeader->getMaxBTSize(P_SLICE)) - floorLog2(picHeader->getMinQTSize(P_SLICE)), "pic_log2_diff_max_bt_min_qt_inter_slice"); @@ -1597,6 +1683,21 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader ) { WRITE_CODE(picHeader->getAlfApsIdChroma(), 3, "pic_alf_aps_id_chroma"); } +#if JVET_Q0795_CCALF + if (sps->getCCALFEnabledFlag()) + { + WRITE_FLAG(picHeader->getCcAlfEnabledFlag(COMPONENT_Cb), "ph_cc_alf_cb_enabled_flag"); + if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cb)) + { + WRITE_CODE(picHeader->getCcAlfCbApsId(), 3, "ph_cc_alf_cb_aps_id"); + } + WRITE_FLAG(picHeader->getCcAlfEnabledFlag(COMPONENT_Cr), "ph_cc_alf_cr_enabled_flag"); + if (picHeader->getCcAlfEnabledFlag(COMPONENT_Cr)) + { + WRITE_CODE(picHeader->getCcAlfCrApsId(), 3, "ph_cc_alf_cr_aps_id"); + } + } +#endif } } else @@ -1604,6 +1705,10 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader ) picHeader->setAlfEnabledFlag(COMPONENT_Y, true); picHeader->setAlfEnabledFlag(COMPONENT_Cb, true); picHeader->setAlfEnabledFlag(COMPONENT_Cr, true); +#if JVET_Q0795_CCALF + picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, sps->getCCALFEnabledFlag()); + picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, sps->getCCALFEnabledFlag()); +#endif } } else @@ -1611,6 +1716,10 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader ) picHeader->setAlfEnabledFlag(COMPONENT_Y, false); picHeader->setAlfEnabledFlag(COMPONENT_Cb, false); picHeader->setAlfEnabledFlag(COMPONENT_Cr, false); +#if JVET_Q0795_CCALF + picHeader->setCcAlfEnabledFlag(COMPONENT_Cb, false); + picHeader->setCcAlfEnabledFlag(COMPONENT_Cr, false); +#endif } // dependent quantization @@ -1720,7 +1829,14 @@ void HLSWriter::codePictureHeader( PicHeader* picHeader ) WRITE_UVLC(0,"pic_segment_header_extension_length"); } +#if JVET_Q0775_PH_IN_SH + if ( writeRbspTrailingBits ) + { + xWriteRbspTrailingBits(); + } +#else xWriteRbspTrailingBits(); +#endif } void HLSWriter::codeSliceHeader ( Slice* pcSlice ) @@ -1730,11 +1846,21 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) #endif CodingStructure& cs = *pcSlice->getPic()->cs; +#if JVET_Q0775_PH_IN_SH + PicHeader *picHeader = cs.picHeader; +#else const PicHeader *picHeader = cs.picHeader; +#endif const ChromaFormat format = pcSlice->getSPS()->getChromaFormatIdc(); const uint32_t numberValidComponents = getNumberValidComponents(format); const bool chromaEnabled = isChromaEnabled(format); - +#if JVET_Q0775_PH_IN_SH + WRITE_FLAG(pcSlice->getPictureHeaderInSliceHeader() ? 1 : 0, "picture_header_in_slice_header_flag"); + if (pcSlice->getPictureHeaderInSliceHeader()) + { + codePictureHeader(picHeader, false); + } +#endif int pocBits = pcSlice->getSPS()->getBitsForPOC(); int pocMask = (1 << pocBits) - 1; WRITE_CODE(pcSlice->getPOC() & pocMask, pocBits, "slice_pic_order_cnt_lsb"); @@ -1787,7 +1913,13 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) WRITE_UVLC( pcSlice->getSliceType(), "slice_type" ); - +#if JVET_Q0155_COLOUR_ID + // 4:4:4 colour plane ID + if( pcSlice->getSPS()->getSeparateColourPlaneFlag() ) + { + WRITE_CODE( pcSlice->getColourPlaneId(), 2, "colour_plane_id" ); + } +#endif if( !picHeader->getPicRplPresentFlag() && (!pcSlice->getIdrPicFlag() || pcSlice->getSPS()->getIDRRefParamListPresent()) ) { @@ -2030,6 +2162,26 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) { WRITE_CODE(pcSlice->getTileGroupApsIdChroma(), 3, "slice_alf_aps_id_chroma"); } + +#if JVET_Q0795_CCALF + if (pcSlice->getSPS()->getCCALFEnabledFlag()) + { + CcAlfFilterParam &filterParam = pcSlice->m_ccAlfFilterParam; + WRITE_FLAG(filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1] ? 1 : 0, "slice_cc_alf_cb_enabled_flag"); + if (filterParam.ccAlfFilterEnabled[COMPONENT_Cb - 1]) + { + // write CC ALF Cb APS ID + WRITE_CODE(pcSlice->getTileGroupCcAlfCbApsId(), 3, "slice_cc_alf_cb_aps_id"); + } + // Cr + WRITE_FLAG(filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1] ? 1 : 0, "slice_cc_alf_cr_enabled_flag"); + if (filterParam.ccAlfFilterEnabled[COMPONENT_Cr - 1]) + { + // write CC ALF Cr APS ID + WRITE_CODE(pcSlice->getTileGroupCcAlfCrApsId(), 3, "slice_cc_alf_cr_aps_id"); + } + } +#endif } } @@ -2088,6 +2240,9 @@ void HLSWriter::codeConstraintInfo ( const ConstraintInfo* cinfo ) WRITE_FLAG(cinfo->getNoPartitionConstraintsOverrideConstraintFlag() ? 1 : 0, "no_partition_constraints_override_constraint_flag"); WRITE_FLAG(cinfo->getNoSaoConstraintFlag() ? 1 : 0, "no_sao_constraint_flag"); WRITE_FLAG(cinfo->getNoAlfConstraintFlag() ? 1 : 0, "no_alf_constraint_flag"); +#if JVET_Q0795_CCALF + WRITE_FLAG(cinfo->getNoCCAlfConstraintFlag() ? 1 : 0, "no_ccalf_constraint_flag"); +#endif WRITE_FLAG(cinfo->getNoJointCbCrConstraintFlag() ? 1 : 0, "no_joint_cbcr_constraint_flag"); WRITE_FLAG(cinfo->getNoRefWraparoundConstraintFlag() ? 1 : 0, "no_ref_wraparound_constraint_flag"); WRITE_FLAG(cinfo->getNoTemporalMvpConstraintFlag() ? 1 : 0, "no_temporal_mvp_constraint_flag"); diff --git a/source/Lib/EncoderLib/VLCWriter.h b/source/Lib/EncoderLib/VLCWriter.h index 7816710363be97eb40bad3bca4f212ca57290756..5fb0ad39090298fbb7e82fa0359a5bd92718156a 100644 --- a/source/Lib/EncoderLib/VLCWriter.h +++ b/source/Lib/EncoderLib/VLCWriter.h @@ -129,7 +129,11 @@ public: void codeScalingListAps ( APS* pcAPS ); void codeVPS ( const VPS* pcVPS ); void codeDPS ( const DPS* dps ); +#if JVET_Q0775_PH_IN_SH + void codePictureHeader ( PicHeader* picHeader, bool writeRbspTrailingBits ); +#else void codePictureHeader ( PicHeader* picHeader ); +#endif void codeSliceHeader ( Slice* pcSlice ); void codeConstraintInfo ( const ConstraintInfo* cinfo ); void codeProfileTierLevel ( const ProfileTierLevel* ptl, int maxNumSubLayersMinus1 );