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

Deepthi Nandakumar deepthi at multicorewareinc.com
Sun Oct 5 16:08:10 CEST 2014


On Sun, Oct 5, 2014 at 5:08 PM, <aarthi at multicorewareinc.com> wrote:

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

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?

 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++;
> +        }
> +    }
>

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.

+
>      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;
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20141005/8299c3db/attachment-0001.html>


More information about the x265-devel mailing list