4f594deff9
This makes sure we don't accidentally return the same sequence of random numbers multiple times within one test (which would be very non-random). Every time srand(time()) is called, the pseudo random number generator is initialized to the same value (as long as time() returned the same value). By initializing the random number generator once and for all before starting to run the unit tests, we are sure we don't need to reinitialize it within all the tests and all the functions that use random numbers. This fixes occasional errors in MotionEstimateTest. MotionEstimateTest was designed to allow the test to occasionally not succeed - if it didn't succeed, it tried again, up to 100 times. However, since the YUVPixelDataGenerator function reset the random seed to time(), every attempt actually ran with the same random data (as long as all 100 attempts ran within 1 second) - thus if one attempt in MotionEstimateTest failed, all 100 of them would fail. If the utility functions don't touch the random seed, this is not an issue.
661 lines
23 KiB
C++
661 lines
23 KiB
C++
#include<gtest/gtest.h>
|
|
|
|
#include "wels_common_basis.h"
|
|
#include "mem_align.h"
|
|
#include "mv_pred.h"
|
|
#include "ls_defines.h"
|
|
|
|
using namespace WelsDec;
|
|
|
|
//Anchor functions
|
|
#define REF_NOT_AVAIL -2
|
|
#define REF_NOT_IN_LIST -1 //intra
|
|
|
|
//cache element equal to 30
|
|
const uint8_t g_kuiAnchorCache30ScanIdx[16] = { //mv or ref_index cache scan index, 4*4 block as basic unit
|
|
7, 8, 13, 14,
|
|
9, 10, 15, 16,
|
|
19, 20, 25, 26,
|
|
21, 22, 27, 28
|
|
};
|
|
|
|
typedef struct TagAnchorMvPred {
|
|
int16_t iMvArray[2][30][2];
|
|
int8_t iRefIdxArray[2][30];
|
|
int32_t iPartIdx;
|
|
int32_t iPartWidth;
|
|
int32_t iRef;
|
|
int16_t iMvp[2];
|
|
} SAnchorMvPred;
|
|
|
|
void AnchorPredMv (int16_t iMotionVector[LIST_A][30][MV_A], int8_t iRefIndex[LIST_A][30],
|
|
int32_t iPartIdx, int32_t iPartWidth, int8_t iRef, int16_t iMVP[2]) {
|
|
const uint8_t kuiLeftIdx = g_kuiAnchorCache30ScanIdx[iPartIdx] - 1;
|
|
const uint8_t kuiTopIdx = g_kuiAnchorCache30ScanIdx[iPartIdx] - 6;
|
|
const uint8_t kuiRightTopIdx = kuiTopIdx + iPartWidth;
|
|
const uint8_t kuiLeftTopIdx = kuiTopIdx - 1;
|
|
const int8_t kiLeftRef = iRefIndex[0][kuiLeftIdx];
|
|
const int8_t kiTopRef = iRefIndex[0][kuiTopIdx];
|
|
const int8_t kiRightTopRef = iRefIndex[0][kuiRightTopIdx];
|
|
const int8_t kiLeftTopRef = iRefIndex[0][kuiLeftTopIdx];
|
|
int8_t iDiagonalRef = kiRightTopRef;
|
|
int8_t iMatchRef = 0;
|
|
|
|
int16_t iAMV[2], iBMV[2], iCMV[2];
|
|
|
|
* (int32_t*)iAMV = INTD32 (iMotionVector[0][kuiLeftIdx]);
|
|
* (int32_t*)iBMV = INTD32 (iMotionVector[0][kuiTopIdx]);
|
|
* (int32_t*)iCMV = INTD32 (iMotionVector[0][kuiRightTopIdx]);
|
|
|
|
if (REF_NOT_AVAIL == iDiagonalRef) {
|
|
iDiagonalRef = kiLeftTopRef;
|
|
* (int32_t*)iCMV = INTD32 (iMotionVector[0][kuiLeftTopIdx]);
|
|
}
|
|
|
|
iMatchRef = (iRef == kiLeftRef) + (iRef == kiTopRef) + (iRef == iDiagonalRef);
|
|
|
|
if ((REF_NOT_AVAIL == kiTopRef) && (REF_NOT_AVAIL == iDiagonalRef) && (kiLeftRef >= REF_NOT_IN_LIST)) {
|
|
ST32 (iMVP, LD32 (iAMV));
|
|
return;
|
|
}
|
|
|
|
if (1 == iMatchRef) {
|
|
if (iRef == kiLeftRef) {
|
|
ST32 (iMVP, LD32 (iAMV));
|
|
} else if (iRef == kiTopRef) {
|
|
ST32 (iMVP, LD32 (iBMV));
|
|
} else {
|
|
ST32 (iMVP, LD32 (iCMV));
|
|
}
|
|
} else {
|
|
iMVP[0] = WelsMedian (iAMV[0], iBMV[0], iCMV[0]);
|
|
iMVP[1] = WelsMedian (iAMV[1], iBMV[1], iCMV[1]);
|
|
}
|
|
}
|
|
|
|
void AnchorPredInter8x16Mv (int16_t iMotionVector[LIST_A][30][MV_A], int8_t iRefIndex[LIST_A][30],
|
|
int32_t iPartIdx, int8_t iRef, int16_t iMVP[2]) {
|
|
if (0 == iPartIdx) {
|
|
const int8_t kiLeftRef = iRefIndex[0][6];
|
|
if (iRef == kiLeftRef) {
|
|
ST32 (iMVP, LD32 (&iMotionVector[0][6][0]));
|
|
return;
|
|
}
|
|
} else { // 4 == iPartIdx
|
|
int8_t iDiagonalRef = iRefIndex[0][5]; //top-right
|
|
int8_t index = 5;
|
|
if (REF_NOT_AVAIL == iDiagonalRef) {
|
|
iDiagonalRef = iRefIndex[0][2]; //top-left for 8*8 block(index 1)
|
|
index = 2;
|
|
}
|
|
if (iRef == iDiagonalRef) {
|
|
ST32 (iMVP, LD32 (&iMotionVector[0][index][0]));
|
|
return;
|
|
}
|
|
}
|
|
|
|
AnchorPredMv (iMotionVector, iRefIndex, iPartIdx, 2, iRef, iMVP);
|
|
}
|
|
|
|
void AnchorPredInter16x8Mv (int16_t iMotionVector[LIST_A][30][MV_A], int8_t iRefIndex[LIST_A][30],
|
|
int32_t iPartIdx, int8_t iRef, int16_t iMVP[2]) {
|
|
if (0 == iPartIdx) {
|
|
const int8_t kiTopRef = iRefIndex[0][1];
|
|
if (iRef == kiTopRef) {
|
|
ST32 (iMVP, LD32 (&iMotionVector[0][1][0]));
|
|
return;
|
|
}
|
|
} else { // 8 == iPartIdx
|
|
const int8_t kiLeftRef = iRefIndex[0][18];
|
|
if (iRef == kiLeftRef) {
|
|
ST32 (iMVP, LD32 (&iMotionVector[0][18][0]));
|
|
return;
|
|
}
|
|
}
|
|
|
|
AnchorPredMv (iMotionVector, iRefIndex, iPartIdx, 4, iRef, iMVP);
|
|
}
|
|
|
|
|
|
//Ref functions in WelsDec
|
|
//Input structure for test
|
|
typedef struct TagWelsMvPred {
|
|
int16_t iMvArray[2][30][2];
|
|
int8_t iRefIdxArray[2][30];
|
|
int32_t iPartIdx;
|
|
int32_t iPartWidth;
|
|
int32_t iRef;
|
|
int16_t iMvp[2];
|
|
} SWelsMvPred;
|
|
|
|
//mok input data
|
|
void AssignMvInputData (SAnchorMvPred* pAncMvPred) {
|
|
int32_t i, j, k;
|
|
//fill MV data and refIdx
|
|
for (i = 0; i < 2; ++i) {
|
|
for (j = 0; j < 30; ++j) {
|
|
for (k = 0; k < 2; ++k) {
|
|
pAncMvPred->iMvArray[i][j][k] = (rand() - RAND_MAX / 2);
|
|
}
|
|
pAncMvPred->iRefIdxArray[i][j] = (rand() % 18) - 2; //-2 ~ 15. 8x8 may have different values, but it matters nothing
|
|
}
|
|
}
|
|
}
|
|
|
|
void CopyMvInputData (SWelsMvPred* pDstMvPred, SAnchorMvPred* pSrcMvPred) {
|
|
int32_t i, j, k;
|
|
//fill MV data and refIdx
|
|
for (i = 0; i < 2; ++i) {
|
|
for (j = 0; j < 30; ++j) {
|
|
for (k = 0; k < 2; ++k) {
|
|
pDstMvPred->iMvArray[i][j][k] = pSrcMvPred->iMvArray[i][j][k];
|
|
}
|
|
pDstMvPred->iRefIdxArray[i][j] = pSrcMvPred->iRefIdxArray[i][j];
|
|
}
|
|
}
|
|
}
|
|
|
|
#define INIT_MV_DATA \
|
|
AssignMvInputData (&sAncMvPred); \
|
|
CopyMvInputData (&sWelsMvPred, &sAncMvPred);
|
|
|
|
#define TEST_MV_PRED \
|
|
AnchorPredMv (sAncMvPred.iMvArray, sAncMvPred.iRefIdxArray, iIndex, iBlockWidth, iRef, sAncMvPred.iMvp); \
|
|
PredMv (sWelsMvPred.iMvArray, sWelsMvPred.iRefIdxArray, iIndex, iBlockWidth, iRef, sWelsMvPred.iMvp); \
|
|
bOK = ((sAncMvPred.iMvp[0] == sWelsMvPred.iMvp[0]) && (sAncMvPred.iMvp[1] == sWelsMvPred.iMvp[1])); \
|
|
EXPECT_EQ (bOK, true);
|
|
|
|
|
|
//TEST cases followed
|
|
|
|
TEST (PredMvTest, PredMv) {
|
|
SWelsMvPred sWelsMvPred;
|
|
SAnchorMvPred sAncMvPred;
|
|
int32_t i, iRef, iBlockWidth, iIndex;
|
|
const int32_t kiRandTime = 100;
|
|
bool bOK = true;
|
|
|
|
//test specific input: 16x16
|
|
iIndex = 0;
|
|
iBlockWidth = 4;
|
|
i = 0;
|
|
while (i++ < kiRandTime) {
|
|
iRef = (rand() % 18) - 2; //-2~15
|
|
INIT_MV_DATA;
|
|
TEST_MV_PRED;
|
|
}
|
|
//test specific input: 16x8
|
|
iBlockWidth = 4;
|
|
i = 0;
|
|
while (i++ < kiRandTime) {
|
|
iIndex = (rand() & 1) << 3; //0,8
|
|
iRef = (rand() % 18) - 2; //-2~15
|
|
INIT_MV_DATA;
|
|
TEST_MV_PRED;
|
|
}
|
|
//test specific input: 8x16
|
|
iBlockWidth = 2;
|
|
i = 0;
|
|
while (i++ < kiRandTime) {
|
|
iIndex = (rand() & 1) << 2; //0,4
|
|
iRef = (rand() % 18) - 2; //-2~15
|
|
INIT_MV_DATA;
|
|
TEST_MV_PRED;
|
|
}
|
|
//test specific input: 8x8
|
|
iBlockWidth = 2;
|
|
i = 0;
|
|
while (i++ < kiRandTime) {
|
|
iIndex = (rand() & 3) << 2; //0,4,8,12
|
|
iRef = (rand() % 18) - 2; //-2~15
|
|
INIT_MV_DATA;
|
|
TEST_MV_PRED;
|
|
}
|
|
//test specific input: 4x4
|
|
iBlockWidth = 1;
|
|
i = 0;
|
|
while (i++ < kiRandTime) {
|
|
iIndex = rand() & 0x0f; //0~15
|
|
iRef = (rand() % 18) - 2; //-2~15
|
|
INIT_MV_DATA;
|
|
TEST_MV_PRED;
|
|
}
|
|
} //TEST PredMv
|
|
|
|
|
|
TEST (PredMvTest, PredInter16x8Mv) {
|
|
SWelsMvPred sWelsMvPred;
|
|
SAnchorMvPred sAncMvPred;
|
|
int32_t i, iRef, iIndex;
|
|
const int32_t kiRandTime = 100;
|
|
bool bOK = true;
|
|
|
|
i = 0;
|
|
while (i++ < kiRandTime) {
|
|
iIndex = (rand() & 1) << 3; //0, 8
|
|
iRef = (rand() % 18) - 2; //-2~15
|
|
INIT_MV_DATA;
|
|
AnchorPredInter16x8Mv (sAncMvPred.iMvArray, sAncMvPred.iRefIdxArray, iIndex, iRef, sAncMvPred.iMvp);
|
|
PredInter16x8Mv (sWelsMvPred.iMvArray, sWelsMvPred.iRefIdxArray, iIndex, iRef, sWelsMvPred.iMvp);
|
|
bOK = ((sAncMvPred.iMvp[0] == sWelsMvPred.iMvp[0]) && (sAncMvPred.iMvp[1] == sWelsMvPred.iMvp[1]));
|
|
EXPECT_EQ (bOK, true);
|
|
}
|
|
} //TEST PredInter16x8Mv
|
|
|
|
TEST (PredMvTest, PredInter8x16Mv) {
|
|
SWelsMvPred sWelsMvPred;
|
|
SAnchorMvPred sAncMvPred;
|
|
int32_t i, iRef, iIndex;
|
|
const int32_t kiRandTime = 100;
|
|
bool bOK = true;
|
|
|
|
i = 0;
|
|
while (i++ < kiRandTime) {
|
|
iIndex = (rand() & 1) << 2; //0, 4
|
|
iRef = (rand() % 18) - 2; //-2~15
|
|
INIT_MV_DATA;
|
|
AnchorPredInter8x16Mv (sAncMvPred.iMvArray, sAncMvPred.iRefIdxArray, iIndex, iRef, sAncMvPred.iMvp);
|
|
PredInter8x16Mv (sWelsMvPred.iMvArray, sWelsMvPred.iRefIdxArray, iIndex, iRef, sWelsMvPred.iMvp);
|
|
bOK = ((sAncMvPred.iMvp[0] == sWelsMvPred.iMvp[0]) && (sAncMvPred.iMvp[1] == sWelsMvPred.iMvp[1]));
|
|
EXPECT_EQ (bOK, true);
|
|
}
|
|
} //TEST PredInter16x8Mv
|
|
|
|
void AnchorPredPSkipMvFromNeighbor (PDqLayer pCurLayer, int16_t iMvp[2]) {
|
|
bool bTopAvail, bLeftTopAvail, bRightTopAvail, bLeftAvail;
|
|
|
|
int32_t iCurSliceIdc, iTopSliceIdc, iLeftTopSliceIdc, iRightTopSliceIdc, iLeftSliceIdc;
|
|
int32_t iLeftTopType, iRightTopType, iTopType, iLeftType;
|
|
int32_t iCurX, iCurY, iCurXy, iLeftXy, iTopXy, iLeftTopXy, iRightTopXy = 0;
|
|
|
|
int8_t iLeftRef;
|
|
int8_t iTopRef;
|
|
int8_t iRightTopRef;
|
|
int8_t iLeftTopRef;
|
|
int8_t iDiagonalRef;
|
|
int8_t iMatchRef;
|
|
int16_t iMvA[2], iMvB[2], iMvC[2], iMvD[2];
|
|
|
|
iCurXy = pCurLayer->iMbXyIndex;
|
|
iCurX = pCurLayer->iMbX;
|
|
iCurY = pCurLayer->iMbY;
|
|
iCurSliceIdc = pCurLayer->pSliceIdc[iCurXy];
|
|
|
|
if (iCurX != 0) {
|
|
iLeftXy = iCurXy - 1;
|
|
iLeftSliceIdc = pCurLayer->pSliceIdc[iLeftXy];
|
|
bLeftAvail = (iLeftSliceIdc == iCurSliceIdc);
|
|
} else {
|
|
bLeftAvail = 0;
|
|
bLeftTopAvail = 0;
|
|
}
|
|
|
|
if (iCurY != 0) {
|
|
iTopXy = iCurXy - pCurLayer->iMbWidth;
|
|
iTopSliceIdc = pCurLayer->pSliceIdc[iTopXy];
|
|
bTopAvail = (iTopSliceIdc == iCurSliceIdc);
|
|
if (iCurX != 0) {
|
|
iLeftTopXy = iTopXy - 1;
|
|
iLeftTopSliceIdc = pCurLayer->pSliceIdc[iLeftTopXy];
|
|
bLeftTopAvail = (iLeftTopSliceIdc == iCurSliceIdc);
|
|
} else {
|
|
bLeftTopAvail = 0;
|
|
}
|
|
if (iCurX != (pCurLayer->iMbWidth - 1)) {
|
|
iRightTopXy = iTopXy + 1;
|
|
iRightTopSliceIdc = pCurLayer->pSliceIdc[iRightTopXy];
|
|
bRightTopAvail = (iRightTopSliceIdc == iCurSliceIdc);
|
|
} else {
|
|
bRightTopAvail = 0;
|
|
}
|
|
} else {
|
|
bTopAvail = 0;
|
|
bLeftTopAvail = 0;
|
|
bRightTopAvail = 0;
|
|
}
|
|
|
|
iLeftType = ((iCurX != 0 && bLeftAvail) ? pCurLayer->pMbType[iLeftXy] : 0);
|
|
iTopType = ((iCurY != 0 && bTopAvail) ? pCurLayer->pMbType[iTopXy] : 0);
|
|
iLeftTopType = ((iCurX != 0 && iCurY != 0 && bLeftTopAvail)
|
|
? pCurLayer->pMbType[iLeftTopXy] : 0);
|
|
iRightTopType = ((iCurX != pCurLayer->iMbWidth - 1 && iCurY != 0 && bRightTopAvail)
|
|
? pCurLayer->pMbType[iRightTopXy] : 0);
|
|
|
|
/*get neb mv&iRefIdxArray*/
|
|
/*left*/
|
|
if (bLeftAvail && IS_INTER (iLeftType)) {
|
|
ST32 (iMvA, LD32 (pCurLayer->pMv[0][iLeftXy][3]));
|
|
iLeftRef = pCurLayer->pRefIndex[0][iLeftXy][3];
|
|
} else {
|
|
ST32 (iMvA, 0);
|
|
if (0 == bLeftAvail) { //not available
|
|
iLeftRef = REF_NOT_AVAIL;
|
|
} else { //available but is intra mb type
|
|
iLeftRef = REF_NOT_IN_LIST;
|
|
}
|
|
}
|
|
if (REF_NOT_AVAIL == iLeftRef ||
|
|
(0 == iLeftRef && 0 == * (int32_t*)iMvA)) {
|
|
ST32 (iMvp, 0);
|
|
return;
|
|
}
|
|
|
|
/*top*/
|
|
if (bTopAvail && IS_INTER (iTopType)) {
|
|
ST32 (iMvB, LD32 (pCurLayer->pMv[0][iTopXy][12]));
|
|
iTopRef = pCurLayer->pRefIndex[0][iTopXy][12];
|
|
} else {
|
|
ST32 (iMvB, 0);
|
|
if (0 == bTopAvail) { //not available
|
|
iTopRef = REF_NOT_AVAIL;
|
|
} else { //available but is intra mb type
|
|
iTopRef = REF_NOT_IN_LIST;
|
|
}
|
|
}
|
|
if (REF_NOT_AVAIL == iTopRef ||
|
|
(0 == iTopRef && 0 == * (int32_t*)iMvB)) {
|
|
ST32 (iMvp, 0);
|
|
return;
|
|
}
|
|
|
|
/*right_top*/
|
|
if (bRightTopAvail && IS_INTER (iRightTopType)) {
|
|
ST32 (iMvC, LD32 (pCurLayer->pMv[0][iRightTopXy][12]));
|
|
iRightTopRef = pCurLayer->pRefIndex[0][iRightTopXy][12];
|
|
} else {
|
|
ST32 (iMvC, 0);
|
|
if (0 == bRightTopAvail) { //not available
|
|
iRightTopRef = REF_NOT_AVAIL;
|
|
} else { //available but is intra mb type
|
|
iRightTopRef = REF_NOT_IN_LIST;
|
|
}
|
|
}
|
|
|
|
/*left_top*/
|
|
if (bLeftTopAvail && IS_INTER (iLeftTopType)) {
|
|
ST32 (iMvD, LD32 (pCurLayer->pMv[0][iLeftTopXy][15]));
|
|
iLeftTopRef = pCurLayer->pRefIndex[0][iLeftTopXy][15];
|
|
} else {
|
|
ST32 (iMvD, 0);
|
|
if (0 == bLeftTopAvail) { //not available
|
|
iLeftTopRef = REF_NOT_AVAIL;
|
|
} else { //available but is intra mb type
|
|
iLeftTopRef = REF_NOT_IN_LIST;
|
|
}
|
|
}
|
|
|
|
iDiagonalRef = iRightTopRef;
|
|
if (REF_NOT_AVAIL == iDiagonalRef) {
|
|
iDiagonalRef = iLeftTopRef;
|
|
* (int32_t*)iMvC = * (int32_t*)iMvD;
|
|
}
|
|
|
|
if (REF_NOT_AVAIL == iTopRef && REF_NOT_AVAIL == iDiagonalRef && iLeftRef >= REF_NOT_IN_LIST) {
|
|
ST32 (iMvp, LD32 (iMvA));
|
|
return;
|
|
}
|
|
|
|
iMatchRef = (0 == iLeftRef) + (0 == iTopRef) + (0 == iDiagonalRef);
|
|
if (1 == iMatchRef) {
|
|
if (0 == iLeftRef) {
|
|
ST32 (iMvp, LD32 (iMvA));
|
|
} else if (0 == iTopRef) {
|
|
ST32 (iMvp, LD32 (iMvB));
|
|
} else {
|
|
ST32 (iMvp, LD32 (iMvC));
|
|
}
|
|
} else {
|
|
iMvp[0] = WelsMedian (iMvA[0], iMvB[0], iMvC[0]);
|
|
iMvp[1] = WelsMedian (iMvA[1], iMvB[1], iMvC[1]);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int32_t AllocLayerData (PDqLayer pDqLayer) {
|
|
|
|
pDqLayer->pSliceIdc = (int32_t*) WelsMalloc (pDqLayer->iMbWidth * pDqLayer->iMbHeight * sizeof (int32_t),
|
|
"pDqLayer->pSliceIdc");
|
|
if (pDqLayer->pSliceIdc == NULL)
|
|
return 1;
|
|
|
|
pDqLayer->pMbType = (int8_t*) WelsMalloc (pDqLayer->iMbWidth * pDqLayer->iMbHeight * sizeof (int8_t),
|
|
"pDqLayer->pMbType");
|
|
if (pDqLayer->pMbType == NULL)
|
|
return 1;
|
|
|
|
pDqLayer->pMv[0] = (int16_t (*)[MB_BLOCK4x4_NUM][MV_A]) WelsMalloc (pDqLayer->iMbWidth * pDqLayer->iMbHeight * sizeof (
|
|
int16_t) * MV_A * MB_BLOCK4x4_NUM, "pDqLayer->pMv");
|
|
if (pDqLayer->pMv[0] == NULL)
|
|
return 1;
|
|
|
|
pDqLayer->pRefIndex[0] = (int8_t (*)[MB_BLOCK4x4_NUM]) WelsMalloc (pDqLayer->iMbWidth * pDqLayer->iMbHeight * sizeof (
|
|
int8_t) * MB_BLOCK4x4_NUM, "pDqLayer->pRefIndex");
|
|
if (pDqLayer->pRefIndex[0] == NULL)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t FreeLayerData (PDqLayer pDqLayer) {
|
|
|
|
if (pDqLayer->pSliceIdc != NULL) {
|
|
WelsFree (pDqLayer->pSliceIdc, "pDqLayer->pSliceIdc");
|
|
pDqLayer->pSliceIdc = NULL;
|
|
}
|
|
|
|
if (pDqLayer->pMbType != NULL) {
|
|
WelsFree (pDqLayer->pMbType, "pDqLayer->pMbType");
|
|
pDqLayer->pMbType = NULL;
|
|
}
|
|
|
|
if (pDqLayer->pMv[0] != NULL) {
|
|
WelsFree (pDqLayer->pMv[0], "pDqlayer->pMv[0]");
|
|
pDqLayer->pMv[0] = NULL;
|
|
}
|
|
|
|
if (pDqLayer->pRefIndex[0] != NULL) {
|
|
WelsFree (pDqLayer->pRefIndex[0], "pDqlayer->pRefIndex[0]");
|
|
pDqLayer->pRefIndex[0] = NULL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void InitRandomLayerSliceIdc (PDqLayer pDqLayer) {
|
|
int32_t i = 0;
|
|
int32_t iTotalMbNum = pDqLayer->iMbWidth * pDqLayer->iMbHeight;
|
|
int32_t iMbFirstSliceEnd = rand() % (iTotalMbNum - 1); //assure 2 slices
|
|
for (i = 0; i <= iMbFirstSliceEnd; ++i) {
|
|
pDqLayer->pSliceIdc[i] = 0; //to keep simple value here
|
|
}
|
|
for (; i < iTotalMbNum; ++i) {
|
|
pDqLayer->pSliceIdc[i] = 1; //to keep simple value here
|
|
}
|
|
}
|
|
|
|
void InitRandomLayerMbType (PDqLayer pDqLayer) {
|
|
for (int32_t i = 0; i < pDqLayer->iMbWidth * pDqLayer->iMbHeight; ++i) {
|
|
pDqLayer->pMbType[i] = (rand() & 0x0f) + 1; //1 ~ 16
|
|
}
|
|
}
|
|
|
|
void InitRandomLayerMvData (PDqLayer pDqLayer) {
|
|
for (int32_t i = 0; i < pDqLayer->iMbWidth * pDqLayer->iMbHeight; ++i) {
|
|
for (int32_t j = 0; j < MB_BLOCK4x4_NUM; ++j) {
|
|
for (int32_t k = 0; k < MV_A; ++k) {
|
|
pDqLayer->pMv[0][i][j][k] = (rand() - RAND_MAX / 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void InitRandomLayerRefIdxData (PDqLayer pDqLayer) {
|
|
for (int32_t i = 0; i < pDqLayer->iMbWidth * pDqLayer->iMbHeight; ++i) {
|
|
for (int32_t j = 0; j < MB_BLOCK4x4_NUM; ++j) {
|
|
pDqLayer->pRefIndex[0][i][j] = (rand() % 18 - 2); //-2 ~ 15
|
|
}
|
|
}
|
|
}
|
|
|
|
void InitRandomLayerData (PDqLayer pDqLayer) {
|
|
InitRandomLayerSliceIdc (pDqLayer);
|
|
InitRandomLayerMbType (pDqLayer);
|
|
InitRandomLayerMvData (pDqLayer);
|
|
InitRandomLayerRefIdxData (pDqLayer);
|
|
}
|
|
|
|
#define TEST_SKIP_MV_PRED \
|
|
PredPSkipMvFromNeighbor (&sDqLayer, iWelsMvp); \
|
|
bOK = ((iWelsMvp[0] == iAncMvp[0]) && (iWelsMvp[1] == iAncMvp[1])); \
|
|
EXPECT_EQ (bOK, true);
|
|
|
|
TEST (PredMvTest, PredSkipMvFromNeighbor) {
|
|
const int32_t kiRandTime = 100;
|
|
bool bOK = true;
|
|
SDqLayer sDqLayer;
|
|
int16_t iAncMvp[2], iWelsMvp[2];
|
|
|
|
memset (&sDqLayer, 0, sizeof (SDqLayer));
|
|
//Assume the input data as 352x288 size
|
|
//allocate the data
|
|
sDqLayer.iMbWidth = 11;
|
|
sDqLayer.iMbHeight = 9;
|
|
if (AllocLayerData (&sDqLayer)) { //memory allocate failed
|
|
FreeLayerData (&sDqLayer);
|
|
return;
|
|
}
|
|
InitRandomLayerData (&sDqLayer); //init MV data, as it would not affect the following logic test
|
|
|
|
#define CURR_MB_IDX (sDqLayer.iMbXyIndex)
|
|
#define LEFT_MB_IDX (sDqLayer.iMbXyIndex - 1)
|
|
#define LEFT_MB_BLK 3
|
|
#define TOP_MB_IDX (sDqLayer.iMbXyIndex - sDqLayer.iMbWidth)
|
|
#define TOP_MB_BLK 12
|
|
#define LEFT_TOP_MB_IDX (sDqLayer.iMbXyIndex - sDqLayer.iMbWidth - 1)
|
|
#define LEFT_TOP_MB_BLK 15
|
|
#define RIGHT_TOP_MB_IDX (sDqLayer.iMbXyIndex - sDqLayer.iMbWidth + 1)
|
|
#define RIGHT_TOP_MB_BLK 12
|
|
|
|
//CASE 1: test MB [0,0], expect mvp = (0,0)
|
|
sDqLayer.iMbX = 0;
|
|
sDqLayer.iMbY = 0;
|
|
sDqLayer.iMbXyIndex = sDqLayer.iMbY * sDqLayer.iMbWidth + sDqLayer.iMbX;
|
|
iAncMvp[0] = iAncMvp[1] = 0; //expect anchor result to 0
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 2: test MB [ANY, 0], expect mvp = (0,0)
|
|
sDqLayer.iMbX = rand() % sDqLayer.iMbWidth;
|
|
sDqLayer.iMbY = 0;
|
|
sDqLayer.iMbXyIndex = sDqLayer.iMbY * sDqLayer.iMbWidth + sDqLayer.iMbX;
|
|
iAncMvp[0] = iAncMvp[1] = 0; //expect anchor result to 0
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 3: test MB [0, ANY], expect mvp = (0,0)
|
|
sDqLayer.iMbX = 0;
|
|
sDqLayer.iMbY = rand() % sDqLayer.iMbHeight;
|
|
sDqLayer.iMbXyIndex = sDqLayer.iMbY * sDqLayer.iMbWidth + sDqLayer.iMbX;
|
|
iAncMvp[0] = iAncMvp[1] = 0; //expect anchor result to 0
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1: test MB [RIGHT_SIDE, ANY]
|
|
sDqLayer.iMbX = sDqLayer.iMbWidth - 1;
|
|
sDqLayer.iMbY = rand() % (sDqLayer.iMbHeight - 1) + 1; //not equal to 0
|
|
sDqLayer.iMbXyIndex = sDqLayer.iMbY * sDqLayer.iMbWidth + sDqLayer.iMbX;
|
|
//CASE 4.1.1: same slice_idc, assume = 0
|
|
memset (sDqLayer.pSliceIdc, 0, sDqLayer.iMbWidth * sDqLayer.iMbHeight * sizeof (int32_t));
|
|
//CASE 4.1.1.1: ALL P modes
|
|
memset (sDqLayer.pMbType, MB_TYPE_16x16, sDqLayer.iMbWidth * sDqLayer.iMbHeight * sizeof (int8_t));
|
|
//CASE 4.1.1.1.1: ref_idx = 0, left MV = 0, top MV != 0, expect mvp = (0,0)
|
|
memset (sDqLayer.pRefIndex[0], 0, sDqLayer.iMbWidth * sDqLayer.iMbHeight * MB_BLOCK4x4_NUM * sizeof (int8_t));
|
|
InitRandomLayerMvData (&sDqLayer); //reset Mv data
|
|
sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][0] = sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][1] = 0; //left_mv = 0
|
|
sDqLayer.pMv[0][ TOP_MB_IDX][ TOP_MB_BLK][0] = sDqLayer.pMv[0][ TOP_MB_IDX][ TOP_MB_BLK][1] = 1; //top_mv != 0
|
|
iAncMvp[0] = iAncMvp[1] = 0; //expect anchor result to 0
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.1.1.2: ref_idx = 0, left MV != 0, top MV = 0, expect mvp = (0,0)
|
|
memset (sDqLayer.pRefIndex[0], 0, sDqLayer.iMbWidth * sDqLayer.iMbHeight * MB_BLOCK4x4_NUM * sizeof (int8_t));
|
|
InitRandomLayerMvData (&sDqLayer); //reset Mv data
|
|
sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][0] = sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][1] = 1; //left_mv != 0
|
|
sDqLayer.pMv[0][ TOP_MB_IDX][ TOP_MB_BLK][0] = sDqLayer.pMv[0][ TOP_MB_IDX][ TOP_MB_BLK][1] = 0; //top_mv = 0
|
|
iAncMvp[0] = iAncMvp[1] = 0; //expect anchor result to 0
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.1.1.3: ref_idx top = 0, others = 1, expect mvp = top mv
|
|
InitRandomLayerMvData (&sDqLayer); //reset Mv data
|
|
sDqLayer.pRefIndex[0][ TOP_MB_IDX][ TOP_MB_BLK] = 0; //top ref_idx = 0
|
|
sDqLayer.pRefIndex[0][LEFT_MB_IDX][LEFT_MB_BLK] = 1; //left ref_idx = 1
|
|
sDqLayer.pRefIndex[0][LEFT_TOP_MB_IDX][LEFT_TOP_MB_BLK] = 1; //left_top ref_idx = 1
|
|
iAncMvp[0] = sDqLayer.pMv[0][TOP_MB_IDX][TOP_MB_BLK][0];
|
|
iAncMvp[1] = sDqLayer.pMv[0][TOP_MB_IDX][TOP_MB_BLK][1];
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.1.1.4: ref_idx left = 0, others = 1, expect mvp = left mv
|
|
sDqLayer.pRefIndex[0][ TOP_MB_IDX][ TOP_MB_BLK] = 1; //top ref_idx = 1
|
|
sDqLayer.pRefIndex[0][LEFT_MB_IDX][LEFT_MB_BLK] = 0; //left ref_idx = 0
|
|
sDqLayer.pRefIndex[0][LEFT_TOP_MB_IDX][LEFT_TOP_MB_BLK] = 1; //left_top ref_idx = 1
|
|
iAncMvp[0] = sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][0];
|
|
iAncMvp[1] = sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][1];
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.1.2: All I
|
|
memset (sDqLayer.pMbType, MB_TYPE_INTRA16x16, sDqLayer.iMbWidth * sDqLayer.iMbHeight * sizeof (int8_t));
|
|
//CASE 4.1.1.2.1: left P, expect mvp = left mv
|
|
sDqLayer.pMbType[LEFT_MB_IDX] = MB_TYPE_16x16; //left P
|
|
iAncMvp[0] = sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][0];
|
|
iAncMvp[1] = sDqLayer.pMv[0][LEFT_MB_IDX][LEFT_MB_BLK][1];
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.1.3: only top P, top ref_idx = 0, expect mvp = top mv
|
|
memset (sDqLayer.pMbType, MB_TYPE_INTRA16x16, sDqLayer.iMbWidth * sDqLayer.iMbHeight * sizeof (int8_t)); // All I MB
|
|
memset (sDqLayer.pRefIndex[0], 1, sDqLayer.iMbWidth * sDqLayer.iMbHeight * MB_BLOCK4x4_NUM * sizeof (
|
|
int8_t)); // All ref_idx = 1
|
|
sDqLayer.pMbType[TOP_MB_IDX] = MB_TYPE_16x16; //top P
|
|
sDqLayer.pRefIndex[0][TOP_MB_IDX][TOP_MB_BLK] = 0; //top ref_idx = 0
|
|
iAncMvp[0] = sDqLayer.pMv[0][TOP_MB_IDX][TOP_MB_BLK][0];
|
|
iAncMvp[1] = sDqLayer.pMv[0][TOP_MB_IDX][TOP_MB_BLK][1];
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.1.4: only left_top P, left_top ref_idx = 0, expect mvp = 0
|
|
sDqLayer.iMbX = (rand() % (sDqLayer.iMbWidth - 2)) + 1; //1 ~ (mb_width - 2)
|
|
sDqLayer.iMbY = (rand() % (sDqLayer.iMbHeight - 2)) + 1; //1 ~ (mb_height - 2)
|
|
sDqLayer.iMbXyIndex = sDqLayer.iMbY * sDqLayer.iMbWidth + sDqLayer.iMbX;
|
|
memset (sDqLayer.pMbType, MB_TYPE_INTRA16x16, sDqLayer.iMbWidth * sDqLayer.iMbHeight * sizeof (int8_t)); // All I MB
|
|
memset (sDqLayer.pRefIndex[0], 1, sDqLayer.iMbWidth * sDqLayer.iMbHeight * MB_BLOCK4x4_NUM * sizeof (
|
|
int8_t)); // All ref_idx = 1
|
|
sDqLayer.pMbType[LEFT_TOP_MB_IDX] = MB_TYPE_16x16; //top P
|
|
sDqLayer.pRefIndex[0][LEFT_TOP_MB_IDX][LEFT_TOP_MB_BLK] = 0; //top ref_idx = 0
|
|
iAncMvp[0] = iAncMvp[1] = 0; //expect anchor result to 0
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.1.5: only right_top P, right_top ref_idx = 0, expect mvp = right_top mv
|
|
sDqLayer.iMbX = (rand() % (sDqLayer.iMbWidth - 2)) + 1; //1 ~ (mb_width - 2)
|
|
sDqLayer.iMbY = (rand() % (sDqLayer.iMbHeight - 2)) + 1; //1 ~ (mb_height - 2)
|
|
sDqLayer.iMbXyIndex = sDqLayer.iMbY * sDqLayer.iMbWidth + sDqLayer.iMbX;
|
|
memset (sDqLayer.pMbType, MB_TYPE_INTRA16x16, sDqLayer.iMbWidth * sDqLayer.iMbHeight * sizeof (int8_t)); // All I MB
|
|
memset (sDqLayer.pRefIndex[0], 1, sDqLayer.iMbWidth * sDqLayer.iMbHeight * MB_BLOCK4x4_NUM * sizeof (
|
|
int8_t)); // All ref_idx = 1
|
|
sDqLayer.pMbType[RIGHT_TOP_MB_IDX] = MB_TYPE_16x16; //top P
|
|
sDqLayer.pRefIndex[0][RIGHT_TOP_MB_IDX][RIGHT_TOP_MB_BLK] = 0; //top ref_idx = 0
|
|
iAncMvp[0] = sDqLayer.pMv[0][RIGHT_TOP_MB_IDX][RIGHT_TOP_MB_BLK][0];
|
|
iAncMvp[1] = sDqLayer.pMv[0][RIGHT_TOP_MB_IDX][RIGHT_TOP_MB_BLK][1];
|
|
TEST_SKIP_MV_PRED;
|
|
//CASE 4.1.2: different neighbor slice idc for all P and ref_idx = 0, expect mvp = 0
|
|
memset (sDqLayer.pMbType, MB_TYPE_16x16, sDqLayer.iMbWidth * sDqLayer.iMbHeight * sizeof (int8_t)); // All I MB
|
|
memset (sDqLayer.pRefIndex[0], 0, sDqLayer.iMbWidth * sDqLayer.iMbHeight * MB_BLOCK4x4_NUM * sizeof (
|
|
int8_t)); // All ref_idx = 1
|
|
sDqLayer.iMbX = (rand() % (sDqLayer.iMbWidth - 2)) + 1; //1 ~ (mb_width - 2)
|
|
sDqLayer.iMbY = (rand() % (sDqLayer.iMbHeight - 2)) + 1; //1 ~ (mb_height - 2)
|
|
sDqLayer.iMbXyIndex = sDqLayer.iMbY * sDqLayer.iMbWidth + sDqLayer.iMbX;
|
|
sDqLayer.pSliceIdc[CURR_MB_IDX] = 5;
|
|
sDqLayer.pSliceIdc[LEFT_MB_IDX] = 0;
|
|
sDqLayer.pSliceIdc[TOP_MB_IDX] = 1;
|
|
sDqLayer.pSliceIdc[LEFT_TOP_MB_IDX] = 2;
|
|
sDqLayer.pSliceIdc[RIGHT_TOP_MB_IDX] = 3;
|
|
iAncMvp[0] = iAncMvp[1] = 0;
|
|
TEST_SKIP_MV_PRED;
|
|
|
|
//add new specific tests here
|
|
|
|
//normal tests
|
|
int32_t i = 0;
|
|
while (i++ < kiRandTime) {
|
|
InitRandomLayerData (&sDqLayer); //init MV data, as it would not affect the following logic test
|
|
AnchorPredPSkipMvFromNeighbor (&sDqLayer, iAncMvp);
|
|
TEST_SKIP_MV_PRED;
|
|
}
|
|
|
|
FreeLayerData (&sDqLayer);
|
|
}
|