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