shithub: openh264

Download patch

ref: c6e7814b57657d79607129b7c5711bd7d7820a12
parent: 51b2ff84fc7845e211d76561453637694b91e93c
author: lyao2 <lyao2@LYAO2-WS01.cisco.com>
date: Fri Jun 6 09:51:32 EDT 2014

add pskip MD functions

--- a/codec/encoder/core/inc/svc_base_layer_md.h
+++ b/codec/encoder/core/inc/svc_base_layer_md.h
@@ -104,7 +104,7 @@
 
 //typedef void (*MD_INTRA_MB_BASE) (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SMB* pCurMb);
 
-void WelsInitScrollingSkipFunc (SWelsFuncPtrList* pFuncList, const bool bScrollingDetection);
+void WelsInitSCDPskipFunc (SWelsFuncPtrList* pFuncList, const bool bScrollingDetection);
 
 }
 #endif//WELS_MACROBLOCK_MODE_DECISION_H__
--- a/codec/encoder/core/inc/svc_enc_frame.h
+++ b/codec/encoder/core/inc/svc_enc_frame.h
@@ -103,6 +103,7 @@
 
   SPicture*				pRefPic;			// reference picture pointer
   SPicture*				pDecPic;			// reconstruction picture pointer for layer
+  SPicture*       pRefOri;
 
   SSliceCtx*			pSliceEncCtx;	// current slice context
 
--- a/codec/encoder/core/inc/svc_mode_decision.h
+++ b/codec/encoder/core/inc/svc_mode_decision.h
@@ -41,6 +41,8 @@
 #ifndef SVC_MODE_DECISION_H
 #define SVC_MODE_DECISION_H
 #include "encoder_context.h"
+#include "svc_encode_mb.h"
+#include "svc_encode_slice.h"
 #include "svc_enc_macroblock.h"
 #include "md.h"
 
@@ -49,14 +51,23 @@
 ////////////////////////
 // INTERFACE, called by svc_encode_slice.c
 ///////////////////////
+#define DELTA_QP_SCD_THD 5
 
+typedef enum {
+  STATIC,
+  SCROLLED,
+} ESkipModes;
+
 // NOILP ILFMD ENTRANCE
 void WelsMdSpatialelInterMbIlfmdNoilp (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice, SMB* pCurMb,
                                        const Mb_Type kuiRefMbType);
 void WelsMdInterMbEnhancelayer (void* pEnc, void* pMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pMbCache);
-
 SMB* GetRefMb (SDqLayer* pCurLayer, SMB* pCurMb);
 void SetMvBaseEnhancelayer (SWelsMD* pMd, SMB* pCurMb, const SMB* kpRefMb);
+bool MdInterSCDPskipProcess (sWelsEncCtx* pEncCtx, SWelsMD* pMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pMbCache,
+                             ESkipModes eSkipMode);
+
+typedef bool (*pJudgeSkipFun) (sWelsEncCtx* pEncCtx, SMB* pCurMb, SMbCache* pMbCache, SWelsMD* pWelsMd);
 void SetBlockStaticIdcToMd (void* pVaa, void* pMd, SMB* pCurMb, void* pDqLay);
 }
 #endif //SVC_MODE_DECISION_H
--- a/codec/encoder/core/inc/wels_func_ptr_def.h
+++ b/codec/encoder/core/inc/wels_func_ptr_def.h
@@ -207,7 +207,7 @@
   PInterMdBackgroundDecisionFunc          pfInterMdBackgroundDecision;
   PInterMdBackgroundInfoUpdateFunc      pfInterMdBackgroundInfoUpdate;
 
-  PInterMdScrollingPSkipDecisionFunc pfScrollingPSkipDecision;
+  PInterMdScrollingPSkipDecisionFunc pfSCDPSkipDecision;
 
   SMcFunc                sMcFuncs;
   SSampleDealingFunc     sSampleDealingFuncs;
--- a/codec/encoder/core/src/encoder.cpp
+++ b/codec/encoder/core/src/encoder.cpp
@@ -192,7 +192,7 @@
 
   //
   WelsInitBGDFunc (pFuncList, pParam->bEnableBackgroundDetection);
-  WelsInitScrollingSkipFunc (pFuncList, bScreenContent && (pParam->bEnableSceneChangeDetect));
+  WelsInitSCDPskipFunc (pFuncList, bScreenContent && (pParam->bEnableSceneChangeDetect));
 
   // for pfGetVarianceFromIntraVaa function ptr adaptive by CPU features, 6/7/2010
   InitIntraAnalysisVaaInfo (pFuncList, uiCpuFlag);
--- a/codec/encoder/core/src/svc_base_layer_md.cpp
+++ b/codec/encoder/core/src/svc_base_layer_md.cpp
@@ -1647,7 +1647,7 @@
   }
 
   //try static or scrolled Pskip
-  if (pEncCtx->pFuncList->pfScrollingPSkipDecision (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache)) {
+  if (pEncCtx->pFuncList->pfSCDPSkipDecision (pEncCtx, pWelsMd, pSlice, pCurMb, pMbCache)) {
     return;
   }
 
--- a/codec/encoder/core/src/svc_mode_decision.cpp
+++ b/codec/encoder/core/src/svc_mode_decision.cpp
@@ -40,8 +40,9 @@
 
  **************************************************************************************
  */
+#include "mv_pred.h"
+#include "ls_defines.h"
 #include "svc_base_layer_md.h"
-
 #include "svc_mode_decision.h"
 
 namespace WelsSVCEnc {
@@ -49,6 +50,36 @@
 //
 // md in enhancement layer
 ///
+
+inline bool IsMbStatic (int32_t* pBlockType, EStaticBlockIdc eType) {
+  return (pBlockType != NULL &&
+          eType == pBlockType[0] &&
+          eType == pBlockType[1] &&
+          eType == pBlockType[2] &&
+          eType == pBlockType[3]);
+}
+inline bool IsMbCollocatedStatic (int32_t* pBlockType) {
+  return IsMbStatic (pBlockType, COLLOCATED_STATIC);
+}
+
+inline bool IsMbScrolledStatic (int32_t* pBlockType) {
+  return IsMbStatic (pBlockType, SCROLLED_STATIC);
+}
+
+inline int32_t CalUVSadCost (SWelsFuncPtrList* pFunc, uint8_t* pEncOri, int32_t iStrideUV, uint8_t* pRefOri,
+                             int32_t iRefLineSize) {
+  return pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_8x8] (pEncOri, iStrideUV, pRefOri, iRefLineSize);
+}
+
+inline bool CheckBorder (int32_t iMbX, int32_t iMbY, int32_t iScrollMvX, int32_t iScrollMvY, int32_t iMbWidth,
+                         int32_t iMbHeight) {
+  return ((iMbX << 4) + iScrollMvX < 0 ||
+          (iMbX << 4) + iScrollMvX > (iMbWidth - 1) << 4 ||
+          (iMbY << 4) + iScrollMvY < 0 ||
+          (iMbY << 4) + iScrollMvY > (iMbHeight - 1) << 4
+         ); //border check for safety
+}
+
 void WelsMdSpatialelInterMbIlfmdNoilp (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice,
                                        SMB* pCurMb, const Mb_Type kuiRefMbType) {
   SDqLayer* pCurDqLayer = pEncCtx->pCurDqLayer;
@@ -153,7 +184,181 @@
   }
 }
 
-void SetBlockStaticIdcToMd (void* pVaa, void* pMd, SMB* pCurMb, void* pDqLay) { //TODO: OPT?
+bool JudgeStaticSkip (sWelsEncCtx* pEncCtx, SMB* pCurMb, SMbCache* pMbCache, SWelsMD* pWelsMd) {
+  SDqLayer* pCurDqLayer			= pEncCtx->pCurDqLayer;
+  const int32_t kiMbX = pCurMb->iMbX;
+  const int32_t kiMbY = pCurMb->iMbY;
+
+  bool bTryStaticSkip = IsMbCollocatedStatic (pWelsMd->iBlock8x8StaticIdc);
+
+  if (bTryStaticSkip) {
+    int32_t iStrideUV, iOffsetUV;
+    SWelsFuncPtrList* pFunc = pEncCtx->pFuncList;
+    SPicture* pRefOri = pCurDqLayer->pRefOri;
+    if (pRefOri != NULL) {
+      iStrideUV	= pCurDqLayer->iEncStride[1];
+      iOffsetUV	= (kiMbX + kiMbY * iStrideUV) << 3;
+
+      int32_t iSadCostCb = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[1], iStrideUV, pRefOri->pData[1] + iOffsetUV,
+                                         pRefOri->iLineSize[1]);
+      if (iSadCostCb == 0) {
+        int32_t iSadCostCr = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[2], iStrideUV, pRefOri->pData[2] + iOffsetUV,
+                                           pRefOri->iLineSize[1]);
+        bTryStaticSkip = (0 == iSadCostCr);
+      } else bTryStaticSkip = false;
+    }
+  }
+  return bTryStaticSkip;
+}
+
+bool JudgeScrollSkip (sWelsEncCtx* pEncCtx, SMB* pCurMb, SMbCache* pMbCache, SWelsMD* pWelsMd) {
+  SDqLayer* pCurDqLayer			= pEncCtx->pCurDqLayer;
+  const int32_t kiMbX = pCurMb->iMbX;
+  const int32_t kiMbY = pCurMb->iMbY;
+  const int32_t kiMbWidth = pCurDqLayer->iMbWidth;
+  const int32_t kiMbHeight = pCurDqLayer->iMbHeight;
+  //	const int32_t block_width = mb_width << 1;
+  SVAAFrameInfoExt_t* pVaaExt = static_cast<SVAAFrameInfoExt_t*> (pEncCtx->pVaa);
+
+  bool bTryScrollSkip = false;
+
+  if (pVaaExt->sScrollDetectInfo.bScrollDetectFlag)
+    bTryScrollSkip = IsMbCollocatedStatic (pWelsMd->iBlock8x8StaticIdc);
+  else return 0;
+
+  if (bTryScrollSkip) {
+    int32_t iStrideUV, iOffsetUV;
+    SWelsFuncPtrList* pFunc = pEncCtx->pFuncList;
+    SPicture* pRefOri = pCurDqLayer->pRefOri;
+    if (pRefOri != NULL) {
+      int32_t iScrollMvX = pVaaExt->sScrollDetectInfo.iScrollMvX;
+      int32_t iScrollMvY = pVaaExt->sScrollDetectInfo.iScrollMvY;
+      if (CheckBorder (kiMbX, kiMbY, iScrollMvX, iScrollMvY, kiMbWidth, kiMbHeight)) {
+        bTryScrollSkip =  false;
+      } else {
+        iStrideUV	= pCurDqLayer->iEncStride[1];
+        iOffsetUV	= (kiMbX << 3) + (iScrollMvX >> 1) + ((kiMbX << 3) + (iScrollMvY >> 1)) * iStrideUV;
+
+        int32_t iSadCostCb = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[1], iStrideUV, pRefOri->pData[1] + iOffsetUV,
+                                           pRefOri->iLineSize[1]);
+        if (iSadCostCb == 0) {
+          int32_t iSadCostCr = CalUVSadCost (pFunc, pMbCache->SPicData.pEncMb[2], iStrideUV, pRefOri->pData[2] + iOffsetUV,
+                                             pRefOri->iLineSize[1]);
+          bTryScrollSkip = (0 == iSadCostCr);
+        } else bTryScrollSkip = false;
+      }
+    }
+  }
+  return bTryScrollSkip;
+}
+
+void SvcMdSCDMbEnc (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SMB* pCurMb, SMbCache* pMbCache, SSlice* pSlice,
+                    bool bQpSimilarFlag,
+                    bool bMbSkipFlag, SMVUnitXY sCurMbMv[], ESkipModes eSkipMode) {
+  SDqLayer* pCurDqLayer		= pEncCtx->pCurDqLayer;
+  SWelsFuncPtrList* pFunc	= pEncCtx->pFuncList;
+  SMVUnitXY sMvp					= { 0};
+  ST16 (&sMvp.iMvX, sCurMbMv[eSkipMode].iMvX);
+  ST16 (&sMvp.iMvY, sCurMbMv[eSkipMode].iMvY);
+  uint8_t* pRefLuma			= pMbCache->SPicData.pRefMb[0];
+  uint8_t* pRefCb				= pMbCache->SPicData.pRefMb[1];
+  uint8_t* pRefCr				= pMbCache->SPicData.pRefMb[2];
+  int32_t iLineSizeY		= pCurDqLayer->pRefPic->iLineSize[0];
+  int32_t iLineSizeUV		= pCurDqLayer->pRefPic->iLineSize[1];
+  uint8_t* pDstLuma			= pMbCache->pSkipMb;
+  uint8_t* pDstCb				= pMbCache->pSkipMb + 256;
+  uint8_t* pDstCr				= pMbCache->pSkipMb + 256 + 64;
+
+  const int32_t iOffsetY	= (sCurMbMv[eSkipMode].iMvX >> 2) + (sCurMbMv[eSkipMode].iMvY >> 2) * iLineSizeY;
+  const int32_t iOffsetUV = (sCurMbMv[eSkipMode].iMvX >> 3) + (sCurMbMv[eSkipMode].iMvY >> 3) * iLineSizeUV;
+
+  if (!bQpSimilarFlag || !bMbSkipFlag) {
+    pDstLuma = pMbCache->pMemPredLuma;
+    pDstCb	= pMbCache->pMemPredChroma;
+    pDstCr	= pMbCache->pMemPredChroma + 64;
+  }
+  //MC
+  pFunc->sMcFuncs.pfLumaQuarpelMc[0] (pRefLuma + iOffsetY, iLineSizeY, pDstLuma, 16, 16);
+  pFunc->sMcFuncs.pfChromaMc (pRefCb + iOffsetUV, iLineSizeUV, pDstCb, 8, sMvp, 8, 8);
+  pFunc->sMcFuncs.pfChromaMc (pRefCr + iOffsetUV, iLineSizeUV, pDstCr, 8, sMvp, 8, 8);
+
+  pCurMb->uiCbp = 0;
+  pWelsMd->iCostLuma = 0;
+  pCurMb->pSadCost[0] = pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_16x16] (pMbCache->SPicData.pEncMb[0],
+                        pCurDqLayer->iEncStride[0], pRefLuma + iOffsetY, iLineSizeY);
+
+  pWelsMd->iCostSkipMb = pCurMb->pSadCost[0];
+
+  ST16 (& (pCurMb->sP16x16Mv.iMvX), sCurMbMv[eSkipMode].iMvX);
+  ST16 (& (pCurMb->sP16x16Mv.iMvY), sCurMbMv[eSkipMode].iMvY);
+
+  ST16 (& (pCurDqLayer->pDecPic->sMvList[pCurMb->iMbXY].iMvX), sCurMbMv[eSkipMode].iMvX);
+  ST16 (& (pCurDqLayer->pDecPic->sMvList[pCurMb->iMbXY].iMvY), sCurMbMv[eSkipMode].iMvY);
+
+  if (bQpSimilarFlag && bMbSkipFlag) {
+    //update motion info to current MB
+    ST32 (pCurMb->pRefIndex, 0);
+    pFunc->pfUpdateMbMv (pCurMb->sMv, sMvp);
+    pCurMb->uiMbType = MB_TYPE_SKIP;
+    WelsRecPskip (pCurDqLayer, pEncCtx->pFuncList, pCurMb, pMbCache);
+    WelsMdInterUpdatePskip (pCurDqLayer, pSlice, pCurMb, pMbCache);
+    return;
+  }
+
+  pCurMb->uiMbType = MB_TYPE_16x16;
+
+  pWelsMd->sMe.sMe16x16.sMv.iMvX = sCurMbMv[eSkipMode].iMvX;
+  pWelsMd->sMe.sMe16x16.sMv.iMvY = sCurMbMv[eSkipMode].iMvY;
+  PredMv (&pMbCache->sMvComponents, 0, 4, 0, &pWelsMd->sMe.sMe16x16.sMvp);
+  pMbCache->sMbMvp[0] = pWelsMd->sMe.sMe16x16.sMvp;
+
+  UpdateP16x16MotionInfo (pMbCache, pCurMb, 0, &pWelsMd->sMe.sMe16x16.sMv);
+
+  if (pWelsMd->bMdUsingSad)
+    pWelsMd->iCostLuma = pCurMb->pSadCost[0];
+  else
+    pWelsMd->iCostLuma = pFunc->sSampleDealingFuncs.pfSampleSad[BLOCK_16x16] (pMbCache->SPicData.pEncMb[0],
+                         pCurDqLayer->iEncStride[0], pRefLuma, iLineSizeY);
+
+  WelsInterMbEncode (pEncCtx, pSlice, pCurMb);
+  WelsPMbChromaEncode (pEncCtx, pSlice, pCurMb);
+
+  pFunc->pfCopy16x16Aligned (pMbCache->SPicData.pCsMb[0], pCurDqLayer->iCsStride[0], pMbCache->pMemPredLuma, 16);
+  pFunc->pfCopy8x8Aligned (pMbCache->SPicData.pCsMb[1], pCurDqLayer->iCsStride[1], pMbCache->pMemPredChroma, 8);
+  pFunc->pfCopy8x8Aligned (pMbCache->SPicData.pCsMb[2], pCurDqLayer->iCsStride[1], pMbCache->pMemPredChroma + 64, 8);
+}
+
+bool MdInterSCDPskipProcess (sWelsEncCtx* pEncCtx, SWelsMD* pWelsMd, SSlice* pSlice, SMB* pCurMb, SMbCache* pMbCache,
+                             ESkipModes eSkipMode) {
+  SVAAFrameInfoExt_t* pVaaExt		= static_cast<SVAAFrameInfoExt_t*> (pEncCtx->pVaa);
+  SDqLayer* pCurDqLayer			= pEncCtx->pCurDqLayer;
+
+  const int32_t kiRefMbQp = pCurDqLayer->pRefPic->pRefMbQp[pCurMb->iMbXY];
+  const int32_t kiCurMbQp = pCurMb->uiLumaQp;// unsigned -> signed
+
+  pJudgeSkipFun pJudeSkip[2] = {JudgeStaticSkip, JudgeScrollSkip};
+  bool bSkipFlag = pJudeSkip[eSkipMode] (pEncCtx, pCurMb, pMbCache, pWelsMd);
+
+  if (bSkipFlag) {
+    bool bQpSimilarFlag = (kiRefMbQp - kiCurMbQp <= DELTA_QP_SCD_THD || kiRefMbQp <= 26);
+    SMVUnitXY	sVaaPredSkipMv = { 0 }, sCurMbMv[2] = {0, 0, 0, 0};
+    PredSkipMv (pMbCache, &sVaaPredSkipMv);
+
+    if (eSkipMode == SCROLLED) {
+      sCurMbMv[1].iMvX = static_cast<int16_t> (pVaaExt->sScrollDetectInfo.iScrollMvX << 2);
+      sCurMbMv[1].iMvY = static_cast<int16_t> (pVaaExt->sScrollDetectInfo.iScrollMvY << 2);
+    }
+
+    bool bMbSkipFlag = (LD32 (&sVaaPredSkipMv) ==  LD32 (&sCurMbMv[eSkipMode])) ;
+    SvcMdSCDMbEnc (pEncCtx, pWelsMd, pCurMb, pMbCache, pSlice, bQpSimilarFlag, bMbSkipFlag, sCurMbMv, eSkipMode);
+
+    return true;
+  }
+
+  return false;
+}
+
+void SetBlockStaticIdcToMd (void* pVaa, void* pMd, SMB* pCurMb, void* pDqLay) {
   SVAAFrameInfoExt_t* pVaaExt = static_cast<SVAAFrameInfoExt_t*> (pVaa);
   SWelsMD* pWelsMd = static_cast<SWelsMD*> (pMd);
   SDqLayer* pDqLayer = static_cast<SDqLayer*> (pDqLay);
@@ -177,12 +382,12 @@
 ///////////////////////
 // Scene Change Detection (SCD) PSkip Decision for screen content
 ////////////////////////
-bool WelsMdInterJudgeSCDPskip (void* pEncCtx, void* pWelsMd, SSlice* slice, SMB* pCurMb, SMbCache* pMbCache) {
-  sWelsEncCtx* pCtx	= (sWelsEncCtx*)pEncCtx;
-  SWelsMD* pMd					= (SWelsMD*)pWelsMd;
-  SDqLayer* pCurDqLayer			= pCtx->pCurDqLayer;
+bool WelsMdInterJudgeSCDPskip (void* pCtx, void* pMd, SSlice* slice, SMB* pCurMb, SMbCache* pMbCache) {
+  sWelsEncCtx* pEncCtx	= (sWelsEncCtx*)pCtx;
+  SWelsMD* pWelsMd					= (SWelsMD*)pMd;
+  SDqLayer* pCurDqLayer			= pEncCtx->pCurDqLayer;
 
-  SetBlockStaticIdcToMd (pCtx->pVaa, pMd, pCurMb, pCurDqLayer);
+  SetBlockStaticIdcToMd (pEncCtx->pVaa, pWelsMd, pCurMb, pCurDqLayer);
 
   //try static Pskip;
 
@@ -191,17 +396,16 @@
 
   return false;
 }
-bool WelsMdInterJudgeSCDPskipFalse (void* pEncCtx, void* pWelsMd, SSlice* slice, SMB* pCurMb,
-                                    SMbCache* pMbCache) {
+bool WelsMdInterJudgeSCDPskipFalse (void* pEncCtx, void* pWelsMd, SSlice* slice, SMB* pCurMb, SMbCache* pMbCache) {
   return false;
 }
 
 
-void WelsInitScrollingSkipFunc (SWelsFuncPtrList* pFuncList, const bool bScrollingDetection) {
+void WelsInitSCDPskipFunc (SWelsFuncPtrList* pFuncList, const bool bScrollingDetection) {
   if (bScrollingDetection) {
-    pFuncList->pfScrollingPSkipDecision = WelsMdInterJudgeSCDPskip;
+    pFuncList->pfSCDPSkipDecision = WelsMdInterJudgeSCDPskip;
   } else {
-    pFuncList->pfScrollingPSkipDecision = WelsMdInterJudgeSCDPskipFalse;
+    pFuncList->pfSCDPSkipDecision = WelsMdInterJudgeSCDPskipFalse;
   }
 }