add slice/frame copy UT for EC
Unified · Split
| @@ -0,0 +1,291 @@ | ||
| 1 | +#include<gtest/gtest.h> | |
| 2 | +#include <stdlib.h> | |
| 3 | +#include <time.h> | |
| 4 | + | |
| 5 | +#include "wels_common_basis.h" | |
| 6 | +#include "mem_align.h" | |
| 7 | +#include "error_concealment.h" | |
| 8 | +#include "ls_defines.h" | |
| 9 | +#include "cpu.h" | |
| 10 | + | |
| 11 | +using namespace WelsDec; | |
| 12 | + | |
| 13 | +#define MAX_MB_WIDTH 260 | |
| 14 | +#define MAX_MB_HEIGHT 130 | |
| 15 | + | |
| 16 | +typedef struct TagECInputCtx { | |
| 17 | + int32_t iMbWidth; | |
| 18 | + int32_t iMbHeight; | |
| 19 | + uint32_t iLinesize[3]; | |
| 20 | + bool* pMbCorrectlyDecodedFlag; //actual memory | |
| 21 | + PWelsDecoderContext pCtx; | |
| 22 | + SDqLayer sDqLayer; | |
| 23 | + SPicture sAncPic; //Anc picture for comparison | |
| 24 | + SPicture sSrcPic; //Src picture as common input picture data | |
| 25 | + SPicture sWelsPic; //Wels picture to be compared | |
| 26 | +} SECInputCtx, *PECInputCtx; | |
| 27 | + | |
| 28 | +void FreeInputData (PECInputCtx pECCtx) { | |
| 29 | + if (pECCtx != NULL) { | |
| 30 | + if (pECCtx->pCtx != NULL) { | |
| 31 | + WELS_SAFE_FREE (pECCtx->pCtx->pSps, "pECCtx->pCtx->pSps"); | |
| 32 | + WELS_SAFE_FREE (pECCtx->pCtx, "pECCtx->pCtx"); | |
| 33 | + } | |
| 34 | + | |
| 35 | + WELS_SAFE_FREE (pECCtx->pMbCorrectlyDecodedFlag, "pECCtx->pMbCorrectlyDecodedFlag"); | |
| 36 | + WELS_SAFE_FREE (pECCtx->sSrcPic.pData[0], "pECCtx->sSrcPic.pData"); | |
| 37 | + WELS_SAFE_FREE (pECCtx->sAncPic.pData[0], "pECCtx->sAncPic.pData"); | |
| 38 | + WELS_SAFE_FREE (pECCtx->sWelsPic.pData[0], "pECCtx->sWelsPic.pData"); | |
| 39 | + | |
| 40 | + WELS_SAFE_FREE (pECCtx, "pECCtx"); | |
| 41 | + } | |
| 42 | +} | |
| 43 | + | |
| 44 | +int32_t InitAndAllocInputData (PECInputCtx& pECCtx) { | |
| 45 | + FreeInputData (pECCtx); | |
| 46 | + | |
| 47 | + pECCtx = (PECInputCtx) WelsMalloc (sizeof (SECInputCtx), "pECCtx"); | |
| 48 | + if (pECCtx == NULL) | |
| 49 | + return 1; | |
| 50 | + memset (pECCtx, 0, sizeof (SECInputCtx)); | |
| 51 | + | |
| 52 | + srand ((uint32_t)time (NULL)); | |
| 53 | + pECCtx->iMbWidth = rand() % MAX_MB_WIDTH; //give a constrained max width | |
| 54 | + pECCtx->iMbHeight = rand() % MAX_MB_HEIGHT; //give a constrained max height | |
| 55 | + pECCtx->iLinesize[0] = pECCtx->iMbWidth << 4; | |
| 56 | + pECCtx->iLinesize[1] = pECCtx->iLinesize[2] = pECCtx->iLinesize[0] >> 1; | |
| 57 | + | |
| 58 | + const uint32_t kiLumaSize = pECCtx->iMbWidth * pECCtx->iMbHeight * 256; | |
| 59 | + | |
| 60 | + //allocate picture data | |
| 61 | + pECCtx->sWelsPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sWelsPic.pData"); | |
| 62 | + if (pECCtx->sWelsPic.pData[0] == NULL) | |
| 63 | + return 1; | |
| 64 | + pECCtx->sWelsPic.pData[1] = pECCtx->sWelsPic.pData[0] + kiLumaSize; | |
| 65 | + pECCtx->sWelsPic.pData[2] = pECCtx->sWelsPic.pData[1] + (kiLumaSize >> 2); | |
| 66 | + | |
| 67 | + pECCtx->sAncPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sAncPic.pData"); | |
| 68 | + if (pECCtx->sAncPic.pData[0] == NULL) | |
| 69 | + return 1; | |
| 70 | + pECCtx->sAncPic.pData[1] = pECCtx->sAncPic.pData[0] + kiLumaSize; | |
| 71 | + pECCtx->sAncPic.pData[2] = pECCtx->sAncPic.pData[1] + (kiLumaSize >> 2); | |
| 72 | + | |
| 73 | + pECCtx->sSrcPic.pData[0] = (uint8_t*) WelsMalloc (kiLumaSize * 3 / 2 * sizeof (uint8_t), "pECCtx->sSrcPic.pData"); | |
| 74 | + if (pECCtx->sAncPic.pData[0] == NULL) | |
| 75 | + return 1; | |
| 76 | + pECCtx->sSrcPic.pData[1] = pECCtx->sSrcPic.pData[0] + kiLumaSize; | |
| 77 | + pECCtx->sSrcPic.pData[2] = pECCtx->sSrcPic.pData[1] + (kiLumaSize >> 2); | |
| 78 | + | |
| 79 | + pECCtx->sWelsPic.iLinesize[0] = pECCtx->sAncPic.iLinesize[0] = pECCtx->sSrcPic.iLinesize[0] = pECCtx->iLinesize[0]; | |
| 80 | + pECCtx->sWelsPic.iLinesize[1] = pECCtx->sAncPic.iLinesize[1] = pECCtx->sSrcPic.iLinesize[1] = pECCtx->iLinesize[1]; | |
| 81 | + pECCtx->sWelsPic.iLinesize[2] = pECCtx->sAncPic.iLinesize[2] = pECCtx->sSrcPic.iLinesize[2] = pECCtx->iLinesize[2]; | |
| 82 | + | |
| 83 | + pECCtx->pMbCorrectlyDecodedFlag = (bool*) WelsMalloc (pECCtx->iMbWidth * pECCtx->iMbHeight * sizeof (bool), | |
| 84 | + "pECCtx->pMbCorrectlyDecodedFlag"); | |
| 85 | + if (pECCtx->pMbCorrectlyDecodedFlag == NULL) | |
| 86 | + return 1; | |
| 87 | + | |
| 88 | + pECCtx->pCtx = (PWelsDecoderContext) WelsMalloc (sizeof (SWelsDecoderContext), "pECCtx->pCtx"); | |
| 89 | + if (pECCtx->pCtx == NULL) | |
| 90 | + return 1; | |
| 91 | + | |
| 92 | + pECCtx->pCtx->pDec = &pECCtx->sWelsPic; | |
| 93 | + pECCtx->pCtx->pCurDqLayer = &pECCtx->sDqLayer; | |
| 94 | + pECCtx->pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag = pECCtx->pMbCorrectlyDecodedFlag; | |
| 95 | + | |
| 96 | + pECCtx->pCtx->pSps = (PSps) WelsMalloc (sizeof (SSps), "pECCtx->pCtx->pSps"); | |
| 97 | + if (pECCtx->pCtx->pSps == NULL) | |
| 98 | + return 1; | |
| 99 | + pECCtx->pCtx->pSps->iMbWidth = pECCtx->iMbWidth; | |
| 100 | + pECCtx->pCtx->pSps->iMbHeight = pECCtx->iMbHeight; | |
| 101 | + | |
| 102 | + return 0; | |
| 103 | +} | |
| 104 | + | |
| 105 | +void InitECCopyData (PECInputCtx pECCtx) { | |
| 106 | + srand ((uint32_t)time (NULL)); | |
| 107 | + const int32_t kiMbNum = pECCtx->iMbWidth * pECCtx->iMbHeight; | |
| 108 | + int i; | |
| 109 | + //init pMbCorrectlyDecodedFlag | |
| 110 | + for (i = 0; i < kiMbNum; ++i) { | |
| 111 | + pECCtx->pMbCorrectlyDecodedFlag[i] = !! (rand() & 1); | |
| 112 | + } | |
| 113 | + //init Data | |
| 114 | + const int32_t iPixNum = kiMbNum * 256 * 3 / 2; | |
| 115 | + for (i = 0; i < iPixNum; ++i) { | |
| 116 | + pECCtx->sSrcPic.pData[0][i] = rand() & 0xff; | |
| 117 | + } | |
| 118 | + int32_t iCpuCores = 1; | |
| 119 | + pECCtx->pCtx->uiCpuFlag = WelsCPUFeatureDetect (&iCpuCores); | |
| 120 | + InitErrorCon (pECCtx->pCtx); | |
| 121 | +} | |
| 122 | + | |
| 123 | +void DoAncErrorConSliceCopy (PECInputCtx pECCtx) { | |
| 124 | + int32_t iMbWidth = (int32_t) pECCtx->iMbWidth; | |
| 125 | + int32_t iMbHeight = (int32_t) pECCtx->iMbHeight; | |
| 126 | + PPicture pDstPic = &pECCtx->sAncPic; | |
| 127 | + PPicture pSrcPic = pECCtx->pCtx->pPreviousDecodedPictureInDpb; | |
| 128 | + | |
| 129 | + //uint8_t *pDstData[3], *pSrcData[3]; | |
| 130 | + bool* pMbCorrectlyDecodedFlag = pECCtx->pMbCorrectlyDecodedFlag; | |
| 131 | + | |
| 132 | + //Do slice copy late | |
| 133 | + int32_t iMbXyIndex, i; | |
| 134 | + uint8_t* pSrcData, *pDstData; | |
| 135 | + uint32_t iSrcStride = pECCtx->iLinesize[0]; | |
| 136 | + uint32_t iDstStride = pECCtx->iLinesize[0]; | |
| 137 | + for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) { | |
| 138 | + for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) { | |
| 139 | + iMbXyIndex = iMbY * iMbWidth + iMbX; | |
| 140 | + if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) { | |
| 141 | + if (pSrcPic != NULL) { | |
| 142 | + //Y component | |
| 143 | + pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16; | |
| 144 | + pSrcData = pSrcPic->pData[0] + iMbY * 16 * iSrcStride + iMbX * 16; | |
| 145 | + for (i = 0; i < 16; ++i) { | |
| 146 | + memcpy (pDstData, pSrcData, 16); | |
| 147 | + pDstData += iDstStride; | |
| 148 | + pSrcData += iSrcStride; | |
| 149 | + } | |
| 150 | + //U component | |
| 151 | + pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8; | |
| 152 | + pSrcData = pSrcPic->pData[1] + iMbY * 8 * iSrcStride / 2 + iMbX * 8; | |
| 153 | + for (i = 0; i < 8; ++i) { | |
| 154 | + memcpy (pDstData, pSrcData, 8); | |
| 155 | + pDstData += iDstStride; | |
| 156 | + pSrcData += iSrcStride; | |
| 157 | + } | |
| 158 | + //V component | |
| 159 | + pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8; | |
| 160 | + pSrcData = pSrcPic->pData[2] + iMbY * 8 * iSrcStride / 2 + iMbX * 8; | |
| 161 | + for (i = 0; i < 8; ++i) { | |
| 162 | + memcpy (pDstData, pSrcData, 8); | |
| 163 | + pDstData += iDstStride; | |
| 164 | + pSrcData += iSrcStride; | |
| 165 | + } | |
| 166 | + } else { //pSrcPic == NULL | |
| 167 | + //Y component | |
| 168 | + pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16; | |
| 169 | + for (int32_t i = 0; i < 16; ++i) { | |
| 170 | + memset (pDstData, 0, 16); | |
| 171 | + pDstData += iDstStride; | |
| 172 | + } | |
| 173 | + //U component | |
| 174 | + pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8; | |
| 175 | + for (int32_t i = 0; i < 8; ++i) { | |
| 176 | + memset (pDstData, 0, 8); | |
| 177 | + pDstData += iDstStride / 2; | |
| 178 | + } | |
| 179 | + //V component | |
| 180 | + pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8; | |
| 181 | + for (int32_t i = 0; i < 8; ++i) { | |
| 182 | + memset (pDstData, 0, 8); | |
| 183 | + pDstData += iDstStride / 2; | |
| 184 | + } | |
| 185 | + } // | |
| 186 | + } //!pMbCorrectlyDecodedFlag[iMbXyIndex] | |
| 187 | + } //iMbX | |
| 188 | + } //iMbY | |
| 189 | +} | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | +bool ComparePictureDataI420 (uint8_t* pSrcData, uint8_t* pDstData, const uint32_t kiStride, const int32_t kiHeight) { | |
| 194 | + bool bSame = true; | |
| 195 | + uint8_t* pAncData; // = pECCtx->sAncPic.pData[0]; | |
| 196 | + uint8_t* pCompData; | |
| 197 | + int32_t iStride; | |
| 198 | + int32_t iCurHeight; | |
| 199 | + int32_t iHeight = kiHeight; | |
| 200 | + | |
| 201 | + //Y component | |
| 202 | + iStride = kiStride; | |
| 203 | + pAncData = pSrcData; | |
| 204 | + pCompData = pDstData; | |
| 205 | + for (iCurHeight = 0; bSame && (iCurHeight < kiHeight); ++iCurHeight) { | |
| 206 | + bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0); | |
| 207 | + pAncData += iStride; | |
| 208 | + pCompData += iStride; | |
| 209 | + } | |
| 210 | + //chroma component | |
| 211 | + iHeight >>= 1; | |
| 212 | + iStride >>= 1; | |
| 213 | + //U component | |
| 214 | + for (iCurHeight = 0; bSame && (iCurHeight < kiHeight / 2); ++iCurHeight) { | |
| 215 | + bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0); | |
| 216 | + pAncData += iStride; | |
| 217 | + pCompData += iStride; | |
| 218 | + } | |
| 219 | + //V component | |
| 220 | + for (iCurHeight = 0; bSame && (iCurHeight < kiHeight / 2); ++iCurHeight) { | |
| 221 | + bSame = (memcmp (pAncData, pCompData, iStride * sizeof (uint8_t)) == 0); | |
| 222 | + pAncData += iStride; | |
| 223 | + pCompData += iStride; | |
| 224 | + } | |
| 225 | + | |
| 226 | + return bSame; | |
| 227 | +} | |
| 228 | + | |
| 229 | +//TEST cases followed | |
| 230 | +TEST (ErrorConTest, DoErrorConFrameCopy) { | |
| 231 | + bool bOK = true; | |
| 232 | + PECInputCtx pECCtx = NULL; | |
| 233 | + if (InitAndAllocInputData (pECCtx)) { | |
| 234 | + FreeInputData (pECCtx); | |
| 235 | + return; | |
| 236 | + } | |
| 237 | + | |
| 238 | + pECCtx->pCtx->iErrorConMethod = ERROR_CON_FRAME_COPY; | |
| 239 | + InitECCopyData (pECCtx); | |
| 240 | + //case 1: no reference picture | |
| 241 | + pECCtx->pCtx->pPreviousDecodedPictureInDpb = NULL; | |
| 242 | + DoErrorConFrameCopy (pECCtx->pCtx); | |
| 243 | + | |
| 244 | + int32_t iLumaSize = pECCtx->iMbWidth * pECCtx->iMbHeight * 256; | |
| 245 | + memset (pECCtx->sAncPic.pData[0], 0, iLumaSize * 3 / 2); //should be the same as known EC method, here all 0 | |
| 246 | + bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], | |
| 247 | + pECCtx->iMbHeight * 16); | |
| 248 | + EXPECT_EQ (bOK, true); | |
| 249 | + | |
| 250 | + //case 2: with reference picture | |
| 251 | + pECCtx->pCtx->pPreviousDecodedPictureInDpb = &pECCtx->sSrcPic; | |
| 252 | + DoErrorConFrameCopy (pECCtx->pCtx); | |
| 253 | + | |
| 254 | + memcpy (pECCtx->sAncPic.pData[0], pECCtx->sSrcPic.pData[0], iLumaSize * 3 / 2); | |
| 255 | + bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], | |
| 256 | + pECCtx->iMbHeight * 16); | |
| 257 | + EXPECT_EQ (bOK, true); | |
| 258 | + | |
| 259 | + FreeInputData (pECCtx); | |
| 260 | +} | |
| 261 | + | |
| 262 | +//TEST cases followed | |
| 263 | +TEST (ErrorConTest, DoErrorConSliceCopy) { | |
| 264 | + bool bOK = true; | |
| 265 | + PECInputCtx pECCtx = NULL; | |
| 266 | + if (InitAndAllocInputData (pECCtx)) { | |
| 267 | + FreeInputData (pECCtx); | |
| 268 | + return; | |
| 269 | + } | |
| 270 | + pECCtx->pCtx->iErrorConMethod = ERROR_CON_SLICE_COPY; | |
| 271 | + InitECCopyData (pECCtx); | |
| 272 | + //case 1: no reference picture | |
| 273 | + pECCtx->pCtx->pPreviousDecodedPictureInDpb = NULL; | |
| 274 | + DoAncErrorConSliceCopy (pECCtx); | |
| 275 | + DoErrorConSliceCopy (pECCtx->pCtx); | |
| 276 | + | |
| 277 | + bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], | |
| 278 | + pECCtx->iMbHeight * 16); | |
| 279 | + EXPECT_EQ (bOK, true); | |
| 280 | + | |
| 281 | + //case 2: with reference picture | |
| 282 | + pECCtx->pCtx->pPreviousDecodedPictureInDpb = &pECCtx->sAncPic; | |
| 283 | + DoAncErrorConSliceCopy (pECCtx); | |
| 284 | + DoErrorConSliceCopy (pECCtx->pCtx); | |
| 285 | + | |
| 286 | + bOK = ComparePictureDataI420 (pECCtx->sAncPic.pData[0], pECCtx->sWelsPic.pData[0], pECCtx->iLinesize[0], | |
| 287 | + pECCtx->iMbHeight * 16); | |
| 288 | + EXPECT_EQ (bOK, true); | |
| 289 | + | |
| 290 | + FreeInputData (pECCtx); | |
| 291 | +} | |
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | DECODER_UNITTEST_SRCDIR=test/decoder |
| 2 | 2 | DECODER_UNITTEST_CPP_SRCS=\ |
| 3 | + $(DECODER_UNITTEST_SRCDIR)/DecUT_ErrorConcealment.cpp\ | |
| 3 | 4 | $(DECODER_UNITTEST_SRCDIR)/DecUT_ExpandPicture.cpp\ |
| 4 | 5 | $(DECODER_UNITTEST_SRCDIR)/DecUT_IdctResAddPred.cpp\ |
| 5 | 6 | $(DECODER_UNITTEST_SRCDIR)/DecUT_IntraPrediction.cpp\ |