openh264/test/decoder/DecUT_ErrorConcealment.cpp
Martin Storsjö 4f594deff9 Don't reset the random number generator within the unit tests
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.
2014-07-01 10:20:45 +03:00

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);
}