diff --git a/cfg/multi-layer/layer1_gop_randomaccess.cfg b/cfg/multi-layer/layer1_gop_randomaccess.cfg index 1d511c107421da1dc0b95e80c1378f9869edeca9..5d0201351ab8916c1bc29622a79578d504ce8d89 100644 --- a/cfg/multi-layer/layer1_gop_randomaccess.cfg +++ b/cfg/multi-layer/layer1_gop_randomaccess.cfg @@ -1,4 +1,5 @@ #======== Coding Structure ============= +EncInterLayerOpt : 1 # RDO adjustments for inter-layer prediction (see JVET-AJ0225) ExplicitILRP : 1 # Explicit configuration of inter-layer reference pictures (0:disabled, 1:enabled) DecodingRefreshType : 1 # Random Accesss 0:none, 1:CRA, 2:IDR, 3:Recovery Point SEI GOPSize : 32 # GOP Size (number of B slice = GOPSize-1) diff --git a/doc/software-manual.tex b/doc/software-manual.tex index a5e5fbbc08033781b14b691bf55ccdb1688698f9..0ef2482461f831975cd73941850a82e231e91da7 100644 --- a/doc/software-manual.tex +++ b/doc/software-manual.tex @@ -1743,6 +1743,19 @@ inter-layer reference pictures are no longer inserted automatically. \par \\ +\Option{EncInterLayerOpt} & +%\ShortOption{\None} & +\Default{false} & +Enables or disables the encoder optimization to favor inter-layer predictions. +\\ + +\Option{EncInterLayerOptLambdaModifier} & +%\ShortOption{\None} & +\Default{0.1} & +Specifies a value that is multiplied with the Lagrange multiplier +$\lambda$, for use in the modified rate-distortion cost calculation when comparing inter-layer with intra-layer modes (only used if EncInterLayerOpt is enabled). +\\ + \Option{LayerId\emph{i}} & %\ShortOption{\None} & \Default{0} & diff --git a/source/App/EncoderApp/EncApp.cpp b/source/App/EncoderApp/EncApp.cpp index 026a1a64f125cc1669932464b43874a041485759..2b28c3994fccb8af223494c4f8248c7caeb8ccfc 100644 --- a/source/App/EncoderApp/EncApp.cpp +++ b/source/App/EncoderApp/EncApp.cpp @@ -302,6 +302,8 @@ void EncApp::xInitLibCfg( int layerIdx ) m_cEncLib.setValidFrames(m_firstValidFrame, m_lastValidFrame); m_cEncLib.setAvoidIntraInDepLayer ( m_avoidIntraInDepLayer ); m_cEncLib.setExplicitILRP ( m_explicitILRP ); + m_cEncLib.setEncILOpt ( m_encILOpt ); + m_cEncLib.setEncILOptLambdaModifier ( m_encILOptLambdaModifier ); m_cEncLib.setRefLayerMetricsEnabled(m_refMetricsEnabled); m_cEncLib.setRefLayerRescaledAvailable(false); diff --git a/source/App/EncoderApp/EncAppCfg.cpp b/source/App/EncoderApp/EncAppCfg.cpp index 7dbd3c3f335857e3a72afba7e4cf98f7624a7f14..0a043300926296deaaafe914bd5e641ce3317854 100644 --- a/source/App/EncoderApp/EncAppCfg.cpp +++ b/source/App/EncoderApp/EncAppCfg.cpp @@ -1788,6 +1788,8 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] ) ( "MaxTidILRefPicsPlusOneLayerId%d", m_maxTidILRefPicsPlus1Str, std::string(""), MAX_VPS_LAYERS, "Maximum temporal ID for inter-layer reference pictures plus 1 of i-th layer, 0 for IRAP only") ( "RPLofDepLayerInSH", m_rplOfDepLayerInSh, false, "define Reference picture lists in slice header instead of SPS for dependant layers") ( "ExplicitILRP", m_explicitILRP, false, "Explicitly define Inter-Layer Reference pictures in GOP entry") + ( "EncInterLayerOpt", m_encILOpt, false, "Enable encoder optimization to favor inter-layer predictions") + ( "EncInterLayerOptLambdaModifier", m_encILOptLambdaModifier, ( double )0.1, "lambda modifier for modified RD cost in Inter-Layer criterion") ; opts.addOptions() diff --git a/source/App/EncoderApp/EncAppCfg.h b/source/App/EncoderApp/EncAppCfg.h index 851d0a8dc8c58bc61bec6550569f1bc6126c09fb..44684e4baa009539f3761f492ed072513130e167 100644 --- a/source/App/EncoderApp/EncAppCfg.h +++ b/source/App/EncoderApp/EncAppCfg.h @@ -1093,6 +1093,8 @@ protected: bool m_allIndependentLayersFlag; std::string m_predDirectionArray; bool m_explicitILRP; + bool m_encILOpt; + double m_encILOptLambdaModifier; int m_numRefLayers[MAX_VPS_LAYERS]; std::string m_refLayerIdxStr[MAX_VPS_LAYERS]; diff --git a/source/Lib/CommonLib/CodingStructure.cpp b/source/Lib/CommonLib/CodingStructure.cpp index b74fe434d30c65a2837e5dd39fd8fe73dd88e42e..a7e4e37073c80a01ac1d61ccf2657d104a592400 100644 --- a/source/Lib/CommonLib/CodingStructure.cpp +++ b/source/Lib/CommonLib/CodingStructure.cpp @@ -1583,6 +1583,7 @@ void CodingStructure::initSubStructure( CodingStructure& subStruct, const Channe subStruct.useDbCost = false; subStruct.costDbOffset = 0; + subStruct.useInterlayerRef = false; for( uint32_t i = 0; i < subStruct.area.blocks.size(); i++ ) { @@ -1716,6 +1717,7 @@ void CodingStructure::useSubStructure( const CodingStructure& subStruct, const C dist += subStruct.dist; cost += subStruct.cost; costDbOffset += subStruct.costDbOffset; + useInterlayerRef |= subStruct.useInterlayerRef; } if( parent ) { @@ -1776,6 +1778,8 @@ void CodingStructure::copyStructure( const CodingStructure& other, const Channel dist = other.dist; cost = other.cost; costDbOffset = other.costDbOffset; + useInterlayerRef = other.useInterlayerRef; + CHECKD( area != other.area, "Incompatible sizes" ); const UnitArea dualITreeArea = CS::getArea( *this, this->area, chType ); @@ -1894,6 +1898,7 @@ void CodingStructure::initStructData( const int &QP, const bool &skipMotBuf ) costDbOffset = 0; useDbCost = false; interHad = std::numeric_limits<Distortion>::max(); + useInterlayerRef = false; } diff --git a/source/Lib/CommonLib/CodingStructure.h b/source/Lib/CommonLib/CodingStructure.h index 131694459a3943958b8db960bd4999e2f5f3c54b..226e5171158fe09511e65ee75db593859f0d2f7a 100644 --- a/source/Lib/CommonLib/CodingStructure.h +++ b/source/Lib/CommonLib/CodingStructure.h @@ -192,6 +192,7 @@ public: bool useDbCost; double costDbOffset; double lumaCost; + bool useInterlayerRef; uint64_t fracBits; Distortion dist; Distortion interHad; diff --git a/source/Lib/CommonLib/Unit.cpp b/source/Lib/CommonLib/Unit.cpp index bb2a7f0340d146d4158232ba3a77f4a9311c6af3..43cb2bbf5b8565d304f75b679c374770b0ee2ca9 100644 --- a/source/Lib/CommonLib/Unit.cpp +++ b/source/Lib/CommonLib/Unit.cpp @@ -705,6 +705,18 @@ CMotionBuf PredictionUnit::getMotionBuf() const return cs->getMotionBuf( *this ); } +bool PredictionUnit::checkUseInterLayerRef() const +{ + bool useInterLayerRef=false; + for( uint32_t i = 0; i < NUM_REF_PIC_LIST_01; i++ ) + { + if (refIdx[i] >= 0) + { + useInterLayerRef |= cu->slice->getRpl(RefPicList(i))->isInterLayerRefPic(refIdx[i]); + } + } + return useInterLayerRef; +} // --------------------------------------------------------------------------- // transform unit method definitions diff --git a/source/Lib/CommonLib/Unit.h b/source/Lib/CommonLib/Unit.h index 1c8187b8ae7bba91482ea24fb5a272e7700f9934..ea2716f7180fa8258bd626ec341c12bbe0716aa1 100644 --- a/source/Lib/CommonLib/Unit.h +++ b/source/Lib/CommonLib/Unit.h @@ -458,6 +458,7 @@ struct PredictionUnit : public UnitArea, public IntraPredictionData, public Inte MotionBuf getMotionBuf(); CMotionBuf getMotionBuf() const; + bool checkUseInterLayerRef() const; bool isAffineBlock() const {return cu->affine && mergeType != MergeType::SUBPU_ATMVP;} }; diff --git a/source/Lib/EncoderLib/EncCfg.h b/source/Lib/EncoderLib/EncCfg.h index a4d30dd887ecaa4debc6aa89dc60f5fdf7d0bb81..6e33719182c9e15356a53d570d072521e4cf0395 100644 --- a/source/Lib/EncoderLib/EncCfg.h +++ b/source/Lib/EncoderLib/EncCfg.h @@ -1138,6 +1138,8 @@ protected: bool m_rprRASLtoolSwitch; bool m_refLayerMetricsEnabled; bool m_explicitILRP; + bool m_encILOpt; + double m_encILOptLambdaModifier; public: EncCfg() @@ -3131,6 +3133,10 @@ public: bool getAvoidIntraInDepLayer() const { return m_avoidIntraInDepLayer; } void setExplicitILRP(bool b) { m_explicitILRP = b; } bool getExplicitILRP() const { return m_explicitILRP; } + void setEncILOpt(bool b) { m_encILOpt = b; } + bool getEncILOpt() const { return m_encILOpt; } + void setEncILOptLambdaModifier(double dValue) { m_encILOptLambdaModifier = dValue; } + double getEncILOptLambdaModifier() const { return m_encILOptLambdaModifier; } const EncCfgParam::CfgVPSParameters &getVPSParameters() const { diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index edbc18f6a846aab7c819d2cf4dc95d3fabae56eb..cca83bc0e597dbab31839be5fe562ac2f3d68fa2 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1152,7 +1152,10 @@ void EncCu::xCheckModeSplit(CodingStructure *&tempCS, CodingStructure *&bestCS, const double cost = costTemp; m_CABACEstimator->getCtx() = SubCtx(Ctx::ctxPartition, ctxStart); - if (cost > bestCS->cost + bestCS->costDbOffset + if ((cost > bestCS->cost + bestCS->costDbOffset + && (!m_pcEncCfg->getEncILOpt() + || tempCS->slice->getRpl(REF_PIC_LIST_0)->getNumberOfInterLayerPictures() + tempCS->slice->getRpl(REF_PIC_LIST_1)->getNumberOfInterLayerPictures() == 0 + || bestCS->useInterlayerRef)) #if ENABLE_QPA_SUB_CTU || (m_pcEncCfg->getUsePerceptQPA() && !m_pcEncCfg->getUseRateCtrl() && pps.getUseDQP() && (slice.getCuQpDeltaSubdiv() > 0) && (split == CU_HORZ_SPLIT || split == CU_VERT_SPLIT) && (currDepth == 0)) // force quad-split or no split at CTU level @@ -2274,6 +2277,10 @@ void EncCu::xCheckRDCostUnifiedMerge(CodingStructure *&tempCS, CodingStructure * // 1. Pass: get SATD-cost for selected candidates and reduce their count m_mergeItemList.resetList(numMergeSatdCand); + if (m_pcEncCfg->getEncILOpt()) + { + m_mergeItemList.resetBackupList(1); + } const TempCtx ctxStart(m_ctxPool, m_CABACEstimator->getCtx()); DistParam distParam; const bool bUseHadamard = !tempCS->slice->getDisableSATDForRD(); @@ -2304,6 +2311,11 @@ void EncCu::xCheckRDCostUnifiedMerge(CodingStructure *&tempCS, CodingStructure * addGpmCandsToPruningList(gpmMergeCtx, localUnitArea, sqrtLambdaForFirstPass, ctxStart, comboList, geoBuffer, distParam, pu); } + if (m_pcEncCfg->getEncILOpt()) + { + m_mergeItemList.insertBackupItemsToList(); + } + // Try to limit number of candidates using SATD-costs const double threshold = m_mergeItemList.getMergeItemInList(0)->cost * MRG_FAST_RATIO; numMergeSatdCand = updateRdCheckingNum(threshold, numMergeSatdCand); @@ -2775,6 +2787,10 @@ void EncCu::generateMergePrediction(const UnitArea& unitArea, MergeItem* mergeIt CHECK((luma && mergeItem->lumaPredReady) || (chroma && mergeItem->chromaPredReady), "Prediction has been avaiable"); // update Pu info mergeItem->exportMergeInfo(pu, forceNoResidual); + if (!finalRd) + { + mergeItem->useInterLayerRef = pu.checkUseInterLayerRef(); + } switch (mergeItem->mergeItemType) { @@ -2884,6 +2900,7 @@ double EncCu::calcLumaCost4MergePrediction(const TempCtx& ctxStart, const PelUni unsigned int EncCu::updateRdCheckingNum(double threshold, unsigned int numMergeSatdCand) { numMergeSatdCand = std::min(numMergeSatdCand, (unsigned int) m_mergeItemList.size()); + int numMergeSatdCandOrig = numMergeSatdCand; for (uint32_t i = 0; i < numMergeSatdCand; i++) { @@ -2894,6 +2911,20 @@ unsigned int EncCu::updateRdCheckingNum(double threshold, unsigned int numMergeS break; } } + + if (m_pcEncCfg->getEncILOpt()) + { + for (uint32_t i = numMergeSatdCand; i < numMergeSatdCandOrig; i++) + { + const auto mergeItem = m_mergeItemList.getMergeItemInList(i); + if (mergeItem->useInterLayerRef) + { + m_mergeItemList.swapItems(i, numMergeSatdCand); + ++numMergeSatdCand; + } + } + } + return numMergeSatdCand; } @@ -2962,7 +2993,7 @@ void EncCu::addRegularCandsToPruningList(const MergeCtx& mergeCtx, const UnitAre regularMerge->cost = MAX_DOUBLE; } } - m_mergeItemList.insertMergeItemToList(regularMerge); + m_mergeItemList.insertMergeItemToList(regularMerge, m_pcEncCfg->getEncILOpt()); } m_pcInterSearch->xDmvrSetEncoderCheckFlag(false); } @@ -3018,7 +3049,7 @@ void EncCu::addCiipCandsToPruningList(const MergeCtx& mergeCtx, const UnitArea& { ciipMerge->cost = calcLumaCost4MergePrediction(ctxStart, dstBuf, sqrtLambdaForFirstPassIntra, *pu, distParam); } - m_mergeItemList.insertMergeItemToList(ciipMerge); + m_mergeItemList.insertMergeItemToList(ciipMerge, m_pcEncCfg->getEncILOpt()); } } @@ -3040,7 +3071,7 @@ void EncCu::addMmvdCandsToPruningList(const MergeCtx& mergeCtx, const UnitArea& auto dstBuf = mmvdMerge->getPredBuf(localUnitArea); generateMergePrediction(localUnitArea, mmvdMerge, *pu, true, false, dstBuf, false, false, nullptr, nullptr); mmvdMerge->cost = calcLumaCost4MergePrediction(ctxStart, dstBuf, sqrtLambdaForFirstPassIntra, *pu, distParam); - m_mergeItemList.insertMergeItemToList(mmvdMerge); + m_mergeItemList.insertMergeItemToList(mmvdMerge, m_pcEncCfg->getEncILOpt()); } } @@ -3088,7 +3119,7 @@ void EncCu::addAffineCandsToPruningList(AffineMergeCtx& affineMergeCtx, const Un } } #endif - m_mergeItemList.insertMergeItemToList(mergeItem); + m_mergeItemList.insertMergeItemToList(mergeItem, m_pcEncCfg->getEncILOpt()); } } @@ -3109,7 +3140,7 @@ void EncCu::addGpmCandsToPruningList(const MergeCtx& mergeCtx, const UnitArea& l generateMergePrediction(localUnitArea, mergeItem, *pu, true, false, dstBuf, false, false, geoBuffer[mergeIdxPair[0]], geoBuffer[mergeIdxPair[1]]); mergeItem->cost = calcLumaCost4MergePrediction(ctxStart, dstBuf, sqrtLambdaForFirstPass, *pu, distParamSAD2); - m_mergeItemList.insertMergeItemToList(mergeItem); + m_mergeItemList.insertMergeItemToList(mergeItem, m_pcEncCfg->getEncILOpt()); } } @@ -4087,6 +4118,11 @@ void EncCu::xEncodeInterResidual(CodingStructure *&tempCS, CodingStructure *&bes } } + if (m_pcEncCfg->getEncILOpt()) + { + tempCS->useInterlayerRef = pu.checkUseInterLayerRef(); + } + const bool mtsAllowed = tempCS->sps->getExplicitMtsInterEnabled() && CU::isInter(*cu) && partitioner.currArea().lwidth() <= MTS_INTER_MAX_CU_SIZE && partitioner.currArea().lheight() <= MTS_INTER_MAX_CU_SIZE; @@ -4506,6 +4542,10 @@ void EncCu::xReuseCachedResult( CodingStructure *&tempCS, CodingStructure *&best tempCS->dist = finalDistortion; tempCS->fracBits = m_CABACEstimator->getEstFracBits(); tempCS->cost = m_pcRdCost->calcRdCost( tempCS->fracBits, tempCS->dist ); + if (m_pcEncCfg->getEncILOpt()) + { + tempCS->useInterlayerRef = cu.firstPU->checkUseInterLayerRef(); + } xEncodeDontSplit( *tempCS, partitioner ); xCheckDQP ( *tempCS, partitioner ); @@ -4542,6 +4582,7 @@ void MergeItem::create(ChromaFormat chromaFormat, const Area& area) bcwIdx = 0; interDir = 0; useAltHpelIf = false; + useInterLayerRef = false; affineType = AffineModel::_4_PARAMS; mergeItemType = MergeItemType::NUM; @@ -4755,12 +4796,18 @@ MergeItemList::~MergeItemList() { m_mergeItemPool.giveBack(p); } + for (auto p : m_backupList) + { + m_mergeItemPool.giveBack(p); + } m_list.clear(); + m_backupList.clear(); } void MergeItemList::init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight) { m_list.reserve(maxSize + 1); // to avoid reallocation when inserting a new item + m_backupList.reserve(2); m_chromaFormat = chromaFormat; m_ctuArea.x = 0; m_ctuArea.y = 0; @@ -4776,25 +4823,41 @@ MergeItem* MergeItemList::allocateNewMergeItem() return p; } -void MergeItemList::insertMergeItemToList(MergeItem* p) +void MergeItemList::insertMergeItemToList(MergeItem* p, bool trackInterLayerCand) { if (m_list.empty()) { m_list.push_back(p); + m_numInterLayers += (trackInterLayerCand && p->useInterLayerRef) ? 1 : 0; } else if (m_list.size() == m_maxTrackingNum && p->cost >= m_list.back()->cost) { - m_mergeItemPool.giveBack(p); + if (trackInterLayerCand && p->useInterLayerRef && m_numInterLayers < m_maxTrackingBackupNum) + { + insertMergeItemToBackupList(p); + } + else + { + m_mergeItemPool.giveBack(p); + } } else { if (m_list.size() == m_maxTrackingNum) { - m_mergeItemPool.giveBack(m_list.back()); + if (trackInterLayerCand && m_list.back()->useInterLayerRef && (--m_numInterLayers) < m_maxTrackingBackupNum) + { + insertMergeItemToBackupList(m_list.back()); + } + else + { + m_mergeItemPool.giveBack(m_list.back()); + } m_list.pop_back(); } auto it = std::find_if(m_list.begin(), m_list.end(), [&p](const MergeItem *mi) { return p->cost < mi->cost; }); m_list.insert(it, p); + m_numInterLayers += (trackInterLayerCand && p->useInterLayerRef) ? 1 : 0; } } @@ -4812,6 +4875,78 @@ void MergeItemList::resetList(size_t maxTrackingNum) m_list.clear(); m_list.reserve(maxTrackingNum); m_maxTrackingNum = maxTrackingNum; + m_numInterLayers = 0; +} + + + +void MergeItemList::insertMergeItemToBackupList(MergeItem* p) +{ + if (m_backupList.empty()) + { + m_backupList.push_back(p); + } + else if (m_backupList.size() == m_maxTrackingBackupNum && p->cost >= m_backupList.back()->cost) + { + m_mergeItemPool.giveBack(p); + } + else + { + if (m_backupList.size() == m_maxTrackingBackupNum) + { + m_mergeItemPool.giveBack(m_backupList.back()); + m_backupList.pop_back(); + } + auto it = std::find_if(m_backupList.begin(), m_backupList.end(), [&p](const MergeItem *mi) { return p->cost < mi->cost; }); + m_backupList.insert(it, p); + } +} + +void MergeItemList::resetBackupList(size_t maxTrackingBackupNum) +{ + for (auto p : m_backupList) + { + m_mergeItemPool.giveBack(p); + } + m_backupList.clear(); + m_backupList.reserve(2*maxTrackingBackupNum-1); + m_maxTrackingBackupNum = maxTrackingBackupNum; +} + +void MergeItemList::insertBackupItemsToList() +{ + if (m_backupList.size() == 0 || m_numInterLayers >= m_maxTrackingBackupNum) + { + return; + } + + size_t backupSize = m_backupList.size(); + size_t maxNumReplacedItems = std::min(m_backupList.size(), m_maxTrackingBackupNum - m_numInterLayers); + int numReplacedItems = 0; + while ( numReplacedItems < maxNumReplacedItems && m_list.size()>0 ) + { + if (m_list.back()->useInterLayerRef) + { + m_backupList.push_back(m_list.back()); //temporarily insert in backup + m_list.pop_back(); + } + else + { + m_mergeItemPool.giveBack(m_list.back()); + m_list.pop_back(); + ++numReplacedItems; + } + } + + m_list.insert( m_list.end(), m_backupList.begin() + backupSize, m_backupList.end() ); //re-insert IL items temporarily placed in backup list. + m_list.insert( m_list.end(), m_backupList.begin(), m_backupList.begin() + numReplacedItems ); //insert IL item initially in backup in replacement of removed non-IL items. + m_numInterLayers += numReplacedItems; + + for (int i = 0; i < m_backupList.size() - numReplacedItems; i++) + { + m_mergeItemPool.giveBack(m_backupList.back()); + } + m_backupList.clear(); } //! \} diff --git a/source/Lib/EncoderLib/EncCu.h b/source/Lib/EncoderLib/EncCu.h index 1ce9eb0eaf48f6754597e6082f57906818c08b2c..5927c13d5467084063ac982a8f1055ee84e4562c 100644 --- a/source/Lib/EncoderLib/EncCu.h +++ b/source/Lib/EncoderLib/EncCu.h @@ -161,6 +161,7 @@ public: uint8_t bcwIdx; uint8_t interDir; bool useAltHpelIf; + bool useInterLayerRef; AffineModel affineType; bool noResidual; @@ -205,6 +206,9 @@ private: Pool<MergeItem> m_mergeItemPool; std::vector<MergeItem *> m_list; size_t m_maxTrackingNum = 0; + std::vector<MergeItem *> m_backupList; + size_t m_maxTrackingBackupNum = 0; + int m_numInterLayers = 0; ChromaFormat m_chromaFormat; Area m_ctuArea; @@ -214,11 +218,17 @@ public: void init(size_t maxSize, ChromaFormat chromaFormat, int ctuWidth, int ctuHeight); MergeItem* allocateNewMergeItem(); - void insertMergeItemToList(MergeItem* p); + void insertMergeItemToList(MergeItem* p, bool trackInterLayerCand=false); void resetList(size_t maxTrackingNum); MergeItem* getMergeItemInList(size_t index); size_t size() { return m_list.size(); } + void insertMergeItemToBackupList(MergeItem* p); + void resetBackupList(size_t maxTrackingBackupNum); + void insertBackupItemsToList(); + void swapItems(int index_first, int index_second) { std::swap(m_list[index_first], m_list[index_second]); } + int getNumInterLayerItems() { return m_numInterLayers; } + }; class EncCu diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index fb6de020b3aa51aa9d9b7dfd3c4a31ba782559f3..aaf3ee9db9a94c464056370045132d9eb3fede9d 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -2268,8 +2268,36 @@ bool EncModeCtrlMTnoRQT::useModeResult( const EncTestMode& encTestmode, CodingSt } } } - // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded - if( tempCS->features[ENC_FT_RD_COST] != MAX_DOUBLE && ( !cuECtx.bestCS || ( ( tempCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? cuECtx.bestCS->costDbOffset : 0 ) ) ) ) ) + + bool chooseTemp = false; + if( tempCS->features[ENC_FT_RD_COST] != MAX_DOUBLE ) + { + if(!cuECtx.bestCS) + { + chooseTemp = true; + } + else + { + // for now just a simple decision based on RD-cost or choose tempCS if bestCS is not yet coded + chooseTemp = ( tempCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? tempCS->costDbOffset : 0 ) ) < ( cuECtx.bestCS->features[ENC_FT_RD_COST] + ( tempCS->useDbCost ? cuECtx.bestCS->costDbOffset : 0 ) ); + + // Adjust criterion to choose mode with inter-layer prediction if it has lower modified RD cost with lambda modifier (regardless of original RD cost). + if (m_pcEncCfg->getEncILOpt() && tempCS->useInterlayerRef != cuECtx.bestCS->useInterlayerRef) + { + const double costTemp = m_pcRdCost->calcRdCost(uint64_t(tempCS->features[ENC_FT_FRAC_BITS] * m_pcEncCfg->getEncILOptLambdaModifier()), tempCS->dist); + const double costBest = m_pcRdCost->calcRdCost(uint64_t(cuECtx.bestCS->features[ENC_FT_FRAC_BITS] * m_pcEncCfg->getEncILOptLambdaModifier()), cuECtx.bestCS->dist); + if (tempCS->useInterlayerRef && costTemp < costBest) + { + chooseTemp = true; + } + else if (!tempCS->useInterlayerRef && costBest < costTemp) + { + chooseTemp = false; + } + } + } + } + if (chooseTemp) { cuECtx.bestCS = tempCS; cuECtx.bestCU = tempCS->cus[0];