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