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

Kirithika Kalirathnam kirithika at multicorewareinc.com
Thu Mar 28 06:14:35 UTC 2024


>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*
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240328/3cf0adc3/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: patch-SBRC-latest.diff
Type: application/octet-stream
Size: 7399 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20240328/3cf0adc3/attachment-0001.obj>


More information about the x265-devel mailing list