/* 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 }; struct TRCParameter { double m_alpha; double m_beta; #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 ); #endif 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 }; class RateCtrl { public: RateCtrl(); ~RateCtrl(); public: #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] ); #endif 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