[x265] [PATCH] abr: reset ABR to prevent high bitrate peaks in single pass ABR

Aarthi Priya Thirumalai aarthi at multicorewareinc.com
Tue Feb 4 19:51:44 CET 2014


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

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 );
>  };
>  }
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20140205/24f1416b/attachment-0001.html>


More information about the x265-devel mailing list