From 0fffdf5bbbfb867764d24cd22ebdba13aebb31ef Mon Sep 17 00:00:00 2001 From: Christian Helmrich <christian.helmrich@hhi.fraunhofer.de> Date: Mon, 22 Jul 2019 20:50:19 +0200 Subject: [PATCH] JVET-O0105 with JVET-O0543: joint chroma coding extension --- source/Lib/CommonLib/Buffer.h | 26 +++ source/Lib/CommonLib/Contexts.cpp | 7 + source/Lib/CommonLib/LoopFilter.cpp | 8 + source/Lib/CommonLib/Quant.cpp | 7 + source/Lib/CommonLib/Rom.cpp | 4 + source/Lib/CommonLib/Rom.h | 4 + source/Lib/CommonLib/Slice.cpp | 9 + source/Lib/CommonLib/Slice.h | 10 + source/Lib/CommonLib/TrQuant.cpp | 171 +++++++++++++++ source/Lib/CommonLib/TrQuant.h | 15 +- source/Lib/CommonLib/TypeDef.h | 3 + source/Lib/CommonLib/UnitTools.cpp | 11 + source/Lib/CommonLib/UnitTools.h | 4 +- source/Lib/DecoderLib/CABACReader.cpp | 27 +++ source/Lib/DecoderLib/CABACReader.h | 4 + source/Lib/DecoderLib/DecCu.cpp | 51 +++++ source/Lib/DecoderLib/VLCReader.cpp | 6 + source/Lib/EncoderLib/CABACWriter.cpp | 28 +++ source/Lib/EncoderLib/CABACWriter.h | 4 + source/Lib/EncoderLib/EncSlice.cpp | 46 ++++ source/Lib/EncoderLib/InterSearch.cpp | 140 ++++++++++++ source/Lib/EncoderLib/IntraSearch.cpp | 294 +++++++++++++++++++++++++- source/Lib/EncoderLib/VLCWriter.cpp | 7 + 23 files changed, 882 insertions(+), 4 deletions(-) diff --git a/source/Lib/CommonLib/Buffer.h b/source/Lib/CommonLib/Buffer.h index d7a10b1fd8..5c287d84f7 100644 --- a/source/Lib/CommonLib/Buffer.h +++ b/source/Lib/CommonLib/Buffer.h @@ -111,8 +111,10 @@ struct AreaBuf : public Size void copyClip ( const AreaBuf<const T> &src, const ClpRng& clpRng); void subtract ( const AreaBuf<const T> &other ); +#if !JVET_O0105_ICT void copyAndNegate ( const AreaBuf<const T> &other ); void subtractAndHalve ( const AreaBuf<const T> &other ); +#endif void extendSingleBorderPel(); void extendBorderPel ( unsigned margin ); void addWeightedAvg ( const AreaBuf<const T> &other1, const AreaBuf<const T> &other2, const ClpRng& clpRng, const int8_t gbiIdx); @@ -357,6 +359,7 @@ void AreaBuf<T>::subtract( const AreaBuf<const T> &other ) #undef SUBS_INC } +#if !JVET_O0105_ICT template<typename T> void AreaBuf<T>::copyAndNegate( const AreaBuf<const T> &other ) { @@ -398,6 +401,7 @@ void AreaBuf<T>::subtractAndHalve( const AreaBuf<const T> &other ) #undef SUBS_OP #undef SUBS_INC } +#endif template<typename T> void AreaBuf<T>::copyClip( const AreaBuf<const T> &src, const ClpRng& clpRng ) @@ -924,5 +928,27 @@ private: Pel *m_origin[MAX_NUM_COMPONENT]; }; +#if JVET_O0105_ICT +struct CompStorage : public PelBuf +{ + CompStorage () { m_memory = nullptr; } + ~CompStorage() { if (valid()) delete [] m_memory; } + + void create( const Size& size ) + { + CHECK( m_memory, "Trying to re-create an already initialized buffer" ); + m_memory = new Pel [ size.area() ]; + *static_cast<PelBuf*>(this) = PelBuf( m_memory, size ); + } + void destroy() + { + if (valid()) delete [] m_memory; + m_memory = nullptr; + } + bool valid() { return m_memory != nullptr; } +private: + Pel* m_memory; +}; +#endif #endif diff --git a/source/Lib/CommonLib/Contexts.cpp b/source/Lib/CommonLib/Contexts.cpp index 6f68221e92..e3df7ce9ac 100644 --- a/source/Lib/CommonLib/Contexts.cpp +++ b/source/Lib/CommonLib/Contexts.cpp @@ -784,10 +784,17 @@ const CtxSet ContextSetCfg::IBCFlag = ContextSetCfg::addCtxSet const CtxSet ContextSetCfg::JointCbCrFlag = ContextSetCfg::addCtxSet ({ +#if JVET_O0105_ICT + { 156, 156, 156, }, + { 156, 156, 156, }, + { 184, 184, 184, }, + { 1, 1, 1, }, +#else { 156, }, { 156, }, { 184, }, { 1, }, +#endif }); const CtxSet ContextSetCfg::TsSigCoeffGroup = ContextSetCfg::addCtxSet diff --git a/source/Lib/CommonLib/LoopFilter.cpp b/source/Lib/CommonLib/LoopFilter.cpp index 60f0bbfbcd..6d51b1c713 100644 --- a/source/Lib/CommonLib/LoopFilter.cpp +++ b/source/Lib/CommonLib/LoopFilter.cpp @@ -667,12 +667,20 @@ unsigned LoopFilter::xGetBoundaryStrengthSingle ( const CodingUnit& cu, const De tmpBs += BsSet(1, COMPONENT_Y); } // U +#if JVET_O0105_ICT + if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Cb) || TU::getCbf(tuP, COMPONENT_Cb) || tuQ.jointCbCr || tuP.jointCbCr)) +#else if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Cb) || TU::getCbf(tuP, COMPONENT_Cb))) +#endif { tmpBs += BsSet(1, COMPONENT_Cb); } // V +#if JVET_O0105_ICT + if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Cr) || TU::getCbf(tuP, COMPONENT_Cr) || tuQ.jointCbCr || tuP.jointCbCr)) +#else if (m_aapucBS[edgeDir][rasterIdx] && (TU::getCbf(tuQ, COMPONENT_Cr) || TU::getCbf(tuP, COMPONENT_Cr))) +#endif { tmpBs += BsSet(1, COMPONENT_Cr); } diff --git a/source/Lib/CommonLib/Quant.cpp b/source/Lib/CommonLib/Quant.cpp index 43f78293fc..f994143f09 100644 --- a/source/Lib/CommonLib/Quant.cpp +++ b/source/Lib/CommonLib/Quant.cpp @@ -103,8 +103,15 @@ QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int if (isChroma(compID)) { +#if JVET_O0105_ICT + const bool useJQP = ( abs(TU::getICTMode(tu)) == 2 ); + + chromaQpOffset += tu.cs->pps->getQpOffset ( useJQP ? JOINT_CbCr : compID ); + chromaQpOffset += tu.cs->slice->getSliceChromaQpDelta( useJQP ? JOINT_CbCr : compID ); +#else chromaQpOffset += tu.cs->pps->getQpOffset ( tu.jointCbCr ? JOINT_CbCr : compID ); chromaQpOffset += tu.cs->slice->getSliceChromaQpDelta( tu.jointCbCr ? JOINT_CbCr : compID ); +#endif chromaQpOffset += tu.cs->pps->getPpsRangeExtension().getChromaQpOffsetListEntry( tu.cu->chromaQpAdj ).u.offset[int( compID ) - 1]; } diff --git a/source/Lib/CommonLib/Rom.cpp b/source/Lib/CommonLib/Rom.cpp index 2537607d5d..7cc906bc18 100644 --- a/source/Lib/CommonLib/Rom.cpp +++ b/source/Lib/CommonLib/Rom.cpp @@ -585,6 +585,10 @@ int8_t g_aucLog2 [MAX_CU_SIZE + 1]; int8_t g_aucNextLog2[MAX_CU_SIZE + 1]; int8_t g_aucPrevLog2[MAX_CU_SIZE + 1]; +#if JVET_O0105_ICT +const int g_ictModes[2][4] = { { 0, 3, 1, 2 }, { 0, -3, -1, -2 } }; +#endif + UnitScale g_miScaling( MIN_CU_LOG2, MIN_CU_LOG2 ); diff --git a/source/Lib/CommonLib/Rom.h b/source/Lib/CommonLib/Rom.h index 7557243d37..ac26cd734f 100644 --- a/source/Lib/CommonLib/Rom.h +++ b/source/Lib/CommonLib/Rom.h @@ -146,6 +146,10 @@ extern int8_t g_aucLog2 [MAX_CU_SIZE + 1]; extern int8_t g_aucNextLog2 [MAX_CU_SIZE + 1]; extern int8_t g_aucPrevLog2 [MAX_CU_SIZE + 1]; +#if JVET_O0105_ICT +extern const int g_ictModes[2][4]; +#endif + inline bool is34( const SizeType& size ) { return ( size & ( ( int64_t ) 1 << ( g_aucLog2[size] - 1 ) ) ); diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index d69f165ab0..b841f2b689 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -97,6 +97,9 @@ Slice::Slice() , m_bTestWeightBiPred ( false ) , m_substreamSizes ( ) , m_cabacInitFlag ( false ) +#if JVET_O0105_ICT +, m_jointCbCrSignFlag ( false ) +#endif , m_bLMvdL1Zero ( false ) , m_LFCrossSliceBoundaryFlag ( false ) , m_enableTMVPFlag ( true ) @@ -192,6 +195,9 @@ void Slice::initSlice() m_disFracMMVD = false; m_substreamSizes.clear(); m_cabacInitFlag = false; +#if JVET_O0105_ICT + m_jointCbCrSignFlag = false; +#endif m_enableTMVPFlag = true; } @@ -672,6 +678,9 @@ void Slice::copySliceInfo(Slice *pSrc, bool cpyAlmostAll) } m_cabacInitFlag = pSrc->m_cabacInitFlag; +#if JVET_O0105_ICT + m_jointCbCrSignFlag = pSrc->m_jointCbCrSignFlag; +#endif memcpy(m_alfApss, pSrc->m_alfApss, sizeof(m_alfApss)); // this might be quite unsafe memcpy( m_tileGroupAlfEnabledFlag, pSrc->m_tileGroupAlfEnabledFlag, sizeof(m_tileGroupAlfEnabledFlag)); m_tileGroupNumAps = pSrc->m_tileGroupNumAps; diff --git a/source/Lib/CommonLib/Slice.h b/source/Lib/CommonLib/Slice.h index cbe18bce93..690419edea 100644 --- a/source/Lib/CommonLib/Slice.h +++ b/source/Lib/CommonLib/Slice.h @@ -1467,6 +1467,10 @@ private: bool m_cabacInitFlag; +#if JVET_O0105_ICT + bool m_jointCbCrSignFlag; +#endif + bool m_bLMvdL1Zero; bool m_LFCrossSliceBoundaryFlag; @@ -1739,6 +1743,12 @@ public: void setCabacInitFlag( bool val ) { m_cabacInitFlag = val; } //!< set CABAC initial flag bool getCabacInitFlag() const { return m_cabacInitFlag; } //!< get CABAC initial flag + +#if JVET_O0105_ICT + void setJointCbCrSignFlag( bool b ) { m_jointCbCrSignFlag = b; } + bool getJointCbCrSignFlag() const { return m_jointCbCrSignFlag; } +#endif + void setLFCrossSliceBoundaryFlag( bool val ) { m_LFCrossSliceBoundaryFlag = val; } bool getLFCrossSliceBoundaryFlag() const { return m_LFCrossSliceBoundaryFlag; } diff --git a/source/Lib/CommonLib/TrQuant.cpp b/source/Lib/CommonLib/TrQuant.cpp index 51e628011f..3206bef3e6 100644 --- a/source/Lib/CommonLib/TrQuant.cpp +++ b/source/Lib/CommonLib/TrQuant.cpp @@ -83,6 +83,80 @@ InvTrans *fastInvTrans[NUM_TRANS_TYPE][g_numTransformMatrixSizes] = //! \ingroup CommonLib //! \{ +#if JVET_O0105_ICT +static inline int64_t square( const int d ) { return d * (int64_t)d; } + +template<int signedMode> std::pair<int64_t,int64_t> fwdTransformCbCr( const PelBuf &resCb, const PelBuf &resCr, PelBuf& resC1, PelBuf& resC2 ) +{ + const Pel* cb = resCb.buf; + const Pel* cr = resCr.buf; + Pel* c1 = resC1.buf; + Pel* c2 = resC2.buf; + int64_t d1 = 0; + int64_t d2 = 0; + for( SizeType y = 0; y < resCb.height; y++, cb += resCb.stride, cr += resCr.stride, c1 += resC1.stride, c2 += resC2.stride ) + { + for( SizeType x = 0; x < resCb.width; x++ ) + { + int cbx = cb[x], crx = cr[x]; + if ( signedMode == 1 ) + { + c1[x] = Pel( ( 4*cbx + 2*crx ) / 5 ); + d1 += square( cbx - c1[x] ) + square( crx - (c1[x]>>1) ); + } + else if ( signedMode == -1 ) + { + c1[x] = Pel( ( 4*cbx - 2*crx ) / 5 ); + d1 += square( cbx - c1[x] ) + square( crx - (-c1[x]>>1) ); + } + else if ( signedMode == 2 ) + { + c1[x] = Pel( ( cbx + crx ) / 2 ); + d1 += square( cbx - c1[x] ) + square( crx - c1[x] ); + } + else if ( signedMode == -2 ) + { + c1[x] = Pel( ( cbx - crx ) / 2 ); + d1 += square( cbx - c1[x] ) + square( crx + c1[x] ); + } + else if ( signedMode == 3 ) + { + c2[x] = Pel( ( 4*crx + 2*cbx ) / 5 ); + d1 += square( cbx - (c2[x]>>1) ) + square( crx - c2[x] ); + } + else if ( signedMode == -3 ) + { + c2[x] = Pel( ( 4*crx - 2*cbx ) / 5 ); + d1 += square( cbx - (-c2[x]>>1) ) + square( crx - c2[x] ); + } + else + { + d1 += square( cbx ); + d2 += square( crx ); + } + } + } + return std::make_pair(d1,d2); +} + +template<int signedMode> void invTransformCbCr( PelBuf &resCb, PelBuf &resCr ) +{ + Pel* cb = resCb.buf; + Pel* cr = resCr.buf; + for( SizeType y = 0; y < resCb.height; y++, cb += resCb.stride, cr += resCr.stride ) + { + for( SizeType x = 0; x < resCb.width; x++ ) + { + if ( signedMode == 1 ) { cr[x] = cb[x] >> 1; } + else if ( signedMode == -1 ) { cr[x] = -cb[x] >> 1; } + else if ( signedMode == 2 ) { cr[x] = cb[x]; } + else if ( signedMode == -2 ) { cr[x] = -cb[x]; } + else if ( signedMode == 3 ) { cb[x] = cr[x] >> 1; } + else if ( signedMode == -3 ) { cb[x] = -cr[x] >> 1; } + } + } +} +#endif // ==================================================================================================================== // TrQuant class member functions @@ -96,6 +170,26 @@ TrQuant::TrQuant() : m_quant( nullptr ) { m_mtsCoeffs[i] = (TCoeff*) xMalloc( TCoeff, MAX_CU_SIZE * MAX_CU_SIZE ); } +#if JVET_O0105_ICT + { + m_invICT = m_invICTMem + maxAbsIctMode; + m_invICT[ 0] = invTransformCbCr< 0>; + m_invICT[ 1] = invTransformCbCr< 1>; + m_invICT[-1] = invTransformCbCr<-1>; + m_invICT[ 2] = invTransformCbCr< 2>; + m_invICT[-2] = invTransformCbCr<-2>; + m_invICT[ 3] = invTransformCbCr< 3>; + m_invICT[-3] = invTransformCbCr<-3>; + m_fwdICT = m_fwdICTMem + maxAbsIctMode; + m_fwdICT[ 0] = fwdTransformCbCr< 0>; + m_fwdICT[ 1] = fwdTransformCbCr< 1>; + m_fwdICT[-1] = fwdTransformCbCr<-1>; + m_fwdICT[ 2] = fwdTransformCbCr< 2>; + m_fwdICT[-2] = fwdTransformCbCr<-2>; + m_fwdICT[ 3] = fwdTransformCbCr< 3>; + m_fwdICT[-3] = fwdTransformCbCr<-3>; + } +#endif } TrQuant::~TrQuant() @@ -556,6 +650,83 @@ void TrQuant::invRdpcmNxN(TransformUnit& tu, const ComponentID &compID, PelBuf & } } +#if JVET_O0105_ICT + +std::pair<int64_t,int64_t> TrQuant::fwdTransformICT( const TransformUnit &tu, const PelBuf &resCb, const PelBuf &resCr, PelBuf &resC1, PelBuf &resC2, int jointCbCr ) +{ + CHECK( Size(resCb) != Size(resCr), "resCb and resCr have different sizes" ); + CHECK( Size(resCb) != Size(resC1), "resCb and resC1 have different sizes" ); + CHECK( Size(resCb) != Size(resC2), "resCb and resC2 have different sizes" ); + return (*m_fwdICT[ TU::getICTMode(tu, jointCbCr) ])( resCb, resCr, resC1, resC2 ); +} + +void TrQuant::invTransformICT( const TransformUnit &tu, PelBuf &resCb, PelBuf &resCr ) +{ + CHECK( Size(resCb) != Size(resCr), "resCb and resCr have different sizes" ); + (*m_invICT[ TU::getICTMode(tu) ])( resCb, resCr ); +} + +std::vector<int> TrQuant::selectICTCandidates( const TransformUnit &tu, CompStorage* resCb, CompStorage* resCr ) +{ + CHECK( !resCb[0].valid() || !resCr[0].valid(), "standard components are not valid" ); + +#if JVET_O0543_ICT_ICU_ONLY + if( !CU::isIntra( *tu.cu ) ) + { + int cbfMask = 3; + resCb[cbfMask].create( tu.blocks[COMPONENT_Cb] ); + resCr[cbfMask].create( tu.blocks[COMPONENT_Cr] ); + fwdTransformICT( tu, resCb[0], resCr[0], resCb[cbfMask], resCr[cbfMask], cbfMask ); + std::vector<int> cbfMasksToTest; + cbfMasksToTest.push_back( cbfMask ); + return cbfMasksToTest; + } +#endif + + std::pair<int64_t,int64_t> pairDist[4]; + for( int cbfMask = 0; cbfMask < 4; cbfMask++ ) + { + if( cbfMask ) + { + CHECK( resCb[cbfMask].valid() || resCr[cbfMask].valid(), "target components for cbfMask=" << cbfMask << " are already present" ); + resCb[cbfMask].create( tu.blocks[COMPONENT_Cb] ); + resCr[cbfMask].create( tu.blocks[COMPONENT_Cr] ); + } + pairDist[cbfMask] = fwdTransformICT( tu, resCb[0], resCr[0], resCb[cbfMask], resCr[cbfMask], cbfMask ); + } + + std::vector<int> cbfMasksToTest; + int64_t minDist1 = std::min<int64_t>( pairDist[0].first, pairDist[0].second ); + int64_t minDist2 = std::numeric_limits<int64_t>::max(); + int cbfMask1 = 0; + int cbfMask2 = 0; + for( int cbfMask : { 1, 2, 3 } ) + { + if( pairDist[cbfMask].first < minDist1 ) + { + cbfMask2 = cbfMask1; minDist2 = minDist1; + cbfMask1 = cbfMask; minDist1 = pairDist[cbfMask1].first; + } + else if( pairDist[cbfMask].first < minDist2 ) + { + cbfMask2 = cbfMask; minDist2 = pairDist[cbfMask2].first; + } + } + if( cbfMask1 ) + { + cbfMasksToTest.push_back( cbfMask1 ); + } + if( cbfMask2 && ( ( minDist2 < (9*minDist1)/8 ) || ( !cbfMask1 && minDist2 < (3*minDist1)/2 ) ) ) + { + cbfMasksToTest.push_back( cbfMask2 ); + } + + return cbfMasksToTest; +} + +#endif + + // ------------------------------------------------------------------------------------------------ // Logical transform // ------------------------------------------------------------------------------------------------ diff --git a/source/Lib/CommonLib/TrQuant.h b/source/Lib/CommonLib/TrQuant.h index b6334ecafe..f762386ac6 100644 --- a/source/Lib/CommonLib/TrQuant.h +++ b/source/Lib/CommonLib/TrQuant.h @@ -103,6 +103,12 @@ public: void transformSkipQuantOneSample(TransformUnit &tu, const ComponentID &compID, const TCoeff &resiDiff, TCoeff &coeff, const uint32_t &uiPos, const QpParam &cQP, const bool bUseHalfRoundingPoint); void invTrSkipDeQuantOneSample (TransformUnit &tu, const ComponentID &compID, const TCoeff &pcCoeff, Pel &reconSample, const uint32_t &uiPos, const QpParam &cQP); +#if JVET_O0105_ICT + void invTransformICT ( const TransformUnit &tu, PelBuf &resCb, PelBuf &resCr ); + std::pair<int64_t,int64_t> fwdTransformICT ( const TransformUnit &tu, const PelBuf &resCb, const PelBuf &resCr, PelBuf& resC1, PelBuf& resC2, int jointCbCr = -1 ); + std::vector<int> selectICTCandidates ( const TransformUnit &tu, CompStorage* resCb, CompStorage* resCr ); +#endif + void invRdpcmNxN(TransformUnit& tu, const ComponentID &compID, PelBuf &pcResidual); #if RDOQ_CHROMA_LAMBDA void setLambdas ( const double lambdas[MAX_NUM_COMPONENT] ) { m_quant->setLambdas( lambdas ); } @@ -128,10 +134,17 @@ protected: bool m_scalingListEnabledFlag; private: - DepQuant *m_quant; //!< Quantizer + DepQuant *m_quant; //!< Quantizer TCoeff** m_mtsCoeffs; TCoeff m_tempInMatrix [ 48 ]; TCoeff m_tempOutMatrix[ 48 ]; +#if JVET_O0105_ICT + static const int maxAbsIctMode = 3; + void (*m_invICTMem[1+2*maxAbsIctMode])(PelBuf&,PelBuf&); + std::pair<int64_t,int64_t>(*m_fwdICTMem[1+2*maxAbsIctMode])(const PelBuf&,const PelBuf&,PelBuf&,PelBuf&); + void (**m_invICT)(PelBuf&,PelBuf&); + std::pair<int64_t,int64_t>(**m_fwdICT)(const PelBuf&,const PelBuf&,PelBuf&,PelBuf&); +#endif // forward Transform diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index f2adb9ece8..da17946c5e 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -52,6 +52,9 @@ #define JVET_O0052_TU_LEVEL_CTX_CODED_BIN_CONSTRAINT 1 // JVET-O0052 Method-1: TU-level context coded bin constraint +#define JVET_O0105_ICT 1 // JVET-O0105: inter-chroma transform (ICT) as extension of joint chroma coding (JCC) +#define JVET_O0543_ICT_ICU_ONLY 1 // JVET-O0543: ICT only in Intra CUs (was Intra slices, modified during adoption) + #define JVET_O0216_ALF_COEFF_EG3 1 // JVET-O0216/O0302/O0648: using EG3 for ALF coefficients coding #define JVET_O0256_ADJUST_THD_DEPQUANT 1 // JVET-O0256: Fast encoder with adjusted threshold in dependent quantization diff --git a/source/Lib/CommonLib/UnitTools.cpp b/source/Lib/CommonLib/UnitTools.cpp index a29072fead..5cd1f3ab5e 100644 --- a/source/Lib/CommonLib/UnitTools.cpp +++ b/source/Lib/CommonLib/UnitTools.cpp @@ -4497,6 +4497,17 @@ bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID) return mtsAllowed; } +#if JVET_O0105_ICT +int TU::getICTMode( const TransformUnit& tu, int jointCbCr ) +{ + if( jointCbCr < 0 ) + { + jointCbCr = tu.jointCbCr; + } + return g_ictModes[ tu.cs->slice->getJointCbCrSignFlag() ][ jointCbCr ]; +} +#endif + uint32_t TU::getGolombRiceStatisticsIndex(const TransformUnit &tu, const ComponentID &compID) { const bool transformSkip = tu.mtsIdx==MTS_SKIP; diff --git a/source/Lib/CommonLib/UnitTools.h b/source/Lib/CommonLib/UnitTools.h index 6bc6eb80c3..3dbe32cdb9 100644 --- a/source/Lib/CommonLib/UnitTools.h +++ b/source/Lib/CommonLib/UnitTools.h @@ -213,7 +213,9 @@ namespace TU bool needsBlockSizeTrafoScale ( const TransformUnit &tu, const ComponentID &compID ); TransformUnit* getPrevTU ( const TransformUnit &tu, const ComponentID compID ); bool getPrevTuCbfAtDepth( const TransformUnit &tu, const ComponentID compID, const int trDepth ); - +#if JVET_O0105_ICT + int getICTMode ( const TransformUnit &tu, int jointCbCr = -1 ); +#endif } uint32_t getCtuAddr (const Position& pos, const PreCalcValues &pcv); diff --git a/source/Lib/DecoderLib/CABACReader.cpp b/source/Lib/DecoderLib/CABACReader.cpp index 6abf393f2e..8575af0490 100644 --- a/source/Lib/DecoderLib/CABACReader.cpp +++ b/source/Lib/DecoderLib/CABACReader.cpp @@ -2328,6 +2328,13 @@ void CABACReader::transform_unit( TransformUnit& tu, CUCtx& cuCtx, ChromaCbfs& c bool cbfLuma = ( tu.cbf[ COMPONENT_Y ] != 0 ); bool cbfChroma = ( lumaOnly ? false : ( chromaCbfs.Cb || chromaCbfs.Cr ) ); +#if JVET_O0105_ICT + if( !lumaOnly ) + { + joint_cb_cr( tu, ( tu.cbf[COMPONENT_Cb] ? 2 : 0 ) + ( tu.cbf[COMPONENT_Cr] ? 1 : 0 ) ); + } +#endif + if( cbfLuma || cbfChroma ) { if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ) @@ -2419,17 +2426,36 @@ void CABACReader::cu_chroma_qp_offset( CodingUnit& cu ) // void residual_coding_subblock( coeffCtx ) //================================================================================ +#if JVET_O0105_ICT +void CABACReader::joint_cb_cr( TransformUnit& tu, const int cbfMask ) +{ +#if JVET_O0543_ICT_ICU_ONLY + if( ( CU::isIntra( *tu.cu ) && cbfMask ) || ( cbfMask == 3 ) ) +#else + if( cbfMask ) +#endif + { + RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__JOINT_CB_CR, tu.blocks[COMPONENT_Cr].lumaSize(), CHANNEL_TYPE_CHROMA ); + tu.jointCbCr = ( m_BinDecoder.decodeBin( Ctx::JointCbCrFlag( cbfMask-1 ) ) ? cbfMask : 0 ); + } +} +#else void CABACReader::joint_cb_cr( TransformUnit& tu ) { RExt__DECODER_DEBUG_BIT_STATISTICS_CREATE_SET_SIZE2( STATS__CABAC_BITS__JOINT_CB_CR, tu.blocks[COMPONENT_Cr].lumaSize(), CHANNEL_TYPE_CHROMA ); tu.jointCbCr = m_BinDecoder.decodeBin( Ctx::JointCbCrFlag( 0 ) ); } +#endif void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) { const CodingUnit& cu = *tu.cu; DTRACE( g_trace_ctx, D_SYNTAX, "residual_coding() etype=%d pos=(%d,%d) size=%dx%d predMode=%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height, cu.predMode ); +#if JVET_O0105_ICT + if( compID == COMPONENT_Cr && tu.jointCbCr == 3 ) + return; +#else // Joint Cb-Cr residual mode is signalled if both Cb and Cr cbfs are true if ( compID == COMPONENT_Cr && TU::getCbf( tu, COMPONENT_Cb ) ) { @@ -2439,6 +2465,7 @@ void CABACReader::residual_coding( TransformUnit& tu, ComponentID compID ) if ( tu.jointCbCr ) return; } +#endif // parse transform skip and explicit rdpcm mode mts_coding ( tu, compID ); diff --git a/source/Lib/DecoderLib/CABACReader.h b/source/Lib/DecoderLib/CABACReader.h index 72868ea7f0..670d2cc4dc 100644 --- a/source/Lib/DecoderLib/CABACReader.h +++ b/source/Lib/DecoderLib/CABACReader.h @@ -138,7 +138,11 @@ public: void residual_coding_subblock ( CoeffCodingContext& cctx, TCoeff* coeff, const int stateTransTable, int& state ); void residual_codingTS ( TransformUnit& tu, ComponentID compID ); void residual_coding_subblockTS( CoeffCodingContext& cctx, TCoeff* coeff ); +#if JVET_O0105_ICT + void joint_cb_cr ( TransformUnit& tu, const int cbfMask ); +#else void joint_cb_cr ( TransformUnit& tu ); +#endif // cross component prediction (clause 7.3.8.12) void cross_comp_pred ( TransformUnit& tu, ComponentID compID ); diff --git a/source/Lib/DecoderLib/DecCu.cpp b/source/Lib/DecoderLib/DecCu.cpp index c3c84a4b0c..31e5ca4100 100644 --- a/source/Lib/DecoderLib/DecCu.cpp +++ b/source/Lib/DecoderLib/DecCu.cpp @@ -228,10 +228,30 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) const QpParam cQP( tu, compID ); +#if JVET_O0105_ICT + if( tu.jointCbCr && isChroma(compID) ) + { + if( compID == COMPONENT_Cb ) + { + PelBuf resiCr = cs.getResiBuf( tu.blocks[ COMPONENT_Cr ] ); + if( tu.jointCbCr >> 1 ) + { + m_pcTrQuant->invTransformNxN( tu, COMPONENT_Cb, piResi, cQP ); + } + else + { + m_pcTrQuant->invTransformNxN( tu, COMPONENT_Cr, resiCr, cQP ); + } + m_pcTrQuant->invTransformICT( tu, piResi, resiCr ); + } + } + else +#else // Joint chroma residual mode: Cr uses negative of the signalled Cb residual if ( tu.jointCbCr && compID == COMPONENT_Cr ) piResi.copyAndNegate( cs.getResiBuf( tu.blocks[COMPONENT_Cb] ) ); else +#endif if( TU::getCbf( tu, compID ) ) { m_pcTrQuant->invTransformNxN( tu, compID, piResi, cQP ); @@ -243,9 +263,14 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID ) //===== reconstruction ===== flag = flag && (tu.blocks[compID].width*tu.blocks[compID].height > 4); +#if JVET_O0105_ICT + if (flag && (TU::getCbf(tu, compID) || tu.jointCbCr) && isChroma(compID) && slice.getLmcsChromaResidualScaleFlag()) + { +#else if (flag && TU::getCbf(tu, compID) && isChroma(compID) && slice.getLmcsChromaResidualScaleFlag()) { if ( !(tu.jointCbCr && compID == COMPONENT_Cr) ) // // Joint chroma residual mode: chroma scaling took place already when doing Cb +#endif piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); } if( isChroma(compID) && tu.compAlpha[compID] != 0 ) @@ -553,10 +578,30 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) const QpParam cQP(currTU, compID); +#if JVET_O0105_ICT + if( currTU.jointCbCr && isChroma(compID) ) + { + if( compID == COMPONENT_Cb ) + { + PelBuf resiCr = cs.getResiBuf( currTU.blocks[ COMPONENT_Cr ] ); + if( currTU.jointCbCr >> 1 ) + { + m_pcTrQuant->invTransformNxN( currTU, COMPONENT_Cb, resiBuf, cQP ); + } + else + { + m_pcTrQuant->invTransformNxN( currTU, COMPONENT_Cr, resiCr, cQP ); + } + m_pcTrQuant->invTransformICT( currTU, resiBuf, resiCr ); + } + } + else +#else // Joint chroma residual mode: Cr uses negative of the signalled Cb residual if ( currTU.jointCbCr && compID == COMPONENT_Cr ) resiBuf.copyAndNegate( cs.getResiBuf( currTU.blocks[COMPONENT_Cb] ) ); else +#endif if( TU::getCbf( currTU, compID ) ) { m_pcTrQuant->invTransformNxN( currTU, compID, resiBuf, cQP ); @@ -568,9 +613,15 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID ) //===== reconstruction ===== const Slice &slice = *cs.slice; +#if JVET_O0105_ICT + if (slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && isChroma(compID) && (TU::getCbf(currTU, compID) || currTU.jointCbCr) + && slice.getLmcsChromaResidualScaleFlag() && currTU.blocks[compID].width * currTU.blocks[compID].height > 4) + { +#else if (slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && isChroma(compID) && TU::getCbf(currTU, compID) && slice.getLmcsChromaResidualScaleFlag() && currTU.blocks[compID].width*currTU.blocks[compID].height > 4) { if ( !(currTU.jointCbCr && compID == COMPONENT_Cr) ) // Joint chroma residual mode: chroma scaling took place already when doing Cb +#endif resiBuf.scaleSignal(currTU.getChromaAdj(), 0, currTU.cu->cs->slice->clpRng(compID)); } if( isChroma( compID ) && currTU.compAlpha[compID] != 0 ) diff --git a/source/Lib/DecoderLib/VLCReader.cpp b/source/Lib/DecoderLib/VLCReader.cpp index 45b84cf56f..71cc2d2f11 100644 --- a/source/Lib/DecoderLib/VLCReader.cpp +++ b/source/Lib/DecoderLib/VLCReader.cpp @@ -1993,6 +1993,12 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para pcSlice->setMaxNumTriangleCand(0); } } +#if JVET_O0105_ICT + if (bChroma) + { + READ_FLAG( uiCode, "joint_cb_cr_sign_flag" ); pcSlice->setJointCbCrSignFlag( uiCode != 0 ); + } +#endif READ_SVLC( iCode, "slice_qp_delta" ); pcSlice->setSliceQp (26 + pps->getPicInitQPMinus26() + iCode); diff --git a/source/Lib/EncoderLib/CABACWriter.cpp b/source/Lib/EncoderLib/CABACWriter.cpp index 4700702c86..053fec7625 100644 --- a/source/Lib/EncoderLib/CABACWriter.cpp +++ b/source/Lib/EncoderLib/CABACWriter.cpp @@ -2211,6 +2211,14 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC } cbfChroma = ( cbf[ COMPONENT_Cb ] || cbf[ COMPONENT_Cr ] ); } + +#if JVET_O0105_ICT + if( !lumaOnly ) + { + joint_cb_cr( tu, ( cbf[COMPONENT_Cb] ? 2 : 0 ) + ( cbf[COMPONENT_Cr] ? 1 : 0 ) ); + } +#endif + if( cbfLuma || cbfChroma ) { if( cu.cs->pps->getUseDQP() && !cuCtx.isDQPCoded ) @@ -2304,16 +2312,35 @@ void CABACWriter::cu_chroma_qp_offset( const CodingUnit& cu ) // void residual_coding_subblock( coeffCtx ) //================================================================================ +#if JVET_O0105_ICT +void CABACWriter::joint_cb_cr( const TransformUnit& tu, const int cbfMask ) +{ + CHECK( tu.jointCbCr && tu.jointCbCr != cbfMask, "wrong value of jointCbCr (" << (int)tu.jointCbCr << " vs " << (int)cbfMask << ")" ); +#if JVET_O0543_ICT_ICU_ONLY + if( ( CU::isIntra( *tu.cu ) && cbfMask ) || ( cbfMask == 3 ) ) +#else + if( cbfMask ) +#endif + { + m_BinEncoder.encodeBin( tu.jointCbCr ? 1 : 0, Ctx::JointCbCrFlag( cbfMask - 1 ) ); + } +} +#else void CABACWriter::joint_cb_cr( const TransformUnit& tu ) { m_BinEncoder.encodeBin( tu.jointCbCr ? 1 : 0, Ctx::JointCbCrFlag( 0 ) ); } +#endif void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) { const CodingUnit& cu = *tu.cu; DTRACE( g_trace_ctx, D_SYNTAX, "residual_coding() etype=%d pos=(%d,%d) size=%dx%d predMode=%d\n", tu.blocks[compID].compID, tu.blocks[compID].x, tu.blocks[compID].y, tu.blocks[compID].width, tu.blocks[compID].height, cu.predMode ); +#if JVET_O0105_ICT + if( compID == COMPONENT_Cr && tu.jointCbCr == 3 ) + return; +#else // Joint Cb-Cr residual mode is signalled if both Cb and Cr cbfs are true if ( compID == COMPONENT_Cr && TU::getCbf( tu, COMPONENT_Cb ) ) { @@ -2323,6 +2350,7 @@ void CABACWriter::residual_coding( const TransformUnit& tu, ComponentID compID ) if ( tu.jointCbCr ) return; } +#endif // code transform skip and explicit rdpcm mode mts_coding ( tu, compID ); diff --git a/source/Lib/EncoderLib/CABACWriter.h b/source/Lib/EncoderLib/CABACWriter.h index f67bb0e65c..90a75be39a 100644 --- a/source/Lib/EncoderLib/CABACWriter.h +++ b/source/Lib/EncoderLib/CABACWriter.h @@ -150,7 +150,11 @@ public: void residual_coding_subblock ( CoeffCodingContext& cctx, const TCoeff* coeff, const int stateTransTable, int& state ); void residual_codingTS ( const TransformUnit& tu, ComponentID compID ); void residual_coding_subblockTS( CoeffCodingContext& cctx, const TCoeff* coeff ); +#if JVET_O0105_ICT + void joint_cb_cr ( const TransformUnit& tu, const int cbfMask ); +#else void joint_cb_cr ( const TransformUnit& tu ); +#endif // cross component prediction (clause 7.3.8.12) void cross_comp_pred ( const TransformUnit& tu, ComponentID compID ); diff --git a/source/Lib/EncoderLib/EncSlice.cpp b/source/Lib/EncoderLib/EncSlice.cpp index 01f99ec69f..a9c4120eda 100644 --- a/source/Lib/EncoderLib/EncSlice.cpp +++ b/source/Lib/EncoderLib/EncSlice.cpp @@ -1459,6 +1459,47 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32 } } + +#if JVET_O0105_ICT +void setJointCbCrModes( CodingStructure& cs, const Position topLeftLuma, const Size sizeLuma ) +{ + bool sgnFlag = true; + + if( isChromaEnabled( cs.picture->chromaFormat) ) + { + const CompArea cbArea = CompArea( COMPONENT_Cb, cs.picture->chromaFormat, Area(topLeftLuma,sizeLuma), true ); + const CompArea crArea = CompArea( COMPONENT_Cr, cs.picture->chromaFormat, Area(topLeftLuma,sizeLuma), true ); + const CPelBuf orgCb = cs.picture->getOrigBuf( cbArea ); + const CPelBuf orgCr = cs.picture->getOrigBuf( crArea ); + const int x0 = ( cbArea.x > 0 ? 0 : 1 ); + const int y0 = ( cbArea.y > 0 ? 0 : 1 ); + const int x1 = ( cbArea.x + cbArea.width < cs.picture->Cb().width ? cbArea.width : cbArea.width - 1 ); + const int y1 = ( cbArea.y + cbArea.height < cs.picture->Cb().height ? cbArea.height : cbArea.height - 1 ); + const int cbs = orgCb.stride; + const int crs = orgCr.stride; + const Pel* pCb = orgCb.buf + y0 * cbs; + const Pel* pCr = orgCr.buf + y0 * crs; + int64_t sumCbCr = 0; + + // determine inter-chroma transform sign from correlation between high-pass filtered (i.e., zero-mean) Cb and Cr planes + for( int y = y0; y < y1; y++, pCb += cbs, pCr += crs ) + { + for( int x = x0; x < x1; x++ ) + { + int cb = ( 12*(int)pCb[x] - 2*((int)pCb[x-1] + (int)pCb[x+1] + (int)pCb[x-cbs] + (int)pCb[x+cbs]) - ((int)pCb[x-1-cbs] + (int)pCb[x+1-cbs] + (int)pCb[x-1+cbs] + (int)pCb[x+1+cbs]) ); + int cr = ( 12*(int)pCr[x] - 2*((int)pCr[x-1] + (int)pCr[x+1] + (int)pCr[x-crs] + (int)pCr[x+crs]) - ((int)pCr[x-1-crs] + (int)pCr[x+1-crs] + (int)pCr[x-1+crs] + (int)pCr[x+1+crs]) ); + sumCbCr += cb*cr; + } + } + + sgnFlag = ( sumCbCr < 0 ); + } + + cs.slice->setJointCbCrSignFlag( sgnFlag ); +} +#endif + + void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, const bool bFastDeltaQP, uint32_t startCtuTsAddr, uint32_t boundingCtuTsAddr, EncLib* pEncLib ) { CodingStructure& cs = *pcPic->cs; @@ -1508,6 +1549,11 @@ void EncSlice::encodeCtus( Picture* pcPic, const bool bCompressEntireSlice, cons } } checkDisFracMmvd( pcPic, startCtuTsAddr, boundingCtuTsAddr ); + +#if JVET_O0105_ICT + setJointCbCrModes( cs, Position(0, 0), cs.area.lumaSize() ); +#endif + // for every CTU in the slice segment (may terminate sooner if there is a byte limit on the slice-segment) uint32_t startSliceRsRow = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) / widthInCtus; uint32_t startSliceRsCol = tileMap.getCtuBsToRsAddrMap(startCtuTsAddr) % widthInCtus; diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 4f876b9ac2..9827166bd1 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -5946,6 +5946,13 @@ void InterSearch::xEncodeInterResidualQT(CodingStructure &cs, Partitioner &parti { if( currArea.blocks[compID].valid() ) { +#if JVET_O0105_ICT + if( compID == COMPONENT_Cr ) + { + const int cbfMask = ( TU::getCbf( currTU, COMPONENT_Cb ) ? 2 : 0) + ( TU::getCbf( currTU, COMPONENT_Cr ) ? 1 : 0 ); + m_CABACEstimator->joint_cb_cr( currTU, cbfMask ); + } +#endif if( TU::hasCrossCompPredInfo( currTU, compID ) ) { m_CABACEstimator->cross_comp_pred( currTU, compID ); @@ -6418,6 +6425,12 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par #endif m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cRescale*cRescale)); } +#if JVET_O0105_ICT + if( isChroma( compID ) && tu.cu->cs->slice->getSliceQp() > 18 ) + { + m_pcTrQuant->setLambda( 1.05 * m_pcTrQuant->getLambda() ); + } +#endif TCoeff currAbsSum = 0; uint64_t currCompFracBits = 0; Distortion currCompDist = 0; @@ -6503,6 +6516,13 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par const bool prevCbf = ( compID == COMPONENT_Cr ? tu.cbf[COMPONENT_Cb] : false ); m_CABACEstimator->cbf_comp( *csFull, true, compArea, currDepth, prevCbf ); +#if JVET_O0105_ICT + if( compID == COMPONENT_Cr ) + { + const int cbfMask = ( tu.cbf[COMPONENT_Cb] ? 2 : 0 ) + 1; + m_CABACEstimator->joint_cb_cr( tu, cbfMask ); + } +#endif if( isCrossCPredictionAvailable ) { @@ -6613,19 +6633,52 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par bool checkJointCbCr = !tu.noResidual && (TU::getCbf(tu, COMPONENT_Cb) || TU::getCbf(tu, COMPONENT_Cr)); +#if JVET_O0105_ICT + const int channelBitDepth = sps.getBitDepth(toChannelType(COMPONENT_Cb)); + bool reshape = slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && slice.getLmcsChromaResidualScaleFlag() + && tu.blocks[COMPONENT_Cb].width * tu.blocks[COMPONENT_Cb].height > 4; + double minCostCbCr = minCost[COMPONENT_Cb] + minCost[COMPONENT_Cr]; + bool isLastBest = false; + + CompStorage orgResiCb[4], orgResiCr[4]; // 0:std, 1-3:jointCbCr + std::vector<int> jointCbfMasksToTest; if ( checkJointCbCr ) { + orgResiCb[0].create(cbArea); + orgResiCr[0].create(crArea); + orgResiCb[0].copyFrom(cs.getOrgResiBuf(cbArea)); + orgResiCr[0].copyFrom(cs.getOrgResiBuf(crArea)); + if (reshape) + { + orgResiCb[0].scaleSignal(tu.getChromaAdj(), 1, tu.cu->cs->slice->clpRng(COMPONENT_Cb)); + orgResiCr[0].scaleSignal(tu.getChromaAdj(), 1, tu.cu->cs->slice->clpRng(COMPONENT_Cr)); + } + jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates(tu, orgResiCb, orgResiCr); + } + + for (int cbfMask: jointCbfMasksToTest) +#else + if ( checkJointCbCr ) +#endif + { +#if !JVET_O0105_ICT const int channelBitDepth = sps.getBitDepth(toChannelType(COMPONENT_Cb)); double minCostCbCr = minCost[COMPONENT_Cb] + minCost[COMPONENT_Cr]; bool isLastBest = false; +#endif TCoeff currAbsSum = 0; uint64_t currCompFracBits = 0; Distortion currCompDistCb = 0; Distortion currCompDistCr = 0; double currCompCost = 0; +#if JVET_O0105_ICT + tu.jointCbCr = (uint8_t) cbfMask; + tu.compAlpha[COMPONENT_Cb] = tu.compAlpha[COMPONENT_Cr] = 0; +#else tu.jointCbCr = 1; tu.getCoeffs(COMPONENT_Cr).fill(0); +#endif const QpParam cQP(tu, COMPONENT_Cb); // note: uses tu.transformSkip[compID] @@ -6633,11 +6686,27 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par m_pcTrQuant->selectLambda(COMPONENT_Cb); #endif // Lambda is loosened for the joint mode with respect to single modes as the same residual is used for both chroma blocks +#if JVET_O0105_ICT + const int absIct = abs( TU::getICTMode(tu) ); + const double lfact = ( absIct == 1 || absIct == 3 ? 0.8 : 0.5 ); + m_pcTrQuant->setLambda( lfact * m_pcTrQuant->getLambda() ); + if( tu.cu->cs->slice->getSliceQp() > 18 ) + { + m_pcTrQuant->setLambda( 1.05 * m_pcTrQuant->getLambda() ); + } +#else m_pcTrQuant->setLambda( 0.60 * m_pcTrQuant->getLambda() ); +#endif m_CABACEstimator->getCtx() = ctxStart; m_CABACEstimator->resetBits(); +#if JVET_O0105_ICT + PelBuf cbResi = csFull->getResiBuf(cbArea); + PelBuf crResi = csFull->getResiBuf(crArea); + cbResi.copyFrom(orgResiCb[cbfMask]); + crResi.copyFrom(orgResiCr[cbfMask]); +#else // Copy the original residual into the residual buffer csFull->getResiBuf(cbArea).copyFrom(cs.getOrgResiBuf(cbArea)); csFull->getResiBuf(crArea).copyFrom(cs.getOrgResiBuf(crArea)); @@ -6648,6 +6717,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par cbResi.subtractAndHalve( crResi ); bool reshape = slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && slice.getLmcsChromaResidualScaleFlag() && tu.blocks[COMPONENT_Cb].width*tu.blocks[COMPONENT_Cb].height > 4; +#endif if ( reshape ) { @@ -6657,14 +6727,65 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par double cRescale = round((double)(1 << CSCALE_FP_PREC) / (double)(tu.getChromaAdj())); #endif m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cRescale*cRescale)); +#if !JVET_O0105_ICT cbResi.scaleSignal(tu.getChromaAdj(), 1, tu.cu->cs->slice->clpRng(COMPONENT_Cb)); +#endif + } + +#if JVET_O0105_ICT + int codedCbfMask = 0; + ComponentID codeCompId = (tu.jointCbCr >> 1 ? COMPONENT_Cb : COMPONENT_Cr); + ComponentID otherCompId = (codeCompId == COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr); + 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; + m_pcTrQuant->transformNxN(tu, codeCompId, cQP, compAbsSum, m_CABACEstimator->getCtx()); + if (compAbsSum > 0) + { + m_pcTrQuant->invTransformNxN(tu, codeCompId, codeResi, cQP); + codedCbfMask += (codeCompId == COMPONENT_Cb ? 2 : 1); + } + else + { + codeResi.fill(0); } + if (tu.jointCbCr == 3 && codedCbfMask == 2) + { + codedCbfMask = 3; + TU::setCbfAtDepth(tu, COMPONENT_Cr, tu.depth, true); + } + if (codedCbfMask && tu.jointCbCr != codedCbfMask) + { + codedCbfMask = 0; + } + currAbsSum = codedCbfMask; +#else m_pcTrQuant->transformNxN(tu, COMPONENT_Cb, cQP, currAbsSum, m_CABACEstimator->getCtx()); +#endif if (currAbsSum > 0) { +#if JVET_O0105_ICT + m_CABACEstimator->cbf_comp(cs, codedCbfMask >> 1, cbArea, currDepth, false); + m_CABACEstimator->cbf_comp(cs, codedCbfMask & 1, crArea, currDepth, codedCbfMask >> 1); + m_CABACEstimator->joint_cb_cr(tu, codedCbfMask); + if (codedCbfMask >> 1) + m_CABACEstimator->residual_coding(tu, COMPONENT_Cb); + if (codedCbfMask & 1) + m_CABACEstimator->residual_coding(tu, COMPONENT_Cr); + currCompFracBits = m_CABACEstimator->getEstFracBits(); + + m_pcTrQuant->invTransformICT(tu, cbResi, crResi); + if (reshape) + { + cbResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(COMPONENT_Cb)); + crResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(COMPONENT_Cr)); + } +#else // Set cfb also for Cr TU::setCbfAtDepth (tu, COMPONENT_Cr, tu.depth, true); @@ -6682,6 +6803,7 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par cbResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(COMPONENT_Cb));; crResi.copyAndNegate( cbResi ); +#endif currCompDistCb = m_pcRdCost->getDistPart(csFull->getOrgResiBuf(cbArea), cbResi, channelBitDepth, COMPONENT_Cb, DF_SSE); currCompDistCr = m_pcRdCost->getDistPart(csFull->getOrgResiBuf(crArea), crResi, channelBitDepth, COMPONENT_Cr, DF_SSE); @@ -6702,7 +6824,18 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par uiSingleDistComp[COMPONENT_Cb] = currCompDistCb; uiSingleDistComp[COMPONENT_Cr] = currCompDistCr; minCostCbCr = currCompCost; +#if JVET_O0105_ICT + isLastBest = (cbfMask == jointCbfMasksToTest.back()); + if (!isLastBest) + { + bestTU.copyComponentFrom(tu, COMPONENT_Cb); + bestTU.copyComponentFrom(tu, COMPONENT_Cr); + saveCS.getResiBuf(cbArea).copyFrom(csFull->getResiBuf(cbArea)); + saveCS.getResiBuf(crArea).copyFrom(csFull->getResiBuf(crArea)); + } +#else isLastBest = true; +#endif } if( !isLastBest ) @@ -6745,6 +6878,13 @@ void InterSearch::xEstimateInterResidualQT(CodingStructure &cs, Partitioner &par continue; if (tu.blocks[compID].valid()) { +#if JVET_O0105_ICT + if( compID == COMPONENT_Cr ) + { + const int cbfMask = ( TU::getCbf( tu, COMPONENT_Cb ) ? 2 : 0 ) + ( TU::getCbf( tu, COMPONENT_Cr ) ? 1 : 0 ); + m_CABACEstimator->joint_cb_cr(tu, cbfMask); + } +#endif if( cs.pps->getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && isChroma(compID) && uiAbsSum[COMPONENT_Y] ) { m_CABACEstimator->cross_comp_pred( tu, compID ); diff --git a/source/Lib/EncoderLib/IntraSearch.cpp b/source/Lib/EncoderLib/IntraSearch.cpp index c403949248..250a2d0b3f 100644 --- a/source/Lib/EncoderLib/IntraSearch.cpp +++ b/source/Lib/EncoderLib/IntraSearch.cpp @@ -1645,6 +1645,13 @@ void IntraSearch::xEncCoeffQT( CodingStructure &cs, Partitioner &partitioner, co if( currArea.blocks[compID].valid() ) { +#if JVET_O0105_ICT + if( compID == COMPONENT_Cr ) + { + const int cbfMask = ( TU::getCbf( currTU, COMPONENT_Cb ) ? 2 : 0 ) + ( TU::getCbf( currTU, COMPONENT_Cr ) ? 1 : 0 ); + m_CABACEstimator->joint_cb_cr( currTU, cbfMask ); + } +#endif if( TU::hasCrossCompPredInfo( currTU, compID ) ) { m_CABACEstimator->cross_comp_pred( currTU, compID ); @@ -1695,7 +1702,12 @@ uint64_t IntraSearch::xGetIntraFracBitsQTSingleChromaComponent( CodingStructure TransformUnit &currTU = *cs.getTU( currArea.blocks[partitioner.chType], partitioner.chType ); //cbf coding +#if JVET_O0105_ICT + const bool prevCbf = ( compID == COMPONENT_Cr ? TU::getCbfAtDepth( currTU, COMPONENT_Cb, partitioner.currTrDepth ) : false ); + m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, partitioner.currTrDepth ), currArea.blocks[compID], partitioner.currTrDepth - 1, prevCbf ); +#else m_CABACEstimator->cbf_comp( cs, TU::getCbfAtDepth( currTU, compID, partitioner.currTrDepth ), currArea.blocks[compID], partitioner.currTrDepth - 1 ); +#endif //coeffs coding and cross comp coding if( TU::hasCrossCompPredInfo( currTU, compID ) ) { @@ -1724,6 +1736,17 @@ uint64_t IntraSearch::xGetIntraFracBitsQTChroma(TransformUnit& currTU, const Com if ( currTU.jointCbCr ) { +#if JVET_O0105_ICT + const int cbfMask = ( TU::getCbf( currTU, COMPONENT_Cb ) ? 2 : 0 ) + ( TU::getCbf( currTU, COMPONENT_Cr ) ? 1 : 0 ); + m_CABACEstimator->cbf_comp( cs, cbfMask>>1, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false ); + m_CABACEstimator->cbf_comp( cs, cbfMask &1, currTU.blocks[ COMPONENT_Cr ], currTU.depth, cbfMask>>1 ); + if( cbfMask ) + m_CABACEstimator->joint_cb_cr( currTU, cbfMask ); + if( cbfMask >> 1 ) + m_CABACEstimator->residual_coding( currTU, COMPONENT_Cb ); + if( cbfMask & 1 ) + m_CABACEstimator->residual_coding( currTU, COMPONENT_Cr ); +#else if ( TU::getCbf( currTU, COMPONENT_Cb ) ) { m_CABACEstimator->cbf_comp( cs, true, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false ); @@ -1735,16 +1758,31 @@ uint64_t IntraSearch::xGetIntraFracBitsQTChroma(TransformUnit& currTU, const Com m_CABACEstimator->cbf_comp( cs, false, currTU.blocks[ COMPONENT_Cb ], currTU.depth, false ); m_CABACEstimator->cbf_comp( cs, false, currTU.blocks[ COMPONENT_Cr ], currTU.depth, false ); } +#endif } else { if ( compID == COMPONENT_Cb ) m_CABACEstimator->cbf_comp( cs, TU::getCbf( currTU, compID ), currTU.blocks[ compID ], currTU.depth, false ); else +#if JVET_O0105_ICT + { + const bool cbCbf = TU::getCbf( currTU, COMPONENT_Cb ); + const bool crCbf = TU::getCbf( currTU, compID ); + const int cbfMask = ( cbCbf ? 2 : 0 ) + ( crCbf ? 1 : 0 ); + m_CABACEstimator->cbf_comp( cs, crCbf, currTU.blocks[ compID ], currTU.depth, cbCbf ); + m_CABACEstimator->joint_cb_cr( currTU, cbfMask ); + } +#else m_CABACEstimator->cbf_comp( cs, TU::getCbf( currTU, compID ), currTU.blocks[ compID ], currTU.depth, TU::getCbf( currTU, COMPONENT_Cb ) ); +#endif } +#if JVET_O0105_ICT + if( !currTU.jointCbCr && TU::getCbf( currTU, compID ) ) +#else if( TU::getCbf( currTU, compID ) ) +#endif { m_CABACEstimator->residual_coding( currTU, compID ); } @@ -1789,6 +1827,9 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp //===== init availability pattern ===== +#if JVET_O0105_ICT + CHECK( tu.jointCbCr && compID == COMPONENT_Cr, "wrong combination of compID and jointCbCr" ); +#endif bool jointCbCr = tu.jointCbCr && compID == COMPONENT_Cb; if ( compID == COMPONENT_Y ) @@ -1838,6 +1879,10 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp const Slice &slice = *cs.slice; bool flag = slice.getLmcsEnabledFlag() && (slice.isIntra() || (!slice.isIntra() && m_pcReshape->getCTUFlag())); +#if JVET_O0105_ICT + if (isLuma(compID)) + { +#endif if (flag && slice.getLmcsChromaResidualScaleFlag() && isChroma(compID)) { const Area area = tu.Y().valid() ? tu.Y() : Area(recalcPosition(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].pos()), recalcSize(tu.chromaFormat, tu.chType, CHANNEL_TYPE_LUMA, tu.blocks[tu.chType].size())); @@ -1878,6 +1923,9 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp } CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, false); } +#if JVET_O0105_ICT + } +#endif //===== transform and quantization ===== //--- init rate estimation arrays for RDOQ --- @@ -1900,8 +1948,10 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp double cResScale = round((double)(1 << CSCALE_FP_PREC) / (double)cResScaleInv); #endif m_pcTrQuant->setLambda(m_pcTrQuant->getLambda() / (cResScale*cResScale)); +#if !JVET_O0105_ICT if ( !jointCbCr ) // Joint CbCr signal is to be scaled in the case of joint chroma piResi.scaleSignal(cResScaleInv, 1, tu.cu->cs->slice->clpRng(compID)); +#endif } const CompArea &crArea = tu.blocks [ COMPONENT_Cr ]; @@ -1912,6 +1962,7 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp if ( jointCbCr ) { +#if !JVET_O0105_ICT // Get Cr prediction and residual crResi.copyFrom( crOrg ); crResi.subtract( crPred ); @@ -1922,13 +1973,30 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp // Scale the joint signal if ( flag && slice.getLmcsChromaResidualScaleFlag() ) piResi.scaleSignal(tu.getChromaAdj(), 1, tu.cu->cs->slice->clpRng(compID)); - +#endif // Lambda is loosened for the joint mode with respect to single modes as the same residual is used for both chroma blocks +#if JVET_O0105_ICT + const int absIct = abs( TU::getICTMode(tu) ); + const double lfact = ( absIct == 1 || absIct == 3 ? 0.8 : 0.5 ); + m_pcTrQuant->setLambda( lfact * m_pcTrQuant->getLambda() ); +#else m_pcTrQuant->setLambda( 0.60 * m_pcTrQuant->getLambda() ); +#endif + } +#if JVET_O0105_ICT + if( isChroma(compID) && tu.cu->cs->slice->getSliceQp() > 18 ) + { + m_pcTrQuant->setLambda( 1.3 * m_pcTrQuant->getLambda() ); } +#else else if ( isChroma(compID) && tu.cu->cs->slice->getSliceQp() > 18 ) m_pcTrQuant->setLambda( 1.10 * m_pcTrQuant->getLambda() ); +#endif +#if JVET_O0105_ICT + if( isLuma(compID) ) + { +#endif double diagRatio = 0, horVerRatio = 0; if( trModes ) @@ -1961,15 +2029,70 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp { piResi.fill(0); } +#if JVET_O0105_ICT + } + else // chroma + { + int codedCbfMask = 0; + ComponentID codeCompId = ( tu.jointCbCr ? ( tu.jointCbCr>>1 ? COMPONENT_Cb : COMPONENT_Cr ) : compID ); + if( tu.jointCbCr ) + { + ComponentID otherCompId = ( codeCompId==COMPONENT_Cr ? COMPONENT_Cb : COMPONENT_Cr ); + tu.getCoeffs( otherCompId ).fill(0); // do we need that? + TU::setCbfAtDepth (tu, otherCompId, tu.depth, false ); + } + PelBuf& codeResi = ( codeCompId == COMPONENT_Cr ? crResi : piResi ); + uiAbsSum = 0; + m_pcTrQuant->transformNxN( tu, codeCompId, cQP, uiAbsSum, m_CABACEstimator->getCtx() ); + DTRACE( g_trace_ctx, D_TU_ABS_SUM, "%d: comp=%d, abssum=%d\n", DTRACE_GET_COUNTER( g_trace_ctx, D_TU_ABS_SUM ), codeCompId, uiAbsSum ); + if( uiAbsSum > 0 ) + { + m_pcTrQuant->invTransformNxN(tu, codeCompId, codeResi, cQP); + codedCbfMask += ( codeCompId == COMPONENT_Cb ? 2 : 1 ); + } + else + { + codeResi.fill(0); + } + + if( tu.jointCbCr ) + { + if( tu.jointCbCr == 3 && codedCbfMask == 2 ) + { + codedCbfMask = 3; + TU::setCbfAtDepth (tu, COMPONENT_Cr, tu.depth, true ); + } + if( tu.jointCbCr != codedCbfMask ) + { + ruiDist = std::numeric_limits<Distortion>::max(); + return; + } + m_pcTrQuant->invTransformICT( tu, piResi, crResi ); + uiAbsSum = codedCbfMask; + } + } +#endif //===== reconstruction ===== if ( flag && uiAbsSum > 0 && isChroma(compID) && slice.getLmcsChromaResidualScaleFlag() ) { piResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(compID)); +#if JVET_O0105_ICT + if( jointCbCr ) + { + crResi.scaleSignal(tu.getChromaAdj(), 0, tu.cu->cs->slice->clpRng(COMPONENT_Cr)); + } +#endif } if (bUseCrossCPrediction) { CrossComponentPrediction::crossComponentPrediction(tu, compID, cs.getResiBuf(tu.Y()), piResi, piResi, true); +#if JVET_O0105_ICT + if( jointCbCr ) + { + CrossComponentPrediction::crossComponentPrediction(tu, COMPONENT_Cr, cs.getResiBuf(tu.Y()), crResi, crResi, true); + } +#endif } if (slice.getLmcsEnabledFlag() && m_pcReshape->getCTUFlag() && compID == COMPONENT_Y) @@ -1980,8 +2103,19 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp piReco.reconstruct(tmpPred, piResi, cs.slice->clpRng(compID)); } else +#if JVET_O0105_ICT + { + piReco.reconstruct(piPred, piResi, cs.slice->clpRng( compID )); + if( jointCbCr ) + { + crReco.reconstruct(crPred, crResi, cs.slice->clpRng( COMPONENT_Cr )); + } + } +#else piReco.reconstruct(piPred, piResi, cs.slice->clpRng( compID )); +#endif +#if !JVET_O0105_ICT if ( jointCbCr ) { // Cr uses negative of the signalled Cb residual @@ -2013,6 +2147,7 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE ); } } +#endif //===== update distortion ===== #if WCG_EXT @@ -2029,12 +2164,28 @@ void IntraSearch::xIntraCodingTUBlock(TransformUnit &tu, const ComponentID &comp ruiDist += m_pcRdCost->getDistPart(piOrg, tmpRecLuma, sps.getBitDepth(toChannelType(compID)), compID, DF_SSE_WTD, &orgLuma); } else +#if JVET_O0105_ICT + { ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma); + if( jointCbCr ) + { + ruiDist += m_pcRdCost->getDistPart(crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE_WTD, &orgLuma); + } + } +#else + ruiDist += m_pcRdCost->getDistPart(piOrg, piReco, bitDepth, compID, DF_SSE_WTD, &orgLuma); +#endif } else #endif { ruiDist += m_pcRdCost->getDistPart( piOrg, piReco, bitDepth, compID, DF_SSE ); +#if JVET_O0105_ICT + if( jointCbCr ) + { + ruiDist += m_pcRdCost->getDistPart( crOrg, crReco, bitDepth, COMPONENT_Cr, DF_SSE ); + } +#endif } } @@ -2537,7 +2688,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio TransformUnit &currTU = *cs.getTU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); const PredictionUnit &pu = *cs.getPU( currArea.chromaPos(), CHANNEL_TYPE_CHROMA ); +#if JVET_O0105_ICT + bool lumaUsesISP = false; +#else bool lumaUsesISP = !CS::isDualITree( cs ) && currTU.cu->ispMode; +#endif uint32_t currDepth = partitioner.currTrDepth; const PPS &pps = *cs.pps; ChromaCbfs cbfs ( false ); @@ -2610,6 +2765,65 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio predIntraAng( COMPONENT_Cr, piPredCr, pu); } +#if JVET_O0105_ICT + // determination of chroma residuals including reshaping and cross-component prediction + //----- get chroma residuals ----- + PelBuf resiCb = cs.getResiBuf(cbArea); + PelBuf resiCr = cs.getResiBuf(crArea); + resiCb.copyFrom( cs.getOrgBuf (cbArea) ); + resiCr.copyFrom( cs.getOrgBuf (crArea) ); + resiCb.subtract( piPredCb ); + resiCr.subtract( piPredCr ); + + //----- get reshape parameter ---- + bool doReshaping = ( cs.slice->getLmcsEnabledFlag() && cs.slice->getLmcsChromaResidualScaleFlag() + && (cs.slice->isIntra() || m_pcReshape->getCTUFlag()) && (cbArea.width * cbArea.height > 4) ); + if( doReshaping ) + { + const Area area = currTU.Y().valid() ? currTU.Y() : Area(recalcPosition(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].pos()), recalcSize(currTU.chromaFormat, currTU.chType, CHANNEL_TYPE_LUMA, currTU.blocks[currTU.chType].size())); + const CompArea &areaY = CompArea(COMPONENT_Y, currTU.chromaFormat, area ); + PelBuf piPredY; + piPredY = cs.picture->getPredBuf(areaY); + const Pel avgLuma = piPredY.computeAvg(); + int adj = m_pcReshape->calculateChromaAdj(avgLuma); + currTU.setChromaAdj(adj); + } + + //----- get cross component prediction parameters ----- + bool checkCrossComponentPrediction = PU::isChromaIntraModeCrossCheckMode( pu ) && pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf( currTU, COMPONENT_Y ); + int compAlpha[MAX_NUM_COMPONENT] = { 0, 0, 0 }; + if( checkCrossComponentPrediction ) + { + compAlpha[COMPONENT_Cb] = xCalcCrossComponentPredictionAlpha( currTU, COMPONENT_Cb, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() ); + compAlpha[COMPONENT_Cr] = xCalcCrossComponentPredictionAlpha( currTU, COMPONENT_Cr, m_pcEncCfg->getUseReconBasedCrossCPredictionEstimate() ); + if( compAlpha[COMPONENT_Cb] == 0 && compAlpha[COMPONENT_Cr] == 0 ) + { + checkCrossComponentPrediction = false; + } + } + + //===== store original residual signals (std and crossCompPred) ===== + CompStorage orgResiCb[5], orgResiCr[5]; // 0:std, 1-3:jointCbCr (placeholder at this stage), 4:crossComp + for( int k = 0; k < (checkCrossComponentPrediction?5:1); k+=4 ) + { + orgResiCb[k].create( cbArea ); + orgResiCr[k].create( crArea ); + if( k >= 4 ) { + CrossComponentPrediction::crossComponentPrediction( currTU, COMPONENT_Cb, cs.getResiBuf(currTU.Y()), resiCb, orgResiCb[k], false); + CrossComponentPrediction::crossComponentPrediction( currTU, COMPONENT_Cr, cs.getResiBuf(currTU.Y()), resiCr, orgResiCr[k], false); + } else { + orgResiCb[k].copyFrom( resiCb ); + orgResiCr[k].copyFrom( resiCr ); + } + if( doReshaping ) + { + int cResScaleInv = currTU.getChromaAdj(); + orgResiCb[k].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cb) ); + orgResiCr[k].scaleSignal( cResScaleInv, 1, currTU.cu->cs->slice->clpRng(COMPONENT_Cr) ); + } + } +#endif + for( uint32_t c = COMPONENT_Cb; c < numTBlocks; c++) { const ComponentID compID = ComponentID(c); @@ -2620,8 +2834,9 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio Distortion singleDistCTmp = 0; double singleCostTmp = 0; +#if !JVET_O0105_ICT const bool checkCrossComponentPrediction = PU::isChromaIntraModeCrossCheckMode( pu ) && pps.getPpsRangeExtension().getCrossComponentPredictionEnabledFlag() && TU::getCbf( currTU, COMPONENT_Y ); - +#endif const int crossCPredictionModesToTest = checkCrossComponentPrediction ? 2 : 1; const int totalModesToTest = crossCPredictionModesToTest; const bool isOneMode = false; @@ -2639,7 +2854,14 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio { for (int crossCPredictionModeId = 0; crossCPredictionModeId < crossCPredictionModesToTest; crossCPredictionModeId++) { +#if JVET_O0105_ICT + resiCb.copyFrom( orgResiCb[4*crossCPredictionModeId] ); + resiCr.copyFrom( orgResiCr[4*crossCPredictionModeId] ); + + currTU.compAlpha [compID] = ( crossCPredictionModeId ? compAlpha[compID] : 0 ); +#else currTU.compAlpha [compID] = 0; +#endif currModeId++; @@ -2736,32 +2958,96 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio double bestCostCbCr = bestCostCb + bestCostCr; Distortion bestDistCbCr = bestDistCb + bestDistCr; int bestJointCbCr = 0; +#if JVET_O0105_ICT + bool lastIsBest = false; + std::vector<int> jointCbfMasksToTest; + if( TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr) ) + { + jointCbfMasksToTest = m_pcTrQuant->selectICTCandidates( currTU, orgResiCb, orgResiCr ); + } + + for( int cbfMask : jointCbfMasksToTest ) +#else bool checkJointCbCr = TU::getCbf(tmpTU, COMPONENT_Cb) || TU::getCbf(tmpTU, COMPONENT_Cr); if ( checkJointCbCr ) +#endif { Distortion distTmp = 0; +#if JVET_O0105_ICT + currTU.jointCbCr = (uint8_t)cbfMask; +#else currTU.jointCbCr = 1; +#endif currTU.compAlpha[COMPONENT_Cb] = 0; + currTU.compAlpha[COMPONENT_Cr] = 0; m_CABACEstimator->getCtx() = ctxStartTU; +#if JVET_O0105_ICT + resiCb.copyFrom( orgResiCb[cbfMask] ); + resiCr.copyFrom( orgResiCr[cbfMask] ); + xIntraCodingTUBlock( currTU, COMPONENT_Cb, false, distTmp, 0 ); + + double costTmp = std::numeric_limits<double>::max(); + if( distTmp < std::numeric_limits<Distortion>::max() ) + { + uint64_t bits = xGetIntraFracBitsQTChroma( currTU, COMPONENT_Cb ); + costTmp = m_pcRdCost->calcRdCost( bits, distTmp ); + } +#else xIntraCodingTUBlock( currTU, COMPONENT_Cb, false, distTmp, 0 ); uint64_t bits = xGetIntraFracBitsQTChroma( currTU, COMPONENT_Cb ); double costTmp = m_pcRdCost->calcRdCost( bits, distTmp ); +#endif if( costTmp < bestCostCbCr ) { bestCostCbCr = costTmp; bestDistCbCr = distTmp; +#if JVET_O0105_ICT + bestJointCbCr = currTU.jointCbCr; + + // store data + if( cbfMask != jointCbfMasksToTest.back() ) + { +#if KEEP_PRED_AND_RESI_SIGNALS + saveCS.getOrgResiBuf(cbArea).copyFrom(cs.getOrgResiBuf(cbArea)); + saveCS.getOrgResiBuf(crArea).copyFrom(cs.getOrgResiBuf(crArea)); +#endif + saveCS.getPredBuf (cbArea).copyFrom(cs.getPredBuf (cbArea)); + saveCS.getPredBuf (crArea).copyFrom(cs.getPredBuf (crArea)); + if( keepResi ) + { + saveCS.getResiBuf (cbArea).copyFrom(cs.getResiBuf (cbArea)); + saveCS.getResiBuf (crArea).copyFrom(cs.getResiBuf (crArea)); + } + saveCS.getRecoBuf (cbArea).copyFrom(cs.getRecoBuf (cbArea)); + saveCS.getRecoBuf (crArea).copyFrom(cs.getRecoBuf (crArea)); + + tmpTU.copyComponentFrom(currTU, COMPONENT_Cb); + tmpTU.copyComponentFrom(currTU, COMPONENT_Cr); + + ctxBest = m_CABACEstimator->getCtx(); + } + else + { + lastIsBest = true; + } +#else bestJointCbCr = 1; +#endif } } // Retrieve the best CU data (unless it was the very last one tested) +#if JVET_O0105_ICT + if ( !( maxModesTested == 1 && jointCbfMasksToTest.empty() ) && !lastIsBest ) +#else if ( !(maxModesTested == 1 && !checkJointCbCr) && bestJointCbCr == 0 ) +#endif { #if KEEP_PRED_AND_RESI_SIGNALS cs.getPredBuf (cbArea).copyFrom(saveCS.getPredBuf (cbArea)); @@ -2795,7 +3081,11 @@ ChromaCbfs IntraSearch::xRecurIntraChromaCodingQT( CodingStructure &cs, Partitio cbfs.cbf(COMPONENT_Cb) = TU::getCbf(currTU, COMPONENT_Cb); cbfs.cbf(COMPONENT_Cr) = TU::getCbf(currTU, COMPONENT_Cr); +#if JVET_O0105_ICT + currTU.jointCbCr = ( (cbfs.cbf(COMPONENT_Cb) + cbfs.cbf(COMPONENT_Cr)) ? bestJointCbCr : 0 ); +#else currTU.jointCbCr = cbfs.cbf(COMPONENT_Cb) ? bestJointCbCr : 0; +#endif cs.dist += bestDistCbCr; } } diff --git a/source/Lib/EncoderLib/VLCWriter.cpp b/source/Lib/EncoderLib/VLCWriter.cpp index cfa58352f8..7d6f17a6bb 100644 --- a/source/Lib/EncoderLib/VLCWriter.cpp +++ b/source/Lib/EncoderLib/VLCWriter.cpp @@ -1375,6 +1375,13 @@ void HLSWriter::codeSliceHeader ( Slice* pcSlice ) pcSlice->setMaxNumTriangleCand(0); } } +#if JVET_O0105_ICT + if (chromaEnabled) + { + WRITE_FLAG( pcSlice->getJointCbCrSignFlag() ? 1 : 0, "joint_cb_cr_sign_flag" ); + } +#endif + int iCode = pcSlice->getSliceQp() - ( pcSlice->getPPS()->getPicInitQPMinus26() + 26 ); WRITE_SVLC( iCode, "slice_qp_delta" ); if (pcSlice->getPPS()->getSliceChromaQpFlag()) -- GitLab