[x265] [PATCH] SBRC:Tune Qp based on segment size constraints

Karam Singh karam.singh at multicorewareinc.com
Wed Apr 3 03:15:26 UTC 2024


  Patch pushed to master branch.

Karam Singh
Senior Software (Video Codec) Engineer
MulticoreWare, India


On Thu, Mar 28, 2024 at 11:44 AM Kirithika Kalirathnam <
kirithika at multicorewareinc.com> wrote:

> From 17f2420bbd07db40b618e96a36586da909a26efb Mon Sep 17 00:00:00 2001
> From: Kirithika <kirithika at multicorewareinc.com>
> Date: Sat, 3 Feb 2024 08:28:18 +0530
> Subject: [PATCH] SBRC:Tune Qp based on segment size constraints
>
> This Commit adds support to tune QP for frames based on the segment
> size constraints
> ---
>  source/encoder/ratecontrol.cpp | 67 +++++++++++++++++++++++++++++++++-
>  source/encoder/ratecontrol.h   |  3 ++
>  2 files changed, 69 insertions(+), 1 deletion(-)
>
> diff --git a/source/encoder/ratecontrol.cpp
> b/source/encoder/ratecontrol.cpp
> index 099a03f0a..5c447d8ad 100644
> --- a/source/encoder/ratecontrol.cpp
> +++ b/source/encoder/ratecontrol.cpp
> @@ -260,6 +260,8 @@ RateControl::RateControl(x265_param& p, Encoder *top)
>      m_initVbv = false;
>      m_singleFrameVbv = 0;
>      m_rateTolerance = 1.0;
> +    m_encodedSegmentBits = 0;
> +    m_segDur = 0;
>
>      if (m_param->rc.vbvBufferSize)
>      {
> @@ -448,7 +450,9 @@ bool RateControl::init(const SPS& sps)
>
>      m_totalBits = 0;
>      m_encodedBits = 0;
> +    m_encodedSegmentBits = 0;
>      m_framesDone = 0;
> +    m_segDur = 0;
>      m_residualCost = 0;
>      m_partialResidualCost = 0;
>      m_amortizeFraction = 0.85;
> @@ -1351,6 +1355,16 @@ int RateControl::rateControlStart(Frame* curFrame,
> RateControlEntry* rce, Encode
>      m_predType = getPredictorType(curFrame->m_lowres.sliceType,
> m_sliceType);
>      rce->poc = m_curSlice->m_poc;
>
> +    if (m_param->bEnableSBRC)
> +    {
> +        if (rce->poc == 0 || (m_framesDone % m_param->keyframeMax == 0))
> +        {
> +            //Reset SBRC buffer
> +            m_encodedSegmentBits = 0;
> +            m_segDur = 0;
> +        }
> +    }
> +
>      if (!m_param->bResetZoneConfig && (rce->encodeOrder %
> m_param->reconfigWindowSize == 0))
>      {
>          int index = m_zoneBufferIdx % m_param->rc.zonefileCount;
> @@ -1974,8 +1988,16 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>              double minScenecutQscale
> =x265_qp2qScale(ABR_SCENECUT_INIT_QP_MIN);
>              m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale,
> m_lastQScaleFor[P_SLICE]);
>          }
> +
>          double qScale = x265_qp2qScale(q);
>          rce->qpNoVbv = q;
> +
> +        if (m_param->bEnableSBRC)
> +        {
> +            qScale = tuneQscaleForSBRC(curFrame, qScale);
> +            rce->qpNoVbv = x265_qScale2qp(qScale);
> +        }
> +
>          double lmin = 0, lmax = 0;
>          if (m_isGrainEnabled && m_isFirstMiniGop)
>          {
> @@ -2200,7 +2222,8 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>                      double rfConstant = m_param->rc.rfConstant;
>                      if (m_currentSatd < rce->movingAvgSum)
>                          rfConstant += 2;
> -                    rfConstant = (rce->sliceType == I_SLICE ? rfConstant
> - m_ipOffset :
> +                    double ipOffset = (curFrame->m_lowres.bScenecut ?
> m_ipOffset : m_ipOffset / 2.0);
> +                    rfConstant = (rce->sliceType == I_SLICE ? rfConstant
> - ipOffset :
>                          (rce->sliceType == B_SLICE ? rfConstant +
> m_pbOffset : rfConstant));
>                      double mbtree_offset = m_param->rc.cuTree ? (1.0 -
> m_param->rc.qCompress) * 13.5 : 0;
>                      double qComp = (m_param->rc.cuTree &&
> !m_param->rc.hevcAq) ? 0.99 : m_param->rc.qCompress;
> @@ -2288,6 +2311,9 @@ double RateControl::rateEstimateQscale(Frame*
> curFrame, RateControlEntry *rce)
>                  q = X265_MAX(minScenecutQscale, q);
>                  m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale,
> m_lastQScaleFor[P_SLICE]);
>              }
> +            if (m_param->bEnableSBRC)
> +                q = tuneQscaleForSBRC(curFrame, q);
> +
>              rce->qpNoVbv = x265_qScale2qp(q);
>              if (m_sliceType == P_SLICE)
>              {
> @@ -2469,6 +2495,43 @@ double RateControl::predictSize(Predictor *p,
> double q, double var)
>      return (p->coeff * var + p->offset) / (q * p->count);
>  }
>
> +double RateControl::tuneQscaleForSBRC(Frame* curFrame, double q)
> +{
> +    int depth = 0;
> +    int framesDoneInSeg = m_framesDone % m_param->keyframeMax;
> +    if (framesDoneInSeg + m_param->lookaheadDepth <= m_param->keyframeMax)
> +        depth = m_param->lookaheadDepth;
> +    else
> +        depth = m_param->keyframeMax - framesDoneInSeg;
> +    for (int iterations = 0; iterations < 1000; iterations++)
> +    {
> +        double totalDuration = m_segDur;
> +        double frameBitsTotal = m_encodedSegmentBits +
> predictSize(&m_pred[m_predType], q, (double)m_currentSatd);
> +        for (int i = 0; i < depth; i++)
> +        {
> +            int type = curFrame->m_lowres.plannedType[i];
> +            if (type == X265_TYPE_AUTO)
> +                break;
> +            int64_t satd = curFrame->m_lowres.plannedSatd[i] >>
> (X265_DEPTH - 8);
> +            type = IS_X265_TYPE_I(curFrame->m_lowres.plannedType[i]) ?
> I_SLICE : IS_X265_TYPE_B(curFrame->m_lowres.plannedType[i]) ? B_SLICE :
> P_SLICE;
> +            int predType =
> getPredictorType(curFrame->m_lowres.plannedType[i], type);
> +            double curBits = predictSize(&m_pred[predType], q,
> (double)satd);
> +            frameBitsTotal += curBits;
> +            totalDuration += m_frameDuration;
> +        }
> +        //Check for segment buffer overflow and adjust QP accordingly
> +        double segDur = m_param->keyframeMax / m_fps;
> +        double allowedSize = m_vbvMaxRate * segDur;
> +        double remDur = segDur - totalDuration;
> +        double remainingBits = frameBitsTotal / totalDuration * remDur;
> +        if (frameBitsTotal + remainingBits > 0.9 * allowedSize)
> +            q = q * 1.01;
> +        else
> +            break;
> +    }
> +    return q;
> +}
> +
>  double RateControl::clipQscale(Frame* curFrame, RateControlEntry* rce,
> double q)
>  {
>      // B-frames are not directly subject to VBV,
> @@ -3072,6 +3135,8 @@ int RateControl::rateControlEnd(Frame* curFrame,
> int64_t bits, RateControlEntry*
>          m_wantedBitsWindow += m_frameDuration * m_bitrate;
>          m_totalBits += bits - rce->rowTotalBits;
>          m_encodedBits += actualBits;
> +        m_encodedSegmentBits += actualBits;
> +        m_segDur += m_frameDuration;
>          int pos = m_sliderPos - m_param->frameNumThreads;
>          if (pos >= 0)
>              m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;
> diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
> index 7c3f60cc7..c3dc0406f 100644
> --- a/source/encoder/ratecontrol.h
> +++ b/source/encoder/ratecontrol.h
> @@ -191,6 +191,8 @@ public:
>      double  m_qCompress;
>      int64_t m_totalBits;        /* total bits used for already encoded
> frames (after ammortization) */
>      int64_t m_encodedBits;      /* bits used for encoded frames (without
> ammortization) */
> +    int64_t m_encodedSegmentBits;      /* bits used for encoded frames in
> a segment*/
> +    double  m_segDur;
>      double  m_fps;
>      int64_t m_satdCostWindow[50];
>      int64_t m_encodedBitsWindow[50];
> @@ -296,6 +298,7 @@ protected:
>      double rateEstimateQscale(Frame* pic, RateControlEntry *rce); // main
> logic for calculating QP based on ABR
>      double tuneAbrQScaleFromFeedback(double qScale);
>      double tuneQScaleForZone(RateControlEntry *rce, double qScale); //
> Tune qScale to adhere to zone budget
> +    double tuneQscaleForSBRC(Frame* curFrame, double q); // Tune qScale
> to adhere to segment budget
>      void   accumPQpUpdate();
>
>      int    getPredictorType(int lowresSliceType, int sliceType);
> --
> 2.28.0.windows.1
>
> *Thanks,*
> *Kirithika*
> _______________________________________________
> 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/20240403/6de09db8/attachment.htm>


More information about the x265-devel mailing list