x265-1.8版本-encoder/ratecontrol.cpp注释

注:问号以及未注释部分 会在x265-1.9版本内更新

/*****************************************************************************
 * Copyright (C) 2013 x265 project
 *
 * Authors: Sumalatha Polureddy <sumalatha@multicorewareinc.com>
 *          Aarthi Priya Thirumalai <aarthi@multicorewareinc.com>
 *          Xun Xu, PPLive Corporation <xunxu@pptv.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
 *
 * This program is also available under a commercial proprietary license.
 * For more information, contact us at license @ x265.com.
 *****************************************************************************/

#include "common.h"
#include "param.h"
#include "frame.h"
#include "framedata.h"
#include "picyuv.h"

#include "encoder.h"
#include "slicetype.h"
#include "ratecontrol.h"
#include "sei.h"

#define BR_SHIFT  6
#define CPB_SHIFT 4

using namespace X265_NS;

/* Amortize the partial cost of I frames over the next N frames */

const int RateControl::s_slidingWindowFrames = 20;//滑动窗口大小
const char *RateControl::s_defaultStatFileName = "x265_2pass.log";

namespace {
#define CMP_OPT_FIRST_PASS(opt, param_val)\
{\
    bErr = 0;\
    p = strstr(opts, opt "=");\
    char* q = strstr(opts, "no-"opt);\
    if (p && sscanf(p, opt "=%d" , &i) && param_val != i)\
        bErr = 1;\
    else if (!param_val && !q && !p)\
        bErr = 1;\
    else if (param_val && (q || !strstr(opts, opt)))\
        bErr = 1;\
    if (bErr)\
    {\
        x265_log(m_param, X265_LOG_ERROR, "different " opt " setting than first pass (%d vs %d)\n", param_val, i);\
        return false;\
    }\
}

inline int calcScale(uint32_t x)
{
    static uint8_t lut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};
    int y, z = (((x & 0xffff) - 1) >> 27) & 16;
    x >>= z;
    z += y = (((x & 0xff) - 1) >> 28) & 8;
    x >>= y;
    z += y = (((x & 0xf) - 1) >> 29) & 4;
    x >>= y;
    return z + lut[x&0xf];
}

inline int calcLength(uint32_t x)
{
    static uint8_t lut[16] = {4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
    int y, z = (((x >> 16) - 1) >> 27) & 16;
    x >>= z ^ 16;
    z += y = ((x - 0x100) >> 28) & 8;
    x >>= y ^ 8;
    z += y = ((x - 0x10) >> 29) & 4;
    x >>= y ^ 4;
    return z + lut[x];
}

inline void reduceFraction(int* n, int* d)
{
    int a = *n;
    int b = *d;
    int c;
    if (!a || !b)
        return;
    c = a % b;
    while (c)
    {
        a = b;
        b = c;
        c = a % b;
    }
    *n /= b;
    *d /= b;
}

inline char *strcatFilename(const char *input, const char *suffix)
{
    char *output = X265_MALLOC(char, strlen(input) + strlen(suffix) + 1);
    if (!output)
    {
        x265_log(NULL, X265_LOG_ERROR, "unable to allocate memory for filename\n");
        return NULL;
    }
    strcpy(output, input);
    strcat(output, suffix);
    return output;
}

inline double qScale2bits(RateControlEntry *rce, double qScale)
{
    if (qScale < 0.1)
        qScale = 0.1;
    return (rce->coeffBits + .1) * pow(rce->qScale / qScale, 1.1)
           + rce->mvBits * pow(X265_MAX(rce->qScale, 1) / X265_MAX(qScale, 1), 0.5)
           + rce->miscBits;
}

inline void copyRceData(RateControlEntry* rce, RateControlEntry* rce2Pass)
{
    rce->coeffBits = rce2Pass->coeffBits;
    rce->mvBits = rce2Pass->mvBits;
    rce->miscBits = rce2Pass->miscBits;
    rce->iCuCount = rce2Pass->iCuCount;
    rce->pCuCount = rce2Pass->pCuCount;
    rce->skipCuCount = rce2Pass->skipCuCount;
    rce->keptAsRef = rce2Pass->keptAsRef;
    rce->qScale = rce2Pass->qScale;
    rce->newQScale = rce2Pass->newQScale;
    rce->expectedBits = rce2Pass->expectedBits;
    rce->expectedVbv = rce2Pass->expectedVbv;
    rce->blurredComplexity = rce2Pass->blurredComplexity;
    rce->sliceType = rce2Pass->sliceType;
}

}  // end anonymous namespace
/* Returns the zone for the current frame */
/** 函数功能             : 获取当前帧所在的zone
/*  调用范围             : 只在rateControlStart(只在CQP模式应用)、getDiffLimitedQScale和RateControl::getQScale函数中被调用
* \返回                  : 返回当前帧所在的zone * */
x265_zone* RateControl::getZone()
{
    for (int i = m_param->rc.zoneCount - 1; i >= 0; i--)
    {
        x265_zone *z = &m_param->rc.zones[i];
        if (m_framesDone + 1 >= z->startFrame && m_framesDone < z->endFrame)//如果当前帧在此范围内
            return z;
    }
    return NULL;
}

RateControl::RateControl(x265_param& p)
{
    m_param = &p; //获取当前配置参数
    int lowresCuWidth = ((m_param->sourceWidth / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS; //1/2下采样帧中一行有多少8x8块
    int lowresCuHeight = ((m_param->sourceHeight / 2) + X265_LOWRES_CU_SIZE - 1) >> X265_LOWRES_CU_BITS;//1/2下采样帧中一列有多少8x8块
    m_ncu = lowresCuWidth * lowresCuHeight;//1/2下采样帧中的8x8块个数

    if (m_param->rc.cuTree) //如果应用cutree 设置强度系数为1 否则从配置参数中获取
        m_qCompress = 1;
    else
        m_qCompress = m_param->rc.qCompress;//获取配置参数中的强度系数

    // validate for param->rc, maybe it is need to add a function like x265_parameters_valiate()
    m_residualFrames = 0;
    m_partialResidualFrames = 0;
    m_residualCost = 0;
    m_partialResidualCost = 0;
    m_rateFactorMaxIncrement = 0;
    m_rateFactorMaxDecrement = 0;
    m_fps = (double)m_param->fpsNum / m_param->fpsDenom;
    m_startEndOrder.set(0); //初始化为0
    m_bTerminated = false;
    m_finalFrameCount = 0;
    m_numEntries = 0;
    m_isSceneTransition = false;
    m_lastPredictorReset = 0;
    if (m_param->rc.rateControlMode == X265_RC_CRF)
    {
        m_param->rc.qp = (int)m_param->rc.rfConstant;
        m_param->rc.bitrate = 0;

        double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);//120*m_ncu
        double mbtree_offset = m_param->rc.cuTree ? (1.0 - m_param->rc.qCompress) * 13.5 : 0;
        m_rateFactorConstant = pow(baseCplx, 1 - m_qCompress) /
            x265_qp2qScale(m_param->rc.rfConstant + mbtree_offset);//一般分辨率越大 此值越大 一般在0.0x之间
        if (m_param->rc.rfConstantMax)//如果配置CRF 的最大量化值
        {
            m_rateFactorMaxIncrement = m_param->rc.rfConstantMax - m_param->rc.rfConstant;//求最大与配置之间的差值
            if (m_rateFactorMaxIncrement <= 0)
            {
                x265_log(m_param, X265_LOG_WARNING, "CRF max must be greater than CRF\n");
                m_rateFactorMaxIncrement = 0;
            }
        }
        if (m_param->rc.rfConstantMin)//如果当前是CRF模式 并且 有配置最小crf值
            m_rateFactorMaxDecrement = m_param->rc.rfConstant - m_param->rc.rfConstantMin;//求最小与配置之间的差值
    }
    m_isAbr = m_param->rc.rateControlMode != X265_RC_CQP && !m_param->rc.bStatRead;//是否应用ABR 当前不是CQP并且不是多pass 读的时候
    m_2pass = m_param->rc.rateControlMode == X265_RC_ABR && m_param->rc.bStatRead;//判断当前是否是2pass
    m_bitrate = m_param->rc.bitrate * 1000;//获取当前配置的目标码率
    m_frameDuration = (double)m_param->fpsDenom / m_param->fpsNum; //当前播放一帧占用的时间(单位秒)
    m_qp = m_param->rc.qp;//获取配置的固定QP
    m_lastRceq = 1; /* handles the cmplxrsum when the previous frame cost is zero */
    m_shortTermCplxSum = 0;
    m_shortTermCplxCount = 0;
    m_lastNonBPictType = I_SLICE;
    m_isAbrReset = false;
    m_lastAbrResetPoc = -1;
    m_statFileOut = NULL;
    m_cutreeStatFileOut = m_cutreeStatFileIn = NULL;
    m_rce2Pass = NULL;
    m_lastBsliceSatdCost = 0;

    // vbv initialization
    m_param->rc.vbvBufferSize = x265_clip3(0, 2000000, m_param->rc.vbvBufferSize);
    m_param->rc.vbvMaxBitrate = x265_clip3(0, 2000000, m_param->rc.vbvMaxBitrate);
    m_param->rc.vbvBufferInit = x265_clip3(0.0, 2000000.0, m_param->rc.vbvBufferInit);
    m_singleFrameVbv = 0;
    m_rateTolerance = 1.0;

    if (m_param->rc.vbvBufferSize)
    {
        if (m_param->rc.rateControlMode == X265_RC_CQP)
        {
            x265_log(m_param, X265_LOG_WARNING, "VBV is incompatible with constant QP, ignored.\n");
            m_param->rc.vbvBufferSize = 0;
            m_param->rc.vbvMaxBitrate = 0;
        }
        else if (m_param->rc.vbvMaxBitrate == 0)
        {
            if (m_param->rc.rateControlMode == X265_RC_ABR)
            {
                x265_log(m_param, X265_LOG_WARNING, "VBV maxrate unspecified, assuming CBR\n");
                m_param->rc.vbvMaxBitrate = m_param->rc.bitrate;
            }
            else
            {
                x265_log(m_param, X265_LOG_WARNING, "VBV bufsize set but maxrate unspecified, ignored\n");
                m_param->rc.vbvBufferSize = 0;
            }
        }
        else if (m_param->rc.vbvMaxBitrate < m_param->rc.bitrate &&
                 m_param->rc.rateControlMode == X265_RC_ABR)
        {
            x265_log(m_param, X265_LOG_WARNING, "max bitrate less than average bitrate, assuming CBR\n");
            m_param->rc.bitrate = m_param->rc.vbvMaxBitrate;
        }
    }
    else if (m_param->rc.vbvMaxBitrate)
    {
        x265_log(m_param, X265_LOG_WARNING, "VBV maxrate specified, but no bufsize, ignored\n");
        m_param->rc.vbvMaxBitrate = 0;
    }
    m_isVbv = m_param->rc.vbvMaxBitrate > 0 && m_param->rc.vbvBufferSize > 0;//判断是否应用VBV
    if (m_param->bEmitHRDSEI && !m_isVbv)
    {
        x265_log(m_param, X265_LOG_WARNING, "NAL HRD parameters require VBV parameters, ignored\n");
        m_param->bEmitHRDSEI = 0;
    }
    m_isCbr = m_param->rc.rateControlMode == X265_RC_ABR && m_isVbv && !m_2pass && m_param->rc.vbvMaxBitrate <= m_param->rc.bitrate;//CBR模式 如果最大码率设定小于目标码率
    if (m_param->rc.bStrictCbr && !m_isCbr)
    {
        x265_log(m_param, X265_LOG_WARNING, "strict CBR set without CBR mode, ignored\n");
        m_param->rc.bStrictCbr = 0;
    }
    if(m_param->rc.bStrictCbr)//如果严格控制目标码率  降低因子
        m_rateTolerance = 0.7;

    m_bframeBits = 0;
    m_leadingNoBSatd = 0;
    m_ipOffset = 6.0 * X265_LOG2(m_param->rc.ipFactor);//用途:I帧与P帧的qp参数关系  P = Iqp + m_ipOffset 默认 2.9125608156077503
    m_pbOffset = 6.0 * X265_LOG2(m_param->rc.pbFactor);//用途:P帧与B帧的qp参数关系  B = Pqp + m_pbOffset 默认 2.2710694220159415

    /* Adjust the first frame in order to stabilize the quality level compared to the rest */
#define ABR_INIT_QP_MIN (24) //ABR默认的最小QP
#define ABR_INIT_QP_MAX (40)
#define ABR_SCENECUT_INIT_QP_MIN (12)//场景切换的最小QP 12
#define CRF_INIT_QP (int)m_param->rc.rfConstant //CRF模式下的默认QP
    for (int i = 0; i < 3; i++)
        m_lastQScaleFor[i] = x265_qp2qScale(m_param->rc.rateControlMode == X265_RC_CRF ? CRF_INIT_QP : ABR_INIT_QP_MIN);//初始化Qsclae

    if (m_param->rc.rateControlMode == X265_RC_CQP)//固定QP模式
    {
        if (m_qp && !m_param->bLossless)//如果m_qp不为0 并且不是无损压缩模式
        {
            m_qpConstant[P_SLICE] = m_qp;//P帧获取QP
            m_qpConstant[I_SLICE] = x265_clip3(QP_MIN, QP_MAX_MAX, (int)(m_qp - m_ipOffset + 0.5));//I帧获取QP
            m_qpConstant[B_SLICE] = x265_clip3(QP_MIN, QP_MAX_MAX, (int)(m_qp + m_pbOffset + 0.5));//B帧获取QP
        }
        else
        {
            m_qpConstant[P_SLICE] = m_qpConstant[I_SLICE] = m_qpConstant[B_SLICE] = m_qp;//无损模式获取相同的QP值 4
        }
    }

    /* qpstep - value set as encoder specific */
    m_lstep = pow(2, m_param->rc.qpStep / 6.0);//初始化m_lstep

    for (int i = 0; i < 2; i++)
        m_cuTreeStats.qpBuffer[i] = NULL;
}
/** 函数功能             : ???分析加权信息(每个list的第一帧分析加权与否,其它不加权)
/*  调用范围             : 只在Encoder::create()和RateControl::checkAndResetABR函数中被调用
* \参数 rce              : ???当前编码帧
* \参数 isFrameDone      : 当前帧是否编码完毕 rateEstimateQscale为false rateControlEnd为true
* \返回                  : ??null * */
bool RateControl::init(const SPS& sps)
{
    if (m_isVbv)
    {
        /* We don't support changing the ABR bitrate right now,
         * so if the stream starts as CBR, keep it CBR. */
        if (m_param->rc.vbvBufferSize < (int)(m_param->rc.vbvMaxBitrate / m_fps))
        {
            m_param->rc.vbvBufferSize = (int)(m_param->rc.vbvMaxBitrate / m_fps);
            x265_log(m_param, X265_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n",
                     m_param->rc.vbvBufferSize);
        }
        int vbvBufferSize = m_param->rc.vbvBufferSize * 1000;
        int vbvMaxBitrate = m_param->rc.vbvMaxBitrate * 1000;//一秒钟占用的最大bits

        if (m_param->bEmitHRDSEI)
        {
            const HRDInfo* hrd = &sps.vuiParameters.hrdParameters;
            vbvBufferSize = hrd->cpbSizeValue << (hrd->cpbSizeScale + CPB_SHIFT);
            vbvMaxBitrate = hrd->bitRateValue << (hrd->bitRateScale + BR_SHIFT);
        }
        m_bufferRate = vbvMaxBitrate / m_fps;//平均每帧最大的bits占用数目
        m_vbvMaxRate = vbvMaxBitrate;//一秒钟占用的最大bits
        m_bufferSize = vbvBufferSize;//获取一秒的bits buffer大小
        m_singleFrameVbv = m_bufferRate * 1.1 > m_bufferSize;//如果平均每帧最大的bits占用数目*1.1 大于一秒的bits buffer大小

        if (m_param->rc.vbvBufferInit > 1.)
            m_param->rc.vbvBufferInit = x265_clip3(0.0, 1.0, m_param->rc.vbvBufferInit / m_param->rc.vbvBufferSize);
        m_param->rc.vbvBufferInit = x265_clip3(0.0, 1.0, X265_MAX(m_param->rc.vbvBufferInit, m_bufferRate / m_bufferSize));
        m_bufferFillFinal = m_bufferSize * m_param->rc.vbvBufferInit;//???
    }

    m_totalBits = 0;
    m_encodedBits = 0;
    m_framesDone = 0;
    m_residualCost = 0;
    m_partialResidualCost = 0;
    m_amortizeFraction = 0.85;
    m_amortizeFrames = 75;
    if (m_param->totalFrames && m_param->totalFrames <= 2 * m_fps && m_param->rc.bStrictCbr) /* Strict CBR segment encode *///编码帧数过少并且严格按照目标码率
    {
        m_amortizeFraction = 0.85;
        m_amortizeFrames = m_param->totalFrames / 2;//重置为一半帧数
    }
    for (int i = 0; i < s_slidingWindowFrames; i++)
    {
        m_satdCostWindow[i] = 0;
        m_encodedBitsWindow[i] = 0;
    }
    m_sliderPos = 0;
    m_isPatternPresent = false;
    m_numBframesInPattern = 0;

    /* 720p videos seem to be a good cutoff for cplxrSum */
    double tuneCplxFactor = (m_param->rc.cuTree && m_ncu > 3600) ? 2.5 : 1;//720p以上参数为2.5 以下为1.0

    /* estimated ratio that produces a reasonable QP for the first I-frame */
    m_cplxrSum = .01 * pow(7.0e5, m_qCompress) * pow(m_ncu, 0.5) * tuneCplxFactor;//初始化用于估计第一帧I帧的QP参数
    m_wantedBitsWindow = m_bitrate * m_frameDuration;//初始化当前第一帧需要的bit数目
    m_accumPNorm = .01;
    m_accumPQp = (m_param->rc.rateControlMode == X265_RC_CRF ? CRF_INIT_QP : ABR_INIT_QP_MIN) * m_accumPNorm;//初始化为0.01*24

    /* Frame Predictors used in vbv */
    initFramePredictors();
    if (!m_statFileOut && (m_param->rc.bStatWrite || m_param->rc.bStatRead))
    {
        /* If the user hasn't defined the stat filename, use the default value */
        const char *fileName = m_param->rc.statFileName;
        if (!fileName)
            fileName = s_defaultStatFileName;
        /* Load stat file and init 2pass algo */
        if (m_param->rc.bStatRead)
        {
            m_expectedBitsSum = 0;
            char *p, *statsIn, *statsBuf;
            /* read 1st pass stats */
            statsIn = statsBuf = x265_slurp_file(fileName);
            if (!statsBuf)
                return false;
            if (m_param->rc.cuTree)
            {
                char *tmpFile = strcatFilename(fileName, ".cutree");
                if (!tmpFile)
                    return false;
                m_cutreeStatFileIn = fopen(tmpFile, "rb");
                X265_FREE(tmpFile);
                if (!m_cutreeStatFileIn)
                {
                    x265_log(m_param, X265_LOG_ERROR, "can't open stats file %s\n", tmpFile);
                    return false;
                }
            }

            /* check whether 1st pass options were compatible with current options */
            if (strncmp(statsBuf, "#options:", 9))
            {
                x265_log(m_param, X265_LOG_ERROR,"options list in stats file not valid\n");
                return false;
            }
            {
                int i, j;
                uint32_t k , l;
                bool bErr = false;
                char *opts = statsBuf;
                statsIn = strchr(statsBuf, '\n');
                if (!statsIn)
                {
                    x265_log(m_param, X265_LOG_ERROR, "Malformed stats file\n");
                    return false;
                }
                *statsIn = '\0';
                statsIn++;
                if (sscanf(opts, "#options: %dx%d", &i, &j) != 2)
                {
                    x265_log(m_param, X265_LOG_ERROR, "Resolution specified in stats file not valid\n");
                    return false;
                }
                if ((p = strstr(opts, " fps=")) == 0 || sscanf(p, " fps=%u/%u", &k, &l) != 2)
                {
                    x265_log(m_param, X265_LOG_ERROR, "fps specified in stats file not valid\n");
                    return false;
                }
                if (k != m_param->fpsNum || l != m_param->fpsDenom)
                {
                    x265_log(m_param, X265_LOG_ERROR, "fps mismatch with 1st pass (%u/%u vs %u/%u)\n",
                              m_param->fpsNum, m_param->fpsDenom, k, l);
                    return false;
                }
                CMP_OPT_FIRST_PASS("bitdepth", m_param->internalBitDepth);
                CMP_OPT_FIRST_PASS("weightp", m_param->bEnableWeightedPred);
                CMP_OPT_FIRST_PASS("bframes", m_param->bframes);
                CMP_OPT_FIRST_PASS("b-pyramid", m_param->bBPyramid);
                CMP_OPT_FIRST_PASS("open-gop", m_param->bOpenGOP);
                CMP_OPT_FIRST_PASS("keyint", m_param->keyframeMax);
                CMP_OPT_FIRST_PASS("scenecut", m_param->scenecutThreshold);

                if ((p = strstr(opts, "b-adapt=")) != 0 && sscanf(p, "b-adapt=%d", &i) && i >= X265_B_ADAPT_NONE && i <= X265_B_ADAPT_TRELLIS)
                {
                    m_param->bFrameAdaptive = i;
                }
                else if (m_param->bframes)
                {
                    x265_log(m_param, X265_LOG_ERROR, "b-adapt method specified in stats file not valid\n");
                    return false;
                }

                if ((p = strstr(opts, "rc-lookahead=")) != 0 && sscanf(p, "rc-lookahead=%d", &i))
                    m_param->lookaheadDepth = i;
            }
            /* find number of pics */
            p = statsIn;
            int numEntries;
            for (numEntries = -1; p; numEntries++)
                p = strchr(p + 1, ';');
            if (!numEntries)
            {
                x265_log(m_param, X265_LOG_ERROR, "empty stats file\n");
                return false;
            }
            m_numEntries = numEntries;

            if (m_param->totalFrames < m_numEntries && m_param->totalFrames > 0)
            {
                x265_log(m_param, X265_LOG_WARNING, "2nd pass has fewer frames than 1st pass (%d vs %d)\n",
                         m_param->totalFrames, m_numEntries);
            }
            if (m_param->totalFrames > m_numEntries)
            {
                x265_log(m_param, X265_LOG_ERROR, "2nd pass has more frames than 1st pass (%d vs %d)\n",
                         m_param->totalFrames, m_numEntries);
                return false;
            }

            m_rce2Pass = X265_MALLOC(RateControlEntry, m_numEntries);
            if (!m_rce2Pass)
            {
                 x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2 pass cannot be allocated\n");
                 return false;
            }
            /* init all to skipped p frames */
            for (int i = 0; i < m_numEntries; i++)
            {
                RateControlEntry *rce = &m_rce2Pass[i];
                rce->sliceType = P_SLICE;
                rce->qScale = rce->newQScale = x265_qp2qScale(20);
                rce->miscBits = m_ncu + 10;
                rce->newQp = 0;
            }
            /* read stats */
            p = statsIn;
            double totalQpAq = 0;
            for (int i = 0; i < m_numEntries; i++)
            {
                RateControlEntry *rce;
                int frameNumber;
                char picType;
                int e;
                char *next;
                double qpRc, qpAq;
                next = strstr(p, ";");
                if (next)
                    *next++ = 0;
                e = sscanf(p, " in:%d ", &frameNumber);
                if (frameNumber < 0 || frameNumber >= m_numEntries)
                {
                    x265_log(m_param, X265_LOG_ERROR, "bad frame number (%d) at stats line %d\n", frameNumber, i);
                    return false;
                }
                rce = &m_rce2Pass[frameNumber];
                e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
                       &picType, &qpRc, &qpAq, &rce->coeffBits,
                       &rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount,
                       &rce->skipCuCount);
                rce->keptAsRef = true;
                if (picType == 'b' || picType == 'p')
                    rce->keptAsRef = false;
                if (picType == 'I' || picType == 'i')
                    rce->sliceType = I_SLICE;
                else if (picType == 'P' || picType == 'p')
                    rce->sliceType = P_SLICE;
                else if (picType == 'B' || picType == 'b')
                    rce->sliceType = B_SLICE;
                else
                    e = -1;
                if (e < 10)
                {
                    x265_log(m_param, X265_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e);
                    return false;
                }
                rce->qScale = x265_qp2qScale(qpRc);
                totalQpAq += qpAq;
                p = next;
            }
            X265_FREE(statsBuf);

            if (m_param->rc.rateControlMode == X265_RC_ABR)
            {
                if (!initPass2())
                    return false;
            } /* else we're using constant quant, so no need to run the bitrate allocation */
        }
        /* Open output file */
        /* If input and output files are the same, output to a temp file
         * and move it to the real name only when it's complete */
        if (m_param->rc.bStatWrite)
        {
            char *p, *statFileTmpname;
            statFileTmpname = strcatFilename(fileName, ".temp");
            if (!statFileTmpname)
                return false;
            m_statFileOut = fopen(statFileTmpname, "wb");
            X265_FREE(statFileTmpname);
            if (!m_statFileOut)
            {
                x265_log(m_param, X265_LOG_ERROR, "can't open stats file %s\n", statFileTmpname);
                return false;
            }
            p = x265_param2string(m_param);
            if (p)
                fprintf(m_statFileOut, "#options: %s\n", p);
            X265_FREE(p);
            if (m_param->rc.cuTree && !m_param->rc.bStatRead)
            {
                statFileTmpname = strcatFilename(fileName, ".cutree.temp");
                if (!statFileTmpname)
                    return false;
                m_cutreeStatFileOut = fopen(statFileTmpname, "wb");
                X265_FREE(statFileTmpname);
                if (!m_cutreeStatFileOut)
                {
                    x265_log(m_param, X265_LOG_ERROR, "can't open mbtree stats file %s\n", statFileTmpname);
                    return false;
                }
            }
        }
        if (m_param->rc.cuTree)
        {
            m_cuTreeStats.qpBuffer[0] = X265_MALLOC(uint16_t, m_ncu * sizeof(uint16_t));
            if (m_param->bBPyramid && m_param->rc.bStatRead)
                m_cuTreeStats.qpBuffer[1] = X265_MALLOC(uint16_t, m_ncu * sizeof(uint16_t));
            m_cuTreeStats.qpBufPos = -1;
        }
    }
    return true;
}

void RateControl::initHRD(SPS& sps)
{
    int vbvBufferSize = m_param->rc.vbvBufferSize * 1000;
    int vbvMaxBitrate = m_param->rc.vbvMaxBitrate * 1000;

    // Init HRD
    HRDInfo* hrd = &sps.vuiParameters.hrdParameters;
    hrd->cbrFlag = m_isCbr;

    // normalize HRD size and rate to the value / scale notation
    hrd->bitRateScale = x265_clip3(0, 15, calcScale(vbvMaxBitrate) - BR_SHIFT);
    hrd->bitRateValue = (vbvMaxBitrate >> (hrd->bitRateScale + BR_SHIFT));

    hrd->cpbSizeScale = x265_clip3(0, 15, calcScale(vbvBufferSize) - CPB_SHIFT);
    hrd->cpbSizeValue = (vbvBufferSize >> (hrd->cpbSizeScale + CPB_SHIFT));
    int bitRateUnscale = hrd->bitRateValue << (hrd->bitRateScale + BR_SHIFT);
    int cpbSizeUnscale = hrd->cpbSizeValue << (hrd->cpbSizeScale + CPB_SHIFT);

    // arbitrary
    #define MAX_DURATION 0.5

    TimingInfo *time = &sps.vuiParameters.timingInfo;
    int maxCpbOutputDelay = (int)(X265_MIN(m_param->keyframeMax * MAX_DURATION * time->timeScale / time->numUnitsInTick, INT_MAX));
    int maxDpbOutputDelay = (int)(sps.maxDecPicBuffering * MAX_DURATION * time->timeScale / time->numUnitsInTick);
    int maxDelay = (int)(90000.0 * cpbSizeUnscale / bitRateUnscale + 0.5);

    hrd->initialCpbRemovalDelayLength = 2 + x265_clip3(4, 22, 32 - calcLength(maxDelay));
    hrd->cpbRemovalDelayLength = x265_clip3(4, 31, 32 - calcLength(maxCpbOutputDelay));
    hrd->dpbOutputDelayLength = x265_clip3(4, 31, 32 - calcLength(maxDpbOutputDelay));

    #undef MAX_DURATION
}

bool RateControl::initPass2()
{
    uint64_t allConstBits = 0;
    uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * m_numEntries * m_frameDuration);
    double rateFactor, stepMult;
    double qBlur = m_param->rc.qblur;
    double cplxBlur = m_param->rc.complexityBlur;
    const int filterSize = (int)(qBlur * 4) | 1;
    double expectedBits;
    double *qScale, *blurredQscale;
    double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);
    double clippedDuration = CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION;

    /* find total/average complexity & const_bits */
    for (int i = 0; i < m_numEntries; i++)
        allConstBits += m_rce2Pass[i].miscBits;

    if (allAvailableBits < allConstBits)
    {
        x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too low. estimated minimum is %d kbps\n",
                 (int)(allConstBits * m_fps / m_numEntries * 1000.));
        return false;
    }

    /* Blur complexities, to reduce local fluctuation of QP.
     * We don't blur the QPs directly, because then one very simple frame
     * could drag down the QP of a nearby complex frame and give it more
     * bits than intended. */
    for (int i = 0; i < m_numEntries; i++)
    {
        double weightSum = 0;
        double cplxSum = 0;
        double weight = 1.0;
        double gaussianWeight;
        /* weighted average of cplx of future frames */
        for (int j = 1; j < cplxBlur * 2 && j < m_numEntries - i; j++)
        {
            RateControlEntry *rcj = &m_rce2Pass[i + j];
            weight *= 1 - pow(rcj->iCuCount / m_ncu, 2);
            if (weight < 0.0001)
                break;
            gaussianWeight = weight * exp(-j * j / 200.0);
            weightSum += gaussianWeight;
            cplxSum += gaussianWeight * (qScale2bits(rcj, 1) - rcj->miscBits) / clippedDuration;
        }
        /* weighted average of cplx of past frames */
        weight = 1.0;
        for (int j = 0; j <= cplxBlur * 2 && j <= i; j++)
        {
            RateControlEntry *rcj = &m_rce2Pass[i - j];
            gaussianWeight = weight * exp(-j * j / 200.0);
            weightSum += gaussianWeight;
            cplxSum += gaussianWeight * (qScale2bits(rcj, 1) - rcj->miscBits) / clippedDuration;
            weight *= 1 - pow(rcj->iCuCount / m_ncu, 2);
            if (weight < .0001)
                break;
        }
        m_rce2Pass[i].blurredComplexity = cplxSum / weightSum;
    }

    CHECKED_MALLOC(qScale, double, m_numEntries);
    if (filterSize > 1)
    {
        CHECKED_MALLOC(blurredQscale, double, m_numEntries);
    }
    else
        blurredQscale = qScale;

    /* Search for a factor which, when multiplied by the RCEQ values from
     * each frame, adds up to the desired total size.
     * There is no exact closed-form solution because of VBV constraints and
     * because qscale2bits is not invertible, but we can start with the simple
     * approximation of scaling the 1st pass by the ratio of bitrates.
     * The search range is probably overkill, but speed doesn't matter here. */

    expectedBits = 1;
    for (int i = 0; i < m_numEntries; i++)
    {
        RateControlEntry* rce = &m_rce2Pass[i];
        double q = getQScale(rce, 1.0);
        expectedBits += qScale2bits(rce, q);
        m_lastQScaleFor[rce->sliceType] = q;
    }
    stepMult = allAvailableBits / expectedBits;

    rateFactor = 0;
    for (double step = 1E4 * stepMult; step > 1E-7 * stepMult; step *= 0.5)
    {
        expectedBits = 0;
        rateFactor += step;

        m_lastNonBPictType = -1;
        m_lastAccumPNorm = 1;
        m_accumPNorm = 0;

        m_lastQScaleFor[0] = m_lastQScaleFor[1] =
        m_lastQScaleFor[2] = pow(baseCplx, 1 - m_qCompress) / rateFactor;

        /* find qscale */
        for (int i = 0; i < m_numEntries; i++)
        {
            RateControlEntry *rce = &m_rce2Pass[i];
            qScale[i] = getQScale(rce, rateFactor);
            m_lastQScaleFor[rce->sliceType] = qScale[i];
        }

        /* fixed I/B qscale relative to P */
        for (int i = m_numEntries - 1; i >= 0; i--)
        {
            qScale[i] = getDiffLimitedQScale(&m_rce2Pass[i], qScale[i]);
            X265_CHECK(qScale[i] >= 0, "qScale became negative\n");
        }

        /* smooth curve */
        if (filterSize > 1)
        {
            X265_CHECK(filterSize % 2 == 1, "filterSize not an odd number\n");
            for (int i = 0; i < m_numEntries; i++)
            {
                double q = 0.0, sum = 0.0;

                for (int j = 0; j < filterSize; j++)
                {
                    int idx = i + j - filterSize / 2;
                    double d = idx - i;
                    double coeff = qBlur == 0 ? 1.0 : exp(-d * d / (qBlur * qBlur));
                    if (idx < 0 || idx >= m_numEntries)
                        continue;
                    if (m_rce2Pass[i].sliceType != m_rce2Pass[idx].sliceType)
                        continue;
                    q += qScale[idx] * coeff;
                    sum += coeff;
                }
                blurredQscale[i] = q / sum;
            }
        }

        /* find expected bits */
        for (int i = 0; i < m_numEntries; i++)
        {
            RateControlEntry *rce = &m_rce2Pass[i];
            rce->newQScale = clipQscale(NULL, rce, blurredQscale[i]); // check if needed
            X265_CHECK(rce->newQScale >= 0, "new Qscale is negative\n");
            expectedBits += qScale2bits(rce, rce->newQScale);
        }

        if (expectedBits > allAvailableBits)
            rateFactor -= step;
    }

    X265_FREE(qScale);
    if (filterSize > 1)
        X265_FREE(blurredQscale);

    if (m_isVbv)
        if (!vbv2Pass(allAvailableBits))
            return false;
    expectedBits = countExpectedBits();

    if (fabs(expectedBits / allAvailableBits - 1.0) > 0.01)
    {
        double avgq = 0;
        for (int i = 0; i < m_numEntries; i++)
            avgq += m_rce2Pass[i].newQScale;
        avgq = x265_qScale2qp(avgq / m_numEntries);

        if (expectedBits > allAvailableBits || !m_isVbv)
            x265_log(m_param, X265_LOG_WARNING, "Error: 2pass curve failed to converge\n");
        x265_log(m_param, X265_LOG_WARNING, "target: %.2f kbit/s, expected: %.2f kbit/s, avg QP: %.4f\n",
                 (double)m_param->rc.bitrate,
                 expectedBits * m_fps / (m_numEntries * 1000.),
                 avgq);
        if (expectedBits < allAvailableBits && avgq < QP_MIN + 2)
        {
            x265_log(m_param, X265_LOG_WARNING, "try reducing target bitrate\n");
        }
        else if (expectedBits > allAvailableBits && avgq > QP_MAX_SPEC - 2)
        {
            x265_log(m_param, X265_LOG_WARNING, "try increasing target bitrate\n");
        }
        else if (!(m_2pass && m_isVbv))
            x265_log(m_param, X265_LOG_WARNING, "internal error\n");
    }

    return true;

fail:
    x265_log(m_param, X265_LOG_WARNING, "two-pass ABR initialization failed\n");
    return false;
}

bool RateControl::vbv2Pass(uint64_t allAvailableBits)
{
    /* for each interval of bufferFull .. underflow, uniformly increase the qp of all
     * frames in the interval until either buffer is full at some intermediate frame or the
     * last frame in the interval no longer underflows.  Recompute intervals and repeat.
     * Then do the converse to put bits back into overflow areas until target size is met */

    double *fills;
    double expectedBits = 0;
    double adjustment;
    double prevBits = 0;
    int t0, t1;
    int iterations = 0 , adjMin, adjMax;
    CHECKED_MALLOC(fills, double, m_numEntries + 1);
    fills++;

    /* adjust overall stream size */
    do
    {
        iterations++;
        prevBits = expectedBits;

        if (expectedBits)
        {   /* not first iteration */
            adjustment = X265_MAX(X265_MIN(expectedBits / allAvailableBits, 0.999), 0.9);
            fills[-1] = m_bufferSize * m_param->rc.vbvBufferInit;
            t0 = 0;
            /* fix overflows */
            adjMin = 1;
            while (adjMin && findUnderflow(fills, &t0, &t1, 1))
            {
                adjMin = fixUnderflow(t0, t1, adjustment, MIN_QPSCALE, MAX_MAX_QPSCALE);
                t0 = t1;
            }
        }

        fills[-1] = m_bufferSize * (1. - m_param->rc.vbvBufferInit);
        t0 = 0;
        /* fix underflows -- should be done after overflow, as we'd better undersize target than underflowing VBV */
        adjMax = 1;
        while (adjMax && findUnderflow(fills, &t0, &t1, 0))
            adjMax = fixUnderflow(t0, t1, 1.001, MIN_QPSCALE, MAX_MAX_QPSCALE );

        expectedBits = countExpectedBits();
    }
    while ((expectedBits < .995 * allAvailableBits) && ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)));

    if (!adjMax)
        x265_log(m_param, X265_LOG_WARNING, "vbv-maxrate issue, qpmax or vbv-maxrate too low\n");

    /* store expected vbv filling values for tracking when encoding */
    for (int i = 0; i < m_numEntries; i++)
        m_rce2Pass[i].expectedVbv = m_bufferSize - fills[i];

    X265_FREE(fills - 1);
    return true;

fail:
    x265_log(m_param, X265_LOG_ERROR, "malloc failure in two-pass VBV init\n");
    return false;
}

/* In 2pass, force the same frame types as in the 1st pass */
int RateControl::rateControlSliceType(int frameNum)
{
    if (m_param->rc.bStatRead)
    {
        if (frameNum >= m_numEntries)
        {
            /* We could try to initialize everything required for ABR and
             * adaptive B-frames, but that would be complicated.
             * So just calculate the average QP used so far. */
            m_param->rc.qp = (m_accumPQp < 1) ? ABR_INIT_QP_MAX : (int)(m_accumPQp + 0.5);
            m_qpConstant[P_SLICE] = x265_clip3(QP_MIN, QP_MAX_MAX, m_param->rc.qp);
            m_qpConstant[I_SLICE] = x265_clip3(QP_MIN, QP_MAX_MAX, (int)(m_param->rc.qp - m_ipOffset + 0.5));
            m_qpConstant[B_SLICE] = x265_clip3(QP_MIN, QP_MAX_MAX, (int)(m_param->rc.qp + m_pbOffset + 0.5));

            x265_log(m_param, X265_LOG_ERROR, "2nd pass has more frames than 1st pass (%d)\n", m_numEntries);
            x265_log(m_param, X265_LOG_ERROR, "continuing anyway, at constant QP=%d\n", m_param->rc.qp);
            if (m_param->bFrameAdaptive)
                x265_log(m_param, X265_LOG_ERROR, "disabling adaptive B-frames\n");

            m_isAbr = 0;
            m_2pass = 0;
            m_param->rc.rateControlMode = X265_RC_CQP;
            m_param->rc.bStatRead = 0;
            m_param->bFrameAdaptive = 0;
            m_param->scenecutThreshold = 0;
            m_param->rc.cuTree = 0;
            if (m_param->bframes > 1)
                m_param->bframes = 1;
            return X265_TYPE_AUTO;
        }
        int frameType = m_rce2Pass[frameNum].sliceType == I_SLICE ? (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR)
                            : m_rce2Pass[frameNum].sliceType == P_SLICE ? X265_TYPE_P
                            : (m_rce2Pass[frameNum].sliceType == B_SLICE && m_rce2Pass[frameNum].keptAsRef? X265_TYPE_BREF : X265_TYPE_B);
        return frameType;
    }
    else
        return X265_TYPE_AUTO;
}
/** 函数功能             : 初始化Predictor
/*  调用范围             : 只在RateControl::init和RateControl::rateControlStart函数中被调用
* \返回                  : null * */
void RateControl::initFramePredictors()
{
    //在初始化和场景切换帧处重置
    /* Frame Predictors used in vbv */
    for (int i = 0; i < 4; i++)
    {
        m_pred[i].coeff = 1.0;
        m_pred[i].count = 1.0;
        m_pred[i].decay = 0.5;
        m_pred[i].offset = 0.0;
    }
    m_pred[0].coeff = m_pred[3].coeff = 0.75;
    if (m_param->rc.qCompress >= 0.8) // when tuned for grain 
    {
        m_pred[1].coeff = 0.75;
        m_pred[0].coeff = m_pred[3].coeff = 0.50;
    }
}
/** 函数功能             : 计算估计当前帧应用的量化参数
/*  调用范围             : 只在FrameEncoder::compressFrame()函数中被调用
* \参数 curFrame         : 当前编码帧
* \参数 rce              : 当前帧的RC编码参数类
* \参数 enc              : 上层encodr类
* \返回                  : 返回当前帧估计的量化参数 * */
int RateControl::rateControlStart(Frame* curFrame, RateControlEntry* rce, Encoder* enc)
{
    //功能:
    //     1.循环等待触发
    //     2.初始化RC帧类型等基本信息
    //     3.如果是2pass:???
    //     4.根据场景切换帧信息选择是否初始化Predictor
    //     5.如果应用VBV:更新bitsbuffer 根据当前level规定设置当前帧最大占用的bits
    //     6.如果应用ABR,CRF或者当前为2pass:估计当前帧的m_qp值
    //       否则 如果是CQP模式   获取当前帧的QP值 (加上相应的offset)
    //     7.更新数据 并返回当前帧估计的量化参数
    int orderValue = m_startEndOrder.get();//获取当前RC线程控制参量
    int startOrdinal = rce->encodeOrder * 2;//触发参量值

    while (orderValue < startOrdinal && !m_bTerminated)//循环等待
        orderValue = m_startEndOrder.waitForChange(orderValue);//等待参量数据改变

    if (!curFrame) //无帧信息情况 一般不进入
    {
        // faked rateControlStart calls when the encoder is flushing
        m_startEndOrder.incr();
        return 0;
    }

    FrameData& curEncData = *curFrame->m_encData;//获取当前帧的编码信息
    m_curSlice = curEncData.m_slice;//获取当前帧的slice
    m_sliceType = m_curSlice->m_sliceType;//获取当前的slice类型
    rce->sliceType = m_sliceType;//获取当前的slice类型
    if (!m_2pass)//如果是1pass
        rce->keptAsRef = IS_REFERENCED(curFrame);//判断当前是否可作参考帧
    m_predType = getPredictorType(curFrame->m_lowres.sliceType, m_sliceType);//获取predictor应用的标号 0:不可参考b帧 1: P帧  2:I帧 3:可参考B帧
    rce->poc = m_curSlice->m_poc;//获取当前poc
    if (m_param->rc.bStatRead)//????
    {
        X265_CHECK(rce->poc >= 0 && rce->poc < m_numEntries, "bad encode ordinal\n");
        copyRceData(rce, &m_rce2Pass[rce->poc]);
    }
    rce->isActive = true;//RC启动
    bool isRefFrameScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refPicList[0][0]->m_lowres.bScenecut == 1; //如果其前向第一个参考帧为场景切换帧
    //设x为场景切换帧
    //IBBBPBBBxBBBPBBBP  对应m_isSceneTransition值
    //00000000111111110
    if (curFrame->m_lowres.bScenecut) //如果当前帧为场景切换帧
    {
        m_isSceneTransition = true;//场景切换帧置为ture
        m_lastPredictorReset = rce->encodeOrder;//记录Predictor重置的编码位置(编码顺序) rce->encodeOrder
        initFramePredictors();//初始化Predictor
    }
    else if (m_sliceType != B_SLICE && !isRefFrameScenecut)//当前是P帧或者不是场景切换帧的I帧   并且 前向参考不是场景切换帧
        m_isSceneTransition = false;//置为false

    if (rce->encodeOrder < m_lastPredictorReset + m_param->frameNumThreads)//如果遇到场景切换帧 或者首帧 将当前的的count置为0  有几个framethread 进入初始化几次
    {
        rce->rowPreds[0][0].count = 0;
    }

    rce->bLastMiniGopBFrame = curFrame->m_lowres.bLastMiniGopBFrame;//标记当前帧是否为当前GOP的最后一个B帧
    rce->bufferRate = m_bufferRate;//平均每帧最大的bits占用数目
    rce->rowCplxrSum = 0.0;//初始化
    rce->rowTotalBits = 0;//初始化
    //功能:更新bitsbuffer 根据当前level规定设置当前帧最大占用的bits
    //      1.根据情况初始化Predictor (场景切换帧后)
    //      2.更新bitsbuffer
    //      3.根据当前level下最小压缩比设置当前帧相应的frameSizeMaximum(当前帧占用的最大bits)
    if (m_isVbv)//如果应用VBV
    {
        //初始化Predictor
        if (rce->rowPreds[0][0].count == 0)
        {
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 2; j++)
                {
                    rce->rowPreds[i][j].coeff = 0.25;
                    rce->rowPreds[i][j].count = 1.0;
                    rce->rowPreds[i][j].decay = 0.5;
                    rce->rowPreds[i][j].offset = 0.0;
                }
            }
        }
        rce->rowPred[0] = &rce->rowPreds[m_sliceType][0];//指向当前帧类型位置 便于计算
        rce->rowPred[1] = &rce->rowPreds[m_sliceType][1];//指向当前帧类型位置 便于计算
        m_predictedBits = m_totalBits;//获取当前已经编码帧总的bits
        updateVbvPlan(enc);//VBV中更新根据当前帧并行情况更新当前RCbuffer
        rce->bufferFill = m_bufferFill;//获取更新后的值

        int mincr = enc->m_vps.ptl.minCrForLevel;//当前的最小压缩比 CR 表示 CompressionRatio 
        //根据当前level下最小压缩比设置当前帧相应的frameSizeMaximum(当前帧占用的最大bits)
        /* Profiles above Main10 don't require maxAU size check, so just set the maximum to a large value. */
        if (enc->m_vps.ptl.profileIdc > Profile::MAIN10 || enc->m_vps.ptl.levelIdc == Level::NONE)//如果是MAINSTILLPICTURE、MAINREXT档次或者没有等级定位 
            rce->frameSizeMaximum = 1e9; //设为一个大值
        else
        {
            /* The spec has a special case for the first frame. */
            if (rce->encodeOrder == 0)//第一帧
            {
                /* 1.5 * (Max( PicSizeInSamplesY, fR * MaxLumaSr) + MaxLumaSr * (AuCpbRemovalTime[ 0 ] -AuNominalRemovalTime[ 0 ])) ? MinCr */
                double fr = 1. / 300;//压缩因子 用于估计bits
                int picSizeInSamplesY = m_param->sourceWidth * m_param->sourceHeight;//当前帧的像素个数
                rce->frameSizeMaximum = 8 * 1.5 * X265_MAX(picSizeInSamplesY, fr * enc->m_vps.ptl.maxLumaSrForLevel) / mincr;//8表示一般一个像素占用8比特  1.5表示 4:2:0 格式 1.5帧(含有两个色度)
            }
            else
            {
                /* 1.5 * MaxLumaSr * (AuCpbRemovalTime[ n ] - AuCpbRemovalTime[ n - 1 ]) / MinCr */
                rce->frameSizeMaximum = 8 * 1.5 * enc->m_vps.ptl.maxLumaSrForLevel * m_frameDuration / mincr;//当前level下当前帧占用的最大bits 
            }
        }
    }
    //功能:估计当前帧的m_qp值
    //    1.如果应用ABR或者VBV 获取framecost 记录连续b帧cost相同数目,并在后一个非B帧中设置为同一模式(个数大于配置的B帧个数时)
    //    2.预估当前帧的m_qp
    if (m_isAbr || m_2pass) // ABR,CRF
    {
        if (m_isAbr || m_isVbv)
        {
            m_currentSatd = curFrame->m_lowres.satdCost >> (X265_DEPTH - 8); //获取当前的framecost 如果需要参考帧,取参考帧列表中各自第一帧当做参考帧的framecost 
            /* Update rce for use in rate control VBV later */
            rce->lastSatd = m_currentSatd;//更新当前最新的SATD值
            X265_CHECK(rce->lastSatd, "satdcost cannot be zero\n");
            /* Detect a pattern for B frames with same SATDcost to identify a series of static frames
             * and the P frame at the end of the series marks a possible case for ABR reset logic */
            if (m_param->bframes) //如果有B帧 功能:记录连续b帧cost相同数目,并在后一个非B帧中设置为同一模式(个数大于配置的B帧个数时)
            {
                if (m_sliceType != B_SLICE && m_numBframesInPattern > m_param->bframes)//如果当前是(I帧或者P帧) 并且相同cost的个数大于配置的B帧个数
                {
                    m_isPatternPresent = true;//置为同一模式
                }
                else if (m_sliceType == B_SLICE && !IS_REFERENCED(curFrame))//如果当前是B帧并且不是B参考帧
                {
                    if (m_currentSatd != m_lastBsliceSatdCost && !rce->bLastMiniGopBFrame)//如果当前B帧的cost不等于上一个B帧(编码顺序)的cost 并且不是当前帧是否为当前GOP的最后一个B帧
                    {
                        m_isPatternPresent = false;//开始一个新的模式 置为false
                        m_lastBsliceSatdCost = m_currentSatd;//记录最新B帧的framecost
                        m_numBframesInPattern = 0;//相同cost的个数置为0
                    }
                    else if (m_currentSatd == m_lastBsliceSatdCost)//如果当期B帧cost等于最近一个B帧的cost
                        m_numBframesInPattern++;//累加相同cost的个数
                }
            }
        }
        /* For a scenecut that occurs within the mini-gop, enable scene transition
         * switch until the next mini-gop to ensure a min qp for all the frames within 
         * the scene-transition mini-gop */

        double q = x265_qScale2qp(rateEstimateQscale(curFrame, rce));//预估当前帧的qscale并将预估qscale转换成qp参数 ???
        q = x265_clip3((double)QP_MIN, (double)QP_MAX_MAX, q);//clip操作防止越界
        m_qp = int(q + 0.5);//四舍五入转换成整数qp参数
        rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = q;//获取预估qp参数值(未四舍五入)
        /* copy value of lastRceq into thread local rce struct *to be used in RateControlEnd() */
        rce->qRceq = m_lastRceq;//获取数据对应未加权的qscale
        accumPQpUpdate();//累加m_accumPQp*0.95+m_qp和m_accumPNorm*0.95+1
    }
    else // CQP 固定QP模式
    {
        if (m_sliceType == B_SLICE && IS_REFERENCED(curFrame))//如果是B参考帧
            m_qp = (m_qpConstant[B_SLICE] + m_qpConstant[P_SLICE]) / 2; //QP取B帧和P帧的一半
        else
            m_qp = m_qpConstant[m_sliceType];//获取相应帧对应的QP
        curEncData.m_avgQpAq = curEncData.m_avgQpRc = m_qp;//获取当前帧的QP值
        
        x265_zone* zone = getZone();//获取当前帧所在的zone
        if (zone)
        {
            if (zone->bForceQp)//如果是QP模式
                m_qp += zone->qp - m_qpConstant[P_SLICE];
            else
                m_qp -= (int)(6.0 * X265_LOG2(zone->bitrateFactor));//因子模式
        }
    }
    if (m_sliceType != B_SLICE)//当前不是B帧
    {
        m_lastNonBPictType = m_sliceType;//更新最新的非B帧类型
        m_leadingNoBSatd = m_currentSatd;//更新最新的非B帧的SATD值
    }
    rce->leadingNoBSatd = m_leadingNoBSatd;//暂无任何作用 获取当前RC的最新非B帧的SATD值
    if (curFrame->m_forceqp)//如果应用QPfile
    {
        m_qp = (int32_t)(curFrame->m_forceqp + 0.5) - 1;//获取当前QP值
        m_qp = x265_clip3(QP_MIN, QP_MAX_MAX, m_qp);//防止越界
        rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = m_qp;//获取当前最新QP
        if (m_isAbr || m_2pass)//如果应用ABR或者当前为2pass
        {
            rce->qpNoVbv = rce->qpaRc;//获取没有经过修正的量化参数
            m_lastQScaleFor[m_sliceType] = x265_qp2qScale(rce->qpaRc);//qp转换为qpscale  存储最新的qscale值
            if (rce->poc == 0)
                 m_lastQScaleFor[P_SLICE] = m_lastQScaleFor[m_sliceType] * fabs(m_param->rc.ipFactor);//第一帧加权
            rce->frameSizePlanned = predictSize(&m_pred[m_predType], m_qp, (double)m_currentSatd);//获取预测的bits
        }
    }
    m_framesDone++;//计数

    return m_qp;//返回当前帧估计的量化参数
}
/** 函数功能             : 累加m_accumPQp*0.95+m_qp和m_accumPNorm*0.95+1
/*  调用范围             : 只在rateControlStart函数中被调用
* \返回                  : null * */
void RateControl::accumPQpUpdate()
{
    m_accumPQp   *= .95;
    m_accumPNorm *= .95;
    m_accumPNorm += 1;
    if (m_sliceType == I_SLICE)
        m_accumPQp += m_qp + m_ipOffset;
    else
        m_accumPQp += m_qp;
}
/** 函数功能             : 获取predictor应用的标号 0:不可参考b帧 1: P帧  2:I帧 3:可参考B帧
/*  调用范围             : 只在rateControlStart和RateControl::clipQscale函数中被调用
* \参数 lowresSliceType  : 在rateControlStart中:当前帧的帧类型(如X265_TYPE_IDR等)             在RateControl::clipQscale中:???
* \参数 sliceType        : 在rateControlStart中:当前帧的slice类型(如B_SLICE,P_SLICE,I_SLICE等)在RateControl::clipQscale中:???
* \返回                  : 返回predictor应用的标号 0:不可参考b帧 1: P帧  2:I帧 3:可参考B帧* */
int RateControl::getPredictorType(int lowresSliceType, int sliceType)
{
    /* Use a different predictor for B Ref and B frames for vbv frame size predictions */
    if (lowresSliceType == X265_TYPE_BREF)
        return 3;
    return sliceType;
}

double RateControl::getDiffLimitedQScale(RateControlEntry *rce, double q)
{
    // force I/B quants as a function of P quants
    const double lastPqScale    = m_lastQScaleFor[P_SLICE];
    const double lastNonBqScale = m_lastQScaleFor[m_lastNonBPictType];
    if (rce->sliceType == I_SLICE)
    {
        double iq = q;
        double pq = x265_qp2qScale(m_accumPQp / m_accumPNorm);
        double ipFactor = fabs(m_param->rc.ipFactor);
        /* don't apply ipFactor if the following frame is also I */
        if (m_accumPNorm <= 0)
            q = iq;
        else if (m_param->rc.ipFactor < 0)
            q = iq / ipFactor;
        else if (m_accumPNorm >= 1)
            q = pq / ipFactor;
        else
            q = m_accumPNorm * pq / ipFactor + (1 - m_accumPNorm) * iq;
    }
    else if (rce->sliceType == B_SLICE)
    {
        if (m_param->rc.pbFactor > 0)
            q = lastNonBqScale;
        if (!rce->keptAsRef)
            q *= fabs(m_param->rc.pbFactor);
    }
    else if (rce->sliceType == P_SLICE
             && m_lastNonBPictType == P_SLICE
             && rce->coeffBits == 0)
    {
        q = lastPqScale;
    }

    /* last qscale / qdiff stuff */
    if (m_lastNonBPictType == rce->sliceType &&
        (rce->sliceType != I_SLICE || m_lastAccumPNorm < 1))
    {
        double maxQscale = m_lastQScaleFor[rce->sliceType] * m_lstep;
        double minQscale = m_lastQScaleFor[rce->sliceType] / m_lstep;
        q = x265_clip3(minQscale, maxQscale, q);
    }

    m_lastQScaleFor[rce->sliceType] = q;
    if (rce->sliceType != B_SLICE)
        m_lastNonBPictType = rce->sliceType;
    if (rce->sliceType == I_SLICE)
    {
        m_lastAccumPNorm = m_accumPNorm;
        m_accumPNorm = 0;
        m_accumPQp = 0;
    }
    if (rce->sliceType == P_SLICE)
    {
        double mask = 1 - pow(rce->iCuCount / m_ncu, 2);
        m_accumPQp   = mask * (x265_qScale2qp(q) + m_accumPQp);
        m_accumPNorm = mask * (1 + m_accumPNorm);
    }

    x265_zone* zone = getZone();
    if (zone)
    {
        if (zone->bForceQp)
            q = x265_qp2qScale(zone->qp);
        else
            q /= zone->bitrateFactor;
    }
    return q;
}

double RateControl::countExpectedBits()
{
    double expectedBits = 0;
    for( int i = 0; i < m_numEntries; i++ )
    {
        RateControlEntry *rce = &m_rce2Pass[i];
        rce->expectedBits = (uint64_t)expectedBits;
        expectedBits += qScale2bits(rce, rce->newQScale);
    }
    return expectedBits;
}

bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over)
{
    /* find an interval ending on an overflow or underflow (depending on whether
     * we're adding or removing bits), and starting on the earliest frame that
     * can influence the buffer fill of that end frame. */
    const double bufferMin = .1 * m_bufferSize;
    const double bufferMax = .9 * m_bufferSize;
    double fill = fills[*t0 - 1];
    double parity = over ? 1. : -1.;
    int start = -1, end = -1;
    for (int i = *t0; i < m_numEntries; i++)
    {
        fill += (m_frameDuration * m_vbvMaxRate -
                 qScale2bits(&m_rce2Pass[i], m_rce2Pass[i].newQScale)) * parity;
        fill = x265_clip3(0.0, m_bufferSize, fill);
        fills[i] = fill;
        if (fill <= bufferMin || i == 0)
        {
            if (end >= 0)
                break;
            start = i;
        }
        else if (fill >= bufferMax && start >= 0)
            end = i;
    }
    *t0 = start;
    *t1 = end;
    return start >= 0 && end >= 0;
}

bool RateControl::fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax)
{
    double qscaleOrig, qscaleNew;
    bool adjusted = false;
    if (t0 > 0)
        t0++;
    for (int i = t0; i <= t1; i++)
    {
        qscaleOrig = m_rce2Pass[i].newQScale;
        qscaleOrig = x265_clip3(qscaleMin, qscaleMax, qscaleOrig);
        qscaleNew  = qscaleOrig * adjustment;
        qscaleNew  = x265_clip3(qscaleMin, qscaleMax, qscaleNew);
        m_rce2Pass[i].newQScale = qscaleNew;
        adjusted = adjusted || (qscaleNew != qscaleOrig);
    }
    return adjusted;
}

bool RateControl::cuTreeReadFor2Pass(Frame* frame)
{
    uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[frame->m_poc].sliceType;

    if (m_rce2Pass[frame->m_poc].keptAsRef)
    {
        /* TODO: We don't need pre-lookahead to measure AQ offsets, but there is currently
         * no way to signal this */
        uint8_t type;
        if (m_cuTreeStats.qpBufPos < 0)
        {
            do
            {
                m_cuTreeStats.qpBufPos++;

                if (!fread(&type, 1, 1, m_cutreeStatFileIn))
                    goto fail;
                if (fread(m_cuTreeStats.qpBuffer[m_cuTreeStats.qpBufPos], sizeof(uint16_t), m_ncu, m_cutreeStatFileIn) != (size_t)m_ncu)
                    goto fail;

                if (type != sliceTypeActual && m_cuTreeStats.qpBufPos == 1)
                {
                    x265_log(m_param, X265_LOG_ERROR, "CU-tree frametype %d doesn't match actual frametype %d.\n", type, sliceTypeActual);
                    return false;
                }
            }
            while(type != sliceTypeActual);
        }
        for (int i = 0; i < m_ncu; i++)
        {
            int16_t qpFix8 = m_cuTreeStats.qpBuffer[m_cuTreeStats.qpBufPos][i];
            frame->m_lowres.qpCuTreeOffset[i] = (double)(qpFix8) / 256.0;
            frame->m_lowres.invQscaleFactor[i] = x265_exp2fix8(frame->m_lowres.qpCuTreeOffset[i]);
        }
        m_cuTreeStats.qpBufPos--;
    }
    return true;

fail:
    x265_log(m_param, X265_LOG_ERROR, "Incomplete CU-tree stats file.\n");
    return false;
}
/** 函数功能             : 根据当前已编码bits数目修正预估的qscale值并计算overflow值(qScale *= overflow)
/*  调用范围             : 只在rateEstimateQscale函数中被调用
* \参数 qScale           : qscale参数
* \返回                  : 返回修正后的qscale值 * */
double RateControl::tuneAbrQScaleFromFeedback(double qScale)
{
    double abrBuffer = 2 * m_rateTolerance * m_bitrate;//最大使用的ABRbuffer大小
    if (m_currentSatd)//如果当前帧的framecost不等于0
    {
        /* use framesDone instead of POC as poc count is not serial with bframes enabled */
        double overflow = 1.0;//用于计算上溢 本次初始化无意义
        double timeDone = (double)(m_framesDone - m_param->frameNumThreads + 1) * m_frameDuration;//当前RC里面帧的总时长 减去并行个数加上当前的一个
        double wantedBits = timeDone * m_bitrate;//当前需要的总共bits数目 (RC里面的所有帧)
        int64_t encodedBits = m_totalBits;//获取当前RC已编码占用的bits
        if (m_param->totalFrames && m_param->totalFrames <= 2 * m_fps)//如果当前编码的总帧数不够2秒钟
        {
            abrBuffer = m_param->totalFrames * (m_bitrate / m_fps);//ABRbuffer修正为这些帧总共需要的空间
            encodedBits = m_encodedBits;//获取时间编码bits (without ammortization)
        }

        if (wantedBits > 0 && encodedBits > 0 && (!m_partialResidualFrames || 
            m_param->rc.bStrictCbr))                    //已经有编码数据
        {
            abrBuffer *= X265_MAX(1, sqrt(timeDone));//修正当前buffer
            overflow = x265_clip3(.5, 2.0, 1.0 + (encodedBits - wantedBits) / abrBuffer);//获取上溢值
            qScale *= overflow;//修正当前qscale
        }
    }
    return qScale;//返回修正后的qscale值
}
/** 函数功能             : ???分析加权信息(每个list的第一帧分析加权与否,其它不加权)
/*  调用范围             : 只在rateControlStart函数中被调用
* \参数 curFrame         : 当前编码帧
* \参数 rce              : ???当前编码帧
* \返回                  : ??null * */
double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)
{
    //功能:???
    //     1. 如果是2pass环节 无须计算(只需验证是否帧类型一致) 如果是1pass并且应用ABR:计算滑动窗口平均framecost和 
    //     2. 如果当前是B帧:根据向后参考帧获取预估qscale值,获取当前帧预估bits 返回预估当前帧的qscale值
    //     3. 如果当前为I帧或者P帧:获取当前帧预估bits 返回预估当前帧的qscale值
    double q;//用于存储当前帧估计的qscale值

    if (m_2pass)//如果当前处在应用2pass
    {
        if (m_sliceType != rce->sliceType)//2pass中 如果帧类型不匹配报错
        {
            x265_log(m_param, X265_LOG_ERROR, "slice=%c but 2pass stats say %c\n",
                     g_sliceTypeToChar[m_sliceType], g_sliceTypeToChar[rce->sliceType]);
        }
    }
    else
    {
        if (m_isAbr)//应用ABR  功能:计算滑动窗口平均framecost和
        {
            double slidingWindowCplxSum = 0;//用于计算滑动窗口平均framecost和
            //计算方式:假设当前序列为 F0 F1 F2 F3 F4.....  
            //则: F0 = 0  F1 = F0*0.5  F2 = (F0*0.5 + F1)*0.5  F3 = ((F0*0.5 + F1)*0.5 + F2)*0.5  F4 = (((F0*0.5 + F1)*0.5 + F2)*0.5 + F3)*0.5
            int start = m_sliderPos > s_slidingWindowFrames ?  m_sliderPos : 0;//获取当前滑动窗口的下标  循环队列
            for (int cnt = 0; cnt < s_slidingWindowFrames; cnt++, start++)//获取滑动窗口framecost和
            {
                int pos = start % s_slidingWindowFrames;//获取当前下标
                slidingWindowCplxSum *= 0.5;
                if (!m_satdCostWindow[pos])
                    break;
                slidingWindowCplxSum += m_satdCostWindow[pos];//累加当前framecost
            }
            rce->movingAvgSum = slidingWindowCplxSum;//获取滑动窗口平均framecost和
            m_satdCostWindow[m_sliderPos % s_slidingWindowFrames] = rce->lastSatd;//获取当前下标
            m_sliderPos++;//用于标示下一帧的滑动窗口下标
        }
    }

    if (m_sliceType == B_SLICE)//如果当前是B帧:根据向后参考帧获取预估qscale值,获取当前帧预估bits 返回预估当前帧的qscale值
    {
        /* B-frames don't have independent rate control, but rather get the
         * average QP of the two adjacent P-frames + an offset */
        Slice* prevRefSlice = m_curSlice->m_refPicList[0][0]->m_encData->m_slice;//获取前向帧slice
        Slice* nextRefSlice = m_curSlice->m_refPicList[1][0]->m_encData->m_slice;//获取后向帧slice
        double q0 = m_curSlice->m_refPicList[0][0]->m_encData->m_avgQpRc;//获取前向参考帧的平均QP
        double q1 = m_curSlice->m_refPicList[1][0]->m_encData->m_avgQpRc;//获取后向参考帧的平均QP
        bool i0 = prevRefSlice->m_sliceType == I_SLICE;//判断前向参考帧是否为I帧
        bool i1 = nextRefSlice->m_sliceType == I_SLICE;//判断后向参考帧是否为I帧
        int dt0 = abs(m_curSlice->m_poc - prevRefSlice->m_poc);//获取当前编码帧与前向参考帧的距离
        int dt1 = abs(m_curSlice->m_poc - nextRefSlice->m_poc);//获取当前编码帧与后向参考帧的距离

        // Skip taking a reference frame before the Scenecut if ABR has been reset.
        if (m_lastAbrResetPoc >= 0)//如果前面有非B帧 ABR进行重置
        {
            if (prevRefSlice->m_sliceType == P_SLICE && prevRefSlice->m_poc < m_lastAbrResetPoc)//如果前向帧为P帧  并且  前向帧在重置位置之前
            {
                i0 = i1; //获取后向帧是否为I帧
                dt0 = dt1;//获取后向帧距离
                q0 = q1;//获取后向帧QP
            }
        }
        if (prevRefSlice->m_sliceType == B_SLICE && IS_REFERENCED(m_curSlice->m_refPicList[0][0]))//如果前向参考帧为B帧  并且 前向参考帧为可参考B帧
            q0 -= m_pbOffset / 2; //修正前向参考帧的平均QP
        if (nextRefSlice->m_sliceType == B_SLICE && IS_REFERENCED(m_curSlice->m_refPicList[1][0]))//如果后向参考帧为B帧  并且 后向参考帧为可参考B帧
            q1 -= m_pbOffset / 2;//修正前向参考帧的平均QP
        if (i0 && i1)//如果前向和后向参考帧都为I帧
            q = (q0 + q1) / 2 + m_ipOffset;//获取当前预估QP值:其平均值
        else if (i0)//如果前向参考帧为I帧
            q = q1;//获取后向帧的平均QP值
        else if (i1)//如果后向参考帧为I帧
            q = q0;//获取前向参考帧的平均QP值
        else
            q = (q0 * dt1 + q1 * dt0) / (dt0 + dt1);//获取按距离加权的平均QP值

        if (IS_REFERENCED(curFrame))//如果当前帧为可参考帧
            q += m_pbOffset / 2;//QP增加一半PBoffset
        else
            q += m_pbOffset;//QP增加PBoffset

        /* Set a min qp at scenechanges and transitions */
        if (m_isSceneTransition)//如果当前帧是场景切换帧
        {
            q = X265_MAX(ABR_SCENECUT_INIT_QP_MIN, q);//取最大QP
            double minScenecutQscale =x265_qp2qScale(ABR_SCENECUT_INIT_QP_MIN); //获取最小Qscale值
            m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale, m_lastQScaleFor[P_SLICE]);//更新P帧最新qscale值
        }
        double qScale = x265_qp2qScale(q);//获取当前预估的qscale值
        rce->qpNoVbv = q;//获取未经VBV修正的qp参数
        double lmin = 0, lmax = 0;//暂存最大 和最小qscale值
        if (m_isVbv)//如果应用VBV
        {
            lmin = m_lastQScaleFor[P_SLICE] / m_lstep;//获取最小qscale
            lmax = m_lastQScaleFor[P_SLICE] * m_lstep;//获取最大qscale
            if (m_isCbr)//如果为CBR
            {
                qScale = tuneAbrQScaleFromFeedback(qScale);//根据当前已编码bits数目修正预估的qscale值并计算overflow值(qScale *= overflow)
                if (!m_isAbrReset)//如果当前没有被重置ABR
                    qScale = x265_clip3(lmin, lmax, qScale);//clip 当前的qscale值
                q = x265_qScale2qp(qScale);//获取qp量化参数
            }
            if (!m_2pass)//如果不是2pass
            {
                qScale = clipQscale(curFrame, rce, qScale);//根据下采样SATD信息修正qscale值
                /* clip qp to permissible range after vbv-lookahead estimation to avoid possible 
                 * mispredictions by initial frame size predictors */
                if (m_pred[m_predType].count == 1)//如果当前帧类型值update过一次predictor
                    qScale = x265_clip3(lmin, lmax, qScale);//clip操作 防止越界
                m_lastQScaleFor[m_sliceType] = qScale;//获取最新的qscale值
                rce->frameSizePlanned = predictSize(&m_pred[m_predType], qScale, (double)m_currentSatd);//预测当前帧需要的bits
            }
            else
                rce->frameSizePlanned = qScale2bits(rce, qScale);//根据1pass 数据 获取2pass当前计划占用的bits

            /* Limit planned size by MinCR */
            rce->frameSizePlanned = X265_MIN(rce->frameSizePlanned, rce->frameSizeMaximum);预估bits与当前level下当前帧占用的最大bit去最小值
            rce->frameSizeEstimated = rce->frameSizePlanned;//获取预估bits
        }
        rce->newQScale = qScale;//获取当前的预估qscale
        return qScale;//返回预估的qscale
    }
    else //如果当前为I帧或者P帧
    {
        //功能:获取当前帧预估bits 返回预估当前帧的qscale值
        //    1. 如果当前是2pass:???
        //       否则如果当前不是2pass:预估当前帧的qscale值 并 根据下采样SATD信息修正qscale值(仅限VBV模式)
        //    2. 获取当前帧预估bits 返回预估当前帧的qscale值
        double abrBuffer = 2 * m_rateTolerance * m_bitrate;//获取当前可用buffer
        if (m_2pass)//????
        {
            int64_t diff;
            if (!m_isVbv)
            {
                m_predictedBits = m_totalBits;
                if (rce->encodeOrder < m_param->frameNumThreads)
                    m_predictedBits += (int64_t)(rce->encodeOrder * m_bitrate / m_fps);
                else
                    m_predictedBits += (int64_t)(m_param->frameNumThreads * m_bitrate / m_fps);
            }
            /* Adjust ABR buffer based on distance to the end of the video. */
            if (m_numEntries > rce->encodeOrder)
            {
                uint64_t finalBits = m_rce2Pass[m_numEntries - 1].expectedBits;
                double videoPos = (double)rce->expectedBits / finalBits;
                double scaleFactor = sqrt((1 - videoPos) * m_numEntries);
                abrBuffer *= 0.5 * X265_MAX(scaleFactor, 0.5);
            }
            diff = m_predictedBits - (int64_t)rce->expectedBits;
            q = rce->newQScale;
            q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer);
            if (m_expectedBitsSum > 0)
            {
                /* Adjust quant based on the difference between
                 * achieved and expected bitrate so far */
                double curTime = (double)rce->encodeOrder / m_numEntries;
                double w = x265_clip3(0.0, 1.0, curTime * 100);
                q *= pow((double)m_totalBits / m_expectedBitsSum, w);
            }
            rce->qpNoVbv = x265_qScale2qp(q);
            if (m_isVbv)
            {
                /* Do not overflow vbv */
                double expectedSize = qScale2bits(rce, q);
                double expectedVbv = m_bufferFill + m_bufferRate - expectedSize;
                double expectedFullness = rce->expectedVbv / m_bufferSize;
                double qmax = q * (2 - expectedFullness);
                double sizeConstraint = 1 + expectedFullness;
                qmax = X265_MAX(qmax, rce->newQScale);
                if (expectedFullness < .05)
                    qmax = MAX_MAX_QPSCALE;
                qmax = X265_MIN(qmax, MAX_MAX_QPSCALE);
                while (((expectedVbv < rce->expectedVbv/sizeConstraint) && (q < qmax)) ||
                        ((expectedVbv < 0) && (q < MAX_MAX_QPSCALE)))
                {
                    q *= 1.05;
                    expectedSize = qScale2bits(rce, q);
                    expectedVbv = m_bufferFill + m_bufferRate - expectedSize;
                }
            }
            q = x265_clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);
        }
        else //不是2pass
        {
            /* 1pass ABR */

            /* Calculate the quantizer which would have produced the desired
             * average bitrate if it had been applied to all frames so far.
             * Then modulate that quant based on the current frame's complexity
             * relative to the average complexity so far (using the 2pass RCEQ).
             * Then bias the quant up or down if total size so far was far from
             * the target.
             * Result: Depending on the value of rate_tolerance, there is a
             * tradeoff between quality and bitrate precision. But at large
             * tolerances, the bit distribution approaches that of 2pass. */
            //功能:预估当前帧的qscale值 并 根据下采样SATD信息修正qscale值(仅限VBV模式)
            //     1.预估RC计算复杂度 初始化
            //     2.获取预估qscale
            //     3.如果应用VBV:根据下采样SATD信息修正qscale值  否则 只是简单的clip操作
            double overflow = 1;//用于调整当前估计的qscale *= overflow
            double lqmin = MIN_QPSCALE, lqmax = MAX_MAX_QPSCALE; //用于标记最大和最小qsclae 防止越界(后面会对其根据实际情况更新) 分别为 0.21249999999999999 615.46574234477100
            /*m_shortTermCplxSum 当前非B帧及以前所有非B帧 framecost * (fps/25)的平均和  
              计算方式: 设当前序列 I0BBBP1BBBP2BBBP3
              则当前m_shortTermCplxSum = (((I0*fps/25)*0.5 + P1*fps/25)*0.5 + P2*fps/25)*0.5 + P3
              m_shortTermCplxCount 当前帧以前非B帧个数 + 1
              I0 = 1
              P1 = I0*0.5 + 1 = 1.5
              P2 = P1*0.5 + 1 = 1.75
              P3 = P2*0.5 + 1 = 1.875
            **/
            m_shortTermCplxSum *= 0.5;//加权求和
            m_shortTermCplxCount *= 0.5;//加权求和
            m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);//计算当前的加权framecost fps越大,其权重越大
            m_shortTermCplxCount++; //累加
            /* coeffBits to be used in 2-pass */
            rce->coeffBits = (int)m_currentSatd;//获取当前帧的framecost值
            rce->blurredComplexity = m_shortTermCplxSum / m_shortTermCplxCount; //预估当前的计算复杂度 (当前非B帧及以前所有非B帧 framecost * (fps/25)的平均和) / (当前帧以前非B帧个数 + 1 )
            rce->mvBits = 0;//初始化
            rce->sliceType = m_sliceType;//无须重新赋值 冗余代码

            //功能:获取预估qscale
            if (m_param->rc.rateControlMode == X265_RC_CRF)//如果当前为CRF模式
            {
                q = getQScale(rce, m_rateFactorConstant);//获取预测qscale
            }
            else
            {
                if (!m_param->rc.bStatRead)//如果不是2pass读
                    checkAndResetABR(rce, false);//检测是否下溢(前面占用bits过少 防止当前非B帧占用bits过多)用于下溢检测并重置ABR
                double initialQScale = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);//获取预测的qscale如果有对应zone信息对qcale进行修正 
                q = tuneAbrQScaleFromFeedback(initialQScale);//根据当前已编码bits数目修正预估的qscale值
                overflow = q / initialQScale;//获取tuneAbrQScaleFromFeedback计算的上溢值
            }
            if (m_sliceType == I_SLICE && m_param->keyframeMax > 1
                && m_lastNonBPictType != I_SLICE && !m_isAbrReset)//如果当前为I帧 并且IDR间隔大于1  并且 前一个非B帧不为I帧 并且没有重置 
            {
                if (!m_param->rc.bStrictCbr)//如果不是严格按照目标码率
                    q = x265_qp2qScale(m_accumPQp / m_accumPNorm);//直接获取平均qscale
                q /= fabs(m_param->rc.ipFactor);//获取I帧的qscale
            }
            else if (m_framesDone > 0)//如果RC中帧数大于0
            {
                if (m_param->rc.rateControlMode != X265_RC_CRF)//当前不为CRF模式
                {
                    lqmin = m_lastQScaleFor[m_sliceType] / m_lstep;//更新最小qscale
                    lqmax = m_lastQScaleFor[m_sliceType] * m_lstep;//更新最大qscale
                    if (!m_partialResidualFrames)//如果当前没有均摊帧数
                    {
                        if (overflow > 1.1 && m_framesDone > 3)
                            lqmax *= m_lstep;//更新最大qscale
                        else if (overflow < 0.9)
                            lqmin /= m_lstep;//更新最小qscale
                    }
                    q = x265_clip3(lqmin, lqmax, q);//clip当前qscale 防止越界
                }
            }
            else if (m_qCompress != 1 && m_param->rc.rateControlMode == X265_RC_CRF)//CRF模式
            {
                q = x265_qp2qScale(CRF_INIT_QP) / fabs(m_param->rc.ipFactor);//获取CFR模式下的qscale
            }
            else if (m_framesDone == 0 && !m_isVbv && m_param->rc.rateControlMode == X265_RC_ABR)//ABR 并且非VBV模式下 第一帧更新最大qscale
            {
                /* for ABR alone, clip the first I frame qp */
                lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;//更新最大qscale (根据初始最大qp)
                q = X265_MIN(lqmax, q);//防止越界 
            }
            q = x265_clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);//clip操作防止越界
            /* Set a min qp at scenechanges and transitions */
            if (m_isSceneTransition)//如果当前是场景切换帧
            {
               double minScenecutQscale =x265_qp2qScale(ABR_SCENECUT_INIT_QP_MIN); //场景切换应用的最小QP 12 对应的qscale
               q = X265_MAX(minScenecutQscale, q);//取最大的qscale
               m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale, m_lastQScaleFor[P_SLICE]);//更新P帧qscale
            }
            rce->qpNoVbv = x265_qScale2qp(q);//获取vbv修正前的量化参数 
            q = clipQscale(curFrame, rce, q);//如果应用VBV:根据下采样SATD信息修正qscale值  否则 只是简单的clip操作
            /*  clip qp to permissible range after vbv-lookahead estimation to avoid possible
             * mispredictions by initial frame size predictors, after each scenecut */
            bool isFrameAfterScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refPicList[0][0]->m_lowres.bScenecut;// 当前帧紧挨帧场景切换帧(编码顺序)如果当前帧不是I帧 并且 其前向参考的第一帧为场景切换帧
            if (!m_2pass && m_isVbv && isFrameAfterScenecut)//如果当前为1pass 并且应用VBV 并且在场景切换帧后面
                q = x265_clip3(lqmin, lqmax, q);//clip操作
        }
        m_lastQScaleFor[m_sliceType] = q;//获取当分B帧的最新qscale
        if ((m_curSlice->m_poc == 0 || m_lastQScaleFor[P_SLICE] < q) && !(m_2pass && !m_isVbv))//(如果是第一帧或者P初始化qscale过小 )
            m_lastQScaleFor[P_SLICE] = q * fabs(m_param->rc.ipFactor);//修正P帧的最新qscale

        if (m_2pass && m_isVbv)//如果当前是2pass 并且应用VBV
            rce->frameSizePlanned = qScale2bits(rce, q);//???
        else
            rce->frameSizePlanned = predictSize(&m_pred[m_predType], q, (double)m_currentSatd);//获取当前帧预估的bits

        /* Always use up the whole VBV in this case. */
        if (m_singleFrameVbv)//如果单帧占用bits过大
            rce->frameSizePlanned = m_bufferRate;//直接将其置为:平均每帧最大的bits占用数目
        /* Limit planned size by MinCR */
        if (m_isVbv)//如果应用VBV
            rce->frameSizePlanned = X265_MIN(rce->frameSizePlanned, rce->frameSizeMaximum);//预估bits与当前level下当前帧占用的最大bit去最小值
        rce->frameSizeEstimated = rce->frameSizePlanned;//获取预估bits
        rce->newQScale = q;//获取当前的预估qscale
        return q;//返回预估的qscale
    }
}
/** 函数功能             : 当前帧编码一半时即时更新数据,便于后续帧快速估计  更新m_startEndOrder计数
/*  调用范围             : 只在processRowEncoder函数中被调用
* \参数 rce              : 当前帧RC相关数据
* \返回                  : null * */
void RateControl::rateControlUpdateStats(RateControlEntry* rce)
{
    if (!m_param->rc.bStatWrite && !m_param->rc.bStatRead)//没有应用多pass结构 既不是读模式 也不是写模式
    {
        if (rce->sliceType == I_SLICE)//如果当前为I帧
        {
            /* previous I still had a residual; roll it into the new loan */
            if (m_partialResidualFrames)//如果已经更新过数据
                rce->rowTotalBits += m_partialResidualCost * m_partialResidualFrames;//当前bits加上剩余bits 
            if ((m_param->totalFrames != 0) && (m_amortizeFrames > (m_param->totalFrames - m_framesDone)))//编码剩余帧数不够分摊帧数
            {
                m_amortizeFrames = 0;//置为0
                m_amortizeFraction = 0;//置为0
            }
            else
            {
                double depreciateRate = 1.1;//因子
                m_amortizeFrames = (int)(m_amortizeFrames / depreciateRate);//更新分摊帧数
                m_amortizeFraction /= depreciateRate;//更新分摊分数
                m_amortizeFrames = X265_MAX(m_amortizeFrames, MIN_AMORTIZE_FRAME);//不能小于默认最小值
                m_amortizeFraction = X265_MAX(m_amortizeFraction, MIN_AMORTIZE_FRACTION);//不能小于默认最小值
            }
            rce->amortizeFrames = m_amortizeFrames;//获取分摊帧数
            rce->amortizeFraction = m_amortizeFraction;//获取分摊因子
            m_partialResidualFrames = X265_MIN((int)rce->amortizeFrames, m_param->keyframeMax);//获取当前分摊帧数
            m_partialResidualCost = (int)((rce->rowTotalBits * rce->amortizeFraction) / m_partialResidualFrames);//获取当前I帧的剩余cost
            rce->rowTotalBits -= m_partialResidualCost * m_partialResidualFrames;//减去更新后的bits
        }
        else if (m_partialResidualFrames)//非I帧
        {
             rce->rowTotalBits += m_partialResidualCost;//修正增加当前I帧的剩余cost
             m_partialResidualFrames--;//减减
        }
    }
    if (rce->sliceType != B_SLICE)//非B帧
        rce->rowCplxrSum = rce->rowTotalBits * x265_qp2qScale(rce->qpaRc) / rce->qRceq;//获取cost值
    else
        rce->rowCplxrSum = rce->rowTotalBits * x265_qp2qScale(rce->qpaRc) / (rce->qRceq * fabs(m_param->rc.pbFactor));//获取cost值

    m_cplxrSum += rce->rowCplxrSum;//获取预测cost
    m_totalBits += rce->rowTotalBits;//累加RC中占有的bits

    /* do not allow the next frame to enter rateControlStart() until this
     * frame has updated its mid-frame statistics */
    //只有在此运行之后,下一个rateControlStart()才继续运行
    if (m_param->rc.rateControlMode == X265_RC_ABR || m_isVbv)//如果应用ABR或者VBV
    {
        m_startEndOrder.incr();//更新计数

        if (rce->encodeOrder < m_param->frameNumThreads - 1)//刚启动时多更新一次
            m_startEndOrder.incr(); // faked rateControlEnd calls for negative frames
    }
}
/** 函数功能             : 检测是否下溢(前面占用bits过少 防止当前非B帧占用bits过多)rateEstimateQscale中用于下溢检测并重置ABR  rateControlEnd用于关闭前面重置的标志位
/*  调用范围             : 只在rateEstimateQscale和RateControl::rateControlEnd函数中被调用
* \参数 rce              : 当前编码帧的RC参数
* \参数 isFrameDone      : 当前帧是否编码完毕 rateEstimateQscale为false rateControlEnd为true
* \返回                  : null * */
void RateControl::checkAndResetABR(RateControlEntry* rce, bool isFrameDone)
{
    //在rateEstimateQscale中只在非B帧中进入
    //在rateControlEnd中:所有帧类型都可以进入
    //一般都符合规则 在此不会改变什么
    double abrBuffer = 2 * m_rateTolerance * m_bitrate;//ARR最多用的buffer大小

    // Check if current Slice is a scene cut that follows low detailed/blank frames
    if (rce->lastSatd > 4 * rce->movingAvgSum)//如果当前帧的framecost 大于4倍的滑动窗口平均framecost和
    {
        if (!m_isAbrReset && rce->movingAvgSum > 0
            && (m_isPatternPresent || !m_param->bframes)) //如果m_isAbrReset为false并且滑动窗口平均cost大于0 并且 序列无B帧或连续大于bframes个数b帧cost相同 ((m_isPatternPresent || !m_param->bframes))这条很难达到一般不进入
        {
            int pos = X265_MAX(m_sliderPos - m_param->frameNumThreads, 0);//排除并行中的frame
            int64_t shrtTermWantedBits = (int64_t) (X265_MIN(pos, s_slidingWindowFrames) * m_bitrate * m_frameDuration);//当前窗口内应该拥有的bits
            int64_t shrtTermTotalBitsSum = 0; //统计当前窗口占用的实际bits
            // Reset ABR if prev frames are blank to prevent further sudden overflows/ high bit rate spikes.
            for (int i = 0; i < s_slidingWindowFrames ; i++)
                shrtTermTotalBitsSum += m_encodedBitsWindow[i];//统计当前窗口占用的实际bits
            double underflow = (shrtTermTotalBitsSum - shrtTermWantedBits) / abrBuffer;//前面由于B帧占用的bits过少,防止下溢,造成当前编码的非B帧占用的bits过大
            const double epsilon = 0.0001f;//阈值
            if (underflow < epsilon && !isFrameDone)//小于阈值并且在rateEstimateQscale函数进入的
            {
                init(*m_curSlice->m_sps);//重新初始化RC
                m_shortTermCplxSum = rce->lastSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);//从开始统计非B帧cost 前面的丢弃
                m_shortTermCplxCount = 1;//重新计数
                m_isAbrReset = true;//标记ABR重置
                m_lastAbrResetPoc = rce->poc;//记录最后的重置poc位置
            }
        }
        else if (m_isAbrReset && isFrameDone)//rateControlEnd进入 用于清除已经set的flag
        {
            // Clear flag to reset ABR and continue as usual.
            m_isAbrReset = false;
        }
    }
}

void RateControl::hrdFullness(SEIBufferingPeriod *seiBP)
{
    const VUI* vui = &m_curSlice->m_sps->vuiParameters;
    const HRDInfo* hrd = &vui->hrdParameters;
    int num = 90000;
    int denom = hrd->bitRateValue << (hrd->bitRateScale + BR_SHIFT);
    reduceFraction(&num, &denom);
    int64_t cpbState = (int64_t)m_bufferFillFinal;
    int64_t cpbSize = (int64_t)hrd->cpbSizeValue << (hrd->cpbSizeScale + CPB_SHIFT);

    if (cpbState < 0 || cpbState > cpbSize)
    {
        x265_log(m_param, X265_LOG_WARNING, "CPB %s: %.0lf bits in a %.0lf-bit buffer\n",
                 cpbState < 0 ? "underflow" : "overflow", (float)cpbState/denom, (float)cpbSize/denom);
    }

    seiBP->m_initialCpbRemovalDelay = (uint32_t)(num * cpbState + denom) / denom;
    seiBP->m_initialCpbRemovalDelayOffset = (uint32_t)(num * cpbSize + denom) / denom - seiBP->m_initialCpbRemovalDelay;
}
/** 函数功能             : VBV中更新根据当前帧并行情况更新当前RCbuffer
/*  调用范围             : 只在RateControl::rateControlStart函数中被调用
* \参数 enc              : 上层encodr类
* \返回                  : null * */
void RateControl::updateVbvPlan(Encoder* enc)
{
    m_bufferFill = m_bufferFillFinal;//获取当前码率控制中一秒钟占用的最大的buffer
    enc->updateVbvPlan(this);//VBV中更新根据当前帧并行情况更新当前RCbuffer
}
/** 函数功能             : 根据当前帧类型的predictor qscale参数 以及对应下采样的SATD值 预估当前块/帧 占用的bits
/*  调用范围             : 只在rateControlStart、rateEstimateQscale、clipQscale、predictRowsSizeSum函数中被调用
* \参数 p                : rateControlStart:m_pred[m_predType]预测器(forceqp时应)、rateEstimateQscale:m_pred[m_predType]、clipQscale:m_pred[m_predType]预测器、predictRowsSizeSum:rowPred[0]、rowPred[1]
* \参数 q                : rateControlStart:当前量化参数(forceqp时应)、rateEstimateQscale:qscale参数、clipQscale:qscale参数、predictRowsSizeSum:当前的qscale值
* \参数 var              : rateControlStart:当前帧的framecost(forceqp时应)、rateEstimateQscale:当前帧的framecost、clipQscale:当前帧的framecost、predictRowsSizeSum:当前行未编码CTU的SATD和
* \返回                  : 返回预测bits * */
double RateControl::predictSize(Predictor *p, double q, double var)
{
    return (p->coeff * var + p->offset) / (q * p->count);//预测当前帧的bits
}
/** 函数功能             : 如果应用VBV:根据下采样SATD信息修正qscale值  否则 只是简单的clip操作
/*  调用范围             : 只在initPass2()、rateEstimateQscale函数中被调用
* \参数 curFrame         : 当前编码帧
* \参数 rce              : 当前编码帧的相关码率控制信息
* \参数 q                : qscale参数
* \返回                  : 返回修正后的qscale * */
double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce, double q)
{
    // B-frames are not directly subject to VBV,
    // since they are controlled by referenced P-frames' QPs.
    double q0 = q;//存储函数进来时的qscale值
    if (m_isVbv && m_currentSatd > 0 && curFrame)//framecost不为0
    {
        //功能:根据下采样SATD信息修正qscale值
        //    1. 如果应用lookachead 或者 应用cuTree 或者应用scencecut 或者 应用自适应B帧决策
        //           : 根据下采样SATD值预测未来的bits占用数目 从而修正当前的qscale
        //       否则:根据当前bits 修正当前的qscale
        //    2. 根据当前bits以及level定义值 修正qscale
        if (m_param->lookaheadDepth || m_param->rc.cuTree ||
            m_param->scenecutThreshold ||
            (m_param->bFrameAdaptive && m_param->bframes))//应用lookachead 或者 应用cuTree 或者应用scencecut 或则 应用自适应B帧决策
        {
           /* Lookahead VBV: If lookahead is done, raise the quantizer as necessary
            * such that no frames in the lookahead overflow and such that the buffer
            * is in a reasonable state by the end of the lookahead. */
            int loopTerminate = 0;
            /* Avoid an infinite loop. */
            //功能:根据下采样SATD值预测未来的bits占用数目 从而修正当前的qscale
            for (int iterations = 0; iterations < 1000 && loopTerminate != 3; iterations++)
            {
                double frameQ[3];//用于存储IPB帧的加权qscale
                double curBits;//存储当前预测未来某帧占用的bits
                curBits = predictSize(&m_pred[m_predType], q, (double)m_currentSatd);//预测当前占用的bits
                double bufferFillCur = m_bufferFill - curBits;//当前剩余的bitsbuffer
                double targetFill;//存储目标填充
                double totalDuration = m_frameDuration; //当前播放一帧占用的时间(单位秒) 
                frameQ[P_SLICE] = m_sliceType == I_SLICE ? q * m_param->rc.ipFactor : (m_sliceType == B_SLICE ? q / m_param->rc.pbFactor : q);//如果当前是I帧 P帧qscale直接获取(q * m_param->rc.ipFactor)P帧直接获取q B帧 q / m_param->rc.pbFactor
                frameQ[B_SLICE] = frameQ[P_SLICE] * m_param->rc.pbFactor;//B帧 = P帧* m_param->rc.pbFactor
                frameQ[I_SLICE] = frameQ[P_SLICE] / m_param->rc.ipFactor;//I帧 = P帧 / m_param->rc.ipFactor
                /* Loop over the planned future frames. */
                for (int j = 0; bufferFillCur >= 0; j++)//循环遍历未来帧占用的bits 直到遍历一秒钟 或者 buffer剩余为0
                {
                    int type = curFrame->m_lowres.plannedType[j];
                    if (type == X265_TYPE_AUTO || totalDuration >= 1.0)//累加一秒帧数 直接退出
                        break;
                    totalDuration += m_frameDuration;//累加帧时间
                    double wantedFrameSize = m_vbvMaxRate * m_frameDuration;//占用的最大bits
                    if (bufferFillCur + wantedFrameSize <= m_bufferSize)//如果没有溢出
                        bufferFillCur += wantedFrameSize;//累加bits
                    int64_t satd = curFrame->m_lowres.plannedSatd[j] >> (X265_DEPTH - 8);//获取下采样cost值
                    type = IS_X265_TYPE_I(type) ? I_SLICE : IS_X265_TYPE_B(type) ? B_SLICE : P_SLICE;//获取slice类型
                    int predType = getPredictorType(curFrame->m_lowres.plannedType[j], type);//获取predictor标号
                    curBits = predictSize(&m_pred[predType], frameQ[type], (double)satd);//预测当前bits
                    bufferFillCur -= curBits;//剩余bitsbuffer 减去当前预测bits
                }

                /* Try to get the buffer at least 50% filled, but don't set an impossible goal. */
                double finalDur = 1;//存储遍历未来帧的秒数(一般是0.x秒)
                if (m_param->rc.bStrictCbr)//如果严格按照目标码率控制
                {
                    finalDur = x265_clip3(0.4, 1.0, totalDuration);//获取遍历未来帧的秒数(一般是0.x秒)
                }
                targetFill = X265_MIN(m_bufferFill + totalDuration * m_vbvMaxRate * 0.5 , m_bufferSize * (1 - 0.5 * finalDur));//获取目标填充bitsbuffer 不能超过一半buffer
                if (bufferFillCur < targetFill)//遍历剩余buffer 小于目标填充buffer  占用bits过大
                {
                    q *= 1.01;//提高qscale
                    loopTerminate |= 1;//或一
                    continue;
                }
                /* Try to get the buffer not more than 80% filled, but don't set an impossible goal. */
                targetFill = x265_clip3(m_bufferSize * (1 - 0.2 * finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);
                if (m_isCbr && bufferFillCur > targetFill && !m_isSceneTransition)//CBR模式 并且剩余buffer过大
                {
                    q /= 1.01;//降低qscale
                    loopTerminate |= 2;//或2
                    continue;
                }
                break;
            }
            q = X265_MAX(q0 / 2, q);//不能修正超过一半
        }
        else//一般不进入: 
        {
            /* Fallback to old purely-reactive algorithm: no lookahead. */
            if ((m_sliceType == P_SLICE || m_sliceType == B_SLICE ||
                    (m_sliceType == I_SLICE && m_lastNonBPictType == I_SLICE)) &&
                m_bufferFill / m_bufferSize < 0.5)//占用bits过少
            {
                q /= x265_clip3(0.5, 1.0, 2.0 * m_bufferFill / m_bufferSize);//调大qscale 因为除以的是一个小数
            }
            // Now a hard threshold to make sure the frame fits in VBV.
            // This one is mostly for I-frames.
            double bits = predictSize(&m_pred[m_predType], q, (double)m_currentSatd);//预测当前占用的bits

            // For small VBVs, allow the frame to use up the entire VBV.
            double maxFillFactor;
            maxFillFactor = m_bufferSize >= 5 * m_bufferRate ? 2 : 1;//最大因子
            // For single-frame VBVs, request that the frame use up the entire VBV.
            double minFillFactor = m_singleFrameVbv ? 1 : 2;//最小一字

            for (int iterations = 0; iterations < 10; iterations++)
            {
                double qf = 1.0;
                if (bits > m_bufferFill / maxFillFactor)
                    qf = x265_clip3(0.2, 1.0, m_bufferFill / (maxFillFactor * bits));
                q /= qf;
                bits *= qf;
                if (bits < m_bufferRate / minFillFactor)
                    q *= bits * minFillFactor / m_bufferRate;
                bits = predictSize(&m_pred[m_predType], q, (double)m_currentSatd);
            }

            q = X265_MAX(q0, q);//不能超过原来的qscale
        }

        /* Apply MinCR restrictions */
        double pbits = predictSize(&m_pred[m_predType], q, (double)m_currentSatd);//预测当前帧占用的bist
        if (pbits > rce->frameSizeMaximum)//如果bits大于当前level定义值
            q *= pbits / rce->frameSizeMaximum;//调大qscale
        /* To detect frames that are more complex in SATD costs compared to prev window, yet 
         * lookahead vbv reduces its qscale by half its value. Be on safer side and avoid drastic 
         * qscale reductions for frames high in complexity */
        bool mispredCheck = rce->movingAvgSum && m_currentSatd >= rce->movingAvgSum && q <= q0 / 2;
        if (!m_isCbr || (m_isAbr && mispredCheck))
            q = X265_MAX(q0, q);

        if (m_rateFactorMaxIncrement)//最大与配置之间的差值:m_param->rc.rfConstantMax - m_param->rc.rfConstant
        {
            double qpNoVbv = x265_qScale2qp(q0);//未经vbv修正的mv
            double qmax = X265_MIN(MAX_MAX_QPSCALE,x265_qp2qScale(qpNoVbv + m_rateFactorMaxIncrement));//最大qscale
            return x265_clip3(MIN_QPSCALE, qmax, q);//clip 防止越界
        }
    }
    if (m_2pass)//如果当前为2pass 根据最大qscale值和最小qscale 修正当前qscale
    {
        double min = log(MIN_QPSCALE);
        double max = log(MAX_MAX_QPSCALE);
        q = (log(q) - min) / (max - min) - 0.5;
        q = 1.0 / (1.0 + exp(-4 * q));
        q = q*(max - min) + min;
        return exp(q);
    }
    return x265_clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);//返回修正后的qscale
}
/** 函数功能             : 计算当前帧已经编码bits加上未编码预测bits
/*  调用范围             : 只在rowDiagonalVbvRateControl函数中被调用
* \参数 curFrame         : 当前编码帧
* \参数 rce              : 当前帧的码率控制数据
* \参数 qpVbv            : 当前更新后的QP参数
* \参数 encodedBitsSoFar : 用于回存当前帧已经编码的bits
* \返回                  : 返回当前帧已经编码bits加上未编码预测bits * */
double RateControl::predictRowsSizeSum(Frame* curFrame, RateControlEntry* rce, double qpVbv, int32_t& encodedBitsSoFar)
{
    uint32_t rowSatdCostSoFar = 0, totalSatdBits = 0;//分别用于存储:当前已经编码完毕的CTU对应的SATD和、未编码预测bits
    encodedBitsSoFar = 0;//初始为0 累加当前已经编码完毕的bits

    double qScale = x265_qp2qScale(qpVbv);//量化参数转换为qscale
    FrameData& curEncData = *curFrame->m_encData;//获取当前帧的编码数据
    int picType = curEncData.m_slice->m_sliceType;//获取slice类型:B_SLICE,P_SLICE,I_SLICE
    Frame* refFrame = curEncData.m_slice->m_refPicList[0][0];//获取前向参考帧 

    uint32_t maxRows = curEncData.m_slice->m_sps->numCuInHeight;//CTU列数
    uint32_t maxCols = curEncData.m_slice->m_sps->numCuInWidth;//CTU行数

    for (uint32_t row = 0; row < maxRows; row++)//遍历所有CTU行
    {
        encodedBitsSoFar += curEncData.m_rowStat[row].encodedBits;//累加当前已经编码完毕的bits
        rowSatdCostSoFar = curEncData.m_rowStat[row].diagSatd;//累加当前已经编码完毕的CTU对应的SATD
        uint32_t satdCostForPendingCus = curEncData.m_rowStat[row].satdForVbv - rowSatdCostSoFar;//当前CTU行还未编码的SATD和
        satdCostForPendingCus >>= X265_DEPTH - 8;//根据像素位宽修正
        if (satdCostForPendingCus  > 0)//还有未编码的CTU
        {
            double pred_s = predictSize(rce->rowPred[0], qScale, satdCostForPendingCus);//预估当前行未编码CTU占用的bits
            uint32_t refRowSatdCost = 0, refRowBits = 0, intraCostForPendingCus = 0;//refRowSatdCost  用于累加当前行未编码CTU参考帧对应位置的下采样cost, refRowBits 累加当前行未编码CTU参考帧对应位置的bits, intraCostForPendingCus 当前行intraSATD值 减去 当前CTU行已编码CTU的对应下采样计算的intraSATD值 
            double refQScale = 0;//用于存储参考帧的refscale

            if (picType != I_SLICE)//如果当前不是I帧
            {
                FrameData& refEncData = *refFrame->m_encData;//获取参考帧的编码数据
                uint32_t endCuAddr = maxCols * (row + 1);//当前行最后一个CTU
                uint32_t startCuAddr = curEncData.m_rowStat[row].numEncodedCUs;//当前CTU行最后一个编码完毕的CTU位置
                if (startCuAddr)//如果当前行编码完毕一个以上CTU
                {
                    for (uint32_t cuAddr = startCuAddr + 1 ; cuAddr < endCuAddr; cuAddr++)//遍历当前帧所有未编码的CTU
                    {
                        refRowSatdCost += refEncData.m_cuStat[cuAddr].vbvCost;//累加参考帧对应位置的CTU cost 8x8下采样
                        refRowBits += refEncData.m_cuStat[cuAddr].totalBits;  //累加参考帧对应位置的CTU占用的bits
                    }
                }
                else//如果当前行刚编码完毕第一个CTU
                {
                    refRowBits = refEncData.m_rowStat[row].encodedBits;//直接获取参考帧对应行的bits
                    refRowSatdCost = refEncData.m_rowStat[row].satdForVbv;//直接获取参考帧对应行的下采样SATD值
                }

                refRowSatdCost >>= X265_DEPTH - 8;//根据位宽修正
                refQScale = refEncData.m_rowStat[row].diagQpScale;//获取参考帧对应的diagQP scale值
            }

            if (picType == I_SLICE || qScale >= refQScale)//如果当前为I帧或者 当前scale大于参考帧的scale
            {
                if (picType == P_SLICE 
                    && refFrame 
                    && refFrame->m_encData->m_slice->m_sliceType == picType
                    && refQScale > 0
                    && refRowSatdCost > 0)//如果当前帧为P帧 并且 参考帧的帧类型也是P帧 并且 参考帧qscale大于0 
                {
                    if (abs((int32_t)(refRowSatdCost - satdCostForPendingCus)) < (int32_t)satdCostForPendingCus / 2)//参考帧未编码cost 与当前帧未编码cost 差距比较小
                    {
                        double predTotal = refRowBits * satdCostForPendingCus / refRowSatdCost * refQScale / qScale;//根据参考帧的bits 预测当前未编码块的bits
                        totalSatdBits += (int32_t)((pred_s + predTotal) * 0.5);//累加当前行未编码CTU占用的bits 并加上预测bits
                        continue;
                    }
                }
                totalSatdBits += (int32_t)pred_s;//累加当前行未编码CTU占用的bits
            }
            else if (picType == P_SLICE)//如果是P帧
            {
                intraCostForPendingCus = curEncData.m_rowStat[row].intraSatdForVbv - curEncData.m_rowStat[row].diagIntraSatd;//当前行intraSATD值 减去 当前CTU行已编码CTU的对应下采样计算的intraSATD值 
                intraCostForPendingCus >>= X265_DEPTH - 8;//根据像素位宽修正
                /* Our QP is lower than the reference! */
                double pred_intra = predictSize(rce->rowPred[1], qScale, intraCostForPendingCus);//预测当前块的bits
                /* Sum: better to overestimate than underestimate by using only one of the two predictors. */
                totalSatdBits += (int32_t)(pred_intra + pred_s);//累加当前行未编码CTU占用的bit 以及intra估计的bits
            }
            else//如果是B帧
                totalSatdBits += (int32_t)pred_s;//累加当前行未编码CTU占用的bits
        }
    }

    return totalSatdBits + encodedBitsSoFar;//返回当前帧已经编码bits加上未编码预测bits
}
/** 函数功能             : 更新predictor、根据当前编码情况估计当前帧占用的bits、计算最优qp参数值、判断是否需要重新编码
/*  调用范围             : 只在processRowEncoder函数中被调用(只在对角线CTU进入)
* \参数 curFrame         : 当前编码帧
* \参数 row              : 当前CTU行号
* \参数 rce              : 当前帧的码率控制数据
* \参数 qpVbv            : 当前CTU对应的baseQp量化参数(更新qp存入此)
* \返回                  : 0:正常编码 -1:qp跳到过大 需要重新编码 * */
int RateControl::rowDiagonalVbvRateControl(Frame* curFrame, uint32_t row, RateControlEntry* rce, double& qpVbv)
{
    //功能:更新predictor、根据当前编码情况估计当前帧占用的bits、计算最优qp参数值、判断是否需要重新编码
    //     1.根据当前bits 更新predictor
    //     2.设置最大最小QP 以及剩余bits
    //     3.如果当前CTU行不是最后一个CTU行:根据当前编码情况估计当前帧占用的bits  计算最优qp参数值
    //       否则,是最后一个CTU行         :根据当前编码情况估计当前帧占用的bits  
    FrameData& curEncData = *curFrame->m_encData;//获取当前帧数据
    double qScaleVbv = x265_qp2qScale(qpVbv);//将量化参数转换为qscale值
    uint64_t rowSatdCost = curEncData.m_rowStat[row].diagSatd;//获取当前CTU行已编码CTU的对应下采样计算的SATD值
    double encodedBits = curEncData.m_rowStat[row].encodedBits;//获取当前CTU行已经编码CTU占用的bits累加值

    if (row == 1)//如果当前是第二个CTU行(从0计数所有当前是第二个CTU行)
    {
        rowSatdCost += curEncData.m_rowStat[0].diagSatd;//累加 第一行已编码的CTU对应下采样的SATD和
        encodedBits += curEncData.m_rowStat[0].encodedBits;//累加 第一CTU行已经编码CTU占用的bits累加值
    }
    rowSatdCost >>= X265_DEPTH - 8;//修正当前row的SATDcost
    updatePredictor(rce->rowPred[0], qScaleVbv, (double)rowSatdCost, encodedBits);//求predictor中系数的CplxSum和
    if (curEncData.m_slice->m_sliceType == P_SLICE)//如果当前为P帧
    {
        Frame* refFrame = curEncData.m_slice->m_refPicList[0][0];//获取前向参考帧
        if (qpVbv < refFrame->m_encData->m_rowStat[row].diagQp)//如果当前QP参数比参考帧QP参数小
        {
            uint64_t intraRowSatdCost = curEncData.m_rowStat[row].diagIntraSatd;//获取当前CTU行已编码CTU的对应下采样计算的intraSATD值
            if (row == 1)//如果是第二个CTU行
                intraRowSatdCost += curEncData.m_rowStat[0].diagIntraSatd;//累加第一行的intraSATD值
            intraRowSatdCost >>= X265_DEPTH - 8;//修正
            updatePredictor(rce->rowPred[1], qScaleVbv, (double)intraRowSatdCost, encodedBits);//求predictor中系数的CplxSum和
        }
    }

    int canReencodeRow = 1;//表示是否可以重新编码当前行 (默认是)
    /* tweak quality based on difference from predicted size */
    double prevRowQp = qpVbv;//当前CTU对应的baseQp量化参数
    double qpAbsoluteMax = QP_MAX_MAX;//RC控制下的最大QP 69
    double qpAbsoluteMin = QP_MIN;//最小QP 0
    if (m_rateFactorMaxIncrement)//如果当前是CRF模式 并且 有配置最大crf值
        qpAbsoluteMax = X265_MIN(qpAbsoluteMax, rce->qpNoVbv + m_rateFactorMaxIncrement);//更新最大QP

    if (m_rateFactorMaxDecrement)//如果当前是CRF模式 并且 有配置最大crf值
        qpAbsoluteMin = X265_MAX(qpAbsoluteMin, rce->qpNoVbv - m_rateFactorMaxDecrement);//更新最小QP

    double qpMax = X265_MIN(prevRowQp + m_param->rc.qpStep, qpAbsoluteMax);//当前最大浮动到的QP最大值
    double qpMin = X265_MAX(prevRowQp - m_param->rc.qpStep, qpAbsoluteMin);//当前最大浮动到的QP最小值
    double stepSize = 0.5;//QP参数缩减的步长
    double bufferLeftPlanned = rce->bufferFill - rce->frameSizePlanned;//当前buffer除去当前帧预测bits还剩下的buffer大小

    const SPS& sps = *curEncData.m_slice->m_sps;//获取当前的SPS
    double maxFrameError = X265_MAX(0.05, 1.0 / sps.numCuInHeight);//错误因子 CTU行总数的倒数

    if (row < sps.numCuInHeight - 1)//不是最后一个CTU行
    {
        /* More threads means we have to be more cautious in letting ratecontrol use up extra bits. */
        double rcTol = bufferLeftPlanned / m_param->frameNumThreads * m_rateTolerance;//在此存储buffer剩余的空间 考虑到并行操作:除以当前的frame并行个数
        int32_t encodedBitsSoFar = 0;//存储目前当前帧已经编码完毕的CTU占用bits
        double accFrameBits = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);//计算当前帧已经编码bits加上未编码预测bits (理解为一帧预估bits)

        /* * Don't increase the row QPs until a sufficent amount of the bits of
         * the frame have been processed, in case a flat area at the top of the
         * frame was measured inaccurately. */
        if (encodedBitsSoFar < 0.05f * rce->frameSizePlanned)//如果当前已编码bits占用不够计划bits的5%
            qpMax = qpAbsoluteMax = prevRowQp;//由于bits占用过少,后面可以适当增加质量 在此降低最大qP设定

        if (rce->sliceType != I_SLICE || (m_param->rc.bStrictCbr && rce->poc > 0))//如果当前不是I帧 或者采用严格目标码率执行并且不是第一帧
            rcTol *= 0.5;//降低剩余buffer 使当前帧占用更少的bits

        if (!m_isCbr)//如果当前不是CBR模式
            qpMin = X265_MAX(qpMin, rce->qpNoVbv);//最小QP 取当前QP

        double totalBitsNeeded = m_wantedBitsWindow;//获取当前应该需要的bits
        if (m_param->totalFrames)
            totalBitsNeeded = (m_param->totalFrames * m_bitrate) / m_fps;//获取视频需要的总的bits数目
        double abrOvershoot = (accFrameBits + m_totalBits - m_wantedBitsWindow) / totalBitsNeeded;//表示:当前帧超出的bits占总序列bits的比值 (预估当前帧bits + 当前已用bits - 当前应该需要的bits)/(整个视频序列需要的bits)

        //当前bits占用过多 循环增加QP步长
        while (qpVbv < qpMax                                                   //保证小于最大QP设定                                             
               && (((accFrameBits > rce->frameSizePlanned + rcTol) ||          // 保证当前帧的预估bits 小于 计算bits加上剩余buffer大小         
                   (rce->bufferFill - accFrameBits < bufferLeftPlanned * 0.5) ||  //保证只占用剩余buffer 的一半  
                   (accFrameBits > rce->frameSizePlanned && qpVbv < rce->qpNoVbv))//当前估计bits大于实际占用bits
                   && (!m_param->rc.bStrictCbr ? 1 : abrOvershoot > 0.1)))        //占用bits过大
        {
            qpVbv += stepSize;//增加QP
            accFrameBits = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);//计算当前帧已经编码bits加上未编码预测bits (理解为一帧预估bits)
            abrOvershoot = (accFrameBits + m_totalBits - m_wantedBitsWindow) / totalBitsNeeded;//表示:当前帧超出的bits占总序列bits的比值 (预估当前帧bits + 当前已用bits - 当前应该需要的bits)/(整个视频序列需要的bits)
        }

        //当前bits占用过小 减小QP
        while (qpVbv > qpMin                                                  //保证大于最小QP设定
               && (qpVbv > curEncData.m_rowStat[0].diagQp || m_singleFrameVbv) //当前QP过大
               && (((accFrameBits < rce->frameSizePlanned * 0.8f && qpVbv <= prevRowQp)  //当前bits占用过小
                   || accFrameBits < (rce->bufferFill - m_bufferSize + m_bufferRate) * 1.1)
                   && (!m_param->rc.bStrictCbr ? 1 : abrOvershoot < 0)))
        {
            qpVbv -= stepSize;//减小QP
            accFrameBits = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);//计算当前帧已经编码bits加上未编码预测bits (理解为一帧预估bits)
            abrOvershoot = (accFrameBits + m_totalBits - m_wantedBitsWindow) / totalBitsNeeded;//表示:当前帧超出的bits占总序列bits的比值 (预估当前帧bits + 当前已用bits - 当前应该需要的bits)/(整个视频序列需要的bits)
        }

        if (m_param->rc.bStrictCbr && m_param->totalFrames)//如果使其更严格的按照目标码率进行编码 
        {
            double timeDone = (double)(m_framesDone) / m_param->totalFrames;//当前已经进入过RC的帧数的比重
            while (qpVbv < qpMax && (qpVbv < rce->qpNoVbv + (m_param->rc.qpStep * timeDone)) &&
                   (timeDone > 0.75 && abrOvershoot > 0))
            {
                qpVbv += stepSize;//增加QP
                accFrameBits = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);//计算当前帧已经编码bits加上未编码预测bits (理解为一帧预估bits)
                abrOvershoot = (accFrameBits + m_totalBits - m_wantedBitsWindow) / totalBitsNeeded;//表示:当前帧超出的bits占总序列bits的比值 (预估当前帧bits + 当前已用bits - 当前应该需要的bits)/(整个视频序列需要的bits)
            }
            if (qpVbv > curEncData.m_rowStat[0].diagQp &&
                abrOvershoot < -0.1 && timeDone > 0.5 && accFrameBits < rce->frameSizePlanned - rcTol)
            {
                qpVbv -= stepSize;//减小QP
                accFrameBits = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);//计算当前帧已经编码bits加上未编码预测bits (理解为一帧预估bits)
            }
        }

        /* avoid VBV underflow or MinCr violation */
        while ((qpVbv < qpAbsoluteMax)
               && ((rce->bufferFill - accFrameBits < m_bufferRate * maxFrameError) ||
                   (rce->frameSizeMaximum - accFrameBits < rce->frameSizeMaximum * maxFrameError)))//占用bits依然过大
        {
            qpVbv += stepSize;//增加QP
            accFrameBits = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);//计算当前帧已经编码bits加上未编码预测bits (理解为一帧预估bits)
        }

        rce->frameSizeEstimated = accFrameBits;//获取当前帧估计的bits

        /* If the current row was large enough to cause a large QP jump, try re-encoding it. */
        if (qpVbv > qpMax && prevRowQp < qpMax && canReencodeRow)//如果当前QP超过设定QP值  QP波动过大
        {
            /* Bump QP to halfway in between... close enough. */
            qpVbv = x265_clip3(prevRowQp + 1.0f, qpMax, (prevRowQp + qpVbv) * 0.5);//重设QP
            return -1;//跳出 重新编码
        }

        if (m_param->rc.rfConstantMin)//CRF模式 有配置最小CRF值
        {
            if (qpVbv < qpMin && prevRowQp > qpMin && canReencodeRow)
            {
                qpVbv = x265_clip3(qpMin, prevRowQp, (prevRowQp + qpVbv) * 0.5);//重设QP
                return -1;//跳出 重新编码
            }
        }
    }
    else
    {
        int32_t encodedBitsSoFar = 0;//存储目前当前帧已经编码完毕的CTU占用bits
        rce->frameSizeEstimated = predictRowsSizeSum(curFrame, rce, qpVbv, encodedBitsSoFar);//计算当前帧已经编码bits加上未编码预测bits (理解为一帧预估bits)

        /* Last-ditch attempt: if the last row of the frame underflowed the VBV,
         * try again. */
        if ((rce->frameSizeEstimated > (rce->bufferFill - m_bufferRate * maxFrameError) &&
             qpVbv < qpMax && canReencodeRow)) //占用bits过大
        {
            qpVbv = qpMax;//重设qp
            return -1;//跳出 重新编码
        }
    }
    return 0;//正常
}

/* modify the bitrate curve from pass1 for one frame */
/** 函数功能             : 在1pass中只在非B帧应用获取预测的qscale如果有对应zone信息对qcale进行修正、在2pass中对所有帧应用获取预测的qscale如果有对应zone信息对qcale进行修正
/*  调用范围             : 只在initPass2()和rateEstimateQscale(只在非B帧应用)函数中被调用 注意:1pass中只在rateEstimateQscale函数中调用 2pass中只在initPass2()调用
* \参数 rce              : 码流控制数据 在initPass2():m_rce2Pass 在rateEstimateQscale:当前编码帧的RC参数 
* \参数 rateFactor       : 参数因子在initPass2():1.0 rateFactor  在rateEstimateQscale:在非B帧中进入 CRF:m_rateFactorConstant ABR:m_wantedBitsWindow / m_cplxrSum (当前需要的总bits/(已编码bits*qscale/m_lastRceq))
* \返回                  : 返回qscale值 * */
double RateControl::getQScale(RateControlEntry *rce, double rateFactor)
{
    double q;//用于存储qscale

    if (m_param->rc.cuTree)//如果应用cutree
    {
        // Scale and units are obtained from rateNum and rateDenom for videos with fixed frame rates.
        double timescale = (double)m_param->fpsDenom / (2 * m_param->fpsNum);//播放一帧时间的一半
        q = pow(BASE_FRAME_DURATION / CLIP_DURATION(2 * timescale), 1 - m_param->rc.qCompress);//值:(fps/25)^(1 - m_param->rc.qCompress)
    }
    else
        q = pow(rce->blurredComplexity, 1 - m_param->rc.qCompress);// rce->blurredComplexity = (当前非B帧及以前所有非B帧 framecost * (fps/25)的平均和) / (当前帧以前非B帧个数 + 1 )
    // avoid NaN's in the Rceq
    if (rce->coeffBits + rce->mvBits == 0)//很少有此情况 一般不进入 在1pass中此处rce->mvBits = 0 前面已经初始化  2pass中会有具体数据
        q = m_lastQScaleFor[rce->sliceType];//选取默认qscale
    else
    {
        m_lastRceq = q;//获取未经过加权的qscale
        q /= rateFactor;//加权qscale
    }
    
    x265_zone* zone = getZone();//获取zone信息
    if (zone)//如果有zone信息
    {
        if (zone->bForceQp)//固定qp模式
            q = x265_qp2qScale(zone->qp);//获取qp对应的scale
        else
            q /= zone->bitrateFactor;//将当前的scale加权
    }
    return q;//返回qscale
}
/** 函数功能             : 求predictor中系数的CplxSum和
/*  调用范围             : 只在rowDiagonalVbvRateControl和RateControl::updateVbv函数中被调用 
* \参数 p                : 在rowDiagonalVbvRateControl:rowPred[0] 和 rowPred[1] 在RateControl::updateVbv:m_pred[predType] 
* \参数 q                : 在rowDiagonalVbvRateControl:qscale值 在RateControl::updateVbv:rce->qpaRc 
* \参数 var              : 在rowDiagonalVbvRateControl:当前row已编码CTU的对应下采样SATD值的累加和  在RateControl::updateVbv:当前帧的SATD值 framecost 
* \参数 bits             : 在rowDiagonalVbvRateControl:当前row已编码CTU占用bits的累加和 在RateControl::updateVbv:当前帧编码占用的实际bits 
* \返回                  : null * */
void RateControl::updatePredictor(Predictor *p, double q, double var, double bits)
{
    if (var < 10) //小采样cost太小 无须更新
        return;
    const double range = 2;//用于clip的返回
    double old_coeff = p->coeff / p->count;//获取先前predictor中coeff的平均值
    double new_coeff = bits * q / var;//用当前编码的实际bits 估计原先占用的系数为多少
    double new_coeff_clipped = x265_clip3(old_coeff / range, old_coeff * range, new_coeff);//clip操作,使当前coeff与 先前coeff不能差距过大
    double new_offset = bits * q - new_coeff_clipped * var;//求最新offset new coeff与clip coeff之间的差距
    if (new_offset >= 0)//new coeff比clip结果大
        new_coeff = new_coeff_clipped;//更新为clip结果
    else
        new_offset = 0;//new coeff比clip结果小,直接取offset为0
    p->count  *= p->decay;//先前count 乘以0.5
    p->coeff  *= p->decay;//先前coeff 乘以0.5
    p->offset *= p->decay;//先前offset 乘以0.5
    p->count++;//更新当前count个数
    p->coeff  += new_coeff;//更新最新coeff和
    p->offset += new_offset;//更新最新offset和
}
/** 函数功能             : 更新帧predictor并且更新当前最新的VBVbuffer
/*  调用范围             : 只在rateControlEnd函数中被调用
* \参数 bits             : 当前帧编码完毕占用的实际bits数目
* \参数 rce              : 当前帧码率控制数据
* \返回                  : null * */
void RateControl::updateVbv(int64_t bits, RateControlEntry* rce)
{
    int predType = rce->sliceType;//获取当前的slice类型 B_SLICE,P_SLICE,I_SLICE 
    predType = rce->sliceType == B_SLICE && rce->keptAsRef ? 3 : predType;//获取标号 用于predictor
    if (rce->lastSatd >= m_ncu && rce->encodeOrder >= m_lastPredictorReset)
        updatePredictor(&m_pred[predType], x265_qp2qScale(rce->qpaRc), (double)rce->lastSatd, (double)bits);//???
    if (!m_isVbv)//如果不应用VBV
        return;

    m_bufferFillFinal -= bits;//当前预设bufferbits 减去当前帧的bits

    if (m_bufferFillFinal < 0)//如果当前预设buffer不够 输出警告信息
        x265_log(m_param, X265_LOG_WARNING, "poc:%d, VBV underflow (%.0f bits)\n", rce->poc, m_bufferFillFinal);

    m_bufferFillFinal = X265_MAX(m_bufferFillFinal, 0);//clip操作 防止为负数
    m_bufferFillFinal += m_bufferRate;//加上新的一帧最大占用的bits
    m_bufferFillFinal = X265_MIN(m_bufferFillFinal, m_bufferSize);//防止溢出 不能超过最大的bits数目
}

/* After encoding one frame, update rate control state */
/** 函数功能             : ???计算估计当前帧应用的量化参数
/*  调用范围             : 只在FrameEncoder::compressFrame()函数中被调用
* \参数 curFrame         : 当前编码帧
* \参数 bits             : 当前帧编码完毕占用的总bits数目
* \参数 rce              : 当前帧的RC编码参数类
* \返回                  : 只会返回0 表示正常结束 * */
int RateControl::rateControlEnd(Frame* curFrame, int64_t bits, RateControlEntry* rce)
{
    //功能:???
    //     1. 等待触发(使RC按顺序进入)
    //     2. 统计QP信息
    //     3. 更新bits相关数据结构
    //     4. ???
    int orderValue = m_startEndOrder.get();//获取RC线程控制数据
    int endOrdinal = (rce->encodeOrder + m_param->frameNumThreads) * 2 - 1;//执行End触发条件
    while (orderValue < endOrdinal && !m_bTerminated)//循环等待
    {
        /* no more frames are being encoded, so fake the start event if we would
         * have blocked on it. Note that this does not enforce rateControlEnd()
         * ordering during flush, but this has no impact on the outputs */
        if (m_finalFrameCount && orderValue >= 2 * m_finalFrameCount)//在读取全部帧时的执行End触发条件
            break;
        orderValue = m_startEndOrder.waitForChange(orderValue);//一直等待数据改变
    }

    FrameData& curEncData = *curFrame->m_encData;//获取编码帧数据
    int64_t actualBits = bits;//获取当前帧实际编码bits
    Slice *slice = curEncData.m_slice;//获取当前slice

    if (m_param->rc.aqMode || m_isVbv)//如若应用自适应量化 或者应用VBV
    {
        if (m_isVbv)//如果应用VBV
        {
            /* determine avg QP decided by VBV rate control */
            for (uint32_t i = 0; i < slice->m_sps->numCuInHeight; i++)
                curEncData.m_avgQpRc += curEncData.m_rowStat[i].sumQpRc; //累加当前帧所有CTU行的sumQpRc和

            curEncData.m_avgQpRc /= slice->m_sps->numCUsInFrame;//获取平均值
            rce->qpaRc = curEncData.m_avgQpRc;//获取平均QP
        }

        if (m_param->rc.aqMode)//如果应用自适应量化
        {
            /* determine actual avg encoded QP, after AQ/cutree adjustments */
            for (uint32_t i = 0; i < slice->m_sps->numCuInHeight; i++)//遍历CTU行
                curEncData.m_avgQpAq += curEncData.m_rowStat[i].sumQpAq;//累加所有CTU行 CU的mqp

            curEncData.m_avgQpAq /= (slice->m_sps->numCUsInFrame * NUM_4x4_PARTITIONS);//求平均值
        }
        else
            curEncData.m_avgQpAq = curEncData.m_avgQpRc;//获取VBVqp值
    }

    if (m_isAbr)//如果应用ABR
    {
        if (m_param->rc.rateControlMode == X265_RC_ABR && !m_param->rc.bStatRead)//如果应用ABR并且当前不是2pass读情况
            checkAndResetABR(rce, true);//用于关闭前面重置的标志位

        if (m_param->rc.rateControlMode == X265_RC_CRF)//如果应用CRF模式
        {
            if (int(curEncData.m_avgQpRc + 0.5) == slice->m_sliceQp)
                curEncData.m_rateFactor = m_rateFactorConstant;//获取相应值
            else
            {
                /* If vbv changed the frame QP recalculate the rate-factor */
                double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);
                double mbtree_offset = m_param->rc.cuTree ? (1.0 - m_param->rc.qCompress) * 13.5 : 0;
                curEncData.m_rateFactor = pow(baseCplx, 1 - m_qCompress) /
                    x265_qp2qScale(int(curEncData.m_avgQpRc + 0.5) + mbtree_offset);//重新计算
            }
        }
    }

    if (m_isAbr && !m_isAbrReset)//如果应用ABR 并且 没有重置过
    {
        /* amortize part of each I slice over the next several frames, up to
         * keyint-max, to avoid over-compensating for the large I slice cost */
        if (!m_param->rc.bStatWrite && !m_param->rc.bStatRead)//不使用多pass结构
        {
            if (rce->sliceType == I_SLICE)//如果当前为I帧
            {
                /* previous I still had a residual; roll it into the new loan */
                if (m_residualFrames)//如果有剩余分摊帧数
                    bits += m_residualCost * m_residualFrames;//当前bits加上剩余均摊cost
                m_residualFrames = X265_MIN((int)rce->amortizeFrames, m_param->keyframeMax);//确定当前分摊帧数
                m_residualCost = (int)((bits * rce->amortizeFraction) / m_residualFrames);//剩余帧分摊bits占用的平均cost
                bits -= m_residualCost * m_residualFrames;
            }
            else if (m_residualFrames)//非I帧 并且有剩余分摊帧数
            {
                bits += m_residualCost;//当前bits加上平均均摊cost
                m_residualFrames--;//均摊帧数减一
            }
        }
        if (rce->sliceType != B_SLICE)//如果是非B帧
        {
            /* The factor 1.5 is to tune up the actual bits, otherwise the cplxrSum is scaled too low
                * to improve short term compensation for next frame. */
            m_cplxrSum += (bits * x265_qp2qScale(rce->qpaRc) / rce->qRceq) - (rce->rowCplxrSum);//获取一帧的bits*qscale值
        }
        else
        {
            /* Depends on the fact that B-frame's QP is an offset from the following P-frame's.
                * Not perfectly accurate with B-refs, but good enough. */
            m_cplxrSum += (bits * x265_qp2qScale(rce->qpaRc) / (rce->qRceq * fabs(m_param->rc.pbFactor))) - (rce->rowCplxrSum);//获取一帧的bits*qscale值
        }
        m_wantedBitsWindow += m_frameDuration * m_bitrate;//累加当前需要的bits
        m_totalBits += bits - rce->rowTotalBits;//累加当前RC占用的bits(扣除前面累加的rowcount行占用的bits)
        m_encodedBits += actualBits;//累加实际占用bits
        int pos = m_sliderPos - m_param->frameNumThreads;//获取滑动窗口下标
        if (pos >= 0)
            m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;//滑动窗口获取实际bits
    }

    if (m_2pass)//如果当前处在2pass ????
    {
        m_expectedBitsSum += qScale2bits(rce, x265_qp2qScale(rce->newQp));
        m_totalBits += bits - rce->rowTotalBits;
    }

    if (m_isVbv)//应用VBV
    {
        updateVbv(actualBits, rce);//更新帧predictor并且更新当前最新的VBVbuffer

        if (m_param->bEmitHRDSEI)//????
        {
            const VUI *vui = &curEncData.m_slice->m_sps->vuiParameters;
            const HRDInfo *hrd = &vui->hrdParameters;
            const TimingInfo *time = &vui->timingInfo;
            if (!curFrame->m_poc)
            {
                // first access unit initializes the HRD
                rce->hrdTiming->cpbInitialAT = 0;
                rce->hrdTiming->cpbRemovalTime = m_nominalRemovalTime = (double)m_bufPeriodSEI.m_initialCpbRemovalDelay / 90000;
            }
            else
            {
                rce->hrdTiming->cpbRemovalTime = m_nominalRemovalTime + (double)rce->picTimingSEI->m_auCpbRemovalDelay * time->numUnitsInTick / time->timeScale;
                double cpbEarliestAT = rce->hrdTiming->cpbRemovalTime - (double)m_bufPeriodSEI.m_initialCpbRemovalDelay / 90000;
                if (!curFrame->m_lowres.bKeyframe)
                    cpbEarliestAT -= (double)m_bufPeriodSEI.m_initialCpbRemovalDelayOffset / 90000;

                rce->hrdTiming->cpbInitialAT = hrd->cbrFlag ? m_prevCpbFinalAT : X265_MAX(m_prevCpbFinalAT, cpbEarliestAT);
            }

            uint32_t cpbsizeUnscale = hrd->cpbSizeValue << (hrd->cpbSizeScale + CPB_SHIFT);
            rce->hrdTiming->cpbFinalAT = m_prevCpbFinalAT = rce->hrdTiming->cpbInitialAT + actualBits / cpbsizeUnscale;
            rce->hrdTiming->dpbOutputTime = (double)rce->picTimingSEI->m_picDpbOutputDelay * time->numUnitsInTick / time->timeScale + rce->hrdTiming->cpbRemovalTime;
        }
    }
    rce->isActive = false;//设置当前帧已经确定好QP值
    // Allow rateControlStart of next frame only when rateControlEnd of previous frame is over
    m_startEndOrder.incr();//控制RC 线程数据 加加
    return 0;//返回0 表示正常结束
}

/* called to write out the rate control frame stats info in multipass encodes */
int RateControl::writeRateControlFrameStats(Frame* curFrame, RateControlEntry* rce)
{
    FrameData& curEncData = *curFrame->m_encData;
    char cType = rce->sliceType == I_SLICE ? (rce->poc > 0 && m_param->bOpenGOP ? 'i' : 'I')
        : rce->sliceType == P_SLICE ? 'P'
        : IS_REFERENCED(curFrame) ? 'B' : 'b';
    if (fprintf(m_statFileOut,
                "in:%d out:%d type:%c q:%.2f q-aq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f ;\n",
                rce->poc, rce->encodeOrder,
                cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq,
                curFrame->m_encData->m_frameStats.coeffBits,
                curFrame->m_encData->m_frameStats.mvBits,
                curFrame->m_encData->m_frameStats.miscBits,
                curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu,
                curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu,
                curFrame->m_encData->m_frameStats.percent8x8Skip  * m_ncu) < 0)
        goto writeFailure;
    /* Don't re-write the data in multi-pass mode. */
    if (m_param->rc.cuTree && IS_REFERENCED(curFrame) && !m_param->rc.bStatRead)
    {
        uint8_t sliceType = (uint8_t)rce->sliceType;
        for (int i = 0; i < m_ncu; i++)
                m_cuTreeStats.qpBuffer[0][i] = (uint16_t)(curFrame->m_lowres.qpCuTreeOffset[i] * 256.0);
        if (fwrite(&sliceType, 1, 1, m_cutreeStatFileOut) < 1)
            goto writeFailure;
        if (fwrite(m_cuTreeStats.qpBuffer[0], sizeof(uint16_t), m_ncu, m_cutreeStatFileOut) < (size_t)m_ncu)
            goto writeFailure;
    }
    return 0;

    writeFailure:
    x265_log(m_param, X265_LOG_ERROR, "RatecontrolEnd: stats file write failure\n");
    return 1;
}
#if defined(_MSC_VER)
#pragma warning(disable: 4996) // POSIX function names are just fine, thank you
#endif

/* called when the encoder is flushing, and thus the final frame count is
 * unambiguously known */
void RateControl::setFinalFrameCount(int count)
{
    m_finalFrameCount = count;
    /* unblock waiting threads */
    m_startEndOrder.poke();
}

/* called when the encoder is closing, and no more frames will be output.
 * all blocked functions must finish so the frame encoder threads can be
 * closed */
void RateControl::terminate()
{
    m_bTerminated = true;
    /* unblock waiting threads */
    m_startEndOrder.poke();
}

void RateControl::destroy()
{
    const char *fileName = m_param->rc.statFileName;
    if (!fileName)
        fileName = s_defaultStatFileName;

    if (m_statFileOut)
    {
        fclose(m_statFileOut);
        char *tmpFileName = strcatFilename(fileName, ".temp");
        int bError = 1;
        if (tmpFileName)
        {
           unlink(fileName);
           bError = rename(tmpFileName, fileName);
        }
        if (bError)
        {
            x265_log(m_param, X265_LOG_ERROR, "failed to rename output stats file to \"%s\"\n",
                     fileName);
        }
        X265_FREE(tmpFileName);
    }

    if (m_cutreeStatFileOut)
    {
        fclose(m_cutreeStatFileOut);
        char *tmpFileName = strcatFilename(fileName, ".cutree.temp");
        char *newFileName = strcatFilename(fileName, ".cutree");
        int bError = 1;
        if (tmpFileName && newFileName)
        {
           unlink(newFileName);
           bError = rename(tmpFileName, newFileName);
        }
        if (bError)
        {
            x265_log(m_param, X265_LOG_ERROR, "failed to rename cutree output stats file to \"%s\"\n",
                     newFileName);
        }
        X265_FREE(tmpFileName);
        X265_FREE(newFileName);
    }

    if (m_cutreeStatFileIn)
        fclose(m_cutreeStatFileIn);

    X265_FREE(m_rce2Pass);
    for (int i = 0; i < 2; i++)
        X265_FREE(m_cuTreeStats.qpBuffer[i]);
    
    X265_FREE(m_param->rc.zones);
}


 

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
V5.4.4完整版/2020年5月 STM32电机控制软件开发套件(MCSDK)- 完整源代码 主要变化: Version 5.4.4 is mostly a bug fix release of X-Cube-MCSDK v5.4.3. It also introduces some new feature. ◾Added Support for PFC on STM32F3. This support is added as an example for the STEVAL-CTM010V1 Dual motor demo board. ◾Atollic TrueSTUDIO & SW4STM32 Deprecation. Atollic TrueSTUDIO and SW4STM32 IDEs are no longer actively developed and ST's strategy is to replace them with STM32CubeIDE. Recent STM32 series like STM32G4 devices for instance, are already not supported by all these IDEs. In a near future release of the Motor Control SDK, support for these IDE will be dropped and it will not be possible anymore to generate a project for them from the Workbench. ◾Introduced a workaround for the issue with injected ADC conversions that exists on STM32G4xx Cut 2.2 devices. See the dedicated section below for more details. ◾Reintroduced the correct ST Motor Profiler version (the same as release 5.4.1 of the SDK). The Motor Profiler delivered with MCSDK 5.4.2 and 5.4.3 was incomplete. ◾Fixed an issue with the faulty setting of the maximum application current for the second drive in dual drive configurations ◾Fixed an issue with Position Control configurations using an absolute position encoder (with Z signal). ◾Fixed another issue with Position Control where a division by 0 was possible. ◾Fixed a bootstrap capacitor charge issue in ICS configurations ◾Fixed a SW Error that could occur during the offset measurement loop ◾Fixed a code generation issue resulting in a compilation error when enabling open loop. ◾Fixed a STM32H7 example compilation issue - missing files have been added. ◾Fixed a generation issue for some STM32G0 and STM32F0 devices where TIM2 does not exist but was referenced in the code anyway. This resulted in a compilation failure. ◾Fixed an issue with STM32F1 HD devices in single shunt configurations ◾In the workbench, the maximum PWM frequency can now be set as high as 500 KHz. ◾Fixed an issue due to the limited RShunt resolution. Now, values such as 0.00025 Ω are accepted. ◾Fixed an issue with NVIC configuration for IHM34V2 inverter boards. ◾Fixed a Workbench issue that resulted in a wrong pin assignment when creating new projects based on the NUCLEO-G431RB control board. See section Pin assignment with NUCLEO-G431RB for more details. ◾Fixed an issue that resulted in incorrect overcurrent settings with some power boards. See section Over current settings correction for some power boards ◾Enable users to select DAC channel 2 with STM32L452

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值