<div dir="ltr"><div># HG changeset patch</div><div># User Aarthi Thirumalai</div><div># Date 1452501832 -19800</div><div># Mon Jan 11 14:13:52 2016 +0530</div><div># Node ID cee55e38a09310c1c3384ee72e548bd72a00a4e7</div><div># Parent f548abe8eae8fb75513a85d1b09233e706c7b5ba</div><div>rc: fix Rate Control for grainy content</div><div><br></div><div>optimize params for tune grain, reduce frequent qp fluctions to prevent grain loss</div><div><br></div><div>diff -r f548abe8eae8 -r cee55e38a093 source/common/param.cpp</div><div>--- a/source/common/param.cpp<span class="" style="white-space:pre"> </span>Wed Jan 20 18:27:42 2016 +0530</div><div>+++ b/source/common/param.cpp<span class="" style="white-space:pre"> </span>Mon Jan 11 14:13:52 2016 +0530</div><div>@@ -454,16 +454,11 @@</div><div> }</div><div> else if (!strcmp(tune, "grain"))</div><div> {</div><div>- param->deblockingFilterBetaOffset = -2;</div><div>- param->deblockingFilterTCOffset = -2;</div><div>- param->bIntraInBFrames = 0;</div><div>- param->rdoqLevel = 2;</div><div>- param->psyRdoq = 10.0;</div><div>- param->psyRd = 0.5;</div><div> param->rc.ipFactor = 1.1;</div><div>- param->rc.pbFactor = 1.1;</div><div>- param->rc.aqStrength = 0.3;</div><div>- param->rc.qCompress = 0.8;</div><div>+ param->rc.pbFactor = 1.0;</div><div>+ param->rc.cuTree = 0;</div><div>+ param->rc.aqMode = 0;</div><div>+ param->rc.qpStep = 1.0;</div><div> }</div><div> else</div><div> return -1;</div><div>diff -r f548abe8eae8 -r cee55e38a093 source/encoder/ratecontrol.cpp</div><div>--- a/source/encoder/ratecontrol.cpp<span class="" style="white-space:pre"> </span>Wed Jan 20 18:27:42 2016 +0530</div><div>+++ b/source/encoder/ratecontrol.cpp<span class="" style="white-space:pre"> </span>Mon Jan 11 14:13:52 2016 +0530</div><div>@@ -190,6 +190,8 @@</div><div> m_numEntries = 0;</div><div> m_isSceneTransition = false;</div><div> m_lastPredictorReset = 0;</div><div>+ m_avgPFrameQp = 0;</div><div>+ m_isFirstMiniGop = false;</div><div> if (m_param->rc.rateControlMode == X265_RC_CRF)</div><div> {</div><div> m_param->rc.qp = (int)m_param->rc.rfConstant;</div><div>@@ -288,9 +290,13 @@</div><div> m_ipOffset = 6.0 * X265_LOG2(m_param->rc.ipFactor);</div><div> m_pbOffset = 6.0 * X265_LOG2(m_param->rc.pbFactor);</div><div> </div><div>+ for (int i = 0; i < QP_MAX_MAX; i++)</div><div>+ m_qpToEncodedBits[i] = 0;</div><div>+</div><div> /* Adjust the first frame in order to stabilize the quality level compared to the rest */</div><div> #define ABR_INIT_QP_MIN (24)</div><div> #define ABR_INIT_QP_MAX (40)</div><div>+#define ABR_INIT_QP_GRAIN_MAX (32)</div><div> #define ABR_SCENECUT_INIT_QP_MIN (12)</div><div> #define CRF_INIT_QP (int)m_param->rc.rfConstant</div><div> for (int i = 0; i < 3; i++)</div><div>@@ -361,6 +367,7 @@</div><div> m_amortizeFraction = 0.85;</div><div> m_amortizeFrames = m_param->totalFrames / 2;</div><div> }</div><div>+</div><div> for (int i = 0; i < s_slidingWindowFrames; i++)</div><div> {</div><div> m_satdCostWindow[i] = 0;</div><div>@@ -370,15 +377,19 @@</div><div> m_isPatternPresent = false;</div><div> m_numBframesInPattern = 0;</div><div> </div><div>+ m_isGrainEnabled = false;</div><div>+ if(m_param->rc.pbFactor <= 1.1 && !m_param->rc.cuTree) // tune for grainy content OR equal p-b frame sizes</div><div>+ m_isGrainEnabled = true;</div><div>+</div><div> /* 720p videos seem to be a good cutoff for cplxrSum */</div><div>- double tuneCplxFactor = (m_param->rc.cuTree && m_ncu > 3600) ? 2.5 : 1;</div><div>-</div><div>+ double tuneCplxFactor = (m_ncu > 3600 && m_param->rc.cuTree) ? 2.5 : m_isGrainEnabled ? 1.9 : 1;</div><div> /* estimated ratio that produces a reasonable QP for the first I-frame */</div><div> m_cplxrSum = .01 * pow(7.0e5, m_qCompress) * pow(m_ncu, 0.5) * tuneCplxFactor;</div><div> m_wantedBitsWindow = m_bitrate * m_frameDuration;</div><div> m_accumPNorm = .01;</div><div> m_accumPQp = (m_param->rc.rateControlMode == X265_RC_CRF ? CRF_INIT_QP : ABR_INIT_QP_MIN) * m_accumPNorm;</div><div> </div><div>+</div><div> /* Frame Predictors used in vbv */</div><div> initFramePredictors();</div><div> if (!m_statFileOut && (m_param->rc.bStatWrite || m_param->rc.bStatRead))</div><div>@@ -1049,12 +1060,12 @@</div><div> }</div><div> m_pred[0].coeff = m_pred[3].coeff = 0.75;</div><div> m_pred[0].coeffMin = m_pred[3].coeffMin = 0.75 / 4;</div><div>- if (m_param->rc.qCompress >= 0.8) // when tuned for grain </div><div>+ if (m_isGrainEnabled) // when tuned for grain </div><div> {</div><div> m_pred[1].coeffMin = 0.75 / 4;</div><div> m_pred[1].coeff = 0.75;</div><div>- m_pred[0].coeff = m_pred[3].coeff = 0.5;</div><div>- m_pred[0].coeffMin = m_pred[3].coeffMin = 0.5 / 4;</div><div>+ m_pred[0].coeff = m_pred[3].coeff = 0.75;</div><div>+ m_pred[0].coeffMin = m_pred[3].coeffMin = 0.75 / 4;</div><div> }</div><div> }</div><div> </div><div>@@ -1089,10 +1100,12 @@</div><div> }</div><div> rce->isActive = true;</div><div> bool isRefFrameScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refFrameList[0][0]->m_lowres.bScenecut;</div><div>+ m_isFirstMiniGop = m_sliceType == I_SLICE ? true : m_isFirstMiniGop;</div><div> if (curFrame->m_lowres.bScenecut)</div><div> {</div><div> m_isSceneTransition = true;</div><div> m_lastPredictorReset = rce->encodeOrder;</div><div>+</div><div> initFramePredictors();</div><div> }</div><div> else if (m_sliceType != B_SLICE && !isRefFrameScenecut)</div><div>@@ -1197,7 +1210,7 @@</div><div> double q = x265_qScale2qp(rateEstimateQscale(curFrame, rce));</div><div> q = x265_clip3((double)QP_MIN, (double)QP_MAX_MAX, q);</div><div> m_qp = int(q + 0.5);</div><div>- rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = q;</div><div>+ rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = int(q + 0.5);</div><div> /* copy value of lastRceq into thread local rce struct *to be used in RateControlEnd() */</div><div> rce->qRceq = m_lastRceq;</div><div> accumPQpUpdate();</div><div>@@ -1450,7 +1463,7 @@</div><div> }</div><div> </div><div> if (wantedBits > 0 && encodedBits > 0 && (!m_partialResidualFrames || </div><div>- m_param->rc.bStrictCbr))</div><div>+ m_param->rc.bStrictCbr || m_isGrainEnabled))</div><div> {</div><div> abrBuffer *= X265_MAX(1, sqrt(timeDone));</div><div> overflow = x265_clip3(.5, 2.0, 1.0 + (encodedBits - wantedBits) / abrBuffer);</div><div>@@ -1460,6 +1473,22 @@</div><div> return qScale;</div><div> }</div><div> </div><div>+double RateControl::tuneQScaleForGrain(double rcOverflow)</div><div>+{</div><div>+ double qpstepBy1 = pow(2, 0.5 / 6.0);</div><div>+ double qScaleAvg = x265_qp2qScale(m_avgPFrameQp);</div><div>+ double q = m_lastQScaleFor[P_SLICE];</div><div>+ int curQp = int (x265_qScale2qp(m_lastQScaleFor[P_SLICE]) + 0.5);</div><div>+ double curBitrate = m_qpToEncodedBits[curQp] * int(m_fps + 0.5);</div><div>+ int newQp = rcOverflow > 1 ? curQp + 1 : curQp - 1 ;</div><div>+ double projectedBitrate = int(m_fps + 0.5) * m_qpToEncodedBits[newQp];</div><div>+ if (curBitrate > 0 && projectedBitrate > 0)</div><div>+ q = abs(projectedBitrate - m_bitrate) < abs (curBitrate - m_bitrate) ? x265_qp2qScale(newQp) : m_lastQScaleFor[P_SLICE];</div><div>+ else</div><div>+ q = rcOverflow > 1 ? qScaleAvg * qpstepBy1 : rcOverflow < 1 ? qScaleAvg / qpstepBy1 : m_lastQScaleFor[P_SLICE];</div><div>+ return q;</div><div>+}</div><div>+</div><div> double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)</div><div> {</div><div> double q;</div><div>@@ -1525,6 +1554,7 @@</div><div> q0 = q1;</div><div> }</div><div> }</div><div>+</div><div> if (prevRefSlice->m_sliceType == B_SLICE && IS_REFERENCED(m_curSlice->m_refFrameList[0][0]))</div><div> q0 -= m_pbOffset / 2;</div><div> if (nextRefSlice->m_sliceType == B_SLICE && IS_REFERENCED(m_curSlice->m_refFrameList[1][0]))</div><div>@@ -1535,7 +1565,9 @@</div><div> q = q1;</div><div> else if (i1)</div><div> q = q0;</div><div>- else</div><div>+ else if(m_isGrainEnabled)</div><div>+ q = q1;</div><div>+ else</div><div> q = (q0 * dt1 + q1 * dt0) / (dt0 + dt1);</div><div> </div><div> if (IS_REFERENCED(curFrame))</div><div>@@ -1543,7 +1575,7 @@</div><div> else</div><div> q += m_pbOffset;</div><div> </div><div>- /* Set a min qp at scenechanges and transitions */</div><div>+ /* Set a min qp at scenechanges and transitions */</div><div> if (m_isSceneTransition)</div><div> {</div><div> q = X265_MAX(ABR_SCENECUT_INIT_QP_MIN, q);</div><div>@@ -1553,11 +1585,28 @@</div><div> double qScale = x265_qp2qScale(q);</div><div> rce->qpNoVbv = q;</div><div> double lmin = 0, lmax = 0;</div><div>+ if (m_isGrainEnabled && m_isFirstMiniGop)</div><div>+ {</div><div>+ lmin = m_lastQScaleFor[P_SLICE] / m_lstep;</div><div>+ lmax = m_lastQScaleFor[P_SLICE] * m_lstep;</div><div>+ double tunedQscale = tuneAbrQScaleFromFeedback(qScale);</div><div>+ double overflow = tunedQscale / qScale;</div><div>+ if (!m_isAbrReset)</div><div>+ qScale = x265_clip3(lmin, lmax, qScale);</div><div>+ m_avgPFrameQp = m_avgPFrameQp == 0 ? rce->qpNoVbv : m_avgPFrameQp;</div><div>+ if (overflow != 1)</div><div>+ {</div><div>+ qScale = tuneQScaleForGrain(overflow);</div><div>+ q = x265_qScale2qp(qScale);</div><div>+ }</div><div>+ rce->qpNoVbv = q;</div><div>+ }</div><div> if (m_isVbv)</div><div> {</div><div> lmin = m_lastQScaleFor[P_SLICE] / m_lstep;</div><div> lmax = m_lastQScaleFor[P_SLICE] * m_lstep;</div><div>- if (m_isCbr)</div><div>+</div><div>+ if (m_isCbr && !m_isGrainEnabled)</div><div> {</div><div> qScale = tuneAbrQScaleFromFeedback(qScale);</div><div> if (!m_isAbrReset)</div><div>@@ -1581,7 +1630,10 @@</div><div> rce->frameSizePlanned = X265_MIN(rce->frameSizePlanned, rce->frameSizeMaximum);</div><div> rce->frameSizeEstimated = rce->frameSizePlanned;</div><div> }</div><div>+</div><div> rce->newQScale = qScale;</div><div>+ if(rce->bLastMiniGopBFrame)</div><div>+ m_isFirstMiniGop = false;</div><div> return qScale;</div><div> }</div><div> else</div><div>@@ -1675,8 +1727,17 @@</div><div> if (!m_param->rc.bStatRead)</div><div> checkAndResetABR(rce, false);</div><div> double initialQScale = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);</div><div>- q = tuneAbrQScaleFromFeedback(initialQScale);</div><div>- overflow = q / initialQScale;</div><div>+ double tunedQScale = tuneAbrQScaleFromFeedback(initialQScale);</div><div>+ overflow = tunedQScale / initialQScale;</div><div>+ q = !m_partialResidualFrames? tunedQScale : initialQScale;</div><div>+ bool isEncodeEnd = (m_param->totalFrames && </div><div>+ m_framesDone > 0.75 * m_param->totalFrames) ? 1 : 0;</div><div>+ bool isEncodeBeg = m_framesDone < (int)(m_fps + 0.5);</div><div>+ if(m_isGrainEnabled && m_sliceType!= I_SLICE && !isEncodeEnd &&</div><div>+ ((overflow < 1.05 && overflow > 0.95) || isEncodeBeg))</div><div>+ {</div><div>+ q = tuneQScaleForGrain(overflow);</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>@@ -1684,6 +1745,7 @@</div><div> if (!m_param->rc.bStrictCbr)</div><div> q = x265_qp2qScale(m_accumPQp / m_accumPNorm);</div><div> q /= fabs(m_param->rc.ipFactor);</div><div>+ m_avgPFrameQp = 0;</div><div> }</div><div> else if (m_framesDone > 0)</div><div> {</div><div>@@ -1708,8 +1770,18 @@</div><div> else if (m_framesDone == 0 && !m_isVbv && m_param->rc.rateControlMode == X265_RC_ABR)</div><div> {</div><div> /* for ABR alone, clip the first I frame qp */</div><div>- lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;</div><div>- q = X265_MIN(lqmax, q);</div><div>+ if (m_isGrainEnabled)</div><div>+ {</div><div>+ /* to maintain grain uniformity, set I frame qp in a fixed range */</div><div>+ lqmax = x265_qp2qScale(ABR_INIT_QP_GRAIN_MAX) * (m_lstep * m_lstep);</div><div>+ lqmin = x265_qp2qScale(ABR_INIT_QP_GRAIN_MAX) / (m_lstep * m_lstep);</div><div>+ q = x265_clip3(lqmin, lqmax, q);</div><div>+ }</div><div>+ else</div><div>+ {</div><div>+ lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;</div><div>+ q = X265_MIN(lqmax, q);</div><div>+ }</div><div> }</div><div> q = x265_clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);</div><div> /* Set a min qp at scenechanges and transitions */</div><div>@@ -1720,6 +1792,11 @@</div><div> m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale, m_lastQScaleFor[P_SLICE]);</div><div> }</div><div> rce->qpNoVbv = x265_qScale2qp(q);</div><div>+ if(m_sliceType == P_SLICE)</div><div>+ {</div><div>+ m_avgPFrameQp = m_avgPFrameQp == 0 ? rce->qpNoVbv : m_avgPFrameQp;</div><div>+ m_avgPFrameQp = (m_avgPFrameQp + rce->qpNoVbv) / 2;</div><div>+ }</div><div> q = clipQscale(curFrame, rce, q);</div><div> /* clip qp to permissible range after vbv-lookahead estimation to avoid possible</div><div> * mispredictions by initial frame size predictors, after each scenecut */</div><div>@@ -2426,6 +2503,11 @@</div><div> int pos = m_sliderPos - m_param->frameNumThreads;</div><div> if (pos >= 0)</div><div> m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;</div><div>+ if(rce->sliceType != I_SLICE)</div><div>+ {</div><div>+ int qp = int (rce->qpaRc + 0.5);</div><div>+ m_qpToEncodedBits[qp] = m_qpToEncodedBits[qp] == 0 ? actualBits : (m_qpToEncodedBits[qp] + actualBits) * 0.5;</div><div>+ }</div><div> }</div><div> </div><div> if (m_2pass)</div><div>diff -r f548abe8eae8 -r cee55e38a093 source/encoder/ratecontrol.h</div><div>--- a/source/encoder/ratecontrol.h<span class="" style="white-space:pre"> </span>Wed Jan 20 18:27:42 2016 +0530</div><div>+++ b/source/encoder/ratecontrol.h<span class="" style="white-space:pre"> </span>Mon Jan 11 14:13:52 2016 +0530</div><div>@@ -126,7 +126,7 @@</div><div> bool m_isVbv;</div><div> bool m_isCbr;</div><div> bool m_singleFrameVbv;</div><div>-</div><div>+ bool m_isGrainEnabled;</div><div> bool m_isAbrReset;</div><div> int m_lastAbrResetPoc;</div><div> </div><div>@@ -141,7 +141,8 @@</div><div> double m_vbvMaxRate; /* in kbps */</div><div> double m_rateFactorMaxIncrement; /* Don't allow RF above (CRF + this value). */</div><div> double m_rateFactorMaxDecrement; /* don't allow RF below (this value). */</div><div>-</div><div>+ double m_avgPFrameQp;</div><div>+ bool m_isFirstMiniGop;</div><div> Predictor m_pred[4]; /* Slice predictors to preidct bits for each Slice type - I,P,Bref and B */</div><div> int64_t m_leadingNoBSatd;</div><div> int m_predType; /* Type of slice predictors to be used - depends on the slice type */</div><div>@@ -178,7 +179,7 @@</div><div> bool m_isPatternPresent;</div><div> bool m_isSceneTransition;</div><div> int m_lastPredictorReset;</div><div>-</div><div>+ double m_qpToEncodedBits[QP_MAX_MAX];</div><div> /* a common variable on which rateControlStart, rateControlEnd and rateControUpdateStats waits to</div><div> * sync the calls to these functions. For example</div><div> * -F2:</div><div>@@ -269,6 +270,7 @@</div><div> bool vbv2Pass(uint64_t allAvailableBits, int frameCount, int startPos);</div><div> bool findUnderflow(double *fills, int *t0, int *t1, int over, int framesCount);</div><div> bool fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax);</div><div>+ double tuneQScaleForGrain(double rcOverflow);</div><div> };</div><div> }</div><div> #endif // ifndef X265_RATECONTROL_H</div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jan 20, 2016 at 2:33 PM, <span dir="ltr"><<a href="mailto:aarthi@multicorewareinc.com" target="_blank">aarthi@multicorewareinc.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"># HG changeset patch<br>
# User Aarthi Thirumalai<br>
# Date 1452501832 -19800<br>
# Mon Jan 11 14:13:52 2016 +0530<br>
# Node ID 46e5a95c852732058200d9a7bb34261011341cff<br>
# Parent 808ece071d225f300feaf08709a9f5e0872edc89<br>
rc: fix Rate Control for grainy content<br>
<br>
optimize params for tune grain, reduce frequent qp fluctions to prevent grain loss<br>
<br>
diff -r 808ece071d22 -r 46e5a95c8527 source/common/param.cpp<br>
--- a/source/common/param.cpp Mon Jan 18 21:21:25 2016 +0530<br>
+++ b/source/common/param.cpp Mon Jan 11 14:13:52 2016 +0530<br>
@@ -454,16 +454,11 @@<br>
}<br>
else if (!strcmp(tune, "grain"))<br>
{<br>
- param->deblockingFilterBetaOffset = -2;<br>
- param->deblockingFilterTCOffset = -2;<br>
- param->bIntraInBFrames = 0;<br>
- param->rdoqLevel = 2;<br>
- param->psyRdoq = 10.0;<br>
- param->psyRd = 0.5;<br>
param->rc.ipFactor = 1.1;<br>
- param->rc.pbFactor = 1.1;<br>
- param->rc.aqStrength = 0.3;<br>
- param->rc.qCompress = 0.8;<br>
+ param->rc.pbFactor = 1.0;<br>
+ param->rc.cuTree = 0;<br>
+ param->rc.aqMode = 0;<br>
+ param->rc.qpStep = 1.0;<br>
}<br>
else<br>
return -1;<br>
diff -r 808ece071d22 -r 46e5a95c8527 source/encoder/ratecontrol.cpp<br>
--- a/source/encoder/ratecontrol.cpp Mon Jan 18 21:21:25 2016 +0530<br>
+++ b/source/encoder/ratecontrol.cpp Mon Jan 11 14:13:52 2016 +0530<br>
@@ -190,6 +190,8 @@<br>
m_numEntries = 0;<br>
m_isSceneTransition = false;<br>
m_lastPredictorReset = 0;<br>
+ m_avgPFrameQp = 0;<br>
+ m_isFirstMiniGop = false;<br>
if (m_param->rc.rateControlMode == X265_RC_CRF)<br>
{<br>
m_param->rc.qp = (int)m_param->rc.rfConstant;<br>
@@ -288,6 +290,9 @@<br>
m_ipOffset = 6.0 * X265_LOG2(m_param->rc.ipFactor);<br>
m_pbOffset = 6.0 * X265_LOG2(m_param->rc.pbFactor);<br>
<br>
+ for (int i = 0; i < QP_MAX_MAX; i++)<br>
+ m_qpToEncodedBits[i] = 0;<br>
+<br>
/* Adjust the first frame in order to stabilize the quality level compared to the rest */<br>
#define ABR_INIT_QP_MIN (24)<br>
#define ABR_INIT_QP_MAX (40)<br>
@@ -361,6 +366,7 @@<br>
m_amortizeFraction = 0.85;<br>
m_amortizeFrames = m_param->totalFrames / 2;<br>
}<br>
+<br>
for (int i = 0; i < s_slidingWindowFrames; i++)<br>
{<br>
m_satdCostWindow[i] = 0;<br>
@@ -370,15 +376,19 @@<br>
m_isPatternPresent = false;<br>
m_numBframesInPattern = 0;<br>
<br>
+ m_isGrainEnabled = false;<br>
+ if(m_param->rc.pbFactor <= 1.1 && !m_param->rc.cuTree) // tune for grainy content OR equal p-b frame sizes<br>
+ m_isGrainEnabled = true;<br>
+<br>
/* 720p videos seem to be a good cutoff for cplxrSum */<br>
- double tuneCplxFactor = (m_param->rc.cuTree && m_ncu > 3600) ? 2.5 : 1;<br>
-<br>
+ double tuneCplxFactor = (m_ncu > 3600 && m_param->rc.cuTree) ? 2.5 : m_isGrainEnabled ? 2 : 1;<br>
/* estimated ratio that produces a reasonable QP for the first I-frame */<br>
m_cplxrSum = .01 * pow(7.0e5, m_qCompress) * pow(m_ncu, 0.5) * tuneCplxFactor;<br>
m_wantedBitsWindow = m_bitrate * m_frameDuration;<br>
m_accumPNorm = .01;<br>
m_accumPQp = (m_param->rc.rateControlMode == X265_RC_CRF ? CRF_INIT_QP : ABR_INIT_QP_MIN) * m_accumPNorm;<br>
<br>
+<br>
/* Frame Predictors used in vbv */<br>
initFramePredictors();<br>
if (!m_statFileOut && (m_param->rc.bStatWrite || m_param->rc.bStatRead))<br>
@@ -1049,7 +1059,7 @@<br>
}<br>
m_pred[0].coeff = m_pred[3].coeff = 0.75;<br>
m_pred[0].coeffMin = m_pred[3].coeffMin = 0.75 / 4;<br>
- if (m_param->rc.qCompress >= 0.8) // when tuned for grain<br>
+ if (m_isGrainEnabled) // when tuned for grain<br>
{<br>
m_pred[1].coeffMin = 0.75 / 4;<br>
m_pred[1].coeff = 0.75;<br>
@@ -1089,10 +1099,12 @@<br>
}<br>
rce->isActive = true;<br>
bool isRefFrameScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refFrameList[0][0]->m_lowres.bScenecut;<br>
+ m_isFirstMiniGop = m_sliceType == I_SLICE ? true : m_isFirstMiniGop;<br>
if (curFrame->m_lowres.bScenecut)<br>
{<br>
m_isSceneTransition = true;<br>
m_lastPredictorReset = rce->encodeOrder;<br>
+<br>
initFramePredictors();<br>
}<br>
else if (m_sliceType != B_SLICE && !isRefFrameScenecut)<br>
@@ -1197,7 +1209,7 @@<br>
double q = x265_qScale2qp(rateEstimateQscale(curFrame, rce));<br>
q = x265_clip3((double)QP_MIN, (double)QP_MAX_MAX, q);<br>
m_qp = int(q + 0.5);<br>
- rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = q;<br>
+ rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = int(q + 0.5);<br>
/* copy value of lastRceq into thread local rce struct *to be used in RateControlEnd() */<br>
rce->qRceq = m_lastRceq;<br>
accumPQpUpdate();<br>
@@ -1450,7 +1462,7 @@<br>
}<br>
<br>
if (wantedBits > 0 && encodedBits > 0 && (!m_partialResidualFrames ||<br>
- m_param->rc.bStrictCbr))<br>
+ m_param->rc.bStrictCbr || m_isGrainEnabled))<br>
{<br>
abrBuffer *= X265_MAX(1, sqrt(timeDone));<br>
overflow = x265_clip3(.5, 2.0, 1.0 + (encodedBits - wantedBits) / abrBuffer);<br>
@@ -1460,6 +1472,22 @@<br>
return qScale;<br>
}<br>
<br>
+double RateControl::tuneQScaleForGrain(double rcOverflow)<br>
+{<br>
+ double qpstepBy1 = pow(2, 0.5 / 6.0);<br>
+ double qScaleAvg = x265_qp2qScale(m_avgPFrameQp);<br>
+ double q = m_lastQScaleFor[P_SLICE];<br>
+ int curQp = int (x265_qScale2qp(m_lastQScaleFor[P_SLICE]) + 0.5);<br>
+ double curBitrate = m_qpToEncodedBits[curQp] * int(m_fps + 0.5);<br>
+ int newQp = rcOverflow > 1 ? curQp + 1 : curQp - 1 ;<br>
+ double projectedBitrate = int(m_fps + 0.5) * m_qpToEncodedBits[newQp];<br>
+ if (curBitrate > 0 && projectedBitrate > 0)<br>
+ q = abs(projectedBitrate - m_bitrate) < abs (curBitrate - m_bitrate) ? x265_qp2qScale(newQp) : m_lastQScaleFor[P_SLICE];<br>
+ else<br>
+ q = rcOverflow > 1 ? qScaleAvg * qpstepBy1 : rcOverflow < 1 ? qScaleAvg / qpstepBy1 : m_lastQScaleFor[P_SLICE];<br>
+ return q;<br>
+}<br>
+<br>
double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br>
{<br>
double q;<br>
@@ -1525,6 +1553,7 @@<br>
q0 = q1;<br>
}<br>
}<br>
+<br>
if (prevRefSlice->m_sliceType == B_SLICE && IS_REFERENCED(m_curSlice->m_refFrameList[0][0]))<br>
q0 -= m_pbOffset / 2;<br>
if (nextRefSlice->m_sliceType == B_SLICE && IS_REFERENCED(m_curSlice->m_refFrameList[1][0]))<br>
@@ -1535,7 +1564,9 @@<br>
q = q1;<br>
else if (i1)<br>
q = q0;<br>
- else<br>
+ else if(m_isGrainEnabled)<br>
+ q = q1;<br>
+ else<br>
q = (q0 * dt1 + q1 * dt0) / (dt0 + dt1);<br>
<br>
if (IS_REFERENCED(curFrame))<br>
@@ -1543,7 +1574,7 @@<br>
else<br>
q += m_pbOffset;<br>
<br>
- /* Set a min qp at scenechanges and transitions */<br>
+ /* Set a min qp at scenechanges and transitions */<br>
if (m_isSceneTransition)<br>
{<br>
q = X265_MAX(ABR_SCENECUT_INIT_QP_MIN, q);<br>
@@ -1553,11 +1584,28 @@<br>
double qScale = x265_qp2qScale(q);<br>
rce->qpNoVbv = q;<br>
double lmin = 0, lmax = 0;<br>
+ if (m_isGrainEnabled && m_isFirstMiniGop)<br>
+ {<br>
+ lmin = m_lastQScaleFor[P_SLICE] / m_lstep;<br>
+ lmax = m_lastQScaleFor[P_SLICE] * m_lstep;<br>
+ double tunedQscale = tuneAbrQScaleFromFeedback(qScale);<br>
+ double overflow = tunedQscale / qScale;<br>
+ if (!m_isAbrReset)<br>
+ qScale = x265_clip3(lmin, lmax, qScale);<br>
+ m_avgPFrameQp = m_avgPFrameQp == 0 ? rce->qpNoVbv : m_avgPFrameQp;<br>
+ if (overflow != 1)<br>
+ {<br>
+ qScale = tuneQScaleForGrain(overflow);<br>
+ q = x265_qScale2qp(qScale);<br>
+ }<br>
+ rce->qpNoVbv = q;<br>
+ }<br>
if (m_isVbv)<br>
{<br>
lmin = m_lastQScaleFor[P_SLICE] / m_lstep;<br>
lmax = m_lastQScaleFor[P_SLICE] * m_lstep;<br>
- if (m_isCbr)<br>
+<br>
+ if (m_isCbr && !m_isGrainEnabled)<br>
{<br>
qScale = tuneAbrQScaleFromFeedback(qScale);<br>
if (!m_isAbrReset)<br>
@@ -1581,7 +1629,10 @@<br>
rce->frameSizePlanned = X265_MIN(rce->frameSizePlanned, rce->frameSizeMaximum);<br>
rce->frameSizeEstimated = rce->frameSizePlanned;<br>
}<br>
+<br>
rce->newQScale = qScale;<br>
+ if(rce->bLastMiniGopBFrame)<br>
+ m_isFirstMiniGop = false;<br>
return qScale;<br>
}<br>
else<br>
@@ -1675,8 +1726,17 @@<br>
if (!m_param->rc.bStatRead)<br>
checkAndResetABR(rce, false);<br>
double initialQScale = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);<br>
- q = tuneAbrQScaleFromFeedback(initialQScale);<br>
- overflow = q / initialQScale;<br>
+ double tunedQScale = tuneAbrQScaleFromFeedback(initialQScale);<br>
+ overflow = tunedQScale / initialQScale;<br>
+ q = !m_partialResidualFrames? tunedQScale : initialQScale;<br>
+ bool isEncodeEnd = (m_param->totalFrames &&<br>
+ m_framesDone > 0.75 * m_param->totalFrames) ? 1 : 0;<br>
+ bool isEncodeBeg = m_framesDone < (int)(m_fps + 0.5);<br>
+ if(m_isGrainEnabled && m_sliceType!= I_SLICE && !isEncodeEnd &&<br>
+ ((overflow < 1.05 && overflow > 0.95) || isEncodeBeg))<br>
+ {<br>
+ q = tuneQScaleForGrain(overflow);<br>
+ }<br>
}<br>
if (m_sliceType == I_SLICE && m_param->keyframeMax > 1<br>
&& m_lastNonBPictType != I_SLICE && !m_isAbrReset)<br>
@@ -1684,6 +1744,7 @@<br>
if (!m_param->rc.bStrictCbr)<br>
q = x265_qp2qScale(m_accumPQp / m_accumPNorm);<br>
q /= fabs(m_param->rc.ipFactor);<br>
+ m_avgPFrameQp = 0;<br>
}<br>
else if (m_framesDone > 0)<br>
{<br>
@@ -1720,6 +1781,11 @@<br>
m_lastQScaleFor[P_SLICE] = X265_MAX(minScenecutQscale, m_lastQScaleFor[P_SLICE]);<br>
}<br>
rce->qpNoVbv = x265_qScale2qp(q);<br>
+ if(m_sliceType == P_SLICE)<br>
+ {<br>
+ m_avgPFrameQp = m_avgPFrameQp == 0 ? rce->qpNoVbv : m_avgPFrameQp;<br>
+ m_avgPFrameQp = (m_avgPFrameQp + rce->qpNoVbv) / 2;<br>
+ }<br>
q = clipQscale(curFrame, rce, q);<br>
/* clip qp to permissible range after vbv-lookahead estimation to avoid possible<br>
* mispredictions by initial frame size predictors, after each scenecut */<br>
@@ -2426,6 +2492,11 @@<br>
int pos = m_sliderPos - m_param->frameNumThreads;<br>
if (pos >= 0)<br>
m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;<br>
+ if(rce->sliceType != I_SLICE)<br>
+ {<br>
+ int qp = int (rce->qpaRc + 0.5);<br>
+ m_qpToEncodedBits[qp] = m_qpToEncodedBits[qp] == 0 ? actualBits : (m_qpToEncodedBits[qp] + actualBits) * 0.5;<br>
+ }<br>
}<br>
<br>
if (m_2pass)<br>
diff -r 808ece071d22 -r 46e5a95c8527 source/encoder/ratecontrol.h<br>
--- a/source/encoder/ratecontrol.h Mon Jan 18 21:21:25 2016 +0530<br>
+++ b/source/encoder/ratecontrol.h Mon Jan 11 14:13:52 2016 +0530<br>
@@ -126,7 +126,7 @@<br>
bool m_isVbv;<br>
bool m_isCbr;<br>
bool m_singleFrameVbv;<br>
-<br>
+ bool m_isGrainEnabled;<br>
bool m_isAbrReset;<br>
int m_lastAbrResetPoc;<br>
<br>
@@ -141,7 +141,8 @@<br>
double m_vbvMaxRate; /* in kbps */<br>
double m_rateFactorMaxIncrement; /* Don't allow RF above (CRF + this value). */<br>
double m_rateFactorMaxDecrement; /* don't allow RF below (this value). */<br>
-<br>
+ double m_avgPFrameQp;<br>
+ bool m_isFirstMiniGop;<br>
Predictor m_pred[4]; /* Slice predictors to preidct bits for each Slice type - I,P,Bref and B */<br>
int64_t m_leadingNoBSatd;<br>
int m_predType; /* Type of slice predictors to be used - depends on the slice type */<br>
@@ -178,7 +179,7 @@<br>
bool m_isPatternPresent;<br>
bool m_isSceneTransition;<br>
int m_lastPredictorReset;<br>
-<br>
+ double m_qpToEncodedBits[QP_MAX_MAX];<br>
/* a common variable on which rateControlStart, rateControlEnd and rateControUpdateStats waits to<br>
* sync the calls to these functions. For example<br>
* -F2:<br>
@@ -269,6 +270,7 @@<br>
bool vbv2Pass(uint64_t allAvailableBits, int frameCount, int startPos);<br>
bool findUnderflow(double *fills, int *t0, int *t1, int over, int framesCount);<br>
bool fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax);<br>
+ double tuneQScaleForGrain(double rcOverflow);<br>
};<br>
}<br>
#endif // ifndef X265_RATECONTROL_H<br>
</blockquote></div><br></div>