[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