<p dir="ltr"><br>
On Oct 5, 2014 7:38 PM, "Deepthi Nandakumar" <<a href="mailto:deepthi@multicorewareinc.com">deepthi@multicorewareinc.com</a>> wrote:<br>
><br>
><br>
><br>
> On Sun, Oct 5, 2014 at 5:08 PM, <<a href="mailto:aarthi@multicorewareinc.com">aarthi@multicorewareinc.com</a>> wrote:<br>
>><br>
>> # HG changeset patch<br>
>> # User Aarthi Thirumalai<br>
>> # Date 1412460518 -19800<br>
>> # Sun Oct 05 03:38:38 2014 +0530<br>
>> # Node ID 41cb94e538b800d8792fac48ceb9f8bdf2a9f627<br>
>> # Parent b6d49505b179cb509aa76f3a065192f0b4926579<br>
>> rc: use a sliding window to calculate moving avg SatdCost for ABR Reset logic<br>
>><br>
>> contains improvements for detection of scene changes within Rate Control to stabilize qp and prevent<br>
>> extreme spikes in bitrate. Removes the blockiness or distortions in the frames that a streak of low-detailed<br>
>> frames and prevents vbv from overreacting at the points of scene cuts.<br>
>><br>
>> diff -r b6d49505b179 -r 41cb94e538b8 source/encoder/ratecontrol.cpp<br>
>> --- a/source/encoder/ratecontrol.cpp Thu Oct 02 16:47:55 2014 -0500<br>
>> +++ b/source/encoder/ratecontrol.cpp Sun Oct 05 03:38:38 2014 +0530<br>
>> @@ -40,6 +40,7 @@<br>
>> /* Amortize the partial cost of I frames over the next N frames */<br>
>> const double RateControl::s_amortizeFraction = 0.85;<br>
>> const int RateControl::s_amortizeFrames = 75;<br>
>> +const int RateControl::s_slidingWindowFrames = 20;<br>
><br>
><br>
> Does it make sense to set this based on the framerate? For a 60fps video, assume 1 sec of black frames, and continually triggering reset 3 times in a row, could this lead to VBV issues?</p>
<p dir="ltr">It won't trigger reset three times in this case..only the frame that ends this streak after 60frames will be identified as the scene change. <br>
But if we have a large window, we cannot identify a scene change with smaller sequence of blank frames. As the moving avg within the window may be high already.<br>
><br>
>> const char *RateControl::s_defaultStatFileName = "x265_2pass.log";<br>
>><br>
>> namespace {<br>
>> @@ -472,6 +473,12 @@<br>
>> m_framesDone = 0;<br>
>> m_residualCost = 0;<br>
>> m_partialResidualCost = 0;<br>
>> + for (int i = 0; i < s_slidingWindowFrames; i++)<br>
>> + {<br>
>> + m_satdCostWindow[i] = 0;<br>
>> + m_encodedBitsWindow[i] = 0;<br>
>> + }<br>
>> + m_sliderPos = 0;<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>
>> @@ -1344,6 +1351,24 @@<br>
>> g_sliceTypeToChar[m_sliceType], g_sliceTypeToChar[rce->sliceType]);<br>
>> }<br>
>> }<br>
>> + else<br>
>> + {<br>
>> + if (m_isAbr)<br>
>> + {<br>
>> + double slidingWindowCplxSum = 0;<br>
>> + for (int i = 0;i < s_slidingWindowFrames; i++)<br>
>> + {<br>
>> + slidingWindowCplxSum *= 0.5;<br>
>> + if (!m_satdCostWindow[i])<br>
>> + break;<br>
>> + slidingWindowCplxSum += m_satdCostWindow[i] / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);<br>
>> + }<br>
>> + rce->movingAvgSum = slidingWindowCplxSum;<br>
>> + m_satdCostWindow[m_sliderPos % s_slidingWindowFrames] = rce->lastSatd;<br>
>> + m_sliderPos++;<br>
>> + }<br>
>> + }<br>
><br>
><br>
> Did you mean to use m_sliderPos in this fashion? For movingAvgSum, you will end up weighting the frames wrongly - you want the closest frames weighted the most, and the furthest ones weighted the least.</p>
<p dir="ltr">Yes, you are right. The logic as it is, will be correct for weighing the frames when the first window is filling up.but once that's done and the window begins to slide, weighing order is messed up.<br>
I will fix this and start the order for weighing the average satd cost from frame : sliderPos (this will be the oldest frame in the window) if the sliderPos > windowSize . else the order start from 0 .</p>
<p dir="ltr">><br>
>> +<br>
>> if (m_sliceType == B_SLICE)<br>
>> {<br>
>> /* B-frames don't have independent rate control, but rather get the<br>
>> @@ -1478,7 +1503,7 @@<br>
>> * tolerances, the bit distribution approaches that of 2pass. */<br>
>><br>
>> double wantedBits, overflow = 1;<br>
>> - rce->movingAvgSum = m_shortTermCplxSum;<br>
>> +<br>
>> m_shortTermCplxSum *= 0.5;<br>
>> m_shortTermCplxCount *= 0.5;<br>
>> m_shortTermCplxSum += m_currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);<br>
>> @@ -1619,8 +1644,12 @@<br>
>> {<br>
>> if (!m_isAbrReset && rce->movingAvgSum > 0)<br>
>> {<br>
>> + int64_t shrtTermWantedBits = (int64_t) (X265_MIN(m_sliderPos, s_slidingWindowFrames) * m_bitrate * m_frameDuration);<br>
>> + int64_t shrtTermTotalBitsSum = 0;<br>
>> // Reset ABR if prev frames are blank to prevent further sudden overflows/ high bit rate spikes.<br>
>> - double underflow = (m_totalBits - m_wantedBitsWindow) / abrBuffer;<br>
>> + for (int i = 0; i < s_slidingWindowFrames ; i++)<br>
>> + shrtTermTotalBitsSum += m_encodedBitsWindow[i];<br>
>> + double underflow = (shrtTermTotalBitsSum - shrtTermWantedBits) / abrBuffer;<br>
>> const double epsilon = 0.0001f;<br>
>> if (underflow < epsilon && !isFrameDone)<br>
>> {<br>
>> @@ -1792,9 +1821,10 @@<br>
>> q = X265_MAX(q0 / 2, q);<br>
>> }<br>
>><br>
>> - if (!m_isCbr)<br>
>> + if (!m_isCbr || m_isAbrReset)<br>
>> q = X265_MAX(q0, q);<br>
>><br>
>> +<br>
>> if (m_rateFactorMaxIncrement)<br>
>> {<br>
>> double qpNoVbv = x265_qScale2qp(q0);<br>
>> @@ -2111,30 +2141,29 @@<br>
>> }<br>
>> }<br>
>> }<br>
>> - if (!m_isAbrReset)<br>
>> +<br>
>> + if (m_param->rc.aqMode || m_isVbv)<br>
>> {<br>
>> - if (m_param->rc.aqMode || m_isVbv)<br>
>> + if (pic->m_qpaRc)<br>
>> {<br>
>> - if (pic->m_qpaRc)<br>
>> - {<br>
>> - for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
>> - pic->m_avgQpRc += pic->m_qpaRc[i];<br>
>> + for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
>> + pic->m_avgQpRc += pic->m_qpaRc[i];<br>
>><br>
>> - pic->m_avgQpRc /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
>> - rce->qpaRc = pic->m_avgQpRc;<br>
>> - // copy avg RC qp to m_avgQpAq. To print out the correct qp when aq/cutree is disabled.<br>
>> - pic->m_avgQpAq = pic->m_avgQpRc;<br>
>> - }<br>
>> + pic->m_avgQpRc /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
>> + rce->qpaRc = pic->m_avgQpRc;<br>
>> + // copy avg RC qp to m_avgQpAq. To print out the correct qp when aq/cutree is disabled.<br>
>> + pic->m_avgQpAq = pic->m_avgQpRc;<br>
>> + }<br>
>><br>
>> - if (pic->m_qpaAq)<br>
>> - {<br>
>> - for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
>> - pic->m_avgQpAq += pic->m_qpaAq[i];<br>
>> + if (pic->m_qpaAq)<br>
>> + {<br>
>> + for (uint32_t i = 0; i < pic->getFrameHeightInCU(); i++)<br>
>> + pic->m_avgQpAq += pic->m_qpaAq[i];<br>
>><br>
>> - pic->m_avgQpAq /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
>> - }<br>
>> + pic->m_avgQpAq /= (pic->getFrameHeightInCU() * pic->getFrameWidthInCU());<br>
>> }<br>
>> }<br>
>> +<br>
>> // Write frame stats into the stats file if 2 pass is enabled.<br>
>> if (m_param->rc.bStatWrite)<br>
>> {<br>
>> @@ -2199,6 +2228,9 @@<br>
>> }<br>
>> m_wantedBitsWindow += m_frameDuration * m_bitrate;<br>
>> m_totalBits += bits - rce->rowTotalBits;<br>
>> + int pos = m_sliderPos - m_param->frameNumThreads;<br>
>> + if (pos >= 0)<br>
>> + m_encodedBitsWindow[pos % s_slidingWindowFrames] = actualBits;<br>
>> }<br>
>><br>
>> if (m_2pass)<br>
>> diff -r b6d49505b179 -r 41cb94e538b8 source/encoder/ratecontrol.h<br>
>> --- a/source/encoder/ratecontrol.h Thu Oct 02 16:47:55 2014 -0500<br>
>> +++ b/source/encoder/ratecontrol.h Sun Oct 05 03:38:38 2014 +0530<br>
>> @@ -173,7 +173,9 @@<br>
>> int64_t m_totalBits; /* total bits used for already encoded frames */<br>
>> int m_framesDone; /* # of frames passed through RateCotrol already */<br>
>> double m_fps;<br>
>> -<br>
>> + int64_t m_satdCostWindow[50];<br>
>> + int m_sliderPos;<br>
>> + int64_t m_encodedBitsWindow[50];<br>
>> /* a common variable on which rateControlStart, rateControlEnd and rateControUpdateStats waits to<br>
>> * sync the calls to these functions. For example<br>
>> * -F2:<br>
>> @@ -233,6 +235,7 @@<br>
>><br>
>> static const double s_amortizeFraction;<br>
>> static const int s_amortizeFrames;<br>
>> + static const int s_slidingWindowFrames;<br>
>> static const char *s_defaultStatFileName;<br>
>><br>
>> int m_residualFrames;<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">https://mailman.videolan.org/listinfo/x265-devel</a><br>
><br>
><br>
><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">https://mailman.videolan.org/listinfo/x265-devel</a><br>
><br>
</p>