/*! * \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. * */ #include "wels_preprocess.h"#include "picture_handle.h"#include "encoder_context.h"#include "utils.h"#include "encoder.h" namespace WelsEnc { //***** entry API declaration ************************************************************************// int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic, CMemoryAlign* pMemoryAlign);bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic);void FreeScaledPic (Scaled_Picture* pScaledPic, CMemoryAlign* pMemoryAlign);void WelsMoveMemory_c (uint8_t* pDstY, uint8_t* pDstU, uint8_t* pDstV, int32_t iDstStrideY, int32_t iDstStrideUV, uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iSrcStrideY, int32_t iSrcStrideUV, int32_t iWidth, int32_t iHeight); //******* table definition ***********************************************************************//const uint8_t g_kuiRefTemporalIdx[MAX_TEMPORAL_LEVEL][MAX_GOP_SIZE] = { { 0, }, // 0 { 0, 0, }, // 1 { 0, 0, 0, 1, }, // 2 { 0, 0, 0, 2, 0, 1, 1, 2, }, // 3}; const int32_t g_kiPixMapSizeInBits = sizeof (uint8_t) * 8; inline void WelsUpdateSpatialIdxMap (sWelsEncCtx* pEncCtx, int32_t iPos, SPicture* pPic, int32_t iDidx) { pEncCtx->sSpatialIndexMap[iPos].pSrc = pPic; pEncCtx->sSpatialIndexMap[iPos].iDid = iDidx;} /***************************************************************************** implement of the interface****************************************************************************/ CWelsPreProcess::CWelsPreProcess (sWelsEncCtx* pEncCtx) { m_pInterfaceVp = NULL; m_bInitDone = false; m_pEncCtx = pEncCtx; memset (&m_sScaledPicture, 0, sizeof (m_sScaledPicture)); memset (m_pSpatialPic, 0, sizeof (m_pSpatialPic)); memset (m_uiSpatialLayersInTemporal, 0, sizeof (m_uiSpatialLayersInTemporal)); memset (m_uiSpatialPicNum, 0, sizeof (m_uiSpatialPicNum));} CWelsPreProcess::~CWelsPreProcess() { FreeScaledPic (&m_sScaledPicture, m_pEncCtx->pMemAlign); WelsPreprocessDestroy();} int32_t CWelsPreProcess::WelsPreprocessCreate() { if (m_pInterfaceVp == NULL) { WelsCreateVpInterface ((void**) &m_pInterfaceVp, WELSVP_INTERFACE_VERION); if (!m_pInterfaceVp) goto exit; } else goto exit; return 0; exit: WelsPreprocessDestroy(); return 1;} int32_t CWelsPreProcess::WelsPreprocessDestroy() { WelsDestroyVpInterface (m_pInterfaceVp, WELSVP_INTERFACE_VERION); m_pInterfaceVp = NULL; return 0;} int32_t CWelsPreProcess::WelsPreprocessReset (sWelsEncCtx* pCtx) { int32_t iRet = -1; if (pCtx) { FreeScaledPic (&m_sScaledPicture, pCtx->pMemAlign); iRet = InitLastSpatialPictures (pCtx); iRet = WelsInitScaledPic (pCtx->pSvcParam, &m_sScaledPicture, pCtx->pMemAlign); } return iRet;} int32_t CWelsPreProcess::AllocSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam) { CMemoryAlign* pMa = pCtx->pMemAlign; const int32_t kiDlayerCount = pParam->iSpatialLayerNum; int32_t iDlayerIndex = 0; // spatial pictures iDlayerIndex = 0; do { const int32_t kiPicWidth = pParam->sSpatialLayers[iDlayerIndex].iVideoWidth; const int32_t kiPicHeight = pParam->sSpatialLayers[iDlayerIndex].iVideoHeight; const uint8_t kuiLayerInTemporal = 2 + WELS_MAX (pParam->sDependencyLayers[iDlayerIndex].iHighestTemporalId, 1); const uint8_t kuiRefNumInTemporal = kuiLayerInTemporal + pParam->iLTRRefNum; uint8_t i = 0; do { SPicture* pPic = AllocPicture (pMa, kiPicWidth, kiPicHeight, false, 0); WELS_VERIFY_RETURN_IF (1, (NULL == pPic)) m_pSpatialPic[iDlayerIndex][i] = pPic; ++ i; } while (i < kuiRefNumInTemporal); if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME) m_uiSpatialLayersInTemporal[iDlayerIndex] = 1; else m_uiSpatialLayersInTemporal[iDlayerIndex] = kuiLayerInTemporal; m_uiSpatialPicNum[iDlayerIndex] = kuiRefNumInTemporal; ++ iDlayerIndex; } while (iDlayerIndex < kiDlayerCount); return 0;} void CWelsPreProcess::FreeSpatialPictures (sWelsEncCtx* pCtx) { CMemoryAlign* pMa = pCtx->pMemAlign; int32_t j = 0; while (j < pCtx->pSvcParam->iSpatialLayerNum) { uint8_t i = 0; uint8_t uiRefNumInTemporal = m_uiSpatialPicNum[j]; while (i < uiRefNumInTemporal) { if (NULL != m_pSpatialPic[j][i]) { FreePicture (pMa, &m_pSpatialPic[j][i]); } ++ i; } m_uiSpatialLayersInTemporal[j] = 0; ++ j; }} int32_t CWelsPreProcess::BuildSpatialPicList (sWelsEncCtx* pCtx, const SSourcePicture* kpSrcPic) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; int32_t iSpatialNum = 0; if (!m_bInitDone) { if (WelsPreprocessCreate() != 0) return -1; //init source width and height pSvcParam->SUsedPicRect.iLeft = 0; pSvcParam->SUsedPicRect.iTop = 0; pSvcParam->SUsedPicRect.iWidth = ((kpSrcPic->iPicWidth >> 1) << 1); pSvcParam->SUsedPicRect.iHeight = ((kpSrcPic->iPicHeight >> 1) << 1); if (WelsPreprocessReset (pCtx) != 0) return -1; m_iAvaliableRefInSpatialPicList = pSvcParam->iNumRefFrame; m_bInitDone = true; } if (m_pInterfaceVp == NULL) return -1; pCtx->pVaa->bSceneChangeFlag = pCtx->pVaa->bIdrPeriodFlag = false; if (pSvcParam->uiIntraPeriod) pCtx->pVaa->bIdrPeriodFlag = (1 + pCtx->iFrameIndex >= (int32_t)pSvcParam->uiIntraPeriod) ? true : false; iSpatialNum = SingleLayerPreprocess (pCtx, kpSrcPic, &m_sScaledPicture); return iSpatialNum;} int32_t CWelsPreProcess::AnalyzeSpatialPic (sWelsEncCtx* pCtx, const int32_t kiDidx) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; bool bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pCtx->eSliceType == P_SLICE)); bool bCalculateBGD = (pCtx->eSliceType == P_SLICE && pSvcParam->bEnableBackgroundDetection); int32_t iCurTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] - 1; int32_t iRefTemporalIdx = (int32_t)g_kuiRefTemporalIdx[pSvcParam->iDecompStages][pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)]; if (pCtx->uiTemporalId == 0 && pCtx->pLtr[pCtx->uiDependencyId].bReceivedT0LostFlag) iRefTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiValidLongTermPicIdx; SPicture* pCurPic = m_pSpatialPic[kiDidx][iCurTemporalIdx]; bool bCalculateVar = (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE); if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) { SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa); SRefInfoParam* BestRefCandidateParam = (pCtx->bCurFrameMarkedAsSceneLtr) ? (& (pVaaExt->sVaaLtrBestRefCandidate[0])) : (& (pVaaExt->sVaaStrBestRefCandidate[0])); SPicture* pRefPic = m_pSpatialPic[0][BestRefCandidateParam->iSrcListIdx]; VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, false, bCalculateVar, bCalculateBGD); if (pSvcParam->bEnableBackgroundDetection) { BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE); } if (bNeededMbAq) { AdaptiveQuantCalculation (pCtx->pVaa, pCurPic, pRefPic); } } else { SPicture* pRefPic = m_pSpatialPic[kiDidx][iRefTemporalIdx]; SPicture* pLastPic = m_pLastSpatialPicture[kiDidx][0]; bool bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq); bool bCalculateVar = (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE); VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, bCalculateSQDiff, bCalculateVar, bCalculateBGD); if (pSvcParam->bEnableBackgroundDetection) { BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE); } if (bNeededMbAq) { SPicture* pCurPic = m_pLastSpatialPicture[kiDidx][1]; SPicture* pRefPic = m_pLastSpatialPicture[kiDidx][0]; AdaptiveQuantCalculation (pCtx->pVaa, pCurPic, pRefPic); } WelsExchangeSpatialPictures (&m_pLastSpatialPicture[kiDidx][1], &m_pLastSpatialPicture[kiDidx][0]); } return 0;} int32_t CWelsPreProcess::GetCurPicPosition(const int32_t kiDidx) { return (m_uiSpatialLayersInTemporal[kiDidx] - 1);} int32_t CWelsPreProcess::UpdateSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam, const int8_t iCurTid, const int32_t kiDidx) { if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) return 0; const int32_t kiCurPos = GetCurPicPosition(kiDidx); if (iCurTid < kiCurPos || pParam->iDecompStages == 0) { if ((iCurTid >= MAX_TEMPORAL_LEVEL) || (kiCurPos > MAX_TEMPORAL_LEVEL)) { InitLastSpatialPictures (pCtx); return 1; } if (pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid]) { const int32_t kiAvailableLtrPos = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiMarkLongTermPicIdx; WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiAvailableLtrPos], &m_pSpatialPic[kiDidx][iCurTid]); pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid] = false; } WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiCurPos], &m_pSpatialPic[kiDidx][iCurTid]); } return 0;} /** SingleLayerPreprocess: down sampling if applicable* @return: exact number of spatial layers need to encoder indeed*/int32_t CWelsPreProcess::SingleLayerPreprocess (sWelsEncCtx* pCtx, const SSourcePicture* kpSrc, Scaled_Picture* pScaledPicture) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; int8_t iDependencyId = pSvcParam->iSpatialLayerNum - 1; int32_t iPicturePos = m_uiSpatialLayersInTemporal[iDependencyId] - 1; SPicture* pSrcPic = NULL; // large SPicture* pDstPic = NULL; // small SSpatialLayerConfig* pDlayerParam = NULL; SSpatialLayerInternal* pDlayerParamInternal = NULL; int32_t iSpatialNum = 0; int32_t iSrcWidth = 0; int32_t iSrcHeight = 0; int32_t iTargetWidth = 0; int32_t iTargetHeight = 0; int32_t iTemporalId = 0; int32_t iActualSpatialLayerNum = 0; pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId]; pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId]; iTargetWidth = pDlayerParam->iVideoWidth; iTargetHeight = pDlayerParam->iVideoHeight; iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)]; iSrcWidth = pSvcParam->SUsedPicRect.iWidth; iSrcHeight = pSvcParam->SUsedPicRect.iHeight; pSrcPic = pScaledPicture->pScaledInputPicture ? pScaledPicture->pScaledInputPicture : m_pSpatialPic[iDependencyId][iPicturePos]; WelsMoveMemoryWrapper (pSvcParam, pSrcPic, kpSrc, iSrcWidth, iSrcHeight); if (pSvcParam->bEnableDenoise) BilateralDenoising (pSrcPic, iSrcWidth, iSrcHeight); // different scaling in between input picture and dst highest spatial picture. int32_t iShrinkWidth = iSrcWidth; int32_t iShrinkHeight = iSrcHeight; pDstPic = pSrcPic; if (pScaledPicture->pScaledInputPicture) { // for highest downsampling pDstPic = m_pSpatialPic[iDependencyId][iPicturePos]; iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; } DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight, false); if (pSvcParam->bEnableSceneChangeDetect && !pCtx->pVaa->bIdrPeriodFlag) { if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) { pCtx->pVaa->eSceneChangeIdc = (pCtx->bEncCurFrmAsIdrFlag ? LARGE_CHANGED_SCENE : DetectSceneChangeScreen (pCtx, pDstPic)); pCtx->pVaa->bSceneChangeFlag = (LARGE_CHANGED_SCENE == pCtx->pVaa->eSceneChangeIdc); } else { if ((!pCtx->bEncCurFrmAsIdrFlag) && ! (pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1))) { SPicture* pRefPic = pCtx->pLtr[iDependencyId].bReceivedT0LostFlag ? m_pSpatialPic[iDependencyId][m_uiSpatialLayersInTemporal[iDependencyId] + pCtx->pVaa->uiValidLongTermPicIdx] : m_pLastSpatialPicture[iDependencyId][0]; pCtx->pVaa->bSceneChangeFlag = DetectSceneChange (pDstPic, pRefPic); } } } for (int32_t i = 0; i < pSvcParam->iSpatialLayerNum; i++) { if (pSvcParam->sDependencyLayers[i].uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)] != INVALID_TEMPORAL_ID) { ++ iActualSpatialLayerNum; } } if (iTemporalId != INVALID_TEMPORAL_ID) { WelsUpdateSpatialIdxMap (pCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); ++ iSpatialNum; -- iActualSpatialLayerNum; } m_pLastSpatialPicture[iDependencyId][1] = m_pSpatialPic[iDependencyId][iPicturePos]; -- iDependencyId; // generate other spacial layer // pSrc is // -- padded input pic, if downsample should be applied to generate highest layer, [if] block above // -- highest layer, if no downsampling, [else] block above if (pSvcParam->iSpatialLayerNum > 1) { while (iDependencyId >= 0) { pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId]; pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId]; iTargetWidth = pDlayerParam->iVideoWidth; iTargetHeight = pDlayerParam->iVideoHeight; iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)]; iPicturePos = m_uiSpatialLayersInTemporal[iDependencyId] - 1; // NOT work for CGS, FIXME // spatial layer is able to encode indeed if ((iTemporalId != INVALID_TEMPORAL_ID)) { // down sampling performed pDstPic = m_pSpatialPic[iDependencyId][iPicturePos]; // small iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight, true); WelsUpdateSpatialIdxMap (pCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); -- iActualSpatialLayerNum; ++ iSpatialNum; m_pLastSpatialPicture[iDependencyId][1] = m_pSpatialPic[iDependencyId][iPicturePos]; } -- iDependencyId; } } return iSpatialNum;} /*! * \brief Whether input picture need be scaled? */bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture) { const int32_t kiInputPicWidth = pParam->SUsedPicRect.iWidth; const int32_t kiInputPicHeight = pParam->SUsedPicRect.iHeight; const int32_t kiDstPicWidth = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualWidth; const int32_t kiDstPicHeight = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualHeight; bool bNeedDownsampling = true; int32_t iSpatialIdx = pParam->iSpatialLayerNum - 1; if (kiDstPicWidth >= kiInputPicWidth && kiDstPicHeight >= kiInputPicHeight) { iSpatialIdx --; // highest D layer do not need downsampling bNeedDownsampling = false; } for (; iSpatialIdx >= 0; iSpatialIdx --) { SSpatialLayerInternal* pCurLayer = &pParam->sDependencyLayers[iSpatialIdx]; int32_t iCurDstWidth = pCurLayer->iActualWidth; int32_t iCurDstHeight = pCurLayer->iActualHeight; int32_t iInputWidthXDstHeight = kiInputPicWidth * iCurDstHeight; int32_t iInputHeightXDstWidth = kiInputPicHeight * iCurDstWidth; if (iInputWidthXDstHeight > iInputHeightXDstWidth) { pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iCurDstWidth, 4); pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iInputHeightXDstWidth / kiInputPicWidth, 4); } else { pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iInputWidthXDstHeight / kiInputPicHeight, 4); pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iCurDstHeight, 4); } } return bNeedDownsampling;} int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) { bool bInputPicNeedScaling = JudgeNeedOfScaling (pParam, pScaledPicture); if (bInputPicNeedScaling) { pScaledPicture->pScaledInputPicture = AllocPicture (pMemoryAlign, pParam->SUsedPicRect.iWidth, pParam->SUsedPicRect.iHeight, false, 0); if (pScaledPicture->pScaledInputPicture == NULL) return -1; } return 0;} void FreeScaledPic (Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) { if (pScaledPicture->pScaledInputPicture) { FreePicture (pMemoryAlign, &pScaledPicture->pScaledInputPicture); pScaledPicture->pScaledInputPicture = NULL; }} int32_t CWelsPreProcess::InitLastSpatialPictures (sWelsEncCtx* pCtx) { SWelsSvcCodingParam* pParam = pCtx->pSvcParam; const int32_t kiDlayerCount = pParam->iSpatialLayerNum; int32_t iDlayerIndex = 0; if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME) { for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) { m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL; } } else { for (; iDlayerIndex < kiDlayerCount; iDlayerIndex++) { const int32_t kiLayerInTemporal = m_uiSpatialLayersInTemporal[iDlayerIndex]; m_pLastSpatialPicture[iDlayerIndex][0] = m_pSpatialPic[iDlayerIndex][kiLayerInTemporal - 2]; m_pLastSpatialPicture[iDlayerIndex][1] = NULL; } for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) { m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL; } } return 0;}//*********************************************************************************************************/ int32_t CWelsPreProcess::ColorspaceConvert (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic, const SSourcePicture* kpSrc, const int32_t kiWidth, const int32_t kiHeight) { return 1; //not support yet} void CWelsPreProcess::BilateralDenoising (SPicture* pSrc, const int32_t kiWidth, const int32_t kiHeight) { int32_t iMethodIdx = METHOD_DENOISE; SPixMap sSrcPixMap; memset (&sSrcPixMap, 0, sizeof (sSrcPixMap)); sSrcPixMap.pPixel[0] = pSrc->pData[0]; sSrcPixMap.pPixel[1] = pSrc->pData[1]; sSrcPixMap.pPixel[2] = pSrc->pData[2]; sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits; sSrcPixMap.sRect.iRectWidth = kiWidth; sSrcPixMap.sRect.iRectHeight = kiHeight; sSrcPixMap.iStride[0] = pSrc->iLineSize[0]; sSrcPixMap.iStride[1] = pSrc->iLineSize[1];Lines 1–500 of 1352. Load more
/*! * \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. * */ #include "wels_preprocess.h" #include "picture_handle.h" #include "encoder_context.h" #include "utils.h" #include "encoder.h" namespace WelsEnc { //***** entry API declaration ************************************************************************// int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic, CMemoryAlign* pMemoryAlign); bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPic); void FreeScaledPic (Scaled_Picture* pScaledPic, CMemoryAlign* pMemoryAlign); void WelsMoveMemory_c (uint8_t* pDstY, uint8_t* pDstU, uint8_t* pDstV, int32_t iDstStrideY, int32_t iDstStrideUV, uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iSrcStrideY, int32_t iSrcStrideUV, int32_t iWidth, int32_t iHeight); //******* table definition ***********************************************************************// const uint8_t g_kuiRefTemporalIdx[MAX_TEMPORAL_LEVEL][MAX_GOP_SIZE] = { { 0, }, // 0 { 0, 0, }, // 1 { 0, 0, 0, 1, }, // 2 { 0, 0, 0, 2, 0, 1, 1, 2, }, // 3 }; const int32_t g_kiPixMapSizeInBits = sizeof (uint8_t) * 8; inline void WelsUpdateSpatialIdxMap (sWelsEncCtx* pEncCtx, int32_t iPos, SPicture* pPic, int32_t iDidx) { pEncCtx->sSpatialIndexMap[iPos].pSrc = pPic; pEncCtx->sSpatialIndexMap[iPos].iDid = iDidx; } /*************************************************************************** * * implement of the interface * ***************************************************************************/ CWelsPreProcess::CWelsPreProcess (sWelsEncCtx* pEncCtx) { m_pInterfaceVp = NULL; m_bInitDone = false; m_pEncCtx = pEncCtx; memset (&m_sScaledPicture, 0, sizeof (m_sScaledPicture)); memset (m_pSpatialPic, 0, sizeof (m_pSpatialPic)); memset (m_uiSpatialLayersInTemporal, 0, sizeof (m_uiSpatialLayersInTemporal)); memset (m_uiSpatialPicNum, 0, sizeof (m_uiSpatialPicNum)); } CWelsPreProcess::~CWelsPreProcess() { FreeScaledPic (&m_sScaledPicture, m_pEncCtx->pMemAlign); WelsPreprocessDestroy(); } int32_t CWelsPreProcess::WelsPreprocessCreate() { if (m_pInterfaceVp == NULL) { WelsCreateVpInterface ((void**) &m_pInterfaceVp, WELSVP_INTERFACE_VERION); if (!m_pInterfaceVp) goto exit; } else goto exit; return 0; exit: WelsPreprocessDestroy(); return 1; } int32_t CWelsPreProcess::WelsPreprocessDestroy() { WelsDestroyVpInterface (m_pInterfaceVp, WELSVP_INTERFACE_VERION); m_pInterfaceVp = NULL; return 0; } int32_t CWelsPreProcess::WelsPreprocessReset (sWelsEncCtx* pCtx) { int32_t iRet = -1; if (pCtx) { FreeScaledPic (&m_sScaledPicture, pCtx->pMemAlign); iRet = InitLastSpatialPictures (pCtx); iRet = WelsInitScaledPic (pCtx->pSvcParam, &m_sScaledPicture, pCtx->pMemAlign); } return iRet; } int32_t CWelsPreProcess::AllocSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam) { CMemoryAlign* pMa = pCtx->pMemAlign; const int32_t kiDlayerCount = pParam->iSpatialLayerNum; int32_t iDlayerIndex = 0; // spatial pictures iDlayerIndex = 0; do { const int32_t kiPicWidth = pParam->sSpatialLayers[iDlayerIndex].iVideoWidth; const int32_t kiPicHeight = pParam->sSpatialLayers[iDlayerIndex].iVideoHeight; const uint8_t kuiLayerInTemporal = 2 + WELS_MAX (pParam->sDependencyLayers[iDlayerIndex].iHighestTemporalId, 1); const uint8_t kuiRefNumInTemporal = kuiLayerInTemporal + pParam->iLTRRefNum; uint8_t i = 0; do { SPicture* pPic = AllocPicture (pMa, kiPicWidth, kiPicHeight, false, 0); WELS_VERIFY_RETURN_IF (1, (NULL == pPic)) m_pSpatialPic[iDlayerIndex][i] = pPic; ++ i; } while (i < kuiRefNumInTemporal); if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME) m_uiSpatialLayersInTemporal[iDlayerIndex] = 1; else m_uiSpatialLayersInTemporal[iDlayerIndex] = kuiLayerInTemporal; m_uiSpatialPicNum[iDlayerIndex] = kuiRefNumInTemporal; ++ iDlayerIndex; } while (iDlayerIndex < kiDlayerCount); return 0; } void CWelsPreProcess::FreeSpatialPictures (sWelsEncCtx* pCtx) { CMemoryAlign* pMa = pCtx->pMemAlign; int32_t j = 0; while (j < pCtx->pSvcParam->iSpatialLayerNum) { uint8_t i = 0; uint8_t uiRefNumInTemporal = m_uiSpatialPicNum[j]; while (i < uiRefNumInTemporal) { if (NULL != m_pSpatialPic[j][i]) { FreePicture (pMa, &m_pSpatialPic[j][i]); } ++ i; } m_uiSpatialLayersInTemporal[j] = 0; ++ j; } } int32_t CWelsPreProcess::BuildSpatialPicList (sWelsEncCtx* pCtx, const SSourcePicture* kpSrcPic) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; int32_t iSpatialNum = 0; if (!m_bInitDone) { if (WelsPreprocessCreate() != 0) return -1; //init source width and height pSvcParam->SUsedPicRect.iLeft = 0; pSvcParam->SUsedPicRect.iTop = 0; pSvcParam->SUsedPicRect.iWidth = ((kpSrcPic->iPicWidth >> 1) << 1); pSvcParam->SUsedPicRect.iHeight = ((kpSrcPic->iPicHeight >> 1) << 1); if (WelsPreprocessReset (pCtx) != 0) return -1; m_iAvaliableRefInSpatialPicList = pSvcParam->iNumRefFrame; m_bInitDone = true; } if (m_pInterfaceVp == NULL) return -1; pCtx->pVaa->bSceneChangeFlag = pCtx->pVaa->bIdrPeriodFlag = false; if (pSvcParam->uiIntraPeriod) pCtx->pVaa->bIdrPeriodFlag = (1 + pCtx->iFrameIndex >= (int32_t)pSvcParam->uiIntraPeriod) ? true : false; iSpatialNum = SingleLayerPreprocess (pCtx, kpSrcPic, &m_sScaledPicture); return iSpatialNum; } int32_t CWelsPreProcess::AnalyzeSpatialPic (sWelsEncCtx* pCtx, const int32_t kiDidx) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; bool bNeededMbAq = (pSvcParam->bEnableAdaptiveQuant && (pCtx->eSliceType == P_SLICE)); bool bCalculateBGD = (pCtx->eSliceType == P_SLICE && pSvcParam->bEnableBackgroundDetection); int32_t iCurTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] - 1; int32_t iRefTemporalIdx = (int32_t)g_kuiRefTemporalIdx[pSvcParam->iDecompStages][pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)]; if (pCtx->uiTemporalId == 0 && pCtx->pLtr[pCtx->uiDependencyId].bReceivedT0LostFlag) iRefTemporalIdx = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiValidLongTermPicIdx; SPicture* pCurPic = m_pSpatialPic[kiDidx][iCurTemporalIdx]; bool bCalculateVar = (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE); if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) { SVAAFrameInfoExt* pVaaExt = static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa); SRefInfoParam* BestRefCandidateParam = (pCtx->bCurFrameMarkedAsSceneLtr) ? (& (pVaaExt->sVaaLtrBestRefCandidate[0])) : (& (pVaaExt->sVaaStrBestRefCandidate[0])); SPicture* pRefPic = m_pSpatialPic[0][BestRefCandidateParam->iSrcListIdx]; VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, false, bCalculateVar, bCalculateBGD); if (pSvcParam->bEnableBackgroundDetection) { BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE); } if (bNeededMbAq) { AdaptiveQuantCalculation (pCtx->pVaa, pCurPic, pRefPic); } } else { SPicture* pRefPic = m_pSpatialPic[kiDidx][iRefTemporalIdx]; SPicture* pLastPic = m_pLastSpatialPicture[kiDidx][0]; bool bCalculateSQDiff = ((pLastPic->pData[0] == pRefPic->pData[0]) && bNeededMbAq); bool bCalculateVar = (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE); VaaCalculation (pCtx->pVaa, pCurPic, pRefPic, bCalculateSQDiff, bCalculateVar, bCalculateBGD); if (pSvcParam->bEnableBackgroundDetection) { BackgroundDetection (pCtx->pVaa, pCurPic, pRefPic, bCalculateBGD && pRefPic->iPictureType != I_SLICE); } if (bNeededMbAq) { SPicture* pCurPic = m_pLastSpatialPicture[kiDidx][1]; SPicture* pRefPic = m_pLastSpatialPicture[kiDidx][0]; AdaptiveQuantCalculation (pCtx->pVaa, pCurPic, pRefPic); } WelsExchangeSpatialPictures (&m_pLastSpatialPicture[kiDidx][1], &m_pLastSpatialPicture[kiDidx][0]); } return 0; } int32_t CWelsPreProcess::GetCurPicPosition(const int32_t kiDidx) { return (m_uiSpatialLayersInTemporal[kiDidx] - 1); } int32_t CWelsPreProcess::UpdateSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam, const int8_t iCurTid, const int32_t kiDidx) { if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) return 0; const int32_t kiCurPos = GetCurPicPosition(kiDidx); if (iCurTid < kiCurPos || pParam->iDecompStages == 0) { if ((iCurTid >= MAX_TEMPORAL_LEVEL) || (kiCurPos > MAX_TEMPORAL_LEVEL)) { InitLastSpatialPictures (pCtx); return 1; } if (pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid]) { const int32_t kiAvailableLtrPos = m_uiSpatialLayersInTemporal[kiDidx] + pCtx->pVaa->uiMarkLongTermPicIdx; WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiAvailableLtrPos], &m_pSpatialPic[kiDidx][iCurTid]); pCtx->bRefOfCurTidIsLtr[kiDidx][iCurTid] = false; } WelsExchangeSpatialPictures (&m_pSpatialPic[kiDidx][kiCurPos], &m_pSpatialPic[kiDidx][iCurTid]); } return 0; } /* * SingleLayerPreprocess: down sampling if applicable * @return: exact number of spatial layers need to encoder indeed */ int32_t CWelsPreProcess::SingleLayerPreprocess (sWelsEncCtx* pCtx, const SSourcePicture* kpSrc, Scaled_Picture* pScaledPicture) { SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam; int8_t iDependencyId = pSvcParam->iSpatialLayerNum - 1; int32_t iPicturePos = m_uiSpatialLayersInTemporal[iDependencyId] - 1; SPicture* pSrcPic = NULL; // large SPicture* pDstPic = NULL; // small SSpatialLayerConfig* pDlayerParam = NULL; SSpatialLayerInternal* pDlayerParamInternal = NULL; int32_t iSpatialNum = 0; int32_t iSrcWidth = 0; int32_t iSrcHeight = 0; int32_t iTargetWidth = 0; int32_t iTargetHeight = 0; int32_t iTemporalId = 0; int32_t iActualSpatialLayerNum = 0; pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId]; pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId]; iTargetWidth = pDlayerParam->iVideoWidth; iTargetHeight = pDlayerParam->iVideoHeight; iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)]; iSrcWidth = pSvcParam->SUsedPicRect.iWidth; iSrcHeight = pSvcParam->SUsedPicRect.iHeight; pSrcPic = pScaledPicture->pScaledInputPicture ? pScaledPicture->pScaledInputPicture : m_pSpatialPic[iDependencyId][iPicturePos]; WelsMoveMemoryWrapper (pSvcParam, pSrcPic, kpSrc, iSrcWidth, iSrcHeight); if (pSvcParam->bEnableDenoise) BilateralDenoising (pSrcPic, iSrcWidth, iSrcHeight); // different scaling in between input picture and dst highest spatial picture. int32_t iShrinkWidth = iSrcWidth; int32_t iShrinkHeight = iSrcHeight; pDstPic = pSrcPic; if (pScaledPicture->pScaledInputPicture) { // for highest downsampling pDstPic = m_pSpatialPic[iDependencyId][iPicturePos]; iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; } DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight, false); if (pSvcParam->bEnableSceneChangeDetect && !pCtx->pVaa->bIdrPeriodFlag) { if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) { pCtx->pVaa->eSceneChangeIdc = (pCtx->bEncCurFrmAsIdrFlag ? LARGE_CHANGED_SCENE : DetectSceneChangeScreen (pCtx, pDstPic)); pCtx->pVaa->bSceneChangeFlag = (LARGE_CHANGED_SCENE == pCtx->pVaa->eSceneChangeIdc); } else { if ((!pCtx->bEncCurFrmAsIdrFlag) && ! (pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1))) { SPicture* pRefPic = pCtx->pLtr[iDependencyId].bReceivedT0LostFlag ? m_pSpatialPic[iDependencyId][m_uiSpatialLayersInTemporal[iDependencyId] + pCtx->pVaa->uiValidLongTermPicIdx] : m_pLastSpatialPicture[iDependencyId][0]; pCtx->pVaa->bSceneChangeFlag = DetectSceneChange (pDstPic, pRefPic); } } } for (int32_t i = 0; i < pSvcParam->iSpatialLayerNum; i++) { if (pSvcParam->sDependencyLayers[i].uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)] != INVALID_TEMPORAL_ID) { ++ iActualSpatialLayerNum; } } if (iTemporalId != INVALID_TEMPORAL_ID) { WelsUpdateSpatialIdxMap (pCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); ++ iSpatialNum; -- iActualSpatialLayerNum; } m_pLastSpatialPicture[iDependencyId][1] = m_pSpatialPic[iDependencyId][iPicturePos]; -- iDependencyId; // generate other spacial layer // pSrc is // -- padded input pic, if downsample should be applied to generate highest layer, [if] block above // -- highest layer, if no downsampling, [else] block above if (pSvcParam->iSpatialLayerNum > 1) { while (iDependencyId >= 0) { pDlayerParamInternal = &pSvcParam->sDependencyLayers[iDependencyId]; pDlayerParam = &pSvcParam->sSpatialLayers[iDependencyId]; iTargetWidth = pDlayerParam->iVideoWidth; iTargetHeight = pDlayerParam->iVideoHeight; iTemporalId = pDlayerParamInternal->uiCodingIdx2TemporalId[pCtx->iCodingIndex & (pSvcParam->uiGopSize - 1)]; iPicturePos = m_uiSpatialLayersInTemporal[iDependencyId] - 1; // NOT work for CGS, FIXME // spatial layer is able to encode indeed if ((iTemporalId != INVALID_TEMPORAL_ID)) { // down sampling performed pDstPic = m_pSpatialPic[iDependencyId][iPicturePos]; // small iShrinkWidth = pScaledPicture->iScaledWidth[iDependencyId]; iShrinkHeight = pScaledPicture->iScaledHeight[iDependencyId]; DownsamplePadding (pSrcPic, pDstPic, iSrcWidth, iSrcHeight, iShrinkWidth, iShrinkHeight, iTargetWidth, iTargetHeight, true); WelsUpdateSpatialIdxMap (pCtx, iActualSpatialLayerNum - 1, pDstPic, iDependencyId); -- iActualSpatialLayerNum; ++ iSpatialNum; m_pLastSpatialPicture[iDependencyId][1] = m_pSpatialPic[iDependencyId][iPicturePos]; } -- iDependencyId; } } return iSpatialNum; } /*! * \brief Whether input picture need be scaled? */ bool JudgeNeedOfScaling (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture) { const int32_t kiInputPicWidth = pParam->SUsedPicRect.iWidth; const int32_t kiInputPicHeight = pParam->SUsedPicRect.iHeight; const int32_t kiDstPicWidth = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualWidth; const int32_t kiDstPicHeight = pParam->sDependencyLayers[pParam->iSpatialLayerNum - 1].iActualHeight; bool bNeedDownsampling = true; int32_t iSpatialIdx = pParam->iSpatialLayerNum - 1; if (kiDstPicWidth >= kiInputPicWidth && kiDstPicHeight >= kiInputPicHeight) { iSpatialIdx --; // highest D layer do not need downsampling bNeedDownsampling = false; } for (; iSpatialIdx >= 0; iSpatialIdx --) { SSpatialLayerInternal* pCurLayer = &pParam->sDependencyLayers[iSpatialIdx]; int32_t iCurDstWidth = pCurLayer->iActualWidth; int32_t iCurDstHeight = pCurLayer->iActualHeight; int32_t iInputWidthXDstHeight = kiInputPicWidth * iCurDstHeight; int32_t iInputHeightXDstWidth = kiInputPicHeight * iCurDstWidth; if (iInputWidthXDstHeight > iInputHeightXDstWidth) { pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iCurDstWidth, 4); pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iInputHeightXDstWidth / kiInputPicWidth, 4); } else { pScaledPicture->iScaledWidth[iSpatialIdx] = WELS_MAX (iInputWidthXDstHeight / kiInputPicHeight, 4); pScaledPicture->iScaledHeight[iSpatialIdx] = WELS_MAX (iCurDstHeight, 4); } } return bNeedDownsampling; } int32_t WelsInitScaledPic (SWelsSvcCodingParam* pParam, Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) { bool bInputPicNeedScaling = JudgeNeedOfScaling (pParam, pScaledPicture); if (bInputPicNeedScaling) { pScaledPicture->pScaledInputPicture = AllocPicture (pMemoryAlign, pParam->SUsedPicRect.iWidth, pParam->SUsedPicRect.iHeight, false, 0); if (pScaledPicture->pScaledInputPicture == NULL) return -1; } return 0; } void FreeScaledPic (Scaled_Picture* pScaledPicture, CMemoryAlign* pMemoryAlign) { if (pScaledPicture->pScaledInputPicture) { FreePicture (pMemoryAlign, &pScaledPicture->pScaledInputPicture); pScaledPicture->pScaledInputPicture = NULL; } } int32_t CWelsPreProcess::InitLastSpatialPictures (sWelsEncCtx* pCtx) { SWelsSvcCodingParam* pParam = pCtx->pSvcParam; const int32_t kiDlayerCount = pParam->iSpatialLayerNum; int32_t iDlayerIndex = 0; if (pParam->iUsageType == SCREEN_CONTENT_REAL_TIME) { for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) { m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL; } } else { for (; iDlayerIndex < kiDlayerCount; iDlayerIndex++) { const int32_t kiLayerInTemporal = m_uiSpatialLayersInTemporal[iDlayerIndex]; m_pLastSpatialPicture[iDlayerIndex][0] = m_pSpatialPic[iDlayerIndex][kiLayerInTemporal - 2]; m_pLastSpatialPicture[iDlayerIndex][1] = NULL; } for (; iDlayerIndex < MAX_DEPENDENCY_LAYER; iDlayerIndex++) { m_pLastSpatialPicture[iDlayerIndex][0] = m_pLastSpatialPicture[iDlayerIndex][1] = NULL; } } return 0; } //*********************************************************************************************************/ int32_t CWelsPreProcess::ColorspaceConvert (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic, const SSourcePicture* kpSrc, const int32_t kiWidth, const int32_t kiHeight) { return 1; //not support yet } void CWelsPreProcess::BilateralDenoising (SPicture* pSrc, const int32_t kiWidth, const int32_t kiHeight) { int32_t iMethodIdx = METHOD_DENOISE; SPixMap sSrcPixMap; memset (&sSrcPixMap, 0, sizeof (sSrcPixMap)); sSrcPixMap.pPixel[0] = pSrc->pData[0]; sSrcPixMap.pPixel[1] = pSrc->pData[1]; sSrcPixMap.pPixel[2] = pSrc->pData[2]; sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits; sSrcPixMap.sRect.iRectWidth = kiWidth; sSrcPixMap.sRect.iRectHeight = kiHeight; sSrcPixMap.iStride[0] = pSrc->iLineSize[0]; sSrcPixMap.iStride[1] = pSrc->iLineSize[1];