Commit 0fffdf5b authored by Christian Helmrich's avatar Christian Helmrich Committed by Xiang Li

JVET-O0105 with JVET-O0543: joint chroma coding extension

parent c81b8ade
......@@ -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
......@@ -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
......
......@@ -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);
}
......
......@@ -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];
}
......
......@@ -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 );
......
......@@ -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 ) ) );
......
......@@ -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;
......
......@@ -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; }
......
......@@ -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
// ------------------------------------------------------------------------------------------------
......
......@@ -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
......
......@@ -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
......
......@@ -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;
......
......@@ -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);
......
......@@ -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 );
......
......@@ -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 );
......
......@@ -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 )
......
......@@ -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);
......
......@@ -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