shithub: openh264

Download patch

ref: 15432d4fc51cff265cb57688178c4f9c424b7c32
parent: cf5edec5ae21423690c6a4aa16996a2d1c0e92c3
parent: 44640712f6466ec6b36ad47618c18cb7b39bd879
author: huili2 <huili2@cisco.com>
date: Mon May 5 11:56:31 EDT 2014

Merge pull request #787 from sijchen/fme_merge97

[Encoder ME] Add FME unit test

--- a/codec/encoder/core/inc/svc_motion_estimate.h
+++ b/codec/encoder/core/inc/svc_motion_estimate.h
@@ -127,6 +127,7 @@
 }SFeatureSearchOut;
 
 #define  COST_MVD(table, mx, my)  (table[mx] + table[my])
+extern const int32_t QStepx16ByQp[52];
 
 // Function definitions below
 
@@ -242,9 +243,9 @@
 
 #define FMESWITCH_DEFAULT_GOODFRAME_NUM (2)
 #define FME_DEFAULT_FEATURE_INDEX (0)
-void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef,
-                          SScreenBlockFeatureStorage* pScreenBlockFeatureStorage);
 
+void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef, uint16_t* pFeatureOfBlock,
+                          SScreenBlockFeatureStorage* pScreenBlockFeatureStorage);
 void UpdateFMESwitch(SDqLayer* pCurLayer);
 void UpdateFMESwitchNull(SDqLayer* pCurLayer);
 
@@ -251,8 +252,7 @@
 //inline functions
 inline void SetMvWithinIntegerMvRange( const int32_t kiMbWidth, const int32_t kiMbHeight, const int32_t kiMbX, const int32_t kiMbY,
                         const int32_t kiMaxMvRange,
-                        SMVUnitXY* pMvMin, SMVUnitXY* pMvMax)
-{
+                        SMVUnitXY* pMvMin, SMVUnitXY* pMvMax) {
   pMvMin->iMvX = WELS_MAX(-1*((kiMbX + 1)<<4) + INTPEL_NEEDED_MARGIN, -1*kiMaxMvRange);
   pMvMin->iMvY = WELS_MAX(-1*((kiMbY + 1)<<4) + INTPEL_NEEDED_MARGIN, -1*kiMaxMvRange);
   pMvMax->iMvX = WELS_MIN( ((kiMbWidth - kiMbX)<<4) - INTPEL_NEEDED_MARGIN, kiMaxMvRange);
@@ -259,19 +259,16 @@
   pMvMax->iMvY = WELS_MIN( ((kiMbHeight - kiMbY)<<4) - INTPEL_NEEDED_MARGIN, kiMaxMvRange);
 }
 
-inline bool CheckMvInRange( const int16_t kiCurrentMv, const int16_t kiMinMv, const int16_t kiMaxMv )
-{
+inline bool CheckMvInRange( const int16_t kiCurrentMv, const int16_t kiMinMv, const int16_t kiMaxMv ) {
   return ((kiCurrentMv >= kiMinMv) && (kiCurrentMv < kiMaxMv));
 }
-inline bool CheckMvInRange( const SMVUnitXY ksCurrentMv, const SMVUnitXY ksMinMv, const SMVUnitXY ksMaxMv )
-{
+inline bool CheckMvInRange( const SMVUnitXY ksCurrentMv, const SMVUnitXY ksMinMv, const SMVUnitXY ksMaxMv ) {
   return (CheckMvInRange(ksCurrentMv.iMvX, ksMinMv.iMvX, ksMaxMv.iMvX)
     && CheckMvInRange(ksCurrentMv.iMvY, ksMinMv.iMvY, ksMaxMv.iMvY));
 }
 //FME switch related
 inline bool CalcFMESwitchFlag(const uint8_t uiFMEGoodFrameCount, const int32_t iHighFreMbPrecentage,
-       const int32_t iAvgMbSAD, const bool bScrollingDetected )
-{
+       const int32_t iAvgMbSAD, const bool bScrollingDetected ) {
   return ( bScrollingDetected ||( uiFMEGoodFrameCount>0 && iAvgMbSAD > FMESWITCH_MBSAD_THRESHOLD ) );
   //TODO: add the logic of iHighFreMbPrecentage
   //return ( iHighFreMbPrecentage > 2
--- a/codec/encoder/core/src/encoder_ext.cpp
+++ b/codec/encoder/core/src/encoder_ext.cpp
@@ -2446,7 +2446,7 @@
       pFuncList->pfInterFineMd = WelsMdInterFinePartition;
     }
   }
-  
+
   return;
   //to init at each frame will be needed when dealing with hybrid content (camera+screen)
   if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
@@ -2467,9 +2467,8 @@
         pFeatureSearchPreparation->pRefBlockFeature = pScreenBlockFeatureStorage;
         if (pFeatureSearchPreparation->bFMESwitchFlag
           && !pScreenBlockFeatureStorage->bRefBlockFeatureCalculated) {
-            pScreenBlockFeatureStorage->pFeatureOfBlockPointer = pFeatureSearchPreparation->pFeatureOfBlock;
             //TODO: use ORIGIN of reference when preprocessing is ready
-            PerformFMEPreprocess( pFuncList, pCurLayer->pRefPic, pScreenBlockFeatureStorage );
+            PerformFMEPreprocess( pFuncList, pCurLayer->pRefPic,pFeatureSearchPreparation->pFeatureOfBlock,pScreenBlockFeatureStorage);
         }
 
         //assign ME pointer
--- a/codec/encoder/core/src/svc_motion_estimate.cpp
+++ b/codec/encoder/core/src/svc_motion_estimate.cpp
@@ -57,14 +57,12 @@
     2560, 2816, 3328, 3584     /* 48~51 */
 };
 
-static inline void UpdateMeResults( const SMVUnitXY ksBestMv, const uint32_t kiBestSadCost, uint8_t* pRef, SWelsME * pMe )
-{
+static inline void UpdateMeResults( const SMVUnitXY ksBestMv, const uint32_t kiBestSadCost, uint8_t* pRef, SWelsME * pMe ) {
   pMe->sMv = ksBestMv;
   pMe->pRefMb = pRef;
   pMe->uiSadCost = kiBestSadCost;
 }
-static inline void MeEndIntepelSearch( SWelsME * pMe )
-{
+static inline void MeEndIntepelSearch( SWelsME * pMe ) {
     /* -> qpel mv */
     pMe->sMv.iMvX <<= 2;
     pMe->sMv.iMvY <<= 2;
@@ -597,14 +595,20 @@
 }
 int32_t ReleaseScreenBlockFeatureStorage( CMemoryAlign *pMa, SScreenBlockFeatureStorage* pScreenBlockFeatureStorage ) {
   if ( pMa && pScreenBlockFeatureStorage ) {
-    pMa->WelsFree( pScreenBlockFeatureStorage->pTimesOfFeatureValue, "pScreenBlockFeatureStorage->pTimesOfFeatureValue");
-    pScreenBlockFeatureStorage->pTimesOfFeatureValue=NULL;
+    if (pScreenBlockFeatureStorage->pTimesOfFeatureValue) {
+      pMa->WelsFree( pScreenBlockFeatureStorage->pTimesOfFeatureValue, "pScreenBlockFeatureStorage->pTimesOfFeatureValue");
+      pScreenBlockFeatureStorage->pTimesOfFeatureValue=NULL;
+    }
 
-    pMa->WelsFree( pScreenBlockFeatureStorage->pLocationOfFeature, "pScreenBlockFeatureStorage->pLocationOfFeature");
-    pScreenBlockFeatureStorage->pLocationOfFeature=NULL;
+    if (pScreenBlockFeatureStorage->pLocationOfFeature) {
+      pMa->WelsFree( pScreenBlockFeatureStorage->pLocationOfFeature, "pScreenBlockFeatureStorage->pLocationOfFeature");
+      pScreenBlockFeatureStorage->pLocationOfFeature=NULL;
+    }
 
-    pMa->WelsFree( pScreenBlockFeatureStorage->pLocationPointer, "pScreenBlockFeatureStorage->pLocationPointer");
-    pScreenBlockFeatureStorage->pLocationPointer=NULL;
+    if (pScreenBlockFeatureStorage->pLocationPointer) {
+      pMa->WelsFree( pScreenBlockFeatureStorage->pLocationPointer, "pScreenBlockFeatureStorage->pLocationPointer");
+      pScreenBlockFeatureStorage->pLocationPointer=NULL;
+    }
 
     return ENC_RETURN_SUCCESS;
   }
@@ -724,8 +728,10 @@
   FillQpelLocationByFeatureValue_c(pFeatureOfBlock, iWidth, kiHeight, pFeatureValuePointerList);
 }
 
-void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef,
-                          SScreenBlockFeatureStorage* pScreenBlockFeatureStorage) {
+void PerformFMEPreprocess( SWelsFuncPtrList *pFunc, SPicture* pRef, uint16_t*	pFeatureOfBlock,
+                          SScreenBlockFeatureStorage* pScreenBlockFeatureStorage)
+{
+    pScreenBlockFeatureStorage->pFeatureOfBlockPointer = pFeatureOfBlock;
     CalculateFeatureOfBlock(pFunc, pRef, pScreenBlockFeatureStorage );
     pScreenBlockFeatureStorage->bRefBlockFeatureCalculated = true;
 
--- a/codec/encoder/core/src/wels_preprocess.cpp
+++ b/codec/encoder/core/src/wels_preprocess.cpp
@@ -1,1197 +1,1197 @@
-/*!
- * \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 WelsSVCEnc {
-
-#define WelsSafeDelete(p) if(p){ delete (p); (p) = NULL; }
-
-
-//***** 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);
-
-//******* 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) {
-    CreateVpInterface ((void**) &m_pInterfaceVp, WELSVP_INTERFACE_VERION);
-    if (!m_pInterfaceVp)
-      goto exit;
-  } else
-    goto exit;
-
-  return 0;
-
-exit:
-  WelsPreprocessDestroy();
-  return 1;
-}
-
-int32_t CWelsPreProcess::WelsPreprocessDestroy() {
-  DestroyVpInterface (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->sDependencyLayers[iDlayerIndex].iFrameWidth;
-    const int32_t kiPicHeight   = pParam->sDependencyLayers[iDlayerIndex].iFrameHeight;
-    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;
-    if (WelsPreprocessReset (pCtx) != 0)
-      return -1;
-
-    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 = & (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);
-    }
-    AnalyzePictureComplexity (pCtx, pCurPic, pRefPic, kiDidx, bCalculateBGD);
-    WelsExchangeSpatialPictures (&m_pLastSpatialPicture[kiDidx][1], &m_pLastSpatialPicture[kiDidx][0]);
-  }
-  return 0;
-}
-
-int32_t CWelsPreProcess::UpdateSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam,
-    const int8_t iCurTid, const int32_t d_idx) {
-  if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME)
-    return 0;
-  if (iCurTid < m_uiSpatialLayersInTemporal[d_idx] - 1 || pParam->iDecompStages == 0) {
-    if ((iCurTid >= MAX_TEMPORAL_LEVEL) || (m_uiSpatialLayersInTemporal[d_idx] - 1 > MAX_TEMPORAL_LEVEL)) {
-      InitLastSpatialPictures (pCtx);
-      return 1;
-    }
-    if (pParam->bEnableLongTermReference && pCtx->bLongTermRefFlag[d_idx][iCurTid]) {
-      SPicture* tmp	= m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] + pCtx->pVaa->uiMarkLongTermPicIdx];
-      m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] + pCtx->pVaa->uiMarkLongTermPicIdx] =
-        m_pSpatialPic[d_idx][iCurTid];
-      m_pSpatialPic[d_idx][iCurTid] = m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1];
-      m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1] = tmp;
-      pCtx->bLongTermRefFlag[d_idx][iCurTid] = false;
-    } else {
-      WelsExchangeSpatialPictures (&m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1],
-                                   &m_pSpatialPic[d_idx][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
-  SDLayerParam* pDlayerParam					= 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;
-
-  pDlayerParam = &pSvcParam->sDependencyLayers[iDependencyId];
-  iTargetWidth	  = pDlayerParam->iFrameWidth;
-  iTargetHeight  = pDlayerParam->iFrameHeight;
-  iTemporalId    = pDlayerParam->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);
-
-  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) {
-      pDlayerParam			= &pSvcParam->sDependencyLayers[iDependencyId];
-      iTargetWidth	= pDlayerParam->iFrameWidth;
-      iTargetHeight	= pDlayerParam->iFrameHeight;
-      iTemporalId = pDlayerParam->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);
-
-        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 --) {
-    SDLayerParam* 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] = iCurDstWidth;
-      pScaledPicture->iScaledHeight[iSpatialIdx] = iInputHeightXDstWidth / kiInputPicWidth;
-    } else {
-      pScaledPicture->iScaledWidth[iSpatialIdx] = iInputWidthXDstHeight / kiInputPicHeight;
-      pScaledPicture->iScaledHeight[iSpatialIdx] = iCurDstHeight;
-    }
-  }
-
-  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;
-
-  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];
-  sSrcPixMap.iStride[2] = pSrc->iLineSize[2];
-  sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
-
-  m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, NULL);
-}
-
-bool CWelsPreProcess::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) {
-  bool bSceneChangeFlag = false;
-  int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION_VIDEO;
-  SSceneChangeResult sSceneChangeDetectResult = { SIMILAR_SCENE };
-  SPixMap sSrcPixMap;
-  SPixMap sRefPixMap;
-  memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
-  memset (&sRefPixMap, 0, sizeof (sRefPixMap));
-  sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
-  sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-  sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
-  sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
-  sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
-  sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
-
-
-  sRefPixMap.pPixel[0] = pRefPicture->pData[0];
-  sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-  sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
-  sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
-  sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
-  sRefPixMap.eFormat = VIDEO_FORMAT_I420;
-
-  int32_t iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
-  if (iRet == 0) {
-    m_pInterfaceVp->Get (iMethodIdx, (void*)&sSceneChangeDetectResult);
-    bSceneChangeFlag = (sSceneChangeDetectResult.eSceneChangeIdc == LARGE_CHANGED_SCENE) ? true : false;
-  }
-
-  return bSceneChangeFlag;
-}
-
-int32_t CWelsPreProcess::DownsamplePadding (SPicture* pSrc, SPicture* pDstPic,  int32_t iSrcWidth, int32_t iSrcHeight,
-    int32_t iShrinkWidth, int32_t iShrinkHeight, int32_t iTargetWidth, int32_t iTargetHeight) {
-  int32_t iRet = 0;
-  SPixMap sSrcPixMap;
-  SPixMap sDstPicMap;
-  memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
-  memset (&sDstPicMap, 0, sizeof (sDstPicMap));
-  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  = iSrcWidth;
-  sSrcPixMap.sRect.iRectHeight = iSrcHeight;
-  sSrcPixMap.iStride[0]  = pSrc->iLineSize[0];
-  sSrcPixMap.iStride[1]  = pSrc->iLineSize[1];
-  sSrcPixMap.iStride[2]  = pSrc->iLineSize[2];
-  sSrcPixMap.eFormat     = VIDEO_FORMAT_I420;
-
-  if (iSrcWidth != iShrinkWidth || iSrcHeight != iShrinkHeight) {
-    int32_t iMethodIdx = METHOD_DOWNSAMPLE;
-    sDstPicMap.pPixel[0]   = pDstPic->pData[0];
-    sDstPicMap.pPixel[1]   = pDstPic->pData[1];
-    sDstPicMap.pPixel[2]   = pDstPic->pData[2];
-    sDstPicMap.iSizeInBits = g_kiPixMapSizeInBits;
-    sDstPicMap.sRect.iRectWidth  = iShrinkWidth;
-    sDstPicMap.sRect.iRectHeight = iShrinkHeight;
-    sDstPicMap.iStride[0]  = pDstPic->iLineSize[0];
-    sDstPicMap.iStride[1]  = pDstPic->iLineSize[1];
-    sDstPicMap.iStride[2]  = pDstPic->iLineSize[2];
-    sDstPicMap.eFormat     = VIDEO_FORMAT_I420;
-
-    iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sDstPicMap);
-  } else {
-    memcpy (&sDstPicMap, &sSrcPixMap, sizeof (sDstPicMap));	// confirmed_safe_unsafe_usage
-  }
-
-  // get rid of odd line
-  iShrinkWidth -= (iShrinkWidth & 1);
-  iShrinkHeight -= (iShrinkHeight & 1);
-  Padding ((uint8_t*)sDstPicMap.pPixel[0], (uint8_t*)sDstPicMap.pPixel[1], (uint8_t*)sDstPicMap.pPixel[2],
-           sDstPicMap.iStride[0], sDstPicMap.iStride[1],	iShrinkWidth, iTargetWidth, iShrinkHeight, iTargetHeight);
-
-  return iRet;
-}
-
-//*********************************************************************************************************/
-void CWelsPreProcess::VaaCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
-                                      bool bCalculateSQDiff, bool bCalculateVar, bool bCalculateBGD) {
-  pVaaInfo->sVaaCalcInfo.pCurY = pCurPicture->pData[0];
-  pVaaInfo->sVaaCalcInfo.pRefY = pRefPicture->pData[0];
-  {
-    int32_t iMethodIdx = METHOD_VAA_STATISTICS;
-    SPixMap sCurPixMap;
-    SPixMap sRefPixMap;
-    memset (&sCurPixMap, 0, sizeof (sCurPixMap));
-    memset (&sRefPixMap, 0, sizeof (sRefPixMap));
-    SVAACalcParam calc_param = {0};
-
-    sCurPixMap.pPixel[0] = pCurPicture->pData[0];
-    sCurPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-    sCurPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
-    sCurPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
-    sCurPixMap.iStride[0] = pCurPicture->iLineSize[0];
-    sCurPixMap.eFormat = VIDEO_FORMAT_I420;
-
-    sRefPixMap.pPixel[0] = pRefPicture->pData[0];
-    sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-    sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
-    sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
-    sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
-    sRefPixMap.eFormat = VIDEO_FORMAT_I420;
-
-    calc_param.iCalcVar	= bCalculateVar;
-    calc_param.iCalcBgd	= bCalculateBGD;
-    calc_param.iCalcSsd	= bCalculateSQDiff;
-    calc_param.pCalcResult = &pVaaInfo->sVaaCalcInfo;
-
-    m_pInterfaceVp->Set (iMethodIdx, &calc_param);
-    m_pInterfaceVp->Process (iMethodIdx, &sCurPixMap, &sRefPixMap);
-  }
-}
-
-void CWelsPreProcess::BackgroundDetection (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
-    bool bDetectFlag) {
-  if (bDetectFlag) {
-    pVaaInfo->iPicWidth     = pCurPicture->iWidthInPixel;
-    pVaaInfo->iPicHeight    = pCurPicture->iHeightInPixel;
-
-    pVaaInfo->iPicStride	= pCurPicture->iLineSize[0];
-    pVaaInfo->iPicStrideUV	= pCurPicture->iLineSize[1];
-    pVaaInfo->pCurY			= pCurPicture->pData[0];
-    pVaaInfo->pRefY			= pRefPicture->pData[0];
-    pVaaInfo->pCurU			= pCurPicture->pData[1];
-    pVaaInfo->pRefU			= pRefPicture->pData[1];
-    pVaaInfo->pCurV			= pCurPicture->pData[2];
-    pVaaInfo->pRefV			= pRefPicture->pData[2];
-
-    int32_t iMethodIdx = METHOD_BACKGROUND_DETECTION;
-    SPixMap sSrcPixMap;
-    SPixMap sRefPixMap;
-    memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
-    memset (&sRefPixMap, 0, sizeof (sRefPixMap));
-    SBGDInterface BGDParam = {0};
-
-    sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
-    sSrcPixMap.pPixel[1] = pCurPicture->pData[1];
-    sSrcPixMap.pPixel[2] = pCurPicture->pData[2];
-    sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-    sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
-    sSrcPixMap.iStride[1] = pCurPicture->iLineSize[1];
-    sSrcPixMap.iStride[2] = pCurPicture->iLineSize[2];
-    sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
-    sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
-    sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
-
-    sRefPixMap.pPixel[0] = pRefPicture->pData[0];
-    sRefPixMap.pPixel[1] = pRefPicture->pData[1];
-    sRefPixMap.pPixel[2] = pRefPicture->pData[2];
-    sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-    sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
-    sRefPixMap.iStride[1] = pRefPicture->iLineSize[1];
-    sRefPixMap.iStride[2] = pRefPicture->iLineSize[2];
-    sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
-    sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
-    sRefPixMap.eFormat = VIDEO_FORMAT_I420;
-
-    BGDParam.pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
-    BGDParam.pCalcRes = & (pVaaInfo->sVaaCalcInfo);
-    m_pInterfaceVp->Set (iMethodIdx, (void*)&BGDParam);
-    m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
-  } else {
-    int32_t	iPicWidthInMb	= (pCurPicture->iWidthInPixel + 15) >> 4;
-    int32_t	iPicHeightInMb = (pCurPicture->iHeightInPixel + 15) >> 4;
-    memset (pVaaInfo->pVaaBackgroundMbFlag, 0, iPicWidthInMb * iPicHeightInMb);
-  }
-}
-
-void CWelsPreProcess::AdaptiveQuantCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture) {
-  pVaaInfo->sAdaptiveQuantParam.pCalcResult = & (pVaaInfo->sVaaCalcInfo);
-  pVaaInfo->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp = 0;
-
-  {
-    int32_t iMethodIdx = METHOD_ADAPTIVE_QUANT;
-    SPixMap pSrc;
-    SPixMap pRef;
-    memset (&pSrc, 0, sizeof (pSrc));
-    memset (&pRef, 0, sizeof (pRef));
-    int32_t iRet = 0;
-
-    pSrc.pPixel[0] = pCurPicture->pData[0];
-    pSrc.iSizeInBits = g_kiPixMapSizeInBits;
-    pSrc.iStride[0] = pCurPicture->iLineSize[0];
-    pSrc.sRect.iRectWidth = pCurPicture->iWidthInPixel;
-    pSrc.sRect.iRectHeight = pCurPicture->iHeightInPixel;
-    pSrc.eFormat = VIDEO_FORMAT_I420;
-
-    pRef.pPixel[0] = pRefPicture->pData[0];
-    pRef.iSizeInBits = g_kiPixMapSizeInBits;
-    pRef.iStride[0] = pRefPicture->iLineSize[0];
-    pRef.sRect.iRectWidth = pRefPicture->iWidthInPixel;
-    pRef.sRect.iRectHeight = pRefPicture->iHeightInPixel;
-    pRef.eFormat = VIDEO_FORMAT_I420;
-
-    iRet = m_pInterfaceVp->Set (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
-    iRet = m_pInterfaceVp->Process (iMethodIdx, &pSrc, &pRef);
-    if (iRet == 0)
-      m_pInterfaceVp->Get (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
-  }
-}
-
-void CWelsPreProcess::SetRefMbType (sWelsEncCtx* pCtx, uint32_t** pRefMbTypeArray, int32_t iRefPicType) {
-  const uint8_t uiTid	    = pCtx->uiTemporalId;
-  const uint8_t uiDid       = pCtx->uiDependencyId;
-  SRefList* pRefPicLlist    = pCtx->ppRefPicListExt[uiDid];
-  SLTRState* pLtr	    = &pCtx->pLtr[uiDid];
-  uint8_t i							= 0;
-
-  if (pCtx->pSvcParam->bEnableLongTermReference && pLtr->bReceivedT0LostFlag && uiTid == 0) {
-    for (i = 0; i < pRefPicLlist->uiLongRefCount; i++) {
-      SPicture* pRef = pRefPicLlist->pLongRefList[i];
-      if (pRef != NULL && pRef->uiRecieveConfirmed == 1/*RECIEVE_SUCCESS*/) {
-        *pRefMbTypeArray = pRef->uiRefMbType;
-        break;
-      }
-    }
-  } else {
-    for (i = 0; i < pRefPicLlist->uiShortRefCount; i++) {
-      SPicture* pRef = pRefPicLlist->pShortRefList[i];
-      if (pRef != NULL && pRef->bUsedAsRef && pRef->iFramePoc >= 0 && pRef->uiTemporalId <= uiTid) {
-        *pRefMbTypeArray = pRef->uiRefMbType;
-        break;
-      }
-    }
-  }
-}
-
-
-void CWelsPreProcess::AnalyzePictureComplexity (sWelsEncCtx* pCtx, SPicture* pCurPicture, SPicture* pRefPicture,
-    const int32_t kiDependencyId, const bool bCalculateBGD) {
-  SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
-  int32_t iComplexityAnalysisMode = 0;
-
-  if (pSvcParam->iRCMode == RC_OFF_MODE)
-    return;
-  if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
-    SVAAFrameInfoExt* pVaaExt		= static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
-    SComplexityAnalysisScreenParam* sComplexityAnalysisParam	= &pVaaExt->sComplexityScreenParam;
-    SWelsSvcRc* pWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
-
-    if (pCtx->eSliceType == P_SLICE)
-      iComplexityAnalysisMode = GOM_SAD;
-    else if (pCtx->eSliceType == I_SLICE)
-      iComplexityAnalysisMode = GOM_VAR;
-    else
-      return;
-
-    memset (pWelsSvcRc->pGomForegroundBlockNum, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
-    memset (pWelsSvcRc->pCurrentFrameGomSad, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
-
-    sComplexityAnalysisParam->iFrameComplexity = 0;
-    sComplexityAnalysisParam->pGomComplexity = pWelsSvcRc->pCurrentFrameGomSad;
-    sComplexityAnalysisParam->iGomNumInFrame = pWelsSvcRc->iGomSize;
-    sComplexityAnalysisParam->iIdrFlag = (pCtx->eSliceType == I_SLICE);
-    sComplexityAnalysisParam->iMbRowInGom = GOM_H_SCC;
-    sComplexityAnalysisParam->sScrollResult.bScrollDetectFlag = false;
-    sComplexityAnalysisParam->sScrollResult.iScrollMvX = 0;
-    sComplexityAnalysisParam->sScrollResult.iScrollMvY = 0;
-
-    const int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS_SCREEN;
-    SPixMap sSrcPixMap;
-    SPixMap sRefPixMap;
-    memset (&sSrcPixMap, 0, sizeof (SPixMap));
-    memset (&sRefPixMap, 0, sizeof (SPixMap));
-    int32_t iRet = 0;
-
-    sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
-    sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-    sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
-    sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
-    sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
-    sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
-
-    if (pRefPicture != NULL) {
-      sRefPixMap.pPixel[0] = pRefPicture->pData[0];
-      sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-      sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
-      sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
-      sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
-      sRefPixMap.eFormat = VIDEO_FORMAT_I420;
-    }
-
-    iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
-    iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
-    if (iRet == 0)
-      m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
-
-  } else {
-    SVAAFrameInfo* pVaaInfo	 = pCtx->pVaa;
-    SComplexityAnalysisParam* sComplexityAnalysisParam = & (pVaaInfo->sComplexityAnalysisParam);
-    SWelsSvcRc* SWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
-
-    if (pSvcParam->iRCMode == RC_QUALITY_MODE && pCtx->eSliceType == P_SLICE) {
-      iComplexityAnalysisMode = FRAME_SAD;
-    } else if (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == P_SLICE) {
-      iComplexityAnalysisMode = GOM_SAD;
-    } else if (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE) {
-      iComplexityAnalysisMode = GOM_VAR;
-    } else {
-      return;
-    }
-    sComplexityAnalysisParam->iComplexityAnalysisMode = iComplexityAnalysisMode;
-    sComplexityAnalysisParam->pCalcResult = & (pVaaInfo->sVaaCalcInfo);
-    sComplexityAnalysisParam->pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
-    SetRefMbType (pCtx, & (sComplexityAnalysisParam->uiRefMbType), pRefPicture->iPictureType);
-    sComplexityAnalysisParam->iCalcBgd = bCalculateBGD;
-    sComplexityAnalysisParam->iFrameComplexity = 0;
-
-    memset (SWelsSvcRc->pGomForegroundBlockNum, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
-    if (iComplexityAnalysisMode != FRAME_SAD)
-      memset (SWelsSvcRc->pCurrentFrameGomSad, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
-
-    sComplexityAnalysisParam->pGomComplexity = SWelsSvcRc->pCurrentFrameGomSad;
-    sComplexityAnalysisParam->pGomForegroundBlockNum = SWelsSvcRc->pGomForegroundBlockNum;
-    sComplexityAnalysisParam->iMbNumInGom = SWelsSvcRc->iNumberMbGom;
-
-    {
-      int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS;
-      SPixMap sSrcPixMap;
-      SPixMap sRefPixMap;
-      memset (&sSrcPixMap, 0, sizeof (SPixMap));
-      memset (&sRefPixMap, 0, sizeof (SPixMap));
-      int32_t iRet = 0;
-
-      sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
-      sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-      sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
-      sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
-      sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
-      sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
-
-      sRefPixMap.pPixel[0] = pRefPicture->pData[0];
-      sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
-      sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
-      sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
-      sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
-      sRefPixMap.eFormat = VIDEO_FORMAT_I420;
-
-      iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
-      iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
-      if (iRet == 0)
-        m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
-    }
-  }
-}
-
-
-void CWelsPreProcess::InitPixMap (const SPicture* pPicture, SPixMap* pPixMap) {
-  pPixMap->pPixel[0] = pPicture->pData[0];
-  pPixMap->pPixel[1] = pPicture->pData[1];
-  pPixMap->pPixel[2] = pPicture->pData[2];
-  pPixMap->iSizeInBits = sizeof (uint8_t);
-  pPixMap->iStride[0] = pPicture->iLineSize[0];
-  pPixMap->iStride[1] = pPicture->iLineSize[1];
-  pPixMap->sRect.iRectWidth = pPicture->iWidthInPixel;
-  pPixMap->sRect.iRectHeight = pPicture->iHeightInPixel;
-
-  pPixMap->eFormat = VIDEO_FORMAT_I420;
-}
-void CWelsPreProcess::GetAvailableRefList (SPicture** pSrcPicList, uint8_t iCurTid, const int32_t iClosestLtrFrameNum,
-    SRefInfoParam* pAvailableRefList, int32_t& iAvailableRefNum, int32_t& iAvailableSceneRefNum) {
-  SWelsSvcCodingParam*		pSvcParam = m_pEncCtx->pSvcParam;
-  const int32_t iSourcePicNum = pSvcParam->iNumRefFrame;
-  if (0 >= iSourcePicNum) {
-    iAvailableRefNum = 0;
-    iAvailableSceneRefNum = 0;
-    return ;
-  }
-  const bool bCurFrameMarkedAsSceneLtr = m_pEncCtx->bCurFrameMarkedAsSceneLtr;
-  SPicture* pRefPic = NULL;
-  uint8_t uiRefTid = 0;
-  bool bRefRealLtr = false;
-
-  iAvailableRefNum = 1; //zero is left for the closest frame
-  iAvailableSceneRefNum = 0;
-
-  //the saving order will be depend on pSrcPicList
-  //TODO: use a frame_idx to find the closer ref in time distance, and correctly sort the ref list
-  for (int32_t i = iSourcePicNum - 1; i >= 0; --i) {
-    pRefPic = pSrcPicList[i];
-    if (NULL == pRefPic || !pRefPic->bUsedAsRef || !pRefPic->bIsLongRef || (bCurFrameMarkedAsSceneLtr
-        && (!pRefPic->bIsSceneLTR))) {
-      continue;
-    }
-    uiRefTid = pRefPic->uiTemporalId;
-    bRefRealLtr = pRefPic->bIsSceneLTR;
-
-    if (bRefRealLtr || (0 == iCurTid && 0 == uiRefTid) || (uiRefTid < iCurTid)) {
-      int32_t idx = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum) ? (0) : (iAvailableRefNum++);
-      pAvailableRefList[idx].pRefPicture = pRefPic;
-      pAvailableRefList[idx].iSrcListIdx = i + 1; //in SrcList, the idx 0 is reserved for CurPic
-      iAvailableSceneRefNum += bRefRealLtr;
-    }
-  }
-
-  if (pAvailableRefList[0].pRefPicture == NULL) {
-    for (int32_t i = 1; i < iAvailableRefNum ; ++i) {
-      pAvailableRefList[i - 1].pRefPicture = pAvailableRefList[i].pRefPicture;
-      pAvailableRefList[i - 1].iSrcListIdx = pAvailableRefList[i].iSrcListIdx;
-    }
-
-    pAvailableRefList[iAvailableRefNum - 1].pRefPicture = NULL;
-    pAvailableRefList[iAvailableRefNum - 1].iSrcListIdx = 0;
-    --iAvailableRefNum;
-  }
-}
-
-
-void CWelsPreProcess::InitRefJudgement (SRefJudgement* pRefJudgement) {
-  pRefJudgement->iMinFrameComplexity = INT_MAX;
-  pRefJudgement->iMinFrameComplexity08 = INT_MAX;
-  pRefJudgement->iMinFrameComplexity11 = INT_MAX;
-
-  pRefJudgement->iMinFrameNumGap = INT_MAX;
-  pRefJudgement->iMinFrameQp = INT_MAX;
-}
-bool CWelsPreProcess::JudgeBestRef (SPicture* pRefPic, const SRefJudgement& sRefJudgement,
-                                    const int32_t iFrameComplexity, const bool bIsClosestLtrFrame) {
-  return (bIsClosestLtrFrame ? (iFrameComplexity < sRefJudgement.iMinFrameComplexity11) :
-          ((iFrameComplexity < sRefJudgement.iMinFrameComplexity08) || ((iFrameComplexity <= sRefJudgement.iMinFrameComplexity11)
-              && (pRefPic->iFrameAverageQp < sRefJudgement.iMinFrameQp))));
-}
-
-void CWelsPreProcess::SaveBestRefToJudgement (const int32_t iRefPictureAvQP, const int32_t iComplexity,
-    SRefJudgement* pRefJudgement) {
-  pRefJudgement->iMinFrameQp = iRefPictureAvQP;
-  pRefJudgement->iMinFrameComplexity =  iComplexity;
-  pRefJudgement->iMinFrameComplexity08 = static_cast<int32_t> (iComplexity * 0.8);
-  pRefJudgement->iMinFrameComplexity11 = static_cast<int32_t> (iComplexity * 1.1);
-}
-void CWelsPreProcess::SaveBestRefToLocal (SRefInfoParam* pRefPicInfo, const SSceneChangeResult& sSceneChangeResult,
-    SRefInfoParam* pRefSaved) {
-  pRefSaved->iSrcListIdx = pRefPicInfo->iSrcListIdx;
-  pRefSaved->bSceneLtrFlag = pRefPicInfo->bSceneLtrFlag;
-}
-
-void CWelsPreProcess::SaveBestRefToVaa (SRefInfoParam& sRefSaved, SRefInfoParam* pVaaBestRef) {
-  (*pVaaBestRef) = sRefSaved;
-}
-
-ESceneChangeIdc CWelsPreProcess::DetectSceneChangeScreen (sWelsEncCtx* pCtx, SPicture* pCurPicture) {
-#define STATIC_SCENE_MOTION_RATIO 0.01f
-  SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
-  SVAAFrameInfoExt* pVaaExt			= static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
-  if (NULL == pCtx || NULL == pVaaExt || NULL == pCurPicture) {
-    return LARGE_CHANGED_SCENE;
-  }
-
-  const int32_t iTargetDid = pSvcParam->iSpatialLayerNum - 1;
-  if (0 != iTargetDid) {
-    return LARGE_CHANGED_SCENE;
-  }
-
-  ESceneChangeIdc iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
-  SPicture** pSrcPicList = &m_pSpatialPic[iTargetDid][1];
-  if (NULL == pSrcPicList) {
-    return LARGE_CHANGED_SCENE;
-  }
-
-  SRefInfoParam sAvailableRefList[MAX_REF_PIC_COUNT] = { { 0 } };
-  int32_t iAvailableRefNum = 0;
-  int32_t iAvailableSceneRefNum = 0;
-
-  int32_t iSceneChangeMethodIdx = METHOD_SCENE_CHANGE_DETECTION_SCREEN;
-  SSceneChangeResult sSceneChangeResult = {SIMILAR_SCENE, 0, 0, NULL};
-
-  SPixMap sSrcMap = { { 0 } };
-  SPixMap sRefMap = { { 0 } };
-  SRefJudgement sLtrJudgement;
-  SRefJudgement sSceneLtrJudgement;
-  SRefInfoParam sLtrSaved = {0};
-  SRefInfoParam sSceneLtrSaved = {0};
-
-  int32_t iNumOfLargeChange = 0, iNumOfMediumChangeToLtr = 0;
-
-  bool bBestRefIsLtr = false, bIsClosestLtrFrame = false;
-  int32_t ret = 1, iScdIdx = 0;
-
-  SPicture* pRefPic = NULL;
-  SRefInfoParam* pRefPicInfo = NULL;
-  uint8_t*  pCurBlockStaticPointer = NULL;
-  uint8_t*  pBestStrBlockStaticPointer = NULL;
-  uint8_t*  pBestLtrBlockStaticPointer = NULL;
-
-  const int32_t iNegligibleMotionBlocks = (static_cast<int32_t> ((pCurPicture->iWidthInPixel >> 3) *
-                                          (pCurPicture->iHeightInPixel >> 3) * STATIC_SCENE_MOTION_RATIO));
-  const uint8_t iCurTid = GetTemporalLevel (&pSvcParam->sDependencyLayers[m_pEncCtx->sSpatialIndexMap[0].iDid],
-                          m_pEncCtx->iCodingIndex, pSvcParam->uiGopSize);
-  const int32_t iClosestLtrFrameNum = pCtx->pLtr[iTargetDid].iLastLtrIdx[iCurTid];//TBD
-  GetAvailableRefList (pSrcPicList, iCurTid, iClosestLtrFrameNum, &sAvailableRefList[0], iAvailableRefNum,
-                       iAvailableSceneRefNum);
-  //after this build, pAvailableRefList[idx].iSrcListIdx is the idx of the ref in h->spatial_pic
-  if (0 == iAvailableRefNum) {
-    WelsLog (pCtx, WELS_LOG_ERROR, "SceneChangeDetect() iAvailableRefNum=0 but not I.\n");
-    return LARGE_CHANGED_SCENE;
-  }
-
-  InitPixMap (pCurPicture, &sSrcMap);
-  InitRefJudgement (&sLtrJudgement);
-  InitRefJudgement (&sSceneLtrJudgement);
-
-  for (iScdIdx = 0; iScdIdx < iAvailableRefNum; iScdIdx ++) {
-    pCurBlockStaticPointer = pVaaExt->pVaaBlockStaticIdc[iScdIdx];
-    sSceneChangeResult.eSceneChangeIdc = SIMILAR_SCENE;
-    sSceneChangeResult.pStaticBlockIdc = pCurBlockStaticPointer;//
-
-    pRefPicInfo = & (sAvailableRefList[iScdIdx]);
-    assert (NULL != pRefPicInfo);
-    pRefPic = pRefPicInfo->pRefPicture;
-    InitPixMap (pRefPic, &sRefMap);
-
-    bIsClosestLtrFrame = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum);
-
-    //TBD scrolling detection
-    m_pInterfaceVp->Set (iSceneChangeMethodIdx, (void*) (&sSceneChangeResult));
-    ret = m_pInterfaceVp->Process (iSceneChangeMethodIdx, &sSrcMap, &sRefMap);
-
-    if (ret == 0) {
-      m_pInterfaceVp->Get (iSceneChangeMethodIdx, (void*)&sSceneChangeResult);
-
-      const int32_t iFrameComplexity = sSceneChangeResult.iFrameComplexity;
-      const int32_t iSceneDetectIdc = sSceneChangeResult.eSceneChangeIdc;
-      const int32_t iMotionBlockNum = sSceneChangeResult.iMotionBlockNum;
-
-      const bool bCurRefIsLtr = pRefPic->bIsSceneLTR;
-      const int32_t iRefPicAvQP = pRefPic->iFrameAverageQp;
-
-      //for scene change detection
-      iNumOfLargeChange += (static_cast<int32_t> (LARGE_CHANGED_SCENE == iSceneDetectIdc));
-      iNumOfMediumChangeToLtr += (static_cast<int32_t> ((bCurRefIsLtr) && (iSceneDetectIdc != SIMILAR_SCENE)));
-
-      //for reference selection
-      //this judge can only be saved when iAvailableRefNum==1, which is very limit
-      //when LTR is OFF, it can still judge from all available STR
-      if (JudgeBestRef (pRefPic, sLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
-        SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sLtrJudgement);
-        SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sLtrSaved);
-        bBestRefIsLtr = bCurRefIsLtr;
-        pBestStrBlockStaticPointer = sSceneChangeResult.pStaticBlockIdc;
-      }
-      if (bCurRefIsLtr && JudgeBestRef (pRefPic, sSceneLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
-        SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sSceneLtrJudgement);
-        SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sSceneLtrSaved);
-        pBestLtrBlockStaticPointer = sSceneChangeResult.pStaticBlockIdc;
-      }
-
-      if (iMotionBlockNum <= iNegligibleMotionBlocks) {
-        break;
-      }
-    }
-  }
-
-  if (iNumOfLargeChange == iAvailableRefNum) {
-    iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
-  } else if ((iNumOfMediumChangeToLtr == iAvailableSceneRefNum) && (0 != iAvailableSceneRefNum)) {
-    iVaaFrameSceneChangeIdc = MEDIUM_CHANGED_SCENE;
-  } else {
-    iVaaFrameSceneChangeIdc = SIMILAR_SCENE;
-  }
-
-  WelsLog(pCtx,WELS_LOG_INFO,"iVaaFrameSceneChangeIdc = %d,codingIdx = %d\n",iVaaFrameSceneChangeIdc,pCtx->iCodingIndex);
-
-  SaveBestRefToVaa (sLtrSaved, & (pVaaExt->sVaaStrBestRefCandidate[0]));
-
-  if (0 == iAvailableSceneRefNum) {
-    SaveBestRefToVaa (sSceneLtrSaved, & (pVaaExt->sVaaStrBestRefCandidate[1]));
-  }
-
-  pVaaExt->iNumOfAvailableRef = 1;
-  return static_cast<ESceneChangeIdc> (iVaaFrameSceneChangeIdc);
-}
-
-int32_t CWelsPreProcess::GetRefCandidateLtrIndex (int32_t iRefIdx) {
-  const int32_t iTargetDid = m_pEncCtx->pSvcParam->iSpatialLayerNum - 1;
-  SVAAFrameInfoExt* pVaaExt			= static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa);
-  SRefInfoParam* BestRefCandidateParam = & (pVaaExt->sVaaStrBestRefCandidate[iRefIdx]);
-  int32_t iLtrRefIdx = m_pSpatialPic[iTargetDid][BestRefCandidateParam->iSrcListIdx]->iLongTermPicNum;
-  return iLtrRefIdx;
-}
-void  CWelsPreProcess::Padding (uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iStrideY, int32_t iStrideUV,
-                                int32_t iActualWidth, int32_t iPaddingWidth, int32_t iActualHeight, int32_t iPaddingHeight) {
-  int32_t i;
-
-  if (iPaddingHeight > iActualHeight) {
-    for (i = iActualHeight; i < iPaddingHeight; i++) {
-      memset (pSrcY + i * iStrideY, 0, iActualWidth);
-
-      if (! (i & 1)) {
-        memset (pSrcU + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
-        memset (pSrcV + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
-      }
-    }
-  }
-
-  if (iPaddingWidth > iActualWidth) {
-    for (i = 0; i < iPaddingHeight; i++) {
-      memset (pSrcY + i * iStrideY + iActualWidth, 0, iPaddingWidth - iActualWidth);
-      if (! (i & 1)) {
-        memset (pSrcU + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
-        memset (pSrcV + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
-      }
-    }
-  }
-}
-
-
-//TODO: may opti later
-//TODO: not use this func?
-void* WelsMemcpy (void* dst, const void* kpSrc, uint32_t uiSize) {
-  return ::memcpy (dst, kpSrc, uiSize);
-}
-void* WelsMemset (void* p, int32_t val, uint32_t uiSize) {
-  return ::memset (p, val, uiSize);
-}
-
-//i420_to_i420_c
-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) {
-  int32_t   iWidth2 = iWidth >> 1;
-  int32_t   iHeight2 = iHeight >> 1;
-  int32_t   j;
-
-  for (j = iHeight; j; j--) {
-    WelsMemcpy (pDstY, pSrcY, iWidth);
-    pDstY += iDstStrideY;
-    pSrcY += iSrcStrideY;
-  }
-
-  for (j = iHeight2; j; j--) {
-    WelsMemcpy (pDstU, pSrcU, iWidth2);
-    WelsMemcpy (pDstV, pSrcV, iWidth2);
-    pDstU += iDstStrideUV;
-    pDstV += iDstStrideUV;
-    pSrcU += iSrcStrideUV;
-    pSrcV += iSrcStrideUV;
-  }
-}
-
-void  CWelsPreProcess::WelsMoveMemoryWrapper (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
-    const SSourcePicture* kpSrc,
-    const int32_t kiTargetWidth, const int32_t kiTargetHeight) {
-  if (VIDEO_FORMAT_I420 != (kpSrc->iColorFormat & (~VIDEO_FORMAT_VFlip)))
-    return;
-
-  int32_t  iSrcWidth       = kpSrc->iPicWidth;
-  int32_t  iSrcHeight      = kpSrc->iPicHeight;
-
-  if (iSrcHeight > kiTargetHeight) 	iSrcHeight = kiTargetHeight;
-  if (iSrcWidth > kiTargetWidth)		iSrcWidth  = kiTargetWidth;
-
-  // copy from fr26 to fix the odd uiSize failed issue
-  if (iSrcWidth & 0x1)		-- iSrcWidth;
-  if (iSrcHeight & 0x1)		-- iSrcHeight;
-
-  const int32_t kiSrcTopOffsetY = pSvcParam->SUsedPicRect.iTop;
-  const int32_t kiSrcTopOffsetUV = (kiSrcTopOffsetY >> 1);
-  const int32_t kiSrcLeftOffsetY = pSvcParam->SUsedPicRect.iLeft;
-  const int32_t kiSrcLeftOffsetUV = (kiSrcLeftOffsetY >> 1);
-  int32_t  iSrcOffset[3]       = {0, 0, 0};
-  iSrcOffset[0] = kpSrc->iStride[0] * kiSrcTopOffsetY + kiSrcLeftOffsetY;
-  iSrcOffset[1] = kpSrc->iStride[1] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV ;
-  iSrcOffset[2] = kpSrc->iStride[2] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV;
-
-  uint8_t* pSrcY = kpSrc->pData[0] + iSrcOffset[0];
-  uint8_t* pSrcU = kpSrc->pData[1] + iSrcOffset[1];
-  uint8_t* pSrcV = kpSrc->pData[2] + iSrcOffset[2];
-  const int32_t kiSrcStrideY = kpSrc->iStride[0];
-  const int32_t kiSrcStrideUV = kpSrc->iStride[1];
-
-  uint8_t* pDstY = pDstPic->pData[0];
-  uint8_t* pDstU = pDstPic->pData[1];
-  uint8_t* pDstV = pDstPic->pData[2];
-  const int32_t kiDstStrideY = pDstPic->iLineSize[0];
-  const int32_t kiDstStrideUV = pDstPic->iLineSize[1];
-
-#define MAX_WIDTH      (4096)
-#define MAX_HEIGHT     (2304)//MAX_FS_LEVEL51 (36864); MAX_FS_LEVEL51*256/4096 = 2304
-  if (pSrcY) {
-    if (iSrcWidth <= 0 || iSrcWidth > MAX_WIDTH || iSrcHeight <= 0 || iSrcHeight > MAX_HEIGHT)
-      return;
-    if (kiSrcTopOffsetY >= iSrcHeight || kiSrcLeftOffsetY >= iSrcWidth || iSrcWidth > kiSrcStrideY)
-      return;
-  }
-  if (pDstY) {
-    if (kiTargetWidth <= 0 || kiTargetWidth > MAX_WIDTH || kiTargetHeight <= 0 || kiTargetHeight > MAX_HEIGHT)
-      return;
-    if (kiTargetWidth > kiDstStrideY)
-      return;
-  }
-
-  if (pSrcY == NULL || pSrcU == NULL || pSrcV == NULL || pDstY == NULL || pDstU == NULL || pDstV == NULL
-      || (iSrcWidth & 1) || (iSrcHeight & 1)) {
-  } else {
-    //i420_to_i420_c
-    WelsMoveMemory_c (pDstY,  pDstU,  pDstV,  kiDstStrideY, kiDstStrideUV,
-                      pSrcY,  pSrcU,  pSrcV, kiSrcStrideY, kiSrcStrideUV, iSrcWidth, iSrcHeight);
-
-    //in VP Process
-    if (kiTargetWidth > iSrcWidth || kiTargetHeight > iSrcHeight) {
-      Padding (pDstY, pDstU, pDstV, kiDstStrideY, kiDstStrideUV, iSrcWidth, kiTargetWidth, iSrcHeight, kiTargetHeight);
-    }
-  }
-
-}
-
-//*********************************************************************************************************/
-} // namespace WelsSVCEnc
+/*!
+ * \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 WelsSVCEnc {
+
+#define WelsSafeDelete(p) if(p){ delete (p); (p) = NULL; }
+
+
+//***** 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);
+
+//******* 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) {
+    CreateVpInterface ((void**) &m_pInterfaceVp, WELSVP_INTERFACE_VERION);
+    if (!m_pInterfaceVp)
+      goto exit;
+  } else
+    goto exit;
+
+  return 0;
+
+exit:
+  WelsPreprocessDestroy();
+  return 1;
+}
+
+int32_t CWelsPreProcess::WelsPreprocessDestroy() {
+  DestroyVpInterface (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->sDependencyLayers[iDlayerIndex].iFrameWidth;
+    const int32_t kiPicHeight   = pParam->sDependencyLayers[iDlayerIndex].iFrameHeight;
+    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;
+    if (WelsPreprocessReset (pCtx) != 0)
+      return -1;
+
+    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 = & (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);
+    }
+    AnalyzePictureComplexity (pCtx, pCurPic, pRefPic, kiDidx, bCalculateBGD);
+    WelsExchangeSpatialPictures (&m_pLastSpatialPicture[kiDidx][1], &m_pLastSpatialPicture[kiDidx][0]);
+  }
+  return 0;
+}
+
+int32_t CWelsPreProcess::UpdateSpatialPictures (sWelsEncCtx* pCtx, SWelsSvcCodingParam* pParam,
+    const int8_t iCurTid, const int32_t d_idx) {
+  if (pCtx->pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME)
+    return 0;
+  if (iCurTid < m_uiSpatialLayersInTemporal[d_idx] - 1 || pParam->iDecompStages == 0) {
+    if ((iCurTid >= MAX_TEMPORAL_LEVEL) || (m_uiSpatialLayersInTemporal[d_idx] - 1 > MAX_TEMPORAL_LEVEL)) {
+      InitLastSpatialPictures (pCtx);
+      return 1;
+    }
+    if (pParam->bEnableLongTermReference && pCtx->bLongTermRefFlag[d_idx][iCurTid]) {
+      SPicture* tmp	= m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] + pCtx->pVaa->uiMarkLongTermPicIdx];
+      m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] + pCtx->pVaa->uiMarkLongTermPicIdx] =
+        m_pSpatialPic[d_idx][iCurTid];
+      m_pSpatialPic[d_idx][iCurTid] = m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1];
+      m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1] = tmp;
+      pCtx->bLongTermRefFlag[d_idx][iCurTid] = false;
+    } else {
+      WelsExchangeSpatialPictures (&m_pSpatialPic[d_idx][m_uiSpatialLayersInTemporal[d_idx] - 1],
+                                   &m_pSpatialPic[d_idx][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
+  SDLayerParam* pDlayerParam					= 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;
+
+  pDlayerParam = &pSvcParam->sDependencyLayers[iDependencyId];
+  iTargetWidth	  = pDlayerParam->iFrameWidth;
+  iTargetHeight  = pDlayerParam->iFrameHeight;
+  iTemporalId    = pDlayerParam->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);
+
+  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) {
+      pDlayerParam			= &pSvcParam->sDependencyLayers[iDependencyId];
+      iTargetWidth	= pDlayerParam->iFrameWidth;
+      iTargetHeight	= pDlayerParam->iFrameHeight;
+      iTemporalId = pDlayerParam->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);
+
+        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 --) {
+    SDLayerParam* 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] = iCurDstWidth;
+      pScaledPicture->iScaledHeight[iSpatialIdx] = iInputHeightXDstWidth / kiInputPicWidth;
+    } else {
+      pScaledPicture->iScaledWidth[iSpatialIdx] = iInputWidthXDstHeight / kiInputPicHeight;
+      pScaledPicture->iScaledHeight[iSpatialIdx] = iCurDstHeight;
+    }
+  }
+
+  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;
+
+  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];
+  sSrcPixMap.iStride[2] = pSrc->iLineSize[2];
+  sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
+
+  m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, NULL);
+}
+
+bool CWelsPreProcess::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) {
+  bool bSceneChangeFlag = false;
+  int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION_VIDEO;
+  SSceneChangeResult sSceneChangeDetectResult = { SIMILAR_SCENE };
+  SPixMap sSrcPixMap;
+  SPixMap sRefPixMap;
+  memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
+  memset (&sRefPixMap, 0, sizeof (sRefPixMap));
+  sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
+  sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+  sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
+  sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
+  sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
+  sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
+
+
+  sRefPixMap.pPixel[0] = pRefPicture->pData[0];
+  sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+  sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
+  sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
+  sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
+  sRefPixMap.eFormat = VIDEO_FORMAT_I420;
+
+  int32_t iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
+  if (iRet == 0) {
+    m_pInterfaceVp->Get (iMethodIdx, (void*)&sSceneChangeDetectResult);
+    bSceneChangeFlag = (sSceneChangeDetectResult.eSceneChangeIdc == LARGE_CHANGED_SCENE) ? true : false;
+  }
+
+  return bSceneChangeFlag;
+}
+
+int32_t CWelsPreProcess::DownsamplePadding (SPicture* pSrc, SPicture* pDstPic,  int32_t iSrcWidth, int32_t iSrcHeight,
+    int32_t iShrinkWidth, int32_t iShrinkHeight, int32_t iTargetWidth, int32_t iTargetHeight) {
+  int32_t iRet = 0;
+  SPixMap sSrcPixMap;
+  SPixMap sDstPicMap;
+  memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
+  memset (&sDstPicMap, 0, sizeof (sDstPicMap));
+  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  = iSrcWidth;
+  sSrcPixMap.sRect.iRectHeight = iSrcHeight;
+  sSrcPixMap.iStride[0]  = pSrc->iLineSize[0];
+  sSrcPixMap.iStride[1]  = pSrc->iLineSize[1];
+  sSrcPixMap.iStride[2]  = pSrc->iLineSize[2];
+  sSrcPixMap.eFormat     = VIDEO_FORMAT_I420;
+
+  if (iSrcWidth != iShrinkWidth || iSrcHeight != iShrinkHeight) {
+    int32_t iMethodIdx = METHOD_DOWNSAMPLE;
+    sDstPicMap.pPixel[0]   = pDstPic->pData[0];
+    sDstPicMap.pPixel[1]   = pDstPic->pData[1];
+    sDstPicMap.pPixel[2]   = pDstPic->pData[2];
+    sDstPicMap.iSizeInBits = g_kiPixMapSizeInBits;
+    sDstPicMap.sRect.iRectWidth  = iShrinkWidth;
+    sDstPicMap.sRect.iRectHeight = iShrinkHeight;
+    sDstPicMap.iStride[0]  = pDstPic->iLineSize[0];
+    sDstPicMap.iStride[1]  = pDstPic->iLineSize[1];
+    sDstPicMap.iStride[2]  = pDstPic->iLineSize[2];
+    sDstPicMap.eFormat     = VIDEO_FORMAT_I420;
+
+    iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sDstPicMap);
+  } else {
+    memcpy (&sDstPicMap, &sSrcPixMap, sizeof (sDstPicMap));	// confirmed_safe_unsafe_usage
+  }
+
+  // get rid of odd line
+  iShrinkWidth -= (iShrinkWidth & 1);
+  iShrinkHeight -= (iShrinkHeight & 1);
+  Padding ((uint8_t*)sDstPicMap.pPixel[0], (uint8_t*)sDstPicMap.pPixel[1], (uint8_t*)sDstPicMap.pPixel[2],
+           sDstPicMap.iStride[0], sDstPicMap.iStride[1],	iShrinkWidth, iTargetWidth, iShrinkHeight, iTargetHeight);
+
+  return iRet;
+}
+
+//*********************************************************************************************************/
+void CWelsPreProcess::VaaCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
+                                      bool bCalculateSQDiff, bool bCalculateVar, bool bCalculateBGD) {
+  pVaaInfo->sVaaCalcInfo.pCurY = pCurPicture->pData[0];
+  pVaaInfo->sVaaCalcInfo.pRefY = pRefPicture->pData[0];
+  {
+    int32_t iMethodIdx = METHOD_VAA_STATISTICS;
+    SPixMap sCurPixMap;
+    SPixMap sRefPixMap;
+    memset (&sCurPixMap, 0, sizeof (sCurPixMap));
+    memset (&sRefPixMap, 0, sizeof (sRefPixMap));
+    SVAACalcParam calc_param = {0};
+
+    sCurPixMap.pPixel[0] = pCurPicture->pData[0];
+    sCurPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+    sCurPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
+    sCurPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
+    sCurPixMap.iStride[0] = pCurPicture->iLineSize[0];
+    sCurPixMap.eFormat = VIDEO_FORMAT_I420;
+
+    sRefPixMap.pPixel[0] = pRefPicture->pData[0];
+    sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+    sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
+    sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
+    sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
+    sRefPixMap.eFormat = VIDEO_FORMAT_I420;
+
+    calc_param.iCalcVar	= bCalculateVar;
+    calc_param.iCalcBgd	= bCalculateBGD;
+    calc_param.iCalcSsd	= bCalculateSQDiff;
+    calc_param.pCalcResult = &pVaaInfo->sVaaCalcInfo;
+
+    m_pInterfaceVp->Set (iMethodIdx, &calc_param);
+    m_pInterfaceVp->Process (iMethodIdx, &sCurPixMap, &sRefPixMap);
+  }
+}
+
+void CWelsPreProcess::BackgroundDetection (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture,
+    bool bDetectFlag) {
+  if (bDetectFlag) {
+    pVaaInfo->iPicWidth     = pCurPicture->iWidthInPixel;
+    pVaaInfo->iPicHeight    = pCurPicture->iHeightInPixel;
+
+    pVaaInfo->iPicStride	= pCurPicture->iLineSize[0];
+    pVaaInfo->iPicStrideUV	= pCurPicture->iLineSize[1];
+    pVaaInfo->pCurY			= pCurPicture->pData[0];
+    pVaaInfo->pRefY			= pRefPicture->pData[0];
+    pVaaInfo->pCurU			= pCurPicture->pData[1];
+    pVaaInfo->pRefU			= pRefPicture->pData[1];
+    pVaaInfo->pCurV			= pCurPicture->pData[2];
+    pVaaInfo->pRefV			= pRefPicture->pData[2];
+
+    int32_t iMethodIdx = METHOD_BACKGROUND_DETECTION;
+    SPixMap sSrcPixMap;
+    SPixMap sRefPixMap;
+    memset (&sSrcPixMap, 0, sizeof (sSrcPixMap));
+    memset (&sRefPixMap, 0, sizeof (sRefPixMap));
+    SBGDInterface BGDParam = {0};
+
+    sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
+    sSrcPixMap.pPixel[1] = pCurPicture->pData[1];
+    sSrcPixMap.pPixel[2] = pCurPicture->pData[2];
+    sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+    sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
+    sSrcPixMap.iStride[1] = pCurPicture->iLineSize[1];
+    sSrcPixMap.iStride[2] = pCurPicture->iLineSize[2];
+    sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
+    sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
+    sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
+
+    sRefPixMap.pPixel[0] = pRefPicture->pData[0];
+    sRefPixMap.pPixel[1] = pRefPicture->pData[1];
+    sRefPixMap.pPixel[2] = pRefPicture->pData[2];
+    sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+    sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
+    sRefPixMap.iStride[1] = pRefPicture->iLineSize[1];
+    sRefPixMap.iStride[2] = pRefPicture->iLineSize[2];
+    sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
+    sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
+    sRefPixMap.eFormat = VIDEO_FORMAT_I420;
+
+    BGDParam.pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
+    BGDParam.pCalcRes = & (pVaaInfo->sVaaCalcInfo);
+    m_pInterfaceVp->Set (iMethodIdx, (void*)&BGDParam);
+    m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
+  } else {
+    int32_t	iPicWidthInMb	= (pCurPicture->iWidthInPixel + 15) >> 4;
+    int32_t	iPicHeightInMb = (pCurPicture->iHeightInPixel + 15) >> 4;
+    memset (pVaaInfo->pVaaBackgroundMbFlag, 0, iPicWidthInMb * iPicHeightInMb);
+  }
+}
+
+void CWelsPreProcess::AdaptiveQuantCalculation (SVAAFrameInfo* pVaaInfo, SPicture* pCurPicture, SPicture* pRefPicture) {
+  pVaaInfo->sAdaptiveQuantParam.pCalcResult = & (pVaaInfo->sVaaCalcInfo);
+  pVaaInfo->sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp = 0;
+
+  {
+    int32_t iMethodIdx = METHOD_ADAPTIVE_QUANT;
+    SPixMap pSrc;
+    SPixMap pRef;
+    memset (&pSrc, 0, sizeof (pSrc));
+    memset (&pRef, 0, sizeof (pRef));
+    int32_t iRet = 0;
+
+    pSrc.pPixel[0] = pCurPicture->pData[0];
+    pSrc.iSizeInBits = g_kiPixMapSizeInBits;
+    pSrc.iStride[0] = pCurPicture->iLineSize[0];
+    pSrc.sRect.iRectWidth = pCurPicture->iWidthInPixel;
+    pSrc.sRect.iRectHeight = pCurPicture->iHeightInPixel;
+    pSrc.eFormat = VIDEO_FORMAT_I420;
+
+    pRef.pPixel[0] = pRefPicture->pData[0];
+    pRef.iSizeInBits = g_kiPixMapSizeInBits;
+    pRef.iStride[0] = pRefPicture->iLineSize[0];
+    pRef.sRect.iRectWidth = pRefPicture->iWidthInPixel;
+    pRef.sRect.iRectHeight = pRefPicture->iHeightInPixel;
+    pRef.eFormat = VIDEO_FORMAT_I420;
+
+    iRet = m_pInterfaceVp->Set (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
+    iRet = m_pInterfaceVp->Process (iMethodIdx, &pSrc, &pRef);
+    if (iRet == 0)
+      m_pInterfaceVp->Get (iMethodIdx, (void*) & (pVaaInfo->sAdaptiveQuantParam));
+  }
+}
+
+void CWelsPreProcess::SetRefMbType (sWelsEncCtx* pCtx, uint32_t** pRefMbTypeArray, int32_t iRefPicType) {
+  const uint8_t uiTid	    = pCtx->uiTemporalId;
+  const uint8_t uiDid       = pCtx->uiDependencyId;
+  SRefList* pRefPicLlist    = pCtx->ppRefPicListExt[uiDid];
+  SLTRState* pLtr	    = &pCtx->pLtr[uiDid];
+  uint8_t i							= 0;
+
+  if (pCtx->pSvcParam->bEnableLongTermReference && pLtr->bReceivedT0LostFlag && uiTid == 0) {
+    for (i = 0; i < pRefPicLlist->uiLongRefCount; i++) {
+      SPicture* pRef = pRefPicLlist->pLongRefList[i];
+      if (pRef != NULL && pRef->uiRecieveConfirmed == 1/*RECIEVE_SUCCESS*/) {
+        *pRefMbTypeArray = pRef->uiRefMbType;
+        break;
+      }
+    }
+  } else {
+    for (i = 0; i < pRefPicLlist->uiShortRefCount; i++) {
+      SPicture* pRef = pRefPicLlist->pShortRefList[i];
+      if (pRef != NULL && pRef->bUsedAsRef && pRef->iFramePoc >= 0 && pRef->uiTemporalId <= uiTid) {
+        *pRefMbTypeArray = pRef->uiRefMbType;
+        break;
+      }
+    }
+  }
+}
+
+
+void CWelsPreProcess::AnalyzePictureComplexity (sWelsEncCtx* pCtx, SPicture* pCurPicture, SPicture* pRefPicture,
+    const int32_t kiDependencyId, const bool bCalculateBGD) {
+  SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
+  int32_t iComplexityAnalysisMode = 0;
+
+  if (pSvcParam->iRCMode == RC_OFF_MODE)
+    return;
+  if (pSvcParam->iUsageType == SCREEN_CONTENT_REAL_TIME) {
+    SVAAFrameInfoExt* pVaaExt		= static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
+    SComplexityAnalysisScreenParam* sComplexityAnalysisParam	= &pVaaExt->sComplexityScreenParam;
+    SWelsSvcRc* pWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
+
+    if (pCtx->eSliceType == P_SLICE)
+      iComplexityAnalysisMode = GOM_SAD;
+    else if (pCtx->eSliceType == I_SLICE)
+      iComplexityAnalysisMode = GOM_VAR;
+    else
+      return;
+
+    memset (pWelsSvcRc->pGomForegroundBlockNum, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
+    memset (pWelsSvcRc->pCurrentFrameGomSad, 0, pWelsSvcRc->iGomSize * sizeof (int32_t));
+
+    sComplexityAnalysisParam->iFrameComplexity = 0;
+    sComplexityAnalysisParam->pGomComplexity = pWelsSvcRc->pCurrentFrameGomSad;
+    sComplexityAnalysisParam->iGomNumInFrame = pWelsSvcRc->iGomSize;
+    sComplexityAnalysisParam->iIdrFlag = (pCtx->eSliceType == I_SLICE);
+    sComplexityAnalysisParam->iMbRowInGom = GOM_H_SCC;
+    sComplexityAnalysisParam->sScrollResult.bScrollDetectFlag = false;
+    sComplexityAnalysisParam->sScrollResult.iScrollMvX = 0;
+    sComplexityAnalysisParam->sScrollResult.iScrollMvY = 0;
+
+    const int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS_SCREEN;
+    SPixMap sSrcPixMap;
+    SPixMap sRefPixMap;
+    memset (&sSrcPixMap, 0, sizeof (SPixMap));
+    memset (&sRefPixMap, 0, sizeof (SPixMap));
+    int32_t iRet = 0;
+
+    sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
+    sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+    sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
+    sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
+    sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
+    sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
+
+    if (pRefPicture != NULL) {
+      sRefPixMap.pPixel[0] = pRefPicture->pData[0];
+      sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+      sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
+      sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
+      sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
+      sRefPixMap.eFormat = VIDEO_FORMAT_I420;
+    }
+
+    iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
+    iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
+    if (iRet == 0)
+      m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
+
+  } else {
+    SVAAFrameInfo* pVaaInfo	 = pCtx->pVaa;
+    SComplexityAnalysisParam* sComplexityAnalysisParam = & (pVaaInfo->sComplexityAnalysisParam);
+    SWelsSvcRc* SWelsSvcRc = &pCtx->pWelsSvcRc[kiDependencyId];
+
+    if (pSvcParam->iRCMode == RC_QUALITY_MODE && pCtx->eSliceType == P_SLICE) {
+      iComplexityAnalysisMode = FRAME_SAD;
+    } else if (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == P_SLICE) {
+      iComplexityAnalysisMode = GOM_SAD;
+    } else if (pSvcParam->iRCMode >= RC_BITRATE_MODE && pCtx->eSliceType == I_SLICE) {
+      iComplexityAnalysisMode = GOM_VAR;
+    } else {
+      return;
+    }
+    sComplexityAnalysisParam->iComplexityAnalysisMode = iComplexityAnalysisMode;
+    sComplexityAnalysisParam->pCalcResult = & (pVaaInfo->sVaaCalcInfo);
+    sComplexityAnalysisParam->pBackgroundMbFlag = pVaaInfo->pVaaBackgroundMbFlag;
+    SetRefMbType (pCtx, & (sComplexityAnalysisParam->uiRefMbType), pRefPicture->iPictureType);
+    sComplexityAnalysisParam->iCalcBgd = bCalculateBGD;
+    sComplexityAnalysisParam->iFrameComplexity = 0;
+
+    memset (SWelsSvcRc->pGomForegroundBlockNum, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
+    if (iComplexityAnalysisMode != FRAME_SAD)
+      memset (SWelsSvcRc->pCurrentFrameGomSad, 0, SWelsSvcRc->iGomSize * sizeof (int32_t));
+
+    sComplexityAnalysisParam->pGomComplexity = SWelsSvcRc->pCurrentFrameGomSad;
+    sComplexityAnalysisParam->pGomForegroundBlockNum = SWelsSvcRc->pGomForegroundBlockNum;
+    sComplexityAnalysisParam->iMbNumInGom = SWelsSvcRc->iNumberMbGom;
+
+    {
+      int32_t iMethodIdx = METHOD_COMPLEXITY_ANALYSIS;
+      SPixMap sSrcPixMap;
+      SPixMap sRefPixMap;
+      memset (&sSrcPixMap, 0, sizeof (SPixMap));
+      memset (&sRefPixMap, 0, sizeof (SPixMap));
+      int32_t iRet = 0;
+
+      sSrcPixMap.pPixel[0] = pCurPicture->pData[0];
+      sSrcPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+      sSrcPixMap.iStride[0] = pCurPicture->iLineSize[0];
+      sSrcPixMap.sRect.iRectWidth = pCurPicture->iWidthInPixel;
+      sSrcPixMap.sRect.iRectHeight = pCurPicture->iHeightInPixel;
+      sSrcPixMap.eFormat = VIDEO_FORMAT_I420;
+
+      sRefPixMap.pPixel[0] = pRefPicture->pData[0];
+      sRefPixMap.iSizeInBits = g_kiPixMapSizeInBits;
+      sRefPixMap.iStride[0] = pRefPicture->iLineSize[0];
+      sRefPixMap.sRect.iRectWidth = pRefPicture->iWidthInPixel;
+      sRefPixMap.sRect.iRectHeight = pRefPicture->iHeightInPixel;
+      sRefPixMap.eFormat = VIDEO_FORMAT_I420;
+
+      iRet = m_pInterfaceVp->Set (iMethodIdx, (void*)sComplexityAnalysisParam);
+      iRet = m_pInterfaceVp->Process (iMethodIdx, &sSrcPixMap, &sRefPixMap);
+      if (iRet == 0)
+        m_pInterfaceVp->Get (iMethodIdx, (void*)sComplexityAnalysisParam);
+    }
+  }
+}
+
+
+void CWelsPreProcess::InitPixMap (const SPicture* pPicture, SPixMap* pPixMap) {
+  pPixMap->pPixel[0] = pPicture->pData[0];
+  pPixMap->pPixel[1] = pPicture->pData[1];
+  pPixMap->pPixel[2] = pPicture->pData[2];
+  pPixMap->iSizeInBits = sizeof (uint8_t);
+  pPixMap->iStride[0] = pPicture->iLineSize[0];
+  pPixMap->iStride[1] = pPicture->iLineSize[1];
+  pPixMap->sRect.iRectWidth = pPicture->iWidthInPixel;
+  pPixMap->sRect.iRectHeight = pPicture->iHeightInPixel;
+
+  pPixMap->eFormat = VIDEO_FORMAT_I420;
+}
+void CWelsPreProcess::GetAvailableRefList (SPicture** pSrcPicList, uint8_t iCurTid, const int32_t iClosestLtrFrameNum,
+    SRefInfoParam* pAvailableRefList, int32_t& iAvailableRefNum, int32_t& iAvailableSceneRefNum) {
+  SWelsSvcCodingParam*		pSvcParam = m_pEncCtx->pSvcParam;
+  const int32_t iSourcePicNum = pSvcParam->iNumRefFrame;
+  if (0 >= iSourcePicNum) {
+    iAvailableRefNum = 0;
+    iAvailableSceneRefNum = 0;
+    return ;
+  }
+  const bool bCurFrameMarkedAsSceneLtr = m_pEncCtx->bCurFrameMarkedAsSceneLtr;
+  SPicture* pRefPic = NULL;
+  uint8_t uiRefTid = 0;
+  bool bRefRealLtr = false;
+
+  iAvailableRefNum = 1; //zero is left for the closest frame
+  iAvailableSceneRefNum = 0;
+
+  //the saving order will be depend on pSrcPicList
+  //TODO: use a frame_idx to find the closer ref in time distance, and correctly sort the ref list
+  for (int32_t i = iSourcePicNum - 1; i >= 0; --i) {
+    pRefPic = pSrcPicList[i];
+    if (NULL == pRefPic || !pRefPic->bUsedAsRef || !pRefPic->bIsLongRef || (bCurFrameMarkedAsSceneLtr
+        && (!pRefPic->bIsSceneLTR))) {
+      continue;
+    }
+    uiRefTid = pRefPic->uiTemporalId;
+    bRefRealLtr = pRefPic->bIsSceneLTR;
+
+    if (bRefRealLtr || (0 == iCurTid && 0 == uiRefTid) || (uiRefTid < iCurTid)) {
+      int32_t idx = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum) ? (0) : (iAvailableRefNum++);
+      pAvailableRefList[idx].pRefPicture = pRefPic;
+      pAvailableRefList[idx].iSrcListIdx = i + 1; //in SrcList, the idx 0 is reserved for CurPic
+      iAvailableSceneRefNum += bRefRealLtr;
+    }
+  }
+
+  if (pAvailableRefList[0].pRefPicture == NULL) {
+    for (int32_t i = 1; i < iAvailableRefNum ; ++i) {
+      pAvailableRefList[i - 1].pRefPicture = pAvailableRefList[i].pRefPicture;
+      pAvailableRefList[i - 1].iSrcListIdx = pAvailableRefList[i].iSrcListIdx;
+    }
+
+    pAvailableRefList[iAvailableRefNum - 1].pRefPicture = NULL;
+    pAvailableRefList[iAvailableRefNum - 1].iSrcListIdx = 0;
+    --iAvailableRefNum;
+  }
+}
+
+
+void CWelsPreProcess::InitRefJudgement (SRefJudgement* pRefJudgement) {
+  pRefJudgement->iMinFrameComplexity = INT_MAX;
+  pRefJudgement->iMinFrameComplexity08 = INT_MAX;
+  pRefJudgement->iMinFrameComplexity11 = INT_MAX;
+
+  pRefJudgement->iMinFrameNumGap = INT_MAX;
+  pRefJudgement->iMinFrameQp = INT_MAX;
+}
+bool CWelsPreProcess::JudgeBestRef (SPicture* pRefPic, const SRefJudgement& sRefJudgement,
+                                    const int32_t iFrameComplexity, const bool bIsClosestLtrFrame) {
+  return (bIsClosestLtrFrame ? (iFrameComplexity < sRefJudgement.iMinFrameComplexity11) :
+          ((iFrameComplexity < sRefJudgement.iMinFrameComplexity08) || ((iFrameComplexity <= sRefJudgement.iMinFrameComplexity11)
+              && (pRefPic->iFrameAverageQp < sRefJudgement.iMinFrameQp))));
+}
+
+void CWelsPreProcess::SaveBestRefToJudgement (const int32_t iRefPictureAvQP, const int32_t iComplexity,
+    SRefJudgement* pRefJudgement) {
+  pRefJudgement->iMinFrameQp = iRefPictureAvQP;
+  pRefJudgement->iMinFrameComplexity =  iComplexity;
+  pRefJudgement->iMinFrameComplexity08 = static_cast<int32_t> (iComplexity * 0.8);
+  pRefJudgement->iMinFrameComplexity11 = static_cast<int32_t> (iComplexity * 1.1);
+}
+void CWelsPreProcess::SaveBestRefToLocal (SRefInfoParam* pRefPicInfo, const SSceneChangeResult& sSceneChangeResult,
+    SRefInfoParam* pRefSaved) {
+  pRefSaved->iSrcListIdx = pRefPicInfo->iSrcListIdx;
+  pRefSaved->bSceneLtrFlag = pRefPicInfo->bSceneLtrFlag;
+}
+
+void CWelsPreProcess::SaveBestRefToVaa (SRefInfoParam& sRefSaved, SRefInfoParam* pVaaBestRef) {
+  (*pVaaBestRef) = sRefSaved;
+}
+
+ESceneChangeIdc CWelsPreProcess::DetectSceneChangeScreen (sWelsEncCtx* pCtx, SPicture* pCurPicture) {
+#define STATIC_SCENE_MOTION_RATIO 0.01f
+  SWelsSvcCodingParam* pSvcParam = pCtx->pSvcParam;
+  SVAAFrameInfoExt* pVaaExt			= static_cast<SVAAFrameInfoExt*> (pCtx->pVaa);
+  if (NULL == pCtx || NULL == pVaaExt || NULL == pCurPicture) {
+    return LARGE_CHANGED_SCENE;
+  }
+
+  const int32_t iTargetDid = pSvcParam->iSpatialLayerNum - 1;
+  if (0 != iTargetDid) {
+    return LARGE_CHANGED_SCENE;
+  }
+
+  ESceneChangeIdc iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
+  SPicture** pSrcPicList = &m_pSpatialPic[iTargetDid][1];
+  if (NULL == pSrcPicList) {
+    return LARGE_CHANGED_SCENE;
+  }
+
+  SRefInfoParam sAvailableRefList[MAX_REF_PIC_COUNT] = { { 0 } };
+  int32_t iAvailableRefNum = 0;
+  int32_t iAvailableSceneRefNum = 0;
+
+  int32_t iSceneChangeMethodIdx = METHOD_SCENE_CHANGE_DETECTION_SCREEN;
+  SSceneChangeResult sSceneChangeResult = {SIMILAR_SCENE, 0, 0, NULL};
+
+  SPixMap sSrcMap = { { 0 } };
+  SPixMap sRefMap = { { 0 } };
+  SRefJudgement sLtrJudgement;
+  SRefJudgement sSceneLtrJudgement;
+  SRefInfoParam sLtrSaved = {0};
+  SRefInfoParam sSceneLtrSaved = {0};
+
+  int32_t iNumOfLargeChange = 0, iNumOfMediumChangeToLtr = 0;
+
+  bool bBestRefIsLtr = false, bIsClosestLtrFrame = false;
+  int32_t ret = 1, iScdIdx = 0;
+
+  SPicture* pRefPic = NULL;
+  SRefInfoParam* pRefPicInfo = NULL;
+  uint8_t*  pCurBlockStaticPointer = NULL;
+  uint8_t*  pBestStrBlockStaticPointer = NULL;
+  uint8_t*  pBestLtrBlockStaticPointer = NULL;
+
+  const int32_t iNegligibleMotionBlocks = (static_cast<int32_t> ((pCurPicture->iWidthInPixel >> 3) *
+                                          (pCurPicture->iHeightInPixel >> 3) * STATIC_SCENE_MOTION_RATIO));
+  const uint8_t iCurTid = GetTemporalLevel (&pSvcParam->sDependencyLayers[m_pEncCtx->sSpatialIndexMap[0].iDid],
+                          m_pEncCtx->iCodingIndex, pSvcParam->uiGopSize);
+  const int32_t iClosestLtrFrameNum = pCtx->pLtr[iTargetDid].iLastLtrIdx[iCurTid];//TBD
+  GetAvailableRefList (pSrcPicList, iCurTid, iClosestLtrFrameNum, &sAvailableRefList[0], iAvailableRefNum,
+                       iAvailableSceneRefNum);
+  //after this build, pAvailableRefList[idx].iSrcListIdx is the idx of the ref in h->spatial_pic
+  if (0 == iAvailableRefNum) {
+    WelsLog (pCtx, WELS_LOG_ERROR, "SceneChangeDetect() iAvailableRefNum=0 but not I.\n");
+    return LARGE_CHANGED_SCENE;
+  }
+
+  InitPixMap (pCurPicture, &sSrcMap);
+  InitRefJudgement (&sLtrJudgement);
+  InitRefJudgement (&sSceneLtrJudgement);
+
+  for (iScdIdx = 0; iScdIdx < iAvailableRefNum; iScdIdx ++) {
+    pCurBlockStaticPointer = pVaaExt->pVaaBlockStaticIdc[iScdIdx];
+    sSceneChangeResult.eSceneChangeIdc = SIMILAR_SCENE;
+    sSceneChangeResult.pStaticBlockIdc = pCurBlockStaticPointer;//
+
+    pRefPicInfo = & (sAvailableRefList[iScdIdx]);
+    assert (NULL != pRefPicInfo);
+    pRefPic = pRefPicInfo->pRefPicture;
+    InitPixMap (pRefPic, &sRefMap);
+
+    bIsClosestLtrFrame = (pRefPic->iLongTermPicNum == iClosestLtrFrameNum);
+
+    //TBD scrolling detection
+    m_pInterfaceVp->Set (iSceneChangeMethodIdx, (void*) (&sSceneChangeResult));
+    ret = m_pInterfaceVp->Process (iSceneChangeMethodIdx, &sSrcMap, &sRefMap);
+
+    if (ret == 0) {
+      m_pInterfaceVp->Get (iSceneChangeMethodIdx, (void*)&sSceneChangeResult);
+
+      const int32_t iFrameComplexity = sSceneChangeResult.iFrameComplexity;
+      const int32_t iSceneDetectIdc = sSceneChangeResult.eSceneChangeIdc;
+      const int32_t iMotionBlockNum = sSceneChangeResult.iMotionBlockNum;
+
+      const bool bCurRefIsLtr = pRefPic->bIsSceneLTR;
+      const int32_t iRefPicAvQP = pRefPic->iFrameAverageQp;
+
+      //for scene change detection
+      iNumOfLargeChange += (static_cast<int32_t> (LARGE_CHANGED_SCENE == iSceneDetectIdc));
+      iNumOfMediumChangeToLtr += (static_cast<int32_t> ((bCurRefIsLtr) && (iSceneDetectIdc != SIMILAR_SCENE)));
+
+      //for reference selection
+      //this judge can only be saved when iAvailableRefNum==1, which is very limit
+      //when LTR is OFF, it can still judge from all available STR
+      if (JudgeBestRef (pRefPic, sLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
+        SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sLtrJudgement);
+        SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sLtrSaved);
+        bBestRefIsLtr = bCurRefIsLtr;
+        pBestStrBlockStaticPointer = sSceneChangeResult.pStaticBlockIdc;
+      }
+      if (bCurRefIsLtr && JudgeBestRef (pRefPic, sSceneLtrJudgement, iFrameComplexity, bIsClosestLtrFrame)) {
+        SaveBestRefToJudgement (iRefPicAvQP, iFrameComplexity, &sSceneLtrJudgement);
+        SaveBestRefToLocal (pRefPicInfo, sSceneChangeResult, &sSceneLtrSaved);
+        pBestLtrBlockStaticPointer = sSceneChangeResult.pStaticBlockIdc;
+      }
+
+      if (iMotionBlockNum <= iNegligibleMotionBlocks) {
+        break;
+      }
+    }
+  }
+
+  if (iNumOfLargeChange == iAvailableRefNum) {
+    iVaaFrameSceneChangeIdc = LARGE_CHANGED_SCENE;
+  } else if ((iNumOfMediumChangeToLtr == iAvailableSceneRefNum) && (0 != iAvailableSceneRefNum)) {
+    iVaaFrameSceneChangeIdc = MEDIUM_CHANGED_SCENE;
+  } else {
+    iVaaFrameSceneChangeIdc = SIMILAR_SCENE;
+  }
+
+  WelsLog(pCtx,WELS_LOG_INFO,"iVaaFrameSceneChangeIdc = %d,codingIdx = %d\n",iVaaFrameSceneChangeIdc,pCtx->iCodingIndex);
+
+  SaveBestRefToVaa (sLtrSaved, & (pVaaExt->sVaaStrBestRefCandidate[0]));
+
+  if (0 == iAvailableSceneRefNum) {
+    SaveBestRefToVaa (sSceneLtrSaved, & (pVaaExt->sVaaStrBestRefCandidate[1]));
+  }
+
+  pVaaExt->iNumOfAvailableRef = 1;
+  return static_cast<ESceneChangeIdc> (iVaaFrameSceneChangeIdc);
+}
+
+int32_t CWelsPreProcess::GetRefCandidateLtrIndex (int32_t iRefIdx) {
+  const int32_t iTargetDid = m_pEncCtx->pSvcParam->iSpatialLayerNum - 1;
+  SVAAFrameInfoExt* pVaaExt			= static_cast<SVAAFrameInfoExt*> (m_pEncCtx->pVaa);
+  SRefInfoParam* BestRefCandidateParam = & (pVaaExt->sVaaStrBestRefCandidate[iRefIdx]);
+  int32_t iLtrRefIdx = m_pSpatialPic[iTargetDid][BestRefCandidateParam->iSrcListIdx]->iLongTermPicNum;
+  return iLtrRefIdx;
+}
+void  CWelsPreProcess::Padding (uint8_t* pSrcY, uint8_t* pSrcU, uint8_t* pSrcV, int32_t iStrideY, int32_t iStrideUV,
+                                int32_t iActualWidth, int32_t iPaddingWidth, int32_t iActualHeight, int32_t iPaddingHeight) {
+  int32_t i;
+
+  if (iPaddingHeight > iActualHeight) {
+    for (i = iActualHeight; i < iPaddingHeight; i++) {
+      memset (pSrcY + i * iStrideY, 0, iActualWidth);
+
+      if (! (i & 1)) {
+        memset (pSrcU + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
+        memset (pSrcV + i / 2 * iStrideUV, 0x80, iActualWidth / 2);
+      }
+    }
+  }
+
+  if (iPaddingWidth > iActualWidth) {
+    for (i = 0; i < iPaddingHeight; i++) {
+      memset (pSrcY + i * iStrideY + iActualWidth, 0, iPaddingWidth - iActualWidth);
+      if (! (i & 1)) {
+        memset (pSrcU + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
+        memset (pSrcV + i / 2 * iStrideUV + iActualWidth / 2, 0x80, (iPaddingWidth - iActualWidth) / 2);
+      }
+    }
+  }
+}
+
+
+//TODO: may opti later
+//TODO: not use this func?
+void* WelsMemcpy (void* dst, const void* kpSrc, uint32_t uiSize) {
+  return ::memcpy (dst, kpSrc, uiSize);
+}
+void* WelsMemset (void* p, int32_t val, uint32_t uiSize) {
+  return ::memset (p, val, uiSize);
+}
+
+//i420_to_i420_c
+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) {
+  int32_t   iWidth2 = iWidth >> 1;
+  int32_t   iHeight2 = iHeight >> 1;
+  int32_t   j;
+
+  for (j = iHeight; j; j--) {
+    WelsMemcpy (pDstY, pSrcY, iWidth);
+    pDstY += iDstStrideY;
+    pSrcY += iSrcStrideY;
+  }
+
+  for (j = iHeight2; j; j--) {
+    WelsMemcpy (pDstU, pSrcU, iWidth2);
+    WelsMemcpy (pDstV, pSrcV, iWidth2);
+    pDstU += iDstStrideUV;
+    pDstV += iDstStrideUV;
+    pSrcU += iSrcStrideUV;
+    pSrcV += iSrcStrideUV;
+  }
+}
+
+void  CWelsPreProcess::WelsMoveMemoryWrapper (SWelsSvcCodingParam* pSvcParam, SPicture* pDstPic,
+    const SSourcePicture* kpSrc,
+    const int32_t kiTargetWidth, const int32_t kiTargetHeight) {
+  if (VIDEO_FORMAT_I420 != (kpSrc->iColorFormat & (~VIDEO_FORMAT_VFlip)))
+    return;
+
+  int32_t  iSrcWidth       = kpSrc->iPicWidth;
+  int32_t  iSrcHeight      = kpSrc->iPicHeight;
+
+  if (iSrcHeight > kiTargetHeight) 	iSrcHeight = kiTargetHeight;
+  if (iSrcWidth > kiTargetWidth)		iSrcWidth  = kiTargetWidth;
+
+  // copy from fr26 to fix the odd uiSize failed issue
+  if (iSrcWidth & 0x1)		-- iSrcWidth;
+  if (iSrcHeight & 0x1)		-- iSrcHeight;
+
+  const int32_t kiSrcTopOffsetY = pSvcParam->SUsedPicRect.iTop;
+  const int32_t kiSrcTopOffsetUV = (kiSrcTopOffsetY >> 1);
+  const int32_t kiSrcLeftOffsetY = pSvcParam->SUsedPicRect.iLeft;
+  const int32_t kiSrcLeftOffsetUV = (kiSrcLeftOffsetY >> 1);
+  int32_t  iSrcOffset[3]       = {0, 0, 0};
+  iSrcOffset[0] = kpSrc->iStride[0] * kiSrcTopOffsetY + kiSrcLeftOffsetY;
+  iSrcOffset[1] = kpSrc->iStride[1] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV ;
+  iSrcOffset[2] = kpSrc->iStride[2] * kiSrcTopOffsetUV + kiSrcLeftOffsetUV;
+
+  uint8_t* pSrcY = kpSrc->pData[0] + iSrcOffset[0];
+  uint8_t* pSrcU = kpSrc->pData[1] + iSrcOffset[1];
+  uint8_t* pSrcV = kpSrc->pData[2] + iSrcOffset[2];
+  const int32_t kiSrcStrideY = kpSrc->iStride[0];
+  const int32_t kiSrcStrideUV = kpSrc->iStride[1];
+
+  uint8_t* pDstY = pDstPic->pData[0];
+  uint8_t* pDstU = pDstPic->pData[1];
+  uint8_t* pDstV = pDstPic->pData[2];
+  const int32_t kiDstStrideY = pDstPic->iLineSize[0];
+  const int32_t kiDstStrideUV = pDstPic->iLineSize[1];
+
+#define MAX_WIDTH      (4096)
+#define MAX_HEIGHT     (2304)//MAX_FS_LEVEL51 (36864); MAX_FS_LEVEL51*256/4096 = 2304
+  if (pSrcY) {
+    if (iSrcWidth <= 0 || iSrcWidth > MAX_WIDTH || iSrcHeight <= 0 || iSrcHeight > MAX_HEIGHT)
+      return;
+    if (kiSrcTopOffsetY >= iSrcHeight || kiSrcLeftOffsetY >= iSrcWidth || iSrcWidth > kiSrcStrideY)
+      return;
+  }
+  if (pDstY) {
+    if (kiTargetWidth <= 0 || kiTargetWidth > MAX_WIDTH || kiTargetHeight <= 0 || kiTargetHeight > MAX_HEIGHT)
+      return;
+    if (kiTargetWidth > kiDstStrideY)
+      return;
+  }
+
+  if (pSrcY == NULL || pSrcU == NULL || pSrcV == NULL || pDstY == NULL || pDstU == NULL || pDstV == NULL
+      || (iSrcWidth & 1) || (iSrcHeight & 1)) {
+  } else {
+    //i420_to_i420_c
+    WelsMoveMemory_c (pDstY,  pDstU,  pDstV,  kiDstStrideY, kiDstStrideUV,
+                      pSrcY,  pSrcU,  pSrcV, kiSrcStrideY, kiSrcStrideUV, iSrcWidth, iSrcHeight);
+
+    //in VP Process
+    if (kiTargetWidth > iSrcWidth || kiTargetHeight > iSrcHeight) {
+      Padding (pDstY, pDstU, pDstV, kiDstStrideY, kiDstStrideUV, iSrcWidth, kiTargetWidth, iSrcHeight, kiTargetHeight);
+    }
+  }
+
+}
+
+//*********************************************************************************************************/
+} // namespace WelsSVCEnc
--- a/test/encoder/EncUT_MotionEstimate.cpp
+++ b/test/encoder/EncUT_MotionEstimate.cpp
@@ -7,6 +7,15 @@
 #include "wels_func_ptr_def.h"
 #include "cpu.h"
 
+namespace WelsSVCEnc {
+  extern void SetFeatureSearchIn( SWelsFuncPtrList *pFunc,  const SWelsME& sMe,
+                                 const SSlice *pSlice, SScreenBlockFeatureStorage* pRefFeatureStorage,
+                                 const int32_t kiEncStride, const int32_t kiRefStride,
+                                 SFeatureSearchIn* pFeatureSearchIn );
+  extern void MotionEstimateFeatureFullSearch( SFeatureSearchIn &sFeatureSearchIn,
+                                              const uint32_t kuiMaxSearchPoint,
+                                              SWelsME* pMe);
+}
 
 using namespace WelsSVCEnc;
 
@@ -32,10 +41,14 @@
   pMe->sMv.iMvX = pMe->sMv.iMvY = 0;
 }
 
+static inline int GetRandomMv(int32_t iMin, int32_t iMax) {
+  return (rand()%(iMax-iMin)-(iMax-iMin)/2);
+}
+
 class MotionEstimateTest : public ::testing::Test {
 public:
   virtual void SetUp() {
-    m_pRefPic = NULL;
+    m_pRefData = NULL;
     m_pSrcBlock = NULL;
     m_pMvdCostTable = NULL;
 
@@ -45,9 +58,9 @@
     m_uiMvdTableSize	=  (1 + (648 << 1));
 
     pMa = new CMemoryAlign(0);
-    m_pRefPic = static_cast<uint8_t *>
+    m_pRefData = static_cast<uint8_t *>
     (pMa->WelsMalloc(m_iWidth*m_iHeight, "RefPic"));
-    ASSERT_TRUE( NULL != m_pRefPic );
+    ASSERT_TRUE( NULL != m_pRefData );
     m_pSrcBlock = static_cast<uint8_t *>
     (pMa->WelsMalloc(m_iMaxSearchBlock*m_iMaxSearchBlock, "SrcBlock"));
     ASSERT_TRUE( NULL != m_pSrcBlock );
@@ -56,12 +69,12 @@
   }
   virtual void TearDown() {
     delete [] m_pMvdCostTable;
-    pMa->WelsFree( m_pRefPic, "RefPic");
+    pMa->WelsFree( m_pRefData, "RefPic");
     pMa->WelsFree( m_pSrcBlock, "SrcBlock");
     delete pMa;
   }
 public:
-  uint8_t *m_pRefPic;
+  uint8_t *m_pRefData;
   uint8_t *m_pSrcBlock;
   uint32_t m_uiMvdTableSize;
   uint16_t *m_pMvdCostTable;
@@ -88,7 +101,7 @@
   SMVUnitXY sTargetMv;
   WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
 
-  uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
+  uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
   bool bDataGeneratorSucceed = false;
   bool bFoundMatch = false;
   int32_t i, iTryTimes;
@@ -99,7 +112,7 @@
     bDataGeneratorSucceed = false;
     bFoundMatch = false;
     while (!bFoundMatch && (iTryTimes--)>0) {
-      if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth ))
+      if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
         continue;
 
       bDataGeneratorSucceed = true;
@@ -138,7 +151,7 @@
   SMVUnitXY sTargetMv;
   WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
 
-  uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
+  uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
   sMe.iCurMeBlockPixX = (m_iWidth/2);
   sMe.iCurMeBlockPixY = (m_iHeight/2);
 
@@ -151,7 +164,7 @@
   bDataGeneratorSucceed = false;
   bFoundMatch = false;
   while (!bFoundMatch && (iTryTimes--)>0) {
-    if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth ))
+    if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
       continue;
 
     bDataGeneratorSucceed = true;
@@ -199,7 +212,7 @@
   SMVUnitXY sTargetMv;
   WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
 
-  uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
+  uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
   sMe.iCurMeBlockPixX = (m_iWidth/2);
   sMe.iCurMeBlockPixY = (m_iHeight/2);
 
@@ -212,7 +225,7 @@
   bDataGeneratorSucceed = false;
   bFoundMatch = false;
   while (!bFoundMatch && (iTryTimes--)>0) {
-    if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth ))
+    if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
       continue;
 
     bDataGeneratorSucceed = true;
@@ -267,7 +280,7 @@
   WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
   WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1);
 
-  uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
+  uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
   sMe.iCurMeBlockPixX = (m_iWidth/2);
   sMe.iCurMeBlockPixY = (m_iHeight/2);
 
@@ -280,7 +293,7 @@
   bDataGeneratorSucceed = false;
   bFoundMatch = false;
   while (!bFoundMatch && (iTryTimes--)>0) {
-    if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth ))
+    if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
       continue;
 
     bDataGeneratorSucceed = true;
@@ -333,7 +346,7 @@
   WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
   WelsInitMeFunc(&sFuncList, WELS_CPU_SSE41, 1);
 
-  uint8_t *pRefPicCenter = m_pRefPic+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
+  uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
   sMe.iCurMeBlockPixX = (m_iWidth/2);
   sMe.iCurMeBlockPixY = (m_iHeight/2);
 
@@ -346,13 +359,12 @@
   bDataGeneratorSucceed = false;
   bFoundMatch = false;
   while (!bFoundMatch && (iTryTimes--)>0) {
-    if (!YUVPixelDataGenerator( m_pRefPic, m_iWidth, m_iHeight, m_iWidth ))
+    if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
       continue;
-
     bDataGeneratorSucceed = true;
-    CopyTargetBlock( m_pSrcBlock, 16, sTargetMv, m_iWidth, pRefPicCenter);
+    CopyTargetBlock( m_pSrcBlock, m_iMaxSearchBlock, sTargetMv, m_iWidth, pRefPicCenter );
 
-    //clean the sMe status
+    //clean sMe status
     sMe.uiBlockSize = rand()%5;
     sMe.pEncMb = m_pSrcBlock;
     sMe.pRefMb = pRefPicCenter;
@@ -383,3 +395,167 @@
   }
 }
 #endif
+
+class FeatureMotionEstimateTest : public ::testing::Test {
+public:
+  virtual void SetUp() {
+    m_pRefData = NULL;
+    m_pSrcBlock = NULL;
+    m_pMvdCostTable = NULL;
+
+    m_iWidth = 64;//size of search window
+    m_iHeight = 64;//size of search window
+    m_iMaxSearchBlock = 8;
+    m_uiMvdTableSize	=  (1 + (648 << 1));
+
+    m_pMa = new CMemoryAlign(16);
+    ASSERT_TRUE( NULL != m_pMa );
+    m_pRefData = (uint8_t*)m_pMa->WelsMalloc (m_iWidth*m_iHeight*sizeof (uint8_t), "m_pRefData");
+    ASSERT_TRUE( NULL != m_pRefData );
+    m_pSrcBlock = (uint8_t*)m_pMa->WelsMalloc (m_iMaxSearchBlock*m_iMaxSearchBlock*sizeof (uint8_t), "m_pSrcBlock");
+    ASSERT_TRUE( NULL != m_pSrcBlock );
+    m_pMvdCostTable = (uint16_t*)m_pMa->WelsMalloc (52*m_uiMvdTableSize*sizeof (uint16_t), "m_pMvdCostTable");
+    ASSERT_TRUE( NULL != m_pMvdCostTable );
+    m_pFeatureSearchPreparation = (SFeatureSearchPreparation*)m_pMa->WelsMalloc (sizeof (SFeatureSearchPreparation), "m_pFeatureSearchPreparation");
+    ASSERT_TRUE( NULL != m_pFeatureSearchPreparation );
+    m_pScreenBlockFeatureStorage = (SScreenBlockFeatureStorage*)m_pMa->WelsMalloc (sizeof (SScreenBlockFeatureStorage), "m_pScreenBlockFeatureStorage");
+    ASSERT_TRUE( NULL != m_pScreenBlockFeatureStorage );
+  }
+  virtual void TearDown() {
+    if (m_pMa) {
+      if (m_pRefData) {
+        m_pMa->WelsFree(m_pRefData, "m_pRefData");
+        m_pRefData = NULL;
+      }
+      if (m_pSrcBlock) {
+        m_pMa->WelsFree(m_pSrcBlock, "m_pSrcBlock");
+        m_pSrcBlock = NULL;
+      }
+      if (m_pMvdCostTable) {
+        m_pMa->WelsFree(m_pMvdCostTable, "m_pMvdCostTable");
+        m_pMvdCostTable = NULL;
+      }
+
+      if (m_pFeatureSearchPreparation) {
+        ReleaseFeatureSearchPreparation( m_pMa, m_pFeatureSearchPreparation->pFeatureOfBlock);
+        m_pMa->WelsFree(m_pFeatureSearchPreparation, "m_pFeatureSearchPreparation");
+        m_pFeatureSearchPreparation = NULL;
+      }
+      if (m_pScreenBlockFeatureStorage) {
+        ReleaseScreenBlockFeatureStorage( m_pMa, m_pScreenBlockFeatureStorage );
+        m_pMa->WelsFree(m_pScreenBlockFeatureStorage, "m_pScreenBlockFeatureStorage");
+        m_pScreenBlockFeatureStorage = NULL;
+      }
+      delete m_pMa;
+      m_pMa = NULL;
+    }
+  }
+  void InitRefPicForMeTest(SPicture* pRefPic) {
+    pRefPic->pData[0] = m_pRefData;
+    pRefPic->iLineSize[0] = m_iWidth;
+    pRefPic->iFrameAverageQp = rand()%52;
+    pRefPic->iWidthInPixel = m_iWidth;
+    pRefPic->iHeightInPixel = m_iHeight;
+  }
+public:
+  CMemoryAlign* m_pMa;
+
+  SFeatureSearchPreparation* m_pFeatureSearchPreparation;
+  SScreenBlockFeatureStorage* m_pScreenBlockFeatureStorage;
+
+  uint8_t *m_pRefData;
+  uint8_t *m_pSrcBlock;
+  uint16_t *m_pMvdCostTable;
+  uint32_t m_uiMvdTableSize;
+
+  int32_t m_iWidth;
+  int32_t m_iHeight;
+  int32_t m_iMaxSearchBlock;
+};
+
+TEST_F(FeatureMotionEstimateTest, TestFeatureSearch) {
+  const int32_t kiMaxBlock16Sad = 72000;//a rough number
+  SWelsFuncPtrList sFuncList;
+  WelsInitSampleSadFunc( &sFuncList, 0 );//test c functions
+  WelsInitMeFunc( &sFuncList, 0, true );
+
+  SWelsME sMe;
+  srand((uint32_t)time(NULL));
+  const uint8_t kuiQp = rand()%52;
+  InitMe(kuiQp, 648, m_uiMvdTableSize, m_pMvdCostTable, &sMe);
+  sMe.iCurMeBlockPixX = (m_iWidth/2);
+  sMe.iCurMeBlockPixY = (m_iHeight/2);
+  uint8_t *pRefPicCenter = m_pRefData+(m_iHeight/2)*m_iWidth+(m_iWidth/2);
+
+  SPicture sRef;
+  InitRefPicForMeTest(&sRef);
+
+  SSlice sSlice;
+  const int32_t kiSupposedPaddingLength=16;
+  SetMvWithinIntegerMvRange( m_iWidth/16-kiSupposedPaddingLength, m_iHeight/16-kiSupposedPaddingLength,
+    m_iWidth/2/16, m_iHeight/2/16, 508,
+    &(sSlice.sMvStartMin), &(sSlice.sMvStartMax));
+  int32_t iReturn;
+  const int32_t kiNeedFeatureStorage = ME_DIA_CROSS_FME;
+  iReturn = RequestFeatureSearchPreparation( m_pMa, m_iWidth,  m_iHeight, kiNeedFeatureStorage,
+    m_pFeatureSearchPreparation);
+  ASSERT_TRUE( ENC_RETURN_SUCCESS==iReturn );
+  iReturn = RequestScreenBlockFeatureStorage( m_pMa, m_iWidth, m_iHeight, kiNeedFeatureStorage,
+    m_pScreenBlockFeatureStorage);
+  ASSERT_TRUE( ENC_RETURN_SUCCESS==iReturn );
+
+  SMVUnitXY sTargetMv;
+  for (int i=sSlice.sMvStartMin.iMvX; i<=sSlice.sMvStartMax.iMvX;i++) {
+    for (int j=sSlice.sMvStartMin.iMvY; j<=sSlice.sMvStartMax.iMvY;j++) {
+      if ( i==0 || j==0) continue;//exclude x=0 or y=0 since that will be skipped by FME
+
+      bool bDataGeneratorSucceed = false;
+      bool bFoundMatch = false;
+
+      if (!YUVPixelDataGenerator( m_pRefData, m_iWidth, m_iHeight, m_iWidth ))
+        continue;
+      bDataGeneratorSucceed = true;
+
+      sTargetMv.iMvX = i;
+      sTargetMv.iMvY = j;
+      CopyTargetBlock( m_pSrcBlock, m_iMaxSearchBlock, sTargetMv, m_iWidth, pRefPicCenter );
+
+      //clean sMe status
+      sMe.uiBlockSize = BLOCK_8x8;
+      sMe.pEncMb = m_pSrcBlock;
+      sMe.pRefMb = pRefPicCenter;
+      sMe.pColoRefMb = pRefPicCenter;
+      sMe.sMv.iMvX = sMe.sMv.iMvY = 0;
+      sMe.uiSadCost = sMe.uiSatdCost = kiMaxBlock16Sad;
+
+      //begin FME process
+      PerformFMEPreprocess(&sFuncList, &sRef, m_pFeatureSearchPreparation->pFeatureOfBlock,
+        m_pScreenBlockFeatureStorage);
+      m_pScreenBlockFeatureStorage->uiSadCostThreshold[BLOCK_8x8] = UINT_MAX;//to avoid early skip
+      uint32_t uiMaxSearchPoint = INT_MAX;
+      SFeatureSearchIn sFeatureSearchIn = {0};
+      SetFeatureSearchIn(&sFuncList, sMe, &sSlice, m_pScreenBlockFeatureStorage,
+        m_iMaxSearchBlock, m_iWidth,
+        &sFeatureSearchIn);
+      MotionEstimateFeatureFullSearch( sFeatureSearchIn, uiMaxSearchPoint, &sMe);
+
+      bool bMvMatch  = sMe.sMv.iMvX==sTargetMv.iMvX && sMe.sMv.iMvY==sTargetMv.iMvY;
+      bool bFeatureMatch =
+        ( *(m_pScreenBlockFeatureStorage->pFeatureOfBlockPointer +(m_iHeight/2+sTargetMv.iMvY)*(m_iWidth-8)+(m_iWidth/2+sTargetMv.iMvX))
+        == *(m_pScreenBlockFeatureStorage->pFeatureOfBlockPointer +(m_iHeight/2+sMe.sMv.iMvY)*(m_iWidth-8)+(m_iWidth/2+sMe.sMv.iMvX)) )
+        && ((sMe.pMvdCost[sMe.sMv.iMvY<<2]+sMe.pMvdCost[sMe.sMv.iMvX<<2]) <= (sMe.pMvdCost[sTargetMv.iMvY<<2]+sMe.pMvdCost[sTargetMv.iMvX<<2]));
+
+      //the last selection may be affected by MVDcost, that is when smaller Mv will be better
+      bFoundMatch = bMvMatch || bFeatureMatch;
+
+      if (bDataGeneratorSucceed) {
+        //if DataGenerator never succeed, there is no meaning to check iTryTimes
+        if (!bFoundMatch) {
+          printf("TestFeatureSearch Target: %d,%d, Result: %d,%d\n", sTargetMv.iMvX, sTargetMv.iMvY, sMe.sMv.iMvX, sMe.sMv.iMvY);
+        }
+        EXPECT_TRUE(bFoundMatch);
+      }
+    }
+  }
+}
+