[x265-commits] [x265] rc: initial work towards VBV rate control
Xun at videolan.org
Xun at videolan.org
Sun Dec 1 21:33:48 CET 2013
details: http://hg.videolan.org/x265/rev/8a90153de720
branches:
changeset: 5399:8a90153de720
user: Xun Xu, PPLive Corporation<xunxu at pptv.com>
date: Fri Nov 08 18:41:21 2013 +0800
description:
rc: initial work towards VBV rate control
1. add parameter "vbv-maxrate" "vbv-bufsize" "vbv-init" into cmd line
2. implement vbv methods, this patch doesn't use lookahead data
future work,
1. vbv-lookahead
2. CU level ratecontrol
diffstat:
source/common/common.cpp | 6 +
source/encoder/encoder.cpp | 20 +++-
source/encoder/encoder.h | 2 +
source/encoder/frameencoder.cpp | 1 +
source/encoder/ratecontrol.cpp | 246 +++++++++++++++++++++++++++++++++++++++-
source/encoder/ratecontrol.h | 39 ++++++-
source/x265.cpp | 6 +
source/x265.h | 3 +
8 files changed, 317 insertions(+), 6 deletions(-)
diffs (truncated from 539 to 300 lines):
diff -r 343d9ba487b2 -r 8a90153de720 source/common/common.cpp
--- a/source/common/common.cpp Sun Dec 01 14:16:46 2013 -0600
+++ b/source/common/common.cpp Fri Nov 08 18:41:21 2013 +0800
@@ -205,6 +205,9 @@ void x265_param_default(x265_param *para
param->rdPenalty = 0;
/* Rate control options */
+ param->rc.vbvMaxBitrate = 0;
+ param->rc.vbvBufferSize = 0;
+ param->rc.vbvBufferInit = 0.9;
param->rc.rfConstant = 28;
param->rc.bitrate = 0;
param->rc.rateTolerance = 1.0;
@@ -718,6 +721,9 @@ int x265_param_parse(x265_param *p, cons
OPT("hash") p->decodedPictureHashSEI = atoi(value);
OPT("aq-mode") p->rc.aqMode = atoi(value);
OPT("aq-strength") p->rc.aqStrength = atof(value);
+ OPT("vbv-maxrate") p->rc.vbvMaxBitrate = atoi(value);
+ OPT("vbv-bufsize") p->rc.vbvBufferSize = atoi(value);
+ OPT("vbv-init") p->rc.vbvBufferInit = atof(value);
OPT("crf")
{
p->rc.rfConstant = atof(value);
diff -r 343d9ba487b2 -r 8a90153de720 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp Sun Dec 01 14:16:46 2013 -0600
+++ b/source/encoder/encoder.cpp Fri Nov 08 18:41:21 2013 +0800
@@ -190,6 +190,24 @@ int Encoder::getStreamHeaders(NALUnitEBS
return m_frameEncoder->getStreamHeaders(nalunits);
}
+void Encoder::updateVbvPlan(RateControl* rc)
+{
+ int encIdx, curIdx;
+ curIdx = (m_curEncoder + param.frameNumThreads - 1) % param.frameNumThreads;
+ encIdx = (curIdx + 1) % param.frameNumThreads;
+ while (encIdx != curIdx)
+ {
+ FrameEncoder *encoder = &m_frameEncoder[encIdx];
+ double bits;
+ bits = encoder->m_rce.frameSizePlanned;
+ rc->bufferFill -= bits;
+ rc->bufferFill = X265_MAX(rc->bufferFill, 0);
+ rc->bufferFill += encoder->m_rce.bufferRate;
+ rc->bufferFill = X265_MIN(rc->bufferFill, rc->bufferSize);
+ encIdx = (encIdx + 1) % param.frameNumThreads;
+ }
+}
+
/**
\param flush force encoder to encode a frame
\param pic_in input original YUV picture or NULL
@@ -313,7 +331,7 @@ int Encoder::encode(bool flush, const x2
m_dpb->prepareEncode(fenc);
// set slice QP
- m_rateControl->rateControlStart(fenc, m_lookahead, &(curEncoder->m_rce));
+ m_rateControl->rateControlStart(fenc, m_lookahead, &(curEncoder->m_rce),this);
// Allow FrameEncoder::compressFrame() to start in a worker thread
curEncoder->m_enable.trigger();
diff -r 343d9ba487b2 -r 8a90153de720 source/encoder/encoder.h
--- a/source/encoder/encoder.h Sun Dec 01 14:16:46 2013 -0600
+++ b/source/encoder/encoder.h Fri Nov 08 18:41:21 2013 +0800
@@ -134,6 +134,8 @@ public:
int extractNalData(NALUnitEBSP **nalunits);
+ void updateVbvPlan(RateControl* rc);
+
protected:
uint64_t calculateHashAndPSNR(TComPic* pic, NALUnitEBSP **nalunits); // Returns total number of bits for encoded pic
diff -r 343d9ba487b2 -r 8a90153de720 source/encoder/frameencoder.cpp
--- a/source/encoder/frameencoder.cpp Sun Dec 01 14:16:46 2013 -0600
+++ b/source/encoder/frameencoder.cpp Fri Nov 08 18:41:21 2013 +0800
@@ -57,6 +57,7 @@ FrameEncoder::FrameEncoder()
m_nalCount = 0;
m_totalTime = 0;
+ memset(&m_rce, 0, sizeof(RateControlEntry));
}
void FrameEncoder::setThreadPool(ThreadPool *p)
diff -r 343d9ba487b2 -r 8a90153de720 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Sun Dec 01 14:16:46 2013 -0600
+++ b/source/encoder/ratecontrol.cpp Fri Nov 08 18:41:21 2013 +0800
@@ -3,6 +3,7 @@
*
* Authors: Sumalatha Polureddy <sumalatha at multicorewareinc.com>
* Aarthi Priya Thirumalai <aarthi at multicorewareinc.com>
+ * Xun Xu, PPLive Corporation <xunxu at 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
@@ -23,9 +24,10 @@
*****************************************************************************/
#include "TLibCommon/TComPic.h"
+#include "TLibEncoder/TEncCfg.h"
+#include "encoder.h"
#include "slicetype.h"
#include "ratecontrol.h"
-#include "TLibEncoder/TEncCfg.h"
#include <math.h>
using namespace x265;
@@ -146,7 +148,7 @@ RateControl::RateControl(TEncCfg * _cfg)
cfg->param.rc.bitrate = 0;
double baseCplx = ncu * (cfg->param.bframes ? 120 : 80);
- double mbtree_offset = 0; //added later
+ double mbtree_offset = 0; // added later
rateFactorConstant = pow(baseCplx, 1 - cfg->param.rc.qCompress) /
qp2qScale(cfg->param.rc.rfConstant + mbtree_offset + QP_BD_OFFSET);
}
@@ -165,6 +167,77 @@ RateControl::RateControl(TEncCfg * _cfg)
framesDone = 0;
lastNonBPictType = I_SLICE;
+ // vbv initialization
+ cfg->param.rc.vbvBufferSize = Clip3(0, 2000000, cfg->param.rc.vbvBufferSize);
+ cfg->param.rc.vbvMaxBitrate = Clip3(0, 2000000, cfg->param.rc.vbvMaxBitrate);
+ cfg->param.rc.vbvBufferInit = Clip3(0.0, 2000000.0, cfg->param.rc.vbvBufferInit);
+
+ if (cfg->param.rc.vbvBufferSize)
+ {
+ if (cfg->param.rc.rateControlMode == X265_RC_CQP)
+ {
+ x265_log(&cfg->param, X265_LOG_WARNING, "VBV is incompatible with constant QP, ignored.\n" );
+ cfg->param.rc.vbvBufferSize = 0;
+ cfg->param.rc.vbvMaxBitrate = 0;
+ }
+ else if (cfg->param.rc.vbvMaxBitrate == 0)
+ {
+ if (cfg->param.rc.rateControlMode == X265_RC_ABR)
+ {
+ x265_log(&cfg->param, X265_LOG_WARNING, "VBV maxrate unspecified, assuming CBR\n");
+ cfg->param.rc.vbvMaxBitrate = cfg->param.rc.bitrate;
+ }
+ else
+ {
+ x265_log(&cfg->param, X265_LOG_WARNING, "VBV bufsize set but maxrate unspecified, ignored\n");
+ cfg->param.rc.vbvBufferSize = 0;
+ }
+ }
+ else if (cfg->param.rc.vbvMaxBitrate < cfg->param.rc.bitrate &&
+ cfg->param.rc.rateControlMode == X265_RC_ABR)
+ {
+ x265_log(&cfg->param, X265_LOG_WARNING, "max bitrate less than average bitrate, assuming CBR\n");
+ cfg->param.rc.bitrate = cfg->param.rc.vbvMaxBitrate;
+ }
+ }
+ else if (cfg->param.rc.vbvMaxBitrate)
+ {
+ x265_log(&cfg->param, X265_LOG_WARNING, "VBV maxrate specified, but no bufsize, ignored\n" );
+ cfg->param.rc.vbvMaxBitrate = 0;
+ }
+
+ isVbv = cfg->param.rc.vbvMaxBitrate > 0 && cfg->param.rc.vbvBufferSize > 0;
+ fps = cfg->param.frameRate;
+ if (isVbv)
+ {
+ if (cfg->param.rc.vbvBufferSize < (int)(cfg->param.rc.vbvMaxBitrate/fps))
+ {
+ cfg->param.rc.vbvBufferSize = (int)(cfg->param.rc.vbvMaxBitrate/fps);
+ x265_log(&cfg->param, X265_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n",
+ cfg->param.rc.vbvBufferSize);
+ }
+ int vbvBufferSize = cfg->param.rc.vbvBufferSize * 1000;
+ int vbvMaxBitrate = cfg->param.rc.vbvMaxBitrate * 1000;
+
+ bufferRate = vbvMaxBitrate / fps;
+ vbvMaxRate = vbvMaxBitrate;
+ bufferSize = vbvBufferSize;
+ singleFrameVbv = bufferRate * 1.1 > bufferSize;
+ bufferFillFinal = bufferSize*cfg->param.rc.vbvBufferInit;
+ }
+
+ for(int i = 0; i < 5; i++ )
+ {
+ pred[i].coeff = 2.0;
+ pred[i].count = 1.0;
+ pred[i].decay = 0.5;
+ pred[i].offset = 0.0;
+ }
+ predBfromP = pred[0];
+ bframes = cfg->param.bframes;
+ bframeBits = 0;
+ leadingNoBSatd = 0;
+
if (cfg->param.rc.rateControlMode == X265_RC_ABR)
{
/* Adjust the first frame in order to stabilize the quality level compared to the rest */
@@ -206,12 +279,24 @@ RateControl::RateControl(TEncCfg * _cfg)
lstep = pow(2, cfg->param.rc.qpStep / 6.0);
}
-void RateControl::rateControlStart(TComPic* pic, Lookahead *l, RateControlEntry* rce)
+void RateControl::rateControlStart(TComPic* pic, Lookahead *l, RateControlEntry* rce, Encoder* enc)
{
curSlice = pic->getSlice();
sliceType = curSlice->getSliceType();
rce->sliceType = sliceType;
+ if (sliceType == B_SLICE)
+ rce->bframes = bframes;
+ else
+ bframes = pic->m_lowres.leadingBframes;
+
+ rce->bLastMiniGopBFrame = pic->m_lowres.bLastMiniGopBFrame;
+ rce->bufferRate = bufferRate;
+ rce->poc = curSlice->getPOC();
+
+ if (isVbv)
+ updateVbvPlan(enc);
+
if (isAbr) //ABR,CRF
{
lastSatd = l->getEstimatedPictureCost(pic);
@@ -220,6 +305,7 @@ void RateControl::rateControlStart(TComP
rce->qpaRc = q;
/* copy value of lastRceq into thread local rce struct *to be used in RateControlEnd() */
rce->qRceq = lastRceq;
+ rce->lastSatd = lastSatd;
accumPQpUpdate();
}
else //CQP
@@ -281,6 +367,8 @@ double RateControl::rateEstimateQscale(R
else
q += pbOffset;
+ rce->frameSizePlanned = predictSize(&predBfromP, qp2qScale(q), leadingNoBSatd);
+
return qp2qScale(q);
}
else
@@ -371,15 +459,108 @@ double RateControl::rateEstimateQscale(R
double lmin1 = lmin[sliceType];
double lmax1 = lmax[sliceType];
q = Clip3(lmin1, lmax1, q);
+
+ q = clipQscale(q);
+
lastQScaleFor[sliceType] = q;
if (curSlice->getPOC() == 0)
lastQScaleFor[P_SLICE] = q * fabs(cfg->param.rc.ipFactor);
+ rce->frameSizePlanned = predictSize(&pred[sliceType], q, lastSatd);
+
return q;
}
}
+
+void RateControl::updateVbvPlan(Encoder* enc)
+{
+ bufferFill = bufferFillFinal;
+ enc->updateVbvPlan(this);
+}
+
+
+double RateControl::predictSize( Predictor *p, double q, double var)
+{
+ return (p->coeff*var + p->offset) / (q*p->count);
+}
+
+double RateControl::clipQscale(double q)
+{
+ double lmin1 = lmin[sliceType];
+ double lmax1 = lmax[sliceType];
+ double q0 = q;
+
+ // B-frames are not directly subject to VBV,
+ // since they are controlled by the P-frames' QPs.
+ if (isVbv && lastSatd > 0)
+ {
+ //if (lookahead){} //for lookahead
+ //else
+ {
+ if ((sliceType == P_SLICE ||
+ (sliceType == I_SLICE && lastNonBPictType == I_SLICE)) &&
+ bufferFill/bufferSize < 0.5)
+ {
+ q /= Clip3(0.5, 1.0, 2.0*bufferFill/bufferSize);
+ }
+
+ // Now a hard threshold to make sure the frame fits in VBV.
+ // This one is mostly for I-frames.
+ double bits = predictSize(&pred[sliceType], q, lastSatd);
+
+ // For small VBVs, allow the frame to use up the entire VBV.
+ double maxFillFactor;
+ maxFillFactor = bufferSize >= 5*bufferRate ? 2 : 1;
+ // For single-frame VBVs, request that the frame use up the entire VBV.
+ double minFillFactor = singleFrameVbv ? 1 : 2;
+
+
+ for( int iterations = 0; iterations < 10; iterations++ )
+ {
More information about the x265-commits
mailing list