Commit b61f6989 authored by Jiahao Li's avatar Jiahao Li

JVET-M0253: Hash-based motion search

parent f7b1ff7d
......@@ -257,6 +257,10 @@ void EncApp::xInitLibCfg()
#endif
m_cEncLib.setUseMHIntra ( m_MHIntra );
m_cEncLib.setUseTriangle ( m_Triangle );
#if JVET_M0253_HASH_ME
m_cEncLib.setUseHashME ( m_HashME );
#endif
#if JVET_M0255_FRACMMVD_SWITCH
m_cEncLib.setAllowDisFracMMVD ( m_allowDisFracMMVD );
#endif
......
......@@ -864,6 +864,10 @@ bool EncAppCfg::parseCfg( int argc, char* argv[] )
#endif
("MHIntra", m_MHIntra, false, "Enable MHIntra mode")
("Triangle", m_Triangle, false, "Enable triangular shape motion vector prediction (0:off, 1:on)")
#if JVET_M0253_HASH_ME
("HashME", m_HashME, false, "Enable hash motion estimation (0:off, 1:on)")
#endif
#if JVET_M0255_FRACMMVD_SWITCH
("AllowDisFracMMVD", m_allowDisFracMMVD, false, "Disable fractional MVD in MMVD mode adaptively")
#endif
......@@ -1943,6 +1947,9 @@ bool EncAppCfg::xCheckParameter()
xConfirmPara( m_MTT, "Multi type tree is only allowed with NEXT profile" );
xConfirmPara( m_ImvMode, "IMV is only allowed with NEXT profile" );
xConfirmPara(m_IBCMode, "IBC Mode only allowed with NEXT profile");
#if JVET_M0253_HASH_ME
xConfirmPara( m_HashME, "Hash motion estimation only allowed with NEXT profile" );
#endif
xConfirmPara( m_useFastLCTU, "Fast large CTU can only be applied when encoding with NEXT profile" );
#if JVET_M0464_UNI_MTS
xConfirmPara( m_MTS, "MTS only allowed with NEXT profile" );
......@@ -3165,6 +3172,9 @@ void EncAppCfg::xPrintParameter()
#endif
}
msg(VERBOSE, "IBC:%d ", m_IBCMode);
#if JVET_M0253_HASH_ME
msg( VERBOSE, "HashME:%d ", m_HashME );
#endif
msg( VERBOSE, "WrapAround:%d ", m_wrapAround);
if( m_wrapAround )
{
......
......@@ -237,6 +237,9 @@ protected:
bool m_MHIntra;
bool m_Triangle;
#if JVET_M0253_HASH_ME
bool m_HashME;
#endif
#if JVET_M0255_FRACMMVD_SWITCH
bool m_allowDisFracMMVD;
#endif
......
This diff is collapsed.
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2010-2019, ITU/ISO/IEC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file Hash.h
\brief Hash class (header)
*/
#ifndef __HASH__
#define __HASH__
// Include files
#include "CommonLib/Buffer.h"
#include "CommonLib/CommonDef.h"
#include "CommonLib/TrQuant.h"
#include "CommonLib/Unit.h"
#include "CommonLib/UnitPartitioner.h"
#include <vector>
struct BlockHash
{
short x;
short y;
unsigned int hashValue2;
};
typedef std::vector<BlockHash>::iterator MapIterator;
// ====================================================================================================================
// Class definitions
// ====================================================================================================================
struct TCRCCalculatorLight
{
public:
TCRCCalculatorLight(unsigned int bits, unsigned int truncPoly);
~TCRCCalculatorLight();
public:
void processData(unsigned char* curData, unsigned int dataLength);
void reset() { m_remainder = 0; }
unsigned int getCRC() { return m_remainder & m_finalResultMask; }
private:
void xInitTable();
private:
unsigned int m_remainder;
unsigned int m_truncPoly;
unsigned int m_bits;
unsigned int m_table[256];
unsigned int m_finalResultMask;
};
struct TComHash
{
public:
TComHash();
~TComHash();
void create();
void clearAll();
void addToTable(unsigned int hashValue, const BlockHash& blockHash);
int count(unsigned int hashValue);
int count(unsigned int hashValue) const;
MapIterator getFirstIterator(unsigned int hashValue);
const MapIterator getFirstIterator(unsigned int hashValue) const;
bool hasExactMatch(unsigned int hashValue1, unsigned int hashValue2);
void generateBlock2x2HashValue(const PelUnitBuf &curPicBuf, int picWidth, int picHeight, const BitDepths bitDepths, unsigned int* picBlockHash[2], bool* picBlockSameInfo[3]);
void generateBlockHashValue(int picWidth, int picHeight, int width, int height, unsigned int* srcPicBlockHash[2], unsigned int* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]);
void generateRectangleHashValue(int picWidth, int picHeight, int width, int height, unsigned int* srcPicBlockHash[2], unsigned int* dstPicBlockHash[2], bool* srcPicBlockSameInfo[3], bool* dstPicBlockSameInfo[3]);
void addToHashMapByRowWithPrecalData(unsigned int* srcHash[2], bool* srcIsSame, int picWidth, int picHeight, int width, int height);
bool isInitial() { return tableHasContent; }
void setInitial() { tableHasContent = true; }
public:
static unsigned int getCRCValue1(unsigned char* p, int length);
static unsigned int getCRCValue2(unsigned char* p, int length);
static void getPixelsIn1DCharArrayByBlock2x2(const PelUnitBuf &curPicBuf, unsigned char* pixelsIn1D, int xStart, int yStart, const BitDepths& bitDepths, bool includeAllComponent = true);
static bool isBlock2x2RowSameValue(unsigned char* p, bool includeAllComponent = true);
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, unsigned int& hashValue1, unsigned int& hashValue2);
static void initBlockSizeToIndex();
private:
std::vector<BlockHash>** m_lookupTable;
bool tableHasContent;
private:
static const int m_CRCBits = 16;
static const int m_blockSizeBits = 3;
static int m_blockSizeToIndex[65][65];
static TCRCCalculatorLight m_crcCalculator1;
static TCRCCalculatorLight m_crcCalculator2;
};
#endif // __HASH__
......@@ -747,6 +747,9 @@ void Picture::create(const ChromaFormat &_chromaFormat, const Size &size, const
m_ctuArea = UnitArea( _chromaFormat, Area( Position{ 0, 0 }, Size( _maxCUSize, _maxCUSize ) ) );
#endif
#if JVET_M0253_HASH_ME
m_hashMap.clearAll();
#endif
}
void Picture::destroy()
......@@ -762,7 +765,9 @@ void Picture::destroy()
{
M_BUFS( jId, t ).destroy();
}
#if JVET_M0253_HASH_ME
m_hashMap.clearAll();
#endif
if( cs )
{
cs->destroy();
......@@ -1162,3 +1167,64 @@ bool Picture::getSpliceFull()
return false;
return true;
}
#if JVET_M0253_HASH_ME
void Picture::addPictureToHashMapForInter()
{
int picWidth = slices[0]->getSPS()->getPicWidthInLumaSamples();
int picHeight = slices[0]->getSPS()->getPicHeightInLumaSamples();
unsigned int* blockHashValues[2][2];
bool* bIsBlockSame[2][3];
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
blockHashValues[i][j] = new unsigned int[picWidth*picHeight];
}
for (int j = 0; j < 3; j++)
{
bIsBlockSame[i][j] = new bool[picWidth*picHeight];
}
}
m_hashMap.create();
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);
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);
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);
m_hashMap.generateBlockHashValue(picWidth, picHeight, 16, 16, blockHashValues[0], blockHashValues[1], bIsBlockSame[0], bIsBlockSame[1]);//16x16
m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[1], bIsBlockSame[1][2], picWidth, picHeight, 16, 16);
m_hashMap.generateBlockHashValue(picWidth, picHeight, 32, 32, blockHashValues[1], blockHashValues[0], bIsBlockSame[1], bIsBlockSame[0]);//32x32
m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[0], bIsBlockSame[0][2], picWidth, picHeight, 32, 32);
m_hashMap.generateBlockHashValue(picWidth, picHeight, 64, 64, blockHashValues[0], blockHashValues[1], bIsBlockSame[0], bIsBlockSame[1]);//64x64
m_hashMap.addToHashMapByRowWithPrecalData(blockHashValues[1], bIsBlockSame[1][2], picWidth, picHeight, 64, 64);
m_hashMap.setInitial();
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
delete[] blockHashValues[i][j];
}
for (int j = 0; j < 3; j++)
{
delete[] bIsBlockSame[i][j];
}
}
}
#endif
......@@ -46,7 +46,9 @@
#include "Unit.h"
#include "Slice.h"
#include "CodingStructure.h"
#if JVET_M0253_HASH_ME
#include "Hash.h"
#endif
#include <deque>
#if ENABLE_WPP_PARALLELISM || ENABLE_SPLIT_PARALLELISM
......@@ -259,6 +261,13 @@ public:
PelStorage m_bufs[NUM_PIC_TYPES];
#endif
#if JVET_M0253_HASH_ME
TComHash m_hashMap;
TComHash* getHashMap() { return &m_hashMap; }
const TComHash* getHashMap() const { return &m_hashMap; }
void addPictureToHashMapForInter();
#endif
CodingStructure* cs;
std::deque<Slice*> slices;
SEIMessages SEIs;
......
......@@ -695,6 +695,9 @@ void Slice::decodingRefreshMarking(int& pocCRA, bool& bRefreshPending, PicList&
if (rpcPic->getPOC() != pocCurr)
{
rpcPic->referenced = false;
#if JVET_M0253_HASH_ME
rpcPic->getHashMap()->clearAll();
#endif
}
iterPic++;
}
......@@ -722,6 +725,9 @@ void Slice::decodingRefreshMarking(int& pocCRA, bool& bRefreshPending, PicList&
if (rpcPic->getPOC() != pocCurr && rpcPic->getPOC() != m_iLastIDR)
{
rpcPic->referenced = false;
#if JVET_M0253_HASH_ME
rpcPic->getHashMap()->clearAll();
#endif
}
iterPic++;
}
......@@ -739,6 +745,9 @@ void Slice::decodingRefreshMarking(int& pocCRA, bool& bRefreshPending, PicList&
if (rpcPic->getPOC() != pocCurr && rpcPic->getPOC() != pocCRA)
{
rpcPic->referenced = false;
#if JVET_M0253_HASH_ME
rpcPic->getHashMap()->clearAll();
#endif
}
iterPic++;
}
......@@ -1150,6 +1159,9 @@ void Slice::applyReferencePictureSet( PicList& rcListPic, const ReferencePicture
pcPic->referenced = false;
pcPic->usedByCurr = false;
pcPic->longTerm = false;
#if JVET_M0253_HASH_ME
pcPic->getHashMap()->clearAll();
#endif
}
// sanity checks
......
......@@ -53,6 +53,8 @@
#define JVET_M0471_LONG_DEBLOCKING_FILTERS 1
#define JVET_M0470 1 // Fixed GR/TU+EG-k transition point, use limited prefix length for escape codes
#define JVET_M0253_HASH_ME 1
#define JVET_M0257 1 // Scan only non zero-out regions of large TUs
#define JVET_M0193_PAIR_AVG_REDUCTION 1 //Use only one pairwise average candidate
......
......@@ -243,6 +243,8 @@ protected:
#endif
#if JVET_M0246_AFFINE_AMVR
bool m_AffineAmvr;
#endif#if JVET_M0253_HASH_ME
bool m_HashME;
#endif
#if JVET_M0247_AFFINE_AMVR_ENCOPT
bool m_AffineAmvrEncOpt;
......@@ -766,6 +768,10 @@ public:
void setAllowDisFracMMVD ( bool b ) { m_allowDisFracMMVD = b; }
bool getAllowDisFracMMVD () const { return m_allowDisFracMMVD; }
#endif
#if JVET_M0253_HASH_ME
void setUseHashME ( bool b ) { m_HashME = b; }
bool getUseHashME () const { return m_HashME; }
#endif
#if JVET_M0246_AFFINE_AMVR
void setUseAffineAmvr ( bool b ) { m_AffineAmvr = b; }
bool getUseAffineAmvr () const { return m_AffineAmvr; }
......
......@@ -754,6 +754,12 @@ void EncCu::xCompressCU( CodingStructure *&tempCS, CodingStructure *&bestCS, Par
}
}
#if JVET_M0253_HASH_ME
else if (currTestMode.type == ETM_HASH_INTER)
{
xCheckRDCostHashInter( tempCS, bestCS, partitioner, currTestMode );
}
#endif
else if( currTestMode.type == ETM_AFFINE )
{
xCheckRDCostAffineMerge2Nx2N( tempCS, bestCS, partitioner, currTestMode );
......@@ -1721,7 +1727,56 @@ void EncCu::xFillPCMBuffer( CodingUnit &cu )
}
}
}
#if JVET_M0253_HASH_ME
void EncCu::xCheckRDCostHashInter( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
bool isPerfectMatch = false;
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
m_pcInterSearch->resetBufferedUniMotions();
m_pcInterSearch->setAffineModeSelected(false);
CodingUnit &cu = tempCS->addCU(tempCS->area, partitioner.chType);
partitioner.setCUData(cu);
cu.slice = tempCS->slice;
cu.skip = false;
cu.predMode = MODE_INTER;
cu.transQuantBypass = encTestMode.lossless;
cu.chromaQpAdj = cu.transQuantBypass ? 0 : m_cuChromaQpOffsetIdxPlus1;
cu.qp = encTestMode.qp;
cu.ibc = false;
CU::addPUs(cu);
cu.mmvdSkip = false;
cu.firstPU->mmvdMergeFlag = false;
if (m_pcInterSearch->predInterHashSearch(cu, partitioner, isPerfectMatch))
{
const unsigned wIdx = gp_sizeIdxInfo->idxFrom(tempCS->area.lwidth());
double equGBiCost = MAX_DOUBLE;
#if JVET_M0464_UNI_MTS
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0
, m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL
, 0
, &equGBiCost
#else
xEncodeInterResidual(tempCS, bestCS, partitioner, encTestMode, 0
, m_pImvTempCS ? m_pImvTempCS[wIdx] : NULL
, 1
, 0
, &equGBiCost
#endif
);
}
tempCS->initStructData(encTestMode.qp, encTestMode.lossless);
if (cu.lwidth() != 64)
{
isPerfectMatch = false;
}
m_modeCtrl->setIsHashPerfectMatch(isPerfectMatch);
}
#endif
void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode )
{
......@@ -2148,10 +2203,25 @@ void EncCu::xCheckRDCostMerge2Nx2N( CodingStructure *&tempCS, CodingStructure *&
}
}
#if !JVET_M0253_HASH_ME
const uint32_t iteration = encTestMode.lossless ? 1 : 2;
// 2. Pass: check candidates using full RD test
for( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ )
#else
uint32_t iteration;
uint32_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0;
if (encTestMode.lossless)
{
iteration = 1;
iterationBegin = 0;
}
else
{
iteration = 2;
}
for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass)
#endif
{
for( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
{
......@@ -2514,8 +2584,23 @@ void EncCu::xCheckRDCostMergeTriangle2Nx2N( CodingStructure *&tempCS, CodingStru
}
{
#if !JVET_M0253_HASH_ME
const uint8_t iteration = encTestMode.lossless ? 1 : 2;
for( uint8_t noResidualPass = 0; noResidualPass < iteration; noResidualPass++ )
#else
uint8_t iteration;
uint8_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0;
if (encTestMode.lossless)
{
iteration = 1;
iterationBegin = 0;
}
else
{
iteration = 2;
}
for (uint8_t noResidualPass = iterationBegin; noResidualPass < iteration; ++noResidualPass)
#endif
{
for( uint8_t mrgHADIdx = 0; mrgHADIdx < triangleNumMrgSATDCand; mrgHADIdx++ )
{
......@@ -2774,10 +2859,25 @@ void EncCu::xCheckRDCostAffineMerge2Nx2N( CodingStructure *&tempCS, CodingStruct
}
}
#if !JVET_M0253_HASH_ME
const uint32_t iteration = encTestMode.lossless ? 1 : 2;
// 2. Pass: check candidates using full RD test
for ( uint32_t uiNoResidualPass = 0; uiNoResidualPass < iteration; uiNoResidualPass++ )
#else
uint32_t iteration;
uint32_t iterationBegin = m_modeCtrl->getIsHashPerfectMatch() ? 1 : 0;
if (encTestMode.lossless)
{
iteration = 1;
iterationBegin = 0;
}
else
{
iteration = 2;
}
for (uint32_t uiNoResidualPass = iterationBegin; uiNoResidualPass < iteration; ++uiNoResidualPass)
#endif
{
for ( uint32_t uiMrgHADIdx = 0; uiMrgHADIdx < uiNumMrgSATDCand; uiMrgHADIdx++ )
{
......
......@@ -210,6 +210,9 @@ protected:
void xCheckDQP ( CodingStructure& cs, Partitioner& partitioner, bool bKeepCtx = false);
void xFillPCMBuffer ( CodingUnit &cu);
#if JVET_M0253_HASH_ME
void xCheckRDCostHashInter ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
#endif
void xCheckRDCostAffineMerge2Nx2N
( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &partitioner, const EncTestMode& encTestMode );
void xCheckRDCostInter ( CodingStructure *&tempCS, CodingStructure *&bestCS, Partitioner &pm, const EncTestMode& encTestMode );
......
......@@ -1643,6 +1643,75 @@ void EncGOP::compressGOP( int iPOCLast, int iNumPicRcvd, PicList& rcListPic,
// Set reference list
pcSlice->setRefPicList ( rcListPic );
#if JVET_M0253_HASH_ME
if (m_pcCfg->getUseHashME())
{
PicList::iterator iterPic = rcListPic.begin();
while (iterPic != rcListPic.end())
{
Picture* refPic = *(iterPic++);
if (refPic->poc != pcPic->poc && refPic->referenced)
{
if (!refPic->getHashMap()->isInitial())
{
if (refPic->getPOC() == 0)
{
Pel* picSrc = refPic->getOrigBuf().get(COMPONENT_Y).buf;
int stridePic = refPic->getOrigBuf().get(COMPONENT_Y).stride;
int picWidth = pcSlice->getSPS()->getPicWidthInLumaSamples();
int picHeight = pcSlice->getSPS()->getPicHeightInLumaSamples();
int blockSize = 4;
int allNum = 0;
int simpleNum = 0;
for (int j = 0; j <= picHeight - blockSize; j += blockSize)
{
for (int i = 0; i <= picWidth - blockSize; i += blockSize)
{
Pel* curBlock = picSrc + j * stridePic + i;
bool isHorSame = true;
for (int m = 0; m < blockSize&&isHorSame; m++)
{
for (int n = 1; n < blockSize&&isHorSame; n++)
{
if (curBlock[m*stridePic] != curBlock[m*stridePic + n])
{
isHorSame = false;
}
}
}
bool isVerSame = true;
for (int m = 1; m < blockSize&&isVerSame; m++)
{
for (int n = 0; n < blockSize&&isVerSame; n++)
{
if (curBlock[n] != curBlock[m*stridePic + n])
{
isVerSame = false;
}
}
}
allNum++;
if (isHorSame || isVerSame)
{
simpleNum++;
}
}
}
if (simpleNum < 0.3*allNum)
{
m_pcCfg->setUseHashME(false);
break;
}
}
refPic->addPictureToHashMapForInter();
}
}
}
}
#endif
if( m_pcCfg->getUseAMaxBT() )
{
if( !pcSlice->isIRAP() )
......
......@@ -84,9 +84,9 @@ void EncLib::create ()
{
// initialize global variables
initROM();
#if JVET_M0253_HASH_ME
TComHash::initBlockSizeToIndex();
#endif
m_iPOCLast = m_compositeRefEnabled ? -2 : -1;
// create processing unit classes
m_cGOPEncoder. create( );
......@@ -756,6 +756,9 @@ void EncLib::xGetNewPicBuffer ( std::list<PelUnitBuf*>& rcListPicYuvRecOut, Pict
rpcPic->setBorderExtension( false );
rpcPic->reconstructed = false;
rpcPic->referenced = true;
#if JVET_M0253_HASH_ME
rpcPic->getHashMap()->clearAll();
#endif
m_iPOCLast += (m_compositeRefEnabled ? 2 : 1);
m_iNumPicRcvd++;
......
......@@ -1183,6 +1183,15 @@ void EncModeCtrlMTnoRQT::initCULevel( Partitioner &partitioner, const CodingStru
m_ComprCUCtxList.back().testModes.push_back( { ETM_AFFINE, ETO_STANDARD, qp, lossless } );
}
}
#if JVET_M0253_HASH_ME
if (m_pcEncCfg->getUseHashME())
{
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))
{
m_ComprCUCtxList.back().testModes.push_back({ ETM_HASH_INTER, ETO_STANDARD, qp, lossless });
}
}
#endif
}
}
......@@ -1206,6 +1215,12 @@ bool EncModeCtrlMTnoRQT::tryMode( const EncTestMode& encTestmode, const CodingSt
ComprCUCtx& cuECtx = m_ComprCUCtxList.back();
// Fast checks, partitioning depended
#if JVET_M0253_HASH_ME
if (cuECtx.isHashPerfectMatch && encTestmode.type != ETM_MERGE_SKIP && encTestmode.type != ETM_AFFINE && encTestmode.type != ETM_MERGE_TRIANGLE)
{
return false;
}
#endif
// if early skip detected, skip all modes checking but the splits
if( cuECtx.earlySkip && m_pcEncCfg->getUseEarlySkipDetection() && !isModeSplit( encTestmode ) && !( isModeInter( encTestmode ) ) )
......
......@@ -54,6 +54,9 @@
enum EncTestModeType
{
#if JVET_M0253_HASH_ME
ETM_HASH_INTER,
#endif
ETM_MERGE_SKIP,
ETM_INTER_ME,
ETM_AFFINE,
......@@ -137,6 +140,9 @@ inline bool isModeInter( const EncTestMode& encTestmode ) // perhaps remove
|| encTestmode.type == ETM_MERGE_SKIP
|| encTestmode.type == ETM_AFFINE
|| encTestmode.type == ETM_MERGE_TRIANGLE
#if JVET_M0253_HASH_ME
|| encTestmode.type == ETM_HASH_INTER
#endif