shithub: openh264

Download patch

ref: 305a2421be82a643b6a8dfa73c179b9d6a5e73f5
parent: f1fb0d6b6980e9705147fcdba2acd80ed6eba5b8
parent: 9425c2ab10acf5c526c96af4c3209c6355c5f756
author: huili2 <huili2@cisco.com>
date: Tue Nov 25 07:59:48 EST 2014

Merge pull request #1549 from dongzha/ECMvCopy

add EC MV copy

--- a/codec/api/svc/codec_app_def.h
+++ b/codec/api/svc/codec_app_def.h
@@ -159,7 +159,9 @@
   ERROR_CON_SLICE_COPY,
   ERROR_CON_FRAME_COPY_CROSS_IDR,
   ERROR_CON_SLICE_COPY_CROSS_IDR,
-  ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE
+  ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE,
+  ERROR_CON_SLICE_MV_COPY_CROSS_IDR,
+  ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE
 } ERROR_CON_IDC;
 /**
 * @brief Feedback that whether or not have VCL NAL in current AU
--- a/codec/console/dec/src/d3d9_utils.cpp
+++ b/codec/console/dec/src/d3d9_utils.cpp
@@ -336,6 +336,7 @@
       || m_nHeight != pInfo->UsrData.sSystemBuffer.iHeight) {
     m_nWidth = pInfo->UsrData.sSystemBuffer.iWidth;
     m_nHeight = pInfo->UsrData.sSystemBuffer.iHeight;
+    MoveWindow(m_hWnd,0,0,pInfo->UsrData.sSystemBuffer.iWidth,pInfo->UsrData.sSystemBuffer.iHeight,true);
     SAFE_RELEASE (m_lpD3D9RawSurfaceShare);
     SAFE_RELEASE (m_lpD3D9Device);
   }
--- a/codec/console/dec/src/h264dec.cpp
+++ b/codec/console/dec/src/h264dec.cpp
@@ -200,7 +200,7 @@
     pDecoder->GetOption (DECODER_OPTION_VCL_NAL, &iFeedbackVclNalInAu);
     int32_t iFeedbackTidInAu;
     pDecoder->GetOption (DECODER_OPTION_TEMPORAL_ID, &iFeedbackTidInAu);
-    int32_t iErrorConMethod = (int32_t) ERROR_CON_SLICE_COPY;
+    int32_t iErrorConMethod = (int32_t) ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE;
     pDecoder->SetOption (DECODER_OPTION_ERROR_CON_IDC, &iErrorConMethod);
 //~end for
 
--- a/codec/decoder/core/inc/decode_slice.h
+++ b/codec/decoder/core/inc/decode_slice.h
@@ -53,7 +53,6 @@
 
 int32_t WelsDecodeSlice (PWelsDecoderContext pCtx, bool bFirstSliceInLayer, PNalUnit pNalCur);
 
-
 int32_t WelsTargetMbConstruction (PWelsDecoderContext pCtx);
 
 int32_t WelsMbIntraPredictionConstruction (PWelsDecoderContext pCtx, PDqLayer pCurLayer, bool bOutput);
--- a/codec/decoder/core/inc/decoder_context.h
+++ b/codec/decoder/core/inc/decoder_context.h
@@ -400,6 +400,8 @@
 PWelsCabacDecEngine   pCabacDecEngine;
 double dDecTime;
 SDecoderStatistics sDecoderStatistics;// For real time debugging
+int32_t iECMVs[16][2];
+PPicture pECRefPic[16];
 } SWelsDecoderContext, *PWelsDecoderContext;
 
 static inline void ResetActiveSPSForEachLayer (PWelsDecoderContext pCtx) {
--- a/codec/decoder/core/inc/error_concealment.h
+++ b/codec/decoder/core/inc/error_concealment.h
@@ -39,6 +39,7 @@
 #ifndef WELS_ERROR_CONCEALMENT_H__
 #define WELS_ERROR_CONCEALMENT_H__
 #include "typedefs.h"
+#include "rec_mb.h"
 #include "decoder_context.h"
 
 namespace WelsDec {
@@ -48,6 +49,10 @@
 void DoErrorConFrameCopy (PWelsDecoderContext pCtx);
 //Do error concealment using slice copy method
 void DoErrorConSliceCopy (PWelsDecoderContext pCtx);
+//Do error concealment using slice MV copy method
+void DoMbECMvCopy (PWelsDecoderContext pCtx, PPicture pDec, PPicture pRef, int32_t iMbXy, int32_t iMbX, int32_t iMbY, sMCRefMember* pMCRefMem, int32_t iCurrPoc);
+void GetAvilInfoFromCorrectMb (PWelsDecoderContext pCtx);
+void DoErrorConSliceMVCopy (PWelsDecoderContext pCtx);
 //Mark erroneous frame as Ref Pic into DPB
 int32_t MarkECFrameAsRef (PWelsDecoderContext pCtx);
 //Judge if EC is needed to current frame
--- a/codec/decoder/core/inc/picture.h
+++ b/codec/decoder/core/inc/picture.h
@@ -50,6 +50,9 @@
 int32_t		iPlanes;			// How many planes are introduced due to color space format?
 // picture information
 
+/*******************************from EC mv copy****************************/
+bool bIdrFlag;
+
 /*******************************from other standard syntax****************************/
 /*from sps*/
 int32_t		iWidthInPixel;	// picture width in pixel
--- a/codec/decoder/core/inc/rec_mb.h
+++ b/codec/decoder/core/inc/rec_mb.h
@@ -48,6 +48,27 @@
 #include "decoder_context.h"
 
 namespace WelsDec {
+typedef struct TagMCRefMember {
+  uint8_t* pDstY;
+  uint8_t* pDstU;
+  uint8_t* pDstV;
+
+  uint8_t* pSrcY;
+  uint8_t* pSrcU;
+  uint8_t* pSrcV;
+
+  int32_t iSrcLineLuma;
+  int32_t iSrcLineChroma;
+
+  int32_t iDstLineLuma;
+  int32_t iDstLineChroma;
+
+  int32_t iPicWidth;
+  int32_t iPicHeight;
+} sMCRefMember;
+
+void BaseMC (sMCRefMember* pMCRefMem, int32_t iXOffset, int32_t iYOffset, SMcFunc* pMCFunc,
+                           int32_t iBlkWidth, int32_t iBlkHeight, int16_t iMVs[2]);
 
 void WelsFillRecNeededMbInfo (PWelsDecoderContext pCtx, bool bOutput, PDqLayer pCurLayer);
 
--- a/codec/decoder/core/inc/slice.h
+++ b/codec/decoder/core/inc/slice.h
@@ -120,6 +120,7 @@
 PPps		pPps;
 int32_t	    iSpsId;
 int32_t	    iPpsId;
+bool bIdrFlag;
 
 /*********************got from other layer for efficency if possible*********************/
 SRefPicListReorderSyn	pRefPicListReordering;	// Reference picture list reordering syntaxs
--- a/codec/decoder/core/src/decoder_core.cpp
+++ b/codec/decoder/core/src/decoder_core.cpp
@@ -113,7 +113,9 @@
   if (pCtx->eErrorConMethod == ERROR_CON_DISABLE) //no buffer output if EC is disabled and frame incomplete
     pDstInfo->iBufferStatus = (int32_t) (bFrameCompleteFlag
                                          && pPic->bIsComplete); // When EC disable, ECed picture not output
-  else if (pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE && pCtx->iErrorCode && bOutResChange)
+  else if ((pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE
+           || pCtx->eErrorConMethod == ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE)
+            && pCtx->iErrorCode && bOutResChange)
     pCtx->bFreezeOutput = true;
 
   if ((pDstInfo->iBufferStatus == 1) && (pCurDq->sLayerInfo.sNalHeaderExt.bIdrFlag)) {
@@ -620,6 +622,7 @@
   pSliceHeadExt->pSubsetSps = pSubsetSps;
 
   bIdrFlag = (!kbExtensionFlag && eNalType == NAL_UNIT_CODED_SLICE_IDR) || (kbExtensionFlag && pNalHeaderExt->bIdrFlag);
+  pSliceHead->bIdrFlag = bIdrFlag;
 
   if (pSps->uiLog2MaxFrameNum == 0) {
     WelsLog (pLogCtx, WELS_LOG_WARNING, "non existing SPS referenced");
@@ -1961,6 +1964,8 @@
       memcpy (&pLayerInfo.sNalHeaderExt, &pNalCur->sNalHeaderExt, sizeof (SNalUnitHeaderExt)); //confirmed_safe_unsafe_usage
 
       pCtx->pDec->iFrameNum = pSh->iFrameNum;
+      pCtx->pDec->iFramePoc = pSh->iPicOrderCntLsb; // still can not obtain correct, because current do not support POCtype 2
+      pCtx->pDec->bIdrFlag = pNalCur->sNalHeaderExt.bIdrFlag;
 
       memcpy (&pLayerInfo.sSliceInLayer.sSliceHeaderExt, pShExt, sizeof (SSliceHeaderExt)); //confirmed_safe_unsafe_usage
       pLayerInfo.sSliceInLayer.bSliceHeaderExtFlag	= pNalCur->sNalData.sVclNal.bSliceHeaderExtFlag;
@@ -2126,6 +2131,9 @@
                                   pCtx->pDec->iLinesize,
                                   pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture);
         pCtx->pDec = NULL;
+      } else if (pCtx->eErrorConMethod == ERROR_CON_SLICE_MV_COPY_CROSS_IDR || pCtx->eErrorConMethod == ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE) {
+        pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //store latest decoded picture for MV Copy EC
+        pCtx->pDec = NULL;
       }
     }
 
@@ -2156,6 +2164,8 @@
         if (pCtx->sLastNalHdrExt.sNalUnitHeader.uiNalRefIdc > 0) {
           pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //save ECed pic for future use
           MarkECFrameAsRef (pCtx);
+        } else if (pCtx->eErrorConMethod == ERROR_CON_SLICE_MV_COPY_CROSS_IDR || pCtx->eErrorConMethod == ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE) {
+          pCtx->pPreviousDecodedPictureInDpb = pCtx->pDec; //save ECed pic for future MV Copy use
         }
       } else {
         if (DecodeFrameConstruction (pCtx, ppDst, pDstInfo))
--- a/codec/decoder/core/src/error_concealment.cpp
+++ b/codec/decoder/core/src/error_concealment.cpp
@@ -42,6 +42,8 @@
 //Init
 void InitErrorCon (PWelsDecoderContext pCtx) {
   if ((pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY) || (pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY_CROSS_IDR)
+      || (pCtx->eErrorConMethod == ERROR_CON_SLICE_MV_COPY_CROSS_IDR)
+      || (pCtx->eErrorConMethod == ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE)
       || (pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE)) {
     pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_c;
     pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_c;
@@ -159,7 +161,264 @@
                                           + ((iMbEcedNum * 100) / iMbNum) ;
 }
 
+//Do error concealment using slice MV copy method
+void DoMbECMvCopy (PWelsDecoderContext pCtx, PPicture pDec, PPicture pRef, int32_t iMbXy, int32_t iMbX, int32_t iMbY,
+                   sMCRefMember* pMCRefMem) {
+  int16_t iMVs[2];
+  int32_t iMbXInPix = iMbX << 4;
+  int32_t iMbYInPix = iMbY << 4;
+  int32_t iScale0;
+  int32_t iScale1;
+  uint8_t* pDst[3];
+  int32_t iCurrPoc = pDec->iFramePoc;
+  pDst[0] = pDec->pData[0] + iMbXInPix + iMbYInPix * pMCRefMem->iDstLineLuma;
+  pDst[1] = pDec->pData[1] + (iMbXInPix >> 1) + (iMbYInPix >> 1) * pMCRefMem->iDstLineChroma;
+  pDst[2] = pDec->pData[2] + (iMbXInPix >> 1) + (iMbYInPix >> 1) * pMCRefMem->iDstLineChroma;
+  if (pDec->bIdrFlag == true || pCtx->pECRefPic[0] == NULL) {
+    uint8_t* pSrcData;
+    //Y component
+    pSrcData = pMCRefMem->pSrcY + iMbY * 16 * pMCRefMem->iSrcLineLuma + iMbX * 16;
+    pCtx->sCopyFunc.pCopyLumaFunc (pDst[0], pMCRefMem->iDstLineLuma, pSrcData, pMCRefMem->iSrcLineLuma);
+    //U component
+    pSrcData = pMCRefMem->pSrcU + iMbY * 8 * pMCRefMem->iSrcLineChroma + iMbX * 8;
+    pCtx->sCopyFunc.pCopyChromaFunc (pDst[1], pMCRefMem->iDstLineChroma, pSrcData, pMCRefMem->iSrcLineChroma);
+    //V component
+    pSrcData = pMCRefMem->pSrcV + iMbY * 8 * pMCRefMem->iSrcLineChroma + iMbX * 8;
+    pCtx->sCopyFunc.pCopyChromaFunc (pDst[2], pMCRefMem->iDstLineChroma, pSrcData, pMCRefMem->iSrcLineChroma);
+    return;
+  }
 
+  if (pCtx->pECRefPic[0]) {
+    if (pCtx->pECRefPic[0] == pRef) {
+      iMVs[0] = pCtx->iECMVs[0][0];
+      iMVs[1] = pCtx->iECMVs[0][1];
+    } else {
+      iScale0 = pCtx->pECRefPic[0]->iFramePoc - iCurrPoc;
+      iScale1 = pRef->iFramePoc - iCurrPoc;
+      iMVs[0] = pCtx->iECMVs[0][0] * iScale1 / iScale0;
+      iMVs[1] = pCtx->iECMVs[0][1] * iScale1 / iScale0;
+    }
+    pMCRefMem->pDstY = pDst[0];
+    pMCRefMem->pDstU = pDst[1];
+    pMCRefMem->pDstV = pDst[2];
+    int32_t iFullMVx = (iMbXInPix << 2) + iMVs[0]; //quarter pixel
+    int32_t iFullMVy = (iMbYInPix << 2) + iMVs[1];
+    // only use to be output pixels to EC;
+    int32_t iPicWidthLeftLimit = 0;
+    int32_t iPicHeightTopLimit = 0;
+    int32_t iPicWidthRightLimit = pMCRefMem->iPicWidth;
+    int32_t iPicHeightBottomLimit = pMCRefMem->iPicHeight;
+    if (pCtx->pSps->bFrameCroppingFlag) {
+      iPicWidthLeftLimit = 0 + pCtx->sFrameCrop.iLeftOffset * 2;
+      iPicWidthRightLimit = (pMCRefMem->iPicWidth - pCtx->sFrameCrop.iRightOffset * 2);
+      iPicHeightTopLimit = 0 + pCtx->sFrameCrop.iTopOffset * 2;
+      iPicHeightBottomLimit = (pMCRefMem->iPicHeight - pCtx->sFrameCrop.iTopOffset * 2);
+    }
+    // further make sure no need to expand picture
+    int32_t iMinLeftOffset = (iPicWidthLeftLimit + 2) << 2;
+    int32_t iMaxRightOffset = ((iPicWidthRightLimit - 19) << 2);
+    int32_t iMinTopOffset = (iPicHeightTopLimit + 2) << 2;
+    int32_t iMaxBottomOffset = ((iPicHeightBottomLimit - 19) << 2);
+    if (iFullMVx < iMinLeftOffset) {
+      iFullMVx = (iFullMVx >> 2) << 2;
+      iFullMVx = WELS_MAX (iPicWidthLeftLimit, iFullMVx);
+    } else if (iFullMVx > iMaxRightOffset) {
+      iFullMVx = (iFullMVx >> 2) << 2;
+      iFullMVx = WELS_MIN (((iPicWidthRightLimit - 17) << 2), iFullMVx);
+    }
+    if (iFullMVy < iMinTopOffset) {
+      iFullMVy = (iFullMVy >> 2) << 2;
+      iFullMVy = WELS_MAX (iPicHeightTopLimit, iFullMVy);
+    } else if (iFullMVy > iMaxBottomOffset) {
+      iFullMVy = (iFullMVy >> 2) << 2;
+      iFullMVy = WELS_MIN (((iPicHeightBottomLimit - 17) << 2), iFullMVy);
+    }
+    iMVs[0] = iFullMVx - (iMbXInPix << 2);
+    iMVs[1] = iFullMVy - (iMbYInPix << 2);
+    BaseMC (pMCRefMem, iMbXInPix, iMbYInPix, &pCtx->sMcFunc, 16, 16, iMVs);
+  }
+  return ;
+}
+
+void GetAvilInfoFromCorrectMb (PWelsDecoderContext pCtx) {
+  int32_t iMbWidth = (int32_t) pCtx->pSps->iMbWidth;
+  int32_t iMbHeight = (int32_t) pCtx->pSps->iMbHeight;
+  bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
+  PDqLayer pCurDqLayer = pCtx->pCurDqLayer;
+  int32_t iInterMbCorrectNum[16];
+  int32_t iMbXyIndex;
+
+  int8_t iRefIdx;
+  memset (pCtx->iECMVs, 0, sizeof (int32_t) * 32);
+  memset (pCtx->pECRefPic, 0, sizeof (PPicture) * 16);
+  memset (iInterMbCorrectNum, 0, sizeof (int32_t) * 16);
+
+  for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
+    for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
+      iMbXyIndex = iMbY * iMbWidth + iMbX;
+      if (pMbCorrectlyDecodedFlag[iMbXyIndex] && IS_INTER (pCurDqLayer->pMbType[iMbXyIndex])) {
+        int32_t iMBType = pCurDqLayer->pMbType[iMbXyIndex];
+        switch (iMBType) {
+        case MB_TYPE_SKIP:
+        case MB_TYPE_16x16:
+          iRefIdx = pCurDqLayer->pRefIndex[0][iMbXyIndex][0];
+          pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][0][0];
+          pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][0][1];
+          pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
+          iInterMbCorrectNum[iRefIdx]++;
+          break;
+        case MB_TYPE_16x8:
+          iRefIdx = pCurDqLayer->pRefIndex[0][iMbXyIndex][0];
+          pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][0][0];
+          pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][0][1];
+          pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
+          iInterMbCorrectNum[iRefIdx]++;
+
+          iRefIdx = pCurDqLayer->pRefIndex[0][iMbXyIndex][8];
+          pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][8][0];
+          pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][8][1];
+          pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
+          iInterMbCorrectNum[iRefIdx]++;
+          break;
+        case MB_TYPE_8x16:
+          iRefIdx = pCurDqLayer->pRefIndex[0][iMbXyIndex][0];
+          pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][0][0];
+          pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][0][1];
+          pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
+          iInterMbCorrectNum[iRefIdx]++;
+
+          iRefIdx = pCurDqLayer->pRefIndex[0][iMbXyIndex][2];
+          pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][2][0];
+          pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][2][1];
+          pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
+          iInterMbCorrectNum[iRefIdx]++;
+          break;
+        case MB_TYPE_8x8:
+        case MB_TYPE_8x8_REF0: {
+          uint32_t iSubMBType;
+          int32_t i, j, iIIdx, iJIdx;
+
+          for (i = 0; i < 4; i++) {
+            iSubMBType = pCurDqLayer->pSubMbType[iMbXyIndex][i];
+            iIIdx = ((i >> 1) << 3) + ((i & 1) << 1);
+            iRefIdx = pCurDqLayer->pRefIndex[0][iMbXyIndex][iIIdx];
+            pCtx->pECRefPic[iRefIdx] = pCtx->sRefPic.pRefList[LIST_0][iRefIdx];
+            switch (iSubMBType) {
+            case SUB_MB_TYPE_8x8:
+              pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx][0];
+              pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx][1];
+              iInterMbCorrectNum[iRefIdx]++;
+
+              break;
+            case SUB_MB_TYPE_8x4:
+              pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx][0];
+              pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx][1];
+
+
+              pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx + 4][0];
+              pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx + 4][1];
+              iInterMbCorrectNum[iRefIdx] += 2;
+
+              break;
+            case SUB_MB_TYPE_4x8:
+              pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx][0];
+              pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx][1];
+
+
+              pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx + 1][0];
+              pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx + 1][1];
+              iInterMbCorrectNum[iRefIdx] += 2;
+              break;
+            case SUB_MB_TYPE_4x4: {
+              for (j = 0; j < 4; j++) {
+                iJIdx = ((j >> 1) << 2) + (j & 1);
+                pCtx->iECMVs[iRefIdx][0] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx + iJIdx][0];
+                pCtx->iECMVs[iRefIdx][1] += pCurDqLayer->pMv[0][iMbXyIndex][iIIdx + iJIdx][1];
+              }
+              iInterMbCorrectNum[iRefIdx] += 4;
+            }
+            break;
+            default:
+              break;
+            }
+          }
+        }
+        break;
+        default:
+          break;
+        }
+      } //pMbCorrectlyDecodedFlag[iMbXyIndex]
+    } //iMbX
+  } //iMbY
+  for (int32_t i = 0; i < 16; i++) {
+    if (iInterMbCorrectNum[i]) {
+      pCtx->iECMVs[i][0] = pCtx->iECMVs[i][0] / iInterMbCorrectNum[i];
+      pCtx->iECMVs[i][1] = pCtx->iECMVs[i][1] / iInterMbCorrectNum[i];
+    }
+  }
+}
+
+void DoErrorConSliceMVCopy (PWelsDecoderContext pCtx) {
+  int32_t iMbWidth = (int32_t) pCtx->pSps->iMbWidth;
+  int32_t iMbHeight = (int32_t) pCtx->pSps->iMbHeight;
+  PPicture pDstPic = pCtx->pDec;
+  PPicture pSrcPic = pCtx->pPreviousDecodedPictureInDpb;
+
+  int32_t iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
+  bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
+  int32_t iMbEcedNum = 0;
+  int32_t iMbXyIndex;
+  uint8_t* pDstData;
+  uint32_t iDstStride = pDstPic->iLinesize[0];
+  sMCRefMember sMCRefMem;
+  if (pSrcPic != NULL) {
+    sMCRefMem.iSrcLineLuma   = pSrcPic->iLinesize[0];
+    sMCRefMem.iSrcLineChroma = pSrcPic->iLinesize[1];
+    sMCRefMem.pSrcY = pSrcPic->pData[0];
+    sMCRefMem.pSrcU = pSrcPic->pData[1];
+    sMCRefMem.pSrcV = pSrcPic->pData[2];
+    sMCRefMem.iDstLineLuma   = pDstPic->iLinesize[0];
+    sMCRefMem.iDstLineChroma = pDstPic->iLinesize[1];
+    sMCRefMem.iPicWidth = pDstPic->iWidthInPixel;
+    sMCRefMem.iPicHeight = pDstPic->iHeightInPixel;
+  }
+
+  for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
+    for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
+      iMbXyIndex = iMbY * iMbWidth + iMbX;
+      if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) {
+        iMbEcedNum++;
+        if (pSrcPic != NULL) {
+          DoMbECMvCopy (pCtx, pDstPic, pSrcPic, iMbXyIndex, iMbX, iMbY, &sMCRefMem);
+        } else { //pSrcPic == NULL
+          //Y component
+          pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;
+          for (int32_t i = 0; i < 16; ++i) {
+            memset (pDstData, 128, 16);
+            pDstData += iDstStride;
+          }
+          //U component
+          pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          for (int32_t i = 0; i < 8; ++i) {
+            memset (pDstData, 128, 8);
+            pDstData += iDstStride / 2;
+          }
+          //V component
+          pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
+          for (int32_t i = 0; i < 8; ++i) {
+            memset (pDstData, 128, 8);
+            pDstData += iDstStride / 2;
+          }
+        } //
+
+      } //!pMbCorrectlyDecodedFlag[iMbXyIndex]
+    } //iMbX
+  } //iMbY
+
+  pCtx->sDecoderStatistics.uiAvgEcRatio = (pCtx->sDecoderStatistics.uiAvgEcRatio * pCtx->sDecoderStatistics.uiEcFrameNum)
+                                          + ((iMbEcedNum * 100) / iMbNum) ;
+}
+
 //Mark erroneous frame as Ref Pic into DPB
 int32_t MarkECFrameAsRef (PWelsDecoderContext pCtx) {
   int32_t iRet = WelsMarkAsRef (pCtx);
@@ -200,6 +459,10 @@
              || (ERROR_CON_SLICE_COPY_CROSS_IDR == pCtx->eErrorConMethod)
              || (ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->eErrorConMethod)) {
     DoErrorConSliceCopy (pCtx);
+  } else if ((ERROR_CON_SLICE_MV_COPY_CROSS_IDR == pCtx->eErrorConMethod)
+             || (ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->eErrorConMethod)) {
+    GetAvilInfoFromCorrectMb (pCtx);
+    DoErrorConSliceMVCopy (pCtx);
   } //TODO add other EC methods here in the future
   pCtx->iErrorCode |= dsDataErrorConcealed;
   pCtx->pDec->bIsComplete = false; // Set complete flag to false after do EC.
--- a/codec/decoder/core/src/manage_dec_ref.cpp
+++ b/codec/decoder/core/src/manage_dec_ref.cpp
@@ -40,6 +40,7 @@
  *****************************************************************************/
 
 #include "manage_dec_ref.h"
+#include "error_concealment.h"
 #include "error_code.h"
 
 namespace WelsDec {
@@ -67,7 +68,7 @@
     pRef->bUsedAsRef = false;
     pRef->bIsLongRef = false;
     pRef->iFrameNum = -1;
-    pRef->iFramePoc = 0;
+    //pRef->iFramePoc = 0;
     pRef->iLongTermFrameIdx = -1;
     pRef->uiQualityId = -1;
     pRef->uiTemporalId = -1;
@@ -121,10 +122,13 @@
         pCtx->iErrorCode |= dsDataErrorConcealed;
         bool bCopyPrevious = ((ERROR_CON_FRAME_COPY_CROSS_IDR == pCtx->eErrorConMethod)
                               || (ERROR_CON_SLICE_COPY_CROSS_IDR == pCtx->eErrorConMethod)
-                              || (ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->eErrorConMethod))
-                             && (NULL != pCtx->pPreviousDecodedPictureInDpb);
+                              || (ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->eErrorConMethod)
+                              || (ERROR_CON_SLICE_MV_COPY_CROSS_IDR == pCtx->eErrorConMethod)
+                              || (ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE == pCtx->eErrorConMethod))
+                              && (NULL != pCtx->pPreviousDecodedPictureInDpb);
         bCopyPrevious = bCopyPrevious && (pRef->iWidthInPixel == pCtx->pPreviousDecodedPictureInDpb->iWidthInPixel)
                         && (pRef->iHeightInPixel == pCtx->pPreviousDecodedPictureInDpb->iHeightInPixel);
+
         if (bCopyPrevious) {
           memcpy (pRef->pData[0], pCtx->pPreviousDecodedPictureInDpb->pData[0], pRef->iLinesize[0] * pRef->iHeightInPixel);
           memcpy (pRef->pData[1], pCtx->pPreviousDecodedPictureInDpb->pData[1], pRef->iLinesize[1] * pRef->iHeightInPixel / 2);
--- a/codec/decoder/core/src/pic_queue.cpp
+++ b/codec/decoder/core/src/pic_queue.cpp
@@ -81,6 +81,7 @@
 
   iLumaSize	= iPicWidth * iPicHeight;
   iChromaSize	= iPicChromaWidth * iPicChromaHeight;
+
   pPic->pBuffer[0]	= static_cast<uint8_t*> (WelsMalloc (iLumaSize /* luma */
                       + (iChromaSize << 1) /* Cb,Cr */, "_pic->buffer[0]"));
   memset (pPic->pBuffer[0], 128, (iLumaSize + (iChromaSize << 1)));
@@ -93,8 +94,6 @@
   pPic->pData[0]	= pPic->pBuffer[0] + (1 + pPic->iLinesize[0]) * PADDING_LENGTH;
   pPic->pData[1]	= pPic->pBuffer[1] + /*WELS_ALIGN*/ (((1 + pPic->iLinesize[1]) * PADDING_LENGTH) >> 1);
   pPic->pData[2]	= pPic->pBuffer[2] + /*WELS_ALIGN*/ (((1 + pPic->iLinesize[2]) * PADDING_LENGTH) >> 1);
-
-
 
   pPic->iPlanes		= 3;	// yv12 in default
   pPic->iWidthInPixel	= kiPicWidth;
--- a/codec/decoder/core/src/rec_mb.cpp
+++ b/codec/decoder/core/src/rec_mb.cpp
@@ -164,24 +164,7 @@
   return ERR_NONE;
 }
 
-typedef struct TagMCRefMember {
-  uint8_t* pDstY;
-  uint8_t* pDstU;
-  uint8_t* pDstV;
 
-  uint8_t* pSrcY;
-  uint8_t* pSrcU;
-  uint8_t* pSrcV;
-
-  int32_t iSrcLineLuma;
-  int32_t iSrcLineChroma;
-
-  int32_t iDstLineLuma;
-  int32_t iDstLineChroma;
-
-  int32_t iPicWidth;
-  int32_t iPicHeight;
-} sMCRefMember;
 //according to current 8*8 block ref_index to gain reference picture
 static inline void GetRefPic (sMCRefMember* pMCRefMem, PWelsDecoderContext pCtx, int8_t* pRefIdxList,
                               int32_t iIndex) {
@@ -202,7 +185,7 @@
 #ifndef MC_FLOW_SIMPLE_JUDGE
 #define MC_FLOW_SIMPLE_JUDGE 1
 #endif //MC_FLOW_SIMPLE_JUDGE
-static inline void BaseMC (sMCRefMember* pMCRefMem, int32_t iXOffset, int32_t iYOffset, SMcFunc* pMCFunc,
+void BaseMC (sMCRefMember* pMCRefMem, int32_t iXOffset, int32_t iYOffset, SMcFunc* pMCFunc,
                            int32_t iBlkWidth, int32_t iBlkHeight, int16_t iMVs[2]) {
   int32_t iFullMVx = (iXOffset << 2) + iMVs[0]; //quarter pixel
   int32_t iFullMVy = (iYOffset << 2) + iMVs[1];
--- a/codec/decoder/plus/src/welsDecoderExt.cpp
+++ b/codec/decoder/plus/src/welsDecoderExt.cpp
@@ -277,7 +277,7 @@
       return cmInitParaError;
 
     iVal	= * ((int*)pOption);	// int value for error concealment idc
-    iVal = WELS_CLIP3 (iVal, (int32_t) ERROR_CON_DISABLE, (int32_t) ERROR_CON_SLICE_COPY_CROSS_IDR_FREEZE_RES_CHANGE);
+    iVal = WELS_CLIP3 (iVal, (int32_t) ERROR_CON_DISABLE, (int32_t) ERROR_CON_SLICE_MV_COPY_CROSS_IDR_FREEZE_RES_CHANGE);
     m_pDecContext->eErrorConMethod = (ERROR_CON_IDC) iVal;
     InitErrorCon (m_pDecContext);
     WelsLog (&m_pWelsTrace->m_sLogCtx, WELS_LOG_INFO,