[x265] [PATCH] rc: add CRF ratecontrol
Steve Borho
steve at borho.org
Fri Nov 1 19:09:58 CET 2013
# HG changeset patch
# User idxa<idxa at sina.com>
# Date 1383123587 -28800
# Wed Oct 30 16:59:47 2013 +0800
# Node ID 8585af48e92116fc1ce71c36661e91816739f1ae
# Parent 0d79e31728a463b676b3ed790cfcc063c6cd4055
rc: add CRF ratecontrol
1. add a parameter of "--crf" to the command line
2. modify the running branches of rateControlStart, using "if(isAbr)" instead of
"switch (cfg->param.rc.rateControlMode)", for the logic of classifying the
combination of multiple ratecontrol methods is very complex, it is not only
based on rateControlMode, so porting x264's way looks feasible.
3. add crf method into x265
diff -r 0d79e31728a4 -r 8585af48e921 source/common/common.cpp
--- a/source/common/common.cpp Fri Nov 01 13:05:34 2013 -0500
+++ b/source/common/common.cpp Wed Oct 30 16:59:47 2013 +0800
@@ -185,6 +185,7 @@
param->saoLcuBasedOptimization = 1;
/* Rate control options */
+ param->rc.rfConstant = 28;
param->rc.bitrate = 0;
param->rc.rateTolerance = 1.0;
param->rc.qCompress = 0.6;
@@ -569,7 +570,7 @@
x265_log(param, X265_LOG_INFO, "Rate Control : CQP-%d\n", param->rc.qp);
break;
case X265_RC_CRF:
- x265_log(param, X265_LOG_INFO, "Rate Control : CRF-%d\n", param->rc.rateFactor);
+ x265_log(param, X265_LOG_INFO, "Rate Control : CRF-%f\n", param->rc.rfConstant);
break;
}
@@ -710,10 +711,21 @@
p->maxNumReferences = atoi(value);
OPT("weightp")
p->bEnableWeightedPred = bvalue;
+ OPT("crf")
+ {
+ p->rc.rfConstant = atof(value);
+ p->rc.rateControlMode = X265_RC_CRF;
+ }
OPT("bitrate")
+ {
p->rc.bitrate = atoi(value);
+ p->rc.rateControlMode = X265_RC_ABR;
+ }
OPT("qp")
+ {
p->rc.qp = atoi(value);
+ p->rc.rateControlMode = X265_RC_CQP;
+ }
OPT("cbqpoffs")
p->cbQpOffset = atoi(value);
OPT("crqpoffs")
diff -r 0d79e31728a4 -r 8585af48e921 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp Fri Nov 01 13:05:34 2013 -0500
+++ b/source/encoder/encoder.cpp Wed Oct 30 16:59:47 2013 +0800
@@ -997,11 +997,6 @@
{
_param->bEnableAMP = false;
}
- // if a bitrate is specified, chose ABR. Else default to CQP
- if (_param->rc.bitrate)
- {
- _param->rc.rateControlMode = X265_RC_ABR;
- }
if (!(_param->bEnableRDOQ && _param->bEnableTransformSkip))
{
diff -r 0d79e31728a4 -r 8585af48e921 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Fri Nov 01 13:05:34 2013 -0500
+++ b/source/encoder/ratecontrol.cpp Wed Oct 30 16:59:47 2013 +0800
@@ -115,9 +115,25 @@
RateControl::RateControl(TEncCfg * _cfg)
{
this->cfg = _cfg;
+ ncu = (int)((cfg->param.sourceHeight * cfg->param.sourceWidth) / pow((int)16, 2.0));
+
+ // validate for cfg->param.rc, maybe it is need to add a function like x265_parameters_valiate()
+ cfg->param.rc.rfConstant = Clip3((double)-QP_BD_OFFSET, (double)51, cfg->param.rc.rfConstant);
+ if (cfg->param.rc.rateControlMode == X265_RC_CRF)
+ {
+ cfg->param.rc.qp = (int)cfg->param.rc.rfConstant + QP_BD_OFFSET;
+ cfg->param.rc.bitrate = 0;
+
+ double baseCplx = ncu * (cfg->param.bframes ? 120 : 80);
+ double mbtree_offset = 0;//added later
+ rateFactorConstant = pow(baseCplx, 1 - cfg->param.rc.qCompress) /
+ qp2qScale(cfg->param.rc.rfConstant + mbtree_offset + QP_BD_OFFSET);
+ }
+
+ isAbr = cfg->param.rc.rateControlMode != X265_RC_CQP; // later add 2pass option
+
bitrate = cfg->param.rc.bitrate * 1000;
frameDuration = 1.0 / cfg->param.frameRate;
- ncu = (int)((cfg->param.sourceHeight * cfg->param.sourceWidth) / pow((int)16, 2.0));
lastNonBPictType = -1;
baseQp = cfg->param.rc.qp;
qp = baseQp;
@@ -126,6 +142,7 @@
shortTermCplxSum = 0;
shortTermCplxCount = 0;
framesDone = 0;
+ lastNonBPictType = I_SLICE;
if (cfg->param.rc.rateControlMode == X265_RC_ABR)
{
@@ -137,8 +154,17 @@
/* estimated ratio that produces a reasonable QP for the first I-frame */
cplxrSum = .01 * pow(7.0e5, cfg->param.rc.qCompress) * pow(ncu, 0.5);
wantedBitsWindow = bitrate * frameDuration;
- lastNonBPictType = I_SLICE;
}
+ else if (cfg->param.rc.rateControlMode == X265_RC_CRF)
+ {
+#define ABR_INIT_QP ((int)cfg->param.rc.rfConstant + QP_BD_OFFSET)
+ accumPNorm = .01;
+ accumPQp = ABR_INIT_QP * accumPNorm;
+ /* estimated ratio that produces a reasonable QP for the first I-frame */
+ cplxrSum = .01 * pow(7.0e5, cfg->param.rc.qCompress) * pow(ncu, 0.5);
+ wantedBitsWindow = bitrate * frameDuration;
+ }
+
ipOffset = 6.0 * X265_LOG2(cfg->param.rc.ipFactor);
pbOffset = 6.0 * X265_LOG2(cfg->param.rc.pbFactor);
for (int i = 0; i < 3; i++)
@@ -164,9 +190,8 @@
curSlice = pic->getSlice();
sliceType = curSlice->getSliceType();
rce->sliceType = sliceType;
- switch (cfg->param.rc.rateControlMode)
- {
- case X265_RC_ABR:
+
+ if (isAbr) //ABR,CRF
{
lastSatd = l->getEstimatedPictureCost(pic);
double q = qScale2qp(rateEstimateQscale(rce));
@@ -175,17 +200,10 @@
/* copy value of lastRceq into thread local rce struct *to be used in RateControlEnd() */
rce->qRceq = lastRceq;
accumPQpUpdate();
- break;
}
-
- case X265_RC_CQP:
+ else //CQP
+ {
qp = qpConstant[sliceType];
- break;
-
- case X265_RC_CRF:
- default:
- assert(!"unimplemented");
- break;
}
if (sliceType != B_SLICE)
@@ -269,20 +287,28 @@
rce->blurredComplexity = shortTermCplxSum / shortTermCplxCount;
rce->mvBits = 0;
rce->sliceType = sliceType;
- q = getQScale(rce, wantedBitsWindow / cplxrSum);
- /* ABR code can potentially be counterproductive in CBR, so just don't bother.
- * Don't run it if the frame complexity is zero either. */
- if (lastSatd)
+ if (cfg->param.rc.rateControlMode == X265_RC_CRF)
{
- /* use framesDone instead of POC as poc count is not serial with bframes enabled */
- double timeDone = (double)(framesDone - cfg->param.frameNumThreads + 1) / cfg->param.frameRate;
- wantedBits = timeDone * bitrate;
- if (wantedBits > 0 && totalBits > 0)
+ q = getQScale(rce, rateFactorConstant);
+ }
+ else
+ {
+ q = getQScale(rce, wantedBitsWindow / cplxrSum);
+
+ /* ABR code can potentially be counterproductive in CBR, so just don't bother.
+ * Don't run it if the frame complexity is zero either. */
+ if (lastSatd)
{
- abrBuffer *= X265_MAX(1, sqrt(timeDone));
- overflow = Clip3(.5, 2.0, 1.0 + (totalBits - wantedBits) / abrBuffer);
- q *= overflow;
+ /* use framesDone instead of POC as poc count is not serial with bframes enabled */
+ double timeDone = (double)(framesDone - cfg->param.frameNumThreads + 1) / cfg->param.frameRate;
+ wantedBits = timeDone * bitrate;
+ if (wantedBits > 0 && totalBits > 0)
+ {
+ abrBuffer *= X265_MAX(1, sqrt(timeDone));
+ overflow = Clip3(.5, 2.0, 1.0 + (totalBits - wantedBits) / abrBuffer);
+ q *= overflow;
+ }
}
}
@@ -292,7 +318,7 @@
q = qp2qScale(accumPQp / accumPNorm);
q /= fabs(cfg->param.rc.ipFactor);
}
- else if (framesDone>0)
+ else if (framesDone > 0)
{
if (cfg->param.rc.rateControlMode != X265_RC_CRF)
{
@@ -350,7 +376,7 @@
/* After encoding one frame, update rate control state */
int RateControl::rateControlEnd(int64_t bits, RateControlEntry* rce)
{
- if (cfg->param.rc.rateControlMode == X265_RC_ABR)
+ if (isAbr)
{
if (rce->sliceType != B_SLICE)
/* The factor 1.5 is to tune up the actual bits, otherwise the cplxrSum is scaled too low
diff -r 0d79e31728a4 -r 8585af48e921 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h Fri Nov 01 13:05:34 2013 -0500
+++ b/source/encoder/ratecontrol.h Wed Oct 30 16:59:47 2013 +0800
@@ -55,6 +55,9 @@
int baseQp; /* CQP base QP */
double frameDuration; /* current frame duration in seconds */
double bitrate;
+ double rateFactorConstant;
+ bool isAbr;
+
int lastSatd;
int qpConstant[3];
double cplxrSum; /* sum of bits*qscale/rceq */
diff -r 0d79e31728a4 -r 8585af48e921 source/x265.cpp
--- a/source/x265.cpp Fri Nov 01 13:05:34 2013 -0500
+++ b/source/x265.cpp Wed Oct 30 16:59:47 2013 +0800
@@ -117,6 +117,7 @@
{ "ref", required_argument, NULL, 0 },
{ "no-weightp", no_argument, NULL, 0 },
{ "weightp", no_argument, NULL, 'w' },
+ { "crf", required_argument, NULL, 0 },
{ "bitrate", required_argument, NULL, 0 },
{ "qp", required_argument, NULL, 'q' },
{ "cbqpoffs", required_argument, NULL, 0 },
@@ -307,6 +308,7 @@
H0("-w/--[no-]weightp Enable weighted prediction in P slices. Default %s\n", OPT(param->bEnableWeightedPred));
H0("\nQP, rate control and rate distortion options:\n");
H0(" --bitrate Target bitrate (kbps), implies ABR. Default %d\n", param->rc.bitrate);
+ H0(" --crf Quality-based VBR (0-51). Default %f\n", param->rc.rfConstant);
H0("-q/--qp Base QP for CQP mode. Default %d\n", param->rc.qp);
H0(" --cbqpoffs Chroma Cb QP Offset. Default %d\n", param->cbQpOffset);
H0(" --crqpoffs Chroma Cr QP Offset. Default %d\n", param->crQpOffset);
diff -r 0d79e31728a4 -r 8585af48e921 source/x265.h
--- a/source/x265.h Fri Nov 01 13:05:34 2013 -0500
+++ b/source/x265.h Wed Oct 30 16:59:47 2013 +0800
@@ -329,7 +329,7 @@
int qpStep;
int rateControlMode; ///<Values corresponding to RcMethod
int qp; ///< Constant QP base value
- int rateFactor; ///< Constant rate factor (CRF)
+ double rfConstant; ///< Constant rate factor (CRF)
int aqMode; ///< Adaptive QP (AQ)
double aqStrength;
} rc;
More information about the x265-devel
mailing list