-
Vadim Seregin authoredVadim Seregin authored
RateCtrl.h 14.91 KiB
/* 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__
#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;
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 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; }
void setBitDepth(int bitDepth) { m_bitDepth = bitDepth; }
int getbitDepth() { return m_bitDepth; }
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;
int m_bitDepth;
};
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 );
double xSolveEqua(EncRCSeq* encRCSeq, 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]; }
double getMinEstLambda() { return m_minEstLambda; }
double getMaxEstLambda() { return m_maxEstLambda; }
private:
EncRCSeq* m_encRCSeq;
int* m_picTargetBitInGOP;
int m_numPic;
int m_targetBits;
int m_picLeft;
int m_bitsLeft;
double m_minEstLambda;
double m_maxEstLambda;
};
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, 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( 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; }
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;
#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;
double m_picMSE;
int m_validPixelsInPic;
};
class RateCtrl
{
public:
RateCtrl();
~RateCtrl();
public:
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]);
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 GeneralHrdParams* generalHrd, const OlsHrdParams* olsHrd, 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