<p dir="ltr"><br>
On Oct 5, 2014 7:38 PM, "Deepthi Nandakumar" <<a href="mailto:deepthi@multicorewareinc.com">deepthi@multicorewareinc.com</a>> wrote:<br>
><br>
><br>
><br>
> On Sun, Oct 5, 2014 at 5:08 PM, <<a href="mailto:aarthi@multicorewareinc.com">aarthi@multicorewareinc.com</a>> wrote:<br>
>><br>
>> # 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>
><br>
><br>
> 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?</p>
<p dir="ltr">It won't trigger reset three times in this case..only the frame that ends this streak after 60frames will be identified as the scene change. <br>
But if we have a large window, we cannot identify a scene change with smaller sequence of  blank frames. As the moving avg within the window may be high already.<br>
><br>
>>  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>
><br>
><br>
> 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.</p>
<p dir="ltr">Yes, you are right. The logic as it is, will be correct for weighing the frames when the first window is filling up.but once that's done and the window begins to slide, weighing order is messed up.<br>
 I will fix this and start the order for weighing the average satd cost  from frame : sliderPos (this will be the oldest frame in the window) if the sliderPos > windowSize . else the order start from 0 .</p>
<p dir="ltr">><br>
>> +<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">https://mailman.videolan.org/listinfo/x265-devel</a><br>
><br>
><br>
><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">https://mailman.videolan.org/listinfo/x265-devel</a><br>
><br>
</p>