Commit bb880dc7 authored by Kenneth Andersson's avatar Kenneth Andersson
Browse files

JVET-V0078: QP control for very smooth blocks

parent 633ea8b1
......@@ -1501,6 +1501,42 @@ For Cb component with BT.2020 container use 1.14; for BT.709 material and 1.04 f
For Cr component with BT.2020 container use 1.79; for BT.709 material and 1.39 for P3 material.
\\
\Option{SmoothQPReductionEnable} &
\Default{0} &
Enable QP reduction for smooth blocks according to a QP reduction model:
$Clip3(SmoothQPReductionLimit, 0, SmoothQPReductionModelScale*QP+SmoothQPReductionModelOffset)$.
The QP reduction model is used when SAD is less than SmoothQPReductionThreshold * number of samples in block.
Where SAD is defined as the sum of absolute differences between original luma samples and luma samples predicted by a 2nd order polynomial model.
The model parameters are determined by a least square fit to original luma samples on a granularity of 64x64 samples.
\\
\Option{SmoothQPReductionThreshold} &
\Default{3.0} &
Threshold parameter for smoothness.
\\
\Option{SmoothQPReductionModelScale} &
\Default{-1.0} &
Scale parameter of the QP reduction model.
\\
\Option{SmoothQPReductionModelOffset} &
\Default{27.0} &
Offset parameter of the QP reduction model.
\\
\Option{SmoothQPReductionLimit} &
\Default{-16.0} &
Threshold parameter for controlling amount of QP reduction by the QP reduction model.
\\
\Option{SmoothQPReductionPeriodicity} &
\Default{1} &
Periodicity parameter for application of the QP reduction model. 1: all frames, 0: only intra pictures, 2: every second frame, etc.
\\
\Option{SliceChromaQPOffsetPeriodicity} &
\Default{0} &
Defines the periodicity for inter slices that use the slice-level chroma QP offsets, as defined by SliceCbQpOffsetIntraOrPeriodic and SliceCrQpOffsetIntraOrPeriodic. A value of 0 disables the periodicity. It is intended to be used in low-delay configurations where an regular intra period is not defined.
......
......@@ -930,6 +930,14 @@ Bool TAppEncCfg::parseCfg( Int argc, TChar* argv[] )
#if ADAPTIVE_QP_SELECTION
("AdaptiveQpSelection,-aqps", m_bUseAdaptQpSelect, false, "AdaptiveQpSelection")
#endif
#if JVET_V0078
("SmoothQPReductionEnable", m_bSmoothQPReductionEnable, false, "Enable QP reduction for smooth blocks according to: Clip3(SmoothQPReductionLimit, 0, SmoothQPReductionModelScale*baseQP+SmoothQPReductionModelOffset)")
("SmoothQPReductionThreshold", m_dSmoothQPReductionThreshold, 3.0, "Threshold parameter for smoothness (SmoothQPReductionThreshold * number of samples in block)")
("SmoothQPReductionModelScale", m_dSmoothQPReductionModelScale, -1.0, "Scale parameter of the QP reduction model")
("SmoothQPReductionModelOffset", m_dSmoothQPReductionModelOffset, 27.0, "Offset parameter of the QP reduction model")
("SmoothQPReductionLimit", m_iSmoothQPReductionLimit, -16, "Threshold parameter for controlling maximum amount of QP reduction by the QP reduction model")
("SmoothQPReductionPeriodicity", m_iSmoothQPReductionPeriodicity, 1, "Periodicity parameter of the QP reduction model, 1: all frames, 0: only intra pictures, 2: every second frame, etc")
#endif
("AdaptiveQP,-aq", m_bUseAdaptiveQP, false, "QP adaptation based on a psycho-visual model")
("MaxQPAdaptationRange,-aqr", m_iQPAdaptationRange, 6, "QP adaptation range")
......
......@@ -179,6 +179,14 @@ protected:
LumaLevelToDeltaQPMapping m_lumaLevelToDeltaQPMapping; ///< mapping from luma level to Delta QP.
#if ADAPTIVE_QP_SELECTION
Bool m_bUseAdaptQpSelect;
#endif
#if JVET_V0078
Bool m_bSmoothQPReductionEnable;
Double m_dSmoothQPReductionThreshold;
Double m_dSmoothQPReductionModelScale;
Double m_dSmoothQPReductionModelOffset;
Int m_iSmoothQPReductionPeriodicity;
Int m_iSmoothQPReductionLimit;
#endif
TComSEIMasteringDisplay m_masteringDisplay;
......
......@@ -184,6 +184,14 @@ Void TAppEncTop::xInitLibCfg()
#if ADAPTIVE_QP_SELECTION
m_cTEncTop.setUseAdaptQpSelect ( m_bUseAdaptQpSelect );
#endif
#if JVET_V0078
m_cTEncTop.setSmoothQPReductionEnable (m_bSmoothQPReductionEnable);
m_cTEncTop.setSmoothQPReductionThreshold (m_dSmoothQPReductionThreshold);
m_cTEncTop.setSmoothQPReductionModelScale (m_dSmoothQPReductionModelScale);
m_cTEncTop.setSmoothQPReductionModelOffset (m_dSmoothQPReductionModelOffset);
m_cTEncTop.setSmoothQPReductionLimit (m_iSmoothQPReductionLimit);
m_cTEncTop.setSmoothQPReductionPeriodicity (m_iSmoothQPReductionPeriodicity);
#endif
m_cTEncTop.setUseAdaptiveQP ( m_bUseAdaptiveQP );
m_cTEncTop.setQPAdaptationRange ( m_iQPAdaptationRange );
......
......@@ -49,6 +49,8 @@
//! \ingroup TLibCommon
//! \{
#define JVET_V0078 1 // JVET-V0078: QP control for very smooth blocks
// ====================================================================================================================
// Debugging
// ====================================================================================================================
......
......@@ -268,6 +268,14 @@ protected:
Int* m_aidQP;
UInt m_uiDeltaQpRD;
Bool m_bFastDeltaQP;
#if JVET_V0078
Bool m_bSmoothQPReductionEnable;
Double m_dSmoothQPReductionThreshold;
Double m_dSmoothQPReductionModelScale;
Double m_dSmoothQPReductionModelOffset;
Int m_iSmoothQPReductionLimit;
Int m_iSmoothQPReductionPeriodicity;
#endif
Bool m_bUseConstrainedIntraPred;
Bool m_bFastUDIUseMPMEnabled;
......@@ -662,6 +670,21 @@ public:
Bool getUseAdaptQpSelect () { return m_bUseAdaptQpSelect; }
#endif
#if JVET_V0078
Bool getSmoothQPReductionEnable () const { return m_bSmoothQPReductionEnable; }
void setSmoothQPReductionEnable (Bool value) { m_bSmoothQPReductionEnable = value; }
Double getSmoothQPReductionThreshold () const { return m_dSmoothQPReductionThreshold; }
void setSmoothQPReductionThreshold (Double value) { m_dSmoothQPReductionThreshold = value; }
Double getSmoothQPReductionModelScale () const { return m_dSmoothQPReductionModelScale; }
void setSmoothQPReductionModelScale (Double value) { m_dSmoothQPReductionModelScale = value; }
Double getSmoothQPReductionModelOffset () const { return m_dSmoothQPReductionModelOffset; }
void setSmoothQPReductionModelOffset (Double value) { m_dSmoothQPReductionModelOffset = value; }
Int getSmoothQPReductionLimit () const { return m_iSmoothQPReductionLimit; }
void setSmoothQPReductionLimit (Int value) { m_iSmoothQPReductionLimit = value; }
Int getSmoothQPReductionPeriodicity () const { return m_iSmoothQPReductionPeriodicity; }
void setSmoothQPReductionPeriodicity (Int value) { m_iSmoothQPReductionPeriodicity = value; }
#endif
Bool getExtendedPrecisionProcessingFlag () const { return m_extendedPrecisionProcessingFlag; }
Void setExtendedPrecisionProcessingFlag (Bool value) { m_extendedPrecisionProcessingFlag = value; }
......
......@@ -219,6 +219,9 @@ Void TEncCu::init( TEncTop* pcEncTop )
m_pcRateCtrl = pcEncTop->getRateCtrl();
m_lumaQPOffset = 0;
initLumaDeltaQpLUT();
#if JVET_V0078
m_smoothQPoffset = 0;
#endif
}
// ====================================================================================================================
......@@ -355,6 +358,86 @@ Int TEncCu::calculateLumaDQP(TComDataCU *pCU, const UInt absPartIdx, const TComY
return QP;
}
#if JVET_V0078
int TEncCu::calculateLumaDQPsmooth(TComDataCU *pCU, const UInt absPartIdx, const TComYuv * pOrgYuv, Int iBaseQP)
{
const Pel *pY = pOrgYuv->getAddr(COMPONENT_Y, absPartIdx);
const Int stride = pOrgYuv->getStride(COMPONENT_Y);
Double avg = 0;
Double diff = 0;
Int width = pCU->getWidth(absPartIdx);
Int height = pCU->getHeight(absPartIdx);
Double thr = (Double)m_pcEncCfg->getSmoothQPReductionThreshold()*height*width;
Int iQP = 0;
if (height == 64 && width == 64)
{
Int sum = 0;
for (Int y = 0; y < height; y++)
{
for (Int x = 0; x < width; x++)
{
sum += pY[x];
}
pY += stride;
}
avg = (Double)sum;
// determine parameters for 1+x+y+x*x+y*y model
const Int numBasis = 6;
Double invb[numBasis][numBasis] = { {0.001*0.244140625000000, 0, 0, 0, 0, 0},
{0, 0.001*0.013204564833946, 0.001*0.002080251479290, -0.001*0.000066039729501, -0.001*0.000165220364313, 0.000000000000000},
{0, 0.001*0.002080251479290, 0.001*0.013204564833946, -0.001*0.000066039729501, 0.000000000000000, -0.001*0.000165220364313},
{0, -0.001*0.000066039729501, -0.001*0.000066039729501, 0.001*0.000002096499349, 0.000000000000000, 0.000000000000000},
{0, -0.001*0.000165220364313, 0.000000000000000, 0.000000000000000, 0.001*0.000002622545465, 0.000000000000000},
{0, 0.000000000000000, -0.001*0.000165220364313, 0.000000000000000, 0.000000000000000, 0.001*0.000002622545465} };
Double boffset[5] = { -31.5, -31.5, -992.25, -1333.5, -1333.5 };
Double b1sum = avg;
Double b2sum = 0.0;
Double b3sum = 0.0;
Double b4sum = 0.0;
Double b5sum = 0.0;;
Double b6sum = 0.0;;
const Pel *pY1 = pOrgYuv->getAddr(COMPONENT_Y, absPartIdx);
for (uint32_t y = 0; y < height; y++)
{
for (uint32_t x = 0; x < width; x++)
{
b2sum += ((Double)pY1[x])*((Double)x + boffset[0]);
b3sum += ((Double)pY1[x])*((Double)y + boffset[1]);
b4sum += ((Double)pY1[x])*((Double)x*(Double)y + boffset[2]);
b5sum += ((double)pY1[x])*((Double)x*(Double)x + boffset[3]);
b6sum += ((double)pY1[x])*((Double)y*(Double)y + boffset[4]);
}
pY1 += stride;
}
Double r[numBasis];
for (uint32_t b = 0; b < numBasis; b++)
{
r[b] = invb[b][0] * b1sum + invb[b][1] * b2sum + invb[b][2] * b3sum + invb[b][3] * b4sum + invb[b][4] * b5sum + invb[b][5] * b6sum;
}
// compute SAD for model
const Pel *pY2 = pOrgYuv->getAddr(COMPONENT_Y, absPartIdx);
for (uint32_t y = 0; y < height; y++)
{
for (uint32_t x = 0; x < width; x++)
{
diff += abs((Int)pY2[x] - (Int)(r[0] + r[1] * ((Double)x + boffset[0]) + r[2] * ((Double)y + boffset[1]) + r[3] * ((Double)x*(Double)y + boffset[2]) + r[4] * ((Double)x*(Double)x + boffset[3]) + r[5] * ((Double)y*(Double)y + boffset[4])));
}
pY2 += stride;
}
if (diff < thr)
{
iQP = std::max(m_pcEncCfg->getSmoothQPReductionLimit(), std::min(0, (int)(m_pcEncCfg->getSmoothQPReductionModelScale()*(double)iBaseQP + m_pcEncCfg->getSmoothQPReductionModelOffset())));
}
}
return iQP;
}
#endif
//! Derive small set of test modes for AMP encoder speed-up
#if AMP_ENC_SPEEDUP
#if AMP_MRG
......@@ -489,6 +572,47 @@ Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const
iMaxQP = iMinQP; // force encode choose the modified QO
}
#if JVET_V0078
if (m_pcEncCfg->getSmoothQPReductionEnable())
{
if (uiDepth <= pps.getMaxCuDQPDepth())
{
m_smoothQPoffset = 0;
// enable smooth QP reduction on selected frames
bool checkSmoothQP = false;
if (m_pcEncCfg->getSmoothQPReductionPeriodicity() != 0)
{
checkSmoothQP = ((m_pcEncCfg->getSmoothQPReductionPeriodicity() == 0) && rpcTempCU->getSlice()->isIntra()) || (m_pcEncCfg->getSmoothQPReductionPeriodicity() == 1) || ((rpcTempCU->getSlice()->getPOC() % m_pcEncCfg->getSmoothQPReductionPeriodicity()) == 0);
}
else
{
checkSmoothQP = ((m_pcEncCfg->getSmoothQPReductionPeriodicity() == 0) && rpcTempCU->getSlice()->isIntra());
}
if (checkSmoothQP)
{
if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled())
{
m_smoothQPoffset = calculateLumaDQPsmooth(rpcTempCU, 0, m_ppcOrigYuv[uiDepth], iBaseQP - m_lumaQPOffset);
}
else
{
m_smoothQPoffset = calculateLumaDQPsmooth(rpcTempCU, 0, m_ppcOrigYuv[uiDepth], iBaseQP);
}
}
}
if (m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled())
{
iMinQP = Clip3(-sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP - m_lumaQPOffset + m_smoothQPoffset);
}
else
{
iMinQP = Clip3(-sps.getQpBDOffset(CHANNEL_TYPE_LUMA), MAX_QP, iBaseQP + m_smoothQPoffset);
}
iMaxQP = iMinQP; // force encode choose the modified QO
}
#endif
if ( m_pcEncCfg->getUseRateCtrl() )
{
iMinQP = m_pcRateCtrl->getRCQP();
......@@ -523,7 +647,11 @@ Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const
{
iQP = lowestQP;
}
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && uiDepth <= pps.getMaxCuDQPDepth() )
#if JVET_V0078
if ((m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || m_pcEncCfg->getSmoothQPReductionEnable()) && uiDepth <= pps.getMaxCuDQPDepth())
#else
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && uiDepth <= pps.getMaxCuDQPDepth() )
#endif
{
getSliceEncoder()->updateLambda(pcSlice, iQP);
}
......@@ -890,7 +1018,11 @@ Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const
rpcTempCU->copyPartFrom( pcSubBestPartCU, uiPartUnitIdx, uhNextDepth ); // Keep best part data to current temporary data.
xCopyYuv2Tmp( pcSubBestPartCU->getTotalNumPart()*uiPartUnitIdx, uhNextDepth );
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && pps.getMaxCuDQPDepth() >= 1 )
#if JVET_V0078
if ((m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || m_pcEncCfg->getSmoothQPReductionEnable()) && pps.getMaxCuDQPDepth() >= 1)
#else
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && pps.getMaxCuDQPDepth() >= 1 )
#endif
{
splitTotalCost += pcSubBestPartCU->getTotalCost();
}
......@@ -907,7 +1039,11 @@ Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const
{
m_pcEntropyCoder->resetBits();
m_pcEntropyCoder->encodeSplitFlag( rpcTempCU, 0, uiDepth, true );
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && pps.getMaxCuDQPDepth() >= 1 )
#if JVET_V0078
if ((m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || m_pcEncCfg->getSmoothQPReductionEnable()) && pps.getMaxCuDQPDepth() >= 1)
#else
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && pps.getMaxCuDQPDepth() >= 1 )
#endif
{
Int splitBits = m_pcEntropyCoder->getNumberOfWrittenBits();
Double splitBitCost = m_pcRdCost->calcRdCost( splitBits, 0 );
......@@ -918,7 +1054,11 @@ Void TEncCu::xCompressCU( TComDataCU*& rpcBestCU, TComDataCU*& rpcTempCU, const
rpcTempCU->getTotalBins() += ((TEncBinCABAC *)((TEncSbac*)m_pcEntropyCoder->m_pcEntropyCoderIf)->getEncBinIf())->getBinsCoded();
}
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && pps.getMaxCuDQPDepth() >= 1 )
#if JVET_V0078
if ((m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() || m_pcEncCfg->getSmoothQPReductionEnable()) && pps.getMaxCuDQPDepth() >= 1)
#else
if ( m_pcEncCfg->getLumaLevelToDeltaQPMapping().isEnabled() && pps.getMaxCuDQPDepth() >= 1 )
#endif
{
rpcTempCU->getTotalCost() = splitTotalCost;
}
......
......@@ -86,6 +86,9 @@ private:
Int m_lumaLevelToDeltaQPLUT[LUMA_LEVEL_TO_DQP_LUT_MAXSIZE];
Int m_lumaQPOffset;
TEncSlice* m_pcSliceEncoder;
#if JVET_V0078
Int m_smoothQPoffset;
#endif
// Access channel
TEncCfg* m_pcEncCfg;
......@@ -109,6 +112,9 @@ public:
TEncSlice* getSliceEncoder() { return m_pcSliceEncoder; }
Void initLumaDeltaQpLUT();
Int calculateLumaDQP( TComDataCU *pCU, const UInt absPartIdx, const TComYuv * pOrgYuv );
#if JVET_V0078
Int calculateLumaDQPsmooth(TComDataCU *pCU, const UInt absPartIdx, const TComYuv * pOrgYuv, Int iBaseQP);
#endif
/// create internal buffers
Void create ( UChar uhTotalDepth, UInt iMaxWidth, UInt iMaxHeight, ChromaFormat chromaFormat );
......
......@@ -922,6 +922,13 @@ Void TEncTop::xInitPPS(TComPPS &pps, const TComSPS &sps)
bUseDQP = true;
}
#if JVET_V0078
if (getSmoothQPReductionEnable())
{
bUseDQP = true;
}
#endif
if (m_costMode==COST_SEQUENCE_LEVEL_LOSSLESS || m_costMode==COST_LOSSLESS_CODING)
{
bUseDQP=false;
......@@ -1415,7 +1422,11 @@ Int TEncCfg::getQPForPicture(const UInt gopIndex, const TComSlice *pSlice) const
else
{
// Only adjust QP when not lossless
#if JVET_V0078
if (!((getMaxDeltaQP() == 0) && (!getLumaLevelToDeltaQPMapping().isEnabled()) && (!getSmoothQPReductionEnable()) && (qp == -lumaQpBDOffset) && (pSlice->getPPS()->getTransquantBypassEnabledFlag())))
#else
if (!(( getMaxDeltaQP() == 0 ) && (!getLumaLevelToDeltaQPMapping().isEnabled()) && (qp == -lumaQpBDOffset ) && (pSlice->getPPS()->getTransquantBypassEnabledFlag())))
#endif
{
const GOPEntry &gopEntry=getGOPEntry(gopIndex);
// adjust QP according to the QP offset for the GOP entry.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment