[x265] [PATCH 2 of 2] rc: implement 2 pass CRF, when vbv is enabled

Aarthi Priya Thirumalai aarthi at multicorewareinc.com
Mon Nov 23 12:37:46 CET 2015


pls ignore the previous patch. It has a few bugs while merging.
here is the fixed one :


# HG changeset patch
# User Divya Manivannan <divya at multicorewareinc.com>
# Date 1448267770 -19800
#      Mon Nov 23 14:06:10 2015 +0530
# Branch stable
# Node ID 0c49c9cc75e4c1ef9534a28b49b97b9107636f5d
# Parent  6b308775b6f065ea5002a76a40aa6f5d81e8ee50
rc: implement 2 pass CRF, when vbv is enabled.

Allow CRF with VBV in 2nd pass to increase the quality of capped CRF in the
first pass.

diff -r 6b308775b6f0 -r 0c49c9cc75e4 source/common/param.cpp
--- a/source/common/param.cpp Mon Nov 23 12:26:45 2015 +0530
+++ b/source/common/param.cpp Mon Nov 23 14:06:10 2015 +0530
@@ -1170,7 +1170,7 @@
         CHECK(0 > param->noiseReductionIntra || param->noiseReductionIntra
> 2000, "Valid noise reduction range 0 - 2000");
     if (param->noiseReductionInter)
         CHECK(0 > param->noiseReductionInter || param->noiseReductionInter
> 2000, "Valid noise reduction range 0 - 2000");
-    CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead,
+    CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead
&& param->rc.vbvMaxBitrate == 0,
           "Constant rate-factor is incompatible with 2pass");
     CHECK(param->rc.rateControlMode == X265_RC_CQP && param->rc.bStatRead,
           "Constant QP is incompatible with 2pass");
diff -r 6b308775b6f0 -r 0c49c9cc75e4 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Mon Nov 23 12:26:45 2015 +0530
+++ b/source/encoder/ratecontrol.cpp Mon Nov 23 14:06:10 2015 +0530
@@ -142,6 +142,8 @@
     rce->expectedVbv = rce2Pass->expectedVbv;
     rce->blurredComplexity = rce2Pass->blurredComplexity;
     rce->sliceType = rce2Pass->sliceType;
+    rce->qpNoVbv = rce2Pass->qpNoVbv;
+    rce->newQp = rce2Pass->newQp;
 }

 }  // end anonymous namespace
@@ -205,7 +207,7 @@
             m_rateFactorMaxDecrement = m_param->rc.rfConstant -
m_param->rc.rfConstantMin;
     }
     m_isAbr = m_param->rc.rateControlMode != X265_RC_CQP &&
!m_param->rc.bStatRead;
-    m_2pass = m_param->rc.rateControlMode == X265_RC_ABR &&
m_param->rc.bStatRead;
+    m_2pass = (m_param->rc.rateControlMode == X265_RC_ABR ||
m_param->rc.vbvMaxBitrate > 0) && m_param->rc.bStatRead;
     m_bitrate = m_param->rc.bitrate * 1000;
     m_frameDuration = (double)m_param->fpsDenom / m_param->fpsNum;
     m_qp = m_param->rc.qp;
@@ -488,6 +490,12 @@
                  x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2 pass
cannot be allocated\n");
                  return false;
             }
+            m_encOrder = X265_MALLOC(int, m_numEntries);
+            if (!m_encOrder)
+            {
+                x265_log(m_param, X265_LOG_ERROR, "Encode order for 2 pass
cannot be allocated\n");
+                return false;
+            }
             /* init all to skipped p frames */
             for (int i = 0; i < m_numEntries; i++)
             {
@@ -504,6 +512,7 @@
             {
                 RateControlEntry *rce;
                 int frameNumber;
+                int encodeOrder;
                 char picType;
                 int e;
                 char *next;
@@ -511,13 +520,14 @@
                 next = strstr(p, ";");
                 if (next)
                     *next++ = 0;
-                e = sscanf(p, " in:%d ", &frameNumber);
+                e = sscanf(p, " in:%d out:%d", &frameNumber, &encodeOrder);
                 if (frameNumber < 0 || frameNumber >= m_numEntries)
                 {
                     x265_log(m_param, X265_LOG_ERROR, "bad frame number
(%d) at stats line %d\n", frameNumber, i);
                     return false;
                 }
-                rce = &m_rce2Pass[frameNumber];
+                rce = &m_rce2Pass[encodeOrder];
+                m_encOrder[frameNumber] = encodeOrder;
                 e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf
q-noVbv:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
                        &picType, &qpRc, &qpAq, &qNoVbv, &rce->coeffBits,
                        &rce->mvBits, &rce->miscBits, &rce->iCuCount,
&rce->pCuCount,
@@ -538,7 +548,7 @@
                     x265_log(m_param, X265_LOG_ERROR, "statistics are
damaged at line %d, parser out=%d\n", i, e);
                     return false;
                 }
-                rce->qScale = x265_qp2qScale(qpRc);
+                rce->qScale = rce->newQScale = x265_qp2qScale(qpRc);
                 totalQpAq += qpAq;
                 rce->qpNoVbv = qNoVbv;
                 rce->qpaRc = qpRc;
@@ -546,8 +556,7 @@
                 p = next;
             }
             X265_FREE(statsBuf);
-
-            if (m_param->rc.rateControlMode == X265_RC_ABR)
+            if (m_param->rc.rateControlMode == X265_RC_ABR ||
m_param->rc.vbvMaxBitrate > 0)
             {
                 if (!initPass2())
                     return false;
@@ -630,11 +639,8 @@

     #undef MAX_DURATION
 }
-
-bool RateControl::initPass2()
+bool RateControl::analyseABR2Pass(int startIndex, int endIndex, uint64_t
allAvailableBits)
 {
-    uint64_t allConstBits = 0;
-    uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. *
m_numEntries * m_frameDuration);
     double rateFactor, stepMult;
     double qBlur = m_param->rc.qblur;
     double cplxBlur = m_param->rc.complexityBlur;
@@ -643,30 +649,19 @@
     double *qScale, *blurredQscale;
     double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);
     double clippedDuration = CLIP_DURATION(m_frameDuration) /
BASE_FRAME_DURATION;
-
-    /* find total/average complexity & const_bits */
-    for (int i = 0; i < m_numEntries; i++)
-        allConstBits += m_rce2Pass[i].miscBits;
-
-    if (allAvailableBits < allConstBits)
-    {
-        x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too low.
estimated minimum is %d kbps\n",
-                 (int)(allConstBits * m_fps / m_numEntries * 1000.));
-        return false;
-    }
-
+    int framesCount = endIndex - startIndex + 1;
     /* Blur complexities, to reduce local fluctuation of QP.
      * We don't blur the QPs directly, because then one very simple frame
      * could drag down the QP of a nearby complex frame and give it more
      * bits than intended. */
-    for (int i = 0; i < m_numEntries; i++)
+    for (int i = startIndex; i <= endIndex; i++)
     {
         double weightSum = 0;
         double cplxSum = 0;
         double weight = 1.0;
         double gaussianWeight;
         /* weighted average of cplx of future frames */
-        for (int j = 1; j < cplxBlur * 2 && j < m_numEntries - i; j++)
+        for (int j = 1; j < cplxBlur * 2 && j <= endIndex - i; j++)
         {
             RateControlEntry *rcj = &m_rce2Pass[i + j];
             weight *= 1 - pow(rcj->iCuCount / m_ncu, 2);
@@ -690,11 +685,10 @@
         }
         m_rce2Pass[i].blurredComplexity = cplxSum / weightSum;
     }
-
-    CHECKED_MALLOC(qScale, double, m_numEntries);
+    CHECKED_MALLOC(qScale, double, framesCount);
     if (filterSize > 1)
     {
-        CHECKED_MALLOC(blurredQscale, double, m_numEntries);
+        CHECKED_MALLOC(blurredQscale, double, framesCount);
     }
     else
         blurredQscale = qScale;
@@ -705,9 +699,8 @@
      * because qscale2bits is not invertible, but we can start with the
simple
      * approximation of scaling the 1st pass by the ratio of bitrates.
      * The search range is probably overkill, but speed doesn't matter
here. */
-
     expectedBits = 1;
-    for (int i = 0; i < m_numEntries; i++)
+    for (int i = startIndex; i <= endIndex; i++)
     {
         RateControlEntry* rce = &m_rce2Pass[i];
         double q = getQScale(rce, 1.0);
@@ -784,12 +777,10 @@
     X265_FREE(qScale);
     if (filterSize > 1)
         X265_FREE(blurredQscale);
-
     if (m_isVbv)
-        if (!vbv2Pass(allAvailableBits))
+    if (!vbv2Pass(allAvailableBits, endIndex, startIndex))
             return false;
-    expectedBits = countExpectedBits();
-
+    expectedBits = countExpectedBits(startIndex, endIndex);
     if (fabs(expectedBits / allAvailableBits - 1.0) > 0.01)
     {
         double avgq = 0;
@@ -822,7 +813,125 @@
     return false;
 }

-bool RateControl::vbv2Pass(uint64_t allAvailableBits)
+bool RateControl::initPass2()
+{
+    uint64_t allConstBits = 0, allCodedBits = 0;
+    uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. *
m_numEntries * m_frameDuration);
+    int startIndex, framesCount, endIndex, cnt;
+    int fps = (int)(m_fps + 0.5);
+    startIndex = endIndex = framesCount = 0;
+    allAvailableBits = uint64_t(m_param->rc.vbvMaxBitrate * 1000. *
m_numEntries * m_frameDuration);
+    bool isQpModified = true;
+    int diffQp = 0;
+    int64_t targetBits = 0;
+    int64_t expectedBits = 0;
+    for (startIndex = 0, endIndex = 0; endIndex < m_numEntries; endIndex++)
+    {
+        allConstBits += m_rce2Pass[endIndex].miscBits;
+        allCodedBits += m_rce2Pass[endIndex].coeffBits +
m_rce2Pass[endIndex].mvBits;
+        if (m_param->rc.rateControlMode == X265_RC_CRF)
+        {
+            framesCount = endIndex - startIndex + 1;
+            diffQp += int (m_rce2Pass[endIndex].qpaRc -
m_rce2Pass[endIndex].qpNoVbv);
+            if (framesCount > fps)
+                diffQp -= int (m_rce2Pass[endIndex - fps].qpaRc -
m_rce2Pass[endIndex - fps].qpNoVbv);
+            if (framesCount >= fps)
+            {
+                if (diffQp >= 1)
+                {
+                    if (!isQpModified && endIndex > fps)
+                    {
+                        double factor = 2;
+                        double step = 0;
+                        for (int start = endIndex; start <= endIndex + fps
- 1 && start < m_numEntries; start++)
+                        {
+                            RateControlEntry *rce = &m_rce2Pass[start];
+                            targetBits += qScale2bits(rce,
x265_qp2qScale(rce->qpNoVbv));
+                            expectedBits += qScale2bits(rce, rce->qScale);
+                        }
+                        if (expectedBits < 0.95 * targetBits)
+                        {
+                            isQpModified = true;
+                            while (endIndex + fps < m_numEntries)
+                            {
+                                step = pow(2, factor / 6.0);
+                                expectedBits = 0;
+                                for (int start = endIndex; start <=
endIndex + fps - 1; start++)
+                                {
+                                    RateControlEntry *rce =
&m_rce2Pass[start];
+                                    rce->newQScale = rce->qScale / step;
+                                    X265_CHECK(rce->newQScale >= 0, "new
Qscale is negative\n");
+                                    expectedBits += qScale2bits(rce,
rce->newQScale);
+                                    rce->newQp =
x265_qScale2qp(rce->newQScale);
+                                }
+                                if (expectedBits >= targetBits && step > 1)
+                                    factor *= 0.90;
+                                else
+                                    break;
+                            }
+
+                            if (m_isVbv && endIndex + fps < m_numEntries)
+                                if (!vbv2Pass(targetBits, endIndex + fps -
1, endIndex))
+                                    return false;
+
+                            double prevFactor = factor;
+                            targetBits = 0;
+                            expectedBits = 0;
+
+                            for (int start = endIndex - fps; start <=
endIndex - 1; start++)
+                            {
+                                RateControlEntry *rce = &m_rce2Pass[start];
+                                targetBits += qScale2bits(rce,
x265_qp2qScale(rce->qpNoVbv));
+                            }
+                            while (1)
+                            {
+                                step = pow(2, factor / 6.0);
+                                expectedBits = 0;
+                                for (int start = endIndex - fps; start <=
endIndex - 1; start++)
+                                {
+                                    RateControlEntry *rce =
&m_rce2Pass[start];
+                                    rce->newQScale = rce->qScale * step;
+                                    X265_CHECK(rce->newQScale >= 0, "new
Qscale is negative\n");
+                                    expectedBits += qScale2bits(rce,
rce->newQScale);
+                                    rce->newQp =
x265_qScale2qp(rce->newQScale);
+                                }
+                                if (expectedBits > targetBits && step > 1)
+                                    factor *= 1.1;
+                                else
+                                     break;
+                            }
+                            if (m_isVbv)
+                            if (!vbv2Pass(targetBits, endIndex - 1,
endIndex - fps))
+                                    return false;
+                            diffQp = 0;
+                            startIndex = endIndex + 1;
+                            targetBits = expectedBits = 0;
+                        }
+                        else
+                            targetBits = expectedBits = 0;
+                    }
+                }
+                else
+                    isQpModified = false;
+            }
+        }
+    }
+
+    if (m_param->rc.rateControlMode == X265_RC_ABR)
+    {
+        if (allAvailableBits < allConstBits)
+        {
+            x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too
low. estimated minimum is %d kbps\n",
+                     (int)(allConstBits * m_fps / framesCount * 1000.));
+            return false;
+        }
+        if (!analyseABR2Pass(0, m_numEntries - 1, allAvailableBits))
+            return false;
+    }
+    return true;
+}
+
+bool RateControl::vbv2Pass(uint64_t allAvailableBits, int endPos, int
startPos)
 {
     /* for each interval of bufferFull .. underflow, uniformly increase
the qp of all
      * frames in the interval until either buffer is full at some
intermediate frame or the
@@ -848,10 +957,10 @@
         {   /* not first iteration */
             adjustment = X265_MAX(X265_MIN(expectedBits /
allAvailableBits, 0.999), 0.9);
             fills[-1] = m_bufferSize * m_param->rc.vbvBufferInit;
-            t0 = 0;
+            t0 = startPos;
             /* fix overflows */
             adjMin = 1;
-            while (adjMin && findUnderflow(fills, &t0, &t1, 1))
+            while (adjMin && findUnderflow(fills, &t0, &t1, 1, endPos))
             {
                 adjMin = fixUnderflow(t0, t1, adjustment, MIN_QPSCALE,
MAX_MAX_QPSCALE);
                 t0 = t1;
@@ -862,20 +971,16 @@
         t0 = 0;
         /* fix underflows -- should be done after overflow, as we'd better
undersize target than underflowing VBV */
         adjMax = 1;
-        while (adjMax && findUnderflow(fills, &t0, &t1, 0))
+        while (adjMax && findUnderflow(fills, &t0, &t1, 0, endPos))
             adjMax = fixUnderflow(t0, t1, 1.001, MIN_QPSCALE,
MAX_MAX_QPSCALE );
-
-        expectedBits = countExpectedBits();
+        expectedBits = countExpectedBits(startPos, endPos);
     }
-    while ((expectedBits < .995 * allAvailableBits) &&
((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)));
-
+    while ((expectedBits < .995 * allAvailableBits) &&
((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)) &&
!(m_param->rc.rateControlMode == X265_RC_CRF));
     if (!adjMax)
         x265_log(m_param, X265_LOG_WARNING, "vbv-maxrate issue, qpmax or
vbv-maxrate too low\n");
-
     /* store expected vbv filling values for tracking when encoding */
-    for (int i = 0; i < m_numEntries; i++)
+    for (int i = startPos; i <= endPos; i++)
         m_rce2Pass[i].expectedVbv = m_bufferSize - fills[i];
-
     X265_FREE(fills - 1);
     return true;

@@ -915,9 +1020,10 @@
                 m_param->bframes = 1;
             return X265_TYPE_AUTO;
         }
-        int frameType = m_rce2Pass[frameNum].sliceType == I_SLICE ?
(frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR)
-                            : m_rce2Pass[frameNum].sliceType == P_SLICE ?
X265_TYPE_P
-                            : (m_rce2Pass[frameNum].sliceType == B_SLICE
&& m_rce2Pass[frameNum].keptAsRef? X265_TYPE_BREF : X265_TYPE_B);
+        int index = m_encOrder[frameNum];
+        int frameType = m_rce2Pass[index].sliceType == I_SLICE ? (frameNum
> 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR)
+                        : m_rce2Pass[index].sliceType == P_SLICE ?
X265_TYPE_P
+                        : (m_rce2Pass[index].sliceType == B_SLICE &&
m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B);
         return frameType;
     }
     else
@@ -968,7 +1074,8 @@
     if (m_param->rc.bStatRead)
     {
         X265_CHECK(rce->poc >= 0 && rce->poc < m_numEntries, "bad encode
ordinal\n");
-        copyRceData(rce, &m_rce2Pass[rce->poc]);
+        int index = m_encOrder[rce->poc];
+        copyRceData(rce, &m_rce2Pass[index]);
     }
     rce->isActive = true;
     bool isRefFrameScenecut = m_sliceType!= I_SLICE &&
m_curSlice->m_refPicList[0][0]->m_lowres.bScenecut == 1;
@@ -1032,6 +1139,16 @@
             }
         }
     }
+    if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == X265_RC_CRF)
+    {
+        rce->qScale = rce->newQScale;
+        rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq =
x265_qScale2qp(rce->newQScale);
+        m_qp = int(rce->qpaRc + 0.5);
+        rce->frameSizePlanned = qScale2bits(rce, rce->qScale);
+        m_framesDone++;
+        return m_qp;
+    }
+
     if (m_isAbr || m_2pass) // ABR,CRF
     {
         if (m_isAbr || m_isVbv)
@@ -1203,11 +1320,10 @@
     }
     return q;
 }
-
-double RateControl::countExpectedBits()
+double RateControl::countExpectedBits(int startPos, int endPos)
 {
     double expectedBits = 0;
-    for( int i = 0; i < m_numEntries; i++ )
+    for (int i = startPos; i <= endPos; i++)
     {
         RateControlEntry *rce = &m_rce2Pass[i];
         rce->expectedBits = (uint64_t)expectedBits;
@@ -1215,8 +1331,7 @@
     }
     return expectedBits;
 }
-
-bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over)
+bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over,
int endPos)
 {
     /* find an interval ending on an overflow or underflow (depending on
whether
      * we're adding or removing bits), and starting on the earliest frame
that
@@ -1226,7 +1341,7 @@
     double fill = fills[*t0 - 1];
     double parity = over ? 1. : -1.;
     int start = -1, end = -1;
-    for (int i = *t0; i < m_numEntries; i++)
+    for (int i = *t0; i <= endPos; i++)
     {
         fill += (m_frameDuration * m_vbvMaxRate -
                  qScale2bits(&m_rce2Pass[i], m_rce2Pass[i].newQScale)) *
parity;
@@ -1263,12 +1378,11 @@
     }
     return adjusted;
 }
-
 bool RateControl::cuTreeReadFor2Pass(Frame* frame)
 {
-    uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[frame->m_poc].sliceType;
-
-    if (m_rce2Pass[frame->m_poc].keptAsRef)
+    int index = m_encOrder[frame->m_poc];
+    uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[index].sliceType;
+    if (m_rce2Pass[index].keptAsRef)
     {
         /* TODO: We don't need pre-lookahead to measure AQ offsets, but
there is currently
          * no way to signal this */
@@ -1948,6 +2062,8 @@

 int RateControl::rowDiagonalVbvRateControl(Frame* curFrame, uint32_t row,
RateControlEntry* rce, double& qpVbv)
 {
+    if (m_param->rc.bStatRead && m_param->rc.rateControlMode ==
X265_RC_CRF)
+        return 0;
     FrameData& curEncData = *curFrame->m_encData;
     double qScaleVbv = x265_qp2qScale(qpVbv);
     uint64_t rowSatdCost = curEncData.m_rowStat[row].diagSatd;
@@ -2195,7 +2311,7 @@

     if (m_param->rc.aqMode || m_isVbv)
     {
-        if (m_isVbv)
+        if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode ==
X265_RC_CRF))
         {
             /* determine avg QP decided by VBV rate control */
             for (uint32_t i = 0; i < slice->m_sps->numCuInHeight; i++)
diff -r 6b308775b6f0 -r 0c49c9cc75e4 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h Mon Nov 23 12:26:45 2015 +0530
+++ b/source/encoder/ratecontrol.h Mon Nov 23 14:06:10 2015 +0530
@@ -205,8 +205,8 @@
     double  m_lastAccumPNorm;
     double  m_expectedBitsSum;   /* sum of qscale2bits after rceq,
ratefactor, and overflow, only includes finished frames */
     int64_t m_predictedBits;
+    int     *m_encOrder;
     RateControlEntry* m_rce2Pass;
-
     struct
     {
         uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree
quantizer data. */
@@ -258,11 +258,12 @@
     void   checkAndResetABR(RateControlEntry* rce, bool isFrameDone);
     double predictRowsSizeSum(Frame* pic, RateControlEntry* rce, double
qpm, int32_t& encodedBits);
     bool   initPass2();
+    bool   analyseABR2Pass(int startPoc, int endPoc, uint64_t
allAvailableBits);
     void   initFramePredictors();
     double getDiffLimitedQScale(RateControlEntry *rce, double q);
-    double countExpectedBits();
-    bool   vbv2Pass(uint64_t allAvailableBits);
-    bool   findUnderflow(double *fills, int *t0, int *t1, int over);
+    double countExpectedBits(int startPos, int framesCount);
+    bool   vbv2Pass(uint64_t allAvailableBits, int frameCount, int
startPos);
+    bool   findUnderflow(double *fills, int *t0, int *t1, int over, int
framesCount);
     bool   fixUnderflow(int t0, int t1, double adjustment, double
qscaleMin, double qscaleMax);
 };
 }


On Mon, Nov 23, 2015 at 2:16 PM, <aarthi at multicorewareinc.com> wrote:

> # HG changeset patch
> # User Divya Manivannan <divya at multicorewareinc.com>
> # Date 1448267770 -19800
> #      Mon Nov 23 14:06:10 2015 +0530
> # Branch stable
> # Node ID ffb0111298cdfcf6fe77d143089144c23b644b2d
> # Parent  6b308775b6f065ea5002a76a40aa6f5d81e8ee50
> rc: implement 2 pass CRF, when vbv is enabled.
>
> Allow CRF with VBV in 2nd pass to increase the quality of capped CRF in
> the first pass.
>
> diff -r 6b308775b6f0 -r ffb0111298cd source/common/param.cpp
> --- a/source/common/param.cpp   Mon Nov 23 12:26:45 2015 +0530
> +++ b/source/common/param.cpp   Mon Nov 23 14:06:10 2015 +0530
> @@ -1170,7 +1170,7 @@
>          CHECK(0 > param->noiseReductionIntra ||
> param->noiseReductionIntra > 2000, "Valid noise reduction range 0 - 2000");
>      if (param->noiseReductionInter)
>          CHECK(0 > param->noiseReductionInter ||
> param->noiseReductionInter > 2000, "Valid noise reduction range 0 - 2000");
> -    CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead,
> +    CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead
> && param->rc.vbvMaxBitrate == 0,
>            "Constant rate-factor is incompatible with 2pass");
>      CHECK(param->rc.rateControlMode == X265_RC_CQP && param->rc.bStatRead,
>            "Constant QP is incompatible with 2pass");
> diff -r 6b308775b6f0 -r ffb0111298cd source/encoder/ratecontrol.cpp
> --- a/source/encoder/ratecontrol.cpp    Mon Nov 23 12:26:45 2015 +0530
> +++ b/source/encoder/ratecontrol.cpp    Mon Nov 23 14:06:10 2015 +0530
> @@ -142,6 +142,8 @@
>      rce->expectedVbv = rce2Pass->expectedVbv;
>      rce->blurredComplexity = rce2Pass->blurredComplexity;
>      rce->sliceType = rce2Pass->sliceType;
> +    rce->qpNoVbv = rce2Pass->qpNoVbv;
> +    rce->newQp = rce2Pass->newQp;
>  }
>
>  }  // end anonymous namespace
> @@ -205,7 +207,7 @@
>              m_rateFactorMaxDecrement = m_param->rc.rfConstant -
> m_param->rc.rfConstantMin;
>      }
>      m_isAbr = m_param->rc.rateControlMode != X265_RC_CQP &&
> !m_param->rc.bStatRead;
> -    m_2pass = m_param->rc.rateControlMode == X265_RC_ABR &&
> m_param->rc.bStatRead;
> +    m_2pass = (m_param->rc.rateControlMode == X265_RC_ABR ||
> m_param->rc.vbvMaxBitrate > 0) && m_param->rc.bStatRead;
>      m_bitrate = m_param->rc.bitrate * 1000;
>      m_frameDuration = (double)m_param->fpsDenom / m_param->fpsNum;
>      m_qp = m_param->rc.qp;
> @@ -488,6 +490,12 @@
>                   x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2
> pass cannot be allocated\n");
>                   return false;
>              }
> +            m_encOrder = X265_MALLOC(int, m_numEntries);
> +            if (!m_encOrder)
> +            {
> +                x265_log(m_param, X265_LOG_ERROR, "Encode order for 2
> pass cannot be allocated\n");
> +                return false;
> +            }
>              /* init all to skipped p frames */
>              for (int i = 0; i < m_numEntries; i++)
>              {
> @@ -504,6 +512,7 @@
>              {
>                  RateControlEntry *rce;
>                  int frameNumber;
> +                int encodeOrder;
>                  char picType;
>                  int e;
>                  char *next;
> @@ -511,13 +520,14 @@
>                  next = strstr(p, ";");
>                  if (next)
>                      *next++ = 0;
> -                e = sscanf(p, " in:%d ", &frameNumber);
> +                e = sscanf(p, " in:%d out:%d", &frameNumber,
> &encodeOrder);
>                  if (frameNumber < 0 || frameNumber >= m_numEntries)
>                  {
>                      x265_log(m_param, X265_LOG_ERROR, "bad frame number
> (%d) at stats line %d\n", frameNumber, i);
>                      return false;
>                  }
> -                rce = &m_rce2Pass[frameNumber];
> +                rce = &m_rce2Pass[encodeOrder];
> +                m_encOrder[frameNumber] = encodeOrder;
>                  e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf
> q-noVbv:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
>                         &picType, &qpRc, &qpAq, &qNoVbv, &rce->coeffBits,
>                         &rce->mvBits, &rce->miscBits, &rce->iCuCount,
> &rce->pCuCount,
> @@ -546,8 +556,7 @@
>                  p = next;
>              }
>              X265_FREE(statsBuf);
> -
> -            if (m_param->rc.rateControlMode == X265_RC_ABR)
> +            if (m_param->rc.rateControlMode == X265_RC_ABR ||
> m_param->rc.vbvMaxBitrate > 0)
>              {
>                  if (!initPass2())
>                      return false;
> @@ -630,11 +639,8 @@
>
>      #undef MAX_DURATION
>  }
> -
> -bool RateControl::initPass2()
> +bool RateControl::analyseABR2Pass(int startIndex, int endIndex, uint64_t
> allAvailableBits)
>  {
> -    uint64_t allConstBits = 0;
> -    uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. *
> m_numEntries * m_frameDuration);
>      double rateFactor, stepMult;
>      double qBlur = m_param->rc.qblur;
>      double cplxBlur = m_param->rc.complexityBlur;
> @@ -643,30 +649,19 @@
>      double *qScale, *blurredQscale;
>      double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);
>      double clippedDuration = CLIP_DURATION(m_frameDuration) /
> BASE_FRAME_DURATION;
> -
> -    /* find total/average complexity & const_bits */
> -    for (int i = 0; i < m_numEntries; i++)
> -        allConstBits += m_rce2Pass[i].miscBits;
> -
> -    if (allAvailableBits < allConstBits)
> -    {
> -        x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too low.
> estimated minimum is %d kbps\n",
> -                 (int)(allConstBits * m_fps / m_numEntries * 1000.));
> -        return false;
> -    }
> -
> +    int framesCount = endIndex - startIndex + 1;
>      /* Blur complexities, to reduce local fluctuation of QP.
>       * We don't blur the QPs directly, because then one very simple frame
>       * could drag down the QP of a nearby complex frame and give it more
>       * bits than intended. */
> -    for (int i = 0; i < m_numEntries; i++)
> +    for (int i = startIndex; i <= endIndex; i++)
>      {
>          double weightSum = 0;
>          double cplxSum = 0;
>          double weight = 1.0;
>          double gaussianWeight;
>          /* weighted average of cplx of future frames */
> -        for (int j = 1; j < cplxBlur * 2 && j < m_numEntries - i; j++)
> +        for (int j = 1; j < cplxBlur * 2 && j <= endIndex - i; j++)
>          {
>              RateControlEntry *rcj = &m_rce2Pass[i + j];
>              weight *= 1 - pow(rcj->iCuCount / m_ncu, 2);
> @@ -690,11 +685,10 @@
>          }
>          m_rce2Pass[i].blurredComplexity = cplxSum / weightSum;
>      }
> -
> -    CHECKED_MALLOC(qScale, double, m_numEntries);
> +    CHECKED_MALLOC(qScale, double, framesCount);
>      if (filterSize > 1)
>      {
> -        CHECKED_MALLOC(blurredQscale, double, m_numEntries);
> +        CHECKED_MALLOC(blurredQscale, double, framesCount);
>      }
>      else
>          blurredQscale = qScale;
> @@ -705,9 +699,8 @@
>       * because qscale2bits is not invertible, but we can start with the
> simple
>       * approximation of scaling the 1st pass by the ratio of bitrates.
>       * The search range is probably overkill, but speed doesn't matter
> here. */
> -
>      expectedBits = 1;
> -    for (int i = 0; i < m_numEntries; i++)
> +    for (int i = startIndex; i <= endIndex; i++)
>      {
>          RateControlEntry* rce = &m_rce2Pass[i];
>          double q = getQScale(rce, 1.0);
> @@ -784,12 +777,10 @@
>      X265_FREE(qScale);
>      if (filterSize > 1)
>          X265_FREE(blurredQscale);
> -
>      if (m_isVbv)
> -        if (!vbv2Pass(allAvailableBits))
> +    if (!vbv2Pass(allAvailableBits, endIndex, startIndex))
>              return false;
> -    expectedBits = countExpectedBits();
> -
> +    expectedBits = countExpectedBits(startIndex, endIndex);
>      if (fabs(expectedBits / allAvailableBits - 1.0) > 0.01)
>      {
>          double avgq = 0;
> @@ -822,7 +813,127 @@
>      return false;
>  }
>
> -bool RateControl::vbv2Pass(uint64_t allAvailableBits)
> +bool RateControl::initPass2()
> +{
> +    uint64_t allConstBits = 0, allCodedBits = 0;
> +    uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. *
> m_numEntries * m_frameDuration);
> +    int startIndex, framesCount, endIndex, cnt;
> +    int fps = (int)(m_fps + 0.5);
> +    startIndex = endIndex = framesCount = 0;
> +    allAvailableBits = uint64_t(m_param->rc.vbvMaxBitrate * 1000. *
> m_numEntries * m_frameDuration);
> +    bool isQpModified = true;
> +    int diffQp = 0;
> +    int64_t targetBits = 0;
> +    int64_t expectedBits = 0;
> +    for (startIndex = 0, endIndex = 0; endIndex < m_numEntries;
> endIndex++)
> +    {
> +        allConstBits += m_rce2Pass[endIndex].miscBits;
> +        allCodedBits += m_rce2Pass[endIndex].coeffBits +
> m_rce2Pass[endIndex].mvBits;
> +        if (m_param->rc.rateControlMode == X265_RC_CRF)
> +        {
> +            framesCount = endIndex - startIndex + 1;
> +            if (m_rce2Pass[endIndex].newQScale < 0)
> +                m_rce2Pass[endIndex].newQScale =
> m_rce2Pass[endIndex].qScale;
> +            diffQp += int (m_rce2Pass[endIndex].qpaRc -
> m_rce2Pass[endIndex].qpNoVbv);
> +            if (framesCount > fps)
> +                diffQp -= int (m_rce2Pass[endIndex - fps].qpaRc -
> m_rce2Pass[endIndex - fps].qpNoVbv);
> +            if (framesCount >= fps)
> +            {
> +                if (diffQp >= 1)
> +                {
> +                    if (!isQpModified && endIndex > fps)
> +                    {
> +                        double factor = 2;
> +                        double step = 0;
> +                        for (int start = endIndex; start <= endIndex +
> fps - 1 && start < m_numEntries; start++)
> +                        {
> +                            RateControlEntry *rce = &m_rce2Pass[start];
> +                            targetBits += qScale2bits(rce,
> x265_qp2qScale(rce->qpNoVbv));
> +                            expectedBits += qScale2bits(rce, rce->qScale);
> +                        }
> +                        if (expectedBits < 0.95 * targetBits)
> +                        {
> +                            isQpModified = true;
> +                            while (endIndex + fps < m_numEntries)
> +                            {
> +                                step = pow(2, factor / 6.0);
> +                                expectedBits = 0;
> +                                for (int start = endIndex; start <=
> endIndex + fps - 1; start++)
> +                                {
> +                                    RateControlEntry *rce =
> &m_rce2Pass[start];
> +                                    rce->newQScale = rce->qScale / step;
> +                                    X265_CHECK(rce->newQScale >= 0, "new
> Qscale is negative\n");
> +                                    expectedBits += qScale2bits(rce,
> rce->newQScale);
> +                                    rce->newQp =
> x265_qScale2qp(rce->newQScale);
> +                                }
> +                                if (expectedBits >= targetBits && step >
> 1)
> +                                    factor *= 0.90;
> +                                else
> +                                    break;
> +                            }
> +
> +                            if (m_isVbv && endIndex + fps < m_numEntries)
> +                                if (!vbv2Pass(targetBits, endIndex + fps
> - 1, endIndex))
> +                                    return false;
> +
> +                            double prevFactor = factor;
> +                            targetBits = 0;
> +                            expectedBits = 0;
> +
> +                            for (int start = endIndex - fps; start <=
> endIndex - 1; start++)
> +                            {
> +                                RateControlEntry *rce =
> &m_rce2Pass[start];
> +                                targetBits += qScale2bits(rce,
> x265_qp2qScale(rce->qpNoVbv));
> +                            }
> +                            while (1)
> +                            {
> +                                step = pow(2, factor / 6.0);
> +                                expectedBits = 0;
> +                                for (int start = endIndex - fps; start <=
> endIndex - 1; start++)
> +                                {
> +                                    RateControlEntry *rce =
> &m_rce2Pass[start];
> +                                    rce->newQScale = rce->qScale * step;
> +                                    X265_CHECK(rce->newQScale >= 0, "new
> Qscale is negative\n");
> +                                    expectedBits += qScale2bits(rce,
> rce->newQScale);
> +                                    rce->newQp =
> x265_qScale2qp(rce->newQScale);
> +                                }
> +                                if (expectedBits > targetBits && step > 1)
> +                                    factor *= 1.1;
> +                                else
> +                                     break;
> +                            }
> +                            if (m_isVbv)
> +                            if (!vbv2Pass(targetBits, endIndex - 1,
> endIndex - fps))
> +                                    return false;
> +                            diffQp = 0;
> +                            startIndex = endIndex + 1;
> +                            targetBits = expectedBits = 0;
> +                        }
> +                        else
> +                            targetBits = expectedBits = 0;
> +                    }
> +                }
> +                else
> +                    isQpModified = false;
> +            }
> +        }
> +    }
> +
> +    if (m_param->rc.rateControlMode == X265_RC_ABR)
> +    {
> +        if (allAvailableBits < allConstBits)
> +        {
> +            x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too
> low. estimated minimum is %d kbps\n",
> +                     (int)(allConstBits * m_fps / framesCount * 1000.));
> +            return false;
> +        }
> +        if (!analyseABR2Pass(0, m_numEntries - 1, allAvailableBits))
> +            return false;
> +    }
> +    return true;
> +}
> +
> +bool RateControl::vbv2Pass(uint64_t allAvailableBits, int endPos, int
> startPos)
>  {
>      /* for each interval of bufferFull .. underflow, uniformly increase
> the qp of all
>       * frames in the interval until either buffer is full at some
> intermediate frame or the
> @@ -848,10 +959,10 @@
>          {   /* not first iteration */
>              adjustment = X265_MAX(X265_MIN(expectedBits /
> allAvailableBits, 0.999), 0.9);
>              fills[-1] = m_bufferSize * m_param->rc.vbvBufferInit;
> -            t0 = 0;
> +            t0 = startPos;
>              /* fix overflows */
>              adjMin = 1;
> -            while (adjMin && findUnderflow(fills, &t0, &t1, 1))
> +            while (adjMin && findUnderflow(fills, &t0, &t1, 1, endPos))
>              {
>                  adjMin = fixUnderflow(t0, t1, adjustment, MIN_QPSCALE,
> MAX_MAX_QPSCALE);
>                  t0 = t1;
> @@ -862,20 +973,16 @@
>          t0 = 0;
>          /* fix underflows -- should be done after overflow, as we'd
> better undersize target than underflowing VBV */
>          adjMax = 1;
> -        while (adjMax && findUnderflow(fills, &t0, &t1, 0))
> +        while (adjMax && findUnderflow(fills, &t0, &t1, 0, endPos))
>              adjMax = fixUnderflow(t0, t1, 1.001, MIN_QPSCALE,
> MAX_MAX_QPSCALE );
> -
> -        expectedBits = countExpectedBits();
> +        expectedBits = countExpectedBits(startPos, endPos);
>      }
> -    while ((expectedBits < .995 * allAvailableBits) &&
> ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)));
> -
> +    while ((expectedBits < .995 * allAvailableBits) &&
> ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)) &&
> !(m_param->rc.rateControlMode == X265_RC_CRF));
>      if (!adjMax)
>          x265_log(m_param, X265_LOG_WARNING, "vbv-maxrate issue, qpmax or
> vbv-maxrate too low\n");
> -
>      /* store expected vbv filling values for tracking when encoding */
> -    for (int i = 0; i < m_numEntries; i++)
> +    for (int i = startPos; i <= endPos; i++)
>          m_rce2Pass[i].expectedVbv = m_bufferSize - fills[i];
> -
>      X265_FREE(fills - 1);
>      return true;
>
> @@ -915,9 +1022,10 @@
>                  m_param->bframes = 1;
>              return X265_TYPE_AUTO;
>          }
> -        int frameType = m_rce2Pass[frameNum].sliceType == I_SLICE ?
> (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR)
> -                            : m_rce2Pass[frameNum].sliceType == P_SLICE ?
> X265_TYPE_P
> -                            : (m_rce2Pass[frameNum].sliceType == B_SLICE
> && m_rce2Pass[frameNum].keptAsRef? X265_TYPE_BREF : X265_TYPE_B);
> +        int index = m_encOrder[frameNum];
> +        int frameType = m_rce2Pass[index].sliceType == I_SLICE ?
> (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR)
> +                        : m_rce2Pass[index].sliceType == P_SLICE ?
> X265_TYPE_P
> +                        : (m_rce2Pass[index].sliceType == B_SLICE &&
> m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B);
>          return frameType;
>      }
>      else
> @@ -968,7 +1076,8 @@
>      if (m_param->rc.bStatRead)
>      {
>          X265_CHECK(rce->poc >= 0 && rce->poc < m_numEntries, "bad encode
> ordinal\n");
> -        copyRceData(rce, &m_rce2Pass[rce->poc]);
> +        int index = m_encOrder[rce->poc];
> +        copyRceData(rce, &m_rce2Pass[index]);
>      }
>      rce->isActive = true;
>      bool isRefFrameScenecut = m_sliceType!= I_SLICE &&
> m_curSlice->m_refPicList[0][0]->m_lowres.bScenecut == 1;
> @@ -1032,6 +1141,16 @@
>              }
>          }
>      }
> +    if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == X265_RC_CRF)
> +    {
> +        rce->qScale = rce->newQScale;
> +        rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq =
> x265_qScale2qp(rce->newQScale);
> +        m_qp = int(rce->qpaRc + 0.5);
> +        rce->frameSizePlanned = qScale2bits(rce, rce->qScale);
> +        m_framesDone++;
> +        return m_qp;
> +    }
> +
>      if (m_isAbr || m_2pass) // ABR,CRF
>      {
>          if (m_isAbr || m_isVbv)
> @@ -1203,11 +1322,10 @@
>      }
>      return q;
>  }
> -
> -double RateControl::countExpectedBits()
> +double RateControl::countExpectedBits(int startPos, int endPos)
>  {
>      double expectedBits = 0;
> -    for( int i = 0; i < m_numEntries; i++ )
> +    for (int i = startPos; i <= endPos; i++)
>      {
>          RateControlEntry *rce = &m_rce2Pass[i];
>          rce->expectedBits = (uint64_t)expectedBits;
> @@ -1215,8 +1333,7 @@
>      }
>      return expectedBits;
>  }
> -
> -bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over)
> +bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int
> over, int endPos)
>  {
>      /* find an interval ending on an overflow or underflow (depending on
> whether
>       * we're adding or removing bits), and starting on the earliest frame
> that
> @@ -1226,7 +1343,7 @@
>      double fill = fills[*t0 - 1];
>      double parity = over ? 1. : -1.;
>      int start = -1, end = -1;
> -    for (int i = *t0; i < m_numEntries; i++)
> +    for (int i = *t0; i <= endPos; i++)
>      {
>          fill += (m_frameDuration * m_vbvMaxRate -
>                   qScale2bits(&m_rce2Pass[i], m_rce2Pass[i].newQScale)) *
> parity;
> @@ -1263,12 +1380,11 @@
>      }
>      return adjusted;
>  }
> -
>  bool RateControl::cuTreeReadFor2Pass(Frame* frame)
>  {
> -    uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[frame->m_poc].sliceType;
> -
> -    if (m_rce2Pass[frame->m_poc].keptAsRef)
> +    int index = m_encOrder[frame->m_poc];
> +    uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[index].sliceType;
> +    if (m_rce2Pass[index].keptAsRef)
>      {
>          /* TODO: We don't need pre-lookahead to measure AQ offsets, but
> there is currently
>           * no way to signal this */
> @@ -1948,6 +2064,8 @@
>
>  int RateControl::rowDiagonalVbvRateControl(Frame* curFrame, uint32_t row,
> RateControlEntry* rce, double& qpVbv)
>  {
> +    if (m_param->rc.bStatRead && m_param->rc.rateControlMode ==
> X265_RC_CRF)
> +        return 0;
>      FrameData& curEncData = *curFrame->m_encData;
>      double qScaleVbv = x265_qp2qScale(qpVbv);
>      uint64_t rowSatdCost = curEncData.m_rowStat[row].diagSatd;
> @@ -2195,7 +2313,7 @@
>
>      if (m_param->rc.aqMode || m_isVbv)
>      {
> -        if (m_isVbv)
> +        if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode ==
> X265_RC_CRF))
>          {
>              /* determine avg QP decided by VBV rate control */
>              for (uint32_t i = 0; i < slice->m_sps->numCuInHeight; i++)
> diff -r 6b308775b6f0 -r ffb0111298cd source/encoder/ratecontrol.h
> --- a/source/encoder/ratecontrol.h      Mon Nov 23 12:26:45 2015 +0530
> +++ b/source/encoder/ratecontrol.h      Mon Nov 23 14:06:10 2015 +0530
> @@ -205,8 +205,8 @@
>      double  m_lastAccumPNorm;
>      double  m_expectedBitsSum;   /* sum of qscale2bits after rceq,
> ratefactor, and overflow, only includes finished frames */
>      int64_t m_predictedBits;
> +    int     *m_encOrder;
>      RateControlEntry* m_rce2Pass;
> -
>      struct
>      {
>          uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree
> quantizer data. */
> @@ -258,11 +258,12 @@
>      void   checkAndResetABR(RateControlEntry* rce, bool isFrameDone);
>      double predictRowsSizeSum(Frame* pic, RateControlEntry* rce, double
> qpm, int32_t& encodedBits);
>      bool   initPass2();
> +    bool   analyseABR2Pass(int startPoc, int endPoc, uint64_t
> allAvailableBits);
>      void   initFramePredictors();
>      double getDiffLimitedQScale(RateControlEntry *rce, double q);
> -    double countExpectedBits();
> -    bool   vbv2Pass(uint64_t allAvailableBits);
> -    bool   findUnderflow(double *fills, int *t0, int *t1, int over);
> +    double countExpectedBits(int startPos, int framesCount);
> +    bool   vbv2Pass(uint64_t allAvailableBits, int frameCount, int
> startPos);
> +    bool   findUnderflow(double *fills, int *t0, int *t1, int over, int
> framesCount);
>      bool   fixUnderflow(int t0, int t1, double adjustment, double
> qscaleMin, double qscaleMax);
>  };
>  }
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20151123/d1b3c8f5/attachment-0001.html>


More information about the x265-devel mailing list