libbpg/jctvc/TLibEncoder/WeightPredAnalysis.cpp
2015-01-16 13:46:18 +01:00

386 lines
14 KiB
C++

/* 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 ; lst<NUM_REF_PIC_LIST_01 ; lst++ )
{
for ( Int iRefIdx=0 ; iRefIdx<MAX_NUM_REF ; iRefIdx++ )
{
for ( Int comp=0 ; comp<MAX_NUM_COMPONENT ;comp++ )
{
WPScalingParam *pwp = &(m_wp[lst][iRefIdx][comp]);
pwp->bPresentFlag = 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;
weightACDCParam[compID].iDC = (((iOrgDC<<fixedBitShift)+(iSample>>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 ; lst<NUM_REF_PIC_LIST_01 ; lst++ )
{
for ( Int iRefIdx=0 ; iRefIdx<MAX_NUM_REF ; iRefIdx++ )
{
for(Int componentIndex = 0; componentIndex < pPic->getNumberValidComponents(); 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 ; lst<NUM_REF_PIC_LIST_01 ; lst++ )
{
for ( Int iRefIdx=0 ; iRefIdx<MAX_NUM_REF ; iRefIdx++ )
{
for(Int componentIndex = 0; componentIndex < pPic->getNumberValidComponents(); 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);
for ( Int comp = 0; comp < numComp; comp++ )
{
const ComponentID compID = ComponentID(comp);
const Int range = bUseHighPrecisionWeighting ? (1<<g_bitDepth[toChannelType(compID)])/2 : 128;
const Int realLog2Denom = log2Denom + (bUseHighPrecisionWeighting ? RExt__PREDICTION_WEIGHTING_ANALYSIS_DC_PRECISION : (g_bitDepth[toChannelType(compID)] - 8));
const Int realOffset = ((Int)1<<(realLog2Denom-1));
// current frame
const Int64 currDC = currWeightACDCParam[comp].iDC;
const Int64 currAC = currWeightACDCParam[comp].iAC;
// reference frame
const Int64 refDC = refWeightACDCParam[comp].iDC;
const Int64 refAC = refWeightACDCParam[comp].iAC;
// calculating iWeight and iOffset params
const Double dWeight = (refAC==0) ? (Double)1.0 : Clip3( -16.0, 15.0, ((Double)currAC / (Double)refAC) );
const Int weight = (Int)( 0.5 + dWeight * (Double)(1<<log2Denom) );
const Int offset = (Int)( ((currDC<<log2Denom) - ((Int64)weight * refDC) + (Int64)realOffset) >> 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<<log2Denom);
const Int deltaWeight = (defaultWeight - weight);
if(deltaWeight >= 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.
* \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<<log2Denom);
const Int iNumPredDir = slice->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; comp<pPic->getNumberValidComponents(); 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; comp<pPic->getNumberValidComponents(); 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<<iRealLog2Denom) ) ) );
}
pOrgPel += iOrgStride;
pRefPel += iRefStride;
}
return (iSAD/iSize);
}