| #include <gtest/gtest.h> |
| |
| #include "wels_common_basis.h" |
| #include "mem_align.h" |
| #include "error_concealment.h" |
| #include "ls_defines.h" |
| #include "cpu.h" |
| |
| using namespace WelsDec; |
| |
| #define MAX_MB_WIDTH 260 |
| #define MAX_MB_HEIGHT 130 |
| |
| typedef struct TagECInputCtx { |
| int32_t iMbWidth; |
| int32_t iMbHeight; |
| uint32_t iLinesize[3]; |
| bool* pMbCorrectlyDecodedFlag; //actual memory |
| PWelsDecoderContext pCtx; |
| SDqLayer sDqLayer; |
| SPicture sAncPic; //Anc picture for comparison |
| SPicture sSrcPic; //Src picture as common input picture data |
| SPicture sWelsPic; //Wels picture to be compared |
| } SECInputCtx, *PECInputCtx; |
| |
| void FreeInputData (PECInputCtx pECCtx) { |
| if (pECCtx != NULL) { |
| if (pECCtx->pCtx != NULL) { |
| WELS_SAFE_FREE (pECCtx->pCtx->pSps, "pECCtx->pCtx->pSps"); |
| WELS_SAFE_FREE (pECCtx->pCtx, "pECCtx->pCtx"); |
| } |
| |
| WELS_SAFE_FREE (pECCtx->pMbCorrectlyDecodedFlag, "pECCtx->pMbCorrectlyDecodedFlag"); |
| WELS_SAFE_FREE (pECCtx->sSrcPic.pData[0], "pECCtx->sSrcPic.pData"); |
| WELS_SAFE_FREE (pECCtx->sAncPic.pData[0], "pECCtx->sAncPic.pData"); |
| WELS_SAFE_FREE (pECCtx->sWelsPic.pData[0], "pECCtx->sWelsPic.pData"); |
| |
| WELS_SAFE_FREE (pECCtx, "pECCtx"); |
| } |
| } |
| |
| int32_t InitAndAllocInputData (PECInputCtx& pECCtx) { |
| FreeInputData (pECCtx); |
| |
| pECCtx = (PECInputCtx) WelsMalloc (sizeof (SECInputCtx), "pECCtx"); |
| if (pECCtx == NULL) |
| return 1; |
| memset (pECCtx, 0, sizeof (SECInputCtx)); |
| |
| pECCtx->iMbWidth = rand() % MAX_MB_WIDTH; //give a constrained max width |
| pECCtx->iMbHeight = rand() % MAX_MB_HEIGHT; //give a constrained max height |
| pECCtx->iLinesize[0] = pECCtx->iMbWidth << 4; |
| pECCtx->iLinesize[1] = pECCtx->iLinesize[2] = pECCtx->iLinesize[0] >> 1; |
| |
| const uint32_t kiLumaSize = pECCtx->iMbWidth * pECCtx->iMbHeight * 256; |
| |
| //allocate picture data |
| pECCtx->sWelsPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sWelsPic.pData"); |
| if (pECCtx->sWelsPic.pData[0] == NULL) |
| return 1; |
| pECCtx->sWelsPic.pData[1] = pECCtx->sWelsPic.pData[0] + kiLumaSize; |
| pECCtx->sWelsPic.pData[2] = pECCtx->sWelsPic.pData[1] + (kiLumaSize >> 2); |
| |
| pECCtx->sAncPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sAncPic.pData"); |
| if (pECCtx->sAncPic.pData[0] == NULL) |
| return 1; |
| pECCtx->sAncPic.pData[1] = pECCtx->sAncPic.pData[0] + kiLumaSize; |
| pECCtx->sAncPic.pData[2] = pECCtx->sAncPic.pData[1] + (kiLumaSize >> 2); |
| |
| pECCtx->sSrcPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sSrcPic.pData"); |
| if (pECCtx->sSrcPic.pData[0] == NULL) |
| return 1; |
| pECCtx->sSrcPic.pData[1] = pECCtx->sSrcPic.pData[0] + kiLumaSize; |
| pECCtx->sSrcPic.pData[2] = pECCtx->sSrcPic.pData[1] + (kiLumaSize >> 2); |
| |
| pECCtx->sWelsPic.iLinesize[0] = pECCtx->sAncPic.iLinesize[0] = pECCtx->sSrcPic.iLinesize[0] = pECCtx->iLinesize[0]; |
| pECCtx->sWelsPic.iLinesize[1] = pECCtx->sAncPic.iLinesize[1] = pECCtx->sSrcPic.iLinesize[1] = pECCtx->iLinesize[1]; |
| pECCtx->sWelsPic.iLinesize[2] = pECCtx->sAncPic.iLinesize[2] = pECCtx->sSrcPic.iLinesize[2] = pECCtx->iLinesize[2]; |
| |
| pECCtx->pMbCorrectlyDecodedFlag = (bool*) WelsMalloc (pECCtx->iMbWidth * pECCtx->iMbHeight * sizeof (bool), |
| "pECCtx->pMbCorrectlyDecodedFlag"); |
| if (pECCtx->pMbCorrectlyDecodedFlag == NULL) |
| return 1; |
| |
| pECCtx->pCtx = (PWelsDecoderContext) WelsMalloc (sizeof (SWelsDecoderContext), "pECCtx->pCtx"); |
| if (pECCtx->pCtx == NULL) |
| return 1; |
| |
| pECCtx->pCtx->pDec = &pECCtx->sWelsPic; |
| pECCtx->pCtx->pCurDqLayer = &pECCtx->sDqLayer; |
| pECCtx->pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag = pECCtx->pMbCorrectlyDecodedFlag; |
| |
| pECCtx->pCtx->pSps = (PSps) WelsMalloc (sizeof (SSps), "pECCtx->pCtx->pSps"); |
| if (pECCtx->pCtx->pSps == NULL) |
| return 1; |
| pECCtx->pCtx->pSps->iMbWidth = pECCtx->iMbWidth; |
| pECCtx->pCtx->pSps->iMbHeight = pECCtx->iMbHeight; |
| |
| return 0; |
| } |
| |
| void InitECCopyData (PECInputCtx pECCtx) { |
| const int32_t kiMbNum = pECCtx->iMbWidth * pECCtx->iMbHeight; |
| int i; |
| //init pMbCorrectlyDecodedFlag |
| for (i = 0; i < kiMbNum; ++i) { |
| pECCtx->pMbCorrectlyDecodedFlag[i] = !! (rand() & 1); |
| } |
| //init Data |
| const int32_t iPixNum = kiMbNum * 256 * 3 / 2; |
| for (i = 0; i < iPixNum; ++i) { |
| pECCtx->sSrcPic.pData[0][i] = rand() & 0xff; |
| } |
| int32_t iCpuCores = 1; |
| pECCtx->pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores); |
| InitErrorCon (pECCtx->pCtx); |
| } |
| |
| void DoAncErrorConSliceCopy (PECInputCtx pECCtx) { |
| int32_t iMbWidth = (int32_t) pECCtx->iMbWidth; |
| int32_t iMbHeight = (int32_t) pECCtx->iMbHeight; |
| PPicture pDstPic = &pECCtx->sAncPic; |
| PPicture pSrcPic = pECCtx->pCtx->pPreviousDecodedPictureInDpb; |
| |
| //uint8_t *pDstData[3], *pSrcData[3]; |
| bool* pMbCorrectlyDecodedFlag = pECCtx->pMbCorrectlyDecodedFlag; |
| |
| //Do slice copy late |
| int32_t iMbXyIndex, i; |
| uint8_t* pSrcData, *pDstData; |
| uint32_t iSrcStride = pECCtx->iLinesize[0]; |
| uint32_t iDstStride = pECCtx->iLinesize[0]; |
| for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) { |
| for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) { |
| iMbXyIndex = iMbY * iMbWidth + iMbX; |
| if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) { |
| if (pSrcPic != NULL) { |
| //Y component |
| pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16; |
| pSrcData = pSrcPic->pData[0] + iMbY * 16 * iSrcStride + iMbX * 16; |
| for (i = 0; i < 16; ++i) { |
| memcpy (pDstData, pSrcData, 16); |
| pDstData += iDstStride; |
| pSrcData += iSrcStride; |
| } |
| //U component |
| pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8; |
| pSrcData = pSrcPic->pData[1] + iMbY * 8 * iSrcStride / 2 + iMbX * 8; |
| for (i = 0; i < 8; ++i) { |
| memcpy (pDstData, pSrcData, 8); |
| pDstData += iDstStride / 2; |
| pSrcData += iSrcStride / 2; |
| } |
| //V component |
| pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8; |
| pSrcData = pSrcPic->pData[2] + iMbY * 8 * iSrcStride / 2 + iMbX * 8; |
| for (i = 0; i < 8; ++i) { |
| memcpy (pDstData, pSrcData, 8); |
| pDstData += iDstStride / 2; |
| pSrcData += iSrcStride / 2; |
| } |
| } else { //pSrcPic == NULL |
| //Y component |
| pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16; |
| for (i = 0; i < 16; ++i) { |
| memset (pDstData, 128, 16); |
| pDstData += iDstStride; |
| } |
| //U component |
| pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8; |
| for (i = 0; i < 8; ++i) { |
| memset (pDstData, 128, 8); |
| pDstData += iDstStride / 2; |
| } |
| //V component |
| pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8; |
| for (i = 0; i < 8; ++i) { |
| memset (pDstData, 128, 8); |
| pDstData += iDstStride / 2; |
| } |
| } // |
| } //!pMbCorrectlyDecodedFlag[iMbXyIndex] |
| } //iMbX |
| } //iMbY |
| } |
| |
| |
| |
| bool ComparePictureDataI420 (uint8_t* pSrcData, uint8_t* pDstData, const uint32_t kiStride, const int32_t kiHeight) { |
| bool bSame = true; |
| uint8_t* pAncData; // = pECCtx->sAncPic.pData[0]; |
| uint8_t* pCompData; |
| int32_t iStride; |
| int32_t iCurHeight; |
| int32_t iHeight = kiHeight; |
| |
| //Y component |
| iStride = kiStride; |
| pAncData = pSrcData; |
| pCompData = pDstData; |
| for (iCurHeight = 0; bSame && (iCurHeight < kiHeight); ++iCurHeight) { |
| bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0); |
| pAncData += iStride; |
| pCompData += iStride; |
| } |
| //chroma component |
| iHeight >>= 1; |
| iStride >>= 1; |
| //U component |
| for (iCurHeight = 0; bSame && (iCurHeight < kiHeight / 2); ++iCurHeight) { |
| bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0); |
| pAncData += iStride; |
| pCompData += iStride; |
| } |
| //V component |
| for (iCurHeight = 0; bSame && (iCurHeight < kiHeight / 2); ++iCurHeight) { |
| bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0); |
| pAncData += iStride; |
| pCompData += iStride; |
| } |
| |
| return bSame; |
| } |
| |
| //TEST cases followed |
| TEST (ErrorConTest, DoErrorConFrameCopy) { |
| bool bOK = true; |
| PECInputCtx pECCtx = NULL; |
| if (InitAndAllocInputData (pECCtx)) { |
| FreeInputData (pECCtx); |
| return; |
| } |
| |
| pECCtx->pCtx->eErrorConMethod = ERROR_CON_FRAME_COPY; |
| InitECCopyData (pECCtx); |
| //case 1: no reference picture |
| pECCtx->pCtx->pPreviousDecodedPictureInDpb = NULL; |
| DoErrorConFrameCopy (pECCtx->pCtx); |
| |
| int32_t iLumaSize = pECCtx->iMbWidth * pECCtx->iMbHeight * 256; |
| memset (pECCtx->sAncPic.pData[0], 128, iLumaSize * 3 / 2); //should be the same as known EC method, here all 128 |
| bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], |
| pECCtx->iMbHeight * 16); |
| EXPECT_EQ (bOK, true); |
| |
| //case 2: with reference picture |
| pECCtx->pCtx->pPreviousDecodedPictureInDpb = &pECCtx->sSrcPic; |
| DoErrorConFrameCopy (pECCtx->pCtx); |
| |
| memcpy (pECCtx->sAncPic.pData[0], pECCtx->sSrcPic.pData[0], iLumaSize * 3 / 2); |
| bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], |
| pECCtx->iMbHeight * 16); |
| EXPECT_EQ (bOK, true); |
| |
| FreeInputData (pECCtx); |
| } |
| |
| //TEST cases followed |
| TEST (ErrorConTest, DoErrorConSliceCopy) { |
| bool bOK = true; |
| PECInputCtx pECCtx = NULL; |
| if (InitAndAllocInputData (pECCtx)) { |
| FreeInputData (pECCtx); |
| return; |
| } |
| pECCtx->pCtx->eErrorConMethod = ERROR_CON_SLICE_COPY; |
| InitECCopyData (pECCtx); |
| //case 1: no reference picture |
| pECCtx->pCtx->pPreviousDecodedPictureInDpb = NULL; |
| DoAncErrorConSliceCopy (pECCtx); |
| DoErrorConSliceCopy (pECCtx->pCtx); |
| |
| bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], |
| pECCtx->iMbHeight * 16); |
| EXPECT_EQ (bOK, true); |
| |
| //case 2: with reference picture |
| pECCtx->pCtx->pPreviousDecodedPictureInDpb = &pECCtx->sSrcPic; |
| DoAncErrorConSliceCopy (pECCtx); |
| DoErrorConSliceCopy (pECCtx->pCtx); |
| |
| bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], |
| pECCtx->iMbHeight * 16); |
| EXPECT_EQ (bOK, true); |
| |
| FreeInputData (pECCtx); |
| } |