From 0921297ae360c58b44dbffa83705a9b60908eb53 Mon Sep 17 00:00:00 2001 From: Jiahao Li <lijiahao.cn@bytedance.com> Date: Fri, 19 Apr 2019 06:29:26 +0200 Subject: [PATCH] JVET-N0247: Improvement of Hash Motion Estimation --- source/Lib/CommonLib/Hash.cpp | 84 ++++++- source/Lib/CommonLib/Hash.h | 17 +- source/Lib/CommonLib/Picture.cpp | 8 +- source/Lib/CommonLib/Slice.cpp | 3 + source/Lib/CommonLib/TypeDef.h | 2 + source/Lib/EncoderLib/EncCu.cpp | 6 +- source/Lib/EncoderLib/EncModeCtrl.cpp | 5 + source/Lib/EncoderLib/InterSearch.cpp | 342 +++++++++++++++++++++++++- source/Lib/EncoderLib/InterSearch.h | 9 + 9 files changed, 468 insertions(+), 8 deletions(-) diff --git a/source/Lib/CommonLib/Hash.cpp b/source/Lib/CommonLib/Hash.cpp index 2301f6845..86806b62c 100644 --- a/source/Lib/CommonLib/Hash.cpp +++ b/source/Lib/CommonLib/Hash.cpp @@ -109,6 +109,12 @@ TComHash::TComHash() { m_lookupTable = NULL; tableHasContent = false; +#if JVET_N0247_HASH_IMPROVE + for (int i = 0; i < 5; i++) + { + hashPic[i] = NULL; + } +#endif } TComHash::~TComHash() @@ -120,7 +126,25 @@ TComHash::~TComHash() m_lookupTable = NULL; } } - +#if JVET_N0247_HASH_IMPROVE +void TComHash::create(int picWidth, int picHeight) +{ + if (m_lookupTable) + { + clearAll(); + } + if (!hashPic[0]) + { + for (int k = 0; k < 5; k++) + { + hashPic[k] = new uint16_t[picWidth*picHeight]; + } + } + if (m_lookupTable) + { + return; + } +#else void TComHash::create() { if (m_lookupTable != NULL) @@ -128,6 +152,7 @@ void TComHash::create() clearAll(); return; } +#endif int maxAddr = 1 << (m_CRCBits + m_blockSizeBits); m_lookupTable = new std::vector<BlockHash>*[maxAddr]; memset(m_lookupTable, 0, sizeof(std::vector<BlockHash>*) * maxAddr); @@ -136,6 +161,16 @@ void TComHash::create() void TComHash::clearAll() { +#if JVET_N0247_HASH_IMPROVE + if (hashPic[0]) + { + for (int k = 0; k < 5; k++) + { + delete[] hashPic[k]; + hashPic[k] = NULL; + } + } +#endif tableHasContent = false; if (m_lookupTable == NULL) { @@ -251,6 +286,7 @@ void TComHash::generateBlock2x2HashValue(const PelUnitBuf &curPicBuf, int picWid delete[] p; } +#if !JVET_N0247_HASH_IMPROVE void TComHash::generateRectangleHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]) { //at present, only support 1:2(2:1) retangle hash value @@ -328,6 +364,7 @@ void TComHash::generateRectangleHashValue(int picWidth, int picHeight, int width delete[] p; } +#endif void TComHash::generateBlockHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]) { @@ -372,15 +409,21 @@ void TComHash::generateBlockHashValue(int picWidth, int picHeight, int width, in if (width >= 4) { +#if !JVET_N0247_HASH_IMPROVE int widthMinus1 = width - 1; int heightMinus1 = height - 1; +#endif pos = 0; for (int yPos = 0; yPos < yEnd; yPos++) { for (int xPos = 0; xPos < xEnd; xPos++) { +#if JVET_N0247_HASH_IMPROVE + dstPicBlockSameInfo[2][pos] = (!dstPicBlockSameInfo[0][pos] && !dstPicBlockSameInfo[1][pos]); +#else dstPicBlockSameInfo[2][pos] = (!dstPicBlockSameInfo[0][pos] && !dstPicBlockSameInfo[1][pos]) || (((xPos & widthMinus1) == 0) && ((yPos & heightMinus1) == 0)); +#endif pos++; } pos += width - 1; @@ -404,12 +447,18 @@ void TComHash::addToHashMapByRowWithPrecalData(uint32_t* picHash[2], bool* picIs addValue <<= m_CRCBits; int crcMask = 1 << m_CRCBits; crcMask -= 1; +#if JVET_N0247_HASH_IMPROVE + int blockIdx = g_aucLog2[width] - 2; +#endif for (int xPos = 0; xPos < xEnd; xPos++) { for (int yPos = 0; yPos < yEnd; yPos++) { int pos = yPos * picWidth + xPos; +#if JVET_N0247_HASH_IMPROVE + hashPic[blockIdx][pos] = (uint16_t)(srcHash[1][pos] & crcMask); +#endif //valid data if (srcIsAdded[pos]) { @@ -557,7 +606,38 @@ bool TComHash::isBlock2x2ColSameValue(unsigned char* p, bool includeAllComponent return true; } +#if JVET_N0247_HASH_IMPROVE +bool TComHash::isHorizontalPerfectLuma(const Pel* srcPel, int stride, int width, int height) +{ + for (int i = 0; i < height; i++) + { + for (int j = 1; j < width; j++) + { + if (srcPel[j] != srcPel[0]) + { + return false; + } + } + srcPel += stride; + } + return true; +} +bool TComHash::isVerticalPerfectLuma(const Pel* srcPel, int stride, int width, int height) +{ + for (int i = 0; i < width; i++) + { + for (int j = 1; j < height; j++) + { + if (srcPel[j*stride + i] != srcPel[i]) + { + return false; + } + } + } + return true; +} +#endif bool TComHash::getBlockHashValue(const PelUnitBuf &curPicBuf, int width, int height, int xStart, int yStart, const BitDepths bitDepths, uint32_t& hashValue1, uint32_t& hashValue2) { int addValue = m_blockSizeToIndex[width][height]; @@ -712,8 +792,10 @@ void TComHash::initBlockSizeToIndex() m_blockSizeToIndex[32][32] = 2; m_blockSizeToIndex[64][64] = 3; m_blockSizeToIndex[4][4] = 4; +#if !JVET_N0247_HASH_IMPROVE m_blockSizeToIndex[4][8] = 5; m_blockSizeToIndex[8][4] = 6; +#endif } uint32_t TComHash::getCRCValue1(unsigned char* p, int length) diff --git a/source/Lib/CommonLib/Hash.h b/source/Lib/CommonLib/Hash.h index d69787cfc..b86322d90 100644 --- a/source/Lib/CommonLib/Hash.h +++ b/source/Lib/CommonLib/Hash.h @@ -91,7 +91,11 @@ struct TComHash public: TComHash(); ~TComHash(); +#if JVET_N0247_HASH_IMPROVE + void create(int picWidth, int picHeight); +#else void create(); +#endif void clearAll(); void addToTable(uint32_t hashValue, const BlockHash& blockHash); int count(uint32_t hashValue); @@ -102,11 +106,15 @@ public: void generateBlock2x2HashValue(const PelUnitBuf &curPicBuf, int picWidth, int picHeight, const BitDepths bitDepths, uint32_t* picBlockHash[2], bool* picBlockSameInfo[3]); void generateBlockHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]); +#if !JVET_N0247_HASH_IMPROVE void generateRectangleHashValue(int picWidth, int picHeight, int width, int height, uint32_t* srcPicBlockHash[2], uint32_t* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]); +#endif void addToHashMapByRowWithPrecalData(uint32_t* srcHash[2], bool* srcIsSame, int picWidth, int picHeight, int width, int height); bool isInitial() { return tableHasContent; } void setInitial() { tableHasContent = true; } - +#if JVET_N0247_HASH_IMPROVE + uint16_t* getHashPic(int baseSize) const { return hashPic[g_aucLog2[baseSize] - 2]; } +#endif public: @@ -117,10 +125,17 @@ public: static bool isBlock2x2ColSameValue(unsigned char* p, bool includeAllComponent = true); static bool getBlockHashValue(const PelUnitBuf &curPicBuf, int width, int height, int xStart, int yStart, const BitDepths bitDepths, uint32_t& hashValue1, uint32_t& hashValue2); static void initBlockSizeToIndex(); +#if JVET_N0247_HASH_IMPROVE + static bool isHorizontalPerfectLuma(const Pel* srcPel, int stride, int width, int height); + static bool isVerticalPerfectLuma(const Pel* srcPel, int stride, int width, int height); +#endif private: std::vector<BlockHash>** m_lookupTable; bool tableHasContent; +#if JVET_N0247_HASH_IMPROVE + uint16_t* hashPic[5];//4x4 ~ 64x64 +#endif private: static const int m_CRCBits = 16; diff --git a/source/Lib/CommonLib/Picture.cpp b/source/Lib/CommonLib/Picture.cpp index 62baca75a..f583805bf 100644 --- a/source/Lib/CommonLib/Picture.cpp +++ b/source/Lib/CommonLib/Picture.cpp @@ -1188,17 +1188,21 @@ void Picture::addPictureToHashMapForInter() bIsBlockSame[i][j] = new bool[picWidth*picHeight]; } } - +#if JVET_N0247_HASH_IMPROVE + m_hashMap.create(picWidth, picHeight); +#else m_hashMap.create(); +#endif m_hashMap.generateBlock2x2HashValue(getOrigBuf(), picWidth, picHeight, slices[0]->getSPS()->getBitDepths(), blockHashValues[0], bIsBlockSame[0]);//2x2 m_hashMap.generateBlockHashValue(picWidth, picHeight, 4, 4, blockHashValues[0], blockHashValues[1], bIsBlockSame[0], bIsBlockSame[1]);//4x4 m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[1], bIsBlockSame[1][2], picWidth, picHeight, 4, 4); - +#if !JVET_N0247_HASH_IMPROVE m_hashMap.generateRectangleHashValue(picWidth, picHeight, 8, 4, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//8x4 m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 8, 4); m_hashMap.generateRectangleHashValue(picWidth, picHeight, 4, 8, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//4x8 m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 4, 8); +#endif m_hashMap.generateBlockHashValue(picWidth, picHeight, 8, 8, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//8x8 m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 8, 8); diff --git a/source/Lib/CommonLib/Slice.cpp b/source/Lib/CommonLib/Slice.cpp index 2e3d9d158..927383a31 100644 --- a/source/Lib/CommonLib/Slice.cpp +++ b/source/Lib/CommonLib/Slice.cpp @@ -1164,6 +1164,9 @@ void Slice::applyReferencePictureSet( PicList& rcListPic, const ReferencePicture if( ! pcPic->referenced) { +#if JVET_N0247_HASH_IMPROVE + pcPic->getHashMap()->clearAll(); +#endif continue; } diff --git a/source/Lib/CommonLib/TypeDef.h b/source/Lib/CommonLib/TypeDef.h index c00888c88..d8b6bbb45 100644 --- a/source/Lib/CommonLib/TypeDef.h +++ b/source/Lib/CommonLib/TypeDef.h @@ -133,6 +133,8 @@ #define JVET_N0325_BDOF 1 // unified right-shifts for BDOF derivation +#define JVET_N0247_HASH_IMPROVE 1 // Improve hash motion estimation + #define JVET_N0449_MMVD_SIMP 1 // Configurable number of mmvd distance entries used #define JVET_N0363_INTRA_COST_MOD 1 // Modified cost criterion for intra encoder search diff --git a/source/Lib/EncoderLib/EncCu.cpp b/source/Lib/EncoderLib/EncCu.cpp index 69ca8817e..bab69d051 100644 --- a/source/Lib/EncoderLib/EncCu.cpp +++ b/source/Lib/EncoderLib/EncCu.cpp @@ -1662,8 +1662,12 @@ void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&b } } tempCS->initStructData(encTestMode.qp, encTestMode.lossless); - +#if JVET_N0247_HASH_IMPROVE + int minSize = min(cu.lwidth(), cu.lheight()); + if (minSize < 64) +#else if (cu.lwidth() != 64) +#endif { isPerfectMatch = false; } diff --git a/source/Lib/EncoderLib/EncModeCtrl.cpp b/source/Lib/EncoderLib/EncModeCtrl.cpp index 505cd72b1..92bb4f3b5 100644 --- a/source/Lib/EncoderLib/EncModeCtrl.cpp +++ b/source/Lib/EncoderLib/EncModeCtrl.cpp @@ -1396,7 +1396,12 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru } if (m_pcEncCfg->getUseHashME()) { +#if JVET_N0247_HASH_IMPROVE + int minSize = min(cs.area.lwidth(), cs.area.lheight()); + if (minSize < 128 && minSize >= 4) +#else if ((cs.area.lwidth() == cs.area.lheight() && cs.area.lwidth() <= 64 && cs.area.lwidth() >= 4) || (cs.area.lwidth() == 4 && cs.area.lheight() == 8) || (cs.area.lwidth() == 8 && cs.area.lheight() == 4)) +#endif { m_ComprCUCtxList.back().testModes.push_back({ ETM_HASH_INTER, ETO_STANDARD, qp, lossless }); } diff --git a/source/Lib/EncoderLib/InterSearch.cpp b/source/Lib/EncoderLib/InterSearch.cpp index 9bc95e794..a954f59f1 100644 --- a/source/Lib/EncoderLib/InterSearch.cpp +++ b/source/Lib/EncoderLib/InterSearch.cpp @@ -1799,7 +1799,301 @@ void InterSearch::selectMatchesInter(const MapIterator& itBegin, int count, std: } } } +#if JVET_N0247_HASH_IMPROVE +void InterSearch::selectRectangleMatchesInter(const MapIterator& itBegin, int count, std::list<BlockHash>& listBlockHash, const BlockHash& currBlockHash, int width, int height, int idxNonSimple, unsigned int* &hashValues, int baseNum, int picWidth, int picHeight, bool isHorizontal, uint16_t* curHashPic) +{ + const int maxReturnNumber = 5; + int baseSize = min(width, height); + unsigned int crcMask = 1 << 16; + crcMask -= 1; + + listBlockHash.clear(); + std::list<int> listCost; + listCost.clear(); + + MapIterator it = itBegin; + + for (int i = 0; i < count; i++, it++) + { + if ((*it).hashValue2 != currBlockHash.hashValue2) + { + continue; + } + int xRef = (*it).x; + int yRef = (*it).y; + if (isHorizontal) + { + xRef -= idxNonSimple * baseSize; + } + else + { + yRef -= idxNonSimple * baseSize; + } + if (xRef < 0 || yRef < 0 || xRef + width >= picWidth || yRef + height >= picHeight) + { + continue; + } + //check Other baseSize hash values + uint16_t* refHashValue = curHashPic + yRef * picWidth + xRef; + bool isSame = true; + + for (int k = 0; k < baseNum; k++) + { + if ((*refHashValue) != (uint16_t)(hashValues[k] & crcMask)) + { + isSame = false; + break; + } + refHashValue += (isHorizontal ? baseSize : (baseSize*picWidth)); + } + if (!isSame) + { + continue; + } + + int currCost = RdCost::xGetExpGolombNumberOfBits(xRef - currBlockHash.x) + + RdCost::xGetExpGolombNumberOfBits(yRef - currBlockHash.y); + + BlockHash refBlockHash; + refBlockHash.hashValue2 = (*it).hashValue2; + refBlockHash.x = xRef; + refBlockHash.y = yRef; + + if (listBlockHash.size() < maxReturnNumber) + { + addToSortList(listBlockHash, listCost, currCost, refBlockHash); + } + else if (!listCost.empty() && currCost < listCost.back()) + { + listCost.pop_back(); + listBlockHash.pop_back(); + addToSortList(listBlockHash, listCost, currCost, refBlockHash); + } + } +} + +bool InterSearch::xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPicList, int& bestRefIndex, Mv& bestMv, Mv& bestMvd, int& bestMVPIndex, bool& isPerfectMatch) +{ + int width = pu.cu->lumaSize().width; + int height = pu.cu->lumaSize().height; + + int baseSize = min(width, height); + bool isHorizontal = true;; + int baseNum = 0; + if (height < width) + { + isHorizontal = true; + baseNum = 1 << (g_aucLog2[width] - g_aucLog2[height]); + } + else + { + isHorizontal = false; + baseNum = 1 << (g_aucLog2[height] - g_aucLog2[width]); + } + + int xPos = pu.cu->lumaPos().x; + int yPos = pu.cu->lumaPos().y; + const int currStride = pu.cs->picture->getOrigBuf().get(COMPONENT_Y).stride; + const Pel* curPel = pu.cs->picture->getOrigBuf().get(COMPONENT_Y).buf + yPos * currStride + xPos; + int picWidth = pu.cu->slice->getSPS()->getPicWidthInLumaSamples(); + int picHeight = pu.cu->slice->getSPS()->getPicHeightInLumaSamples(); + + int xBase = xPos; + int yBase = yPos; + const Pel* basePel = curPel; + int idxNonSimple = -1; + unsigned int* hashValue1s = new unsigned int[baseNum]; + unsigned int* hashValue2s = new unsigned int[baseNum]; + + for (int k = 0; k < baseNum; k++) + { + if (isHorizontal) + { + xBase = xPos + k * baseSize; + basePel = curPel + k * baseSize; + } + else + { + yBase = yPos + k * baseSize; + basePel = curPel + k * baseSize * currStride; + } + + if (idxNonSimple == -1 && !TComHash::isHorizontalPerfectLuma(basePel, currStride, baseSize, baseSize) && !TComHash::isVerticalPerfectLuma(basePel, currStride, baseSize, baseSize)) + { + idxNonSimple = k; + } + TComHash::getBlockHashValue((pu.cs->picture->getOrigBuf()), baseSize, baseSize, xBase, yBase, pu.cu->slice->getSPS()->getBitDepths(), hashValue1s[k], hashValue2s[k]); + } + if (idxNonSimple == -1) + { + idxNonSimple = 0; + } + + Distortion bestCost = UINT64_MAX; + + BlockHash currBlockHash; + currBlockHash.x = xPos;//still use the first base block location + currBlockHash.y = yPos; + + currBlockHash.hashValue2 = hashValue2s[idxNonSimple]; + + m_pcRdCost->setDistParam(m_cDistParam, pu.cs->getOrgBuf(pu).Y(), 0, 0, m_lumaClpRng.bd, COMPONENT_Y, 0, 1, false); + + int imvBest = 0; + int numPredDir = pu.cu->slice->isInterP() ? 1 : 2; + for (int refList = 0; refList < numPredDir; refList++) + { + RefPicList eRefPicList = (refList == 0) ? REF_PIC_LIST_0 : REF_PIC_LIST_1; + int refPicNumber = pu.cu->slice->getNumRefIdx(eRefPicList); + + for (int refIdx = 0; refIdx < refPicNumber; refIdx++) + { + int bitsOnRefIdx = 1; + if (refPicNumber > 1) + { + bitsOnRefIdx += refIdx + 1; + if (refIdx == refPicNumber - 1) + { + bitsOnRefIdx--; + } + } + m_numHashMVStoreds[eRefPicList][refIdx] = 0; + + if (refList == 0 || pu.cu->slice->getList1IdxToList0Idx(refIdx) < 0) + { + int count = static_cast<int>(pu.cu->slice->getRefPic(eRefPicList, refIdx)->getHashMap()->count(hashValue1s[idxNonSimple])); + if (count == 0) + { + continue; + } + + list<BlockHash> listBlockHash; + selectRectangleMatchesInter(pu.cu->slice->getRefPic(eRefPicList, refIdx)->getHashMap()->getFirstIterator(hashValue1s[idxNonSimple]), count, listBlockHash, currBlockHash, width, height, idxNonSimple, hashValue2s, baseNum, picWidth, picHeight, isHorizontal, pu.cu->slice->getRefPic(eRefPicList, refIdx)->getHashMap()->getHashPic(baseSize)); + + m_numHashMVStoreds[eRefPicList][refIdx] = int(listBlockHash.size()); + if (listBlockHash.empty()) + { + continue; + } + AMVPInfo currAMVPInfoPel; + AMVPInfo currAMVPInfo4Pel; + AMVPInfo currAMVPInfoQPel; + pu.cu->imv = 2; + PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfo4Pel); + pu.cu->imv = 1; + PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfoPel); + pu.cu->imv = 0; + PU::fillMvpCand(pu, eRefPicList, refIdx, currAMVPInfoQPel); + + const Pel* refBufStart = pu.cu->slice->getRefPic(eRefPicList, refIdx)->getRecoBuf().get(COMPONENT_Y).buf; + const int refStride = pu.cu->slice->getRefPic(eRefPicList, refIdx)->getRecoBuf().get(COMPONENT_Y).stride; + m_cDistParam.cur.stride = refStride; + m_pcRdCost->selectMotionLambda(pu.cu->transQuantBypass); + m_pcRdCost->setCostScale(0); + + list<BlockHash>::iterator it; + int countMV = 0; + for (it = listBlockHash.begin(); it != listBlockHash.end(); ++it) + { + int curMVPIdx = 0; + unsigned int curMVPbits = MAX_UINT; + Mv cMv((*it).x - currBlockHash.x, (*it).y - currBlockHash.y); + m_hashMVStoreds[eRefPicList][refIdx][countMV++] = cMv; + cMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_QUARTER); + + for (int mvpIdxTemp = 0; mvpIdxTemp < 2; mvpIdxTemp++) + { + Mv cMvPredPel = currAMVPInfoQPel.mvCand[mvpIdxTemp]; + m_pcRdCost->setPredictor(cMvPredPel); + + unsigned int tempMVPbits = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 0); + + if (tempMVPbits < curMVPbits) + { + curMVPbits = tempMVPbits; + curMVPIdx = mvpIdxTemp; + pu.cu->imv = 0; + } + + if (pu.cu->slice->getSPS()->getAMVREnabledFlag()) + { + unsigned int bitsMVP1Pel = MAX_UINT; + Mv mvPred1Pel = currAMVPInfoPel.mvCand[mvpIdxTemp]; + m_pcRdCost->setPredictor(mvPred1Pel); + bitsMVP1Pel = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 2); + if (bitsMVP1Pel < curMVPbits) + { + curMVPbits = bitsMVP1Pel; + curMVPIdx = mvpIdxTemp; + pu.cu->imv = 1; + } + + if ((cMv.getHor() % 16 == 0) && (cMv.getVer() % 16 == 0)) + { + unsigned int bitsMVP4Pel = MAX_UINT; + Mv mvPred4Pel = currAMVPInfo4Pel.mvCand[mvpIdxTemp]; + m_pcRdCost->setPredictor(mvPred4Pel); + bitsMVP4Pel = m_pcRdCost->getBitsOfVectorWithPredictor(cMv.getHor(), cMv.getVer(), 4); + if (bitsMVP4Pel < curMVPbits) + { + curMVPbits = bitsMVP4Pel; + curMVPIdx = mvpIdxTemp; + pu.cu->imv = 2; + } + } + } + } + curMVPbits += bitsOnRefIdx; + + m_cDistParam.cur.buf = refBufStart + (*it).y*refStride + (*it).x; + Distortion currSad = m_cDistParam.distFunc(m_cDistParam); + Distortion currCost = currSad + m_pcRdCost->getCost(curMVPbits); + + if (!isPerfectMatch) + { + if (pu.cu->slice->getRefPic(eRefPicList, refIdx)->slices[0]->getSliceQp() <= pu.cu->slice->getSliceQp()) + { + isPerfectMatch = true; + } + } + + if (currCost < bestCost) + { + bestCost = currCost; + bestRefPicList = eRefPicList; + bestRefIndex = refIdx; + bestMv = cMv; + bestMVPIndex = curMVPIdx; + imvBest = pu.cu->imv; + if (pu.cu->imv == 2) + { + bestMvd = cMv - currAMVPInfo4Pel.mvCand[curMVPIdx]; + } + else if (pu.cu->imv == 1) + { + bestMvd = cMv - currAMVPInfoPel.mvCand[curMVPIdx]; + } + else + { + bestMvd = cMv - currAMVPInfoQPel.mvCand[curMVPIdx]; + } + } + } + } + } + } + delete[] hashValue1s; + delete[] hashValue2s; + pu.cu->imv = imvBest; + if (bestMvd == Mv(0, 0)) + { + pu.cu->imv = 0; + return false; + } + return (bestCost < MAX_INT); +} +#else int InterSearch::xHashInterPredME(const PredictionUnit& pu, RefPicList currRefPicList, int currRefPicIndex, Mv bestMv[5]) { int width = pu.cu->lumaSize().width; @@ -1843,11 +2137,18 @@ int InterSearch::xHashInterPredME(const PredictionUnit& pu, RefPicList currRefPi return totalSize; } +#endif bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPicList, int& bestRefIndex, Mv& bestMv, Mv& bestMvd, int& bestMVPIndex, bool& isPerfectMatch) { int width = pu.cu->lumaSize().width; int height = pu.cu->lumaSize().height; +#if JVET_N0247_HASH_IMPROVE + if (width != height) + { + return xRectHashInterEstimation(pu, bestRefPicList, bestRefIndex, bestMv, bestMvd, bestMVPIndex, isPerfectMatch); + } +#endif int xPos = pu.cu->lumaPos().x; int yPos = pu.cu->lumaPos().y; @@ -1887,6 +2188,9 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi bitsOnRefIdx--; } } +#if JVET_N0247_HASH_IMPROVE + m_numHashMVStoreds[eRefPicList][refIdx] = 0; +#endif if (refList == 0 || pu.cu->slice->getList1IdxToList0Idx(refIdx) < 0) { @@ -1898,7 +2202,9 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi list<BlockHash> listBlockHash; selectMatchesInter(pu.cu->slice->getRefPic(eRefPicList, refIdx)->getHashMap()->getFirstIterator(hashValue1), count, listBlockHash, currBlockHash); - +#if JVET_N0247_HASH_IMPROVE + m_numHashMVStoreds[eRefPicList][refIdx] = (int)listBlockHash.size(); +#endif if (listBlockHash.empty()) { continue; @@ -1923,11 +2229,17 @@ bool InterSearch::xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPi m_pcRdCost->setCostScale(0); list<BlockHash>::iterator it; +#if JVET_N0247_HASH_IMPROVE + int countMV = 0; +#endif for (it = listBlockHash.begin(); it != listBlockHash.end(); ++it) { int curMVPIdx = 0; unsigned int curMVPbits = MAX_UINT; Mv cMv((*it).x - currBlockHash.x, (*it).y - currBlockHash.y); +#if JVET_N0247_HASH_IMPROVE + m_hashMVStoreds[eRefPicList][refIdx][countMV++] = cMv; +#endif cMv.changePrecision(MV_PRECISION_INT, MV_PRECISION_QUARTER); for (int mvpIdxTemp = 0; mvpIdxTemp < 2; mvpIdxTemp++) @@ -3500,6 +3812,18 @@ void InterSearch::xTZSearch( const PredictionUnit& pu, , cStruct ); } +#if JVET_N0247_HASH_IMPROVE + if (m_pcEncCfg->getUseHashME() && (m_currRefPicList == 0 || pu.cu->slice->getList1IdxToList0Idx(m_currRefPicIndex) < 0)) + { + int minSize = min(pu.cu->lumaSize().width, pu.cu->lumaSize().height); + if (minSize < 128 && minSize >= 4) + { + int numberOfOtherMvps = m_numHashMVStoreds[m_currRefPicList][m_currRefPicIndex]; + for (int i = 0; i < numberOfOtherMvps; i++) + { + xTZSearchHelp(cStruct, m_hashMVStoreds[m_currRefPicList][m_currRefPicIndex][i].getHor(), m_hashMVStoreds[m_currRefPicList][m_currRefPicIndex][i].getVer(), 0, 0); + } +#else if (m_pcEncCfg->getUseHashME()) { int width = pu.cu->lumaSize().width; @@ -3513,6 +3837,7 @@ void InterSearch::xTZSearch( const PredictionUnit& pu, { xTZSearchHelp(cStruct, otherMvps[i].getHor(), otherMvps[i].getVer(), 0, 0); } +#endif if (numberOfOtherMvps > 0) { // write out best match @@ -3779,7 +4104,18 @@ void InterSearch::xTZSearchSelective( const PredictionUnit& pu, , cStruct ); } - +#if JVET_N0247_HASH_IMPROVE + if (m_pcEncCfg->getUseHashME() && (m_currRefPicList == 0 || pu.cu->slice->getList1IdxToList0Idx(m_currRefPicIndex) < 0)) + { + int minSize = min(pu.cu->lumaSize().width, pu.cu->lumaSize().height); + if (minSize < 128 && minSize >= 4) + { + int numberOfOtherMvps = m_numHashMVStoreds[m_currRefPicList][m_currRefPicIndex]; + for (int i = 0; i < numberOfOtherMvps; i++) + { + xTZSearchHelp(cStruct, m_hashMVStoreds[m_currRefPicList][m_currRefPicIndex][i].getHor(), m_hashMVStoreds[m_currRefPicList][m_currRefPicIndex][i].getVer(), 0, 0); + } +#else if (m_pcEncCfg->getUseHashME()) { int width = pu.cu->lumaSize().width; @@ -3793,7 +4129,7 @@ void InterSearch::xTZSearchSelective( const PredictionUnit& pu, { xTZSearchHelp(cStruct, otherMvps[i].getHor(), otherMvps[i].getVer(), 0, 0); } - +#endif if (numberOfOtherMvps > 0) { // write out best match diff --git a/source/Lib/EncoderLib/InterSearch.h b/source/Lib/EncoderLib/InterSearch.h index acc2861c1..0115d2505 100644 --- a/source/Lib/EncoderLib/InterSearch.h +++ b/source/Lib/EncoderLib/InterSearch.h @@ -143,6 +143,10 @@ protected: RefPicList m_currRefPicList; int m_currRefPicIndex; bool m_skipFracME; +#if JVET_N0247_HASH_IMPROVE + int m_numHashMVStoreds[NUM_REF_PIC_LIST_01][MAX_NUM_REF]; + Mv m_hashMVStoreds[NUM_REF_PIC_LIST_01][MAX_NUM_REF][5]; +#endif // Misc. Pel *m_pTempPel; @@ -308,7 +312,12 @@ public: void addToSortList(std::list<BlockHash>& listBlockHash, std::list<int>& listCost, int cost, const BlockHash& blockHash); bool predInterHashSearch(CodingUnit& cu, Partitioner& partitioner, bool& isPerfectMatch); bool xHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPicList, int& bestRefIndex, Mv& bestMv, Mv& bestMvd, int& bestMVPIndex, bool& isPerfectMatch); +#if JVET_N0247_HASH_IMPROVE + bool xRectHashInterEstimation(PredictionUnit& pu, RefPicList& bestRefPicList, int& bestRefIndex, Mv& bestMv, Mv& bestMvd, int& bestMVPIndex, bool& isPerfectMatch); + void selectRectangleMatchesInter(const MapIterator& itBegin, int count, std::list<BlockHash>& listBlockHash, const BlockHash& currBlockHash, int width, int height, int idxNonSimple, unsigned int* &hashValues, int baseNum, int picWidth, int picHeight, bool isHorizontal, uint16_t* curHashPic); +#else int xHashInterPredME(const PredictionUnit& pu, RefPicList currRefPicList, int currRefPicIndex, Mv bestMv[5]); +#endif void selectMatchesInter(const MapIterator& itBegin, int count, std::list<BlockHash>& vecBlockHash, const BlockHash& currBlockHash); protected: -- GitLab