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