[x265] [PATCH] Add real-time VBV fullness based QP tuning in VBV 2 pass

Aruna Matheswaran aruna at multicorewareinc.com
Wed Sep 9 18:13:57 CEST 2020


Pushed to master

On Wed, Sep 9, 2020 at 1:21 PM Kirithika Kalirathnam <
kirithika at multicorewareinc.com> wrote:

> From f83db031a5308bb6bc2ca54dd079e20630fc5701 Mon Sep 17 00:00:00 2001
> From: Kirithika <kirithika at multicorewareinc.com>
> Date: Fri, 28 Aug 2020 09:20:47 +0530
> Subject: [PATCH] Add real-time VBV fullness based QP tuning in VBV 2 pass
>
> This commit enables real-time VBV fullness based 2nd pass QP  tuning.
> Experimental feature.Default disabled
> ---
>  doc/reST/cli.rst               |  9 ++++
>  source/CMakeLists.txt          |  2 +-
>  source/common/param.cpp        | 13 +++++
>  source/encoder/ratecontrol.cpp | 98 +++++++++++++++++++---------------
>  source/encoder/slicetype.cpp   | 14 ++---
>  source/x265.h                  |  5 ++
>  source/x265cli.cpp             |  1 +
>  source/x265cli.h               |  2 +
>  8 files changed, 93 insertions(+), 51 deletions(-)
>
> diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
> index e6c628c36..7777ee49e 100755
> --- a/doc/reST/cli.rst
> +++ b/doc/reST/cli.rst
> @@ -1977,6 +1977,15 @@ Quality, rate control and rate distortion options
>
>     **Range of values:**  0 to 10
>
> +.. option:: --vbv-live-multi-pass, --no-vbv-live-multi-pass
> +
> +   It enables the Qp tuning at frame level based on real time VBV Buffer
> fullness
> +   in the ratecontrol 2nd pass of multi pass mode to reduce the VBV
> violations.
> +   It could only be enabled with rate control stat-read encodes with VBV
> and ABR
> +   rate control mode.
> +
> +   Default disabled. **Experimental feature**
> +
>  Quantization Options
>  ====================
>
> diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
> index d9ed3983e..5738c861c 100755
> --- a/source/CMakeLists.txt
> +++ b/source/CMakeLists.txt
> @@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)
>  option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)
>  mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
>  # X265_BUILD must be incremented each time the public API is changed
> -set(X265_BUILD 196)
> +set(X265_BUILD 197)
>  configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
>                 "${PROJECT_BINARY_DIR}/x265.def")
>  configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
> diff --git a/source/common/param.cpp b/source/common/param.cpp
> index 845c38bd2..b3001fcf6 100755
> --- a/source/common/param.cpp
> +++ b/source/common/param.cpp
> @@ -288,6 +288,7 @@ void x265_param_default(x265_param* param)
>      param->bResetZoneConfig = 1;
>      param->reconfigWindowSize = 0;
>      param->decoderVbvMaxRate = 0;
> +    param->bliveVBV2pass = 0;
>
>      /* Video Usability Information (VUI) */
>      param->vui.aspectRatioIdc = 0;
> @@ -1375,6 +1376,7 @@ int x265_param_parse(x265_param* p, const char*
> name, const char* value)
>              sscanf(value, "%d,%d,%d", &p->hmeRange[0], &p->hmeRange[1],
> &p->hmeRange[2]);
>              p->bEnableHME = true;
>          }
> +        OPT("vbv-live-multi-pass") p->bliveVBV2pass = atobool(value);
>          else
>              return X265_PARAM_BAD_NAME;
>      }
> @@ -1817,6 +1819,15 @@ int x265_check_params(x265_param* param)
>      CHECK(param->confWinRightOffset < 0, "Conformance Window Right Offset
> must be 0 or greater");
>      CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom
> Offset must be 0 or greater");
>      CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate.
> Value can not be less than zero");
> +    if (param->bliveVBV2pass)
> +    {
> +        CHECK((param->rc.bStatRead == 0), "Live VBV in multi pass option
> requires rate control 2 pass to be enabled");
> +        if ((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize <=
> 0))
> +        {
> +            param->bliveVBV2pass = 0;
> +            x265_log(param, X265_LOG_WARNING, "Live VBV enabled without
> VBV settings.Disabling live VBV in 2 pass\n");
> +        }
> +    }
>      return check_failed;
>  }
>
> @@ -2238,6 +2249,7 @@ char *x265_param2string(x265_param* p, int padx, int
> pady)
>          s += sprintf(s, " scenecut-window=%d qp-delta-ref=%f
> qp-delta-nonref=%f", p->scenecutWindow, p->refQpDelta, p->nonRefQpDelta);
>      s += sprintf(s, "conformance-window-offsets right=%d bottom=%d",
> p->confWinRightOffset, p->confWinBottomOffset);
>      s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate);
> +    BOOL(p->bliveVBV2pass, "vbv-live-multi-pass");
>  #undef BOOL
>      return buf;
>  }
> @@ -2593,6 +2605,7 @@ void x265_copy_params(x265_param* dst, x265_param*
> src)
>
>      dst->confWinRightOffset = src->confWinRightOffset;
>      dst->confWinBottomOffset = src->confWinBottomOffset;
> +    dst->bliveVBV2pass = src->bliveVBV2pass;
>  #ifdef SVT_HEVC
>      memcpy(dst->svtHevcParam, src->svtHevcParam,
> sizeof(EB_H265_ENC_CONFIGURATION));
>  #endif
> diff --git a/source/encoder/ratecontrol.cpp
> b/source/encoder/ratecontrol.cpp
> index 82d7c4f2a..8e9187e8a 100644
> --- a/source/encoder/ratecontrol.cpp
> +++ b/source/encoder/ratecontrol.cpp
> @@ -1755,34 +1755,32 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>                       g_sliceTypeToChar[m_sliceType],
> g_sliceTypeToChar[rce->sliceType]);
>          }
>      }
> -    else
> +
> +    if ((m_param->bliveVBV2pass && m_param->rc.rateControlMode ==
> X265_RC_ABR) || m_isAbr)
>      {
> -        if (m_isAbr)
> +        int pos = m_sliderPos % s_slidingWindowFrames;
> +        int addPos = (pos + s_slidingWindowFrames - 1) %
> s_slidingWindowFrames;
> +        if (m_sliderPos > s_slidingWindowFrames)
>          {
> -            int pos = m_sliderPos % s_slidingWindowFrames;
> -            int addPos = (pos + s_slidingWindowFrames - 1) %
> s_slidingWindowFrames;
> -            if (m_sliderPos > s_slidingWindowFrames)
> -            {
> -                const static double base = pow(0.5, s_slidingWindowFrames
> - 1);
> -                m_movingAvgSum -= m_lastRemovedSatdCost * base;
> -                m_movingAvgSum *= 0.5;
> -                m_movingAvgSum += m_satdCostWindow[addPos];
> -            }
> -            else if (m_sliderPos == s_slidingWindowFrames)
> -            {
> -                m_movingAvgSum += m_satdCostWindow[addPos];
> -            }
> -            else if (m_sliderPos > 0)
> -            {
> -                m_movingAvgSum += m_satdCostWindow[addPos];
> -                m_movingAvgSum *= 0.5;
> -            }
> -
> -            rce->movingAvgSum = m_movingAvgSum;
> -            m_lastRemovedSatdCost = m_satdCostWindow[pos];
> -            m_satdCostWindow[pos] = rce->lastSatd;
> -            m_sliderPos++;
> +            const static double base = pow(0.5, s_slidingWindowFrames -
> 1);
> +            m_movingAvgSum -= m_lastRemovedSatdCost * base;
> +            m_movingAvgSum *= 0.5;
> +            m_movingAvgSum += m_satdCostWindow[addPos];
> +        }
> +        else if (m_sliderPos == s_slidingWindowFrames)
> +        {
> +            m_movingAvgSum += m_satdCostWindow[addPos];
>          }
> +        else if (m_sliderPos > 0)
> +        {
> +            m_movingAvgSum += m_satdCostWindow[addPos];
> +            m_movingAvgSum *= 0.5;
> +        }
> +
> +        rce->movingAvgSum = m_movingAvgSum;
> +        m_lastRemovedSatdCost = m_satdCostWindow[pos];
> +        m_satdCostWindow[pos] = rce->lastSatd;
> +        m_sliderPos++;
>      }
>
>      if (m_sliceType == B_SLICE)
> @@ -1887,7 +1885,7 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>                  qScale = x265_clip3(lqmin, lqmax, qScale);
>              }
>
> -            if (!m_2pass)
> +            if (!m_2pass || m_param->bliveVBV2pass)
>              {
>                  /* clip qp to permissible range after vbv-lookahead
> estimation to avoid possible
>                   * mispredictions by initial frame size predictors */
> @@ -1955,7 +1953,9 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>                  else
>                      q /= zone->bitrateFactor;
>              }
> -            q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
> abrBuffer);
> +            /*Existing ABR conformance check may not be valid with real
> time VBV*/
> +            if(!m_param->bliveVBV2pass)
> +                q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
> abrBuffer);
>              if (m_expectedBitsSum > 0)
>              {
>                  /* Adjust quant based on the difference between
> @@ -1988,24 +1988,34 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>
>              if (m_isVbv)
>              {
> -                /* Do not overflow vbv */
> -                double expectedSize = qScale2bits(rce, q);
> -                double expectedVbv = m_bufferFill + m_bufferRate -
> expectedSize;
> -                double expectedFullness = rce->expectedVbv / m_bufferSize;
> -                double qmax = q * (2 - expectedFullness);
> -                double sizeConstraint = 1 + expectedFullness;
> -                qmax = X265_MAX(qmax, rce->newQScale);
> -                if (expectedFullness < .05)
> -                    qmax = lmax;
> -                qmax = X265_MIN(qmax, lmax);
> -                while (((expectedVbv < rce->expectedVbv/sizeConstraint)
> && (q < qmax)) ||
> +                if (!m_param->bliveVBV2pass)
> +                {
> +                    /* Do not overflow vbv */
> +                    double expectedSize = qScale2bits(rce, q);
> +                    double expectedVbv = m_bufferFill + m_bufferRate -
> expectedSize;
> +                    double expectedFullness = rce->expectedVbv /
> m_bufferSize;
> +                    double qmax = q * (2 - expectedFullness);
> +                    double sizeConstraint = 1 + expectedFullness;
> +                    qmax = X265_MAX(qmax, rce->newQScale);
> +                    if (expectedFullness < .05)
> +                        qmax = lmax;
> +                    qmax = X265_MIN(qmax, lmax);
> +                    while (((expectedVbv < rce->expectedVbv /
> sizeConstraint) && (q < qmax)) ||
>                          ((expectedVbv < 0) && (q < lmax)))
> +                    {
> +                        q *= 1.05;
> +                        expectedSize = qScale2bits(rce, q);
> +                        expectedVbv = m_bufferFill + m_bufferRate -
> expectedSize;
> +                    }
> +                }
> +                else
>                  {
> -                    q *= 1.05;
> -                    expectedSize = qScale2bits(rce, q);
> -                    expectedVbv = m_bufferFill + m_bufferRate -
> expectedSize;
> +                        /*  clip qp to permissible range after
> vbv-lookahead estimation to avoid possible
> +                        * mispredictions by Rate Control pass 1
> statistics analysis */
> +                        q = clipQscale(curFrame, rce, q);
>                  }
>              }
> +
>              q = x265_clip3(lmin, lmax, q);
>          }
>          else
> @@ -2379,7 +2389,7 @@ double RateControl::clipQscale(Frame* curFrame,
> RateControlEntry* rce, double q)
>                      }
>                      /* Try to get the buffer not more than 80% filled,
> but don't set an impossible goal. */
>                      targetFill = x265_clip3(m_bufferSize * (1 - 0.2 *
> finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);
> -                    if (m_isCbr && bufferFillCur > targetFill &&
> !m_isSceneTransition)
> +                    if ((m_isCbr || m_2pass) && bufferFillCur >
> targetFill && !m_isSceneTransition)
>                      {
>                          q /= 1.01;
>                          loopTerminate |= 2;
> @@ -2432,7 +2442,7 @@ double RateControl::clipQscale(Frame* curFrame,
> RateControlEntry* rce, double q)
>           * lookahead vbv reduces its qscale by half its value. Be on
> safer side and avoid drastic
>           * qscale reductions for frames high in complexity */
>          bool mispredCheck = rce->movingAvgSum && m_currentSatd >=
> rce->movingAvgSum && q <= q0 / 2;
> -        if (!m_isCbr || (m_isAbr && mispredCheck))
> +        if (!m_isCbr || ((m_isAbr || m_2pass) && mispredCheck))
>              q = X265_MAX(q0, q);
>
>          if (m_rateFactorMaxIncrement)
> @@ -2442,7 +2452,7 @@ double RateControl::clipQscale(Frame* curFrame,
> RateControlEntry* rce, double q)
>              return x265_clip3(lmin, qmax, q);
>          }
>      }
> -    if (m_2pass)
> +    if (!curFrame && m_2pass)
>      {
>          double min = log(lmin);
>          double max = log(lmax);
> diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp
> index 4e52e584c..0adb0d0db 100644
> --- a/source/encoder/slicetype.cpp
> +++ b/source/encoder/slicetype.cpp
> @@ -1497,14 +1497,15 @@ void Lookahead::slicetypeDecide()
>          }
>      }
>
> -    if (m_lastNonB && !m_param->rc.bStatRead &&
> +    if (m_lastNonB &&
>          ((m_param->bFrameAdaptive && m_param->bframes) ||
>           m_param->rc.cuTree || m_param->scenecutThreshold ||
> m_param->bHistBasedSceneCut ||
>           (m_param->lookaheadDepth && m_param->rc.vbvBufferSize)))
>      {
> -        slicetypeAnalyse(frames, false);
> +        if(!m_param->rc.bStatRead)
> +            slicetypeAnalyse(frames, false);
>          bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
> m_param->rc.vbvMaxBitrate > 0;
> -        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
> +        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) ||
> m_param->bliveVBV2pass)
>          {
>              int numFrames;
>              for (numFrames = 0; numFrames < maxSearch; numFrames++)
> @@ -1749,7 +1750,7 @@ void Lookahead::slicetypeDecide()
>          }
>      }
>
> -    bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
> (m_param->rc.vbvBufferSize && m_param->lookaheadDepth)) &&
> !m_param->rc.bStatRead;
> +    bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
> (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));
>      if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))
>      {
>          m_inputLock.acquire();
> @@ -1764,9 +1765,10 @@ void Lookahead::slicetypeDecide()
>          m_inputLock.release();
>
>          frames[j + 1] = NULL;
> -        slicetypeAnalyse(frames, true);
> +        if (!m_param->rc.bStatRead)
> +            slicetypeAnalyse(frames, true);
>          bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
> m_param->rc.vbvMaxBitrate > 0;
> -        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
> +        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) ||
> m_param->bliveVBV2pass)
>          {
>              int numFrames;
>              for (numFrames = 0; numFrames < maxSearch; numFrames++)
> diff --git a/source/x265.h b/source/x265.h
> index 0ffa600b0..3fc464f6d 100644
> --- a/source/x265.h
> +++ b/source/x265.h
> @@ -1920,6 +1920,11 @@ typedef struct x265_param
>
>      /* Maxrate that could be signaled to the decoder. Default 0. API
> only. */
>      int      decoderVbvMaxRate;
> +
> +    /*Enables Qp tuning with respect to real time VBV buffer fullness in
> rate
> +    control 2 pass. Experimental.Default is disabled*/
> +    int      bliveVBV2pass;
> +
>  } x265_param;
>
>  /* x265_param_alloc:
> diff --git a/source/x265cli.cpp b/source/x265cli.cpp
> index 6e8e0e661..0cf2d815c 100755
> --- a/source/x265cli.cpp
> +++ b/source/x265cli.cpp
> @@ -221,6 +221,7 @@ namespace X265_NS {
>              "                                   - 3 : Nth pass,
> overwrites stats file\n");
>          H0("   --[no-]multi-pass-opt-analysis   Refine analysis in 2 pass
> based on analysis information from pass 1\n");
>          H0("   --[no-]multi-pass-opt-distortion Use distortion of CTU
> from pass 1 to refine qp in 2 pass\n");
> +        H0("   --[no-]vbv-live-multi-pass    Enable realtime VBV in rate
> control 2 pass.Default %s\n", OPT(param->bliveVBV2pass));
>          H0("   --stats                       Filename for stats file in
> multipass pass rate control. Default x265_2pass.log\n");
>          H0("   --[no-]analyze-src-pics       Motion estimation uses
> source frame planes. Default disable\n");
>          H0("   --[no-]slow-firstpass         Enable a slow first pass in
> a multipass rate control mode. Default %s\n",
> OPT(param->rc.bEnableSlowFirstPass));
> diff --git a/source/x265cli.h b/source/x265cli.h
> index 311f06935..3e2fd5e6d 100644
> --- a/source/x265cli.h
> +++ b/source/x265cli.h
> @@ -284,6 +284,8 @@ static const struct option long_options[] =
>      { "no-multi-pass-opt-analysis",    no_argument, NULL, 0 },
>      { "multi-pass-opt-distortion",     no_argument, NULL, 0 },
>      { "no-multi-pass-opt-distortion",  no_argument, NULL, 0 },
> +    { "vbv-live-multi-pass",           no_argument, NULL, 0 },
> +    { "no-vbv-live-multi-pass",        no_argument, NULL, 0 },
>      { "slow-firstpass",       no_argument, NULL, 0 },
>      { "no-slow-firstpass",    no_argument, NULL, 0 },
>      { "multi-pass-opt-rps",   no_argument, NULL, 0 },
> --
> 2.28.0.windows.1
>
> *Thanks,*
> *Kirithika*
>
>
> On Wed, Sep 9, 2020 at 10:52 AM Kirithika Kalirathnam <
> kirithika at multicorewareinc.com> wrote:
>
>> On Mon, Sep 7, 2020 at 6:19 PM Aruna Matheswaran <
>> aruna at multicorewareinc.com> wrote:
>>
>>>
>>>
>>> On Fri, Sep 4, 2020 at 5:44 PM Kirithika Kalirathnam <
>>> kirithika at multicorewareinc.com> wrote:
>>>
>>>> From f1391f094c9c3c0502624532f751219d126905aa Mon Sep 17 00:00:00 2001
>>>> From: Kirithika <kirithika at multicorewareinc.com>
>>>> Date: Fri, 28 Aug 2020 09:20:47 +0530
>>>> Subject: [PATCH] Add real-time VBV fullness based QP tuning in VBV 2
>>>> pass
>>>>
>>>> This commit enables real-time VBV fullness based 2nd pass QP  tuning.
>>>> Experimental feature.Default disabled
>>>> ---
>>>>  doc/reST/cli.rst               |   9 +++
>>>>  source/CMakeLists.txt          |   2 +-
>>>>  source/common/param.cpp        |  12 ++++
>>>>  source/encoder/ratecontrol.cpp | 100 ++++++++++++++++++---------------
>>>>  source/encoder/slicetype.cpp   |  14 +++--
>>>>  source/x265.h                  |   4 ++
>>>>  source/x265cli.cpp             |   1 +
>>>>  source/x265cli.h               |   2 +
>>>>  8 files changed, 92 insertions(+), 52 deletions(-)
>>>>
>>>> diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
>>>> index e6c628c36..2a4b25aca 100755
>>>> --- a/doc/reST/cli.rst
>>>> +++ b/doc/reST/cli.rst
>>>> @@ -1977,6 +1977,15 @@ Quality, rate control and rate distortion options
>>>>
>>>>     **Range of values:**  0 to 10
>>>>
>>>> +.. option:: --realtime-vbv-2pass, --no-realtime-vbv-2pass
>>>>
>>> [AM] Can we find a better alternate for the CLI option?
>>> --real-time-vbv-2-pass looks a bit long.
>>> The term 2pass is a little confusing. Technically it is multi-pass; not
>>> just 2pass.
>>>
>> Ok.I shall update the name to vbv-live-multi-pass,as it is
>> self-explanatory though it's a bit longer.
>>
>>> +
>>>> +   It enables the Qp tuning at frame level based on real time VBV
>>>> Buffer fullness
>>>> +   in the ratecontrol second pass to reduce the VBV violations.
>>>> +   It could only be enabled with rate control pass 2 encodes with VBV
>>>> and ABR
>>>> +   rate control mode.
>>>> +
>>>>
>>> [AM] why not for CRF rate-control mode?
>>>
>> Currently,we have tested the feature only for ABR case.We shall extend
>> this to CRF mode also in future.
>>
>>> +   Default disabled. **Experimental feature**
>>>> +
>>>>  Quantization Options
>>>>  ====================
>>>>
>>>> diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
>>>> index d9ed3983e..5738c861c 100755
>>>> --- a/source/CMakeLists.txt
>>>> +++ b/source/CMakeLists.txt
>>>> @@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)
>>>>  option(STATIC_LINK_CRT "Statically link C runtime for release builds"
>>>> OFF)
>>>>  mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)
>>>>  # X265_BUILD must be incremented each time the public API is changed
>>>> -set(X265_BUILD 196)
>>>> +set(X265_BUILD 197)
>>>>  configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
>>>>                 "${PROJECT_BINARY_DIR}/x265.def")
>>>>  configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
>>>> diff --git a/source/common/param.cpp b/source/common/param.cpp
>>>> index 845c38bd2..fc0425905 100755
>>>> --- a/source/common/param.cpp
>>>> +++ b/source/common/param.cpp
>>>> @@ -288,6 +288,7 @@ void x265_param_default(x265_param* param)
>>>>      param->bResetZoneConfig = 1;
>>>>      param->reconfigWindowSize = 0;
>>>>      param->decoderVbvMaxRate = 0;
>>>> +    param->rc.bRealtimeVBV2pass = 0;
>>>>
>>>>      /* Video Usability Information (VUI) */
>>>>      param->vui.aspectRatioIdc = 0;
>>>> @@ -1375,6 +1376,7 @@ int x265_param_parse(x265_param* p, const char*
>>>> name, const char* value)
>>>>              sscanf(value, "%d,%d,%d", &p->hmeRange[0],
>>>> &p->hmeRange[1], &p->hmeRange[2]);
>>>>              p->bEnableHME = true;
>>>>          }
>>>> +        OPT("realtime-vbv-2pass") p->rc.bRealtimeVBV2pass =
>>>> atobool(value);
>>>>          else
>>>>              return X265_PARAM_BAD_NAME;
>>>>      }
>>>> @@ -1817,6 +1819,15 @@ int x265_check_params(x265_param* param)
>>>>      CHECK(param->confWinRightOffset < 0, "Conformance Window Right
>>>> Offset must be 0 or greater");
>>>>      CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom
>>>> Offset must be 0 or greater");
>>>>      CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate.
>>>> Value can not be less than zero");
>>>> +    if (param->rc.bRealtimeVBV2pass)
>>>> +    {
>>>> +        CHECK((param->rc.bStatRead == 0), "Real time VBV in 2 pass
>>>> option requires rate control 2 pass to be enabled");
>>>> +        if ((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize
>>>> <= 0))
>>>> +        {
>>>> +            param->rc.bRealtimeVBV2pass = 0;
>>>> +            x265_log(param, X265_LOG_WARNING, "Real time VBV enabled
>>>> without VBV settings.Disabling real time VBV in 2 pass\n");
>>>> +        }
>>>> +    }
>>>>      return check_failed;
>>>>  }
>>>>
>>>> @@ -2593,6 +2604,7 @@ void x265_copy_params(x265_param* dst,
>>>> x265_param* src)
>>>>
>>>>      dst->confWinRightOffset = src->confWinRightOffset;
>>>>      dst->confWinBottomOffset = src->confWinBottomOffset;
>>>> +    dst->rc.bRealtimeVBV2pass = src->rc.bRealtimeVBV2pass;
>>>>  #ifdef SVT_HEVC
>>>>      memcpy(dst->svtHevcParam, src->svtHevcParam,
>>>> sizeof(EB_H265_ENC_CONFIGURATION));
>>>>  #endif
>>>> diff --git a/source/encoder/ratecontrol.cpp
>>>> b/source/encoder/ratecontrol.cpp
>>>> index 82d7c4f2a..ebf374759 100644
>>>> --- a/source/encoder/ratecontrol.cpp
>>>> +++ b/source/encoder/ratecontrol.cpp
>>>> @@ -1755,34 +1755,32 @@ double RateControl::rateEstimateQscale(Frame*
>>>> curFrame, RateControlEntry *rce)
>>>>                       g_sliceTypeToChar[m_sliceType],
>>>> g_sliceTypeToChar[rce->sliceType]);
>>>>          }
>>>>      }
>>>> -    else
>>>> +
>>>> +    if ((m_param->rc.bRealtimeVBV2pass && m_param->rc.rateControlMode
>>>> == X265_RC_ABR) || m_isAbr)
>>>>      {
>>>> -        if (m_isAbr)
>>>> +        int pos = m_sliderPos % s_slidingWindowFrames;
>>>> +        int addPos = (pos + s_slidingWindowFrames - 1) %
>>>> s_slidingWindowFrames;
>>>> +        if (m_sliderPos > s_slidingWindowFrames)
>>>>          {
>>>> -            int pos = m_sliderPos % s_slidingWindowFrames;
>>>> -            int addPos = (pos + s_slidingWindowFrames - 1) %
>>>> s_slidingWindowFrames;
>>>> -            if (m_sliderPos > s_slidingWindowFrames)
>>>> -            {
>>>> -                const static double base = pow(0.5,
>>>> s_slidingWindowFrames - 1);
>>>> -                m_movingAvgSum -= m_lastRemovedSatdCost * base;
>>>> -                m_movingAvgSum *= 0.5;
>>>> -                m_movingAvgSum += m_satdCostWindow[addPos];
>>>> -            }
>>>> -            else if (m_sliderPos == s_slidingWindowFrames)
>>>> -            {
>>>> -                m_movingAvgSum += m_satdCostWindow[addPos];
>>>> -            }
>>>> -            else if (m_sliderPos > 0)
>>>> -            {
>>>> -                m_movingAvgSum += m_satdCostWindow[addPos];
>>>> -                m_movingAvgSum *= 0.5;
>>>> -            }
>>>> -
>>>> -            rce->movingAvgSum = m_movingAvgSum;
>>>> -            m_lastRemovedSatdCost = m_satdCostWindow[pos];
>>>> -            m_satdCostWindow[pos] = rce->lastSatd;
>>>> -            m_sliderPos++;
>>>> +            const static double base = pow(0.5, s_slidingWindowFrames
>>>> - 1);
>>>> +            m_movingAvgSum -= m_lastRemovedSatdCost * base;
>>>> +            m_movingAvgSum *= 0.5;
>>>> +            m_movingAvgSum += m_satdCostWindow[addPos];
>>>> +        }
>>>> +        else if (m_sliderPos == s_slidingWindowFrames)
>>>> +        {
>>>> +            m_movingAvgSum += m_satdCostWindow[addPos];
>>>>          }
>>>> +        else if (m_sliderPos > 0)
>>>> +        {
>>>> +            m_movingAvgSum += m_satdCostWindow[addPos];
>>>> +            m_movingAvgSum *= 0.5;
>>>> +        }
>>>> +
>>>> +        rce->movingAvgSum = m_movingAvgSum;
>>>> +        m_lastRemovedSatdCost = m_satdCostWindow[pos];
>>>> +        m_satdCostWindow[pos] = rce->lastSatd;
>>>> +        m_sliderPos++;
>>>>      }
>>>>
>>>>      if (m_sliceType == B_SLICE)
>>>> @@ -1887,7 +1885,7 @@ double RateControl::rateEstimateQscale(Frame*
>>>> curFrame, RateControlEntry *rce)
>>>>                  qScale = x265_clip3(lqmin, lqmax, qScale);
>>>>              }
>>>>
>>>> -            if (!m_2pass)
>>>> +            if (!m_2pass || m_param->rc.bRealtimeVBV2pass)
>>>>              {
>>>>                  /* clip qp to permissible range after vbv-lookahead
>>>> estimation to avoid possible
>>>>                   * mispredictions by initial frame size predictors */
>>>> @@ -1955,7 +1953,9 @@ double RateControl::rateEstimateQscale(Frame*
>>>> curFrame, RateControlEntry *rce)
>>>>                  else
>>>>                      q /= zone->bitrateFactor;
>>>>              }
>>>> -            q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
>>>> abrBuffer);
>>>> +            /*Existing ABR conformance check may not be valid with
>>>> real time VBV*/
>>>> +            if(!m_param->rc.bRealtimeVBV2pass)
>>>> +                q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) /
>>>> abrBuffer);
>>>>              if (m_expectedBitsSum > 0)
>>>>              {
>>>>                  /* Adjust quant based on the difference between
>>>> @@ -1988,24 +1988,34 @@ double RateControl::rateEstimateQscale(Frame*
>>>> curFrame, RateControlEntry *rce)
>>>>
>>>>              if (m_isVbv)
>>>>              {
>>>> -                /* Do not overflow vbv */
>>>> -                double expectedSize = qScale2bits(rce, q);
>>>> -                double expectedVbv = m_bufferFill + m_bufferRate -
>>>> expectedSize;
>>>> -                double expectedFullness = rce->expectedVbv /
>>>> m_bufferSize;
>>>> -                double qmax = q * (2 - expectedFullness);
>>>> -                double sizeConstraint = 1 + expectedFullness;
>>>> -                qmax = X265_MAX(qmax, rce->newQScale);
>>>> -                if (expectedFullness < .05)
>>>> -                    qmax = lmax;
>>>> -                qmax = X265_MIN(qmax, lmax);
>>>> -                while (((expectedVbv <
>>>> rce->expectedVbv/sizeConstraint) && (q < qmax)) ||
>>>> +                if (!m_param->rc.bRealtimeVBV2pass)
>>>> +                {
>>>> +                    /* Do not overflow vbv */
>>>> +                    double expectedSize = qScale2bits(rce, q);
>>>> +                    double expectedVbv = m_bufferFill + m_bufferRate -
>>>> expectedSize;
>>>> +                    double expectedFullness = rce->expectedVbv /
>>>> m_bufferSize;
>>>> +                    double qmax = q * (2 - expectedFullness);
>>>> +                    double sizeConstraint = 1 + expectedFullness;
>>>> +                    qmax = X265_MAX(qmax, rce->newQScale);
>>>> +                    if (expectedFullness < .05)
>>>> +                        qmax = lmax;
>>>> +                    qmax = X265_MIN(qmax, lmax);
>>>> +                    while (((expectedVbv < rce->expectedVbv /
>>>> sizeConstraint) && (q < qmax)) ||
>>>>                          ((expectedVbv < 0) && (q < lmax)))
>>>> +                    {
>>>> +                        q *= 1.05;
>>>> +                        expectedSize = qScale2bits(rce, q);
>>>> +                        expectedVbv = m_bufferFill + m_bufferRate -
>>>> expectedSize;
>>>> +                    }
>>>> +                }
>>>> +                else
>>>>                  {
>>>> -                    q *= 1.05;
>>>> -                    expectedSize = qScale2bits(rce, q);
>>>> -                    expectedVbv = m_bufferFill + m_bufferRate -
>>>> expectedSize;
>>>> +                        /*  clip qp to permissible range after
>>>> vbv-lookahead estimation to avoid possible
>>>> +                        * mispredictions by Rate Control pass 1
>>>> statistics analysis */
>>>> +                        q = clipQscale(curFrame, rce, q);
>>>>                  }
>>>>              }
>>>> +
>>>>              q = x265_clip3(lmin, lmax, q);
>>>>          }
>>>>          else
>>>> @@ -2301,7 +2311,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>>> RateControlEntry* rce, double q)
>>>>      double lmin = m_lmin[rce->sliceType];
>>>>      double lmax = m_lmax[rce->sliceType];
>>>>      double q0 = q;
>>>> -    if (m_isVbv && m_currentSatd > 0 && curFrame)
>>>> +    if ((m_isVbv || m_param->rc.bRealtimeVBV2pass) && curFrame &&
>>>> m_currentSatd > 0 )
>>>>      {
>>>>
>>> [AM] Do we need to m_param->rc.bRealtimeVBV2pass check here? The call to
>>> clipQscale() is guarded by "m_param->rc.bRealtimeVBV2pass" from what I see.
>>>
>> yeah,the check is redundant and I shall remove it.
>>
>>>          if (m_param->lookaheadDepth || m_param->rc.cuTree ||
>>>>              (m_param->scenecutThreshold ||
>>>> m_param->bHistBasedSceneCut) ||
>>>> @@ -2379,7 +2389,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>>> RateControlEntry* rce, double q)
>>>>                      }
>>>>                      /* Try to get the buffer not more than 80% filled,
>>>> but don't set an impossible goal. */
>>>>                      targetFill = x265_clip3(m_bufferSize * (1 - 0.2 *
>>>> finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);
>>>> -                    if (m_isCbr && bufferFillCur > targetFill &&
>>>> !m_isSceneTransition)
>>>> +                    if ((m_isCbr || m_2pass) && bufferFillCur >
>>>> targetFill && !m_isSceneTransition)
>>>>                      {
>>>>                          q /= 1.01;
>>>>                          loopTerminate |= 2;
>>>> @@ -2432,7 +2442,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>>> RateControlEntry* rce, double q)
>>>>           * lookahead vbv reduces its qscale by half its value. Be on
>>>> safer side and avoid drastic
>>>>           * qscale reductions for frames high in complexity */
>>>>          bool mispredCheck = rce->movingAvgSum && m_currentSatd >=
>>>> rce->movingAvgSum && q <= q0 / 2;
>>>> -        if (!m_isCbr || (m_isAbr && mispredCheck))
>>>> +        if (!m_isCbr || ((m_isAbr || m_2pass) && mispredCheck))
>>>>
>>> [AM] Same question here.
>>>
>> m_isAbr is not set with 2 pass encodes.Hence I have added an additional
>> check here.
>>
>>>              q = X265_MAX(q0, q);
>>>>
>>>>          if (m_rateFactorMaxIncrement)
>>>> @@ -2442,7 +2452,7 @@ double RateControl::clipQscale(Frame* curFrame,
>>>> RateControlEntry* rce, double q)
>>>>              return x265_clip3(lmin, qmax, q);
>>>>          }
>>>>      }
>>>> -    if (m_2pass)
>>>> +    if (!curFrame && m_2pass)
>>>>      {
>>>>          double min = log(lmin);
>>>>          double max = log(lmax);
>>>> diff --git a/source/encoder/slicetype.cpp b/source/encoder/slicetype.cpp
>>>> index 4e52e584c..69f3b0ad1 100644
>>>> --- a/source/encoder/slicetype.cpp
>>>> +++ b/source/encoder/slicetype.cpp
>>>> @@ -1497,14 +1497,15 @@ void Lookahead::slicetypeDecide()
>>>>          }
>>>>      }
>>>>
>>>> -    if (m_lastNonB && !m_param->rc.bStatRead &&
>>>> +    if (m_lastNonB &&
>>>>          ((m_param->bFrameAdaptive && m_param->bframes) ||
>>>>           m_param->rc.cuTree || m_param->scenecutThreshold ||
>>>> m_param->bHistBasedSceneCut ||
>>>>           (m_param->lookaheadDepth && m_param->rc.vbvBufferSize)))
>>>>      {
>>>> -        slicetypeAnalyse(frames, false);
>>>> +        if(!m_param->rc.bStatRead)
>>>> +            slicetypeAnalyse(frames, false);
>>>>          bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
>>>> m_param->rc.vbvMaxBitrate > 0;
>>>> -        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>>> +        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>>> || m_param->rc.bRealtimeVBV2pass)
>>>>          {
>>>>              int numFrames;
>>>>              for (numFrames = 0; numFrames < maxSearch; numFrames++)
>>>> @@ -1749,7 +1750,7 @@ void Lookahead::slicetypeDecide()
>>>>          }
>>>>      }
>>>>
>>>> -    bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
>>>> (m_param->rc.vbvBufferSize && m_param->lookaheadDepth)) &&
>>>> !m_param->rc.bStatRead;
>>>> +    bool isKeyFrameAnalyse = (m_param->rc.cuTree ||
>>>> (m_param->rc.vbvBufferSize && m_param->lookaheadDepth));
>>>>      if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType))
>>>>      {
>>>>          m_inputLock.acquire();
>>>> @@ -1764,9 +1765,10 @@ void Lookahead::slicetypeDecide()
>>>>          m_inputLock.release();
>>>>
>>>>          frames[j + 1] = NULL;
>>>> -        slicetypeAnalyse(frames, true);
>>>> +        if (!m_param->rc.bStatRead)
>>>> +            slicetypeAnalyse(frames, true);
>>>>          bool bIsVbv = m_param->rc.vbvBufferSize > 0 &&
>>>> m_param->rc.vbvMaxBitrate > 0;
>>>> -        if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>>> +        if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv)
>>>> || m_param->rc.bRealtimeVBV2pass)
>>>>          {
>>>>              int numFrames;
>>>>              for (numFrames = 0; numFrames < maxSearch; numFrames++)
>>>> diff --git a/source/x265.h b/source/x265.h
>>>> index 0ffa600b0..bcd1d4e58 100644
>>>> --- a/source/x265.h
>>>> +++ b/source/x265.h
>>>> @@ -1486,6 +1486,10 @@ typedef struct x265_param
>>>>          /* internally enable if tune grain is set */
>>>>          int      bEnableConstVbv;
>>>>
>>>> +        /*Enables Qp tuning with respect to real time VBV buffer
>>>> fullness in rate
>>>> +        control 2 pass. Experimental.Default is disabled*/
>>>> +        int      bRealtimeVBV2pass;
>>>> +
>>>>
>>> [AM] Always add new param options to the end of the structure. Nested
>>> structures shall break backward compatibility.
>>>
>> Ok.I will add the new param at the end of param struct.
>>
>>>      } rc;
>>>>
>>>>      /*== Video Usability Information ==*/
>>>> diff --git a/source/x265cli.cpp b/source/x265cli.cpp
>>>> index 6e8e0e661..0b17a8d3a 100755
>>>> --- a/source/x265cli.cpp
>>>> +++ b/source/x265cli.cpp
>>>> @@ -221,6 +221,7 @@ namespace X265_NS {
>>>>              "                                   - 3 : Nth pass,
>>>> overwrites stats file\n");
>>>>          H0("   --[no-]multi-pass-opt-analysis   Refine analysis in 2
>>>> pass based on analysis information from pass 1\n");
>>>>          H0("   --[no-]multi-pass-opt-distortion Use distortion of CTU
>>>> from pass 1 to refine qp in 2 pass\n");
>>>> +        H0("   --[no-]realtime-vbv-2pass     Enable realtime VBV in
>>>> rate control 2 pass.Default %s\n", OPT(param->bLossless));
>>>>          H0("   --stats                       Filename for stats file
>>>> in multipass pass rate control. Default x265_2pass.log\n");
>>>>          H0("   --[no-]analyze-src-pics       Motion estimation uses
>>>> source frame planes. Default disable\n");
>>>>          H0("   --[no-]slow-firstpass         Enable a slow first pass
>>>> in a multipass rate control mode. Default %s\n",
>>>> OPT(param->rc.bEnableSlowFirstPass));
>>>> diff --git a/source/x265cli.h b/source/x265cli.h
>>>> index 311f06935..89840d9af 100644
>>>> --- a/source/x265cli.h
>>>> +++ b/source/x265cli.h
>>>> @@ -284,6 +284,8 @@ static const struct option long_options[] =
>>>>      { "no-multi-pass-opt-analysis",    no_argument, NULL, 0 },
>>>>      { "multi-pass-opt-distortion",     no_argument, NULL, 0 },
>>>>      { "no-multi-pass-opt-distortion",  no_argument, NULL, 0 },
>>>> +    { "realtime-vbv-2pass",           no_argument, NULL, 0 },
>>>> +    { "no-realtime-vbv-2pass",        no_argument, NULL, 0 },
>>>>
>>> [AM] Please add an entry for the new option in x265_param2string(); This
>>> will keep the info SEI updated.
>>>
>> Ok,will update
>>
>>>      { "slow-firstpass",       no_argument, NULL, 0 },
>>>>      { "no-slow-firstpass",    no_argument, NULL, 0 },
>>>>      { "multi-pass-opt-rps",   no_argument, NULL, 0 },
>>>> --
>>>> 2.28.0.windows.1
>>>>
>>>> *Thanks,*
>>>> *Kirithika*
>>>> _______________________________________________
>>>> x265-devel mailing list
>>>> x265-devel at videolan.org
>>>> https://mailman.videolan.org/listinfo/x265-devel
>>>>
>>>
>>>
>>> --
>>> Regards,
>>> *Aruna Matheswaran,*
>>> Video Codec Engineer,
>>> Media & AI analytics BU,
>>>
>>>
>>>
>>> _______________________________________________
>>> x265-devel mailing list
>>> x265-devel at videolan.org
>>> https://mailman.videolan.org/listinfo/x265-devel
>>>
>> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>


-- 
Regards,
*Aruna Matheswaran,*
Video Codec Engineer,
Media & AI analytics BU,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20200909/185ae67c/attachment-0001.html>


More information about the x265-devel mailing list