[x265] [PATCH] rc: update vbv for all b frames

Steve Borho steve at borho.org
Thu Jul 31 22:04:13 CEST 2014


# HG changeset patch
# User Santhoshini Sekar <santhoshini at multicorewareinc.com>
# Date 1406785082 -19800
#      Thu Jul 31 11:08:02 2014 +0530
# Node ID e85b0aaa64e4aaccdfd37de92e14d91a53a789ea
# Parent  88a18a365d56cb6ef67df157f16ff52f5ccbd1db
rc: update vbv for all b frames

HEVC is complex (and slow) enough that we can afford to update/plan the VBV
buffer states for all frames, not just I and P. The leads to smoother rate
control, particularly when there are large stretches of B frames, and less
(over) compensation is necessary for P frames.

diff -r 88a18a365d56 -r e85b0aaa64e4 source/common/lowres.cpp
--- a/source/common/lowres.cpp	Thu Jul 31 16:49:02 2014 +0530
+++ b/source/common/lowres.cpp	Thu Jul 31 11:08:02 2014 +0530
@@ -135,6 +135,7 @@
     sliceType = type;
     frameNum = poc;
     leadingBframes = 0;
+    indB = 0;
     satdCost = (int64_t)-1;
     memset(costEst, -1, sizeof(costEst));
     memset(weightedCostDelta, 0, sizeof(weightedCostDelta));
diff -r 88a18a365d56 -r e85b0aaa64e4 source/common/lowres.h
--- a/source/common/lowres.h	Thu Jul 31 16:49:02 2014 +0530
+++ b/source/common/lowres.h	Thu Jul 31 11:08:02 2014 +0530
@@ -121,8 +121,11 @@
     uint16_t(*lowresCosts[X265_BFRAME_MAX + 2][X265_BFRAME_MAX + 2]);
     int32_t*  lowresMvCosts[2][X265_BFRAME_MAX + 1];
     MV*       lowresMvs[2][X265_BFRAME_MAX + 1];
+
+    /* used for vbvLookahead */
     int       plannedType[X265_LOOKAHEAD_MAX + 1];
     int64_t   plannedSatd[X265_LOOKAHEAD_MAX + 1];
+    int       indB;
     int       bframes;
 
     /* rate control / adaptive quant data */
@@ -132,6 +135,7 @@
     uint64_t  wp_ssd[3];       // This is different than SSDY, this is sum(pixel^2) - sum(pixel)^2 for entire frame
     uint64_t  wp_sum[3];
 
+    /* cutree intermediate data */
     uint16_t* propagateCost;
     double    weightedCostDelta[X265_BFRAME_MAX + 2];
 
diff -r 88a18a365d56 -r e85b0aaa64e4 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Thu Jul 31 16:49:02 2014 +0530
+++ b/source/encoder/ratecontrol.cpp	Thu Jul 31 11:08:02 2014 +0530
@@ -1368,6 +1368,11 @@
             q += m_pbOffset;
         rce->qpNoVbv = q;
         double qScale = x265_qp2qScale(q);
+        if (m_bframes > 5 && m_isVbv)
+        {
+            qScale = clipQscale(pic, qScale);
+            m_lastQScaleFor[m_sliceType] = qScale;
+        }
         rce->frameSizePlanned = predictSize(&m_predBfromP, qScale, (double)m_leadingNoBSatd);
         rce->frameSizeEstimated = rce->frameSizePlanned;
         rce->newQScale = qScale;
@@ -1652,11 +1657,15 @@
             for (int iterations = 0; iterations < 1000 && loopTerminate != 3; iterations++)
             {
                 double frameQ[3];
-                double curBits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
+                double curBits;
+                if (m_sliceType == B_SLICE)
+                    curBits = predictSize(&m_predBfromP, q, (double)m_currentSatd);
+                else
+                    curBits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
                 double bufferFillCur = m_bufferFill - curBits;
                 double targetFill;
                 double totalDuration = 0;
-                frameQ[P_SLICE] = m_sliceType == I_SLICE ? q * m_param->rc.ipFactor : q;
+                frameQ[P_SLICE] = m_sliceType == I_SLICE ? q * m_param->rc.ipFactor : (m_sliceType == B_SLICE ? q / m_param->rc.pbFactor : q);
                 frameQ[B_SLICE] = frameQ[P_SLICE] * m_param->rc.pbFactor;
                 frameQ[I_SLICE] = frameQ[P_SLICE] / m_param->rc.ipFactor;
                 /* Loop over the planned future frames. */
@@ -1695,7 +1704,7 @@
         else
         {
             /* Fallback to old purely-reactive algorithm: no lookahead. */
-            if ((m_sliceType == P_SLICE ||
+            if ((m_sliceType == P_SLICE || m_sliceType == B_SLICE ||
                     (m_sliceType == I_SLICE && m_lastNonBPictType == I_SLICE)) &&
                 m_bufferFill / m_bufferSize < 0.5)
             {
@@ -1726,25 +1735,6 @@
             q = X265_MAX(q0, q);
         }
 
-        // Check B-frame complexity, and use up any bits that would
-        // overflow before the next P-frame.
-        if (m_sliceType == P_SLICE && !m_singleFrameVbv)
-        {
-            int nb = m_bframes;
-            double bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
-            double bbits = predictSize(&m_predBfromP, q * m_param->rc.pbFactor, (double)m_currentSatd);
-            double space;
-            if (bbits > m_bufferRate)
-                nb = 0;
-            double pbbits = nb * bbits;
-
-            space = m_bufferFill + (1 + nb) * m_bufferRate - m_bufferSize;
-            if (pbbits < space)
-            {
-                q *= X265_MAX(pbbits / space, bits / (0.5 * m_bufferSize));
-            }
-            q = X265_MAX(q0 / 2, q);
-        }
         if (!m_isCbr)
             q = X265_MAX(q0, q);
 
diff -r 88a18a365d56 -r e85b0aaa64e4 source/encoder/slicetype.cpp
--- a/source/encoder/slicetype.cpp	Thu Jul 31 16:49:02 2014 +0530
+++ b/source/encoder/slicetype.cpp	Thu Jul 31 11:08:02 2014 +0530
@@ -532,13 +532,13 @@
 void Lookahead::vbvLookahead(Lowres **frames, int numFrames, int keyframe)
 {
     int prevNonB = 0, curNonB = 1, idx = 0;
+    bool isNextNonB = false;
 
     while (curNonB < numFrames && frames[curNonB]->sliceType == X265_TYPE_B)
-    {
         curNonB++;
-    }
 
     int nextNonB = keyframe ? prevNonB : curNonB;
+    int nextB = keyframe ? prevNonB + 1 : curNonB + 1;
 
     while (curNonB < numFrames + !keyframe)
     {
@@ -557,12 +557,33 @@
             frames[nextNonB]->plannedType[idx] = X265_TYPE_B;
         }
 
+        for (int i = nextB; i <= curNonB; i++)
+        {
+            for (int j = frames[i]->indB + i + 1; j <= curNonB; j++, frames[i]->indB++)
+            {
+                if (j == curNonB)
+                {
+                    if (isNextNonB)
+                    {
+                        int p0 = IS_X265_TYPE_I(frames[curNonB]->sliceType) ? curNonB : prevNonB;
+                        frames[i]->plannedSatd[frames[i]->indB] = vbvFrameCost(frames, p0, curNonB, curNonB);
+                        frames[i]->plannedType[frames[i]->indB] = frames[curNonB]->sliceType;
+                    }
+                }
+                else
+                {
+                    frames[i]->plannedSatd[frames[i]->indB] = vbvFrameCost(frames, prevNonB, curNonB, j);
+                    frames[i]->plannedType[frames[i]->indB] = X265_TYPE_B;
+                }
+            }
+            if (i == curNonB && !isNextNonB)
+                isNextNonB = true;
+        }
+
         prevNonB = curNonB;
         curNonB++;
         while (curNonB <= numFrames && frames[curNonB]->sliceType == X265_TYPE_B)
-        {
             curNonB++;
-        }
     }
 
     frames[nextNonB]->plannedType[idx] = X265_TYPE_AUTO;


More information about the x265-devel mailing list