• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2  * \copy
3  *     Copyright (c)  2013, Cisco Systems
4  *     All rights reserved.
5  *
6  *     Redistribution and use in source and binary forms, with or without
7  *     modification, are permitted provided that the following conditions
8  *     are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *
13  *        * Redistributions in binary form must reproduce the above copyright
14  *          notice, this list of conditions and the following disclaimer in
15  *          the documentation and/or other materials provided with the
16  *          distribution.
17  *
18  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  *     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  *     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  *     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  *     COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  *     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  *     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  *     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  *     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  *     POSSIBILITY OF SUCH DAMAGE.
30  *
31  *      error_concealment.cpp:  Wels decoder error concealment implementation
32  */
33 
34 #include "error_code.h"
35 #include "expand_pic.h"
36 #include "manage_dec_ref.h"
37 #include "copy_mb.h"
38 #include "error_concealment.h"
39 #include "cpu_core.h"
40 
41 namespace WelsDec {
42 //Init
InitErrorCon(PWelsDecoderContext pCtx)43 void InitErrorCon (PWelsDecoderContext pCtx) {
44   if ((pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_COPY)
45       || (pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_COPY_CROSS_IDR)
46       || (pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_MV_COPY_CROSS_IDR)
47       || (pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE)
48       || (pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE)) {
49     if ((pCtx->pParam->eEcActiveIdc != ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE)
50         && (pCtx->pParam->eEcActiveIdc != ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE)) {
51       pCtx->bFreezeOutput = false;
52     }
53     pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_c;
54     pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_c;
55 
56 #if defined(X86_ASM)
57     if (pCtx->uiCpuFlag & WELS_CPU_MMXEXT) {
58       pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_mmx; //aligned
59     }
60 
61     if (pCtx->uiCpuFlag & WELS_CPU_SSE2) {
62       pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_sse2; //this is aligned copy;
63     }
64 #endif //X86_ASM
65 
66 #if defined(HAVE_NEON)
67     if (pCtx->uiCpuFlag & WELS_CPU_NEON) {
68       pCtx->sCopyFunc.pCopyLumaFunc     = WelsCopy16x16_neon; //aligned
69       pCtx->sCopyFunc.pCopyChromaFunc   = WelsCopy8x8_neon; //aligned
70     }
71 #endif //HAVE_NEON
72 
73 #if defined(HAVE_NEON_AARCH64)
74     if (pCtx->uiCpuFlag & WELS_CPU_NEON) {
75       pCtx->sCopyFunc.pCopyLumaFunc     = WelsCopy16x16_AArch64_neon; //aligned
76       pCtx->sCopyFunc.pCopyChromaFunc   = WelsCopy8x8_AArch64_neon; //aligned
77     }
78 #endif //HAVE_NEON_AARCH64
79 
80 #if defined(HAVE_LSX)
81      if (pCtx->uiCpuFlag & WELS_CPU_LSX) {
82        pCtx->sCopyFunc.pCopyChromaFunc   = WelsCopy8x8_lsx;   //aligned
83        pCtx->sCopyFunc.pCopyLumaFunc     = WelsCopy16x16_lsx; //aligned
84      }
85 #endif// HAVE_LSX
86   } //TODO add more methods here
87   return;
88 }
89 
90 //Do error concealment using frame copy method
DoErrorConFrameCopy(PWelsDecoderContext pCtx)91 void DoErrorConFrameCopy (PWelsDecoderContext pCtx) {
92   PPicture pDstPic = pCtx->pDec;
93   PPicture pSrcPic = pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb;
94   uint32_t uiHeightInPixelY = (pCtx->pSps->iMbHeight) << 4;
95   int32_t iStrideY = pDstPic->iLinesize[0];
96   int32_t iStrideUV = pDstPic->iLinesize[1];
97   pCtx->pDec->iMbEcedNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
98   if ((pCtx->pParam->eEcActiveIdc == ERROR_CON_FRAME_COPY) && (pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.bIdrFlag))
99     pSrcPic = NULL; //no cross IDR method, should fill in data instead of copy
100   if (pSrcPic == NULL) { //no ref pic, assign specific data to picture
101     memset (pDstPic->pData[0], 128, uiHeightInPixelY * iStrideY);
102     memset (pDstPic->pData[1], 128, (uiHeightInPixelY >> 1) * iStrideUV);
103     memset (pDstPic->pData[2], 128, (uiHeightInPixelY >> 1) * iStrideUV);
104   } else if (pSrcPic == pDstPic) {
105     WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "DoErrorConFrameCopy()::EC memcpy overlap.");
106   } else { //has ref pic here
107     memcpy (pDstPic->pData[0], pSrcPic->pData[0], uiHeightInPixelY * iStrideY);
108     memcpy (pDstPic->pData[1], pSrcPic->pData[1], (uiHeightInPixelY >> 1) * iStrideUV);
109     memcpy (pDstPic->pData[2], pSrcPic->pData[2], (uiHeightInPixelY >> 1) * iStrideUV);
110   }
111 }
112 
113 
114 //Do error concealment using slice copy method
DoErrorConSliceCopy(PWelsDecoderContext pCtx)115 void DoErrorConSliceCopy (PWelsDecoderContext pCtx) {
116   int32_t iMbWidth = (int32_t) pCtx->pSps->iMbWidth;
117   int32_t iMbHeight = (int32_t) pCtx->pSps->iMbHeight;
118   PPicture pDstPic = pCtx->pDec;
119   PPicture pSrcPic = pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb;
120   if ((pCtx->pParam->eEcActiveIdc == ERROR_CON_SLICE_COPY) && (pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.bIdrFlag))
121     pSrcPic = NULL; //no cross IDR method, should fill in data instead of copy
122 
123   //uint8_t *pDstData[3], *pSrcData[3];
124   bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
125   //Do slice copy late
126   int32_t iMbXyIndex;
127   uint8_t* pSrcData, *pDstData;
128   uint32_t iSrcStride; // = pSrcPic->iLinesize[0];
129   uint32_t iDstStride = pDstPic->iLinesize[0];
130   if (pSrcPic == pDstPic) {
131     WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "DoErrorConSliceCopy()::EC memcpy overlap.");
132     return;
133   }
134   for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
135     for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
136       iMbXyIndex = iMbY * iMbWidth + iMbX;
137       if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) {
138         pCtx->pDec->iMbEcedNum++;
139         if (pSrcPic != NULL) {
140           iSrcStride = pSrcPic->iLinesize[0];
141           //Y component
142           pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;
143           pSrcData = pSrcPic->pData[0] + iMbY * 16 * iSrcStride + iMbX * 16;
144           pCtx->sCopyFunc.pCopyLumaFunc (pDstData, iDstStride, pSrcData, iSrcStride);
145           //U component
146           pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
147           pSrcData = pSrcPic->pData[1] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
148           pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2);
149           //V component
150           pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
151           pSrcData = pSrcPic->pData[2] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
152           pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2);
153         } else { //pSrcPic == NULL
154           //Y component
155           pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;
156           for (int32_t i = 0; i < 16; ++i) {
157             memset (pDstData, 128, 16);
158             pDstData += iDstStride;
159           }
160           //U component
161           pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
162           for (int32_t i = 0; i < 8; ++i) {
163             memset (pDstData, 128, 8);
164             pDstData += iDstStride / 2;
165           }
166           //V component
167           pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
168           for (int32_t i = 0; i < 8; ++i) {
169             memset (pDstData, 128, 8);
170             pDstData += iDstStride / 2;
171           }
172         } //
173       } //!pMbCorrectlyDecodedFlag[iMbXyIndex]
174     } //iMbX
175   } //iMbY
176 }
177 
178 //Do error concealment using slice MV copy method
DoMbECMvCopy(PWelsDecoderContext pCtx,PPicture pDec,PPicture pRef,int32_t iMbXy,int32_t iMbX,int32_t iMbY,sMCRefMember * pMCRefMem)179 void DoMbECMvCopy (PWelsDecoderContext pCtx, PPicture pDec, PPicture pRef, int32_t iMbXy, int32_t iMbX, int32_t iMbY,
180                    sMCRefMember* pMCRefMem) {
181   if (pDec == pRef) {
182     return; // for protection, shall never go into this logic, error info printed outside.
183   }
184   int16_t iMVs[2];
185   int32_t iMbXInPix = iMbX << 4;
186   int32_t iMbYInPix = iMbY << 4;
187   int32_t iScale0;
188   int32_t iScale1;
189   uint8_t* pDst[3];
190   int32_t iCurrPoc = pDec->iFramePoc;
191   pDst[0] = pDec->pData[0] + iMbXInPix + iMbYInPix * pMCRefMem->iDstLineLuma;
192   pDst[1] = pDec->pData[1] + (iMbXInPix >> 1) + (iMbYInPix >> 1) * pMCRefMem->iDstLineChroma;
193   pDst[2] = pDec->pData[2] + (iMbXInPix >> 1) + (iMbYInPix >> 1) * pMCRefMem->iDstLineChroma;
194   if (pDec->bIdrFlag == true || pCtx->pECRefPic[0] == NULL) {
195     uint8_t* pSrcData;
196     //Y component
197     pSrcData = pMCRefMem->pSrcY + iMbY * 16 * pMCRefMem->iSrcLineLuma + iMbX * 16;
198     pCtx->sCopyFunc.pCopyLumaFunc (pDst[0], pMCRefMem->iDstLineLuma, pSrcData, pMCRefMem->iSrcLineLuma);
199     //U component
200     pSrcData = pMCRefMem->pSrcU + iMbY * 8 * pMCRefMem->iSrcLineChroma + iMbX * 8;
201     pCtx->sCopyFunc.pCopyChromaFunc (pDst[1], pMCRefMem->iDstLineChroma, pSrcData, pMCRefMem->iSrcLineChroma);
202     //V component
203     pSrcData = pMCRefMem->pSrcV + iMbY * 8 * pMCRefMem->iSrcLineChroma + iMbX * 8;
204     pCtx->sCopyFunc.pCopyChromaFunc (pDst[2], pMCRefMem->iDstLineChroma, pSrcData, pMCRefMem->iSrcLineChroma);
205     return;
206   }
207 
208   if (pCtx->pECRefPic[0]) {
209     if (pCtx->pECRefPic[0] == pRef) {
210       iMVs[0] = pCtx->iECMVs[0][0];
211       iMVs[1] = pCtx->iECMVs[0][1];
212     } else {
213       iScale0 = pCtx->pECRefPic[0]->iFramePoc - iCurrPoc;
214       iScale1 = pRef->iFramePoc - iCurrPoc;
215       iMVs[0] = iScale0 == 0 ? 0 : pCtx->iECMVs[0][0] * iScale1 / iScale0;
216       iMVs[1] = iScale0 == 0 ? 0 : pCtx->iECMVs[0][1] * iScale1 / iScale0;
217     }
218     pMCRefMem->pDstY = pDst[0];
219     pMCRefMem->pDstU = pDst[1];
220     pMCRefMem->pDstV = pDst[2];
221     int32_t iFullMVx = (iMbXInPix << 2) + iMVs[0]; //quarter pixel
222     int32_t iFullMVy = (iMbYInPix << 2) + iMVs[1];
223     // only use to be output pixels to EC;
224     int32_t iPicWidthLeftLimit = 0;
225     int32_t iPicHeightTopLimit = 0;
226     int32_t iPicWidthRightLimit = pMCRefMem->iPicWidth;
227     int32_t iPicHeightBottomLimit = pMCRefMem->iPicHeight;
228     if (pCtx->pSps->bFrameCroppingFlag) {
229       iPicWidthLeftLimit = 0 + pCtx->sFrameCrop.iLeftOffset * 2;
230       iPicWidthRightLimit = (pMCRefMem->iPicWidth - pCtx->sFrameCrop.iRightOffset * 2);
231       iPicHeightTopLimit = 0 + pCtx->sFrameCrop.iTopOffset * 2;
232       iPicHeightBottomLimit = (pMCRefMem->iPicHeight - pCtx->sFrameCrop.iTopOffset * 2);
233     }
234     // further make sure no need to expand picture
235     int32_t iMinLeftOffset = (iPicWidthLeftLimit + 2) * (1 << 2);
236     int32_t iMaxRightOffset = ((iPicWidthRightLimit - 18) * (1 << 2));
237     int32_t iMinTopOffset = (iPicHeightTopLimit + 2) * (1 << 2);
238     int32_t iMaxBottomOffset = ((iPicHeightBottomLimit - 18) * (1 << 2));
239     if (iFullMVx < iMinLeftOffset) {
240       iFullMVx = (iFullMVx >> 2) * (1 << 2);
241       iFullMVx = WELS_MAX (iPicWidthLeftLimit, iFullMVx);
242     } else if (iFullMVx > iMaxRightOffset) {
243       iFullMVx = (iFullMVx >> 2) * (1 << 2);
244       iFullMVx = WELS_MIN (((iPicWidthRightLimit - 16) * (1 << 2)), iFullMVx);
245     }
246     if (iFullMVy < iMinTopOffset) {
247       iFullMVy = (iFullMVy >> 2) * (1 << 2);
248       iFullMVy = WELS_MAX (iPicHeightTopLimit, iFullMVy);
249     } else if (iFullMVy > iMaxBottomOffset) {
250       iFullMVy = (iFullMVy >> 2) * (1 << 2);
251       iFullMVy = WELS_MIN (((iPicHeightBottomLimit - 16) * (1 << 2)), iFullMVy);
252     }
253     iMVs[0] = iFullMVx - (iMbXInPix << 2);
254     iMVs[1] = iFullMVy - (iMbYInPix << 2);
255     BaseMC (pCtx, pMCRefMem, -1, -1, iMbXInPix, iMbYInPix, &pCtx->sMcFunc, 16, 16, iMVs);
256   }
257   return;
258 }
259 
GetAvilInfoFromCorrectMb(PWelsDecoderContext pCtx)260 void GetAvilInfoFromCorrectMb (PWelsDecoderContext pCtx) {
261   int32_t iMbWidth = (int32_t) pCtx->pSps->iMbWidth;
262   int32_t iMbHeight = (int32_t) pCtx->pSps->iMbHeight;
263   bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
264   PDqLayer pCurDqLayer = pCtx->pCurDqLayer;
265   int32_t iInterMbCorrectNum[16];
266   int32_t iMbXyIndex;
267 
268   int8_t iRefIdx;
269   memset (pCtx->iECMVs, 0, sizeof (int32_t) * 32);
270   memset (pCtx->pECRefPic, 0, sizeof (PPicture) * 16);
271   memset (iInterMbCorrectNum, 0, sizeof (int32_t) * 16);
272 
273   for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
274     for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
275       iMbXyIndex = iMbY * iMbWidth + iMbX;
276       if (pMbCorrectlyDecodedFlag[iMbXyIndex] && IS_INTER (pCurDqLayer->pDec->pMbType[iMbXyIndex])) {
277         uint32_t iMBType = pCurDqLayer->pDec->pMbType[iMbXyIndex];
278         switch (iMBType) {
279         case MB_TYPE_SKIP:
280         case MB_TYPE_16x16:
281           iRefIdx = pCurDqLayer->pDec->pRefIndex[0][iMbXyIndex][0];
282           pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][0][0];
283           pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][0][1];
284           pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
285           iInterMbCorrectNum[iRefIdx]++;
286           break;
287         case MB_TYPE_16x8:
288           iRefIdx = pCurDqLayer->pDec->pRefIndex[0][iMbXyIndex][0];
289           pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][0][0];
290           pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][0][1];
291           pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
292           iInterMbCorrectNum[iRefIdx]++;
293 
294           iRefIdx = pCurDqLayer->pDec->pRefIndex[0][iMbXyIndex][8];
295           pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][8][0];
296           pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][8][1];
297           pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
298           iInterMbCorrectNum[iRefIdx]++;
299           break;
300         case MB_TYPE_8x16:
301           iRefIdx = pCurDqLayer->pDec->pRefIndex[0][iMbXyIndex][0];
302           pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][0][0];
303           pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][0][1];
304           pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
305           iInterMbCorrectNum[iRefIdx]++;
306 
307           iRefIdx = pCurDqLayer->pDec->pRefIndex[0][iMbXyIndex][2];
308           pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][2][0];
309           pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][2][1];
310           pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
311           iInterMbCorrectNum[iRefIdx]++;
312           break;
313         case MB_TYPE_8x8:
314         case MB_TYPE_8x8_REF0: {
315           uint32_t iSubMBType;
316           int32_t i, j, iIIdx, iJIdx;
317 
318           for (i = 0; i < 4; i++) {
319             iSubMBType = pCurDqLayer->pSubMbType[iMbXyIndex][i];
320             iIIdx = ((i >> 1) << 3) + ((i & 1) << 1);
321             iRefIdx = pCurDqLayer->pDec->pRefIndex[0][iMbXyIndex][iIIdx];
322             pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
323             switch (iSubMBType) {
324             case SUB_MB_TYPE_8x8:
325               pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx][0];
326               pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx][1];
327               iInterMbCorrectNum[iRefIdx]++;
328 
329               break;
330             case SUB_MB_TYPE_8x4:
331               pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx][0];
332               pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx][1];
333 
334 
335               pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx + 4][0];
336               pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx + 4][1];
337               iInterMbCorrectNum[iRefIdx] += 2;
338 
339               break;
340             case SUB_MB_TYPE_4x8:
341               pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx][0];
342               pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx][1];
343 
344 
345               pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx + 1][0];
346               pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx + 1][1];
347               iInterMbCorrectNum[iRefIdx] += 2;
348               break;
349             case SUB_MB_TYPE_4x4: {
350               for (j = 0; j < 4; j++) {
351                 iJIdx = ((j >> 1) << 2) + (j & 1);
352                 pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx + iJIdx][0];
353                 pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pDec->pMv[0][iMbXyIndex][iIIdx + iJIdx][1];
354               }
355               iInterMbCorrectNum[iRefIdx] += 4;
356             }
357             break;
358             default:
359               break;
360             }
361           }
362         }
363         break;
364         default:
365           break;
366         }
367       } //pMbCorrectlyDecodedFlag[iMbXyIndex]
368     } //iMbX
369   } //iMbY
370   for (int32_t i = 0; i < 16; i++) {
371     if (iInterMbCorrectNum[i]) {
372       pCtx->iECMVs[i][0] = pCtx->iECMVs[i][0] / iInterMbCorrectNum[i];
373       pCtx->iECMVs[i][1] = pCtx->iECMVs[i][1] / iInterMbCorrectNum[i];
374     }
375   }
376 }
377 
DoErrorConSliceMVCopy(PWelsDecoderContext pCtx)378 void DoErrorConSliceMVCopy (PWelsDecoderContext pCtx) {
379   int32_t iMbWidth = (int32_t) pCtx->pSps->iMbWidth;
380   int32_t iMbHeight = (int32_t) pCtx->pSps->iMbHeight;
381   PPicture pDstPic = pCtx->pDec;
382   PPicture pSrcPic = pCtx->pLastDecPicInfo->pPreviousDecodedPictureInDpb;
383 
384   bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
385   int32_t iMbXyIndex;
386   uint8_t* pDstData;
387   uint32_t iDstStride = pDstPic->iLinesize[0];
388   sMCRefMember sMCRefMem;
389   if (pSrcPic != NULL) {
390     sMCRefMem.iSrcLineLuma   = pSrcPic->iLinesize[0];
391     sMCRefMem.iSrcLineChroma = pSrcPic->iLinesize[1];
392     sMCRefMem.pSrcY = pSrcPic->pData[0];
393     sMCRefMem.pSrcU = pSrcPic->pData[1];
394     sMCRefMem.pSrcV = pSrcPic->pData[2];
395     sMCRefMem.iDstLineLuma   = pDstPic->iLinesize[0];
396     sMCRefMem.iDstLineChroma = pDstPic->iLinesize[1];
397     sMCRefMem.iPicWidth = pDstPic->iWidthInPixel;
398     sMCRefMem.iPicHeight = pDstPic->iHeightInPixel;
399     if (pDstPic == pSrcPic) {
400       // output error info, EC will be ignored in DoMbECMvCopy
401       WelsLog (& (pCtx->sLogCtx), WELS_LOG_WARNING, "DoErrorConSliceMVCopy()::EC memcpy overlap.");
402       return;
403     }
404   }
405 
406   for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
407     for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
408       iMbXyIndex = iMbY * iMbWidth + iMbX;
409       if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) {
410         pCtx->pDec->iMbEcedNum++;
411         if (pSrcPic != NULL) {
412           DoMbECMvCopy (pCtx, pDstPic, pSrcPic, iMbXyIndex, iMbX, iMbY, &sMCRefMem);
413         } else { //pSrcPic == NULL
414           //Y component
415           pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;
416           for (int32_t i = 0; i < 16; ++i) {
417             memset (pDstData, 128, 16);
418             pDstData += iDstStride;
419           }
420           //U component
421           pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
422           for (int32_t i = 0; i < 8; ++i) {
423             memset (pDstData, 128, 8);
424             pDstData += iDstStride / 2;
425           }
426           //V component
427           pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
428           for (int32_t i = 0; i < 8; ++i) {
429             memset (pDstData, 128, 8);
430             pDstData += iDstStride / 2;
431           }
432         } //
433 
434       } //!pMbCorrectlyDecodedFlag[iMbXyIndex]
435     } //iMbX
436   } //iMbY
437 }
438 
439 //Mark erroneous frame as Ref Pic into DPB
MarkECFrameAsRef(PWelsDecoderContext pCtx)440 int32_t MarkECFrameAsRef (PWelsDecoderContext pCtx) {
441   int32_t iRet = WelsMarkAsRef (pCtx);
442   // Under EC mode, the ERR_INFO_DUPLICATE_FRAME_NUM does not need to be process
443   if (iRet != ERR_NONE) {
444     return iRet;
445   }
446   ExpandReferencingPicture (pCtx->pDec->pData, pCtx->pDec->iWidthInPixel, pCtx->pDec->iHeightInPixel,
447                             pCtx->pDec->iLinesize,
448                             pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture);
449 
450   return ERR_NONE;
451 }
452 
NeedErrorCon(PWelsDecoderContext pCtx)453 bool NeedErrorCon (PWelsDecoderContext pCtx) {
454   bool bNeedEC = false;
455   int32_t iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
456   for (int32_t i = 0; i < iMbNum; ++i) {
457     if (!pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag[i]) {
458       bNeedEC = true;
459       break;
460     }
461   }
462   return bNeedEC;
463 }
464 
465 // ImplementErrorConceal
466 // Do actual error concealment
ImplementErrorCon(PWelsDecoderContext pCtx)467 void ImplementErrorCon (PWelsDecoderContext pCtx) {
468   if (ERROR_CON_DISABLE == pCtx->pParam->eEcActiveIdc) {
469     pCtx->iErrorCode |= dsBitstreamError;
470     return;
471   } else if ((ERROR_CON_FRAME_COPY == pCtx->pParam->eEcActiveIdc)
472              || (ERROR_CON_FRAME_COPY_CROSS_IDR == pCtx->pParam->eEcActiveIdc)) {
473     DoErrorConFrameCopy (pCtx);
474   } else if ((ERROR_CON_SLICE_COPY == pCtx->pParam->eEcActiveIdc)
475              || (ERROR_CON_SLICE_COPY_CROSS_IDR == pCtx->pParam->eEcActiveIdc)
476              || (ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->pParam->eEcActiveIdc)) {
477     DoErrorConSliceCopy (pCtx);
478   } else if ((ERROR_CON_SLICE_MV_COPY_CROSS_IDR == pCtx->pParam->eEcActiveIdc)
479              || (ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->pParam->eEcActiveIdc)) {
480     GetAvilInfoFromCorrectMb (pCtx);
481     DoErrorConSliceMVCopy (pCtx);
482   } //TODO add other EC methods here in the future
483   pCtx->iErrorCode |= dsDataErrorConcealed;
484   pCtx->pDec->bIsComplete = false; // Set complete flag to false after do EC.
485 }
486 
487 } // namespace WelsDec
488