<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 class="" style="white-space:pre">        </span>Sat Feb 01 16:39:12 2014 -0600</div><div>+++ b/source/encoder/ratecontrol.cpp<span class="" style="white-space:pre"> </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 class="" style="white-space:pre">    </span>Sat Feb 01 16:39:12 2014 -0600</div>
<div>+++ b/source/encoder/ratecontrol.h<span class="" style="white-space:pre">  </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>