/* 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-2014, 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/TypeDef.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() { m_weighted_pred_flag = false; m_weighted_bipred_flag = false; for ( UInt lst =0 ; lstbPresentFlag = false; pwp->uiLog2WeightDenom = 0; pwp->iWeight = 1; pwp->iOffset = 0; } } } } /** calculate AC and DC values for current original image * \param TComSlice *slice * \returns Void */ 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()->getUseHighPrecisionPredictionWeighting())?RExt__PREDICTION_WEIGHTING_ANALYSIS_DC_PRECISION:0; #if O0194_WEIGHTED_PREDICTION_CGS weightACDCParam[compID].iSamples = iSample; #endif weightACDCParam[compID].iDC = (((iOrgDC<>1)) / iSample); weightACDCParam[compID].iAC = iOrgAC; } slice->setWpAcDcParam(weightACDCParam); } /** store weighted_pred_flag and weighted_bipred_idc values * \param weighted_pred_flag * \param weighted_bipred_idc * \returns Void */ Void WeightPredAnalysis::xStoreWPparam(const Bool weighted_pred_flag, const Bool weighted_bipred_flag) { m_weighted_pred_flag = weighted_pred_flag; m_weighted_bipred_flag = weighted_bipred_flag; } /** restore weighted_pred_flag and weighted_bipred_idc values * \param TComSlice *slice * \returns Void */ Void WeightPredAnalysis::xRestoreWPparam(TComSlice *const slice) { slice->getPPS()->setUseWP (m_weighted_pred_flag); slice->getPPS()->setWPBiPred(m_weighted_bipred_flag); } /** check weighted pred or non-weighted pred * \param TComSlice *slice * \returns Void */ 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->getPPS()->setUseWP(false); slice->getPPS()->setWPBiPred(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 ); } } /** estimate wp tables for explicit wp * \param TComSlice *slice */ 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 xSelectWP(slice, iDenom); slice->setWpScaling( m_wp ); } /** update wp tables for explicit wp w.r.t ramge limitation * \param TComSlice *slice * \returns Bool */ Bool WeightPredAnalysis::xUpdatingWPParameters(TComSlice *const slice, const Int log2Denom) { const Int numComp = slice->getPic()->getPicYuvOrg()->getNumberValidComponents(); const Bool bUseHighPrecisionWeighting = slice->getSPS()->getUseHighPrecisionPredictionWeighting(); 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); #if O0194_WEIGHTED_PREDICTION_CGS UInt currLayerId = slice->getLayerId(); UInt refLayerId = slice->getRefPic(eRefPicList, refIdxTemp)->getLayerId(); Bool validILRPic = slice->getRefPic(eRefPicList, refIdxTemp)->isILR( currLayerId ) && refLayerId == 0; if( validILRPic ) { refWeightACDCParam = (WPACDCParam *)g_refWeightACDCParam; } #endif for ( Int comp = 0; comp < numComp; comp++ ) { const ComponentID compID = ComponentID(comp); const Int range = bUseHighPrecisionWeighting ? (1<> realLog2Denom ); if( !validILRPic ) { dWeight = 1; offset = 0; } weight = (Int)( 0.5 + dWeight * (Double)(1<> realLog2Denom ); #endif 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; #if O0194_WEIGHTED_PREDICTION_CGS // make sure the reference frames other than ILR are not using weighted prediction else if( !validILRPic ) { continue; } #endif 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. * \param TComSlice *slice * \param log2Denom * \returns Bool */ 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()->getUseHighPrecisionPredictionWeighting(); 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 = g_bitDepth[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. * \param Pel *pOrgPel * \param Pel *pRefPel * \param Int iWidth * \param Int iHeight * \param Int iOrgStride * \param Int iRefStride * \param Int iLog2Denom * \param Int iWeight * \param Int iOffset * \returns Int64 */ 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<