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