ref: ad8ba85136a92c496f29e8d3a27e981142686321
dir: /codec/processing/src/complexityanalysis/ComplexityAnalysis.cpp/
/*!
* \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 "ComplexityAnalysis.h"
#include "cpu.h"
#include "macros.h"
#include "intra_pred_common.h"
WELSVP_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
CComplexityAnalysis::CComplexityAnalysis (int32_t iCpuFlag) {
m_eMethod = METHOD_COMPLEXITY_ANALYSIS;
m_pfGomSad = NULL;
WelsMemset (&m_sComplexityAnalysisParam, 0, sizeof (m_sComplexityAnalysisParam));
}
CComplexityAnalysis::~CComplexityAnalysis() {
}
EResult CComplexityAnalysis::Process (int32_t iType, SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
EResult eReturn = RET_SUCCESS;
switch (m_sComplexityAnalysisParam.iComplexityAnalysisMode) {
case FRAME_SAD:
AnalyzeFrameComplexityViaSad (pSrcPixMap, pRefPixMap);
break;
case GOM_SAD:
AnalyzeGomComplexityViaSad (pSrcPixMap, pRefPixMap);
break;
case GOM_VAR:
AnalyzeGomComplexityViaVar (pSrcPixMap, pRefPixMap);
break;
default:
eReturn = RET_INVALIDPARAM;
break;
}
return eReturn;
}
EResult CComplexityAnalysis::Set (int32_t iType, void* pParam) {
if (pParam == NULL) {
return RET_INVALIDPARAM;
}
m_sComplexityAnalysisParam = * (SComplexityAnalysisParam*)pParam;
return RET_SUCCESS;
}
EResult CComplexityAnalysis::Get (int32_t iType, void* pParam) {
if (pParam == NULL) {
return RET_INVALIDPARAM;
}
SComplexityAnalysisParam* sComplexityAnalysisParam = (SComplexityAnalysisParam*)pParam;
sComplexityAnalysisParam->iFrameComplexity = m_sComplexityAnalysisParam.iFrameComplexity;
return RET_SUCCESS;
}
///////////////////////////////////////////////////////////////////////////////////////////////
void CComplexityAnalysis::AnalyzeFrameComplexityViaSad (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
SVAACalcResult* pVaaCalcResults = NULL;
pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
m_sComplexityAnalysisParam.iFrameComplexity = pVaaCalcResults->iFrameSad;
if (m_sComplexityAnalysisParam.iCalcBgd) { //BGD control
m_sComplexityAnalysisParam.iFrameComplexity = GetFrameSadExcludeBackground (pSrcPixMap, pRefPixMap);
}
}
int32_t CComplexityAnalysis::GetFrameSadExcludeBackground (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
int32_t iWidth = pSrcPixMap->sRect.iRectWidth;
int32_t iHeight = pSrcPixMap->sRect.iRectHeight;
int32_t iMbWidth = iWidth >> 4;
int32_t iMbHeight = iHeight >> 4;
int32_t iMbNum = iMbWidth * iMbHeight;
int32_t iMbNumInGom = m_sComplexityAnalysisParam.iMbNumInGom;
int32_t iGomMbNum = (iMbNum + iMbNumInGom - 1) / iMbNumInGom;
int32_t iGomMbStartIndex = 0, iGomMbEndIndex = 0;
uint8_t* pBackgroundMbFlag = (uint8_t*)m_sComplexityAnalysisParam.pBackgroundMbFlag;
uint32_t* uiRefMbType = (uint32_t*)m_sComplexityAnalysisParam.uiRefMbType;
SVAACalcResult* pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
int32_t* pGomForegroundBlockNum = m_sComplexityAnalysisParam.pGomForegroundBlockNum;
uint32_t uiFrameSad = 0;
for (int32_t j = 0; j < iGomMbNum; j ++) {
iGomMbStartIndex = j * iMbNumInGom;
iGomMbEndIndex = WELS_MIN ((j + 1) * iMbNumInGom, iMbNum);
for (int32_t i = iGomMbStartIndex; i < iGomMbEndIndex; i ++) {
if (pBackgroundMbFlag[i] == 0 || IS_INTRA (uiRefMbType[i])) {
pGomForegroundBlockNum[j]++;
uiFrameSad += pVaaCalcResults->pSad8x8[i][0];
uiFrameSad += pVaaCalcResults->pSad8x8[i][1];
uiFrameSad += pVaaCalcResults->pSad8x8[i][2];
uiFrameSad += pVaaCalcResults->pSad8x8[i][3];
}
}
}
return (uiFrameSad);
}
void InitGomSadFunc (PGOMSadFunc& pfGomSad, uint8_t iCalcBgd) {
pfGomSad = GomSampleSad;
if (iCalcBgd) {
pfGomSad = GomSampleSadExceptBackground;
}
}
void GomSampleSad (uint32_t* pGomSad, int32_t* pGomForegroundBlockNum, int32_t* pSad8x8, uint8_t pBackgroundMbFlag) {
(*pGomForegroundBlockNum) ++;
*pGomSad += pSad8x8[0];
*pGomSad += pSad8x8[1];
*pGomSad += pSad8x8[2];
*pGomSad += pSad8x8[3];
}
void GomSampleSadExceptBackground (uint32_t* pGomSad, int32_t* pGomForegroundBlockNum, int32_t* pSad8x8,
uint8_t pBackgroundMbFlag) {
if (pBackgroundMbFlag == 0) {
(*pGomForegroundBlockNum) ++;
*pGomSad += pSad8x8[0];
*pGomSad += pSad8x8[1];
*pGomSad += pSad8x8[2];
*pGomSad += pSad8x8[3];
}
}
void CComplexityAnalysis::AnalyzeGomComplexityViaSad (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
int32_t iWidth = pSrcPixMap->sRect.iRectWidth;
int32_t iHeight = pSrcPixMap->sRect.iRectHeight;
int32_t iMbWidth = iWidth >> 4;
int32_t iMbHeight = iHeight >> 4;
int32_t iMbNum = iMbWidth * iMbHeight;
int32_t iMbNumInGom = m_sComplexityAnalysisParam.iMbNumInGom;
int32_t iGomMbNum = (iMbNum + iMbNumInGom - 1) / iMbNumInGom;
int32_t iGomMbStartIndex = 0, iGomMbEndIndex = 0, iGomMbRowNum = 0;
int32_t iMbStartIndex = 0, iMbEndIndex = 0;
uint8_t* pBackgroundMbFlag = (uint8_t*)m_sComplexityAnalysisParam.pBackgroundMbFlag;
uint32_t* uiRefMbType = (uint32_t*)m_sComplexityAnalysisParam.uiRefMbType;
SVAACalcResult* pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
int32_t* pGomForegroundBlockNum = (int32_t*)m_sComplexityAnalysisParam.pGomForegroundBlockNum;
int32_t* pGomComplexity = (int32_t*)m_sComplexityAnalysisParam.pGomComplexity;
uint32_t uiGomSad = 0, uiFrameSad = 0;
InitGomSadFunc (m_pfGomSad, m_sComplexityAnalysisParam.iCalcBgd);
for (int32_t j = 0; j < iGomMbNum; j ++) {
uiGomSad = 0;
iGomMbStartIndex = j * iMbNumInGom;
iGomMbEndIndex = WELS_MIN ((j + 1) * iMbNumInGom, iMbNum);
iGomMbRowNum = (iGomMbEndIndex + iMbWidth - 1) / iMbWidth - iGomMbStartIndex / iMbWidth;
iMbStartIndex = iGomMbStartIndex;
iMbEndIndex = WELS_MIN ((iMbStartIndex / iMbWidth + 1) * iMbWidth, iGomMbEndIndex);
do {
for (int32_t i = iMbStartIndex; i < iMbEndIndex; i ++) {
m_pfGomSad (&uiGomSad, pGomForegroundBlockNum + j, pVaaCalcResults->pSad8x8[i], pBackgroundMbFlag[i]
&& !IS_INTRA (uiRefMbType[i]));
}
iMbStartIndex = iMbEndIndex;
iMbEndIndex = WELS_MIN (iMbEndIndex + iMbWidth , iGomMbEndIndex);
} while (--iGomMbRowNum);
pGomComplexity[j] = uiGomSad;
uiFrameSad += pGomComplexity[j];
}
m_sComplexityAnalysisParam.iFrameComplexity = uiFrameSad;
}
void CComplexityAnalysis::AnalyzeGomComplexityViaVar (SPixMap* pSrcPixMap, SPixMap* pRefPixMap) {
int32_t iWidth = pSrcPixMap->sRect.iRectWidth;
int32_t iHeight = pSrcPixMap->sRect.iRectHeight;
int32_t iMbWidth = iWidth >> 4;
int32_t iMbHeight = iHeight >> 4;
int32_t iMbNum = iMbWidth * iMbHeight;
int32_t iMbNumInGom = m_sComplexityAnalysisParam.iMbNumInGom;
int32_t iGomMbNum = (iMbNum + iMbNumInGom - 1) / iMbNumInGom;
int32_t iGomSampleNum = 0;
int32_t iGomMbStartIndex = 0, iGomMbEndIndex = 0, iGomMbRowNum = 0;
int32_t iMbStartIndex = 0, iMbEndIndex = 0;
SVAACalcResult* pVaaCalcResults = m_sComplexityAnalysisParam.pCalcResult;
int32_t* pGomComplexity = (int32_t*)m_sComplexityAnalysisParam.pGomComplexity;
uint32_t uiSampleSum = 0, uiSquareSum = 0;
for (int32_t j = 0; j < iGomMbNum; j ++) {
uiSampleSum = 0;
uiSquareSum = 0;
iGomMbStartIndex = j * iMbNumInGom;
iGomMbEndIndex = WELS_MIN ((j + 1) * iMbNumInGom, iMbNum);
iGomMbRowNum = (iGomMbEndIndex + iMbWidth - 1) / iMbWidth - iGomMbStartIndex / iMbWidth;
iMbStartIndex = iGomMbStartIndex;
iMbEndIndex = WELS_MIN ((iMbStartIndex / iMbWidth + 1) * iMbWidth, iGomMbEndIndex);
iGomSampleNum = (iMbEndIndex - iMbStartIndex) * MB_WIDTH_LUMA * MB_WIDTH_LUMA;
do {
for (int32_t i = iMbStartIndex; i < iMbEndIndex; i ++) {
uiSampleSum += pVaaCalcResults->pSum16x16[i];
uiSquareSum += pVaaCalcResults->pSumOfSquare16x16[i];
}
iMbStartIndex = iMbEndIndex;
iMbEndIndex = WELS_MIN (iMbEndIndex + iMbWidth, iGomMbEndIndex);
} while (--iGomMbRowNum);
pGomComplexity[j] = uiSquareSum - (uiSampleSum * uiSampleSum / iGomSampleNum);
}
}
CComplexityAnalysisScreen::CComplexityAnalysisScreen (int32_t iCpuFlag) {
m_eMethod = METHOD_COMPLEXITY_ANALYSIS_SCREEN;
WelsMemset (&m_ComplexityAnalysisParam, 0, sizeof (m_ComplexityAnalysisParam));
m_pSadFunc = WelsSampleSad16x16_c;
m_pIntraFunc[0] = WelsI16x16LumaPredV_c;
m_pIntraFunc[1] = WelsI16x16LumaPredH_c;
#ifdef X86_ASM
if (iCpuFlag & WELS_CPU_SSE2) {
m_pSadFunc = WelsSampleSad16x16_sse2;
m_pIntraFunc[0] = WelsI16x16LumaPredV_sse2;
m_pIntraFunc[1] = WelsI16x16LumaPredH_sse2;
}
#endif
#if defined (HAVE_NEON)
if (iCpuFlag & WELS_CPU_NEON) {
m_pSadFunc = WelsSampleSad16x16_neon;
m_pIntraFunc[0] = WelsI16x16LumaPredV_neon;
m_pIntraFunc[1] = WelsI16x16LumaPredH_neon;
}
#endif
#if defined (HAVE_NEON_AARCH64)
if (iCpuFlag & WELS_CPU_NEON) {
m_pSadFunc = WelsSampleSad16x16_AArch64_neon;
m_pIntraFunc[0] = WelsI16x16LumaPredV_AArch64_neon;
m_pIntraFunc[1] = WelsI16x16LumaPredH_AArch64_neon;
}
#endif
}
CComplexityAnalysisScreen::~CComplexityAnalysisScreen() {
}
EResult CComplexityAnalysisScreen::Process (int32_t nType, SPixMap* pSrc, SPixMap* pRef) {
bool bScrollFlag = m_ComplexityAnalysisParam.sScrollResult.bScrollDetectFlag;
int32_t iIdrFlag = m_ComplexityAnalysisParam.iIdrFlag;
int32_t iScrollMvX = m_ComplexityAnalysisParam.sScrollResult.iScrollMvX;
int32_t iScrollMvY = m_ComplexityAnalysisParam.sScrollResult.iScrollMvY;
if (m_ComplexityAnalysisParam.iMbRowInGom <= 0)
return RET_INVALIDPARAM;
if (!iIdrFlag && pRef == NULL)
return RET_INVALIDPARAM;
if (iIdrFlag || pRef == NULL) {
GomComplexityAnalysisIntra (pSrc);
} else if (!bScrollFlag || ((iScrollMvX == 0) && (iScrollMvY == 0))) {
GomComplexityAnalysisInter (pSrc, pRef, 0);
} else {
GomComplexityAnalysisInter (pSrc, pRef, 1);;
}
return RET_SUCCESS;
}
EResult CComplexityAnalysisScreen::Set (int32_t nType, void* pParam) {
if (pParam == NULL)
return RET_INVALIDPARAM;
m_ComplexityAnalysisParam = * (SComplexityAnalysisScreenParam*)pParam;
return RET_SUCCESS;
}
EResult CComplexityAnalysisScreen::Get (int32_t nType, void* pParam) {
if (pParam == NULL)
return RET_INVALIDPARAM;
* (SComplexityAnalysisScreenParam*)pParam = m_ComplexityAnalysisParam;
return RET_SUCCESS;
}
void CComplexityAnalysisScreen::GomComplexityAnalysisIntra (SPixMap* pSrc) {
int32_t iWidth = pSrc->sRect.iRectWidth;
int32_t iHeight = pSrc->sRect.iRectHeight;
int32_t iBlockWidth = iWidth >> 4;
int32_t iBlockHeight = iHeight >> 4;
int32_t iBlockSadH, iBlockSadV, iGomSad = 0;
int32_t iIdx = 0;
uint8_t* pPtrY = NULL;
int32_t iStrideY = 0;
int32_t iRowStrideY = 0;
uint8_t* pTmpCur = NULL;
ENFORCE_STACK_ALIGN_1D (uint8_t, iMemPredMb, 256, 16)
pPtrY = (uint8_t*)pSrc->pPixel[0];
iStrideY = pSrc->iStride[0];
iRowStrideY = iStrideY << 4;
m_ComplexityAnalysisParam.iFrameComplexity = 0;
for (int32_t j = 0; j < iBlockHeight; j ++) {
pTmpCur = pPtrY;
for (int32_t i = 0; i < iBlockWidth; i++) {
iBlockSadH = iBlockSadV = 0x7fffffff; // INT_MAX
if (j > 0) {
m_pIntraFunc[0] (iMemPredMb, pTmpCur, iStrideY);
iBlockSadH = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
}
if (i > 0) {
m_pIntraFunc[1] (iMemPredMb, pTmpCur, iStrideY);
iBlockSadV = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
}
if (i || j)
iGomSad += WELS_MIN (iBlockSadH, iBlockSadV);
pTmpCur += 16;
if (i == iBlockWidth - 1 && ((j + 1) % m_ComplexityAnalysisParam.iMbRowInGom == 0 || j == iBlockHeight - 1)) {
m_ComplexityAnalysisParam.pGomComplexity[iIdx] = iGomSad;
m_ComplexityAnalysisParam.iFrameComplexity += iGomSad;
iIdx++;
iGomSad = 0;
}
}
pPtrY += iRowStrideY;
}
m_ComplexityAnalysisParam.iGomNumInFrame = iIdx;
}
void CComplexityAnalysisScreen::GomComplexityAnalysisInter (SPixMap* pSrc, SPixMap* pRef, bool bScrollFlag) {
int32_t iWidth = pSrc->sRect.iRectWidth;
int32_t iHeight = pSrc->sRect.iRectHeight;
int32_t iBlockWidth = iWidth >> 4;
int32_t iBlockHeight = iHeight >> 4;
int32_t iInterSad, iScrollSad, iBlockSadH, iBlockSadV, iGomSad = 0;
int32_t iIdx = 0;
int32_t iScrollMvX = m_ComplexityAnalysisParam.sScrollResult.iScrollMvX;
int32_t iScrollMvY = m_ComplexityAnalysisParam.sScrollResult.iScrollMvY;
uint8_t* pPtrX = NULL, *pPtrY = NULL;
int32_t iStrideX = 0, iStrideY = 0;
int32_t iRowStrideX = 0, iRowStrideY = 0;
uint8_t* pTmpRef = NULL, *pTmpCur = NULL, *pTmpRefScroll = NULL;
ENFORCE_STACK_ALIGN_1D (uint8_t, iMemPredMb, 256, 16)
pPtrX = (uint8_t*)pRef->pPixel[0];
pPtrY = (uint8_t*)pSrc->pPixel[0];
iStrideX = pRef->iStride[0];
iStrideY = pSrc->iStride[0];
iRowStrideX = pRef->iStride[0] << 4;
iRowStrideY = pSrc->iStride[0] << 4;
m_ComplexityAnalysisParam.iFrameComplexity = 0;
for (int32_t j = 0; j < iBlockHeight; j ++) {
pTmpRef = pPtrX;
pTmpCur = pPtrY;
for (int32_t i = 0; i < iBlockWidth; i++) {
int32_t iBlockPointX = i << 4;
int32_t iBlockPointY = j << 4;
iInterSad = m_pSadFunc (pTmpCur, iStrideY, pTmpRef, iStrideX);
if (bScrollFlag) {
if ((iInterSad != 0) &&
(iBlockPointX + iScrollMvX >= 0) && (iBlockPointX + iScrollMvX <= iWidth - 8) &&
(iBlockPointY + iScrollMvY >= 0) && (iBlockPointY + iScrollMvY <= iHeight - 8)) {
pTmpRefScroll = pTmpRef - iScrollMvY * iStrideX + iScrollMvX;
iScrollSad = m_pSadFunc (pTmpCur, iStrideY, pTmpRefScroll, iStrideX);
if (iScrollSad < iInterSad) {
iInterSad = iScrollSad;
}
}
}
iBlockSadH = iBlockSadV = 0x7fffffff; // INT_MAX
if (j > 0) {
m_pIntraFunc[0] (iMemPredMb, pTmpCur, iStrideY);
iBlockSadH = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
}
if (i > 0) {
m_pIntraFunc[1] (iMemPredMb, pTmpCur, iStrideY);
iBlockSadV = m_pSadFunc (pTmpCur, iStrideY, iMemPredMb, 16);
}
iGomSad += WELS_MIN (WELS_MIN (iBlockSadH, iBlockSadV), iInterSad);
if (i == iBlockWidth - 1 && ((j + 1) % m_ComplexityAnalysisParam.iMbRowInGom == 0 || j == iBlockHeight - 1)) {
m_ComplexityAnalysisParam.pGomComplexity[iIdx] = iGomSad;
m_ComplexityAnalysisParam.iFrameComplexity += iGomSad;
iIdx++;
iGomSad = 0;
}
pTmpRef += 16;
pTmpCur += 16;
}
pPtrX += iRowStrideX;
pPtrY += iRowStrideY;
}
m_ComplexityAnalysisParam.iGomNumInFrame = iIdx;
}
WELSVP_NAMESPACE_END