[x265] [PATCH] rc: use a sliding window to calculate moving avg SatdCost for ABR Reset logic

aarthi at multicorewareinc.com aarthi at multicorewareinc.com
Sun Oct 5 13:38:25 CEST 2014


# HG changeset patch
# User Aarthi Thirumalai
# Date 1412460518 -19800
#      Sun Oct 05 03:38:38 2014 +0530
# Node ID 41cb94e538b800d8792fac48ceb9f8bdf2a9f627
# Parent  b6d49505b179cb509aa76f3a065192f0b4926579
rc: use a sliding window to calculate moving avg SatdCost for ABR Reset logic

contains improvements for detection of scene changes within Rate Control to stabilize qp and prevent
extreme spikes in bitrate. Removes the blockiness or distortions in the frames that a streak of low-detailed
frames and prevents vbv from overreacting at the points of scene cuts.

diff -r b6d49505b179 -r 41cb94e538b8 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Thu Oct 02 16:47:55 2014 -0500
+++ b/source/encoder/ratecontrol.cpp	Sun Oct 05 03:38:38 2014 +0530
@@ -40,6 +40,7 @@
 /* Amortize the partial cost of I frames over the next N frames */
 const double RateControl::s_amortizeFraction = 0.85;
 const int RateControl::s_amortizeFrames = 75;
+const int RateControl::s_slidingWindowFrames = 20;
 const char *RateControl::s_defaultStatFileName = "x265_2pass.log";
 
 namespace {
@@ -472,6 +473,12 @@
     m_framesDone = 0;
     m_residualCost = 0;
     m_partialResidualCost = 0;
+    for (int i = 0; i < s_slidingWindowFrames; i++)
+    {
+        m_satdCostWindow[i] = 0;
+        m_encodedBitsWindow[i] = 0;
+    }
+    m_sliderPos = 0;
 
     /* 720p videos seem to be a good cutoff for cplxrSum */
     double tuneCplxFactor = (m_param->rc.cuTree && m_ncu > 3600) ? 2.5 : 1;
@@ -1344,6 +1351,24 @@
                      g_sliceTypeToChar[m_sliceType], g_sliceTypeToChar[rce->sliceType]);
         }
     }
+    else
+    {
+        if (m_isAbr)
+        {
+            double slidingWindowCplxSum = 0;
+            for (int i = 0;i < s_slidingWindowFrames; i++)
+            {
+                slidingWindowCplxSum *= 0.5;
+                if (!m_satdCostWindow[i])
+                    break;
+                slidingWindowCplxSum += m_satdCostWindow[i] / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);
+            }
+            rce->movingAvgSum = slidingWindowCplxSum;
+            m_satdCostWindow[m_sliderPos % s_slidingWindowFrames] = rce->lastSatd;
+            m_sliderPos++;
+        }
+    }
+
     if (m_sliceType == B_SLICE)
     {
         /* B-frames don't have independent rate control, but rather get the
@@ -1478,7 +1503,7 @@
              * tolerances, the bit distribution approaches that of 2pass. */
 
             double wantedBits, overflow = 1;
-            rce->movingAvgSum = m_shortTermCplxSum;
+
             m_shortTermCplxSum *= 0.5;
             m_shortTermCplxCount *= 0.5;
             m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);
@@ -1619,8 +1644,12 @@
     {
         if (!m_isAbrReset && rce->movingAvgSum > 0)
         {
+            int64_t shrtTermWantedBits = (int64_t) (X265_MIN(m_sliderPos, s_slidingWindowFrames) * m_bitrate * m_frameDuration);
+            int64_t shrtTermTotalBitsSum = 0;
             // Reset ABR if prev frames are blank to prevent further sudden overflows/ high bit rate spikes.
-            double underflow = (m_totalBits - m_wantedBitsWindow) / abrBuffer;
+            for (int i = 0; i < s_slidingWindowFrames ; i++)
+                shrtTermTotalBitsSum += m_encodedBitsWindow[i];
+            double underflow = (shrtTermTotalBitsSum - shrtTermWantedBits) / abrBuffer;
             const double epsilon = 0.0001f;
             if (underflow < epsilon && !isFrameDone)
             {
@@ -1792,9 +1821,10 @@
              q = X265_MAX(q0 / 2, q);
          }
 
-        if (!m_isCbr)
+         if (!m_isCbr || m_isAbrReset)
             q = X265_MAX(q0, q);
 
+
         if (m_rateFactorMaxIncrement)
         {
             double qpNoVbv = x265_qScale2qp(q0);
@@ -2111,30 +2141,29 @@
             }
         }
     }
-    if (!m_isAbrReset)
+
+    if (m_param->rc.aqMode || m_isVbv)
     {
-        if (m_param->rc.aqMode || m_isVbv)
+        if (pic->m_qpaRc)
         {
-            if (pic->m_qpaRc)
-            {
-                for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)
-                    pic->m_avgQpRc += pic->m_qpaRc[i];
+            for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)
+                pic->m_avgQpRc += pic->m_qpaRc[i];
 
-                pic->m_avgQpRc /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());
-                rce->qpaRc = pic->m_avgQpRc;
-                // copy avg RC qp to m_avgQpAq. To print out the correct qp when aq/cutree is disabled.
-                pic->m_avgQpAq = pic->m_avgQpRc;
-            }
+            pic->m_avgQpRc /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());
+            rce->qpaRc = pic->m_avgQpRc;
+            // copy avg RC qp to m_avgQpAq. To print out the correct qp when aq/cutree is disabled.
+            pic->m_avgQpAq = pic->m_avgQpRc;
+        }
 
-            if (pic->m_qpaAq)
-            {
-                for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)
-                    pic->m_avgQpAq += pic->m_qpaAq[i];
+        if (pic->m_qpaAq)
+        {
+            for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)
+                pic->m_avgQpAq += pic->m_qpaAq[i];
 
-                pic->m_avgQpAq /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());
-            }
+            pic->m_avgQpAq /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());
         }
     }
+
     // Write frame stats into the stats file if 2 pass is enabled.
     if (m_param->rc.bStatWrite)
     {
@@ -2199,6 +2228,9 @@
         }
         m_wantedBitsWindow += m_frameDuration * m_bitrate;
         m_totalBits += bits - rce->rowTotalBits;
+        int pos = m_sliderPos - m_param->frameNumThreads;
+        if (pos >= 0)
+            m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;
     }
 
     if (m_2pass)
diff -r b6d49505b179 -r 41cb94e538b8 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h	Thu Oct 02 16:47:55 2014 -0500
+++ b/source/encoder/ratecontrol.h	Sun Oct 05 03:38:38 2014 +0530
@@ -173,7 +173,9 @@
     int64_t  m_totalBits;        /* total bits used for already encoded frames */
     int      m_framesDone;       /* # of frames passed through RateCotrol already */
     double   m_fps;
-
+    int64_t  m_satdCostWindow[50];
+    int      m_sliderPos;
+    int64_t  m_encodedBitsWindow[50];
     /* a common variable on which rateControlStart, rateControlEnd and rateControUpdateStats waits to
      * sync the calls to these functions. For example
      * -F2:
@@ -233,6 +235,7 @@
 
     static const double s_amortizeFraction;
     static const int    s_amortizeFrames;
+    static const int    s_slidingWindowFrames;
     static const char  *s_defaultStatFileName;
 
     int m_residualFrames;


More information about the x265-devel mailing list