| /*! |
| * \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" |
| |
| 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; |
| } |
| #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 |