Skip to content
Snippets Groups Projects
RateCtrl.h 15.1 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-2018, 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.h
        \brief    Rate control manager class
    */
    
    #ifndef __ENCRATECTRL__
    #define __ENCRATECTRL__
    
    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    
    
    #include "../CommonLib/CommonDef.h"
    
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    //! \ingroup EncoderLib
    //! \{
    
    #include "../EncoderLib/EncCfg.h"
    #include <list>
    
    const int g_RCInvalidQPValue = -999;
    const int g_RCSmoothWindowSize = 40;
    const int g_RCMaxPicListSize = 32;
    const double g_RCWeightPicTargetBitInGOP    = 0.9;
    const double g_RCWeightPicRargetBitInBuffer = 1.0 - g_RCWeightPicTargetBitInGOP;
    const int g_RCIterationNum = 20;
    const double g_RCWeightHistoryLambda = 0.5;
    const double g_RCWeightCurrentLambda = 1.0 - g_RCWeightHistoryLambda;
    const int g_RCLCUSmoothWindowSize = 4;
    const double g_RCAlphaMinValue = 0.05;
    const double g_RCAlphaMaxValue = 500.0;
    const double g_RCBetaMinValue  = -3.0;
    const double g_RCBetaMaxValue  = -0.1;
    
    #define ALPHA     6.7542;
    #define BETA1     1.2517
    #define BETA2     1.7860
    
    struct TRCLCU
    {
      int m_actualBits;
      int m_QP;     // QP of skip mode is set to g_RCInvalidQPValue
      int m_targetBits;
      double m_lambda;
      double m_bitWeight;
      int m_numberOfPixel;
      double m_costIntra;
      int m_targetBitsLeft;
    
    #if JVET_K0390_RATECTRL
      double m_actualSSE;
      double m_actualMSE;
    #endif
    
    #if JVET_K0390_RATECTRL
      int    m_validPix;
    #endif
    
    };
    
    class EncRCSeq
    {
    public:
      EncRCSeq();
      ~EncRCSeq();
    
    public:
      void create( int totalFrames, int targetBitrate, int frameRate, int GOPSize, int picWidth, int picHeight, int LCUWidth, int LCUHeight, int numberOfLevel, bool useLCUSeparateModel, int adaptiveBit );
      void destroy();
      void initBitsRatio( int bitsRatio[] );
      void initGOPID2Level( int GOPID2Level[] );
      void initPicPara( TRCParameter* picPara  = NULL );    // NULL to initial with default value
      void initLCUPara( TRCParameter** LCUPara = NULL );    // NULL to initial with default value
      void updateAfterPic ( int bits );
      void setAllBitRatio( double basicLambda, double* equaCoeffA, double* equaCoeffB );
    
    public:
      int  getTotalFrames()                 { return m_totalFrames; }
      int  getTargetRate()                  { return m_targetRate; }
      int  getFrameRate()                   { return m_frameRate; }
      int  getGOPSize()                     { return m_GOPSize; }
      int  getPicWidth()                    { return m_picWidth; }
      int  getPicHeight()                   { return m_picHeight; }
      int  getLCUWidth()                    { return m_LCUWidth; }
      int  getLCUHeight()                   { return m_LCUHeight; }
      int  getNumberOfLevel()               { return m_numberOfLevel; }
      int  getAverageBits()                 { return m_averageBits; }
      int  getLeftAverageBits()             { CHECK(!( m_framesLeft > 0 ), "No frames left"); return (int)(m_bitsLeft / m_framesLeft); }
      bool getUseLCUSeparateModel()         { return m_useLCUSeparateModel; }
    
      int  getNumPixel()                    { return m_numberOfPixel; }
      int64_t  getTargetBits()                { return m_targetBits; }
      int  getNumberOfLCU()                 { return m_numberOfLCU; }
      int* getBitRatio()                    { return m_bitsRatio; }
      int  getBitRatio( int idx )           { CHECK(!( idx<m_GOPSize), "Idx exceeds GOP size"); return m_bitsRatio[idx]; }
      int* getGOPID2Level()                 { return m_GOPID2Level; }
      int  getGOPID2Level( int ID )         { CHECK(!( ID < m_GOPSize ), "Idx exceeds GOP size"); return m_GOPID2Level[ID]; }
      TRCParameter*  getPicPara()                                   { return m_picPara; }
      TRCParameter   getPicPara( int level )                        { CHECK(!( level < m_numberOfLevel ), "Level too big"); return m_picPara[level]; }
      void           setPicPara( int level, TRCParameter para )     { CHECK(!( level < m_numberOfLevel ), "Level too big"); m_picPara[level] = para; }
      TRCParameter** getLCUPara()                                   { return m_LCUPara; }
      TRCParameter*  getLCUPara( int level )                        { CHECK(!( level < m_numberOfLevel ), "Level too big"); return m_LCUPara[level]; }
      TRCParameter   getLCUPara( int level, int LCUIdx )            { CHECK(!( LCUIdx  < m_numberOfLCU ), "LCU id exceeds number of LCU"); return getLCUPara(level)[LCUIdx]; }
      void           setLCUPara( int level, int LCUIdx, TRCParameter para ) { CHECK(!( level < m_numberOfLevel ), "Level too big"); CHECK(!( LCUIdx  < m_numberOfLCU ), "LCU id exceeds number of LCU"); m_LCUPara[level][LCUIdx] = para; }
    
      int  getFramesLeft()                  { return m_framesLeft; }
      int64_t  getBitsLeft()                  { return m_bitsLeft; }
    
      double getSeqBpp()                    { return m_seqTargetBpp; }
      double getAlphaUpdate()               { return m_alphaUpdate; }
      double getBetaUpdate()                { return m_betaUpdate; }
    
      int    getAdaptiveBits()              { return m_adaptiveBit;  }
      double getLastLambda()                { return m_lastLambda;   }
      void   setLastLambda( double lamdba ) { m_lastLambda = lamdba; }
    
    #if RATECTRL_FIX_FULLNBIT
      void setBitDepth(int bitDepth) { m_bitDepth = bitDepth; }
      int getbitDepth() { return m_bitDepth; }
    #endif
    
    
    private:
      int m_totalFrames;
      int m_targetRate;
      int m_frameRate;
      int m_GOPSize;
      int m_picWidth;
      int m_picHeight;
      int m_LCUWidth;
      int m_LCUHeight;
      int m_numberOfLevel;
      int m_averageBits;
    
      int m_numberOfPixel;
      int64_t m_targetBits;
      int m_numberOfLCU;
      int* m_bitsRatio;
      int* m_GOPID2Level;
      TRCParameter*  m_picPara;
      TRCParameter** m_LCUPara;
    
      int m_framesLeft;
      int64_t m_bitsLeft;
      double m_seqTargetBpp;
      double m_alphaUpdate;
      double m_betaUpdate;
      bool m_useLCUSeparateModel;
    
      int m_adaptiveBit;
      double m_lastLambda;
    
    #if RATECTRL_FIX_FULLNBIT
      int m_bitDepth;
    #endif
    
    };
    
    class EncRCGOP
    {
    public:
      EncRCGOP();
      ~EncRCGOP();
    
    public:
      void create( EncRCSeq* encRCSeq, int numPic );
      void destroy();
      void updateAfterPicture( int bitsCost );
    
    private:
      int  xEstGOPTargetBits( EncRCSeq* encRCSeq, int GOPSize );
      void   xCalEquaCoeff( EncRCSeq* encRCSeq, double* lambdaRatio, double* equaCoeffA, double* equaCoeffB, int GOPSize );
    
    #if JVET_K0390_RATECTRL
      double xSolveEqua(EncRCSeq* encRCSeq, double targetBpp, double* equaCoeffA, double* equaCoeffB, int GOPSize);
    #else
    
      double xSolveEqua( double targetBpp, double* equaCoeffA, double* equaCoeffB, int GOPSize );
    
    
    public:
      EncRCSeq* getEncRCSeq()        { return m_encRCSeq; }
      int  getNumPic()                { return m_numPic;}
      int  getTargetBits()            { return m_targetBits; }
      int  getPicLeft()               { return m_picLeft; }
      int  getBitsLeft()              { return m_bitsLeft; }
      int  getTargetBitInGOP( int i ) { return m_picTargetBitInGOP[i]; }
    
    private:
      EncRCSeq* m_encRCSeq;
      int* m_picTargetBitInGOP;
      int m_numPic;
      int m_targetBits;
      int m_picLeft;
      int m_bitsLeft;
    };
    
    class EncRCPic
    {
    public:
      EncRCPic();
      ~EncRCPic();
    
    public:
      void create( EncRCSeq* encRCSeq, EncRCGOP* encRCGOP, int frameLevel, list<EncRCPic*>& listPreviousPictures );
      void destroy();
    
      int    estimatePicQP    ( double lambda, list<EncRCPic*>& listPreviousPictures );
      int    getRefineBitsForIntra(int orgBits);
      double calculateLambdaIntra(double alpha, double beta, double MADPerPixel, double bitsPerPixel);
      double estimatePicLambda( list<EncRCPic*>& listPreviousPictures, SliceType eSliceType);
    
      void   updateAlphaBetaIntra(double *alpha, double *beta);
    
      double getLCUTargetBpp(SliceType eSliceType);
      double getLCUEstLambdaAndQP(double bpp, int clipPicQP, int *estQP);
      double getLCUEstLambda( double bpp );
      int    getLCUEstQP( double lambda, int clipPicQP );
    
      void updateAfterCTU( int LCUIdx, int bits, int QP, double lambda, bool updateLCUParameter = true );
      void updateAfterPicture( int actualHeaderBits, int actualTotalBits, double averageQP, double averageLambda, SliceType eSliceType);
    
      void addToPictureLsit( list<EncRCPic*>& listPreviousPictures );
      double calAverageQP();
      double calAverageLambda();
    
    private:
      int xEstPicTargetBits( EncRCSeq* encRCSeq, EncRCGOP* encRCGOP );
      int xEstPicHeaderBits( list<EncRCPic*>& listPreviousPictures, int frameLevel );
    #if V0078_ADAPTIVE_LOWER_BOUND
      int xEstPicLowerBound( EncRCSeq* encRCSeq, EncRCGOP* encRCGOP );
    #endif
    
    public:
      EncRCSeq*      getRCSequence()                         { return m_encRCSeq; }
      EncRCGOP*      getRCGOP()                              { return m_encRCGOP; }
    
      int  getFrameLevel()                                    { return m_frameLevel; }
      int  getNumberOfPixel()                                 { return m_numberOfPixel; }
      int  getNumberOfLCU()                                   { return m_numberOfLCU; }
      int  getTargetBits()                                    { return m_targetBits; }
      int  getEstHeaderBits()                                 { return m_estHeaderBits; }
      int  getLCULeft()                                       { return m_LCULeft; }
      int  getBitsLeft()                                      { return m_bitsLeft; }
      int  getPixelsLeft()                                    { return m_pixelsLeft; }
      int  getBitsCoded()                                     { return m_targetBits - m_estHeaderBits - m_bitsLeft; }
      int  getLCUCoded()                                      { return m_numberOfLCU - m_LCULeft; }
    #if V0078_ADAPTIVE_LOWER_BOUND
      int  getLowerBound()                                    { return m_lowerBound; }
    #endif
      TRCLCU* getLCU()                                        { return m_LCUs; }
      TRCLCU& getLCU( int LCUIdx )                            { return m_LCUs[LCUIdx]; }
      int  getPicActualHeaderBits()                           { return m_picActualHeaderBits; }
    #if U0132_TARGET_BITS_SATURATION
      void setBitLeft(int bits)                               { m_bitsLeft = bits; }
    #endif
      void setTargetBits( int bits )                          { m_targetBits = bits; m_bitsLeft = bits;}
      void setTotalIntraCost(double cost)                     { m_totalCostIntra = cost; }
      void getLCUInitTargetBits();
    
      int  getPicActualBits()                                 { return m_picActualBits; }
      int  getPicActualQP()                                   { return m_picQP; }
      double getPicActualLambda()                             { return m_picLambda; }
      int  getPicEstQP()                                      { return m_estPicQP; }
      void setPicEstQP( int QP )                              { m_estPicQP = QP; }
      double getPicEstLambda()                                { return m_estPicLambda; }
      void setPicEstLambda( double lambda )                   { m_picLambda = lambda; }
    
    #if JVET_K0390_RATECTRL
      double getPicMSE()                                      { return m_picMSE; }
      void  setPicMSE(double avgMSE)                           { m_picMSE = avgMSE; }
    #endif
    
    
    private:
      EncRCSeq* m_encRCSeq;
      EncRCGOP* m_encRCGOP;
    
      int m_frameLevel;
      int m_numberOfPixel;
      int m_numberOfLCU;
      int m_targetBits;
      int m_estHeaderBits;
      int m_estPicQP;
    #if V0078_ADAPTIVE_LOWER_BOUND
      int m_lowerBound;
    #endif
      double m_estPicLambda;
    
      int m_LCULeft;
      int m_bitsLeft;
      int m_pixelsLeft;
    
      TRCLCU* m_LCUs;
      int m_picActualHeaderBits;    // only SH and potential APS
      double m_totalCostIntra;
      double m_remainingCostIntra;
      int m_picActualBits;          // the whole picture, including header
      int m_picQP;                  // in integer form
      double m_picLambda;
    
    #if JVET_K0390_RATECTRL
      double m_picMSE;
      int m_validPixelsInPic;
    #endif
    
    #if RATECTRL_FIX_FULLNBIT
      void init(int totalFrames, int targetBitrate, int frameRate, int GOPSize, int picWidth, int picHeight, int LCUWidth, int LCUHeight, int bitDepth, int keepHierBits, bool useLCUSeparateModel, GOPEntry GOPList[MAX_GOP]);
    #else
    
      void 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] );
    
      void destroy();
      void initRCPic( int frameLevel );
      void initRCGOP( int numberOfPictures );
      void destroyRCGOP();
    
    public:
      void       setRCQP ( int QP ) { m_RCQP = QP;   }
      int        getRCQP () const   { return m_RCQP; }
      EncRCSeq* getRCSeq()          { CHECK( m_encRCSeq == NULL, "Object does not exist" ); return m_encRCSeq; }
      EncRCGOP* getRCGOP()          { CHECK( m_encRCGOP == NULL, "Object does not exist" ); return m_encRCGOP; }
      EncRCPic* getRCPic()          { CHECK( m_encRCPic == NULL, "Object does not exist" ); return m_encRCPic; }
      list<EncRCPic*>& getPicList() { return m_listRCPictures; }
    #if U0132_TARGET_BITS_SATURATION
      bool       getCpbSaturationEnabled()  { return m_CpbSaturationEnabled;  }
      uint32_t       getCpbState()              { return m_cpbState;       }
      uint32_t       getCpbSize()               { return m_cpbSize;        }
      uint32_t       getBufferingRate()         { return m_bufferingRate;  }
      int        updateCpbState(int actualBits);
      void       initHrdParam(const HRD* pcHrd, int iFrameRate, double fInitialCpbFullness);
    #endif
    
    private:
      EncRCSeq* m_encRCSeq;
      EncRCGOP* m_encRCGOP;
      EncRCPic* m_encRCPic;
      list<EncRCPic*> m_listRCPictures;
      int        m_RCQP;
    #if U0132_TARGET_BITS_SATURATION
      bool       m_CpbSaturationEnabled;    // Enable target bits saturation to avoid CPB overflow and underflow
      int        m_cpbState;                // CPB State
      uint32_t       m_cpbSize;                 // CPB size
      uint32_t       m_bufferingRate;           // Buffering rate
    #endif
    };
    
    #endif