/* The copyright in this software is being made available under the BSD * License, included below. This software may be subject to other third party * and contributor rights, including patent rights, and no such rights are * granted under this license. * * Copyright (c) 2010-2015, ITU/ISO/IEC * 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. * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * 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. */ /** \file WeightPredAnalysis.cpp \brief weighted prediction encoder class */ #include "../TLibCommon/CommonDef.h" #include "../TLibCommon/TComSlice.h" #include "../TLibCommon/TComPic.h" #include "../TLibCommon/TComPicYuv.h" #include "WeightPredAnalysis.h" #define ABS(a) ((a) < 0 ? - (a) : (a)) #define DTHRESH (0.99) WeightPredAnalysis::WeightPredAnalysis() { for ( UInt lst =0 ; lstbPresentFlag = false; pwp->uiLog2WeightDenom = 0; pwp->iWeight = 1; pwp->iOffset = 0; } } } } //! calculate AC and DC values for current original image Void WeightPredAnalysis::xCalcACDCParamSlice(TComSlice *const slice) { //===== calculate AC/DC value ===== TComPicYuv* pPic = slice->getPic()->getPicYuvOrg(); WPACDCParam weightACDCParam[MAX_NUM_COMPONENT]; for(Int componentIndex = 0; componentIndex < pPic->getNumberValidComponents(); componentIndex++) { const ComponentID compID = ComponentID(componentIndex); // calculate DC/AC value for channel const Int iStride = pPic->getStride(compID); const Int iWidth = pPic->getWidth(compID); const Int iHeight = pPic->getHeight(compID); const Int iSample = iWidth*iHeight; Int64 iOrgDC = 0; { const Pel *pPel = pPic->getAddr(compID); for(Int y = 0; y < iHeight; y++, pPel+=iStride ) { for(Int x = 0; x < iWidth; x++ ) { iOrgDC += (Int)( pPel[x] ); } } } const Int64 iOrgNormDC = ((iOrgDC+(iSample>>1)) / iSample); Int64 iOrgAC = 0; { const Pel *pPel = pPic->getAddr(compID); for(Int y = 0; y < iHeight; y++, pPel += iStride ) { for(Int x = 0; x < iWidth; x++ ) { iOrgAC += abs( (Int)pPel[x] - (Int)iOrgNormDC ); } } } const Int fixedBitShift = (slice->getSPS()->getSpsRangeExtension().getHighPrecisionOffsetsEnabledFlag())?RExt__PREDICTION_WEIGHTING_ANALYSIS_DC_PRECISION:0; weightACDCParam[compID].iDC = (((iOrgDC<>1)) / iSample); weightACDCParam[compID].iAC = iOrgAC; } slice->setWpAcDcParam(weightACDCParam); } //! check weighted pred or non-weighted pred Void WeightPredAnalysis::xCheckWPEnable(TComSlice *const slice) { const TComPicYuv *pPic = slice->getPic()->getPicYuvOrg(); Int iPresentCnt = 0; for ( UInt lst=0 ; lstgetNumberValidComponents(); componentIndex++) { WPScalingParam *pwp = &(m_wp[lst][iRefIdx][componentIndex]); iPresentCnt += (Int)pwp->bPresentFlag; } } } if(iPresentCnt==0) { slice->setTestWeightPred(false); slice->setTestWeightBiPred(false); for ( UInt lst=0 ; lstgetNumberValidComponents(); componentIndex++) { WPScalingParam *pwp = &(m_wp[lst][iRefIdx][componentIndex]); pwp->bPresentFlag = false; pwp->uiLog2WeightDenom = 0; pwp->iWeight = 1; pwp->iOffset = 0; } } } slice->setWpScaling( m_wp ); } else { slice->setTestWeightPred(slice->getPPS()->getUseWP()); slice->setTestWeightBiPred(slice->getPPS()->getWPBiPred()); } } //! estimate wp tables for explicit wp Void WeightPredAnalysis::xEstimateWPParamSlice(TComSlice *const slice) { Int iDenom = 6; Bool validRangeFlag = false; if(slice->getNumRefIdx(REF_PIC_LIST_0)>3) { iDenom = 7; } do { validRangeFlag = xUpdatingWPParameters(slice, iDenom); if (!validRangeFlag) { iDenom--; // decrement to satisfy the range limitation } } while (validRangeFlag == false); // selecting whether WP is used, or not (fast search) // NOTE: This is not operating on a slice, but the entire picture. xSelectWP(slice, iDenom); slice->setWpScaling( m_wp ); } //! update wp tables for explicit wp w.r.t range limitation Bool WeightPredAnalysis::xUpdatingWPParameters(TComSlice *const slice, const Int log2Denom) { const Int numComp = slice->getPic()->getPicYuvOrg()->getNumberValidComponents(); const Bool bUseHighPrecisionWeighting = slice->getSPS()->getSpsRangeExtension().getHighPrecisionOffsetsEnabledFlag(); const Int numPredDir = slice->isInterP() ? 1 : 2; assert (numPredDir <= Int(NUM_REF_PIC_LIST_01)); for ( Int refList = 0; refList < numPredDir; refList++ ) { const RefPicList eRefPicList = ( refList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); for ( Int refIdxTemp = 0; refIdxTemp < slice->getNumRefIdx(eRefPicList); refIdxTemp++ ) { WPACDCParam *currWeightACDCParam, *refWeightACDCParam; slice->getWpAcDcParam(currWeightACDCParam); slice->getRefPic(eRefPicList, refIdxTemp)->getSlice(0)->getWpAcDcParam(refWeightACDCParam); for ( Int comp = 0; comp < numComp; comp++ ) { const ComponentID compID = ComponentID(comp); const Int bitDepth = slice->getSPS()->getBitDepth(toChannelType(compID)); const Int range = bUseHighPrecisionWeighting ? (1<> realLog2Denom ); Int clippedOffset; if(isChroma(compID)) // Chroma offset range limination { const Int pred = ( range - ( ( range*weight)>>(log2Denom) ) ); const Int deltaOffset = Clip3( -4*range, 4*range-1, (offset - pred) ); // signed 10bit clippedOffset = Clip3( -range, range-1, (deltaOffset + pred) ); // signed 8bit } else // Luma offset range limitation { clippedOffset = Clip3( -range, range-1, offset); } // Weighting factor limitation const Int defaultWeight = (1<= range || deltaWeight < -range) { return false; } m_wp[refList][refIdxTemp][comp].bPresentFlag = true; m_wp[refList][refIdxTemp][comp].iWeight = weight; m_wp[refList][refIdxTemp][comp].iOffset = clippedOffset; m_wp[refList][refIdxTemp][comp].uiLog2WeightDenom = log2Denom; } } } return true; } //! select whether weighted pred enables or not. Bool WeightPredAnalysis::xSelectWP(TComSlice *const slice, const Int log2Denom) { TComPicYuv *const pPic = slice->getPic()->getPicYuvOrg(); const Int iDefaultWeight = ((Int)1<isInterP() ? 1 : 2; const Bool useHighPrecisionPredictionWeighting = slice->getSPS()->getSpsRangeExtension().getHighPrecisionOffsetsEnabledFlag(); assert (iNumPredDir <= Int(NUM_REF_PIC_LIST_01)); for ( Int iRefList = 0; iRefList < iNumPredDir; iRefList++ ) { const RefPicList eRefPicList = ( iRefList ? REF_PIC_LIST_1 : REF_PIC_LIST_0 ); for ( Int iRefIdxTemp = 0; iRefIdxTemp < slice->getNumRefIdx(eRefPicList); iRefIdxTemp++ ) { Int64 iSADWP = 0, iSADnoWP = 0; for(Int comp=0; compgetNumberValidComponents(); comp++) { const ComponentID compID = ComponentID(comp); Pel *pOrg = pPic->getAddr(compID); Pel *pRef = slice->getRefPic(eRefPicList, iRefIdxTemp)->getPicYuvRec()->getAddr(compID); const Int iOrgStride = pPic->getStride(compID); const Int iRefStride = slice->getRefPic(eRefPicList, iRefIdxTemp)->getPicYuvRec()->getStride(compID); const Int iWidth = pPic->getWidth(compID); const Int iHeight = pPic->getHeight(compID); const Int bitDepth = slice->getSPS()->getBitDepth(toChannelType(compID)); // calculate SAD costs with/without wp for luma iSADWP += xCalcSADvalueWP(bitDepth, pOrg, pRef, iWidth, iHeight, iOrgStride, iRefStride, log2Denom, m_wp[iRefList][iRefIdxTemp][compID].iWeight, m_wp[iRefList][iRefIdxTemp][compID].iOffset, useHighPrecisionPredictionWeighting); iSADnoWP += xCalcSADvalueWP(bitDepth, pOrg, pRef, iWidth, iHeight, iOrgStride, iRefStride, log2Denom, iDefaultWeight, 0, useHighPrecisionPredictionWeighting); } const Double dRatio = ((Double)iSADWP / (Double)iSADnoWP); if(dRatio >= (Double)DTHRESH) { for(Int comp=0; compgetNumberValidComponents(); comp++) { m_wp[iRefList][iRefIdxTemp][comp].bPresentFlag = false; m_wp[iRefList][iRefIdxTemp][comp].iOffset = 0; m_wp[iRefList][iRefIdxTemp][comp].iWeight = iDefaultWeight; m_wp[iRefList][iRefIdxTemp][comp].uiLog2WeightDenom = log2Denom; } } } } return true; } //! calculate SAD values for both WP version and non-WP version. Int64 WeightPredAnalysis::xCalcSADvalueWP(const Int bitDepth, const Pel *pOrgPel, const Pel *pRefPel, const Int iWidth, const Int iHeight, const Int iOrgStride, const Int iRefStride, const Int iLog2Denom, const Int iWeight, const Int iOffset, const Bool useHighPrecisionPredictionWeighting) { const Int64 iSize = iWidth*iHeight; const Int64 iRealLog2Denom = useHighPrecisionPredictionWeighting ? iLog2Denom : (iLog2Denom + (bitDepth - 8)); Int64 iSAD = 0; for( Int y = 0; y < iHeight; y++ ) { for( Int x = 0; x < iWidth; x++ ) { iSAD += ABS(( ((Int64)pOrgPel[x]<<(Int64)iLog2Denom) - ( (Int64)pRefPel[x] * (Int64)iWeight + ((Int64)iOffset<