[x265] [PATCH] rc: apply maxAU size restrictions while encoding each frame

aarthi at multicorewareinc.com aarthi at multicorewareinc.com
Tue Sep 30 10:53:03 CEST 2014


# HG changeset patch
# User Aarthi Thirumalai
# Date 1411987402 -19800
#      Mon Sep 29 16:13:22 2014 +0530
# Node ID e87b6941e7f44af27ae797fb68696bacb74b12ac
# Parent  5a6845566d1492d29af29ecc0cf75d644994735c
rc: apply maxAU size restrictions while encoding each frame

diff -r 5a6845566d14 -r e87b6941e7f4 source/common/slice.h
--- a/source/common/slice.h	Mon Sep 29 17:37:47 2014 -0500
+++ b/source/common/slice.h	Mon Sep 29 16:13:22 2014 +0530
@@ -102,6 +102,8 @@
     bool    interlacedSourceFlag;
     bool    nonPackedConstraintFlag;
     bool    frameOnlyConstraintFlag;
+    uint32_t    minCrForLevel;
+    uint32_t    maxLumaSrForLevel;
 };
 
 struct HRDInfo
diff -r 5a6845566d14 -r e87b6941e7f4 source/encoder/level.cpp
--- a/source/encoder/level.cpp	Mon Sep 29 17:37:47 2014 -0500
+++ b/source/encoder/level.cpp	Mon Sep 29 16:13:22 2014 +0530
@@ -156,6 +156,9 @@
         }
 
         vps.ptl.levelIdc = levels[i].levelEnum;
+        vps.ptl.minCrForLevel = levels[i].minCompressionRatio;
+        vps.ptl.maxLumaSrForLevel = levels[i].maxLumaSamplesPerSecond;
+
         if (bitrate > levels[i].maxBitrateMain && bitrate <= levels[i].maxBitrateHigh &&
             levels[i].maxBitrateHigh != MAX_UINT)
             vps.ptl.tierFlag = Level::HIGH;
diff -r 5a6845566d14 -r e87b6941e7f4 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Mon Sep 29 17:37:47 2014 -0500
+++ b/source/encoder/ratecontrol.cpp	Mon Sep 29 16:13:22 2014 +0530
@@ -887,7 +887,7 @@
         for (int i = 0; i < m_numEntries; i++)
         {
             RateControlEntry *rce = &m_rce2Pass[i];
-            rce->newQScale = clipQscale(NULL, blurredQscale[i]); // check if needed
+            rce->newQScale = clipQscale(NULL, rce, blurredQscale[i]); // check if needed
             X265_CHECK(rce->newQScale >= 0, "new Qscale is negative\n");
             expectedBits += qScale2bits(rce, rce->newQScale);
         }
@@ -1093,6 +1093,27 @@
         m_predictedBits = m_totalBits;
         updateVbvPlan(enc);
         rce->bufferFill = m_bufferFill;
+
+        int mincr = enc->m_vps.ptl.minCrForLevel;
+        /* Profiles above Main10 don't require maxAU size check, so just set the maximum to a large value. */
+        if (enc->m_vps.ptl.profileIdc > Profile::MAIN10 || enc->m_vps.ptl.levelIdc == Level::NONE)
+            rce->frameSizeMaximum = 1e9;
+        else
+        {
+            /* The spec has a special case for the first frame. */
+            if (rce->encodeOrder == 0)
+            {
+                /* 1.5 * (Max( PicSizeInSamplesY, fR * MaxLumaSr) + MaxLumaSr * (AuCpbRemovalTime[ 0 ] -AuNominalRemovalTime[ 0 ])) ÷ MinCr */
+                double fr = 1. / 300;
+                int picSizeInSamplesY = m_param->sourceWidth * m_param->sourceHeight;
+                rce->frameSizeMaximum = 8 * 1.5 * (X265_MAX(picSizeInSamplesY, fr * enc->m_vps.ptl.maxLumaSrForLevel) + enc->m_vps.ptl.maxLumaSrForLevel * m_frameDuration) / mincr;
+            }
+            else
+            {
+                /* 1.5 * MaxLumaSr * (AuCpbRemovalTime[ n ] - AyCpbRemovalTime[ n - 1 ]) ÷ MinCr */
+                rce->frameSizeMaximum = 8 * 1.5 * enc->m_vps.ptl.maxLumaSrForLevel * m_frameDuration / mincr;
+            }
+        }
     }
     if (m_isAbr || m_2pass) // ABR,CRF
     {
@@ -1370,7 +1391,7 @@
         {
             if (m_leadingBframes > 5)
             {
-                qScale = clipQscale(pic, qScale);
+                qScale = clipQscale(pic, rce, qScale);
                 m_lastQScaleFor[m_sliceType] = qScale;
             }
             rce->frameSizePlanned = predictSize(&m_predBfromP, qScale, (double)m_leadingNoBSatd);
@@ -1379,6 +1400,9 @@
         {
             rce->frameSizePlanned = qScale2bits(rce, qScale);
         }
+        /* Limit planned size by MinCR */
+        if (m_isVbv)
+            rce->frameSizePlanned = X265_MIN(rce->frameSizePlanned, rce->frameSizeMaximum);
         rce->frameSizeEstimated = rce->frameSizePlanned;
         rce->newQScale = qScale;
         return qScale;
@@ -1527,7 +1551,7 @@
             }
             q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);
             rce->qpNoVbv = x265_qScale2qp(q);
-            q = clipQscale(pic, q);
+            q = clipQscale(pic, rce, q);
         }
         m_lastQScaleFor[m_sliceType] = q;
         if ((m_curSlice->m_poc == 0 || m_lastQScaleFor[P_SLICE] < q) && !(m_2pass && !m_isVbv))
@@ -1537,11 +1561,14 @@
             rce->frameSizePlanned = qScale2bits(rce, q);
         else
             rce->frameSizePlanned = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
-        rce->frameSizeEstimated = rce->frameSizePlanned;
+
         /* Always use up the whole VBV in this case. */
         if (m_singleFrameVbv)
             rce->frameSizePlanned = m_bufferRate;
-
+        /* Limit planned size by MinCR */
+        if (m_isVbv)
+            rce->frameSizePlanned = X265_MIN(rce->frameSizePlanned, rce->frameSizeMaximum);
+        rce->frameSizeEstimated = rce->frameSizePlanned;
         rce->newQScale = q;
         return q;
     }
@@ -1642,12 +1669,12 @@
     return (p->coeff * var + p->offset) / (q * p->count);
 }
 
-double RateControl::clipQscale(Frame* pic, double q)
+double RateControl::clipQscale(Frame* pic, RateControlEntry* rce, double q)
 {
     // B-frames are not directly subject to VBV,
     // since they are controlled by referenced P-frames' QPs.
     double q0 = q;
-    if (m_isVbv && m_currentSatd > 0)
+    if (m_isVbv && m_currentSatd > 0 && pic)
     {
         if (m_param->lookaheadDepth || m_param->rc.cuTree ||
             m_param->scenecutThreshold ||
@@ -1738,6 +1765,12 @@
 
             q = X265_MAX(q0, q);
         }
+
+        /* Apply MinCR restrictions */
+        double bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);
+        if (bits > rce->frameSizeMaximum)
+            q *= bits / rce->frameSizeMaximum;
+
          // Check B-frame complexity, and use up any bits that would
          // overflow before the next P-frame.
          if (m_leadingBframes <= 5 && m_sliceType == P_SLICE && !m_singleFrameVbv)
@@ -1934,9 +1967,10 @@
             accFrameBits = predictRowsSizeSum(pic, rce, qpVbv, encodedBitsSoFar);
         }
 
-        /* avoid VBV underflow */
+        /* avoid VBV underflow or MinCr violation */
         while ((qpVbv < qpAbsoluteMax)
-               && (rce->bufferFill - accFrameBits < m_bufferRate * maxFrameError))
+               && ((rce->bufferFill - accFrameBits < m_bufferRate * maxFrameError) ||
+                   (rce->frameSizeMaximum - accFrameBits < rce->frameSizeMaximum * maxFrameError)))
         {
             qpVbv += stepSize;
             accFrameBits = predictRowsSizeSum(pic, rce, qpVbv, encodedBitsSoFar);
diff -r 5a6845566d14 -r e87b6941e7f4 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h	Mon Sep 29 17:37:47 2014 -0500
+++ b/source/encoder/ratecontrol.h	Mon Sep 29 16:13:22 2014 +0530
@@ -99,6 +99,7 @@
     Predictor rowPreds[3][2];
     Predictor* rowPred[2];
     double frameSizeEstimated;  /* hold frameSize, updated from cu level vbv rc */
+    double frameSizeMaximum;  /* max frame Size according to minCR restrictions and level of the video */
     bool isActive;
     SEIPictureTiming *picTimingSEI;
     HRDTiming        *hrdTiming;
@@ -246,7 +247,7 @@
 
     void updateVbv(int64_t bits, RateControlEntry* rce);
     void updatePredictor(Predictor *p, double q, double var, double bits);
-    double clipQscale(Frame* pic, double q);
+    double clipQscale(Frame* pic, RateControlEntry* rce, double q);
     void updateVbvPlan(Encoder* enc);
     double predictSize(Predictor *p, double q, double var);
     void checkAndResetABR(RateControlEntry* rce, bool isFrameDone);


More information about the x265-devel mailing list