| #include <gtest/gtest.h> |
| |
| #include "wels_common_basis.h" |
| #include "memory_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, LIST_0, 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, LIST_0, 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, LIST_0, 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 = 0, iLeftTopXy = 0, 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*) WelsMallocz (pDqLayer->iMbWidth * pDqLayer->iMbHeight * sizeof (int32_t), |
| "pDqLayer->pSliceIdc"); |
| if (pDqLayer->pSliceIdc == NULL) |
| return 1; |
| |
| pDqLayer->pMbType = (uint32_t*) WelsMallocz (pDqLayer->iMbWidth * pDqLayer->iMbHeight * sizeof (uint32_t), |
| "pDqLayer->pMbType"); |
| if (pDqLayer->pMbType == NULL) |
| return 1; |
| |
| pDqLayer->pMv[0] = (int16_t (*)[MB_BLOCK4x4_NUM][MV_A]) WelsMallocz (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]) WelsMallocz (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] = 1 << (rand() % 11); //2^(1 ~ 10) |
| } |
| } |
| |
| 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]; |
| int i; |
| |
| 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 |
| |
| int32_t iTotalMbNum = sDqLayer.iMbHeight * sDqLayer.iMbWidth; |
| //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, iTotalMbNum * sizeof (int32_t)); |
| //CASE 4.1.1.1: ALL P modes |
| for (i = 0; i < iTotalMbNum; ++i) { |
| sDqLayer.pMbType[i] = MB_TYPE_16x16; |
| } |
| //CASE 4.1.1.1.1: ref_idx = 0, left MV = 0, top MV != 0, expect mvp = (0,0) |
| memset (sDqLayer.pRefIndex[0], 0, iTotalMbNum * 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, iTotalMbNum * 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 |
| for (i = 0; i < iTotalMbNum; ++i) { |
| sDqLayer.pMbType[i] = MB_TYPE_INTRA16x16; |
| } |
| //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 |
| for (i = 0; i < iTotalMbNum; ++i) { // All I MB |
| sDqLayer.pMbType[i] = MB_TYPE_INTRA16x16; |
| } |
| memset (sDqLayer.pRefIndex[0], 1, iTotalMbNum * 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; |
| for (i = 0; i < iTotalMbNum; ++i) { // All I MB |
| sDqLayer.pMbType[i] = MB_TYPE_INTRA16x16; |
| } |
| memset (sDqLayer.pRefIndex[0], 1, iTotalMbNum * 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; |
| for (i = 0; i < iTotalMbNum; ++i) { // All I MB |
| sDqLayer.pMbType[i] = MB_TYPE_INTRA16x16; |
| } |
| memset (sDqLayer.pRefIndex[0], 1, iTotalMbNum * 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 |
| for (i = 0; i < iTotalMbNum; ++i) { // All P MB |
| sDqLayer.pMbType[i] = MB_TYPE_16x16; |
| } |
| memset (sDqLayer.pRefIndex[0], 0, iTotalMbNum * 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 |
| 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); |
| } |