ref: 44b048edd6e5f81d8eb14d8a4130984e6f2004b8
dir: /codec/processing/src/adaptivequantization/AdaptiveQuantization.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 "AdaptiveQuantization.h" WELSVP_NAMESPACE_BEGIN #define AVERAGE_TIME_MOTION (0.3) //0.3046875 // 1/4 + 1/16 - 1/128 ~ 0.3 #define AVERAGE_TIME_TEXTURE_QUALITYMODE (1.0) //0.5 // 1/2 #define AVERAGE_TIME_TEXTURE_BITRATEMODE (0.875) //0.5 // 1/2 #define MODEL_ALPHA (0.9910) //1.5 //1.1102 #define MODEL_TIME (5.8185) //9.0 //5.9842 /////////////////////////////////////////////////////////////////////////////////////////////////////////////// CAdaptiveQuantization::CAdaptiveQuantization (int32_t iCpuFlag) { m_CPUFlag = iCpuFlag; m_eMethod = METHOD_ADAPTIVE_QUANT; m_pfVar = NULL; WelsMemset (&m_sAdaptiveQuantParam, 0, sizeof (m_sAdaptiveQuantParam)); WelsInitVarFunc (m_pfVar, m_CPUFlag); } CAdaptiveQuantization::~CAdaptiveQuantization() { } EResult CAdaptiveQuantization::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 iMbWidth = iWidth >> 4; int32_t iMbHeight = iHeight >> 4; int32_t iMbTotalNum = iMbWidth * iMbHeight; SMotionTextureUnit* pMotionTexture = NULL; SVAACalcResult* pVaaCalcResults = NULL; int8_t iMotionTextureIndexToDeltaQp = 0; int32_t iAverMotionTextureIndexToDeltaQp = 0; // double to uint32 double dAverageMotionIndex = 0.0; // double to float double dAverageTextureIndex = 0.0; double dQStep = 0.0; double dLumaMotionDeltaQp = 0; double dLumaTextureDeltaQp = 0; uint8_t* pRefFrameY = NULL, *pCurFrameY = NULL; int32_t iRefStride = 0, iCurStride = 0; uint8_t* pRefFrameTmp = NULL, *pCurFrameTmp = NULL; int32_t i = 0, j = 0; pRefFrameY = (uint8_t*)pRefPixMap->pPixel[0]; pCurFrameY = (uint8_t*)pSrcPixMap->pPixel[0]; iRefStride = pRefPixMap->iStride[0]; iCurStride = pSrcPixMap->iStride[0]; /////////////////////////////////////// motion ////////////////////////////////// // motion MB residual variance dAverageMotionIndex = 0.0; dAverageTextureIndex = 0.0; pMotionTexture = m_sAdaptiveQuantParam.pMotionTextureUnit; pVaaCalcResults = m_sAdaptiveQuantParam.pCalcResult; if (pVaaCalcResults->pRefY == pRefFrameY && pVaaCalcResults->pCurY == pCurFrameY) { int32_t iMbIndex = 0; int32_t iSumDiff, iSQDiff, uiSum, iSQSum; for (j = 0; j < iMbHeight; j ++) { pRefFrameTmp = pRefFrameY; pCurFrameTmp = pCurFrameY; for (i = 0; i < iMbWidth; i++) { iSumDiff = pVaaCalcResults->pSad8x8[iMbIndex][0]; iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][1]; iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][2]; iSumDiff += pVaaCalcResults->pSad8x8[iMbIndex][3]; iSQDiff = pVaaCalcResults->pSsd16x16[iMbIndex]; uiSum = pVaaCalcResults->pSum16x16[iMbIndex]; iSQSum = pVaaCalcResults->pSumOfSquare16x16[iMbIndex]; iSumDiff = iSumDiff >> 8; pMotionTexture->uiMotionIndex = (iSQDiff >> 8) - (iSumDiff * iSumDiff); uiSum = uiSum >> 8; pMotionTexture->uiTextureIndex = (iSQSum >> 8) - (uiSum * uiSum); dAverageMotionIndex += pMotionTexture->uiMotionIndex; dAverageTextureIndex += pMotionTexture->uiTextureIndex; pMotionTexture++; ++iMbIndex; pRefFrameTmp += MB_WIDTH_LUMA; pCurFrameTmp += MB_WIDTH_LUMA; } pRefFrameY += (iRefStride) << 4; pCurFrameY += (iCurStride) << 4; } } else { for (j = 0; j < iMbHeight; j ++) { pRefFrameTmp = pRefFrameY; pCurFrameTmp = pCurFrameY; for (i = 0; i < iMbWidth; i++) { m_pfVar (pRefFrameTmp, iRefStride, pCurFrameTmp, iCurStride, pMotionTexture); dAverageMotionIndex += pMotionTexture->uiMotionIndex; dAverageTextureIndex += pMotionTexture->uiTextureIndex; pMotionTexture++; pRefFrameTmp += MB_WIDTH_LUMA; pCurFrameTmp += MB_WIDTH_LUMA; } pRefFrameY += (iRefStride) << 4; pCurFrameY += (iCurStride) << 4; } } dAverageMotionIndex = dAverageMotionIndex / iMbTotalNum; dAverageTextureIndex = dAverageTextureIndex / iMbTotalNum; if ((dAverageMotionIndex <= PESN) && (dAverageMotionIndex >= -PESN)) { dAverageMotionIndex = 1.0; } if ((dAverageTextureIndex <= PESN) && (dAverageTextureIndex >= -PESN)) { dAverageTextureIndex = 1.0; } // motion mb residual map to QP // texture mb original map to QP iAverMotionTextureIndexToDeltaQp = 0; dAverageMotionIndex = AVERAGE_TIME_MOTION * dAverageMotionIndex; if (m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_QUALITY_MODE) { dAverageTextureIndex = AVERAGE_TIME_TEXTURE_QUALITYMODE * dAverageTextureIndex; } else { dAverageTextureIndex = AVERAGE_TIME_TEXTURE_BITRATEMODE * dAverageTextureIndex; } pMotionTexture = m_sAdaptiveQuantParam.pMotionTextureUnit; for (j = 0; j < iMbHeight; j ++) { for (i = 0; i < iMbWidth; i++) { double a = pMotionTexture->uiTextureIndex / dAverageTextureIndex; dQStep = (a - 1) / (a + MODEL_ALPHA); dLumaTextureDeltaQp = MODEL_TIME * dQStep;// range +- 6 iMotionTextureIndexToDeltaQp = (int8_t)dLumaTextureDeltaQp; a = pMotionTexture->uiMotionIndex / dAverageMotionIndex; dQStep = (a - 1) / (a + MODEL_ALPHA); dLumaMotionDeltaQp = MODEL_TIME * dQStep;// range +- 6 if ((m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_QUALITY_MODE && dLumaMotionDeltaQp < -PESN) || (m_sAdaptiveQuantParam.iAdaptiveQuantMode == AQ_BITRATE_MODE)) { iMotionTextureIndexToDeltaQp += (int8_t)dLumaMotionDeltaQp; } m_sAdaptiveQuantParam.pMotionTextureIndexToDeltaQp[j * iMbWidth + i] = iMotionTextureIndexToDeltaQp; iAverMotionTextureIndexToDeltaQp += iMotionTextureIndexToDeltaQp; pMotionTexture++; } } m_sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp = (1.0 * iAverMotionTextureIndexToDeltaQp) / iMbTotalNum; eReturn = RET_SUCCESS; return eReturn; } EResult CAdaptiveQuantization::Set (int32_t iType, void* pParam) { if (pParam == NULL) { return RET_INVALIDPARAM; } m_sAdaptiveQuantParam = * (SAdaptiveQuantizationParam*)pParam; return RET_SUCCESS; } EResult CAdaptiveQuantization::Get (int32_t iType, void* pParam) { if (pParam == NULL) { return RET_INVALIDPARAM; } SAdaptiveQuantizationParam* sAdaptiveQuantParam = (SAdaptiveQuantizationParam*)pParam; sAdaptiveQuantParam->dAverMotionTextureIndexToDeltaQp = m_sAdaptiveQuantParam.dAverMotionTextureIndexToDeltaQp; return RET_SUCCESS; } /////////////////////////////////////////////////////////////////////////////////////////////// void CAdaptiveQuantization::WelsInitVarFunc (PVarFunc& pfVar, int32_t iCpuFlag) { pfVar = SampleVariance16x16_c; #ifdef X86_ASM if (iCpuFlag & WELS_CPU_SSE2) { pfVar = SampleVariance16x16_sse2; } #endif #ifdef HAVE_NEON if (iCpuFlag & WELS_CPU_NEON) { pfVar = SampleVariance16x16_neon; } #endif } void SampleVariance16x16_c (uint8_t* pRefY, int32_t iRefStride, uint8_t* pSrcY, int32_t iSrcStride, SMotionTextureUnit* pMotionTexture) { uint32_t uiCurSquare = 0, uiSquare = 0; uint16_t uiCurSum = 0, uiSum = 0; for (int32_t y = 0; y < MB_WIDTH_LUMA; y++) { for (int32_t x = 0; x < MB_WIDTH_LUMA; x++) { uint32_t uiDiff = WELS_ABS (pRefY[x] - pSrcY[x]); uiSum += uiDiff; uiSquare += uiDiff * uiDiff; uiCurSum += pSrcY[x]; uiCurSquare += pSrcY[x] * pSrcY[x]; } pRefY += iRefStride; pSrcY += iSrcStride; } uiSum = uiSum >> 8; pMotionTexture->uiMotionIndex = (uiSquare >> 8) - (uiSum * uiSum); uiCurSum = uiCurSum >> 8; pMotionTexture->uiTextureIndex = (uiCurSquare >> 8) - (uiCurSum * uiCurSum); } WELSVP_NAMESPACE_END