<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Oct 5, 2014 at 5:08 PM,  <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"># HG changeset patch<br>
# User Aarthi Thirumalai<br>
# Date 1412460518 -19800<br>
#      Sun Oct 05 03:38:38 2014 +0530<br>
# Node ID 41cb94e538b800d8792fac48ceb9f8bdf2a9f627<br>
# Parent  b6d49505b179cb509aa76f3a065192f0b4926579<br>
rc: use a sliding window to calculate moving avg SatdCost for ABR Reset logic<br>
<br>
contains improvements for detection of scene changes within Rate Control to stabilize qp and prevent<br>
extreme spikes in bitrate. Removes the blockiness or distortions in the frames that a streak of low-detailed<br>
frames and prevents vbv from overreacting at the points of scene cuts.<br>
<br>
diff -r b6d49505b179 -r 41cb94e538b8 source/encoder/ratecontrol.cpp<br>
--- a/source/encoder/ratecontrol.cpp    Thu Oct 02 16:47:55 2014 -0500<br>
+++ b/source/encoder/ratecontrol.cpp    Sun Oct 05 03:38:38 2014 +0530<br>
@@ -40,6 +40,7 @@<br>
 /* Amortize the partial cost of I frames over the next N frames */<br>
 const double RateControl::s_amortizeFraction = 0.85;<br>
 const int RateControl::s_amortizeFrames = 75;<br>
+const int RateControl::s_slidingWindowFrames = 20;<br></blockquote><div><br></div><div>Does it make sense to set this based on the framerate? For a 60fps video, assume 1 sec of black frames, and continually triggering reset 3 times in a row, could this lead to VBV issues?<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
 const char *RateControl::s_defaultStatFileName = "x265_2pass.log";<br>
<br>
 namespace {<br>
@@ -472,6 +473,12 @@<br>
     m_framesDone = 0;<br>
     m_residualCost = 0;<br>
     m_partialResidualCost = 0;<br>
+    for (int i = 0; i < s_slidingWindowFrames; i++)<br>
+    {<br>
+        m_satdCostWindow[i] = 0;<br>
+        m_encodedBitsWindow[i] = 0;<br>
+    }<br>
+    m_sliderPos = 0;<br>
<br>
     /* 720p videos seem to be a good cutoff for cplxrSum */<br>
     double tuneCplxFactor = (m_param->rc.cuTree && m_ncu > 3600) ? 2.5 : 1;<br>
@@ -1344,6 +1351,24 @@<br>
                      g_sliceTypeToChar[m_sliceType], g_sliceTypeToChar[rce->sliceType]);<br>
         }<br>
     }<br>
+    else<br>
+    {<br>
+        if (m_isAbr)<br>
+        {<br>
+            double slidingWindowCplxSum = 0;<br>
+            for (int i = 0;i < s_slidingWindowFrames; i++)<br>
+            {<br>
+                slidingWindowCplxSum *= 0.5;<br>
+                if (!m_satdCostWindow[i])<br>
+                    break;<br>
+                slidingWindowCplxSum += m_satdCostWindow[i] / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);<br>
+            }<br>
+            rce->movingAvgSum = slidingWindowCplxSum;<br>
+            m_satdCostWindow[m_sliderPos % s_slidingWindowFrames] = rce->lastSatd;<br>
+            m_sliderPos++;<br>
+        }<br>
+    }<br></blockquote><div><br></div><div>Did you mean to use m_sliderPos in this fashion? For movingAvgSum, you will end up weighting the frames wrongly - you want the closest frames weighted the most, and the furthest ones weighted the least.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
     if (m_sliceType == B_SLICE)<br>
     {<br>
         /* B-frames don't have independent rate control, but rather get the<br>
@@ -1478,7 +1503,7 @@<br>
              * tolerances, the bit distribution approaches that of 2pass. */<br>
<br>
             double wantedBits, overflow = 1;<br>
-            rce->movingAvgSum = m_shortTermCplxSum;<br>
+<br>
             m_shortTermCplxSum *= 0.5;<br>
             m_shortTermCplxCount *= 0.5;<br>
             m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);<br>
@@ -1619,8 +1644,12 @@<br>
     {<br>
         if (!m_isAbrReset && rce->movingAvgSum > 0)<br>
         {<br>
+            int64_t shrtTermWantedBits = (int64_t) (X265_MIN(m_sliderPos, s_slidingWindowFrames) * m_bitrate * m_frameDuration);<br>
+            int64_t shrtTermTotalBitsSum = 0;<br>
             // Reset ABR if prev frames are blank to prevent further sudden overflows/ high bit rate spikes.<br>
-            double underflow = (m_totalBits - m_wantedBitsWindow) / abrBuffer;<br>
+            for (int i = 0; i < s_slidingWindowFrames ; i++)<br>
+                shrtTermTotalBitsSum += m_encodedBitsWindow[i];<br>
+            double underflow = (shrtTermTotalBitsSum - shrtTermWantedBits) / abrBuffer;<br>
             const double epsilon = 0.0001f;<br>
             if (underflow < epsilon && !isFrameDone)<br>
             {<br>
@@ -1792,9 +1821,10 @@<br>
              q = X265_MAX(q0 / 2, q);<br>
          }<br>
<br>
-        if (!m_isCbr)<br>
+         if (!m_isCbr || m_isAbrReset)<br>
             q = X265_MAX(q0, q);<br>
<br>
+<br>
         if (m_rateFactorMaxIncrement)<br>
         {<br>
             double qpNoVbv = x265_qScale2qp(q0);<br>
@@ -2111,30 +2141,29 @@<br>
             }<br>
         }<br>
     }<br>
-    if (!m_isAbrReset)<br>
+<br>
+    if (m_param->rc.aqMode || m_isVbv)<br>
     {<br>
-        if (m_param->rc.aqMode || m_isVbv)<br>
+        if (pic->m_qpaRc)<br>
         {<br>
-            if (pic->m_qpaRc)<br>
-            {<br>
-                for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
-                    pic->m_avgQpRc += pic->m_qpaRc[i];<br>
+            for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
+                pic->m_avgQpRc += pic->m_qpaRc[i];<br>
<br>
-                pic->m_avgQpRc /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
-                rce->qpaRc = pic->m_avgQpRc;<br>
-                // copy avg RC qp to m_avgQpAq. To print out the correct qp when aq/cutree is disabled.<br>
-                pic->m_avgQpAq = pic->m_avgQpRc;<br>
-            }<br>
+            pic->m_avgQpRc /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
+            rce->qpaRc = pic->m_avgQpRc;<br>
+            // copy avg RC qp to m_avgQpAq. To print out the correct qp when aq/cutree is disabled.<br>
+            pic->m_avgQpAq = pic->m_avgQpRc;<br>
+        }<br>
<br>
-            if (pic->m_qpaAq)<br>
-            {<br>
-                for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
-                    pic->m_avgQpAq += pic->m_qpaAq[i];<br>
+        if (pic->m_qpaAq)<br>
+        {<br>
+            for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
+                pic->m_avgQpAq += pic->m_qpaAq[i];<br>
<br>
-                pic->m_avgQpAq /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
-            }<br>
+            pic->m_avgQpAq /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
         }<br>
     }<br>
+<br>
     // Write frame stats into the stats file if 2 pass is enabled.<br>
     if (m_param->rc.bStatWrite)<br>
     {<br>
@@ -2199,6 +2228,9 @@<br>
         }<br>
         m_wantedBitsWindow += m_frameDuration * m_bitrate;<br>
         m_totalBits += bits - rce->rowTotalBits;<br>
+        int pos = m_sliderPos - m_param->frameNumThreads;<br>
+        if (pos >= 0)<br>
+            m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;<br>
     }<br>
<br>
     if (m_2pass)<br>
diff -r b6d49505b179 -r 41cb94e538b8 source/encoder/ratecontrol.h<br>
--- a/source/encoder/ratecontrol.h      Thu Oct 02 16:47:55 2014 -0500<br>
+++ b/source/encoder/ratecontrol.h      Sun Oct 05 03:38:38 2014 +0530<br>
@@ -173,7 +173,9 @@<br>
     int64_t  m_totalBits;        /* total bits used for already encoded frames */<br>
     int      m_framesDone;       /* # of frames passed through RateCotrol already */<br>
     double   m_fps;<br>
-<br>
+    int64_t  m_satdCostWindow[50];<br>
+    int      m_sliderPos;<br>
+    int64_t  m_encodedBitsWindow[50];<br>
     /* a common variable on which rateControlStart, rateControlEnd and rateControUpdateStats waits to<br>
      * sync the calls to these functions. For example<br>
      * -F2:<br>
@@ -233,6 +235,7 @@<br>
<br>
     static const double s_amortizeFraction;<br>
     static const int    s_amortizeFrames;<br>
+    static const int    s_slidingWindowFrames;<br>
     static const char  *s_defaultStatFileName;<br>
<br>
     int m_residualFrames;<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br></div></div>