这个函数是帧间进行KL变换之前,在插值图像中找到当前块的预测块的相似块
关键函数
candidateSearch()函数调用了searchCandidateFromOnePicInteger();
searchCandidateFromOnePicInteger()调用了xSetSearchRange();
下面依次注释:
candidateSearch()
Void TComTrQuant::candidateSearch(TComDataCU *pcCU, UInt uiPartAddr, UInt uiBlkSize, UInt uiTempSize)
{
ComponentID compID = COMPONENT_Y;
UInt uiPatchSize = uiBlkSize + uiTempSize;
UInt uiTarDepth = g_aucConvertToBit[uiBlkSize];
Pel **tarPatch = m_pppTarPatch[uiTarDepth];
Int iRefIdx[2] = { -1, -1 };
#if !VCEG_AZ08_INTER_KLT_MV_BUGFIXED
TComMv cMvs[2];
#endif
UInt uiTargetCandiNum = g_uiDepth2MaxCandiNum[uiTarDepth];
const Int channelBitDepth = pcCU->getSlice()->getSPS()->getBitDepth(toChannelType(compID));
//Initialize the library for saving the best candidates
m_tempLibFast.initDiff(uiPatchSize, channelBitDepth, uiTargetCandiNum);
Short setId = -1; //to record the reference picture.
Int iCurrPOC = pcCU->getPic()->getPOC();
Int iRefPOC = 0;
TComMv cMvRef;
Int iRefPOCs[2] = { 0, 0 };
TComMv cMvRefs[2];
cMvRefs[0].setZero();
cMvRefs[1].setZero();
Int filledNum = 0;
for (Int iRefList = 0; iRefList < 2; iRefList++)
{
RefPicList eRefPicList = (iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
iRefIdx[eRefPicList] = pcCU->getCUMvField(eRefPicList)->getRefIdx(uiPartAddr);
if (iRefIdx[eRefPicList] >= 0)
{
#if VCEG_AZ08_INTER_KLT_MV_BUGFIXED
cMvRefs[filledNum] = pcCU->getCUMvField(eRefPicList)->getMv(uiPartAddr);
#else
cMvRefs[filledNum] = cMvs[eRefPicList];
#endif
iRefPOCs[filledNum] = pcCU->getSlice()->getRefPic(eRefPicList, iRefIdx[eRefPicList])->getPOC();
filledNum++;
}
}
//for other reference frames not related with prediction
for (Int iRefList = 0; iRefList < 2; iRefList++)
{
RefPicList eRefPicList = (iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0);
for (Int iRefIdxTemp = 0; iRefIdxTemp < pcCU->getSlice()->getNumRefIdx(eRefPicList); iRefIdxTemp++)
{
TComMv cMv;
Int iTargetPOC = pcCU->getSlice()->getRefPic(eRefPicList, iRefIdxTemp)->getPOC();
Int minDistancePOC = MAX_INT;
Int distance;
//use the reference frame (having mvs) with nearest distacne from the current iTargetPOC
for (Int filledId = 0; filledId < filledNum; filledId++)
{
distance = abs(iRefPOCs[filledId] - iTargetPOC);
if (distance < minDistancePOC)
{
minDistancePOC = distance;
iRefPOC = iRefPOCs[filledId];
cMvRef = cMvRefs[filledId];
}
}
Double dScale = ((Double)(iCurrPOC - iTargetPOC) / (Double)(iCurrPOC - iRefPOC));
cMv.set((Short)(cMvRef.getHor()*dScale + 0.5), (Short)(cMvRef.getVer()*dScale + 0.5));
if (eRefPicList == REF_PIC_LIST_1)
{
//check whether the reference frames in list1 had appeared in list0, if so, will not use it to find candidates.
bool bSimilarSearchRegion = false;
for (Int iRefIdxList0 = 0; iRefIdxList0 < pcCU->getSlice()->getNumRefIdx(REF_PIC_LIST_0); iRefIdxList0++)
{
UInt prevPicPOCList0 = pcCU->getSlice()->getRefPic(eRefPicList, iRefIdxList0)->getPOC();
if (prevPicPOCList0 == iTargetPOC)
{
bSimilarSearchRegion = true;
break; //had appeared in list0 for this reference in list1
}
}
if (bSimilarSearchRegion)
{
continue;
}
}
/***************************************************************************************/
//get参考帧首地址*refPic
TComPic* refPic = pcCU->getSlice()->getRefPic(eRefPicList, iRefIdxTemp);
UInt uiRow = 0;
UInt uiCol = 0;
//get重建参考帧
//uiRow = 0uiCol = 0表示重建参考帧;
//uiRow = 1,0uiCol = 0表示水平方向进行1/4插值后的参考帧
//uiRow = 0,0uiCol = 1表示水平方向进行1/4插值后的参考帧,以此类推
TComPicYuv *refPicRec = refPic->getPicQuaYuvRec(uiRow, uiCol);
//get当前块在当前帧位置,并找出同样位置在参考帧中的地址
//即找出当前帧和参考帧同位PU的位置
Pel *ref = refPicRec->getAddr(compID, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu() + uiPartAddr);
setId++;
setRefPicUsed(setId, ref); //to facilitate the access of each candidate point
setRefPicBuf(setId, refPic);
setStride(refPicRec->getStride(compID));
searchCandidateFromOnePicInteger(pcCU, uiPartAddr, refPicRec, cMv, tarPatch, uiPatchSize, uiTempSize, setId);
}
}
Short setIdFraStart = setId + 1;
RecordPosition(uiTargetCandiNum);
searchCandidateFraBasedOnInteger(pcCU, tarPatch, uiPatchSize, uiTempSize, uiPartAddr, setIdFraStart);
}
searchCandidateFromOnePicInteger()
Void TComTrQuant::searchCandidateFromOnePicInteger(TComDataCU *pcCU, UInt uiPartAddr, TComPicYuv *refPic, TComMv cMv, Pel **tarPatch, UInt uiPatchSize, UInt uiTempSize, UInt setId)
{
const ComponentID compID = COMPONENT_Y;
UInt uiBlkSize = uiPatchSize - uiTempSize;
UInt uiTarDepth = g_aucConvertToBit[uiBlkSize];
UInt uiTargetCandiNum = g_uiDepth2MaxCandiNum[uiTarDepth];
UInt uiLibSizeMinusOne = uiTargetCandiNum - 1;
m_uiPartLibSize = uiTargetCandiNum;
Int *pX = m_tempLibFast.getX();
Int *pY = m_tempLibFast.getY();
DistType *pDiff = m_tempLibFast.getDiff();
Short *pId = m_tempLibFast.getId();
Int refStride = refPic->getStride(compID);
//同位PU
Pel *ref = refPic->getAddr(compID, pcCU->getCtuRsAddr(), pcCU->getZorderIdxInCtu() + uiPartAddr);
Int iSrchRng = SEARCHRANGE;
TComMv cMvSrchRngLT;
TComMv cMvSrchRngRB;
//设置加上搜索范围之后,当前块和预测值,在当前帧和未插值的参考帧中的整数位移
xSetSearchRange(pcCU, cMv, iSrchRng, cMvSrchRngLT, cMvSrchRngRB);
Int mvYMin = cMvSrchRngLT.getVer();
Int mvYMax = cMvSrchRngRB.getVer();
Int mvXMin = cMvSrchRngLT.getHor();
Int mvXMax = cMvSrchRngRB.getHor();
//search
//在未插值参考帧中的搜索起点*refMove
Pel *refMove = ref + mvYMin*refStride + mvXMin;
DistType *pDiffEnd = &pDiff[uiLibSizeMinusOne];
DistType diff;
for (Int iYOffset = mvYMin; iYOffset <= mvYMax; iYOffset++)
{
Pel *refCurr = refMove;
for (Int iXOffset = mvXMin; iXOffset <= mvXMax; iXOffset++)
{
//The position of the leftup pixel within this block: refCurr = ref + iYOffset*refStride + iXOffset;
diff = calcPatchDiff(refCurr, refStride, tarPatch, uiPatchSize, uiTempSize, *pDiffEnd);
refCurr++;
if (diff > 0 && diff < (*pDiffEnd))//when residual is zero, may not contribute to the distribution.
{
insertNode(diff, iXOffset, iYOffset, pDiff, pX, pY, pId, uiLibSizeMinusOne, setId);
}
}
refMove += refStride;
}
}
xSetSearchRange()
Void TComTrQuant::xSetSearchRange(TComDataCU* pcCU, TComMv& cMvPred, Int iSrchRng, TComMv& rcMvSrchRngLT, TComMv& rcMvSrchRngRB)
{
Int iMvShift = 2;
#if VCEG_AZ08_INTER_KLT_MV_BUGFIXED
#if VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE
iMvShift += VCEG_AZ07_MV_ADD_PRECISION_BIT_FOR_STORE;
#endif
#endif
//需要注意的是,cTmpMvPred对应1/4插值后的运动向量
TComMv cTmpMvPred = cMvPred;
pcCU->clipMv(cTmpMvPred);
//iSrchRng对应1/4插值之后范围
rcMvSrchRngLT.setHor(cTmpMvPred.getHor() - (iSrchRng << iMvShift));
rcMvSrchRngLT.setVer(cTmpMvPred.getVer() - (iSrchRng << iMvShift));
rcMvSrchRngRB.setHor(cTmpMvPred.getHor() + (iSrchRng << iMvShift));
rcMvSrchRngRB.setVer(cTmpMvPred.getVer() + (iSrchRng << iMvShift));
pcCU->clipMv(rcMvSrchRngLT);
pcCU->clipMv(rcMvSrchRngRB);
//运动矢量值向右移动2位,即保留除4后的整数部分。
//此时的运动矢量为当前块和预测块,在当前帧和未插值的参考帧中的整数位移
rcMvSrchRngLT >>= iMvShift;
rcMvSrchRngRB >>= iMvShift;
}