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