/* 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 TEncRateCtrl.cpp \brief Rate control manager class */ #include "TEncRateCtrl.h" #include "../TLibCommon/TComPic.h" #include "../TLibCommon/TComChromaFormat.h" #include using namespace std; //sequence level TEncRCSeq::TEncRCSeq() { m_totalFrames = 0; m_targetRate = 0; m_frameRate = 0; m_targetBits = 0; m_GOPSize = 0; m_picWidth = 0; m_picHeight = 0; m_LCUWidth = 0; m_LCUHeight = 0; m_numberOfLevel = 0; m_numberOfLCU = 0; m_averageBits = 0; m_bitsRatio = NULL; m_GOPID2Level = NULL; m_picPara = NULL; m_LCUPara = NULL; m_numberOfPixel = 0; m_framesLeft = 0; m_bitsLeft = 0; m_useLCUSeparateModel = false; m_adaptiveBit = 0; m_lastLambda = 0.0; } TEncRCSeq::~TEncRCSeq() { destroy(); } Void TEncRCSeq::create( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int numberOfLevel, Bool useLCUSeparateModel, Int adaptiveBit ) { destroy(); m_totalFrames = totalFrames; m_targetRate = targetBitrate; m_frameRate = frameRate; m_GOPSize = GOPSize; m_picWidth = picWidth; m_picHeight = picHeight; m_LCUWidth = LCUWidth; m_LCUHeight = LCUHeight; m_numberOfLevel = numberOfLevel; m_useLCUSeparateModel = useLCUSeparateModel; m_numberOfPixel = m_picWidth * m_picHeight; m_targetBits = (Int64)m_totalFrames * (Int64)m_targetRate / (Int64)m_frameRate; m_seqTargetBpp = (Double)m_targetRate / (Double)m_frameRate / (Double)m_numberOfPixel; if ( m_seqTargetBpp < 0.03 ) { m_alphaUpdate = 0.01; m_betaUpdate = 0.005; } else if ( m_seqTargetBpp < 0.08 ) { m_alphaUpdate = 0.05; m_betaUpdate = 0.025; } else if ( m_seqTargetBpp < 0.2 ) { m_alphaUpdate = 0.1; m_betaUpdate = 0.05; } else if ( m_seqTargetBpp < 0.5 ) { m_alphaUpdate = 0.2; m_betaUpdate = 0.1; } else { m_alphaUpdate = 0.4; m_betaUpdate = 0.2; } m_averageBits = (Int)(m_targetBits / totalFrames); Int picWidthInBU = ( m_picWidth % m_LCUWidth ) == 0 ? m_picWidth / m_LCUWidth : m_picWidth / m_LCUWidth + 1; Int picHeightInBU = ( m_picHeight % m_LCUHeight ) == 0 ? m_picHeight / m_LCUHeight : m_picHeight / m_LCUHeight + 1; m_numberOfLCU = picWidthInBU * picHeightInBU; m_bitsRatio = new Int[m_GOPSize]; for ( Int i=0; i0) { m_picPara[i].m_alpha = 3.2003; m_picPara[i].m_beta = -1.367; } else { m_picPara[i].m_alpha = ALPHA; m_picPara[i].m_beta = BETA2; } } } else { for ( Int i=0; igetAdaptiveBits() > 0 && encRCSeq->getLastLambda() > 0.1 ) { Double targetBpp = (Double)targetBits / encRCSeq->getNumPixel(); Double basicLambda = 0.0; Double* lambdaRatio = new Double[encRCSeq->getGOPSize()]; Double* equaCoeffA = new Double[encRCSeq->getGOPSize()]; Double* equaCoeffB = new Double[encRCSeq->getGOPSize()]; if ( encRCSeq->getAdaptiveBits() == 1 ) // for GOP size =4, low delay case { if ( encRCSeq->getLastLambda() < 120.0 ) { lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.5793; lambdaRatio[0] = 1.3 * lambdaRatio[1]; lambdaRatio[2] = 1.3 * lambdaRatio[1]; lambdaRatio[3] = 1.0; } else { lambdaRatio[0] = 5.0; lambdaRatio[1] = 4.0; lambdaRatio[2] = 5.0; lambdaRatio[3] = 1.0; } } else if ( encRCSeq->getAdaptiveBits() == 2 ) // for GOP size = 8, random access case { if ( encRCSeq->getLastLambda() < 90.0 ) { lambdaRatio[0] = 1.0; lambdaRatio[1] = 0.725 * log( encRCSeq->getLastLambda() ) + 0.7963; lambdaRatio[2] = 1.3 * lambdaRatio[1]; lambdaRatio[3] = 3.25 * lambdaRatio[1]; lambdaRatio[4] = 3.25 * lambdaRatio[1]; lambdaRatio[5] = 1.3 * lambdaRatio[1]; lambdaRatio[6] = 3.25 * lambdaRatio[1]; lambdaRatio[7] = 3.25 * lambdaRatio[1]; } else { lambdaRatio[0] = 1.0; lambdaRatio[1] = 4.0; lambdaRatio[2] = 5.0; lambdaRatio[3] = 12.3; lambdaRatio[4] = 12.3; lambdaRatio[5] = 5.0; lambdaRatio[6] = 12.3; lambdaRatio[7] = 12.3; } } xCalEquaCoeff( encRCSeq, lambdaRatio, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() ); basicLambda = xSolveEqua( targetBpp, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() ); encRCSeq->setAllBitRatio( basicLambda, equaCoeffA, equaCoeffB ); delete []lambdaRatio; delete []equaCoeffA; delete []equaCoeffB; } m_picTargetBitInGOP = new Int[numPic]; Int i; Int totalPicRatio = 0; Int currPicRatio = 0; for ( i=0; igetBitRatio( i ); } for ( i=0; igetBitRatio( i ); m_picTargetBitInGOP[i] = (Int)( ((Double)targetBits) * currPicRatio / totalPicRatio ); } m_encRCSeq = encRCSeq; m_numPic = numPic; m_targetBits = targetBits; m_picLeft = m_numPic; m_bitsLeft = m_targetBits; } Void TEncRCGOP::xCalEquaCoeff( TEncRCSeq* encRCSeq, Double* lambdaRatio, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize ) { for ( Int i=0; igetGOPID2Level(i); Double alpha = encRCSeq->getPicPara(frameLevel).m_alpha; Double beta = encRCSeq->getPicPara(frameLevel).m_beta; equaCoeffA[i] = pow( 1.0/alpha, 1.0/beta ) * pow( lambdaRatio[i], 1.0/beta ); equaCoeffB[i] = 1.0/beta; } } Double TEncRCGOP::xSolveEqua( Double targetBpp, Double* equaCoeffA, Double* equaCoeffB, Int GOPSize ) { Double solution = 100.0; Double minNumber = 0.1; Double maxNumber = 10000.0; for ( Int i=0; i targetBpp ) { minNumber = solution; solution = ( solution + maxNumber ) / 2.0; } else { maxNumber = solution; solution = ( solution + minNumber ) / 2.0; } } solution = Clip3( 0.1, 10000.0, solution ); return solution; } Void TEncRCGOP::destroy() { m_encRCSeq = NULL; if ( m_picTargetBitInGOP != NULL ) { delete[] m_picTargetBitInGOP; m_picTargetBitInGOP = NULL; } } Void TEncRCGOP::updateAfterPicture( Int bitsCost ) { m_bitsLeft -= bitsCost; m_picLeft--; } Int TEncRCGOP::xEstGOPTargetBits( TEncRCSeq* encRCSeq, Int GOPSize ) { Int realInfluencePicture = min( g_RCSmoothWindowSize, encRCSeq->getFramesLeft() ); Int averageTargetBitsPerPic = (Int)( encRCSeq->getTargetBits() / encRCSeq->getTotalFrames() ); Int currentTargetBitsPerPic = (Int)( ( encRCSeq->getBitsLeft() - averageTargetBitsPerPic * (encRCSeq->getFramesLeft() - realInfluencePicture) ) / realInfluencePicture ); Int targetBits = currentTargetBitsPerPic * GOPSize; if ( targetBits < 200 ) { targetBits = 200; // at least allocate 200 bits for one GOP } return targetBits; } //picture level TEncRCPic::TEncRCPic() { m_encRCSeq = NULL; m_encRCGOP = NULL; m_frameLevel = 0; m_numberOfPixel = 0; m_numberOfLCU = 0; m_targetBits = 0; m_estHeaderBits = 0; m_estPicQP = 0; m_estPicLambda = 0.0; m_LCULeft = 0; m_bitsLeft = 0; m_pixelsLeft = 0; m_LCUs = NULL; m_picActualHeaderBits = 0; m_picActualBits = 0; m_picQP = 0; m_picLambda = 0.0; } TEncRCPic::~TEncRCPic() { destroy(); } Int TEncRCPic::xEstPicTargetBits( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP ) { Int targetBits = 0; Int GOPbitsLeft = encRCGOP->getBitsLeft(); Int i; Int currPicPosition = encRCGOP->getNumPic()-encRCGOP->getPicLeft(); Int currPicRatio = encRCSeq->getBitRatio( currPicPosition ); Int totalPicRatio = 0; for ( i=currPicPosition; igetNumPic(); i++ ) { totalPicRatio += encRCSeq->getBitRatio( i ); } targetBits = Int( ((Double)GOPbitsLeft) * currPicRatio / totalPicRatio ); if ( targetBits < 100 ) { targetBits = 100; // at least allocate 100 bits for one picture } if ( m_encRCSeq->getFramesLeft() > 16 ) { targetBits = Int( g_RCWeightPicRargetBitInBuffer * targetBits + g_RCWeightPicTargetBitInGOP * m_encRCGOP->getTargetBitInGOP( currPicPosition ) ); } return targetBits; } Int TEncRCPic::xEstPicHeaderBits( list& listPreviousPictures, Int frameLevel ) { Int numPreviousPics = 0; Int totalPreviousBits = 0; list::iterator it; for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) { if ( (*it)->getFrameLevel() == frameLevel ) { totalPreviousBits += (*it)->getPicActualHeaderBits(); numPreviousPics++; } } Int estHeaderBits = 0; if ( numPreviousPics > 0 ) { estHeaderBits = totalPreviousBits / numPreviousPics; } return estHeaderBits; } Void TEncRCPic::addToPictureLsit( list& listPreviousPictures ) { if ( listPreviousPictures.size() > g_RCMaxPicListSize ) { TEncRCPic* p = listPreviousPictures.front(); listPreviousPictures.pop_front(); p->destroy(); delete p; } listPreviousPictures.push_back( this ); } Void TEncRCPic::create( TEncRCSeq* encRCSeq, TEncRCGOP* encRCGOP, Int frameLevel, list& listPreviousPictures ) { destroy(); m_encRCSeq = encRCSeq; m_encRCGOP = encRCGOP; Int targetBits = xEstPicTargetBits( encRCSeq, encRCGOP ); Int estHeaderBits = xEstPicHeaderBits( listPreviousPictures, frameLevel ); if ( targetBits < estHeaderBits + 100 ) { targetBits = estHeaderBits + 100; // at least allocate 100 bits for picture data } m_frameLevel = frameLevel; m_numberOfPixel = encRCSeq->getNumPixel(); m_numberOfLCU = encRCSeq->getNumberOfLCU(); m_estPicLambda = 100.0; m_targetBits = targetBits; m_estHeaderBits = estHeaderBits; m_bitsLeft = m_targetBits; Int picWidth = encRCSeq->getPicWidth(); Int picHeight = encRCSeq->getPicHeight(); Int LCUWidth = encRCSeq->getLCUWidth(); Int LCUHeight = encRCSeq->getLCUHeight(); Int picWidthInLCU = ( picWidth % LCUWidth ) == 0 ? picWidth / LCUWidth : picWidth / LCUWidth + 1; Int picHeightInLCU = ( picHeight % LCUHeight ) == 0 ? picHeight / LCUHeight : picHeight / LCUHeight + 1; m_LCULeft = m_numberOfLCU; m_bitsLeft -= m_estHeaderBits; m_pixelsLeft = m_numberOfPixel; m_LCUs = new TRCLCU[m_numberOfLCU]; Int i, j; Int LCUIdx; for ( i=0; i& listPreviousPictures, SliceType eSliceType) { Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; Double bpp = (Double)m_targetBits/(Double)m_numberOfPixel; Double estLambda; if (eSliceType == I_SLICE) { estLambda = calculateLambdaIntra(alpha, beta, pow(m_totalCostIntra/(Double)m_numberOfPixel, BETA1), bpp); } else { estLambda = alpha * pow( bpp, beta ); } Double lastLevelLambda = -1.0; Double lastPicLambda = -1.0; Double lastValidLambda = -1.0; list::iterator it; for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) { if ( (*it)->getFrameLevel() == m_frameLevel ) { lastLevelLambda = (*it)->getPicActualLambda(); } lastPicLambda = (*it)->getPicActualLambda(); if ( lastPicLambda > 0.0 ) { lastValidLambda = lastPicLambda; } } if ( lastLevelLambda > 0.0 ) { lastLevelLambda = Clip3( 0.1, 10000.0, lastLevelLambda ); estLambda = Clip3( lastLevelLambda * pow( 2.0, -3.0/3.0 ), lastLevelLambda * pow( 2.0, 3.0/3.0 ), estLambda ); } if ( lastPicLambda > 0.0 ) { lastPicLambda = Clip3( 0.1, 2000.0, lastPicLambda ); estLambda = Clip3( lastPicLambda * pow( 2.0, -10.0/3.0 ), lastPicLambda * pow( 2.0, 10.0/3.0 ), estLambda ); } else if ( lastValidLambda > 0.0 ) { lastValidLambda = Clip3( 0.1, 2000.0, lastValidLambda ); estLambda = Clip3( lastValidLambda * pow(2.0, -10.0/3.0), lastValidLambda * pow(2.0, 10.0/3.0), estLambda ); } else { estLambda = Clip3( 0.1, 10000.0, estLambda ); } if ( estLambda < 0.1 ) { estLambda = 0.1; } m_estPicLambda = estLambda; Double totalWeight = 0.0; // initial BU bit allocation weight for ( Int i=0; igetUseLCUSeparateModel() ) { alphaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_alpha; betaLCU = m_encRCSeq->getLCUPara( m_frameLevel, i ).m_beta; } else { alphaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; betaLCU = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; } m_LCUs[i].m_bitWeight = m_LCUs[i].m_numberOfPixel * pow( estLambda/alphaLCU, 1.0/betaLCU ); if ( m_LCUs[i].m_bitWeight < 0.01 ) { m_LCUs[i].m_bitWeight = 0.01; } totalWeight += m_LCUs[i].m_bitWeight; } for ( Int i=0; i& listPreviousPictures ) { Int QP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); Int lastLevelQP = g_RCInvalidQPValue; Int lastPicQP = g_RCInvalidQPValue; Int lastValidQP = g_RCInvalidQPValue; list::iterator it; for ( it = listPreviousPictures.begin(); it != listPreviousPictures.end(); it++ ) { if ( (*it)->getFrameLevel() == m_frameLevel ) { lastLevelQP = (*it)->getPicActualQP(); } lastPicQP = (*it)->getPicActualQP(); if ( lastPicQP > g_RCInvalidQPValue ) { lastValidQP = lastPicQP; } } if ( lastLevelQP > g_RCInvalidQPValue ) { QP = Clip3( lastLevelQP - 3, lastLevelQP + 3, QP ); } if( lastPicQP > g_RCInvalidQPValue ) { QP = Clip3( lastPicQP - 10, lastPicQP + 10, QP ); } else if( lastValidQP > g_RCInvalidQPValue ) { QP = Clip3( lastValidQP - 10, lastValidQP + 10, QP ); } return QP; } Double TEncRCPic::getLCUTargetBpp(SliceType eSliceType) { Int LCUIdx = getLCUCoded(); Double bpp = -1.0; Int avgBits = 0; if (eSliceType == I_SLICE) { Int noOfLCUsLeft = m_numberOfLCU - LCUIdx + 1; Int bitrateWindow = min(4,noOfLCUsLeft); Double MAD = getLCU(LCUIdx).m_costIntra; if (m_remainingCostIntra > 0.1 ) { Double weightedBitsLeft = (m_bitsLeft*bitrateWindow+(m_bitsLeft-getLCU(LCUIdx).m_targetBitsLeft)*noOfLCUsLeft)/(Double)bitrateWindow; avgBits = Int( MAD*weightedBitsLeft/m_remainingCostIntra ); } else { avgBits = Int( m_bitsLeft / m_LCULeft ); } m_remainingCostIntra -= MAD; } else { Double totalWeight = 0; for ( Int i=LCUIdx; igetUseLCUSeparateModel() ) { alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha; beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta; } else { alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; } Double estLambda = alpha * pow( bpp, beta ); //for Lambda clip, picture level clip Double clipPicLambda = m_estPicLambda; //for Lambda clip, LCU level clip Double clipNeighbourLambda = -1.0; for ( Int i=LCUIdx - 1; i>=0; i-- ) { if ( m_LCUs[i].m_lambda > 0 ) { clipNeighbourLambda = m_LCUs[i].m_lambda; break; } } if ( clipNeighbourLambda > 0.0 ) { estLambda = Clip3( clipNeighbourLambda * pow( 2.0, -1.0/3.0 ), clipNeighbourLambda * pow( 2.0, 1.0/3.0 ), estLambda ); } if ( clipPicLambda > 0.0 ) { estLambda = Clip3( clipPicLambda * pow( 2.0, -2.0/3.0 ), clipPicLambda * pow( 2.0, 2.0/3.0 ), estLambda ); } else { estLambda = Clip3( 10.0, 1000.0, estLambda ); } if ( estLambda < 0.1 ) { estLambda = 0.1; } return estLambda; } Int TEncRCPic::getLCUEstQP( Double lambda, Int clipPicQP ) { Int LCUIdx = getLCUCoded(); Int estQP = Int( 4.2005 * log( lambda ) + 13.7122 + 0.5 ); //for Lambda clip, LCU level clip Int clipNeighbourQP = g_RCInvalidQPValue; for ( Int i=LCUIdx - 1; i>=0; i-- ) { if ( (getLCU(i)).m_QP > g_RCInvalidQPValue ) { clipNeighbourQP = getLCU(i).m_QP; break; } } if ( clipNeighbourQP > g_RCInvalidQPValue ) { estQP = Clip3( clipNeighbourQP - 1, clipNeighbourQP + 1, estQP ); } estQP = Clip3( clipPicQP - 2, clipPicQP + 2, estQP ); return estQP; } Void TEncRCPic::updateAfterCTU( Int LCUIdx, Int bits, Int QP, Double lambda, Bool updateLCUParameter ) { m_LCUs[LCUIdx].m_actualBits = bits; m_LCUs[LCUIdx].m_QP = QP; m_LCUs[LCUIdx].m_lambda = lambda; m_LCULeft--; m_bitsLeft -= bits; m_pixelsLeft -= m_LCUs[LCUIdx].m_numberOfPixel; if ( !updateLCUParameter ) { return; } if ( !m_encRCSeq->getUseLCUSeparateModel() ) { return; } Double alpha = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_alpha; Double beta = m_encRCSeq->getLCUPara( m_frameLevel, LCUIdx ).m_beta; Int LCUActualBits = m_LCUs[LCUIdx].m_actualBits; Int LCUTotalPixels = m_LCUs[LCUIdx].m_numberOfPixel; Double bpp = ( Double )LCUActualBits/( Double )LCUTotalPixels; Double calLambda = alpha * pow( bpp, beta ); Double inputLambda = m_LCUs[LCUIdx].m_lambda; if( inputLambda < 0.01 || calLambda < 0.01 || bpp < 0.0001 ) { alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 ); beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 ); alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); TRCParameter rcPara; rcPara.m_alpha = alpha; rcPara.m_beta = beta; m_encRCSeq->setLCUPara( m_frameLevel, LCUIdx, rcPara ); return; } calLambda = Clip3( inputLambda / 10.0, inputLambda * 10.0, calLambda ); alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha; Double lnbpp = log( bpp ); lnbpp = Clip3( -5.0, -0.1, lnbpp ); beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp; alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); TRCParameter rcPara; rcPara.m_alpha = alpha; rcPara.m_beta = beta; m_encRCSeq->setLCUPara( m_frameLevel, LCUIdx, rcPara ); } Double TEncRCPic::calAverageQP() { Int totalQPs = 0; Int numTotalLCUs = 0; Int i; for ( i=0; i 0 ) { totalQPs += m_LCUs[i].m_QP; numTotalLCUs++; } } Double avgQP = 0.0; if ( numTotalLCUs == 0 ) { avgQP = g_RCInvalidQPValue; } else { avgQP = ((Double)totalQPs) / ((Double)numTotalLCUs); } return avgQP; } Double TEncRCPic::calAverageLambda() { Double totalLambdas = 0.0; Int numTotalLCUs = 0; Int i; for ( i=0; i 0.01 ) { totalLambdas += log( m_LCUs[i].m_lambda ); numTotalLCUs++; } } Double avgLambda; if( numTotalLCUs == 0 ) { avgLambda = -1.0; } else { avgLambda = pow( 2.7183, totalLambdas / numTotalLCUs ); } return avgLambda; } Void TEncRCPic::updateAfterPicture( Int actualHeaderBits, Int actualTotalBits, Double averageQP, Double averageLambda, SliceType eSliceType) { m_picActualHeaderBits = actualHeaderBits; m_picActualBits = actualTotalBits; if ( averageQP > 0.0 ) { m_picQP = Int( averageQP + 0.5 ); } else { m_picQP = g_RCInvalidQPValue; } m_picLambda = averageLambda; Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; if (eSliceType == I_SLICE) { updateAlphaBetaIntra(&alpha, &beta); } else { // update parameters Double picActualBits = ( Double )m_picActualBits; Double picActualBpp = picActualBits/(Double)m_numberOfPixel; Double calLambda = alpha * pow( picActualBpp, beta ); Double inputLambda = m_picLambda; if ( inputLambda < 0.01 || calLambda < 0.01 || picActualBpp < 0.0001 ) { alpha *= ( 1.0 - m_encRCSeq->getAlphaUpdate() / 2.0 ); beta *= ( 1.0 - m_encRCSeq->getBetaUpdate() / 2.0 ); alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); TRCParameter rcPara; rcPara.m_alpha = alpha; rcPara.m_beta = beta; m_encRCSeq->setPicPara( m_frameLevel, rcPara ); return; } calLambda = Clip3( inputLambda / 10.0, inputLambda * 10.0, calLambda ); alpha += m_encRCSeq->getAlphaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * alpha; Double lnbpp = log( picActualBpp ); lnbpp = Clip3( -5.0, -0.1, lnbpp ); beta += m_encRCSeq->getBetaUpdate() * ( log( inputLambda ) - log( calLambda ) ) * lnbpp; alpha = Clip3( g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha ); beta = Clip3( g_RCBetaMinValue, g_RCBetaMaxValue, beta ); } TRCParameter rcPara; rcPara.m_alpha = alpha; rcPara.m_beta = beta; m_encRCSeq->setPicPara( m_frameLevel, rcPara ); if ( m_frameLevel == 1 ) { Double currLambda = Clip3( 0.1, 10000.0, m_picLambda ); Double updateLastLambda = g_RCWeightHistoryLambda * m_encRCSeq->getLastLambda() + g_RCWeightCurrentLambda * currLambda; m_encRCSeq->setLastLambda( updateLastLambda ); } } Int TEncRCPic::getRefineBitsForIntra( Int orgBits ) { Double alpha=0.25, beta=0.5582; Int iIntraBits; if (orgBits*40 < m_numberOfPixel) { alpha=0.25; } else { alpha=0.30; } iIntraBits = (Int)(alpha* pow(m_totalCostIntra*4.0/(Double)orgBits, beta)*(Double)orgBits+0.5); return iIntraBits; } Double TEncRCPic::calculateLambdaIntra(Double alpha, Double beta, Double MADPerPixel, Double bitsPerPixel) { return ( (alpha/256.0) * pow( MADPerPixel/bitsPerPixel, beta ) ); } Void TEncRCPic::updateAlphaBetaIntra(Double *alpha, Double *beta) { Double lnbpp = log(pow(m_totalCostIntra / (Double)m_numberOfPixel, BETA1)); Double diffLambda = (*beta)*(log((Double)m_picActualBits)-log((Double)m_targetBits)); diffLambda = Clip3(-0.125, 0.125, 0.25*diffLambda); *alpha = (*alpha) * exp(diffLambda); *beta = (*beta) + diffLambda / lnbpp; } Void TEncRCPic::getLCUInitTargetBits() { Int iAvgBits = 0; m_remainingCostIntra = m_totalCostIntra; for (Int i=m_numberOfLCU-1; i>=0; i--) { iAvgBits += Int(m_targetBits * getLCU(i).m_costIntra/m_totalCostIntra); getLCU(i).m_targetBitsLeft = iAvgBits; } } Double TEncRCPic::getLCUEstLambdaAndQP(Double bpp, Int clipPicQP, Int *estQP) { Int LCUIdx = getLCUCoded(); Double alpha = m_encRCSeq->getPicPara( m_frameLevel ).m_alpha; Double beta = m_encRCSeq->getPicPara( m_frameLevel ).m_beta; Double costPerPixel = getLCU(LCUIdx).m_costIntra/(Double)getLCU(LCUIdx).m_numberOfPixel; costPerPixel = pow(costPerPixel, BETA1); Double estLambda = calculateLambdaIntra(alpha, beta, costPerPixel, bpp); Int clipNeighbourQP = g_RCInvalidQPValue; for (Int i=LCUIdx-1; i>=0; i--) { if ((getLCU(i)).m_QP > g_RCInvalidQPValue) { clipNeighbourQP = getLCU(i).m_QP; break; } } Int minQP = clipPicQP - 2; Int maxQP = clipPicQP + 2; if ( clipNeighbourQP > g_RCInvalidQPValue ) { maxQP = min(clipNeighbourQP + 1, maxQP); minQP = max(clipNeighbourQP - 1, minQP); } Double maxLambda=exp(((Double)(maxQP+0.49)-13.7122)/4.2005); Double minLambda=exp(((Double)(minQP-0.49)-13.7122)/4.2005); estLambda = Clip3(minLambda, maxLambda, estLambda); *estQP = Int( 4.2005 * log(estLambda) + 13.7122 + 0.5 ); *estQP = Clip3(minQP, maxQP, *estQP); return estLambda; } TEncRateCtrl::TEncRateCtrl() { m_encRCSeq = NULL; m_encRCGOP = NULL; m_encRCPic = NULL; } TEncRateCtrl::~TEncRateCtrl() { destroy(); } Void TEncRateCtrl::destroy() { if ( m_encRCSeq != NULL ) { delete m_encRCSeq; m_encRCSeq = NULL; } if ( m_encRCGOP != NULL ) { delete m_encRCGOP; m_encRCGOP = NULL; } while ( m_listRCPictures.size() > 0 ) { TEncRCPic* p = m_listRCPictures.front(); m_listRCPictures.pop_front(); delete p; } } Void TEncRateCtrl::init( Int totalFrames, Int targetBitrate, Int frameRate, Int GOPSize, Int picWidth, Int picHeight, Int LCUWidth, Int LCUHeight, Int keepHierBits, Bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP] ) { destroy(); Bool isLowdelay = true; for ( Int i=0; i GOPList[i+1].m_POC ) { isLowdelay = false; break; } } Int numberOfLevel = 1; Int adaptiveBit = 0; if ( keepHierBits > 0 ) { numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1; } if ( !isLowdelay && GOPSize == 8 ) { numberOfLevel = Int( log((Double)GOPSize)/log(2.0) + 0.5 ) + 1; } numberOfLevel++; // intra picture numberOfLevel++; // non-reference picture Int* bitsRatio; bitsRatio = new Int[ GOPSize ]; for ( Int i=0; i 0 ) { Double bpp = (Double)( targetBitrate / (Double)( frameRate*picWidth*picHeight ) ); if ( GOPSize == 4 && isLowdelay ) { if ( bpp > 0.2 ) { bitsRatio[0] = 2; bitsRatio[1] = 3; bitsRatio[2] = 2; bitsRatio[3] = 6; } else if( bpp > 0.1 ) { bitsRatio[0] = 2; bitsRatio[1] = 3; bitsRatio[2] = 2; bitsRatio[3] = 10; } else if ( bpp > 0.05 ) { bitsRatio[0] = 2; bitsRatio[1] = 3; bitsRatio[2] = 2; bitsRatio[3] = 12; } else { bitsRatio[0] = 2; bitsRatio[1] = 3; bitsRatio[2] = 2; bitsRatio[3] = 14; } if ( keepHierBits == 2 ) { adaptiveBit = 1; } } else if ( GOPSize == 8 && !isLowdelay ) { if ( bpp > 0.2 ) { bitsRatio[0] = 15; bitsRatio[1] = 5; bitsRatio[2] = 4; bitsRatio[3] = 1; bitsRatio[4] = 1; bitsRatio[5] = 4; bitsRatio[6] = 1; bitsRatio[7] = 1; } else if ( bpp > 0.1 ) { bitsRatio[0] = 20; bitsRatio[1] = 6; bitsRatio[2] = 4; bitsRatio[3] = 1; bitsRatio[4] = 1; bitsRatio[5] = 4; bitsRatio[6] = 1; bitsRatio[7] = 1; } else if ( bpp > 0.05 ) { bitsRatio[0] = 25; bitsRatio[1] = 7; bitsRatio[2] = 4; bitsRatio[3] = 1; bitsRatio[4] = 1; bitsRatio[5] = 4; bitsRatio[6] = 1; bitsRatio[7] = 1; } else { bitsRatio[0] = 30; bitsRatio[1] = 8; bitsRatio[2] = 4; bitsRatio[3] = 1; bitsRatio[4] = 1; bitsRatio[5] = 4; bitsRatio[6] = 1; bitsRatio[7] = 1; } if ( keepHierBits == 2 ) { adaptiveBit = 2; } } else { printf( "\n hierarchical bit allocation is not support for the specified coding structure currently.\n" ); } } Int* GOPID2Level = new Int[ GOPSize ]; for ( Int i=0; i 0 ) { if ( GOPSize == 4 && isLowdelay ) { GOPID2Level[0] = 3; GOPID2Level[1] = 2; GOPID2Level[2] = 3; GOPID2Level[3] = 1; } else if ( GOPSize == 8 && !isLowdelay ) { GOPID2Level[0] = 1; GOPID2Level[1] = 2; GOPID2Level[2] = 3; GOPID2Level[3] = 4; GOPID2Level[4] = 4; GOPID2Level[5] = 3; GOPID2Level[6] = 4; GOPID2Level[7] = 4; } } if ( !isLowdelay && GOPSize == 8 ) { GOPID2Level[0] = 1; GOPID2Level[1] = 2; GOPID2Level[2] = 3; GOPID2Level[3] = 4; GOPID2Level[4] = 4; GOPID2Level[5] = 3; GOPID2Level[6] = 4; GOPID2Level[7] = 4; } m_encRCSeq = new TEncRCSeq; m_encRCSeq->create( totalFrames, targetBitrate, frameRate, GOPSize, picWidth, picHeight, LCUWidth, LCUHeight, numberOfLevel, useLCUSeparateModel, adaptiveBit ); m_encRCSeq->initBitsRatio( bitsRatio ); m_encRCSeq->initGOPID2Level( GOPID2Level ); m_encRCSeq->initPicPara(); if ( useLCUSeparateModel ) { m_encRCSeq->initLCUPara(); } delete[] bitsRatio; delete[] GOPID2Level; } Void TEncRateCtrl::initRCPic( Int frameLevel ) { m_encRCPic = new TEncRCPic; m_encRCPic->create( m_encRCSeq, m_encRCGOP, frameLevel, m_listRCPictures ); } Void TEncRateCtrl::initRCGOP( Int numberOfPictures ) { m_encRCGOP = new TEncRCGOP; m_encRCGOP->create( m_encRCSeq, numberOfPictures ); } Void TEncRateCtrl::destroyRCGOP() { delete m_encRCGOP; m_encRCGOP = NULL; }