<div dir="ltr"><div># HG changeset patch</div><div># User Aarthi Thirumalai<<a href="mailto:aarthi@multicorewareinc.com">aarthi@multicorewareinc.com</a>></div><div># Date 1405013200 -19800</div><div>#      Thu Jul 10 22:56:40 2014 +0530</div>
<div># Node ID 96e43814fcc6e9b661c16ec8230768b348ec6ce1</div><div># Parent  2737d0b05b72ca90f09987e6cf30b7c37e38b83c</div><div>rc: add 2 pass logic in rateEstimateQscale</div><div><br></div><div>adjust qscale of each frame based on distance to end of the video and</div>
<div>the difference between achieved and expected bits so far in the final pass.</div><div><br></div><div>diff -r 2737d0b05b72 -r 96e43814fcc6 source/encoder/encoder.cpp</div><div>--- a/source/encoder/encoder.cpp<span class="" style="white-space:pre">   </span>Wed Jul 16 01:20:29 2014 -0500</div>
<div>+++ b/source/encoder/encoder.cpp<span class="" style="white-space:pre">    </span>Thu Jul 10 22:56:40 2014 +0530</div><div>@@ -41,7 +41,7 @@</div><div> </div><div> #include "x265.h"</div><div> </div><div>-static const char *summaryCSVHeader =</div>
<div>+const char *summaryCSVHeader =</div><div>     "Command, Date/Time, Elapsed Time, FPS, Bitrate, "</div><div>     "Y PSNR, U PSNR, V PSNR, Global PSNR, SSIM, SSIM (dB), "</div><div>     "I count, I ave-QP, I kpbs, I-PSNR Y, I-PSNR U, I-PSNR V, I-SSIM (dB), "</div>
<div>@@ -49,6 +49,8 @@</div><div>     "B count, B ave-QP, B kpbs, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), "</div><div>     "Version\n";</div><div> </div><div>+const char sliceTypeToChar[] = { 'B', 'P', 'I' };</div>
<div>+</div><div> using namespace x265;</div><div> </div><div> Encoder::Encoder()</div><div>@@ -227,6 +229,8 @@</div><div>             rc->m_bufferFill = X265_MAX(rc->m_bufferFill, 0);</div><div>             rc->m_bufferFill += encoder->m_rce.bufferRate;</div>
<div>             rc->m_bufferFill = X265_MIN(rc->m_bufferFill, rc->m_bufferSize);</div><div>+            if (rc->m_2pass)</div><div>+                rc->m_predictedBits += (int64_t)encoder->m_rce.frameSizeEstimated;</div>
<div>         }</div><div>         encIdx = (encIdx + 1) % m_param->frameNumThreads;</div><div>     }</div><div>diff -r 2737d0b05b72 -r 96e43814fcc6 source/encoder/encoder.h</div><div>--- a/source/encoder/encoder.h<span class="" style="white-space:pre">   </span>Wed Jul 16 01:20:29 2014 -0500</div>
<div>+++ b/source/encoder/encoder.h<span class="" style="white-space:pre">      </span>Thu Jul 10 22:56:40 2014 +0530</div><div>@@ -30,6 +30,9 @@</div><div> </div><div> struct x265_encoder {};</div><div> </div><div>+extern const char *summaryCSVHeader;</div>
<div>+extern const char sliceTypeToChar[3];</div><div>+</div><div> namespace x265 {</div><div> // private namespace</div><div> </div><div>diff -r 2737d0b05b72 -r 96e43814fcc6 source/encoder/ratecontrol.cpp</div><div>--- a/source/encoder/ratecontrol.cpp<span class="" style="white-space:pre">  </span>Wed Jul 16 01:20:29 2014 -0500</div>
<div>+++ b/source/encoder/ratecontrol.cpp<span class="" style="white-space:pre">        </span>Thu Jul 10 22:56:40 2014 +0530</div><div>@@ -122,6 +122,23 @@</div><div>            + rce->miscBits;</div><div> }</div><div> </div>
<div>+inline void copyRceData(RateControlEntry* rce, RateControlEntry* rce2Pass)</div><div>+{</div><div>+    rce->coeffBits = rce2Pass->coeffBits;</div><div>+    rce->mvBits = rce2Pass->mvBits;</div><div>+    rce->miscBits = rce2Pass->miscBits;</div>
<div>+    rce->iCuCount = rce2Pass->iCuCount;</div><div>+    rce->pCuCount = rce2Pass->pCuCount;</div><div>+    rce->skipCuCount = rce2Pass->skipCuCount;</div><div>+    rce->keptAsRef = rce2Pass->keptAsRef;</div>
<div>+    rce->qScale = rce2Pass->qScale;</div><div>+    rce->newQScale = rce2Pass->newQScale;</div><div>+    rce->expectedBits = rce2Pass->expectedBits;</div><div>+    rce->expectedVbv = rce2Pass->expectedVbv;</div>
<div>+    rce->blurredComplexity = rce2Pass->blurredComplexity;</div><div>+    rce->sliceType = rce2Pass->sliceType;</div><div>+}</div><div>+</div><div> }  // end anonymous namespace</div><div> /* Compute variance to derive AC energy of each block */</div>
<div> static inline uint32_t acEnergyVar(Frame *pic, uint64_t sum_ssd, int shift, int i)</div><div>@@ -982,6 +999,12 @@</div><div>     m_curSlice = pic->getSlice();</div><div>     m_sliceType = m_curSlice->getSliceType();</div>
<div>     rce->sliceType = m_sliceType;</div><div>+    if (m_param->rc.bStatRead)</div><div>+    {</div><div>+        X265_CHECK(rce->encodeOrder >= 0 && rce->encodeOrder < m_numEntries, </div><div>
+                    "Frame encode order is more than total no. of frames in the first pass");</div><div>+        copyRceData(rce, &m_rce2Pass[rce->encodeOrder]);</div><div>+    }</div><div>     rce->isActive = true;</div>
<div>     if (m_sliceType == B_SLICE)</div><div>         rce->bframes = m_bframes;</div><div>@@ -1008,6 +1031,7 @@</div><div>         }</div><div>         rce->rowPred[0] = &rce->rowPreds[m_sliceType][0];</div>
<div>         rce->rowPred[1] = &rce->rowPreds[m_sliceType][1];</div><div>+        m_predictedBits = m_totalBits;</div><div>         updateVbvPlan(enc);</div><div>         rce->bufferFill = m_bufferFill;</div>
<div>     }</div><div>@@ -1045,6 +1069,7 @@</div><div>         rce->qpaRc = pic->m_avgQpRc = pic->m_avgQpAq = m_qp;</div><div>     }</div><div>     m_framesDone++;</div><div>+    rce->newQp = m_qp;</div><div>     /* set the final QP to slice structure */</div>
<div>     m_curSlice->setSliceQp(m_qp);</div><div> }</div><div>@@ -1186,6 +1211,14 @@</div><div> {</div><div>     double q;</div><div> </div><div>+    if (m_2pass)</div><div>+    {</div><div>+        if (m_sliceType != rce->sliceType)</div>
<div>+        {</div><div>+            x265_log(m_param, X265_LOG_ERROR, "slice=%c but 2pass stats say %c\n",</div><div>+                     sliceTypeToChar[m_sliceType], sliceTypeToChar[rce->sliceType]);</div>
<div>+        }</div><div>+    }</div><div>     if (m_sliceType == B_SLICE)</div><div>     {</div><div>         /* B-frames don't have independent rate control, but rather get the</div><div>@@ -1230,109 +1263,172 @@</div>
<div>         double qScale = x265_qp2qScale(q);</div><div>         rce->frameSizePlanned = predictSize(&m_predBfromP, qScale, (double)m_leadingNoBSatd);</div><div>         rce->frameSizeEstimated = rce->frameSizePlanned;</div>
<div>+        rce->newQScale = qScale;</div><div>         return qScale;</div><div>     }</div><div>     else</div><div>     {</div><div>         double abrBuffer = 2 * m_param->rc.rateTolerance * m_bitrate;</div><div>
+        if (m_2pass)</div><div>+        {</div><div>+            int64_t diff;</div><div>+            if (!m_isVbv)</div><div>+            {</div><div>+                m_predictedBits = m_totalBits;</div><div>+                if (rce->encodeOrder < m_param->frameNumThreads)</div>
<div>+                    m_predictedBits += (int64_t)(rce->encodeOrder * m_bitrate / m_fps) ;</div><div>+                else</div><div>+                    m_predictedBits += (int64_t)(m_param->frameNumThreads * m_bitrate / m_fps);</div>
<div>+            }</div><div>+            /* Adjust ABR buffer based on distance to the end of the video. */</div><div>+            if (m_numEntries > rce->encodeOrder)</div><div>+            {</div><div>+                uint64_t finalBits = m_rce2Pass[m_numEntries - 1].expectedBits;</div>
<div>+                double videoPos = (double)rce->expectedBits / finalBits;</div><div>+                double scaleFactor = sqrt((1 - videoPos) * m_numEntries);</div><div>+                abrBuffer *= 0.5 * X265_MAX(scaleFactor, 0.5);</div>
<div>+            }</div><div> </div><div>-        /* 1pass ABR */</div><div>+            diff = m_predictedBits - (int64_t)rce->expectedBits;</div><div>+            q = rce->newQScale;</div><div>+            q /= Clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer);</div>
<div>+            if (((rce->encodeOrder + 1 - m_param->frameNumThreads) >= m_fps) &&</div><div>+                (m_expectedBitsSum > 0))</div><div>+            {</div><div>+                /* Adjust quant based on the difference between</div>
<div>+                 * achieved and expected bitrate so far */</div><div>+                double curTime = (double)rce->encodeOrder / m_numEntries;</div><div>+                double w = Clip3(0.0, 1.0, curTime * 100);</div>
<div>+                q *= pow((double)m_totalBits / m_expectedBitsSum, w);</div><div>+            }</div><div>+            rce->qpNoVbv = x265_qScale2qp(q);</div><div>+            if (m_isVbv)</div><div>+            {</div>
<div>+                /* Do not overflow vbv */</div><div>+                double expectedSize = qScale2bits(rce, q);</div><div>+                double expectedVbv = m_bufferFill + m_bufferRate - expectedSize;</div><div>+                double expectedFullness = rce->expectedVbv / m_bufferSize;</div>
<div>+                double qmax = q * (2 - expectedFullness);</div><div>+                double sizeConstraint = 1 + expectedFullness;</div><div>+                qmax = X265_MAX(qmax, rce->newQScale);</div><div>+                if (expectedFullness < .05)</div>
<div>+                    qmax = MAX_MAX_QPSCALE;</div><div>+                qmax = X265_MIN(qmax, MAX_MAX_QPSCALE);</div><div>+                while (((expectedVbv < rce->expectedVbv/sizeConstraint) && (q < qmax)) ||</div>
<div>+                        ((expectedVbv < 0) && (q < MAX_MAX_QPSCALE)))</div><div>+                {</div><div>+                    q *= 1.05;</div><div>+                    expectedSize = qScale2bits(rce, q);</div>
<div>+                    expectedVbv = m_bufferFill + m_bufferRate - expectedSize;</div><div>+                }</div><div> </div><div>-        /* Calculate the quantizer which would have produced the desired</div><div>-         * average bitrate if it had been applied to all frames so far.</div>
<div>-         * Then modulate that quant based on the current frame's complexity</div><div>-         * relative to the average complexity so far (using the 2pass RCEQ).</div><div>-         * Then bias the quant up or down if total size so far was far from</div>
<div>-         * the target.</div><div>-         * Result: Depending on the value of rate_tolerance, there is a</div><div>-         * tradeoff between quality and bitrate precision. But at large</div><div>-         * tolerances, the bit distribution approaches that of 2pass. */</div>
<div>-</div><div>-        double wantedBits, overflow = 1;</div><div>-        rce->movingAvgSum = m_shortTermCplxSum;</div><div>-        m_shortTermCplxSum *= 0.5;</div><div>-        m_shortTermCplxCount *= 0.5;</div><div>
-        m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);</div><div>-        m_shortTermCplxCount++;</div><div>-        /* coeffBits to be used in 2-pass */</div><div>-        rce->coeffBits = (int)m_currentSatd;</div>
<div>-        rce->blurredComplexity = m_shortTermCplxSum / m_shortTermCplxCount;</div><div>-        rce->mvBits = 0;</div><div>-        rce->sliceType = m_sliceType;</div><div>-</div><div>-        if (m_param->rc.rateControlMode == X265_RC_CRF)</div>
<div>-        {</div><div>-            q = getQScale(rce, m_rateFactorConstant);</div><div>+            }</div><div>+            q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);</div><div>         }</div><div>         else</div>
<div>         {</div><div>-            if (!m_param->rc.bStatRead)</div><div>-                checkAndResetABR(rce, false);</div><div>-            q = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);</div><div>+            /* 1pass ABR */</div>
<div> </div><div>-            /* ABR code can potentially be counterproductive in CBR, so just</div><div>-             * don't bother.  Don't run it if the frame complexity is zero</div><div>-             * either. */</div>
<div>-            if (!m_isCbr && m_currentSatd)</div><div>+            /* Calculate the quantizer which would have produced the desired</div><div>+             * average bitrate if it had been applied to all frames so far.</div>
<div>+             * Then modulate that quant based on the current frame's complexity</div><div>+             * relative to the average complexity so far (using the 2pass RCEQ).</div><div>+             * Then bias the quant up or down if total size so far was far from</div>
<div>+             * the target.</div><div>+             * Result: Depending on the value of rate_tolerance, there is a</div><div>+             * tradeoff between quality and bitrate precision. But at large</div><div>+             * tolerances, the bit distribution approaches that of 2pass. */</div>
<div>+</div><div>+            double wantedBits, overflow = 1;</div><div>+            rce->movingAvgSum = m_shortTermCplxSum;</div><div>+            m_shortTermCplxSum *= 0.5;</div><div>+            m_shortTermCplxCount *= 0.5;</div>
<div>+            m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);</div><div>+            m_shortTermCplxCount++;</div><div>+            /* coeffBits to be used in 2-pass */</div>
<div>+            rce->coeffBits = (int)m_currentSatd;</div><div>+            rce->blurredComplexity = m_shortTermCplxSum / m_shortTermCplxCount;</div><div>+            rce->mvBits = 0;</div><div>+            rce->sliceType = m_sliceType;</div>
<div>+</div><div>+            if (m_param->rc.rateControlMode == X265_RC_CRF)</div><div>             {</div><div>-                /* use framesDone instead of POC as poc count is not serial with bframes enabled */</div>
<div>-                double timeDone = (double)(m_framesDone - m_param->frameNumThreads + 1) * m_frameDuration;</div><div>-                wantedBits = timeDone * m_bitrate;</div><div>-                if (wantedBits > 0 && m_totalBits > 0 && !m_residualFrames)</div>
<div>+                q = getQScale(rce, m_rateFactorConstant);</div><div>+            }</div><div>+            else</div><div>+            {</div><div>+                if (!m_param->rc.bStatRead)</div><div>+                    checkAndResetABR(rce, false);</div>
<div>+                q = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);</div><div>+</div><div>+                /* ABR code can potentially be counterproductive in CBR, so just</div><div>+                 * don't bother.  Don't run it if the frame complexity is zero</div>
<div>+                 * either. */</div><div>+                if (!m_isCbr && m_currentSatd)</div><div>                 {</div><div>-                    abrBuffer *= X265_MAX(1, sqrt(timeDone));</div><div>-                    overflow = Clip3(.5, 2.0, 1.0 + (m_totalBits - wantedBits) / abrBuffer);</div>
<div>-                    q *= overflow;</div><div>+                    /* use framesDone instead of POC as poc count is not serial with bframes enabled */</div><div>+                    double timeDone = (double)(m_framesDone - m_param->frameNumThreads + 1) * m_frameDuration;</div>
<div>+                    wantedBits = timeDone * m_bitrate;</div><div>+                    if (wantedBits > 0 && m_totalBits > 0 && !m_residualFrames)</div><div>+                    {</div><div>+                        abrBuffer *= X265_MAX(1, sqrt(timeDone));</div>
<div>+                        overflow = Clip3(.5, 2.0, 1.0 + (m_totalBits - wantedBits) / abrBuffer);</div><div>+                        q *= overflow;</div><div>+                    }</div><div>                 }</div><div>
             }</div><div>+</div><div>+            if (m_sliceType == I_SLICE && m_param->keyframeMax > 1</div><div>+                && m_lastNonBPictType != I_SLICE && !m_isAbrReset)</div><div>
+            {</div><div>+                q = x265_qp2qScale(m_accumPQp / m_accumPNorm);</div><div>+                q /= fabs(m_param->rc.ipFactor);</div><div>+            }</div><div>+            else if (m_framesDone > 0)</div>
<div>+            {</div><div>+                if (m_param->rc.rateControlMode != X265_RC_CRF)</div><div>+                {</div><div>+                    double lqmin = 0, lqmax = 0;</div><div>+                    lqmin = m_lastQScaleFor[m_sliceType] / m_lstep;</div>
<div>+                    lqmax = m_lastQScaleFor[m_sliceType] * m_lstep;</div><div>+                    if (!m_residualFrames)</div><div>+                    {</div><div>+                        if (overflow > 1.1 && m_framesDone > 3)</div>
<div>+                            lqmax *= m_lstep;</div><div>+                        else if (overflow < 0.9)</div><div>+                            lqmin /= m_lstep;</div><div>+                    }</div><div>+                    q = Clip3(lqmin, lqmax, q);</div>
<div>+                }</div><div>+            }</div><div>+            else if (m_qCompress != 1 && m_param->rc.rateControlMode == X265_RC_CRF)</div><div>+            {</div><div>+                q = x265_qp2qScale(CRF_INIT_QP) / fabs(m_param->rc.ipFactor);</div>
<div>+            }</div><div>+            else if (m_framesDone == 0 && !m_isVbv)</div><div>+            {</div><div>+                /* for ABR alone, clip the first I frame qp */</div><div>+                double lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;</div>
<div>+                q = X265_MIN(lqmax, q);</div><div>+            }</div><div>+            q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);</div><div>+            rce->qpNoVbv = x265_qScale2qp(q);</div><div>+            q = clipQscale(pic, q);</div>
<div>         }</div><div>-</div><div>-        if (m_sliceType == I_SLICE && m_param->keyframeMax > 1</div><div>-            && m_lastNonBPictType != I_SLICE && !m_isAbrReset)</div><div>-        {</div>
<div>-            q = x265_qp2qScale(m_accumPQp / m_accumPNorm);</div><div>-            q /= fabs(m_param->rc.ipFactor);</div><div>-        }</div><div>-        else if (m_framesDone > 0)</div><div>-        {</div><div>
-            if (m_param->rc.rateControlMode != X265_RC_CRF)</div><div>-            {</div><div>-                double lqmin = 0, lqmax = 0;</div><div>-                lqmin = m_lastQScaleFor[m_sliceType] / m_lstep;</div>
<div>-                lqmax = m_lastQScaleFor[m_sliceType] * m_lstep;</div><div>-                if (!m_residualFrames)</div><div>-                {</div><div>-                    if (overflow > 1.1 && m_framesDone > 3)</div>
<div>-                        lqmax *= m_lstep;</div><div>-                    else if (overflow < 0.9)</div><div>-                        lqmin /= m_lstep;</div><div>-                }</div><div>-                q = Clip3(lqmin, lqmax, q);</div>
<div>-            }</div><div>-        }</div><div>-        else if (m_qCompress != 1 && m_param->rc.rateControlMode == X265_RC_CRF)</div><div>-        {</div><div>-            q = x265_qp2qScale(CRF_INIT_QP) / fabs(m_param->rc.ipFactor);</div>
<div>-        }</div><div>-        else if (m_framesDone == 0 && !m_isVbv)</div><div>-        {</div><div>-            /* for ABR alone, clip the first I frame qp */</div><div>-            double lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;</div>
<div>-            q = X265_MIN(lqmax, q);</div><div>-        }</div><div>-        q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);</div><div>-        rce->qpNoVbv = x265_qScale2qp(q);</div><div>-        q = clipQscale(pic, q);</div>
<div>         m_lastQScaleFor[m_sliceType] = q;</div><div>-        if (m_curSlice->getPOC() == 0 || m_lastQScaleFor[P_SLICE] < q)</div><div>+        if ((m_curSlice->getPOC() == 0 || m_lastQScaleFor[P_SLICE] < q) && !(m_2pass && !m_isVbv))</div>
<div>             m_lastQScaleFor[P_SLICE] = q * fabs(m_param->rc.ipFactor);</div><div> </div><div>-        rce->frameSizePlanned = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);</div><div>+        if (m_2pass && m_isVbv)</div>
<div>+            rce->frameSizePlanned = qScale2bits(rce, q);</div><div>+        else</div><div>+            rce->frameSizePlanned = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);</div><div>         rce->frameSizeEstimated = rce->frameSizePlanned;</div>
<div>         /* Always use up the whole VBV in this case. */</div><div>         if (m_singleFrameVbv)</div><div>             rce->frameSizePlanned = m_bufferRate;</div><div> </div><div>+        rce->newQScale = q;</div>
<div>         return q;</div><div>     }</div><div> }</div><div>@@ -1932,6 +2028,8 @@</div><div>             m_totalBits += bits;</div><div>         }</div><div>     }</div><div>+    if (m_2pass)</div><div>+        m_expectedBitsSum += qScale2bits(rce, x265_qp2qScale(rce->newQp));</div>
<div> </div><div>     if (m_isVbv)</div><div>     {</div><div>diff -r 2737d0b05b72 -r 96e43814fcc6 source/encoder/ratecontrol.h</div><div>--- a/source/encoder/ratecontrol.h<span class="" style="white-space:pre">      </span>Wed Jul 16 01:20:29 2014 -0500</div>
<div>+++ b/source/encoder/ratecontrol.h<span class="" style="white-space:pre">  </span>Thu Jul 10 22:56:40 2014 +0530</div><div>@@ -160,6 +160,8 @@</div><div>     int      m_numEntries;</div><div>     RateControlEntry *m_rce2Pass;</div>
<div>     double   m_lastAccumPNorm;</div><div>+    int64_t  m_predictedBits;</div><div>+    double   m_expectedBitsSum;   /* sum of qscale2bits after rceq, ratefactor, and overflow, only includes finished frames */</div>
<div>     struct</div><div>     {</div><div>         uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree quantizer data. */</div><div><br></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Jul 13, 2014 at 8:27 PM, Steve Borho <span dir="ltr"><<a href="mailto:steve@borho.org" target="_blank">steve@borho.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On 07/13, <a href="mailto:aarthi@multicorewareinc.com">aarthi@multicorewareinc.com</a> wrote:<br>

> # HG changeset patch<br>
> # User Aarthi Thirumalai<<a href="mailto:aarthi@multicorewareinc.com">aarthi@multicorewareinc.com</a>><br>
> # Date 1405013200 -19800<br>
> #      Thu Jul 10 22:56:40 2014 +0530<br>
> # Node ID cf8b11c379f304cd80da524e0d33a5eba2aa6155<br>
> # Parent  9d3683ab096b6efbaddd3ed388673e171457455f<br>
> rc: add 2 pass logic in rateEstimateQscale<br>
><br>
> adjust qscale of each frame based on distance to end of the video and<br>
> the difference between achieved and expected bits so far in the final pass.<br>
><br>
> diff -r 9d3683ab096b -r cf8b11c379f3 source/encoder/encoder.cpp<br>
> --- a/source/encoder/encoder.cpp      Sat Jul 12 01:18:07 2014 -0500<br>
> +++ b/source/encoder/encoder.cpp      Thu Jul 10 22:56:40 2014 +0530<br>
> @@ -41,14 +41,6 @@<br>
><br>
>  #include "x265.h"<br>
><br>
> -static const char *summaryCSVHeader =<br>
> -    "Command, Date/Time, Elapsed Time, FPS, Bitrate, "<br>
> -    "Y PSNR, U PSNR, V PSNR, Global PSNR, SSIM, SSIM (dB), "<br>
> -    "I count, I ave-QP, I kpbs, I-PSNR Y, I-PSNR U, I-PSNR V, I-SSIM (dB), "<br>
> -    "P count, P ave-QP, P kpbs, P-PSNR Y, P-PSNR U, P-PSNR V, P-SSIM (dB), "<br>
> -    "B count, B ave-QP, B kpbs, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), "<br>
> -    "Version\n";<br>
> -<br>
>  using namespace x265;<br>
><br>
>  Encoder::Encoder()<br>
> @@ -227,6 +219,8 @@<br>
>              rc->m_bufferFill = X265_MAX(rc->m_bufferFill, 0);<br>
>              rc->m_bufferFill += encoder->m_rce.bufferRate;<br>
>              rc->m_bufferFill = X265_MIN(rc->m_bufferFill, rc->m_bufferSize);<br>
> +            if (rc->m_2pass)<br>
> +                rc->m_predictedBits += (int64_t)encoder->m_rce.frameSizeEstimated;<br>
>          }<br>
>          encIdx = (encIdx + 1) % m_param->frameNumThreads;<br>
>      }<br>
> diff -r 9d3683ab096b -r cf8b11c379f3 source/encoder/encoder.h<br>
> --- a/source/encoder/encoder.h        Sat Jul 12 01:18:07 2014 -0500<br>
> +++ b/source/encoder/encoder.h        Thu Jul 10 22:56:40 2014 +0530<br>
> @@ -30,6 +30,16 @@<br>
><br>
>  struct x265_encoder {};<br>
><br>
> +static const char *summaryCSVHeader =<br>
> +    "Command, Date/Time, Elapsed Time, FPS, Bitrate, "<br>
> +    "Y PSNR, U PSNR, V PSNR, Global PSNR, SSIM, SSIM (dB), "<br>
> +    "I count, I ave-QP, I kpbs, I-PSNR Y, I-PSNR U, I-PSNR V, I-SSIM (dB), "<br>
> +    "P count, P ave-QP, P kpbs, P-PSNR Y, P-PSNR U, P-PSNR V, P-SSIM (dB), "<br>
> +    "B count, B ave-QP, B kpbs, B-PSNR Y, B-PSNR U, B-PSNR V, B-SSIM (dB), "<br>
> +    "Version\n";<br>
> +<br>
> +static const char sliceTypeToChar[] = { 'B', 'P', 'I' };<br>
> +<br>
<br>
</div></div>This causes warnings from GCC from most files that include this header:<br>
<br>
In file included from<br>
/Users/steve/repos/x265/source/encoder/api.cpp:26:0:<br>
/Users/steve/repos/x265/source/encoder/encoder.h:33:20: warning: 'summaryCSVHeader' defined but not used [-Wunused-variable]<br>
<div><div class="h5"><br>
>  namespace x265 {<br>
>  // private namespace<br>
><br>
> diff -r 9d3683ab096b -r cf8b11c379f3 source/encoder/ratecontrol.cpp<br>
> --- a/source/encoder/ratecontrol.cpp  Sat Jul 12 01:18:07 2014 -0500<br>
> +++ b/source/encoder/ratecontrol.cpp  Thu Jul 10 22:56:40 2014 +0530<br>
> @@ -122,6 +122,23 @@<br>
>             + rce->miscBits;<br>
>  }<br>
><br>
> +inline void copyRceData(RateControlEntry* rce, RateControlEntry* rce2Pass)<br>
> +{<br>
> +    rce->coeffBits = rce2Pass->coeffBits;<br>
> +    rce->mvBits = rce2Pass->mvBits;<br>
> +    rce->miscBits = rce2Pass->miscBits;<br>
> +    rce->iCuCount = rce2Pass->iCuCount;<br>
> +    rce->pCuCount = rce2Pass->pCuCount;<br>
> +    rce->skipCuCount = rce2Pass->skipCuCount;<br>
> +    rce->keptAsRef = rce2Pass->keptAsRef;<br>
> +    rce->qScale = rce2Pass->qScale;<br>
> +    rce->newQScale = rce2Pass->newQScale;<br>
> +    rce->expectedBits = rce2Pass->expectedBits;<br>
> +    rce->expectedVbv = rce2Pass->expectedVbv;<br>
> +    rce->blurredComplexity = rce2Pass->blurredComplexity;<br>
> +    rce->sliceType = rce2Pass->sliceType;<br>
> +}<br>
> +<br>
>  }  // end anonymous namespace<br>
>  /* Compute variance to derive AC energy of each block */<br>
>  static inline uint32_t acEnergyVar(Frame *pic, uint64_t sum_ssd, int shift, int i)<br>
> @@ -989,6 +1006,12 @@<br>
>      m_curSlice = pic->getSlice();<br>
>      m_sliceType = m_curSlice->getSliceType();<br>
>      rce->sliceType = m_sliceType;<br>
> +    if (m_param->rc.bStatRead)<br>
> +    {<br>
> +        X265_CHECK(rce->encodeOrder >= 0 && rce->encodeOrder < m_numEntries,<br>
> +                    "Frame encode order is more than total no. of frames in the first pass");<br>
> +        copyRceData(rce, &m_rce2Pass[rce->encodeOrder]);<br>
> +    }<br>
>      rce->isActive = true;<br>
>      if (m_sliceType == B_SLICE)<br>
>          rce->bframes = m_bframes;<br>
> @@ -1015,6 +1038,7 @@<br>
>          }<br>
>          rce->rowPred[0] = &rce->rowPreds[m_sliceType][0];<br>
>          rce->rowPred[1] = &rce->rowPreds[m_sliceType][1];<br>
> +        m_predictedBits = m_totalBits;<br>
>          updateVbvPlan(enc);<br>
>          rce->bufferFill = m_bufferFill;<br>
>      }<br>
> @@ -1052,6 +1076,7 @@<br>
>          rce->qpaRc = pic->m_avgQpRc = pic->m_avgQpAq = m_qp;<br>
>      }<br>
>      m_framesDone++;<br>
> +    rce->newQp = m_qp;<br>
>      /* set the final QP to slice structure */<br>
>      m_curSlice->setSliceQp(m_qp);<br>
>  }<br>
> @@ -1193,6 +1218,14 @@<br>
>  {<br>
>      double q;<br>
><br>
> +    if (m_2pass)<br>
> +    {<br>
> +        if (m_sliceType != rce->sliceType)<br>
> +        {<br>
> +            x265_log(m_param, X265_LOG_ERROR, "slice=%c but 2pass stats say %c\n",<br>
> +                     sliceTypeToChar[m_sliceType], sliceTypeToChar[rce->sliceType]);<br>
> +        }<br>
> +    }<br>
>      if (m_sliceType == B_SLICE)<br>
>      {<br>
>          /* B-frames don't have independent rate control, but rather get the<br>
> @@ -1237,109 +1270,172 @@<br>
>          double qScale = x265_qp2qScale(q);<br>
>          rce->frameSizePlanned = predictSize(&m_predBfromP, qScale, (double)m_leadingNoBSatd);<br>
>          rce->frameSizeEstimated = rce->frameSizePlanned;<br>
> +        rce->newQScale = qScale;<br>
>          return qScale;<br>
>      }<br>
>      else<br>
>      {<br>
>          double abrBuffer = 2 * m_param->rc.rateTolerance * m_bitrate;<br>
> +         if (m_2pass)<br>
<br>
</div></div>white-space<br>
<div><div class="h5"><br>
> +        {<br>
> +            int64_t diff;<br>
> +            if (!m_isVbv)<br>
> +            {<br>
> +                m_predictedBits = m_totalBits;<br>
> +                if (rce->encodeOrder < m_param->frameNumThreads)<br>
> +                    m_predictedBits += (int64_t)(rce->encodeOrder * m_bitrate / m_fps) ;<br>
> +                else<br>
> +                    m_predictedBits += (int64_t)(m_param->frameNumThreads * m_bitrate / m_fps);<br>
> +            }<br>
> +            /* Adjust ABR buffer based on distance to the end of the video. */<br>
> +            if (m_numEntries > rce->encodeOrder)<br>
> +            {<br>
> +                uint64_t finalBits = m_rce2Pass[m_numEntries - 1].expectedBits;<br>
> +                double videoPos = (double)rce->expectedBits / finalBits;<br>
> +                double scaleFactor = sqrt((1 - videoPos) * m_numEntries);<br>
> +                abrBuffer *= 0.5 * X265_MAX(scaleFactor, 0.5);<br>
> +            }<br>
><br>
> -        /* 1pass ABR */<br>
> +            diff = m_predictedBits - (int64_t)rce->expectedBits;<br>
> +            q = rce->newQScale;<br>
> +            q /= Clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer);<br>
> +            if (((rce->encodeOrder + 1 - m_param->frameNumThreads) >= m_fps) &&<br>
> +                (m_expectedBitsSum > 0))<br>
> +            {<br>
> +                /* Adjust quant based on the difference between<br>
> +                 * achieved and expected bitrate so far */<br>
> +                double curTime = (double)rce->encodeOrder / m_numEntries;<br>
> +                double w = Clip3(0.0, 1.0, curTime * 100);<br>
> +                q *= pow((double)m_totalBits / m_expectedBitsSum, w);<br>
> +            }<br>
> +            rce->qpNoVbv = x265_qScale2qp(q);<br>
> +            if (m_isVbv)<br>
> +            {<br>
> +                /* Do not overflow vbv */<br>
> +                double expectedSize = qScale2bits(rce, q);<br>
> +                double expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>
> +                double expectedFullness = rce->expectedVbv / m_bufferSize;<br>
> +                double qmax = q * (2 - expectedFullness);<br>
> +                double sizeConstraint = 1 + expectedFullness;<br>
> +                qmax = X265_MAX(qmax, rce->newQScale);<br>
> +                if (expectedFullness < .05)<br>
> +                    qmax = MAX_MAX_QPSCALE;<br>
> +                qmax = X265_MIN(qmax, MAX_MAX_QPSCALE);<br>
> +                while (((expectedVbv < rce->expectedVbv/sizeConstraint) && (q < qmax)) ||<br>
> +                        ((expectedVbv < 0) && (q < MAX_MAX_QPSCALE)))<br>
> +                {<br>
> +                    q *= 1.05;<br>
> +                    expectedSize = qScale2bits(rce, q);<br>
> +                    expectedVbv = m_bufferFill + m_bufferRate - expectedSize;<br>
> +                }<br>
><br>
> -        /* Calculate the quantizer which would have produced the desired<br>
> -         * average bitrate if it had been applied to all frames so far.<br>
> -         * Then modulate that quant based on the current frame's complexity<br>
> -         * relative to the average complexity so far (using the 2pass RCEQ).<br>
> -         * Then bias the quant up or down if total size so far was far from<br>
> -         * the target.<br>
> -         * Result: Depending on the value of rate_tolerance, there is a<br>
> -         * tradeoff between quality and bitrate precision. But at large<br>
> -         * tolerances, the bit distribution approaches that of 2pass. */<br>
> -<br>
> -        double wantedBits, overflow = 1;<br>
> -        rce->movingAvgSum = m_shortTermCplxSum;<br>
> -        m_shortTermCplxSum *= 0.5;<br>
> -        m_shortTermCplxCount *= 0.5;<br>
> -        m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);<br>
> -        m_shortTermCplxCount++;<br>
> -        /* coeffBits to be used in 2-pass */<br>
> -        rce->coeffBits = (int)m_currentSatd;<br>
> -        rce->blurredComplexity = m_shortTermCplxSum / m_shortTermCplxCount;<br>
> -        rce->mvBits = 0;<br>
> -        rce->sliceType = m_sliceType;<br>
> -<br>
> -        if (m_param->rc.rateControlMode == X265_RC_CRF)<br>
> -        {<br>
> -            q = getQScale(rce, m_rateFactorConstant);<br>
> +            }<br>
> +            q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);<br>
>          }<br>
>          else<br>
>          {<br>
> -            if (!m_param->rc.bStatRead)<br>
> -                checkAndResetABR(rce, false);<br>
> -            q = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);<br>
> +            /* 1pass ABR */<br>
><br>
> -            /* ABR code can potentially be counterproductive in CBR, so just<br>
> -             * don't bother.  Don't run it if the frame complexity is zero<br>
> -             * either. */<br>
> -            if (!m_isCbr && m_currentSatd)<br>
> +            /* Calculate the quantizer which would have produced the desired<br>
> +             * average bitrate if it had been applied to all frames so far.<br>
> +             * Then modulate that quant based on the current frame's complexity<br>
> +             * relative to the average complexity so far (using the 2pass RCEQ).<br>
> +             * Then bias the quant up or down if total size so far was far from<br>
> +             * the target.<br>
> +             * Result: Depending on the value of rate_tolerance, there is a<br>
> +             * tradeoff between quality and bitrate precision. But at large<br>
> +             * tolerances, the bit distribution approaches that of 2pass. */<br>
> +<br>
> +            double wantedBits, overflow = 1;<br>
> +            rce->movingAvgSum = m_shortTermCplxSum;<br>
> +            m_shortTermCplxSum *= 0.5;<br>
> +            m_shortTermCplxCount *= 0.5;<br>
> +            m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);<br>
> +            m_shortTermCplxCount++;<br>
> +            /* coeffBits to be used in 2-pass */<br>
> +            rce->coeffBits = (int)m_currentSatd;<br>
> +            rce->blurredComplexity = m_shortTermCplxSum / m_shortTermCplxCount;<br>
> +            rce->mvBits = 0;<br>
> +            rce->sliceType = m_sliceType;<br>
> +<br>
> +            if (m_param->rc.rateControlMode == X265_RC_CRF)<br>
>              {<br>
> -                /* use framesDone instead of POC as poc count is not serial with bframes enabled */<br>
> -                double timeDone = (double)(m_framesDone - m_param->frameNumThreads + 1) * m_frameDuration;<br>
> -                wantedBits = timeDone * m_bitrate;<br>
> -                if (wantedBits > 0 && m_totalBits > 0 && !m_residualFrames)<br>
> +                q = getQScale(rce, m_rateFactorConstant);<br>
> +            }<br>
> +            else<br>
> +            {<br>
> +                if (!m_param->rc.bStatRead)<br>
> +                    checkAndResetABR(rce, false);<br>
> +                q = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);<br>
> +<br>
> +                /* ABR code can potentially be counterproductive in CBR, so just<br>
> +                 * don't bother.  Don't run it if the frame complexity is zero<br>
> +                 * either. */<br>
> +                if (!m_isCbr && m_currentSatd)<br>
>                  {<br>
> -                    abrBuffer *= X265_MAX(1, sqrt(timeDone));<br>
> -                    overflow = Clip3(.5, 2.0, 1.0 + (m_totalBits - wantedBits) / abrBuffer);<br>
> -                    q *= overflow;<br>
> +                    /* use framesDone instead of POC as poc count is not serial with bframes enabled */<br>
> +                    double timeDone = (double)(m_framesDone - m_param->frameNumThreads + 1) * m_frameDuration;<br>
> +                    wantedBits = timeDone * m_bitrate;<br>
> +                    if (wantedBits > 0 && m_totalBits > 0 && !m_residualFrames)<br>
> +                    {<br>
> +                        abrBuffer *= X265_MAX(1, sqrt(timeDone));<br>
> +                        overflow = Clip3(.5, 2.0, 1.0 + (m_totalBits - wantedBits) / abrBuffer);<br>
> +                        q *= overflow;<br>
> +                    }<br>
>                  }<br>
>              }<br>
> +<br>
> +            if (m_sliceType == I_SLICE && m_param->keyframeMax > 1<br>
> +                && m_lastNonBPictType != I_SLICE && !m_isAbrReset)<br>
> +            {<br>
> +                q = x265_qp2qScale(m_accumPQp / m_accumPNorm);<br>
> +                q /= fabs(m_param->rc.ipFactor);<br>
> +            }<br>
> +            else if (m_framesDone > 0)<br>
> +            {<br>
> +                if (m_param->rc.rateControlMode != X265_RC_CRF)<br>
> +                {<br>
> +                    double lqmin = 0, lqmax = 0;<br>
> +                    lqmin = m_lastQScaleFor[m_sliceType] / m_lstep;<br>
> +                    lqmax = m_lastQScaleFor[m_sliceType] * m_lstep;<br>
> +                    if (!m_residualFrames)<br>
> +                    {<br>
> +                        if (overflow > 1.1 && m_framesDone > 3)<br>
> +                            lqmax *= m_lstep;<br>
> +                        else if (overflow < 0.9)<br>
> +                            lqmin /= m_lstep;<br>
> +                    }<br>
> +                    q = Clip3(lqmin, lqmax, q);<br>
> +                }<br>
> +            }<br>
> +            else if (m_qCompress != 1 && m_param->rc.rateControlMode == X265_RC_CRF)<br>
> +            {<br>
> +                q = x265_qp2qScale(CRF_INIT_QP) / fabs(m_param->rc.ipFactor);<br>
> +            }<br>
> +            else if (m_framesDone == 0 && !m_isVbv)<br>
> +            {<br>
> +                /* for ABR alone, clip the first I frame qp */<br>
> +                double lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;<br>
> +                q = X265_MIN(lqmax, q);<br>
> +            }<br>
> +            q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);<br>
> +            rce->qpNoVbv = x265_qScale2qp(q);<br>
> +            q = clipQscale(pic, q);<br>
>          }<br>
> -<br>
> -        if (m_sliceType == I_SLICE && m_param->keyframeMax > 1<br>
> -            && m_lastNonBPictType != I_SLICE && !m_isAbrReset)<br>
> -        {<br>
> -            q = x265_qp2qScale(m_accumPQp / m_accumPNorm);<br>
> -            q /= fabs(m_param->rc.ipFactor);<br>
> -        }<br>
> -        else if (m_framesDone > 0)<br>
> -        {<br>
> -            if (m_param->rc.rateControlMode != X265_RC_CRF)<br>
> -            {<br>
> -                double lqmin = 0, lqmax = 0;<br>
> -                lqmin = m_lastQScaleFor[m_sliceType] / m_lstep;<br>
> -                lqmax = m_lastQScaleFor[m_sliceType] * m_lstep;<br>
> -                if (!m_residualFrames)<br>
> -                {<br>
> -                    if (overflow > 1.1 && m_framesDone > 3)<br>
> -                        lqmax *= m_lstep;<br>
> -                    else if (overflow < 0.9)<br>
> -                        lqmin /= m_lstep;<br>
> -                }<br>
> -                q = Clip3(lqmin, lqmax, q);<br>
> -            }<br>
> -        }<br>
> -        else if (m_qCompress != 1 && m_param->rc.rateControlMode == X265_RC_CRF)<br>
> -        {<br>
> -            q = x265_qp2qScale(CRF_INIT_QP) / fabs(m_param->rc.ipFactor);<br>
> -        }<br>
> -        else if (m_framesDone == 0 && !m_isVbv)<br>
> -        {<br>
> -            /* for ABR alone, clip the first I frame qp */<br>
> -            double lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;<br>
> -            q = X265_MIN(lqmax, q);<br>
> -        }<br>
> -        q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);<br>
> -        rce->qpNoVbv = x265_qScale2qp(q);<br>
> -        q = clipQscale(pic, q);<br>
>          m_lastQScaleFor[m_sliceType] = q;<br>
> -        if (m_curSlice->getPOC() == 0 || m_lastQScaleFor[P_SLICE] < q)<br>
> +        if ((m_curSlice->getPOC() == 0 || m_lastQScaleFor[P_SLICE] < q) && !(m_2pass && !m_isVbv))<br>
>              m_lastQScaleFor[P_SLICE] = q * fabs(m_param->rc.ipFactor);<br>
><br>
> -        rce->frameSizePlanned = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> +        if (m_2pass && m_isVbv)<br>
> +            rce->frameSizePlanned = qScale2bits(rce, q);<br>
> +        else<br>
> +            rce->frameSizePlanned = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
>          rce->frameSizeEstimated = rce->frameSizePlanned;<br>
>          /* Always use up the whole VBV in this case. */<br>
>          if (m_singleFrameVbv)<br>
>              rce->frameSizePlanned = m_bufferRate;<br>
><br>
> +        rce->newQScale = q;<br>
>          return q;<br>
>      }<br>
>  }<br>
> @@ -1913,6 +2009,8 @@<br>
>              m_totalBits += bits;<br>
>          }<br>
>      }<br>
> +    if (m_2pass)<br>
> +        m_expectedBitsSum += qScale2bits(rce, x265_qp2qScale(rce->newQp));<br>
><br>
>      if (m_isVbv)<br>
>      {<br>
> diff -r 9d3683ab096b -r cf8b11c379f3 source/encoder/ratecontrol.h<br>
> --- a/source/encoder/ratecontrol.h    Sat Jul 12 01:18:07 2014 -0500<br>
> +++ b/source/encoder/ratecontrol.h    Thu Jul 10 22:56:40 2014 +0530<br>
> @@ -158,6 +158,8 @@<br>
>      int      m_numEntries;<br>
>      RateControlEntry *m_rce2Pass;<br>
>      double   m_lastAccumPNorm;<br>
> +    int64_t  m_predictedBits;<br>
> +    double   m_expectedBitsSum;   /* sum of qscale2bits after rceq, ratefactor, and overflow, only includes finished frames */<br>
>      struct<br>
>      {<br>
>          uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree quantizer data. */<br>
</div></div>> _______________________________________________<br>
> x265-devel mailing list<br>
> <a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
> <a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
<span class="HOEnZb"><font color="#888888"><br>
--<br>
Steve Borho<br>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</font></span></blockquote></div><br></div>