Skip to content
Snippets Groups Projects
RateCtrl.cpp 49.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* 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-2019, 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     RateCtrl.cpp
        \brief    Rate control manager class
    */
    #include "RateCtrl.h"
    #include "../CommonLib/ChromaFormat.h"
    
    #include <cmath>
    
    
    using namespace std;
    
    //sequence level
    EncRCSeq::EncRCSeq()
    {
      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;
    
    }
    
    EncRCSeq::~EncRCSeq()
    {
      destroy();
    }
    
    void EncRCSeq::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_t)m_totalFrames * (int64_t)m_targetRate / (int64_t)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; i<m_GOPSize; i++ )
      {
        m_bitsRatio[i] = 1;
      }
    
      m_GOPID2Level = new int[m_GOPSize];
      for ( int i=0; i<m_GOPSize; i++ )
      {
        m_GOPID2Level[i] = 1;
      }
    
      m_picPara = new TRCParameter[m_numberOfLevel];
      for ( int i=0; i<m_numberOfLevel; i++ )
      {
        m_picPara[i].m_alpha = 0.0;
        m_picPara[i].m_beta  = 0.0;
    
        m_picPara[i].m_skipRatio = 0.0;
    
      }
    
      if ( m_useLCUSeparateModel )
      {
        m_LCUPara = new TRCParameter*[m_numberOfLevel];
        for ( int i=0; i<m_numberOfLevel; i++ )
        {
          m_LCUPara[i] = new TRCParameter[m_numberOfLCU];
          for ( int j=0; j<m_numberOfLCU; j++)
          {
            m_LCUPara[i][j].m_alpha = 0.0;
            m_LCUPara[i][j].m_beta  = 0.0;
    
            m_LCUPara[i][j].m_validPix = -1;
    
            m_LCUPara[i][j].m_skipRatio = 0.0;
    
          }
        }
      }
    
      m_framesLeft = m_totalFrames;
      m_bitsLeft   = m_targetBits;
      m_adaptiveBit = adaptiveBit;
      m_lastLambda = 0.0;
    }
    
    void EncRCSeq::destroy()
    {
      if (m_bitsRatio != NULL)
      {
        delete[] m_bitsRatio;
        m_bitsRatio = NULL;
      }
    
      if ( m_GOPID2Level != NULL )
      {
        delete[] m_GOPID2Level;
        m_GOPID2Level = NULL;
      }
    
      if ( m_picPara != NULL )
      {
        delete[] m_picPara;
        m_picPara = NULL;
      }
    
      if ( m_LCUPara != NULL )
      {
        for ( int i=0; i<m_numberOfLevel; i++ )
        {
          delete[] m_LCUPara[i];
        }
        delete[] m_LCUPara;
        m_LCUPara = NULL;
      }
    }
    
    void EncRCSeq::initBitsRatio( int bitsRatio[])
    {
      for (int i=0; i<m_GOPSize; i++)
      {
        m_bitsRatio[i] = bitsRatio[i];
      }
    }
    
    void EncRCSeq::initGOPID2Level( int GOPID2Level[] )
    {
      for ( int i=0; i<m_GOPSize; i++ )
      {
        m_GOPID2Level[i] = GOPID2Level[i];
      }
    }
    
    void EncRCSeq::initPicPara( TRCParameter* picPara )
    {
      CHECK( m_picPara == NULL, "Object does not exist" );
    
      if ( picPara == NULL )
      {
        for ( int i=0; i<m_numberOfLevel; i++ )
        {
          if (i>0)
          {
    
            int bitdepth_luma_scale =
              2
              * (m_bitDepth - 8
                - DISTORTION_PRECISION_ADJUSTMENT(m_bitDepth));
            m_picPara[i].m_alpha = 3.2003 * pow(2.0, bitdepth_luma_scale);
            m_picPara[i].m_beta = -1.367;
    
            int bitdepth_luma_scale =
              2
              * (m_bitDepth - 8
                - DISTORTION_PRECISION_ADJUSTMENT(m_bitDepth));
            m_picPara[i].m_alpha = pow(2.0, bitdepth_luma_scale) * ALPHA;
            m_picPara[i].m_beta = BETA2;
    
          }
        }
      }
      else
      {
        for ( int i=0; i<m_numberOfLevel; i++ )
        {
          m_picPara[i] = picPara[i];
        }
      }
    }
    
    void EncRCSeq::initLCUPara( TRCParameter** LCUPara )
    {
      if ( m_LCUPara == NULL )
      {
        return;
      }
      if ( LCUPara == NULL )
      {
        for ( int i=0; i<m_numberOfLevel; i++ )
        {
          for ( int j=0; j<m_numberOfLCU; j++)
          {
            m_LCUPara[i][j].m_alpha = m_picPara[i].m_alpha;
            m_LCUPara[i][j].m_beta  = m_picPara[i].m_beta;
          }
        }
      }
      else
      {
        for ( int i=0; i<m_numberOfLevel; i++ )
        {
          for ( int j=0; j<m_numberOfLCU; j++)
          {
            m_LCUPara[i][j] = LCUPara[i][j];
          }
        }
      }
    }
    
    void EncRCSeq::updateAfterPic ( int bits )
    {
      m_bitsLeft -= bits;
      m_framesLeft--;
    }
    
    void EncRCSeq::setAllBitRatio( double basicLambda, double* equaCoeffA, double* equaCoeffB )
    {
      int* bitsRatio = new int[m_GOPSize];
      for ( int i=0; i<m_GOPSize; i++ )
      {
    
        bitsRatio[i] = (int)(equaCoeffA[i] * pow(basicLambda, equaCoeffB[i]) * (double)getPicPara(getGOPID2Level(i)).m_validPix);
    
      }
      initBitsRatio( bitsRatio );
      delete[] bitsRatio;
    }
    
    //GOP level
    EncRCGOP::EncRCGOP()
    {
      m_encRCSeq  = NULL;
      m_picTargetBitInGOP = NULL;
      m_numPic     = 0;
      m_targetBits = 0;
      m_picLeft    = 0;
      m_bitsLeft   = 0;
    }
    
    EncRCGOP::~EncRCGOP()
    {
      destroy();
    }
    
    void EncRCGOP::create( EncRCSeq* encRCSeq, int numPic )
    {
      destroy();
      int targetBits = xEstGOPTargetBits( encRCSeq, numPic );
    
      if ( encRCSeq->getAdaptiveBits() > 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;
          }
        }
    
        else if (encRCSeq->getAdaptiveBits() == 3)  // for GOP size = 16, random access case
        {
          {
            int bitdepth_luma_scale =
              2
              * (encRCSeq->getbitDepth() - 8
                - DISTORTION_PRECISION_ADJUSTMENT(encRCSeq->getbitDepth()));
    
            double hierarQp = 4.2005 * log(encRCSeq->getLastLambda() / pow(2.0, bitdepth_luma_scale)) + 13.7122;  //  the qp of POC16
            double qpLev2 = (hierarQp + 0.0) + 0.2016    * (hierarQp + 0.0) - 4.8848;
            double qpLev3 = (hierarQp + 3.0) + 0.22286 * (hierarQp + 3.0) - 5.7476;
            double qpLev4 = (hierarQp + 4.0) + 0.2333    * (hierarQp + 4.0) - 5.9;
            double qpLev5 = (hierarQp + 5.0) + 0.3            * (hierarQp + 5.0) - 7.1444;
    
            double lambdaLev1 = exp((hierarQp - 13.7122) / 4.2005) *pow(2.0, bitdepth_luma_scale);
            double lambdaLev2 = exp((qpLev2 - 13.7122) / 4.2005) * pow(2.0, bitdepth_luma_scale);
            double lambdaLev3 = exp((qpLev3 - 13.7122) / 4.2005) * pow(2.0, bitdepth_luma_scale);
            double lambdaLev4 = exp((qpLev4 - 13.7122) / 4.2005) * pow(2.0, bitdepth_luma_scale);
            double lambdaLev5 = exp((qpLev5 - 13.7122) / 4.2005) * pow(2.0, bitdepth_luma_scale);
    
            lambdaRatio[0] = 1.0;
            lambdaRatio[1] = lambdaLev2 / lambdaLev1;
            lambdaRatio[2] = lambdaLev3 / lambdaLev1;
            lambdaRatio[3] = lambdaLev4 / lambdaLev1;
            lambdaRatio[4] = lambdaLev5 / lambdaLev1;
            lambdaRatio[5] = lambdaLev5 / lambdaLev1;
            lambdaRatio[6] = lambdaLev4 / lambdaLev1;
            lambdaRatio[7] = lambdaLev5 / lambdaLev1;
            lambdaRatio[8] = lambdaLev5 / lambdaLev1;
            lambdaRatio[9] = lambdaLev3 / lambdaLev1;
            lambdaRatio[10] = lambdaLev4 / lambdaLev1;
            lambdaRatio[11] = lambdaLev5 / lambdaLev1;
            lambdaRatio[12] = lambdaLev5 / lambdaLev1;
            lambdaRatio[13] = lambdaLev4 / lambdaLev1;
            lambdaRatio[14] = lambdaLev5 / lambdaLev1;
            lambdaRatio[15] = lambdaLev5 / lambdaLev1;
    
            const double qdfParaLev2A = 0.5847;
            const double qdfParaLev2B = -0.0782;
            const double qdfParaLev3A = 0.5468;
            const double qdfParaLev3B = -0.1364;
            const double qdfParaLev4A = 0.6539;
            const double qdfParaLev4B = -0.203;
            const double qdfParaLev5A = 0.8623;
            const double qdfParaLev5B = -0.4676;
            double qdfLev1Lev2 = Clip3(0.12, 0.9, qdfParaLev2A * encRCSeq->getPicPara(2).m_skipRatio + qdfParaLev2B);
            double qdfLev1Lev3 = Clip3(0.13, 0.9, qdfParaLev3A * encRCSeq->getPicPara(3).m_skipRatio + qdfParaLev3B);
            double qdfLev1Lev4 = Clip3(0.15, 0.9, qdfParaLev4A * encRCSeq->getPicPara(4).m_skipRatio + qdfParaLev4B);
            double qdfLev1Lev5 = Clip3(0.20, 0.9, qdfParaLev5A * encRCSeq->getPicPara(5).m_skipRatio + qdfParaLev5B);
            double qdfLev2Lev3 = Clip3(0.09, 0.9, qdfLev1Lev3 * (1 - qdfLev1Lev2));
            double qdfLev2Lev4 = Clip3(0.12, 0.9, qdfLev1Lev4 * (1 - qdfLev1Lev2));
            double qdfLev2Lev5 = Clip3(0.14, 0.9, qdfLev1Lev5 * (1 - qdfLev1Lev2));
            double qdfLev3Lev4 = Clip3(0.06, 0.9, qdfLev1Lev4 * (1 - qdfLev1Lev3));
            double qdfLev3Lev5 = Clip3(0.09, 0.9, qdfLev1Lev5 * (1 - qdfLev1Lev3));
            double qdfLev4Lev5 = Clip3(0.10, 0.9, qdfLev1Lev5 * (1 - qdfLev1Lev4));
    
            lambdaLev1 = 1 / (1 + 2 * (qdfLev1Lev2 + 2 * qdfLev1Lev3 + 4 * qdfLev1Lev4 + 8 * qdfLev1Lev5));
            lambdaLev2 = 1 / (1 + (3 * qdfLev2Lev3 + 5 * qdfLev2Lev4 + 8 * qdfLev2Lev5));
            lambdaLev3 = 1 / (1 + 2 * qdfLev3Lev4 + 4 * qdfLev3Lev5);
            lambdaLev4 = 1 / (1 + 2 * qdfLev4Lev5);
            lambdaLev5 = 1 / (1.0);
    
            lambdaRatio[1] = lambdaLev2 / lambdaLev1;
            lambdaRatio[2] = lambdaLev3 / lambdaLev1;
            lambdaRatio[3] = lambdaLev4 / lambdaLev1;
            lambdaRatio[4] = lambdaLev5 / lambdaLev1;
            lambdaRatio[5] = lambdaLev5 / lambdaLev1;
            lambdaRatio[6] = lambdaLev4 / lambdaLev1;
            lambdaRatio[7] = lambdaLev5 / lambdaLev1;
            lambdaRatio[8] = lambdaLev5 / lambdaLev1;
            lambdaRatio[9] = lambdaLev3 / lambdaLev1;
            lambdaRatio[10] = lambdaLev4 / lambdaLev1;
            lambdaRatio[11] = lambdaLev5 / lambdaLev1;
            lambdaRatio[12] = lambdaLev5 / lambdaLev1;
            lambdaRatio[13] = lambdaLev4 / lambdaLev1;
            lambdaRatio[14] = lambdaLev5 / lambdaLev1;
            lambdaRatio[15] = lambdaLev5 / lambdaLev1;
    
    
        xCalEquaCoeff( encRCSeq, lambdaRatio, equaCoeffA, equaCoeffB, encRCSeq->getGOPSize() );
    
        basicLambda = xSolveEqua(encRCSeq, 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; i<numPic; i++ )
      {
        totalPicRatio += encRCSeq->getBitRatio( i );
      }
      for ( i=0; i<numPic; i++ )
      {
        currPicRatio = encRCSeq->getBitRatio( 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 EncRCGOP::xCalEquaCoeff( EncRCSeq* encRCSeq, double* lambdaRatio, double* equaCoeffA, double* equaCoeffB, int GOPSize )
    {
      for ( int i=0; i<GOPSize; i++ )
      {
        int frameLevel = encRCSeq->getGOPID2Level(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 EncRCGOP::xSolveEqua(EncRCSeq* encRCSeq, 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<g_RCIterationNum; i++ )
      {
        double fx = 0.0;
        for ( int j=0; j<GOPSize; j++ )
        {
    
          double tmpBpp = equaCoeffA[j] * pow(solution, equaCoeffB[j]);
          double actualBpp = tmpBpp * (double)encRCSeq->getPicPara(encRCSeq->getGOPID2Level(j)).m_validPix / (double)encRCSeq->getNumPixel();
          fx += actualBpp;
    
        }
    
        if ( fabs( fx - targetBpp ) < 0.000001 )
        {
          break;
        }
    
        if ( fx > 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 EncRCGOP::destroy()
    {
      m_encRCSeq = NULL;
      if ( m_picTargetBitInGOP != NULL )
      {
        delete[] m_picTargetBitInGOP;
        m_picTargetBitInGOP = NULL;
      }
    }
    
    void EncRCGOP::updateAfterPicture( int bitsCost )
    {
      m_bitsLeft -= bitsCost;
      m_picLeft--;
    }
    
    int EncRCGOP::xEstGOPTargetBits( EncRCSeq* 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
    EncRCPic::EncRCPic()
    {
      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;
    
      m_picMSE              = 0.0;
      m_validPixelsInPic    = 0;
    
    }
    
    EncRCPic::~EncRCPic()
    {
      destroy();
    }
    
    int EncRCPic::xEstPicTargetBits( EncRCSeq* encRCSeq, EncRCGOP* 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; i<encRCGOP->getNumPic(); 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 EncRCPic::xEstPicHeaderBits( list<EncRCPic*>& listPreviousPictures, int frameLevel )
    {
      int numPreviousPics   = 0;
      int totalPreviousBits = 0;
    
      list<EncRCPic*>::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;
    }
    
    #if V0078_ADAPTIVE_LOWER_BOUND
    int EncRCPic::xEstPicLowerBound(EncRCSeq* encRCSeq, EncRCGOP* encRCGOP)
    {
      int lowerBound = 0;
      int GOPbitsLeft = encRCGOP->getBitsLeft();
    
      const int nextPicPosition = (encRCGOP->getNumPic() - encRCGOP->getPicLeft() + 1) % encRCGOP->getNumPic();
      const int nextPicRatio = encRCSeq->getBitRatio(nextPicPosition);
    
      int totalPicRatio = 0;
      for (int i = nextPicPosition; i < encRCGOP->getNumPic(); i++)
      {
        totalPicRatio += encRCSeq->getBitRatio(i);
      }
    
      if (nextPicPosition == 0)
      {
        GOPbitsLeft = encRCGOP->getTargetBits();
      }
      else
      {
        GOPbitsLeft -= m_targetBits;
      }
    
      lowerBound = int(((double)GOPbitsLeft) * nextPicRatio / totalPicRatio);
    
      if (lowerBound < 100)
      {
        lowerBound = 100;   // at least allocate 100 bits for one picture
      }
    
      if (m_encRCSeq->getFramesLeft() > 16)
      {
        lowerBound = int(g_RCWeightPicRargetBitInBuffer * lowerBound + g_RCWeightPicTargetBitInGOP * m_encRCGOP->getTargetBitInGOP(nextPicPosition));
      }
    
      return lowerBound;
    }
    #endif
    
    void EncRCPic::addToPictureLsit( list<EncRCPic*>& listPreviousPictures )
    {
      if ( listPreviousPictures.size() > g_RCMaxPicListSize )
      {
        EncRCPic* p = listPreviousPictures.front();
        listPreviousPictures.pop_front();
        p->destroy();
        delete p;
      }
    
      listPreviousPictures.push_back( this );
    }
    
    void EncRCPic::create( EncRCSeq* encRCSeq, EncRCGOP* encRCGOP, int frameLevel, list<EncRCPic*>& 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;
    #if V0078_ADAPTIVE_LOWER_BOUND
      m_lowerBound       = xEstPicLowerBound( encRCSeq, encRCGOP );
    #endif
    
      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<picWidthInLCU; i++ )
      {
        for ( j=0; j<picHeightInLCU; j++ )
        {
          LCUIdx = j*picWidthInLCU + i;
          m_LCUs[LCUIdx].m_actualBits = 0;
    
          m_LCUs[LCUIdx].m_actualSSE  = 0.0;
          m_LCUs[LCUIdx].m_actualMSE  = 0.0;
    
          m_LCUs[LCUIdx].m_QP         = 0;
          m_LCUs[LCUIdx].m_lambda     = 0.0;
          m_LCUs[LCUIdx].m_targetBits = 0;
          m_LCUs[LCUIdx].m_bitWeight  = 1.0;
          int currWidth  = ( (i == picWidthInLCU -1) ? picWidth  - LCUWidth *(picWidthInLCU -1) : LCUWidth  );
          int currHeight = ( (j == picHeightInLCU-1) ? picHeight - LCUHeight*(picHeightInLCU-1) : LCUHeight );
          m_LCUs[LCUIdx].m_numberOfPixel = currWidth * currHeight;
        }
      }
      m_picActualHeaderBits = 0;
      m_picActualBits       = 0;
      m_picQP               = 0;
      m_picLambda           = 0.0;
    
      m_validPixelsInPic    = 0;
      m_picMSE              = 0.0;
    
    }
    
    void EncRCPic::destroy()
    {
      if( m_LCUs != NULL )
      {
        delete[] m_LCUs;
        m_LCUs = NULL;
      }
      m_encRCSeq = NULL;
      m_encRCGOP = NULL;
    }
    
    
    
    double EncRCPic::estimatePicLambda( list<EncRCPic*>& listPreviousPictures, bool isIRAP)
    
    {
      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;
    
    
      int lastPicValPix = 0;
      if (listPreviousPictures.size() > 0)
      {
        lastPicValPix = m_encRCSeq->getPicPara(m_frameLevel).m_validPix;
      }
      if (lastPicValPix > 0)
      {
        bpp = (double)m_targetBits / (double)lastPicValPix;
      }
    
    
      {
        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<EncRCPic*>::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;
      }
    
    
      //Avoid different results in different platforms. The problem is caused by the different results of pow() in different platforms.
      estLambda = double(int64_t(estLambda * (double)LAMBDA_PREC + 0.5)) / (double)LAMBDA_PREC;
    
      m_estPicLambda = estLambda;
    
      double totalWeight = 0.0;
      // initial BU bit allocation weight
      for ( int i=0; i<m_numberOfLCU; i++ )
      {
        double alphaLCU, betaLCU;
        if ( m_encRCSeq->getUseLCUSeparateModel() )
        {
          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<m_numberOfLCU; i++ )
      {
        double BUTargetBits = m_targetBits * m_LCUs[i].m_bitWeight / totalWeight;
        m_LCUs[i].m_bitWeight = BUTargetBits;
      }
    
      return estLambda;
    }
    
    int EncRCPic::estimatePicQP( double lambda, list<EncRCPic*>& listPreviousPictures )
    {
    
      int bitdepth_luma_scale =
        2
        * (m_encRCSeq->getbitDepth() - 8
          - DISTORTION_PRECISION_ADJUSTMENT(m_encRCSeq->getbitDepth()));
    
      int QP = int(4.2005 * log(lambda / pow(2.0, bitdepth_luma_scale)) + 13.7122 + 0.5);
    
    
      int lastLevelQP = g_RCInvalidQPValue;
      int lastPicQP   = g_RCInvalidQPValue;
      int lastValidQP = g_RCInvalidQPValue;
      list<EncRCPic*>::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 EncRCPic::getLCUTargetBpp(bool isIRAP)
    
    {
      int   LCUIdx    = getLCUCoded();
      double bpp      = -1.0;
      int avgBits     = 0;
    
    
      {
        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; i<m_numberOfLCU; i++ )
        {
          totalWeight += m_LCUs[i].m_bitWeight;
        }
        int realInfluenceLCU = min( g_RCLCUSmoothWindowSize, getLCULeft() );
        avgBits = (int)( m_LCUs[LCUIdx].m_bitWeight - ( totalWeight - m_bitsLeft ) / realInfluenceLCU + 0.5 );
      }
    
      if ( avgBits < 1 )
      {
        avgBits = 1;
      }
    
      bpp = ( double )avgBits/( double )m_LCUs[ LCUIdx ].m_numberOfPixel;
      m_LCUs[ LCUIdx ].m_targetBits = avgBits;
    
      return bpp;
    }
    
    double EncRCPic::getLCUEstLambda( double bpp )
    {
      int   LCUIdx = getLCUCoded();
      double alpha;
      double beta;
      if ( m_encRCSeq->getUseLCUSeparateModel() )
      {
        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 )
      {