ref: d81dbeaa2e24cf7ad7154203145105463bdcc788
parent: 58966cb2e8d8c8a5f78c1acd7edc92bb99c65291
parent: cbbbe4cbae88dd49b1da5c1373882f52d1dcae2b
author: Licai Guo <licaguo@cisco.com>
date: Fri Mar 21 05:03:42 EDT 2014
Merge pull request #559 from huili2/UT_PredMv add UT for PredMv in decoder
--- /dev/null
+++ b/test/DecUT_PredMv.cpp
@@ -1,0 +1,670 @@
+#include<gtest/gtest.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "../codec/decoder/core/inc/wels_common_basis.h"
+#include "../codec/decoder/core/inc/mem_align.h"
+#include "../codec/decoder/core/inc/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;
+ srand ((uint32_t)time (NULL));
+ //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 (SAnchorMvPred* pDstMvPred, SWelsMvPred* 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 (&sAncMvPred, &sWelsMvPred);
+
+#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;
+ srand ((uint32_t)time (NULL));
+ 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;
+ srand ((uint32_t)time (NULL));
+ 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;
+ srand ((uint32_t)time (NULL));
+ 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;
+
+ 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) {
+ srand ((uint32_t)time (NULL));
+ 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) {
+ srand ((uint32_t)time (NULL));
+ for (int32_t i = 0; i < pDqLayer->iMbWidth * pDqLayer->iMbHeight; ++i) {
+ pDqLayer->pMbType[i] = (rand() & 0x0f) + 1; //1 ~ 16
+ }
+}
+
+void InitRandomLayerMvData (PDqLayer pDqLayer) {
+ srand ((uint32_t)time (NULL));
+ 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) {
+ srand ((uint32_t)time (NULL));
+ 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);
+}
--- a/test/targets.mk
+++ b/test/targets.mk
@@ -9,6 +9,7 @@
$(CODEC_UNITTEST_SRCDIR)/DecUT_ExpandPicture.cpp\
$(CODEC_UNITTEST_SRCDIR)/DecUT_IdctResAddPred.cpp\
$(CODEC_UNITTEST_SRCDIR)/DecUT_IntraPrediction.cpp\
+ $(CODEC_UNITTEST_SRCDIR)/DecUT_PredMv.cpp\
$(CODEC_UNITTEST_SRCDIR)/encoder_test.cpp\
$(CODEC_UNITTEST_SRCDIR)/EncUT_MemoryAlloc.cpp\
$(CODEC_UNITTEST_SRCDIR)/EncUT_MotionEstimate.cpp\