diff --git a/codec/encoder/core/src/wels_preprocess.cpp b/codec/encoder/core/src/wels_preprocess.cpp index baf8243c..a867610d 100644 --- a/codec/encoder/core/src/wels_preprocess.cpp +++ b/codec/encoder/core/src/wels_preprocess.cpp @@ -604,7 +604,7 @@ void CWelsPreProcess::BilateralDenoising (SPicture* pSrc, const int32_t kiWidth, bool CWelsPreProcess::DetectSceneChange (SPicture* pCurPicture, SPicture* pRefPicture) { bool bSceneChangeFlag = false; - int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION; + int32_t iMethodIdx = METHOD_SCENE_CHANGE_DETECTION_VIDEO; SSceneChangeResult sSceneChangeDetectResult = { SIMILAR_SCENE }; SPixMap sSrcPixMap = {0}; SPixMap sRefPixMap = {0}; diff --git a/codec/processing/interface/IWelsVP.h b/codec/processing/interface/IWelsVP.h index b54474f3..c0b7742e 100644 --- a/codec/processing/interface/IWelsVP.h +++ b/codec/processing/interface/IWelsVP.h @@ -122,7 +122,8 @@ typedef enum { METHOD_NULL = 0, METHOD_COLORSPACE_CONVERT ,//not support yet METHOD_DENOISE , - METHOD_SCENE_CHANGE_DETECTION , + METHOD_SCENE_CHANGE_DETECTION_VIDEO , + METHOD_SCENE_CHANGE_DETECTION_SCREEN , METHOD_DOWNSAMPLE , METHOD_VAA_STATISTICS , METHOD_BACKGROUND_DETECTION , diff --git a/codec/processing/src/common/WelsFrameWork.cpp b/codec/processing/src/common/WelsFrameWork.cpp index d980e032..3f5ab544 100644 --- a/codec/processing/src/common/WelsFrameWork.cpp +++ b/codec/processing/src/common/WelsFrameWork.cpp @@ -265,8 +265,9 @@ IStrategy* CVpFrameWork::CreateStrategy (EMethods m_eMethod, int32_t iCpuFlag) { case METHOD_DENOISE: pStrategy = WelsDynamicCast (IStrategy*, new CDenoiser (iCpuFlag)); break; - case METHOD_SCENE_CHANGE_DETECTION: - pStrategy = WelsDynamicCast (IStrategy*, new CSceneChangeDetection (iCpuFlag)); + case METHOD_SCENE_CHANGE_DETECTION_VIDEO: + case METHOD_SCENE_CHANGE_DETECTION_SCREEN: + pStrategy = BuildSceneChangeDetection(m_eMethod, iCpuFlag); break; case METHOD_DOWNSAMPLE: pStrategy = WelsDynamicCast (IStrategy*, new CDownsampling (iCpuFlag)); diff --git a/codec/processing/src/scenechangedetection/SceneChangeDetection.cpp b/codec/processing/src/scenechangedetection/SceneChangeDetection.cpp index 3f04f282..eb43e201 100644 --- a/codec/processing/src/scenechangedetection/SceneChangeDetection.cpp +++ b/codec/processing/src/scenechangedetection/SceneChangeDetection.cpp @@ -35,108 +35,17 @@ WELSVP_NAMESPACE_BEGIN -#define HIGH_MOTION_BLOCK_THRESHOLD 320 -#define SCENE_CHANGE_MOTION_RATIO 0.85f - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////// - -CSceneChangeDetection::CSceneChangeDetection (int32_t iCpuFlag) { - m_iCpuFlag = iCpuFlag; - m_eMethod = METHOD_SCENE_CHANGE_DETECTION; - m_pfSad = NULL; - WelsMemset (&m_sSceneChangeParam, 0, sizeof (m_sSceneChangeParam)); - InitSadFuncs (m_pfSad, m_iCpuFlag); -} - -CSceneChangeDetection::~CSceneChangeDetection() { -} - -EResult CSceneChangeDetection::Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) { - EResult eReturn = RET_INVALIDPARAM; - - int32_t iWidth = pSrcPixMap->sRect.iRectWidth; - int32_t iHeight = pSrcPixMap->sRect.iRectHeight; - int32_t iBlock8x8Width = iWidth >> 3; - int32_t iBlock8x8Height = iHeight >> 3; - int32_t iBlock8x8Num = iBlock8x8Width * iBlock8x8Height; - int32_t iSceneChangeThreshold = WelsStaticCast (int32_t, SCENE_CHANGE_MOTION_RATIO * iBlock8x8Num + 0.5f + PESN); - - int32_t iBlockSad = 0; - int32_t iMotionBlockNum = 0; - - uint8_t* pRefY = NULL, *pCurY = NULL; - int32_t iRefStride = 0, iCurStride = 0; - int32_t iRefRowStride = 0, iCurRowStride = 0; - - uint8_t* pRefTmp = NULL, *pCurTmp = NULL; - - pRefY = (uint8_t*)pRefPixMap->pPixel[0]; - pCurY = (uint8_t*)pSrcPixMap->pPixel[0]; - - iRefStride = pRefPixMap->iStride[0]; - iCurStride = pSrcPixMap->iStride[0]; - - iRefRowStride = pRefPixMap->iStride[0] << 3; - iCurRowStride = pSrcPixMap->iStride[0] << 3; - - m_sSceneChangeParam.eSceneChangeIdc = SIMILAR_SCENE; - - for (int32_t j = 0; j < iBlock8x8Height; j ++) { - pRefTmp = pRefY; - pCurTmp = pCurY; - - for (int32_t i = 0; i < iBlock8x8Width; i++) { - iBlockSad = m_pfSad (pRefTmp, iRefStride, pCurTmp, iCurStride); - - iMotionBlockNum += (iBlockSad > HIGH_MOTION_BLOCK_THRESHOLD); - - pRefTmp += 8; - pCurTmp += 8; - } - - pRefY += iRefRowStride; - pCurY += iCurRowStride; +IStrategy * BuildSceneChangeDetection(EMethods eMethod, int32_t iCpuFlag){ + switch(eMethod){ + case METHOD_SCENE_CHANGE_DETECTION_VIDEO: + return new CSceneChangeDetection(eMethod, iCpuFlag); + break; + case METHOD_SCENE_CHANGE_DETECTION_SCREEN: + default: + // not support yet + return NULL; } - - if (iMotionBlockNum >= iSceneChangeThreshold) { - m_sSceneChangeParam.eSceneChangeIdc = LARGE_CHANGED_SCENE; - } - - eReturn = RET_SUCCESS; - - return eReturn; } - -EResult CSceneChangeDetection::Get (int32_t iType, void* pParam) { - if (pParam == NULL) { - return RET_INVALIDPARAM; - } - - * (SSceneChangeResult*)pParam = m_sSceneChangeParam; - - return RET_SUCCESS; -} - -/////////////////////////////////////////////////////////////////////////////////////////////// - -void CSceneChangeDetection::InitSadFuncs (SadFuncPtr& pfSad, int32_t iCpuFlag) { - pfSad = WelsSampleSad8x8_c; - -#ifdef X86_ASM - if (iCpuFlag & WELS_CPU_SSE2) { - pfSad = WelsSampleSad8x8_sse21; - } -#endif - -#ifdef HAVE_NEON - if (iCpuFlag & WELS_CPU_NEON) { - pfSad = WelsProcessingSampleSad8x8_neon; - } -#endif -} - - WELSVP_NAMESPACE_END + diff --git a/codec/processing/src/scenechangedetection/SceneChangeDetection.h b/codec/processing/src/scenechangedetection/SceneChangeDetection.h index ce83c4a3..98b534d8 100644 --- a/codec/processing/src/scenechangedetection/SceneChangeDetection.h +++ b/codec/processing/src/scenechangedetection/SceneChangeDetection.h @@ -44,29 +44,117 @@ #include "util.h" #include "memory.h" +#include "cpu.h" #include "WelsFrameWork.h" #include "IWelsVP.h" #include "SceneChangeDetectionCommon.h" +#define HIGH_MOTION_BLOCK_THRESHOLD 320 +#define SCENE_CHANGE_MOTION_RATIO 0.85f + WELSVP_NAMESPACE_BEGIN +class CSceneChangeDetectorVideo { +public: + CSceneChangeDetectorVideo(int32_t iCpuFlag) { + m_pfSad = WelsSampleSad8x8_c; +#ifdef X86_ASM + if (iCpuFlag & WELS_CPU_SSE2){ + m_pfSad = WelsSampleSad8x8_sse21; + } +#endif +#ifdef HAVE_NEON + if (iCpuFlag & WELS_CPU_NEON){ + m_pfSad = WelsProcessingSampleSad8x8_neon; + } +#endif + } + virtual ~CSceneChangeDetectorVideo() { + } + virtual int32_t operator () (uint8_t* pSrcY, int32_t iSrcStrideY, uint8_t* pRefY, int32_t iRefStrideY) { + return m_pfSad(pSrcY, iSrcStrideY, pRefY, iSrcStrideY); + } +private: + SadFuncPtr m_pfSad; +}; + +template class CSceneChangeDetection : public IStrategy { public: - CSceneChangeDetection (int32_t iCpuFlag); - ~CSceneChangeDetection(); + CSceneChangeDetection (EMethods eMethod, int32_t iCpuFlag): m_cDetector(iCpuFlag) { + m_eMethod = eMethod; + WelsMemset (&m_sSceneChangeParam, 0, sizeof (m_sSceneChangeParam)); + } - EResult Process (int32_t iType, SPixMap* pSrc, SPixMap* pRef); - EResult Get (int32_t iType, void* pParam); + ~CSceneChangeDetection(){ + } + + EResult Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap){ + EResult eReturn = RET_INVALIDPARAM; + int32_t iWidth = pSrcPixMap->sRect.iRectWidth; + int32_t iHeight = pSrcPixMap->sRect.iRectHeight; + int32_t iBlock8x8Width = iWidth >> 3; + int32_t iBlock8x8Height = iHeight >> 3; + int32_t iBlock8x8Num = iBlock8x8Width * iBlock8x8Height; + int32_t iSceneChangeThreshold = WelsStaticCast (int32_t, SCENE_CHANGE_MOTION_RATIO * iBlock8x8Num + 0.5f + PESN); + int32_t iBlockSad = 0; + int32_t iMotionBlockNum = 0; + uint8_t* pRefY = NULL, *pCurY = NULL; + int32_t iRefStride = 0, iCurStride = 0; + int32_t iRefRowStride = 0, iCurRowStride = 0; + uint8_t* pRefTmp = NULL, *pCurTmp = NULL; + + pRefY = (uint8_t*)pRefPixMap->pPixel[0]; + pCurY = (uint8_t*)pSrcPixMap->pPixel[0]; + + iRefStride = pRefPixMap->iStride[0]; + iCurStride = pSrcPixMap->iStride[0]; + + iRefRowStride = pRefPixMap->iStride[0] << 3; + iCurRowStride = pSrcPixMap->iStride[0] << 3; + + m_sSceneChangeParam.eSceneChangeIdc = SIMILAR_SCENE; + + for (int32_t j = 0; j < iBlock8x8Height; j ++) { + pRefTmp = pRefY; + pCurTmp = pCurY; + + for (int32_t i = 0; i < iBlock8x8Width; i++) { + iBlockSad = m_cDetector(pRefTmp, iRefStride, pCurTmp, iCurStride); + iMotionBlockNum += (iBlockSad > HIGH_MOTION_BLOCK_THRESHOLD); + + pRefTmp += 8; + pCurTmp += 8; + } + + pRefY += iRefRowStride; + pCurY += iCurRowStride; + } + + if (iMotionBlockNum >= iSceneChangeThreshold) { + m_sSceneChangeParam.eSceneChangeIdc = LARGE_CHANGED_SCENE; + } + + eReturn = RET_SUCCESS; + + return eReturn; + } + + EResult Get (int32_t iType, void* pParam) { + if (pParam == NULL) { + return RET_INVALIDPARAM; + } + * (SSceneChangeResult*)pParam = m_sSceneChangeParam; + return RET_SUCCESS; + } private: - void InitSadFuncs (SadFuncPtr& pfSadFunc, int32_t iCpuFlag); - - private: - SadFuncPtr m_pfSad; - int32_t m_iCpuFlag; SSceneChangeResult m_sSceneChangeParam; + T m_cDetector; }; +IStrategy * BuildSceneChangeDetection(EMethods eMethod, int32_t iCpuFlag); + WELSVP_NAMESPACE_END #endif