Commit 504bf391 authored by Christian Helmrich's avatar Christian Helmrich

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

parent 2637b3c2
......@@ -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_HHI
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_HHI
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_HHI
struct CompStorage : public PelBuf
{
CompStorage () { m_memory = nullptr; }
~CompStorage() { 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()
{
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_HHI
{ 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_HHI
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_HHI
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,16 @@ QpParam::QpParam(const TransformUnit& tu, const ComponentID &compIDX, const int
if (isChroma(compID))
{
#if JVET_O0105_ICT_HHI
const int absIct = abs( TU::getICTMode(tu) );
const bool useJQP = ( absIct == 2 || absIct == 4 );
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];
}
......
......@@ -97,6 +97,9 @@ Slice::Slice()
, m_bTestWeightBiPred ( false )
, m_substreamSizes ( )
, m_cabacInitFlag ( false )
#if JVET_O0105_ICT_HHI
, 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_HHI
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_HHI
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_HHI
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_HHI
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_HHI
int64_t sqr( int d ) { return d*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 += sqr( cbx - c1[x] ) + sqr( crx - (c1[x]>>1) );
}
else if ( signedMode == -1 )
{
c1[x] = Pel( ( 4*cbx - 2*crx ) / 5 );
d1 += sqr( cbx - c1[x] ) + sqr( crx - (-c1[x]>>1) );
}
else if ( signedMode == 2 )
{
c1[x] = Pel( ( cbx + crx ) / 2 );
d1 += sqr( cbx - c1[x] ) + sqr( crx - c1[x] );
}
else if ( signedMode == -2 )
{
c1[x] = Pel( ( cbx - crx ) / 2 );
d1 += sqr( cbx - c1[x] ) + sqr( crx + c1[x] );
}
else if ( signedMode == 3 )
{
c2[x] = Pel( ( 4*crx + 2*cbx ) / 5 );
d1 += sqr( cbx - (c2[x]>>1) ) + sqr( crx - c2[x] );
}
else if ( signedMode == -3 )
{
c2[x] = Pel( ( 4*crx - 2*cbx ) / 5 );
d1 += sqr( cbx - (-c2[x]>>1) ) + sqr( crx - c2[x] );
}
else
{
d1 += sqr( cbx );
d2 += sqr( 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_HHI
{
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_HHI
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_HHI_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_HHI
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_HHI
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
......
......@@ -50,6 +50,9 @@
#include <assert.h>
#include <cassert>
#define JVET_O0105_ICT_HHI 1 // JVET-O0105: inter-chroma transform (ICT) as extension of joint chroma coding (JCC)
#define JVET_O0543_ICT_HHI_ICU_ONLY 1 // JVET-O0543: ICT only in Intra CUs (was Intra slices, modified during adoption)
#define JVET_O0247_ALF_CTB_CODING_REDUNDANCY_REMOVAL 1 // JVET-O0247: not signal APS index when number APS is 2
#define JVET_O0288_UNIFY_ALF_SLICE_TYPE_REMOVAL 1 // JVET-O0288: remove slice type dependency in ALF
......
......@@ -4489,6 +4489,18 @@ bool TU::isMTSAllowed(const TransformUnit &tu, const ComponentID compID)
return mtsAllowed;
}
#if JVET_O0105_ICT_HHI
int TU::getICTMode( const TransformUnit& tu, int jointCbCr )
{
if( jointCbCr < 0 )
{
jointCbCr = tu.jointCbCr;
}
static const int g_ictModes[2][4] = { { 0, 3, 1, 2 }, { 0, -3, -1, -2 } };
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_HHI
int getICTMode ( const TransformUnit &tu, int jointCbCr = -1 );
#endif
}
uint32_t getCtuAddr (const Position& pos, const PreCalcValues &pcv);
......
......@@ -2318,6 +2318,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_HHI
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 )
......@@ -2409,17 +2416,36 @@ void CABACReader::cu_chroma_qp_offset( CodingUnit& cu )
// void residual_coding_subblock( coeffCtx )
//================================================================================
#if JVET_O0105_ICT_HHI
void CABACReader::joint_cb_cr( TransformUnit& tu, const int cbfMask )
{
#if JVET_O0543_ICT_HHI_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_HHI
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 ) )
{
......@@ -2429,6 +2455,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_HHI
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 );
......
......@@ -226,10 +226,30 @@ void DecCu::xIntraRecBlk( TransformUnit& tu, const ComponentID compID )
const QpParam cQP( tu, compID );
#if JVET_O0105_ICT_HHI
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 );
......@@ -241,9 +261,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_HHI
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 )
......@@ -546,10 +571,30 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID )
const QpParam cQP(currTU, compID);
#if JVET_O0105_ICT_HHI
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 );
......@@ -561,9 +606,15 @@ void DecCu::xDecodeInterTU( TransformUnit & currTU, const ComponentID compID )
//===== reconstruction =====
const Slice &slice = *cs.slice;
#if JVET_O0105_ICT_HHI
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 )
......
......@@ -1967,6 +1967,12 @@ void HLSyntaxReader::parseSliceHeader (Slice* pcSlice, ParameterSetManager *para
pcSlice->setMaxNumTriangleCand(0);
}
}
#if JVET_O0105_ICT_HHI
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);
......
......@@ -2197,6 +2197,14 @@ void CABACWriter::transform_unit( const TransformUnit& tu, CUCtx& cuCtx, ChromaC
}
cbfChroma = ( cbf[ COMPONENT_Cb ] || cbf[ COMPONENT_Cr ] );
}
#if JVET_O0105_ICT_HHI
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 )
......@@ -2290,16 +2298,35 @@ void CABACWriter::cu_chroma_qp_offset( const CodingUnit& cu )
// void residual_coding_subblock( coeffCtx )
//================================================================================
#if JVET_O0105_ICT_HHI
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_HHI_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_HHI
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 ) )
{
......@@ -2309,6 +2336,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 );
......
......@@ -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_HHI
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 );
......
......@@ -1459,6 +1459,45 @@ void EncSlice::checkDisFracMmvd( Picture* pcPic, uint32_t startCtuTsAddr, uint32
}
}
#if JVET_O0105_ICT_HHI
void setJointCbCrModes( CodingStructure& cs, const Position topLeftLuma, const Size sizeLuma )
{
bool sgnFlag = true;
if( isChromaEnabled( cs.picture->chromaFormat) )
{
const CompArea cbArea = CompArea(