<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>