/*! * \copy * Copyright (c) 2013, Cisco Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * error_concealment.cpp: Wels decoder error concealment implementation */ #include "error_code.h"#include "expand_pic.h"#include "manage_dec_ref.h"#include "copy_mb.h"#include "error_concealment.h"#include "cpu_core.h" namespace WelsDec {//Initvoid 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; #if defined(X86_ASM) if (pCtx->uiCpuFlag & WELS_CPU_MMXEXT) { pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_mmx; //aligned } if (pCtx->uiCpuFlag & WELS_CPU_SSE2) { pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_sse2; //this is aligned copy; }#endif //X86_ASM #if defined(HAVE_NEON) if (pCtx->uiCpuFlag & WELS_CPU_NEON) { pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_neon; //aligned pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_neon; //aligned }#endif //HAVE_NEON #if defined(HAVE_NEON_AARCH64) if (pCtx->uiCpuFlag & WELS_CPU_NEON) { pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_AArch64_neon; //aligned pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_AArch64_neon; //aligned }#endif //HAVE_NEON_AARCH64 } //TODO add more methods here return;} //Do error concealment using frame copy methodvoid DoErrorConFrameCopy (PWelsDecoderContext pCtx) { PPicture pDstPic = pCtx->pDec; PPicture pSrcPic = pCtx->pPreviousDecodedPictureInDpb; uint32_t uiHeightInPixelY = (pCtx->pSps->iMbHeight) << 4; int32_t iStrideY = pDstPic->iLinesize[0]; int32_t iStrideUV = pDstPic->iLinesize[1]; pCtx->iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; pCtx->iMbEcedNum = pCtx->iMbNum; if ((pCtx->eErrorConMethod == ERROR_CON_FRAME_COPY) && (pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.bIdrFlag)) pSrcPic = NULL; //no cross IDR method, should fill in data instead of copy if (pSrcPic == NULL) { //no ref pic, assign specific data to picture memset (pDstPic->pData[0], 128, uiHeightInPixelY * iStrideY); memset (pDstPic->pData[1], 128, (uiHeightInPixelY >> 1) * iStrideUV); memset (pDstPic->pData[2], 128, (uiHeightInPixelY >> 1) * iStrideUV); } else { //has ref pic here memcpy (pDstPic->pData[0], pSrcPic->pData[0], uiHeightInPixelY * iStrideY); memcpy (pDstPic->pData[1], pSrcPic->pData[1], (uiHeightInPixelY >> 1) * iStrideUV); memcpy (pDstPic->pData[2], pSrcPic->pData[2], (uiHeightInPixelY >> 1) * iStrideUV); }} //Do error concealment using slice copy methodvoid DoErrorConSliceCopy (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; if ((pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY) && (pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.bIdrFlag)) pSrcPic = NULL; //no cross IDR method, should fill in data instead of copy pCtx->iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; //uint8_t *pDstData[3], *pSrcData[3]; bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag; pCtx->iMbEcedNum = 0; //Do slice copy late int32_t iMbXyIndex; uint8_t* pSrcData, *pDstData; uint32_t iSrcStride; // = pSrcPic->iLinesize[0]; uint32_t iDstStride = pDstPic->iLinesize[0]; for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) { for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) { iMbXyIndex = iMbY * iMbWidth + iMbX; if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) { pCtx->iMbEcedNum++; if (pSrcPic != NULL) { iSrcStride = pSrcPic->iLinesize[0]; //Y component pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;; pSrcData = pSrcPic->pData[0] + iMbY * 16 * iSrcStride + iMbX * 16; pCtx->sCopyFunc.pCopyLumaFunc (pDstData, iDstStride, pSrcData, iSrcStride); //U component pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8; pSrcData = pSrcPic->pData[1] + iMbY * 8 * iSrcStride / 2 + iMbX * 8; pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2); //V component pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8; pSrcData = pSrcPic->pData[2] + iMbY * 8 * iSrcStride / 2 + iMbX * 8; pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2); } 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} //Do error concealment using slice MV copy methodvoid DoMbECMvCopy (PWelsDecoderContext pCtx, PPicture pDec, PPicture pRef, int32_t iMbXy, int32_t iMbX, int32_t iMbY, sMCRefMember* pMCRefMem) { if (pDec == pRef) { return; // for protection, shall never go into this logic, error info printed outside. } 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; pCtx->iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag; pCtx->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; if (pDstPic == pSrcPic) { // output error info, EC will be ignored in DoMbECMvCopy WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "DoErrorConSliceMVCopy()::pPreviousPic and pDec use same buffer, ignored."); } } for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) { for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) { iMbXyIndex = iMbY * iMbWidth + iMbX; if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) { pCtx->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} //Mark erroneous frame as Ref Pic into DPBint32_t MarkECFrameAsRef (PWelsDecoderContext pCtx) { int32_t iRet = WelsMarkAsRef (pCtx); if (iRet != ERR_NONE) { pCtx->pDec = NULL; return iRet; } ExpandReferencingPicture (pCtx->pDec->pData, pCtx->pDec->iWidthInPixel, pCtx->pDec->iHeightInPixel, pCtx->pDec->iLinesize, pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture); pCtx->pDec = NULL; return ERR_NONE;} bool NeedErrorCon (PWelsDecoderContext pCtx) { bool bNeedEC = false; int32_t iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight; for (int32_t i = 0; i < iMbNum; ++i) { if (!pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag[i]) { bNeedEC = true; break; } } return bNeedEC;} // ImplementErrorConceal// Do actual error concealmentvoid ImplementErrorCon (PWelsDecoderContext pCtx) { if (ERROR_CON_DISABLE == pCtx->eErrorConMethod) { pCtx->iErrorCode |= dsBitstreamError; return; } else if ((ERROR_CON_FRAME_COPY == pCtx->eErrorConMethod) || (ERROR_CON_FRAME_COPY_CROSS_IDR == pCtx->eErrorConMethod)) { DoErrorConFrameCopy (pCtx); } else if ((ERROR_CON_SLICE_COPY == pCtx->eErrorConMethod) || (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.} } // namespace WelsDec
/*!
* \copy
* Copyright (c) 2013, Cisco Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* error_concealment.cpp: Wels decoder error concealment implementation
*/
#include "error_code.h"
#include "expand_pic.h"
#include "manage_dec_ref.h"
#include "copy_mb.h"
#include "error_concealment.h"
#include "cpu_core.h"
namespace WelsDec {
//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;
#if defined(X86_ASM)
if (pCtx->uiCpuFlag & WELS_CPU_MMXEXT) {
pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_mmx; //aligned
}
if (pCtx->uiCpuFlag & WELS_CPU_SSE2) {
pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_sse2; //this is aligned copy;
}
#endif //X86_ASM
#if defined(HAVE_NEON)
if (pCtx->uiCpuFlag & WELS_CPU_NEON) {
pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_neon; //aligned
pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_neon; //aligned
}
#endif //HAVE_NEON
#if defined(HAVE_NEON_AARCH64)
if (pCtx->uiCpuFlag & WELS_CPU_NEON) {
pCtx->sCopyFunc.pCopyLumaFunc = WelsCopy16x16_AArch64_neon; //aligned
pCtx->sCopyFunc.pCopyChromaFunc = WelsCopy8x8_AArch64_neon; //aligned
}
#endif //HAVE_NEON_AARCH64
} //TODO add more methods here
return;
}
//Do error concealment using frame copy method
void DoErrorConFrameCopy (PWelsDecoderContext pCtx) {
PPicture pDstPic = pCtx->pDec;
PPicture pSrcPic = pCtx->pPreviousDecodedPictureInDpb;
uint32_t uiHeightInPixelY = (pCtx->pSps->iMbHeight) << 4;
int32_t iStrideY = pDstPic->iLinesize[0];
int32_t iStrideUV = pDstPic->iLinesize[1];
pCtx->iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
pCtx->iMbEcedNum = pCtx->iMbNum;
if ((pCtx->eErrorConMethod == ERROR_CON_FRAME_COPY) && (pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.bIdrFlag))
pSrcPic = NULL; //no cross IDR method, should fill in data instead of copy
if (pSrcPic == NULL) { //no ref pic, assign specific data to picture
memset (pDstPic->pData[0], 128, uiHeightInPixelY * iStrideY);
memset (pDstPic->pData[1], 128, (uiHeightInPixelY >> 1) * iStrideUV);
memset (pDstPic->pData[2], 128, (uiHeightInPixelY >> 1) * iStrideUV);
} else { //has ref pic here
memcpy (pDstPic->pData[0], pSrcPic->pData[0], uiHeightInPixelY * iStrideY);
memcpy (pDstPic->pData[1], pSrcPic->pData[1], (uiHeightInPixelY >> 1) * iStrideUV);
memcpy (pDstPic->pData[2], pSrcPic->pData[2], (uiHeightInPixelY >> 1) * iStrideUV);
}
}
//Do error concealment using slice copy method
void DoErrorConSliceCopy (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;
if ((pCtx->eErrorConMethod == ERROR_CON_SLICE_COPY) && (pCtx->pCurDqLayer->sLayerInfo.sNalHeaderExt.bIdrFlag))
pSrcPic = NULL; //no cross IDR method, should fill in data instead of copy
pCtx->iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
//uint8_t *pDstData[3], *pSrcData[3];
bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
pCtx->iMbEcedNum = 0;
//Do slice copy late
int32_t iMbXyIndex;
uint8_t* pSrcData, *pDstData;
uint32_t iSrcStride; // = pSrcPic->iLinesize[0];
uint32_t iDstStride = pDstPic->iLinesize[0];
for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
iMbXyIndex = iMbY * iMbWidth + iMbX;
if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) {
pCtx->iMbEcedNum++;
if (pSrcPic != NULL) {
iSrcStride = pSrcPic->iLinesize[0];
//Y component
pDstData = pDstPic->pData[0] + iMbY * 16 * iDstStride + iMbX * 16;;
pSrcData = pSrcPic->pData[0] + iMbY * 16 * iSrcStride + iMbX * 16;
pCtx->sCopyFunc.pCopyLumaFunc (pDstData, iDstStride, pSrcData, iSrcStride);
//U component
pDstData = pDstPic->pData[1] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
pSrcData = pSrcPic->pData[1] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2);
//V component
pDstData = pDstPic->pData[2] + iMbY * 8 * iDstStride / 2 + iMbX * 8;
pSrcData = pSrcPic->pData[2] + iMbY * 8 * iSrcStride / 2 + iMbX * 8;
pCtx->sCopyFunc.pCopyChromaFunc (pDstData, iDstStride / 2, pSrcData, iSrcStride / 2);
} 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
}
//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) {
if (pDec == pRef) {
return; // for protection, shall never go into this logic, error info printed outside.
}
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;
pCtx->iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
bool* pMbCorrectlyDecodedFlag = pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag;
pCtx->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;
if (pDstPic == pSrcPic) {
// output error info, EC will be ignored in DoMbECMvCopy
WelsLog (& (pCtx->sLogCtx), WELS_LOG_ERROR, "DoErrorConSliceMVCopy()::pPreviousPic and pDec use same buffer, ignored.");
}
}
for (int32_t iMbY = 0; iMbY < iMbHeight; ++iMbY) {
for (int32_t iMbX = 0; iMbX < iMbWidth; ++iMbX) {
iMbXyIndex = iMbY * iMbWidth + iMbX;
if (!pMbCorrectlyDecodedFlag[iMbXyIndex]) {
pCtx->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
}
//Mark erroneous frame as Ref Pic into DPB
int32_t MarkECFrameAsRef (PWelsDecoderContext pCtx) {
int32_t iRet = WelsMarkAsRef (pCtx);
if (iRet != ERR_NONE) {
pCtx->pDec = NULL;
return iRet;
}
ExpandReferencingPicture (pCtx->pDec->pData, pCtx->pDec->iWidthInPixel, pCtx->pDec->iHeightInPixel,
pCtx->pDec->iLinesize,
pCtx->sExpandPicFunc.pfExpandLumaPicture, pCtx->sExpandPicFunc.pfExpandChromaPicture);
pCtx->pDec = NULL;
return ERR_NONE;
}
bool NeedErrorCon (PWelsDecoderContext pCtx) {
bool bNeedEC = false;
int32_t iMbNum = pCtx->pSps->iMbWidth * pCtx->pSps->iMbHeight;
for (int32_t i = 0; i < iMbNum; ++i) {
if (!pCtx->pCurDqLayer->pMbCorrectlyDecodedFlag[i]) {
bNeedEC = true;
break;
}
}
return bNeedEC;
}
// ImplementErrorConceal
// Do actual error concealment
void ImplementErrorCon (PWelsDecoderContext pCtx) {
if (ERROR_CON_DISABLE == pCtx->eErrorConMethod) {
pCtx->iErrorCode |= dsBitstreamError;
return;
} else if ((ERROR_CON_FRAME_COPY == pCtx->eErrorConMethod)
|| (ERROR_CON_FRAME_COPY_CROSS_IDR == pCtx->eErrorConMethod)) {
DoErrorConFrameCopy (pCtx);
} else if ((ERROR_CON_SLICE_COPY == pCtx->eErrorConMethod)
|| (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.
}
} // namespace WelsDec