/* 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-2023, 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__ #pragma once #include "../CommonLib/CommonDef.h" #include #include //! \ingroup EncoderLib //! \{ #include "../EncoderLib/EncCfg.h" #include const int g_RCInvalidQPValue = -999; const int g_RCSmoothWindowSizeAlpha = 20; const int g_RCSmoothWindowSizeBeta = 60; 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; double m_actualSSE; double m_actualMSE; }; struct TRCParameter { double m_alpha; double m_beta; int m_validPix; double m_skipRatio; }; class EncRCSeq { public: EncRCSeq(); ~EncRCSeq(); public: void create(int totalFrames, int targetBitrate, int frameRate, int GOPSize, int intraPeriod, 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 = nullptr); // nullptr to initial with default value void initLCUPara(TRCParameter **LCUPara = nullptr); // nullptr 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 getIntraPeriod() { return m_intraPeriod; } 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 &listPreviousPictures); void destroy(); int estimatePicQP(double lambda, std::list &listPreviousPictures); int getRefineBitsForIntra(int orgBits); double calculateLambdaIntra(double alpha, double beta, double MADPerPixel, double bitsPerPixel); double estimatePicLambda(std::list &listPreviousPictures, bool isIRAP); void updateAlphaBetaIntra(double *alpha, double *beta); double getLCUTargetBpp(bool isIRAP); 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, double skipRatio, bool updateLCUParameter = true); void updateAfterPicture( int actualHeaderBits, int actualTotalBits, double averageQP, double averageLambda, bool isIRAP); double clipRcAlpha(const int bitdepth, const double alpha); double clipRcBeta(const double beta); void addToPictureLsit(std::list &listPreviousPictures); double calAverageQP(); double calAverageLambda(); private: int xEstPicTargetBits( EncRCSeq* encRCSeq, EncRCGOP* encRCGOP ); int xEstPicHeaderBits(std::list &listPreviousPictures, int frameLevel); int xEstPicLowerBound( EncRCSeq* encRCSeq, EncRCGOP* encRCGOP ); 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; } int getLowerBound() { return m_lowerBound; } TRCLCU* getLCU() { return m_LCUs; } TRCLCU& getLCU( int LCUIdx ) { return m_LCUs[LCUIdx]; } int getPicActualHeaderBits() { return m_picActualHeaderBits; } void setBitLeft(int bits) { m_bitsLeft = bits; } 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; } double getPicMSE() { return m_picMSE; } void setPicMSE(double avgMSE) { m_picMSE = avgMSE; } 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; int m_lowerBound; 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; double m_picMSE; int m_validPixelsInPic; }; class RateCtrl { public: RateCtrl(); ~RateCtrl(); public: void init(int totalFrames, int targetBitrate, int frameRate, int GOPSize, int intraPeriod, int picWidth, int picHeight, int LCUWidth, int LCUHeight, int bitDepth, 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 == nullptr, "Object does not exist"); return m_encRCSeq; } EncRCGOP *getRCGOP() { CHECK(m_encRCGOP == nullptr, "Object does not exist"); return m_encRCGOP; } EncRCPic *getRCPic() { CHECK(m_encRCPic == nullptr, "Object does not exist"); return m_encRCPic; } std::list &getPicList() { return m_listRCPictures; } 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 GeneralHrdParams* generalHrd, const OlsHrdParams* olsHrd, int iFrameRate, double fInitialCpbFullness); private: EncRCSeq* m_encRCSeq; EncRCGOP* m_encRCGOP; EncRCPic* m_encRCPic; std::list m_listRCPictures; int m_RCQP; 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