<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sun, Oct 5, 2014 at 5:08 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 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></blockquote><div><br></div><div>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?<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
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></blockquote><div><br></div><div>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.<br><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<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" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br></div></div>