注:问号以及未注释部分 会在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.
*****************************************************************************/
#ifndef X265_RATECONTROL_H
#define X265_RATECONTROL_H
#include "common.h"
#include "sei.h"
namespace X265_NS {
// encoder namespace
class Encoder;
class Frame;
class SEIBufferingPeriod;
struct SPS;
#define BASE_FRAME_DURATION 0.04 //播放一帧需要多少秒 基准为25fps
/* Arbitrary limitations as a sanity check. */
#define MAX_FRAME_DURATION 1.00 //播放一帧需要最长时间
#define MIN_FRAME_DURATION 0.01 //播放一帧需要最短时间
#define MIN_AMORTIZE_FRAME 10 //最小分摊帧数 (用于码率控制)
#define MIN_AMORTIZE_FRACTION 0.2 //最小分摊分数 (用于码率控制)
#define CLIP_DURATION(f) x265_clip3(MIN_FRAME_DURATION, MAX_FRAME_DURATION, f)
struct Predictor //用途:估计预测bits 存在于:RateControlEntry类(rowPreds[3][2]、*rowPred[2])和RateControl类(m_pred[4])中 updatePredictor中更新
{
//预测当前帧的bits (p->coeff * var + p->offset) / (q * p->count) q 一般为qscale var 当前帧的framecost (可以是行的 也可以是8x8块的) 主要是 SATD与bits的映射关系
double coeff;//当前未经量化的系数 累加和 (new_coeff = bits * q / var bits:实际编码bits q为qscale var为satd值 p->coeff *= p->decay p->coeff += new_coeff)
double count;//当前个数的累加和 sum*0.5+1
double decay;//固定值 0.5 用于求CplxSum: sum*0.5 + x 更新coeff、count、offset时应用
double offset;//当前偏移量的累加和
};
struct HRDTiming
{
double cpbInitialAT;
double cpbFinalAT;
double dpbOutputTime;
double cpbRemovalTime;
};
struct RateControlEntry
{
Predictor rowPreds[3][2];// 第一维 slice类型:B_SLICE,P_SLICE,I_SLICE 第二维:所有帧 和P帧 遇到场景切换帧后全部初始化为(0.25,1.0,0.5,0.0)
Predictor* rowPred[2];//指针 指向上面rowPreds对应帧类型的位置 所有帧 和P帧
int64_t lastSatd; //当前帧的SATD值 framecost 在rateControlStart中获取值 /* Contains the picture cost of the previous frame, required for resetAbr and VBV */
int64_t leadingNoBSatd;//暂无任何作用 存储当前RC的最新非B帧的SATD值rateControlStart更新
int64_t rowTotalBits; //只在frameEncoder中应用:在processRowEncoder获取当前帧rowcount以前CTU编码占用的bits 紧接着在rateControlUpdateStats作适当修正 在m_rce2Pass中:不用 /* update cplxrsum and totalbits at the end of 2 rows */
double blurredComplexity; //预估当前非B帧的计算复杂度 在rateControlStart中获取值 m_shortTermCplxSum / m_shortTermCplxCount(当前非B帧及以前所有非B帧 framecost * (fps/25)的平均和) / (当前帧以前非B帧个数 + 1 ) 在m_rce2Pass中:?????
double qpaRc;//在rateControlStart中 获取预估qp参数值(未四舍五入) 在rateControlEnd 如果应用VBV 获取当前帧所有QP的平均值(多加了一次估计的QP值) 如果没有应用VBV 依然为在rateControlStart中 获取预估qp参数值(未四舍五入)
double qpAq;
double qRceq;//在rateControlStart中 获取数据对应未加权的qscale = m_lastRceq m_lastRceq:在getQScale中获取数据对应未加权的qscale 初始化为1 应用cutree一般全序列是一个值:如果应用cutree 值:(fps/25)^(1 - m_param->rc.qCompress) 否则:是个变值 q = pow(rce->blurredComplexity, 1 - m_param->rc.qCompress)
double frameSizePlanned; //根据估计qscale值预估的当前帧RC需要的bits 在rateEstimateQscale函数中获取数据 2pass???/* frame Size decided by RateCotrol before encoding the frame */
double bufferRate; //只在frameEncoder中应用: 平均每帧最大的bits占用数目 在m_rce2Pass中:不用
//计算方式:假设当前序列为 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
double movingAvgSum; //滑动窗口平均framecost和 在rateEstimateQscale中获取数据
double rowCplxrSum; //只在frameEncoder中应用:通过具体bits计算一帧rowcountCTU行前的cost值 在rateControlUpdateStats中获取数据:非B帧:rce->rowCplxrSum = rce->rowTotalBits * x265_qp2qScale(rce->qpaRc) / rce->qRceq; B帧:rce->rowCplxrSum = rce->rowTotalBits * x265_qp2qScale(rce->qpaRc) / (rce->qRceq * fabs(m_param->rc.pbFactor)); 在m_rce2Pass中:不用
double qpNoVbv; //在rowDiagonalVbvRateControl应用 没经过VBV修正的估计量化参数 在rateControlStart和rateEstimateQscale中获取数据
double bufferFill; //在rateControlStart VBV中获取扣除并行帧影响的RCbuffer
double frameDuration;
double clippedDuration;
double frameSizeEstimated; //用途:估计当前正在编码帧的占用bits 在rateEstimateQscale中获取当前帧的预估bits(rce->frameSizePlanned 在rowDiagonalVbvRateControl 根据当前已经编码的CTU重新更新当前帧预估的bits/* hold frameSize, updated from cu level vbv rc */
double frameSizeMaximum; //当前level下当前帧占用的最大bits (x265自定义)rateControlStart中设置 (第一帧与其它帧分别设置) /* max frame Size according to minCR restrictions and level of the video */
int sliceType; //在frameEncoder中:表示当前编码帧的帧类型:B_SLICE,P_SLICE,I_SLICE
int bframes; //无任何作用
int poc; //在frameEncoder中: 当前poc RateControl::rateControlStart中赋值
int encodeOrder; //在frameEncoder中: 当前的编码顺序(从0开始计数)
bool bLastMiniGopBFrame;//只在frameEncoder中应用: 标记当前帧是否为当前GOP的最后一个B帧 在m_rce2Pass中:不用
bool isActive; //只在frameEncoder中应用:rateControlStart中置为ture rateControlEnd中置为false 在m_rce2Pass中:不用
double amortizeFrames; // 码率控制bits分摊帧数 init初始化为为75 遇到I帧 /=1.1 随着编码分摊帧数越来越小 在非多pass结构应用 只I帧应用
double amortizeFraction; // 码率控制bits分摊分数 init初始化为为0.85 遇到I帧 /=1.1 随着编码分数越来越小 在非多pass结构应用 只I帧应用
/* Required in 2-pass rate control */
uint64_t expectedBits; /* total expected bits up to the current frame (current one excluded) */
double iCuCount;
double pCuCount;
double skipCuCount;
double expectedVbv;
double qScale;
double newQScale;//用途:???在rateEstimateQscale函数中获取预估qscale 2pass???
double newQp; //存储经过rateControlStart估计后的当前帧的量化参数
int mvBits;//用途??? 在rateEstimateQscale中对非B帧初始化为0 在m_rce2Pass中:???
int miscBits;
int coeffBits;//用途??? 在rateEstimateQscale中并且只是非B帧获取当前帧的framecost值 在m_rce2Pass中:???
bool keptAsRef;//当前是否可作参考帧 在frameEncoder中:1pass中在rateControlStart设置 2pass中???? 在m_rce2Pass中:???
SEIPictureTiming *picTimingSEI;
HRDTiming *hrdTiming;
};
class RateControl// 用于码流控制 只在encoder类中存在
{
public:
x265_param* m_param; //配置参数信息
Slice* m_curSlice; //当前编码的slice信息 /* all info about the current frame */
SliceType m_sliceType; //当前编码的slice类型:B_SLICE,P_SLICE,I_SLICE /* Current frame type */
int m_ncu; //1/2下采样帧中的8x8块个数 /* number of CUs in a frame */
int m_qp; //在rateControlStart中获取四舍五入的预估qp参数 ???/* updated qp for current frame */
bool m_isAbr;//是否应用ABR 当前不是CQP并且不是多pass 读的时候
bool m_isVbv;//是否应用VBV m_param->rc.vbvMaxBitrate > 0 && m_param->rc.vbvBufferSize > 0
bool m_isCbr;//CBR模式 如果最大码率设定小于目标码率 m_isCbr = m_param->rc.rateControlMode == X265_RC_ABR && m_isVbv && !m_2pass && m_param->rc.vbvMaxBitrate <= m_param->rc.bitrate;
bool m_singleFrameVbv;//初始化为0 如果平均每帧最大的bits占用数目*1.1 大于一秒的bits buffer大小置为1
bool m_isAbrReset;//用途 标记当前是否对RC进行重置 在rateEstimateQscale函数会根据是否下溢(前面占用bits过少 防止当前非B帧占用bits过多)对其置为true 在rateControlEnd中置为false 初始化为false
int m_lastAbrResetPoc;//记录最后的重置poc位置 该位置一定是非B帧 初始化为-1
double m_rateTolerance;//码率buffer因子,默认为1.0 如果打开bStrictCbr 为0.7 abrBuffer = 2 * m_rateTolerance * m_bitrate
double m_frameDuration; //当前播放一帧占用的时间(单位秒) /* current frame duration in seconds */
double m_bitrate; //当前配置的目标码率 (单位b) 配置的时候是kb 这里等于m_param->rc.bitrate * 1000
double m_rateFactorConstant;//用途:一般分辨率越大 此值越大 一般在0.0x之间 只在CRF模式中应用 在RC类中初始化
double m_bufferSize; //一秒的bits buffer大小 (vbv一秒占用的最大bits数目)
double m_bufferFillFinal; //当前码率控制中一秒钟占用的最大的buffer 一帧编码完毕后 减去当前帧占用的bits 加上预设一帧占用的最大bits 初始化为 一秒bits占用的配置buffer * m_param->rc.vbvBufferInit (VBV应用: 最大bits*0.9) /* real buffer as of the last finished frame */
double m_bufferFill; //VBV中应用,获取m_bufferFillFinal???/* planned buffer, if all in-progress frames hit their bit budget */
double m_bufferRate; //平均每帧最大的bits占用数目 vbvMaxBitrate / m_fps; /* # of bits added to buffer_fill after each frame */
double m_vbvMaxRate; //一秒钟占用的最大bits/* in kbps */
double m_rateFactorMaxIncrement;//最大与配置之间的差值:m_param->rc.rfConstantMax - m_param->rc.rfConstant; /* Don't allow RF above (CRF + this value). */
double m_rateFactorMaxDecrement;//配置与最小之间的差值:m_rateFactorMaxDecrement = m_param->rc.rfConstant - m_param->rc.rfConstantMin; /* don't allow RF below (this value). */
Predictor m_pred[4]; //用途:用于预测当前帧占用的bits(predictSize函数) 数据更新:在一帧编码完毕后RateControl::updateVbv中更新维度:标号 0:不可参考b帧 1: P帧 2:I帧 3:可参考B帧 全部初始化为1.0 1.0 0.5 0.0 如果 m_param->rc.qCompress >= 0.8 .coeff初始为(0.5 0.75 1.0 0.5) 否则 .coeff初始为(0.75 1.0 1.0 0.75) 在RateControl::init和RateControl::rateControlStart函数中调用initFramePredictors()被初始化/* Slice predictors to preidct bits for each Slice type - I,P,Bref and B */
int64_t m_leadingNoBSatd; //存储码流控制中最新的非B帧的SATD值 在rateControlStart函数中更新 初始化为0
int m_predType; //????/* Type of slice predictors to be used - depends on the slice type */
double m_ipOffset; //用途:I帧与P帧的qp参数关系 P = Iqp + m_ipOffset 默认 2.9125608156077503
double m_pbOffset;//用途:P帧与B帧的qp参数关系 B = Pqp + m_pbOffset 默认 2.2710694220159415
int64_t m_bframeBits;
int64_t m_currentSatd; //当前的framecost 如果需要参考帧,取参考帧列表中各自第一帧当做参考帧的framecost 在rateControlStart中获取值
int m_qpConstant[3];//维度 P_SLICE B_SLICE I_SLICE 分别存储对应的固定QP值 2pass:???
int m_lastNonBPictType;//存储码流控制中最新的非B帧类型 在rateControlStart函数中更新 初始化为I帧
int m_framesDone; //当前进入已经进入RC的帧数 初始化为0 ABR reset后也初始化为0 rateControlStart后累计1 /* # of frames passed through RateCotrol already */
double m_cplxrSum; //用途用于估计QP值(在RC中一直累加) 后续更新:在rateControlUpdateStats函数中累加 rce->rowCplxrSum 在rateControlEnd中更新为一帧的bits*qscale(已扣除rowcount行累加的部分)值 初始化用于估计第一帧I帧的QP参数 0.01 * pow(700000, m_qCompress) * pow(m_ncu, 0.5) * tuneCplxFactor 其中tuneCplxFactor如果应用720p以上并且应用cutree为2.0 其它为1.0/* sum of bits*qscale/rceq */
double m_wantedBitsWindow; //表示当前应该需要的bits数目(从重置一直累加到当前) 初始化:m_bitrate * m_frameDuration 在RateControl::rateControlEnd 累加:m_wantedBitsWindow += m_frameDuration * m_bitrate /* target bitrate * window */
double m_accumPQp; //用途:???初始化为 0.01*24(ABR模式)在rateControlStart函数中更新 m_accumPQp*0.95+m_qp /* for determining I-frame quant */
double m_accumPNorm;//用途:???初始化为0.01在rateControlStart函数中更新 m_accumPNorm
double m_lastQScaleFor[3]; //(rateEstimateQscale 只获取对应帧类型最近的qscale值[3] getDiffLimitedQScale??? init2pass???)??? 存储对应帧类型最近的qscale值[3] 为B_SLICE,P_SLICE,I_SLICE 全部初始化为:ABR: QP=24 对应的 qscale(3.4) CRF:m_param->rc.rfConstant对应的qscale /* last qscale for a specific pict type, used for max_diff & ipb factor stuff */
double m_lstep;//在类初构造时初始化 为pow(2, m_param->rc.qpStep / 6.0)
/*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
**/
double m_shortTermCplxSum;// 当前非B帧及以前所有非B帧 framecost * (fps/25)的平均和 初始化为0 rateEstimateQscale获取数据
double m_shortTermCplxCount;//当前帧以前非B帧个数 + 1 初始化为0 rateEstimateQscale获取数据
double m_lastRceq;//在getQScale中获取数据对应未加权的qscale 初始化为1 应用cutree一般全序列是一个值:如果应用cutree 值:(fps/25)^(1 - m_param->rc.qCompress) 否则:是个变值 q = pow(rce->blurredComplexity, 1 - m_param->rc.qCompress)
double m_qCompress; //用途:????如果应用cutree 设置强度系数为1 否则从配置参数中获取 m_qCompress = m_param->rc.qCompress
int64_t m_totalBits; //在RC中一直累加占用的所有已编码bits 在rateControlUpdateStats中累加当前row行以前的编码bits 在rateControlEnd中累加一帧的bits(扣除前面rowcount行的占用bits)init中初始化为0/* total bits used for already encoded frames (after ammortization) */
int64_t m_encodedBits; //当前已经编码帧占用的bits init初始化为0 rateControlEnd中更新/* bits used for encoded frames (without ammortization) */
double m_fps;
int64_t m_satdCostWindow[50];//用途:存储当前滑动窗口每帧的下采样framecost 全部初始化为0 (根据滑动窗口大小(x265定为20))
int64_t m_encodedBitsWindow[50];//用途:存储当前滑动窗口每帧占用的实际bits(在rateControlEnd中获取数据) 如果不对要全部修改注释 全部初始化为0 (根据滑动窗口大小(x265定为20))
int m_sliderPos;//等于编码顺序(从1计数) 用于指示滑动窗口的下标 初始化为0
/* To detect a pattern of low detailed static frames in single pass ABR using satdcosts */
int64_t m_lastBsliceSatdCost;//最近的非参考B帧的framcost 初始化为0 rateControlStart中计算
int m_numBframesInPattern;//连续b帧(非参考)framecost相同的个数 初始化为0 rateControlStart中计算 一般很少有这种情况
bool m_isPatternPresent;//如果当前非B帧前又大于bframes个数个连续framecost相同 置为true 在b帧framecost不同与前一个b帧cost时置为false 初始化为false rateControlStart中计算
bool m_isSceneTransition;//如果当前帧是场景切换帧 标记为true 如果 初始化为false
//设x为场景切换帧
//IBBBPBBBxBBBPBBBP 对应m_isSceneTransition值
//00000000111111110
int m_lastPredictorReset;//记录Predictor重置的编码位置(编码顺序) rce->encodeOrder 初始化为0
/* a common variable on which rateControlStart, rateControlEnd and rateControUpdateStats waits to
* sync the calls to these functions. For example
* -F2:
* rceStart 10
* rceUpdate 10
* rceEnd 9
* rceStart 11
* rceUpdate 11
* rceEnd 10
* rceStart 12
* rceUpdate 12
* rceEnd 11 */
ThreadSafeInteger m_startEndOrder;//控制RC互相等待的数据(全局控制) 初始化为0
/*与三个函数有关系rateControlStart、rateControlUpdateStats、rateControlEnd、setFinalFrameCount
rateControlStart:一直是蓄势待发的状态 一旦不满足条件即执行 :m_startEndOrder < rce->encodeOrder * 2 && !m_bTerminated (此函数用于估计当前帧的qP值)
rateControlUpdateStats: 会对m_startEndOrder更新两次 一次必须累加1 一次满足条件:if (rce->encodeOrder < m_param->frameNumThreads - 1) m_startEndOrder累加1 (帧编码大约一半时进入)
rateControlEnd:帧编码结束 (在编码完毕时是蓄势待发状态) 一旦不满足条件即执行 :(m_startEndOrder < (rce->encodeOrder + m_param->frameNumThreads) * 2 - 1 && !m_bTerminated) 满足条件立即执行:(m_finalFrameCount && orderValue >= 2 * m_finalFrameCount)
执行完毕时会对m_startEndOrder累加1
setFinalFrameCount:m_finalFrameCount 一直为0 再读完帧的时候 设置为编码帧数
约定符号:
start 表示 rateControlStart可以执行
UP0 表示 rateControlUpdateStats更新m_startEndOrder第一次
UP1 表示 rateControlUpdateStats更新m_startEndOrder第二次(不满足不更新) if (rce->encodeOrder < m_param->frameNumThreads - 1)
end0 表示 rateControlEnd 满足条件执行
end1 表示 rateControlEnd 满足第二条件 立即执行 (m_finalFrameCount && m_startEndOrder >= 2 * m_finalFrameCount) 需要改进!
END 表示end执行m_startEndOrder累加1
(x/y/z/g) x: 当前poc y 当前编码序号 z start执行需要满足的最小序号 g end执行需要满足的最小序号
以4framethread编码10帧为例
(0/0/0/7) (4/1/2/9) (2/2/4/11) (1/3/6/13) (3/4/8/15) (8/5/10/17) (6/6/12/19) (5/7/14/21) (7/8/16/23) (9/9/18/25)
m_startEndOrder 0: start
m_startEndOrder 1: UP0
m_startEndOrder 2: UP1 ---触发-->start
m_startEndOrder 3: UP0
m_startEndOrder 4: UP1---触发--->start
m_startEndOrder 5: UP0
m_startEndOrder 6: UP1 ---触发--->start
m_startEndOrder 7: end0<-------------------触发------------------UP0
m_startEndOrder 8: END --------------------------触发--------------------------->start
m_startEndOrder 9: end0<----------------------触发---------------------UP0
m_startEndOrder10: END ----------------------------触发----------------------------->start
m_startEndOrder11: end0<----------------------触发---------------------UP0
m_startEndOrder12: END ----------------------------触发------------------------------->start
m_startEndOrder13: end0<-----------------------触发-----------------------UP0
m_startEndOrder14: END -----------------------------触发-------------------------------->start
m_startEndOrder15: end0<-----------------------触发-----------------------UP0
m_startEndOrder16: END -----------------------------触发-------------------------------->start
m_startEndOrder17: end0<-----------------------触发-----------------------UP0
m_startEndOrder18: END -----------------------------触发-------------------------------->start
m_startEndOrder19: end0<-----------------------触发-----------------------UP0
m_startEndOrder20: END
外环控制 setFinalFrameCount 设定m_finalFrameCount值 并将所有RC打开 (当前再也没有其它帧)
m_startEndOrder20: END(通过setFinalFrameCount) 这里到底触发哪个,很容易出问题 也可能会先触发后面的 潜在威胁 (一般先进行前面的)
m_startEndOrder20: end1
m_startEndOrder21: END(没有触发只说 潜在的危险,只是系统默认顺序执行)
m_startEndOrder22: END(没有触发只说 潜在的危险,只是系统默认顺序执行,这是是在20的情况下进入的)
m_startEndOrder23: END(没有触发只说 潜在的危险,只是系统默认顺序执行,这是是在22的情况下进入的)
**/
int m_finalFrameCount; /* set when encoder begins flushing */
bool m_bTerminated; //是否码流控制结束 初始化为false 结束置为ture/* set true when encoder is closing */
/* hrd stuff */
SEIBufferingPeriod m_bufPeriodSEI;
double m_nominalRemovalTime;
double m_prevCpbFinalAT;
/* 2 pass */
bool m_2pass; //当前是否是2pass 是为true 否为false
int m_numEntries;
FILE* m_statFileOut;
FILE* m_cutreeStatFileOut;
FILE* m_cutreeStatFileIn;
double m_lastAccumPNorm;
double m_expectedBitsSum; /* sum of qscale2bits after rceq, ratefactor, and overflow, only includes finished frames */
int64_t m_predictedBits;//????在rateControlStart VBV模式下一开始获取已编码bits数目
RateControlEntry* m_rce2Pass;
struct
{
uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree quantizer data. */
int qpBufPos; /* In order to handle pyramid reordering, QP buffer acts as a stack.
* This value is the current position (0 or 1). */
} m_cuTreeStats;
RateControl(x265_param& p);
bool init(const SPS& sps);
void initHRD(SPS& sps);
void setFinalFrameCount(int count);
void terminate(); /* un-block all waiting functions so encoder may close */
void destroy();
// to be called for each curFrame to process RateControl and set QP
int rateControlStart(Frame* curFrame, RateControlEntry* rce, Encoder* enc);
/** 函数功能 : 当前帧编码一半时即时更新数据,便于后续帧快速估计 更新m_startEndOrder计数
/* 调用范围 : 只在processRowEncoder函数中被调用
* \参数 rce : 当前帧RC相关数据
* \返回 : null * */
void rateControlUpdateStats(RateControlEntry* rce);
int rateControlEnd(Frame* curFrame, int64_t bits, RateControlEntry* rce);
/** 函数功能 : 更新predictor、根据当前编码情况估计当前帧占用的bits、计算最优qp参数值、判断是否需要重新编码
/* 调用范围 : 只在processRowEncoder函数中被调用(只在对角线CTU进入)
* \参数 curFrame : 当前编码帧
* \参数 row : 当前CTU行号
* \参数 rce : 当前帧的码率控制数据
* \参数 qpVbv : 当前CTU对应的baseQp量化参数
* \返回 : 0:正常编码 -1:qp跳到过大 需要重新编码 * */
int rowDiagonalVbvRateControl(Frame* curFrame, uint32_t row, RateControlEntry* rce, double& qpVbv);
int rateControlSliceType(int frameNum);
bool cuTreeReadFor2Pass(Frame* curFrame);
void hrdFullness(SEIBufferingPeriod* sei);
int writeRateControlFrameStats(Frame* curFrame, RateControlEntry* rce);
protected:
static const int s_slidingWindowFrames;
static const char* s_defaultStatFileName;
double m_amortizeFraction;//码率控制bits分摊分数 init初始化为为0.85 遇到I帧 /=1.1 随着编码分数越来越小 在非多pass结构应用 只I帧应用
int m_amortizeFrames;//码率控制bits分摊帧数 init初始化为为75 遇到I帧 /=1.1 随着编码分摊帧数越来越小 在非多pass结构应用 只I帧应用
int m_residualFrames;//类构造时初始化为0 分摊帧数随着编码越来越小 只在rateControlEnd中应用
int m_partialResidualFrames;//码率控制bits分摊帧数 类初始化时为0 在非多pass结构应用 遇到I帧 更新为X265_MIN((int)rce->amortizeFrames, m_param->keyframeMax); 遇到非I帧 m_partialResidualFrames--;
int m_residualCost;//init初始化为0 剩余帧分摊bits占用的平均cost 只在rateControlEnd中应用
int m_partialResidualCost;//I帧的剩余cost init初始化为0 在非多pass结构应用 遇到I帧获取数据 在 rateControlUpdateStats中获取数据 m_partialResidualCost = (int)((rce->rowTotalBits * rce->amortizeFraction) / m_partialResidualFrames);
/** 函数功能 : 获取当前帧所在的zone
/* 调用范围 : 只在rateControlStart(只在CQP模式应用)、getDiffLimitedQScale和RateControl::getQScale函数中被调用
* \返回 : 返回当前帧所在的zone * */
x265_zone* getZone();
/** 函数功能 : 在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
* \返回 : 返回qscale值 * */
double getQScale(RateControlEntry *rce, double rateFactor);
double rateEstimateQscale(Frame* pic, RateControlEntry *rce); // main logic for calculating QP based on ABR
/** 函数功能 : 根据当前已编码bits数目修正预估的qscale值并计算overflow值(qScale *= overflow)
/* 调用范围 : 只在rateEstimateQscale函数中被调用
* \参数 qScale : qscale参数
* \返回 : 返回修正后的qscale值 * */
double tuneAbrQScaleFromFeedback(double qScale);
/** 函数功能 : 累加m_accumPQp*0.95+m_qp和m_accumPNorm*0.95+1
/* 调用范围 : 只在rateControlStart函数中被调用
* \返回 : null * */
void accumPQpUpdate();
int getPredictorType(int lowresSliceType, int sliceType);
/** 函数功能 : 更新帧predictor并且更新当前最新的VBVbuffer
/* 调用范围 : 只在rateControlEnd函数中被调用
* \参数 bits : 当前帧编码完毕占用的实际bits数目
* \参数 rce : 当前帧码率控制数据
* \返回 : null * */
void updateVbv(int64_t bits, RateControlEntry* rce);
/** 函数功能 : 求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 updatePredictor(Predictor *p, double q, double var, double bits);
/** 函数功能 : 如果应用VBV:根据下采样SATD信息修正qscale值 否则 只是简单的clip操作
/* 调用范围 : 只在initPass2()、rateEstimateQscale函数中被调用
* \参数 curFrame : 当前编码帧
* \参数 rce : 当前编码帧的相关码率控制信息
* \参数 q : qscale参数
* \返回 : 返回修正后的qscale * */
double clipQscale(Frame* pic, RateControlEntry* rce, double q);
/** 函数功能 : VBV中更新根据当前帧并行情况更新当前RCbuffer
/* 调用范围 : 只在RateControl::rateControlStart函数中被调用
* \参数 enc : 上层encodr类
* \返回 : null * */
void updateVbvPlan(Encoder* enc);
/** 函数功能 : 根据当前帧类型的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 predictSize(Predictor *p, double q, double var);
/** 函数功能 : 检测是否下溢(前面占用bits过少 防止当前非B帧占用bits过多)rateEstimateQscale中用于下溢检测并重置ABR rateControlEnd用于关闭前面重置的标志位
/* 调用范围 : 只在rateEstimateQscale和RateControl::rateControlEnd函数中被调用
* \参数 rce : 当前编码帧的RC参数
* \参数 isFrameDone : 当前帧是否编码完毕 rateEstimateQscale为false rateControlEnd为true
* \返回 : null * */
void checkAndResetABR(RateControlEntry* rce, bool isFrameDone);
/** 函数功能 : 计算当前帧已经编码bits加上未编码预测bits
/* 调用范围 : 只在rowDiagonalVbvRateControl函数中被调用
* \参数 curFrame : 当前编码帧
* \参数 rce : 当前帧的码率控制数据
* \参数 qpVbv : 当前更新后的QP参数
* \参数 encodedBitsSoFar : 用于回存当前帧已经编码的bits
* \返回 : 返回当前帧已经编码bits加上未编码预测bits * */
double predictRowsSizeSum(Frame* pic, RateControlEntry* rce, double qpm, int32_t& encodedBits);
bool initPass2();
/** 函数功能 : 初始化Predictor
/* 调用范围 : 只在RateControl::init和RateControl::rateControlStart函数中被调用
* \返回 : null * */
void initFramePredictors();
double getDiffLimitedQScale(RateControlEntry *rce, double q);
double countExpectedBits();
bool vbv2Pass(uint64_t allAvailableBits);
bool findUnderflow(double *fills, int *t0, int *t1, int over);
bool fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax);
};
}
#endif // ifndef X265_RATECONTROL_H