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 | DECODER_UNITTEST_SRCDIR=test/decoder | 1 | DECODER_UNITTEST_SRCDIR=test/decoder |
| 2 | DECODER_UNITTEST_CPP_SRCS=\ | 2 | DECODER_UNITTEST_CPP_SRCS=\ |
| 3 | $(DECODER_UNITTEST_SRCDIR)/DecUT_ErrorConcealment.cpp\ | ||
| 3 | $(DECODER_UNITTEST_SRCDIR)/DecUT_ExpandPicture.cpp\ | 4 | $(DECODER_UNITTEST_SRCDIR)/DecUT_ExpandPicture.cpp\ |
| 4 | $(DECODER_UNITTEST_SRCDIR)/DecUT_IdctResAddPred.cpp\ | 5 | $(DECODER_UNITTEST_SRCDIR)/DecUT_IdctResAddPred.cpp\ |
| 5 | $(DECODER_UNITTEST_SRCDIR)/DecUT_IntraPrediction.cpp\ | 6 | $(DECODER_UNITTEST_SRCDIR)/DecUT_IntraPrediction.cpp\ |