<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>