[x265] [PATCH] abr: reset ABR to prevent high bitrate peaks in single pass ABR
Steve Borho
steve at borho.org
Wed Feb 5 18:35:11 CET 2014
On Tue, Feb 4, 2014 at 12:51 PM, Aarthi Priya Thirumalai <
aarthi at multicorewareinc.com> wrote:
> # HG changeset patch
> # User Aarthi Thirumalai
> # Date 1391539452 -19800
> # Wed Feb 05 00:14:12 2014 +0530
> # Node ID ce4d1e450d2670d9f4b9ab9f1408decb32e4846b
> # Parent 2beb0bfb95032ecbedcda956d169f58bfd2b9386
> abr: reset ABR to prevent high bitrate peaks in single pass ABR
>
> Long series of blank frames in video followed by detailed content causes
> heavy ABR underflow and overall bitrates surges high for a long while.
> This patch detects this condition in Single pass ABR mode and resets ABR -
> to not consider history from blank frames and continue from following
> scene-cut.
>
queued
>
> diff -r 2beb0bfb9503 -r ce4d1e450d26 source/encoder/ratecontrol.cpp
> --- a/source/encoder/ratecontrol.cpp Tue Feb 04 12:17:11 2014 -0600
> +++ b/source/encoder/ratecontrol.cpp Wed Feb 05 00:14:12 2014 +0530
> @@ -239,7 +239,8 @@
> shortTermCplxCount = 0;
> framesDone = 0;
> lastNonBPictType = I_SLICE;
> -
> + isAbrReset = false;
> + lastAbrResetPoc = -1;
> // vbv initialization
> cfg->param.rc.vbvBufferSize = Clip3(0, 2000000,
> cfg->param.rc.vbvBufferSize);
> cfg->param.rc.vbvMaxBitrate = Clip3(0, 2000000,
> cfg->param.rc.vbvMaxBitrate);
> @@ -374,12 +375,12 @@
> if (isAbr) //ABR,CRF
> {
> lastSatd = l->getEstimatedPictureCost(pic);
> + rce->lastSatd = lastSatd;
> double q = qScale2qp(rateEstimateQscale(rce));
> qp = Clip3(MIN_QP, MAX_MAX_QP, (int)(q + 0.5));
> rce->qpaRc = q;
> /* copy value of lastRceq into thread local rce struct *to be
> used in RateControlEnd() */
> rce->qRceq = lastRceq;
> - rce->lastSatd = lastSatd;
> accumPQpUpdate();
> }
> else //CQP
> @@ -424,6 +425,16 @@
> double q0 = prevRefSlice->m_avgQpRc;
> double q1 = nextRefSlice->m_avgQpRc;
>
> + //Skip taking a reference frame before the Scenecut if ABR has
> been reset.
> + if (lastAbrResetPoc >= 0 && !isVbv)
> + {
> + if (prevRefSlice->getSliceType() == P_SLICE &&
> prevRefSlice->getPOC() < lastAbrResetPoc)
> + {
> + i0 = i1;
> + dt0 = dt1;
> + q0 = q1;
> + }
> + }
> if (prevRefSlice->getSliceType() == B_SLICE &&
> prevRefSlice->isReferenced())
> q0 -= pbOffset / 2;
> if (nextRefSlice->getSliceType() == B_SLICE &&
> nextRefSlice->isReferenced())
> @@ -463,6 +474,7 @@
> * tolerances, the bit distribution approaches that of 2pass. */
>
> double wantedBits, overflow = 1;
> + rce->movingAvgSum = shortTermCplxSum;
> shortTermCplxSum *= 0.5;
> shortTermCplxCount *= 0.5;
> shortTermCplxSum += lastSatd / (CLIP_DURATION(frameDuration) /
> BASE_FRAME_DURATION);
> @@ -478,6 +490,10 @@
> }
> else
> {
> + if (!isVbv)
> + {
> + checkAndResetABR(rce);
> + }
> q = getQScale(rce, wantedBitsWindow / cplxrSum);
>
> /* ABR code can potentially be counterproductive in CBR, so
> just don't bother.
> @@ -497,7 +513,7 @@
> }
>
> if (sliceType == I_SLICE && cfg->param.keyframeMax > 1
> - && lastNonBPictType != I_SLICE)
> + && lastNonBPictType != I_SLICE && !isAbrReset)
> {
> q = qp2qScale(accumPQp / accumPNorm);
> q /= fabs(cfg->param.rc.ipFactor);
> @@ -538,7 +554,7 @@
>
> lastQScaleFor[sliceType] = q;
>
> - if (curSlice->getPOC() == 0)
> + if (curSlice->getPOC() == 0 || (isAbrReset && sliceType ==
> I_SLICE))
> lastQScaleFor[P_SLICE] = q * fabs(cfg->param.rc.ipFactor);
>
> rce->frameSizePlanned = predictSize(&pred[sliceType], q,
> (double)lastSatd);
> @@ -547,6 +563,38 @@
> }
> }
>
> +void RateControl::checkAndResetABR(RateControlEntry* rce)
> +{
> + double abrBuffer = 2 * cfg->param.rc.rateTolerance * bitrate;
> + // Check if current Slice is a scene cut that follows low
> detailed/blank frames
> + if (rce->lastSatd > 4 * rce->movingAvgSum)
> + {
> + if (!isAbrReset && rce->movingAvgSum > 0)
> + {
> + // Reset ABR if prev frames are blank to prevent further
> sudden overflows/ high bit rate spikes.
> + double underflow = 1.0 + (totalBits - wantedBitsWindow) /
> abrBuffer;
> + if (underflow < 1 && curSlice->m_avgQpRc == 0)
> + {
> + totalBits = 0;
> + framesDone = 0;
> + cplxrSum = .01 * pow(7.0e5, qCompress) * pow(ncu, 0.5);
> + wantedBitsWindow = bitrate * frameDuration;
> + accumPNorm = .01;
> + accumPQp = (ABR_INIT_QP_MIN)*accumPNorm;
> + shortTermCplxSum = rce->lastSatd /
> (CLIP_DURATION(frameDuration) / BASE_FRAME_DURATION);
> + shortTermCplxCount = 1;
> + isAbrReset = true;
> + lastAbrResetPoc = rce->poc;
> + }
> + }
> + else
> + {
> + // Clear flag to reset ABR and continue as usual.
> + isAbrReset = false;
> + }
> + }
> +}
> +
> void RateControl::updateVbvPlan(Encoder* enc)
> {
> bufferFill = bufferFillFinal;
> @@ -705,19 +753,27 @@
> {
> 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
> - * to improve short term compensation for next frame. */
> - cplxrSum += bits * qp2qScale(rce->qpaRc) / rce->qRceq;
> - else
> + if (!isVbv)
> {
> - /* Depends on the fact that B-frame's QP is an offset from
> the following P-frame's.
> - * Not perfectly accurate with B-refs, but good enough. */
> - cplxrSum += bits * qp2qScale(rce->qpaRc) / (rce->qRceq *
> fabs(cfg->param.rc.pbFactor));
> + checkAndResetABR(rce);
> }
> - wantedBitsWindow += frameDuration * bitrate;
> +
> + if (!isAbrReset)
> + {
> + if (rce->sliceType != B_SLICE)
> + /* The factor 1.5 is to tune up the actual bits,
> otherwise the cplxrSum is scaled too low
> + * to improve short term compensation for next frame. */
> + cplxrSum += bits * qp2qScale(rce->qpaRc) / rce->qRceq;
> + else
> + {
> + /* Depends on the fact that B-frame's QP is an offset
> from the following P-frame's.
> + * Not perfectly accurate with B-refs, but good enough. */
> + cplxrSum += bits * qp2qScale(rce->qpaRc) / (rce->qRceq *
> fabs(cfg->param.rc.pbFactor));
> + }
> + wantedBitsWindow += frameDuration * bitrate;
> + totalBits += bits;
> + }
> }
> - totalBits += bits;
>
> if (isVbv)
> {
> @@ -731,8 +787,7 @@
> bframeBits = 0;
> }
> }
> + updateVbv(bits, rce);
> }
> -
> - updateVbv(bits, rce);
> return 0;
> }
> diff -r 2beb0bfb9503 -r ce4d1e450d26 source/encoder/ratecontrol.h
> --- a/source/encoder/ratecontrol.h Tue Feb 04 12:17:11 2014 -0600
> +++ b/source/encoder/ratecontrol.h Wed Feb 05 00:14:12 2014 +0530
> @@ -60,6 +60,7 @@
> double qRceq;
> double frameSizePlanned;
> double bufferRate;
> + double movingAvgSum;
> };
>
> struct Predictor
> @@ -83,7 +84,6 @@
> double bitrate;
> double rateFactorConstant;
> bool isAbr;
> -
> double bufferSize;
> double bufferFillFinal; /* real buffer as of the last finished frame
> */
> double bufferFill; /* planned buffer, if all in-progress frames
> hit their bit budget */
> @@ -97,7 +97,8 @@
> int bframes;
> int bframeBits;
> double leadingNoBSatd;
> -
> + bool isAbrReset;
> + int lastAbrResetPoc;
> int64_t lastSatd;
> int qpConstant[3];
> double cplxrSum; /* sum of bits*qscale/rceq */
> @@ -136,6 +137,7 @@
> double clipQscale(double q);
> void updateVbvPlan(Encoder* enc);
> double predictSize(Predictor *p, double q, double var);
> + void checkAndResetABR(RateControlEntry* rce);
> };
> }
>
>
>
>
> On Sun, Feb 2, 2014 at 6:07 PM, Aarthi Priya Thirumalai <
> aarthi at multicorewareinc.com> wrote:
>
>> # HG changeset patch
>> # User Aarthi Thirumalai
>> # Date 1391343895 -19800
>> # Sun Feb 02 17:54:55 2014 +0530
>> # Node ID bf00f495951eb882e34225740c43540311bf51cb
>> # Parent bb33ab0f4ef933315cedf388d70443bc97fefeea
>> abr: reset ABR to prevent high bitrate peaks in single pass ABR .
>>
>> Long series of blank frames in video followed by detailed content causes
>> heavy ABR underflow and overall bitrates surges high for a long while.
>> patch detects this condition in Single pass ABR mode and resets ABR - to
>> not consider history from blank frames and continue from following
>> scene-cut.
>>
>> diff -r bb33ab0f4ef9 -r bf00f495951e source/encoder/ratecontrol.cpp
>> --- a/source/encoder/ratecontrol.cpp Sat Feb 01 16:39:12 2014 -0600
>> +++ b/source/encoder/ratecontrol.cpp Sun Feb 02 17:54:55 2014 +0530
>> @@ -240,7 +240,7 @@
>> shortTermCplxCount = 0;
>> framesDone = 0;
>> lastNonBPictType = I_SLICE;
>> -
>> + isAbrReset = false;
>> // vbv initialization
>> cfg->param.rc.vbvBufferSize = Clip3(0, 2000000,
>> cfg->param.rc.vbvBufferSize);
>> cfg->param.rc.vbvMaxBitrate = Clip3(0, 2000000,
>> cfg->param.rc.vbvMaxBitrate);
>> @@ -375,12 +375,12 @@
>> if (isAbr) //ABR,CRF
>> {
>> lastSatd = l->getEstimatedPictureCost(pic);
>> + rce->lastSatd = lastSatd;
>> double q = qScale2qp(rateEstimateQscale(rce));
>> qp = Clip3(MIN_QP, MAX_MAX_QP, (int)(q + 0.5));
>> rce->qpaRc = q;
>> /* copy value of lastRceq into thread local rce struct *to be
>> used in RateControlEnd() */
>> rce->qRceq = lastRceq;
>> - rce->lastSatd = lastSatd;
>> accumPQpUpdate();
>> }
>> else //CQP
>> @@ -464,6 +464,7 @@
>> * tolerances, the bit distribution approaches that of 2pass. */
>>
>> double wantedBits, overflow = 1;
>> + rce->movingAvgSum = shortTermCplxSum;
>> shortTermCplxSum *= 0.5;
>> shortTermCplxCount *= 0.5;
>> shortTermCplxSum += lastSatd / (CLIP_DURATION(frameDuration) /
>> BASE_FRAME_DURATION);
>> @@ -479,6 +480,8 @@
>> }
>> else
>> {
>> + if (!isVbv)
>> + checkAndResetABR(rce);
>> q = getQScale(rce, wantedBitsWindow / cplxrSum);
>>
>> /* ABR code can potentially be counterproductive in CBR, so
>> just don't bother.
>> @@ -498,7 +501,7 @@
>> }
>>
>> if (sliceType == I_SLICE && cfg->param.keyframeMax > 1
>> - && lastNonBPictType != I_SLICE)
>> + && lastNonBPictType != I_SLICE && !isAbrReset)
>> {
>> q = qp2qScale(accumPQp / accumPNorm);
>> q /= fabs(cfg->param.rc.ipFactor);
>> @@ -539,7 +542,7 @@
>>
>> lastQScaleFor[sliceType] = q;
>>
>> - if (curSlice->getPOC() == 0)
>> + if (curSlice->getPOC() == 0 || (isAbrReset && sliceType ==
>> I_SLICE))
>> lastQScaleFor[P_SLICE] = q * fabs(cfg->param.rc.ipFactor);
>>
>> rce->frameSizePlanned = predictSize(&pred[sliceType], q,
>> (double)lastSatd);
>> @@ -548,6 +551,35 @@
>> }
>> }
>>
>> +void RateControl::checkAndResetABR( RateControlEntry* rce )
>> +{
>> + double abrBuffer = 2 * cfg->param.rc.rateTolerance * bitrate;
>> + // Check if current SLice is a scene cut that follow low
>> detailed/blank frames
>> + if (rce->lastSatd > 4 * rce->movingAvgSum)
>> + {
>> + if (!isAbrReset && rce->movingAvgSum > 0 )
>> + {
>> + // Reset ABR if prev frames are blank to prevent further
>> sudden overflows/ high bit rate spikes.
>> + double underflow = 1.0 + (totalBits - wantedBitsWindow) /
>> abrBuffer;
>> + if (underflow < 1 && curSlice->m_avgQpRc==0)
>> + {
>> + totalBits = 0;
>> + framesDone = 0;
>> + cplxrSum = .01 * pow(7.0e5, qCompress) * pow(ncu, 0.5);
>> + wantedBitsWindow = bitrate * frameDuration;
>> + accumPNorm = .01;
>> + accumPQp = (ABR_INIT_QP_MIN)*accumPNorm;
>> + isAbrReset = true;
>> + }
>> + }
>> + // Clear flag to reset ABR and continue as usual.
>> + else
>> + {
>> + isAbrReset = false;
>> + }
>> + }
>> +}
>> +
>> void RateControl::updateVbvPlan(Encoder* enc)
>> {
>> bufferFill = bufferFillFinal;
>> @@ -706,19 +738,25 @@
>> {
>> 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
>> - * to improve short term compensation for next frame. */
>> - cplxrSum += bits * qp2qScale(rce->qpaRc) / rce->qRceq;
>> - else
>> + if (!isVbv)
>> + checkAndResetABR(rce);
>> +
>> + if(!isAbrReset)
>> {
>> - /* Depends on the fact that B-frame's QP is an offset from
>> the following P-frame's.
>> - * Not perfectly accurate with B-refs, but good enough. */
>> - cplxrSum += bits * qp2qScale(rce->qpaRc) / (rce->qRceq *
>> fabs(cfg->param.rc.pbFactor));
>> + if (rce->sliceType != B_SLICE)
>> + /* The factor 1.5 is to tune up the actual bits,
>> otherwise the cplxrSum is scaled too low
>> + * to improve short term compensation for next frame. */
>> + cplxrSum += bits * qp2qScale(rce->qpaRc) / rce->qRceq;
>> + else
>> + {
>> + /* Depends on the fact that B-frame's QP is an offset
>> from the following P-frame's.
>> + * Not perfectly accurate with B-refs, but good enough.
>> */
>> + cplxrSum += bits * qp2qScale(rce->qpaRc) / (rce->qRceq *
>> fabs(cfg->param.rc.pbFactor));
>> + }
>> + wantedBitsWindow += frameDuration * bitrate;
>> + totalBits += bits;
>> }
>> - wantedBitsWindow += frameDuration * bitrate;
>> }
>> - totalBits += bits;
>>
>> if (isVbv)
>> {
>> @@ -732,8 +770,9 @@
>> bframeBits = 0;
>> }
>> }
>> + updateVbv(bits, rce);
>> }
>>
>> - updateVbv(bits, rce);
>> +
>> return 0;
>> }
>> diff -r bb33ab0f4ef9 -r bf00f495951e source/encoder/ratecontrol.h
>> --- a/source/encoder/ratecontrol.h Sat Feb 01 16:39:12 2014 -0600
>> +++ b/source/encoder/ratecontrol.h Sun Feb 02 17:54:55 2014 +0530
>> @@ -60,6 +60,7 @@
>> double qRceq;
>> double frameSizePlanned;
>> double bufferRate;
>> + double movingAvgSum;
>> };
>>
>> struct Predictor
>> @@ -97,7 +98,7 @@
>> int bframes;
>> int bframeBits;
>> double leadingNoBSatd;
>> -
>> + bool isAbrReset;
>> int64_t lastSatd;
>> int qpConstant[3];
>> double cplxrSum; /* sum of bits*qscale/rceq */
>> @@ -136,6 +137,7 @@
>> double clipQscale(double q);
>> void updateVbvPlan(Encoder* enc);
>> double predictSize(Predictor *p, double q, double var);
>> + void checkAndResetABR( RateControlEntry* rce );
>> };
>> }
>>
>>
>>
>
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
>
--
Steve Borho
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20140205/fc6e474d/attachment-0001.html>
More information about the x265-devel
mailing list