[x265] [PATCH] rc: add CRF ratecontrol

Steve Borho steve at borho.org
Fri Nov 1 22:24:39 CET 2013


On Fri, Nov 1, 2013 at 1:09 PM, Steve Borho <steve at borho.org> wrote:

> # HG changeset patch
> # User idxa<idxa at sina.com>
>

To clarify, this is Idxa's patch.  I have cleaned up the white-space
problems and posted it here inline for review



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



-- 
Steve Borho
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20131101/42b9b28e/attachment.html>


More information about the x265-devel mailing list