![Martin Storsjö](/assets/img/avatar_default.png)
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.
288 lines
10 KiB
C++
288 lines
10 KiB
C++
#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, 0, 16);
|
|
pDstData += iDstStride;
|
|
}
|
|
//U component
|
|
pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
|
|
for (i = 0; i < 8; ++i) {
|
|
memset (pDstData, 0, 8);
|
|
pDstData += iDstStride / 2;
|
|
}
|
|
//V component
|
|
pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
|
|
for (i = 0; i < 8; ++i) {
|
|
memset (pDstData, 0, 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->iErrorConMethod = 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], 0, iLumaSize * 3 / 2); //should be the same as known EC method, here all 0
|
|
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->iErrorConMethod = 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);
|
|
}
|