<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Jul 11, 2014 at 11:58 AM, 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 Thu, Jul 10, 2014 at 12:56 PM, <<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 1404933617 -19800<br>
> # Thu Jul 10 00:50:17 2014 +0530<br>
> # Node ID 418b68734fd83bf32dbdd4a097e51ce455267c3d<br>
> # Parent cbfe2ac89d418f7cf9cc53ad31b7eb2c06fbcb85<br>
> rc: init second pass in multi pass encode<br>
><br>
> read stat file from previous pass and compute the blurred<br>
> complexity of each frame<br>
><br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/common/common.cpp<br>
> --- a/source/common/common.cpp Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/common/common.cpp Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -159,3 +159,51 @@<br>
><br>
> return size;<br>
> }<br>
> +<br>
> +char* x265_slurp_file(const char *filename)<br>
> +{<br>
> + if (!filename)<br>
> + return NULL;<br>
> +<br>
> + int bError = 0;<br>
> + size_t fSize;<br>
> + char *buf = NULL;<br>
> +<br>
> + FILE *fh = fopen(filename, "rb");<br>
> + if (!fh)<br>
> + {<br>
> + x265_log(NULL, X265_LOG_ERROR, "unable to open file %s \n", filename);<br>
> + return NULL;<br>
> + }<br>
> +<br>
> + bError |= fseek(fh, 0, SEEK_END) < 0;<br>
> + bError |= (fSize = ftell(fh)) <= 0;<br>
> + bError |= fseek(fh, 0, SEEK_SET) < 0;<br>
> + if (bError)<br>
> + goto error;<br>
> +<br>
> + buf = X265_MALLOC(char, fSize + 2);<br>
> + if (!buf)<br>
> + {<br>
> + x265_log(NULL, X265_LOG_ERROR, "unable to allocate memory \n");<br>
> + goto error;<br>
> + }<br>
> +<br>
> + bError |= fread(buf, 1, fSize, fh) != fSize;<br>
> + if (buf[fSize - 1] != '\n')<br>
> + buf[fSize++] = '\n';<br>
> + buf[fSize] = 0;<br>
> + fclose(fh);<br>
> +<br>
> + if (bError)<br>
> + {<br>
> + x265_log(NULL, X265_LOG_ERROR, "unable to read the file\n");<br>
> + free(buf);<br>
> + buf = NULL;<br>
> + }<br>
> + return buf;<br>
> +<br>
> +error:<br>
> + fclose(fh);<br>
> + return NULL;<br>
> +}<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/common/common.h<br>
> --- a/source/common/common.h Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/common/common.h Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -204,5 +204,5 @@<br>
> double x265_qp2qScale(double qp);<br>
><br>
> uint32_t x265_picturePlaneSize(int csp, int width, int height, int plane);<br>
> -<br>
> +char* x265_slurp_file(const char *filename);<br>
> #endif // ifndef X265_COMMON_H<br>
<br>
</div></div>can you split this into another patch?<br></blockquote><div> ok </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class=""><br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/common/param.cpp<br>
> --- a/source/common/param.cpp Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/common/param.cpp Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -1212,9 +1212,10 @@<br>
><br>
> #define BOOL(param, cliopt) \<br>
> s += sprintf(s, " %s", (param) ? cliopt : "no-"cliopt);<br>
> -<br>
> + s += sprintf(s, "%dx%d", p->sourceWidth,p->sourceHeight);<br>
> + s += sprintf(s, " fps=%u/%u", p->fpsNum, p->fpsDenom);<br>
> + s += sprintf(s, " bitdepth=%d",p->internalBitDepth);<br>
> BOOL(p->bEnableWavefront, "wpp");<br>
> - s += sprintf(s, " fps=%d/%d", p->fpsNum, p->fpsDenom);<br>
> s += sprintf(s, " ctu=%d", p->maxCUSize);<br>
> s += sprintf(s, " tu-intra-depth=%d", p->tuQTMaxIntraDepth);<br>
> s += sprintf(s, " tu-inter-depth=%d", p->tuQTMaxInterDepth);<br>
> @@ -1286,7 +1287,7 @@<br>
> {<br>
> s += sprintf(s, " ip_ratio=%.2f", p->rc.ipFactor);<br>
> if (p->bframes)<br>
> - s += sprintf(s, " pb_ratio=%.2f", p->rc.pbFactor);<br>
> + s += sprintf(s, " pb_ratio=%.2f ", p->rc.pbFactor);<br>
<br>
</div>is there a reason for the trailing space here?<br></blockquote><div>no, my mistake. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
in param_parse, these are ipratio/pbratio or ip-factor/pb-factor<br>
<div><div class="h5"><br>
> }<br>
> #undef BOOL<br>
> return buf;<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/encoder/encoder.cpp<br>
> --- a/source/encoder/encoder.cpp Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/encoder/encoder.cpp Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -1346,7 +1346,7 @@<br>
> p->rc.aqStrength = 0.0;<br>
> }<br>
><br>
> - if (p->lookaheadDepth == 0 && p->rc.cuTree)<br>
> + if (p->lookaheadDepth == 0 && p->rc.cuTree && !p->rc.bStatRead)<br>
> {<br>
> x265_log(p, X265_LOG_WARNING, "cuTree disabled, requires lookahead to be enabled\n");<br>
> p->rc.cuTree = 0;<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/encoder/frameencoder.cpp<br>
> --- a/source/encoder/frameencoder.cpp Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/encoder/frameencoder.cpp Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -490,6 +490,7 @@<br>
> compressCTURows();<br>
><br>
> if (m_param->rc.bStatWrite)<br>
> + {<br>
> // accumulate intra,inter,skip cu count per frame for 2 pass<br>
> for (int i = 0; i < m_numRows; i++)<br>
> {<br>
> @@ -497,7 +498,11 @@<br>
> m_frameStats.cuCount_p += m_rows[i].m_pCuCnt;<br>
> m_frameStats.cuCount_skip += m_rows[i].m_skipCuCnt;<br>
> }<br>
> -<br>
> + double totalCuCount = m_frameStats.cuCount_i + m_frameStats.cuCount_p + m_frameStats.cuCount_skip;<br>
> + m_frameStats.cuCount_i /= totalCuCount;<br>
> + m_frameStats.cuCount_p /= totalCuCount;<br>
> + m_frameStats.cuCount_skip /= totalCuCount;<br>
> + }<br>
> if (m_sps.getUseSAO())<br>
> {<br>
> SAOParam* saoParam = m_frame->getPicSym()->getSaoParam();<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/encoder/frameencoder.h<br>
> --- a/source/encoder/frameencoder.h Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/encoder/frameencoder.h Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -61,7 +61,7 @@<br>
> /* Texture bits (DCT coefs) */<br>
> int coeffBits;<br>
> int miscBits;<br>
> - /* CU type counts */<br>
> + /* CU type counts stored as percentage*/<br>
<br>
</div></div>ws nit<br>
<div><div class="h5"><br>
> double cuCount_i;<br>
> double cuCount_p;<br>
> double cuCount_skip;<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/encoder/ratecontrol.cpp<br>
> --- a/source/encoder/ratecontrol.cpp Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/encoder/ratecontrol.cpp Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -45,6 +45,24 @@<br>
><br>
> namespace {<br>
><br>
> +#define CMP_OPT_FIRST_PASS(opt, param_val)\<br>
> +{\<br>
> + bErr = 0;\<br>
> + p = strstr(opts, opt "=");\<br>
> + char* q = strstr(opts, "no-"opt);\<br>
> + if (p && sscanf(p, opt "=%d" , &i) && param_val != i)\<br>
> + bErr = 1;\<br>
> + else if (!param_val && !q)\<br>
> + bErr = 1;\<br>
> + else if (param_val && (q || !strstr(opts, opt)))\<br>
> + bErr = 1;\<br>
> + if (bErr)\<br>
> + {\<br>
> + x265_log(m_param, X265_LOG_ERROR, "different " opt " setting than first pass (%d vs %d)\n", param_val, i);\<br>
> + return false;\<br>
> + }\<br>
> +}<br>
> +<br>
> inline int calcScale(uint32_t x)<br>
> {<br>
> static uint8_t lut[16] = {4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0};<br>
> @@ -97,6 +115,15 @@<br>
> return output;<br>
> }<br>
><br>
> +inline double qScale2bits(RateControlEntry *rce, double qScale)<br>
> +{<br>
> + if (qScale < 0.1)<br>
> + qScale = 0.1;<br>
> + return (rce->coeffBits + .1) * pow(rce->qScale / qScale, 1.1)<br>
> + + rce->mvBits * pow(X265_MAX(rce->qScale, 1) / X265_MAX(qScale, 1), 0.5)<br>
> + + rce->miscBits;<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>
> @@ -274,6 +301,7 @@<br>
> m_residualCost = 0;<br>
> m_rateFactorMaxIncrement = 0;<br>
> m_rateFactorMaxDecrement = 0;<br>
> + m_fps = m_param->fpsNum / m_param->fpsDenom;<br>
><br>
> if (m_param->rc.rateControlMode == X265_RC_CRF)<br>
> {<br>
> @@ -398,6 +426,174 @@<br>
> if (!fileName)<br>
> fileName = s_defaultStatFileName;<br>
><br>
> + /* Load stat file and init 2pass algo */<br>
> + if (m_param->rc.bStatRead)<br>
> + {<br>
> + char *p, *statsIn, *statsBuf;<br>
> + /* read 1st pass stats */<br>
> + statsIn = statsBuf = x265_slurp_file(fileName);<br>
> + if (!statsBuf)<br>
> + return false;<br>
> + if (m_param->rc.cuTree)<br>
> + {<br>
> + char *tmpFile = strcatFilename(fileName, ".cutree");<br>
> + if (!tmpFile)<br>
> + return false;<br>
> + m_cutreeStatFileIn = fopen(tmpFile, "rb");<br>
> + x265_free(tmpFile);<br>
> + if (!m_cutreeStatFileIn)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "can't open stats file %s\n", tmpFile);<br>
> + return false;<br>
> + }<br>
> + }<br>
> +<br>
> + /* check whether 1st pass options were compatible with current options */<br>
> + if (strncmp(statsBuf, "#options:", 9))<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR,"options list in stats file not valid\n");<br>
> + return false;<br>
> + }<br>
> + {<br>
> + int i, j;<br>
> + uint32_t k , l;<br>
> + bool bErr = false;<br>
> + char *opts = statsBuf;<br>
> + statsIn = strchr(statsBuf, '\n');<br>
> + if (!statsIn)<br>
> + return false;<br>
> + *statsIn = '\0';<br>
> + statsIn++;<br>
> + if (sscanf(opts, "#options: %dx%d", &i, &j) != 2)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "Resolution specified in stats file not valid\n");<br>
> + return false;<br>
> + }<br>
> + if ((p = strstr(opts, " fps=")) == 0 || sscanf(p, " fps=%u/%u", &k, &l) != 2)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "fps specified in stats file not valid\n");<br>
> + return false;<br>
> + }<br>
> + if (k != m_param->fpsNum || l != m_param->fpsDenom)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "fps mismatch with 1st pass (%u/%u vs %u/%u)\n",<br>
> + m_param->fpsNum, m_param->fpsDenom, k, l);<br>
> + return false;<br>
> + }<br>
> + CMP_OPT_FIRST_PASS("bitdepth", m_param->internalBitDepth);<br>
> + CMP_OPT_FIRST_PASS("weightp", m_param->bEnableWeightedPred);<br>
> + CMP_OPT_FIRST_PASS("bframes", m_param->bframes);<br>
> + CMP_OPT_FIRST_PASS("b-pyramid", m_param->bBPyramid);<br>
> + CMP_OPT_FIRST_PASS("open-gop", m_param->bOpenGOP);<br>
> + CMP_OPT_FIRST_PASS("keyint", m_param->keyframeMax);<br>
> + CMP_OPT_FIRST_PASS("wpp", m_param->bEnableWavefront);<br>
> +<br>
> + if ((p = strstr(opts, "b-adapt=")) != 0 && sscanf(p, "b-adapt=%d", &i) && i >= X265_B_ADAPT_NONE && i <= X265_B_ADAPT_TRELLIS)<br>
> + {<br>
> + m_param->bFrameAdaptive = i;<br>
> + }<br>
> + else if (m_param->bframes)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "b-adapt method specified in stats file not valid\n");<br>
> + return false;<br>
> + }<br>
> +<br>
> + if ((m_param->rc.cuTree || m_param->rc.vbvBufferSize) && ((p = strstr(opts, "rc-lookahead=")) != 0) && sscanf(p, "rc-lookahead=%d", &i))<br>
> + m_param->lookaheadDepth = i;<br>
> + }<br>
> + /* find number of pics */<br>
> + p = statsIn;<br>
> + int numEntries;<br>
> + for (numEntries = -1; p; numEntries++)<br>
> + p = strchr(p + 1, ';');<br>
> + if (!numEntries)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "empty stats file\n");<br>
> + return false;<br>
> + }<br>
> + m_numEntries = numEntries;<br>
> +<br>
> + if (m_param->totalFrames < m_numEntries && m_param->totalFrames > 0)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_WARNING, "2nd pass has fewer frames than 1st pass (%d vs %d)\n",<br>
> + m_param->totalFrames, m_numEntries);<br>
> + }<br>
> + if (m_param->totalFrames > m_numEntries)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "2nd pass has more frames than 1st pass (%d vs %d)\n",<br>
> + m_param->totalFrames, m_numEntries);<br>
> + return false;<br>
> + }<br>
> +<br>
> + m_rce2Pass = X265_MALLOC(RateControlEntry, m_numEntries);<br>
> + if (!m_rce2Pass)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2 pass cannot be allocated\n");<br>
> + return false;<br>
> + }<br>
> + /* init all to skipped p frames */<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + RateControlEntry *rce = &m_rce2Pass[i];<br>
> + rce->sliceType = P_SLICE;<br>
> + rce->qScale = rce->newQScale = x265_qp2qScale(20);<br>
> + rce->miscBits = m_ncu + 10;<br>
> + rce->newQp = 0;<br>
> + }<br>
> + /* read stats */<br>
> + p = statsIn;<br>
> + double totalQpAq = 0;<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + RateControlEntry *rce;<br>
> + int frameNumber;<br>
> + char picType;<br>
> + int e;<br>
> + char *next;<br>
> + double qpRc, qpAq;<br>
> + next = strstr(p, ";");<br>
> + if (next)<br>
> + *next++ = 0;<br>
> + e = sscanf(p, " in:%d ", &frameNumber);<br>
> +<br>
> + if (frameNumber < 0 || frameNumber >= m_numEntries)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "bad frame number (%d) at stats line %d\n", frameNumber, i);<br>
> + return false;<br>
> + }<br>
> + rce = &m_rce2Pass[frameNumber];<br>
> + e += sscanf(p, " in:%*d out:%*d type:%c dur:%lf q:%lf q-aq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",<br>
> + &picType, &rce->frameDuration, &qpRc, &qpAq, &rce->coeffBits,<br>
> + &rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount,<br>
> + &rce->skipCuCount);<br>
> +<br>
> + if (picType != 'b' || picType != 'p')<br>
> + rce->keptAsRef = true;<br>
> + if (picType == 'I' || picType == 'i')<br>
> + rce->sliceType = I_SLICE;<br>
> + else if (picType == 'P' || picType == 'p')<br>
> + rce->sliceType = P_SLICE;<br>
> + else if (picType == 'B' || picType == 'b')<br>
> + rce->sliceType = B_SLICE;<br>
> + else<br>
> + e = -1;<br>
> + if (e < 11)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e);<br>
> + return false;<br>
> + }<br>
> + rce->qScale = x265_qp2qScale(qpRc);<br>
> + totalQpAq += qpAq;<br>
> + p = next;<br>
> + }<br>
> + X265_FREE(statsBuf);<br>
> +<br>
> + if (m_param->rc.rateControlMode == X265_RC_ABR)<br>
> + {<br>
> + if (!initPass2())<br>
> + return false;<br>
> + } /* else we're using constant quant, so no need to run the bitrate allocation */<br>
> + }<br>
> /* Open output file */<br>
> /* If input and output files are the same, output to a temp file<br>
> * and move it to the real name only when it's complete */<br>
> @@ -411,7 +607,7 @@<br>
> x265_free(statFileTmpname);<br>
> if (!m_statFileOut)<br>
> {<br>
> - x265_log(m_param, X265_LOG_ERROR, "RateControl Init: can't open stats file\n");<br>
> + x265_log(m_param, X265_LOG_ERROR, " can't open stats file %s \n, statFileTmpname");<br>
> return false;<br>
> }<br>
> p = x265_param2string(m_param);<br>
> @@ -427,7 +623,7 @@<br>
> x265_free(statFileTmpname);<br>
> if (!m_cutreeStatFileOut)<br>
> {<br>
> - x265_log(m_param, X265_LOG_ERROR, "RateControl Init: can't open mbtree stats file\n");<br>
> + x265_log(m_param, X265_LOG_ERROR, "can't open mbtree stats file %s \n", statFileTmpname);<br>
> return false;<br>
> }<br>
> }<br>
> @@ -443,13 +639,11 @@<br>
><br>
> if (m_isVbv && !m_2pass)<br>
> {<br>
> - double fps = (double)m_param->fpsNum / m_param->fpsDenom;<br>
> -<br>
> /* We don't support changing the ABR bitrate right now,<br>
> * so if the stream starts as CBR, keep it CBR. */<br>
> - if (m_param->rc.vbvBufferSize < (int)(m_param->rc.vbvMaxBitrate / fps))<br>
> + if (m_param->rc.vbvBufferSize < (int)(m_param->rc.vbvMaxBitrate / m_fps))<br>
> {<br>
> - m_param->rc.vbvBufferSize = (int)(m_param->rc.vbvMaxBitrate / fps);<br>
> + m_param->rc.vbvBufferSize = (int)(m_param->rc.vbvMaxBitrate / m_fps);<br>
> x265_log(m_param, X265_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n",<br>
> m_param->rc.vbvBufferSize);<br>
> }<br>
> @@ -466,7 +660,7 @@<br>
> }<br>
> }<br>
><br>
> - m_bufferRate = vbvMaxBitrate / fps;<br>
> + m_bufferRate = vbvMaxBitrate / m_fps;<br>
> m_vbvMaxRate = vbvMaxBitrate;<br>
> m_bufferSize = vbvBufferSize;<br>
> m_singleFrameVbv = m_bufferRate * 1.1 > m_bufferSize;<br>
> @@ -538,6 +732,262 @@<br>
> #undef MAX_DURATION<br>
> }<br>
><br>
> + bool RateControl::initPass2()<br>
> +{<br>
> + uint64_t allConstBits = 0;<br>
> + double duration = 0;<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + duration += m_rce2Pass[i].frameDuration;<br>
> + uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * duration);<br>
> + double rateFactor, stepMult;<br>
> + double qBlur = m_param->rc.qblur;<br>
> + double cplxBlur = m_param->rc.complexityBlur;<br>
> + const int filterSize = (int)(qBlur * 4) | 1;<br>
> + double expectedBits;<br>
> + double *qScale, *blurredQscale;<br>
> + double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);<br>
> +<br>
> + /* find total/average complexity & const_bits */<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + allConstBits += m_rce2Pass[i].miscBits;<br>
> + }<br>
> +<br>
> + if (allAvailableBits < allConstBits)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_ERROR, "requested bitrate is too low. estimated minimum is %d kbps\n",<br>
> + (int)(allConstBits * m_fps / m_numEntries * 1000.));<br>
> + return false;<br>
> + }<br>
> +<br>
> + /* Blur complexities, to reduce local fluctuation of QP.<br>
> + * We don't blur the QPs directly, because then one very simple frame<br>
> + * could drag down the QP of a nearby complex frame and give it more<br>
> + * bits than intended. */<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + double weightSum = 0;<br>
> + double cplxSum = 0;<br>
> + double weight = 1.0;<br>
> + double gaussianWeight;<br>
> + /* weighted average of cplx of future frames */<br>
> + for (int j = 1; j < cplxBlur * 2 && j < m_numEntries - i; j++)<br>
> + {<br>
> + RateControlEntry *rcj = &m_rce2Pass[i + j];<br>
> + double frameDuration = CLIP_DURATION(rcj->frameDuration) / BASE_FRAME_DURATION;<br>
> + weight *= 1 - pow(rcj->iCuCount / m_ncu, 2);<br>
> + if (weight < 0.0001)<br>
> + break;<br>
> + gaussianWeight = weight * exp(-j * j / 200.0);<br>
> + weightSum += gaussianWeight;<br>
> + cplxSum += gaussianWeight * (qScale2bits(rcj, 1) - rcj->miscBits) / frameDuration;<br>
> + }<br>
> + /* weighted average of cplx of past frames */<br>
> + weight = 1.0;<br>
> + for (int j = 0; j <= cplxBlur * 2 && j <= i; j++)<br>
> + {<br>
> + RateControlEntry *rcj = &m_rce2Pass[i - j];<br>
> + double frameDuration = CLIP_DURATION(rcj->frameDuration) / BASE_FRAME_DURATION;<br>
> + gaussianWeight = weight * exp(-j * j / 200.0);<br>
> + weightSum += gaussianWeight;<br>
> + cplxSum += gaussianWeight * (qScale2bits(rcj, 1) - rcj->miscBits) / frameDuration;<br>
> + weight *= 1 - pow(rcj->iCuCount / m_ncu, 2);<br>
> + if (weight < .0001)<br>
> + break;<br>
> + }<br>
> + m_rce2Pass[i].blurredComplexity = cplxSum / weightSum;<br>
> + }<br>
> +<br>
> + CHECKED_MALLOC(qScale, double, m_numEntries);<br>
> + if (filterSize > 1)<br>
> + {<br>
> + CHECKED_MALLOC(blurredQscale, double, m_numEntries);<br>
> + }<br>
> + else<br>
> + blurredQscale = qScale;<br>
> +<br>
> + /* Search for a factor which, when multiplied by the RCEQ values from<br>
> + * each frame, adds up to the desired total size.<br>
> + * There is no exact closed-form solution because of VBV constraints and<br>
> + * because qscale2bits is not invertible, but we can start with the simple<br>
> + * approximation of scaling the 1st pass by the ratio of bitrates.<br>
> + * The search range is probably overkill, but speed doesn't matter here. */<br>
> +<br>
> + expectedBits = 1;<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + RateControlEntry* rce = &m_rce2Pass[i];<br>
> + double q = getQScale(rce, 1.0);<br>
> + expectedBits += qScale2bits(rce, q);<br>
> + m_lastQScaleFor[rce->sliceType] = q;<br>
> + }<br>
> + stepMult = allAvailableBits / expectedBits;<br>
> +<br>
> + rateFactor = 0;<br>
> + for (double step = 1E4 * stepMult; step > 1E-7 * stepMult; step *= 0.5)<br>
> + {<br>
> + expectedBits = 0;<br>
> + rateFactor += step;<br>
> +<br>
> + m_lastNonBPictType = -1;<br>
> + m_lastAccumPNorm = 1;<br>
> + m_accumPNorm = 0;<br>
> +<br>
> + m_lastQScaleFor[0] = m_lastQScaleFor[1] =<br>
> + m_lastQScaleFor[2] = pow(baseCplx, 1 - m_qCompress) / rateFactor;<br>
> +<br>
> + /* find qscale */<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + RateControlEntry *rce = &m_rce2Pass[i];<br>
> + qScale[i] = getQScale(rce, rateFactor);<br>
> + m_lastQScaleFor[rce->sliceType] = qScale[i];<br>
> + }<br>
> +<br>
> + /* fixed I/B qscale relative to P */<br>
> + for (int i = m_numEntries - 1; i >= 0; i--)<br>
> + {<br>
> + qScale[i] = getDiffLimitedQScale(&m_rce2Pass[i], qScale[i]);<br>
> + assert(qScale[i] >= 0);<br>
> + }<br>
> +<br>
> + /* smooth curve */<br>
> + if (filterSize > 1)<br>
> + {<br>
> + assert(filterSize % 2 == 1);<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + double q = 0.0, sum = 0.0;<br>
> +<br>
> + for (int j = 0; j < filterSize; j++)<br>
> + {<br>
> + int idx = i + j - filterSize / 2;<br>
> + double d = idx - i;<br>
> + double coeff = qBlur == 0 ? 1.0 : exp(-d * d / (qBlur * qBlur));<br>
> + if (idx < 0 || idx >= m_numEntries)<br>
> + continue;<br>
> + if (m_rce2Pass[i].sliceType != m_rce2Pass[idx].sliceType)<br>
> + continue;<br>
> + q += qScale[idx] * coeff;<br>
> + sum += coeff;<br>
> + }<br>
> + blurredQscale[i] = q / sum;<br>
> + }<br>
> + }<br>
> +<br>
> + /* find expected bits */<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + {<br>
> + RateControlEntry *rce = &m_rce2Pass[i];<br>
> + rce->newQScale = clipQscale(NULL, blurredQscale[i]); // check if needed<br>
> + assert(rce->newQScale >= 0);<br>
> + expectedBits += qScale2bits(rce, rce->newQScale);<br>
> + }<br>
> +<br>
> + if (expectedBits > allAvailableBits)<br>
> + rateFactor -= step;<br>
> + }<br>
> +<br>
> + X265_FREE(qScale);<br>
> + if (filterSize > 1)<br>
> + X265_FREE(blurredQscale);<br>
> +<br>
> + if (m_isVbv)<br>
> + if (vbv2Pass(allAvailableBits))<br>
> + return false;<br>
> + expectedBits = countExpectedBits();<br>
> +<br>
> + if (fabs(expectedBits / allAvailableBits - 1.0) > 0.01)<br>
> + {<br>
> + double avgq = 0;<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + avgq += m_rce2Pass[i].newQScale;<br>
> + avgq = x265_qScale2qp(avgq / m_numEntries);<br>
> +<br>
> + if (expectedBits > allAvailableBits || !m_isVbv)<br>
> + x265_log(m_param, X265_LOG_WARNING, "Error: 2pass curve failed to converge\n");<br>
> + x265_log(m_param, X265_LOG_WARNING, "target: %.2f kbit/s, expected: %.2f kbit/s, avg QP: %.4f\n",<br>
> + (double)m_param->rc.bitrate,<br>
> + expectedBits * m_fps / (m_numEntries * 1000.),<br>
> + avgq);<br>
> + if (expectedBits < allAvailableBits && avgq < MIN_QP + 2)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_WARNING, "try reducing target bitrate\n");<br>
> + }<br>
> + else if (expectedBits > allAvailableBits && avgq > MAX_QP - 2)<br>
> + {<br>
> + x265_log(m_param, X265_LOG_WARNING, "try increasing target bitrate\n");<br>
> + }<br>
> + else if (!(m_2pass && m_isVbv))<br>
> + x265_log(m_param, X265_LOG_WARNING, "internal error\n");<br>
> + }<br>
> +<br>
> + return true;<br>
> +fail:<br>
> + return false;<br>
> +}<br>
> +<br>
> +bool RateControl::vbv2Pass(uint64_t allAvailableBits)<br>
> +{<br>
> + /* for each interval of bufferFull .. underflow, uniformly increase the qp of all<br>
> + * frames in the interval until either buffer is full at some intermediate frame or the<br>
> + * last frame in the interval no longer underflows. Recompute intervals and repeat.<br>
> + * Then do the converse to put bits back into overflow areas until target size is met */<br>
> +<br>
> + double *fills;<br>
> + double expectedBits = 0;<br>
> + double adjustment;<br>
> + double prevBits = 0;<br>
> + int t0, t1;<br>
> + int iterations = 0 , adjMin, adjMax;<br>
> + CHECKED_MALLOC(fills, double, m_numEntries + 1);<br>
> + fills++;<br>
> +<br>
> + /* adjust overall stream size */<br>
> + do<br>
> + {<br>
> + iterations++;<br>
> + prevBits = expectedBits;<br>
> +<br>
> + if (expectedBits)<br>
> + { /* not first iteration */<br>
> + adjustment = X265_MAX(X265_MIN(expectedBits / allAvailableBits, 0.999), 0.9);<br>
> + fills[-1] = m_bufferSize * m_param->rc.vbvBufferInit;<br>
> + t0 = 0;<br>
> + /* fix overflows */<br>
> + adjMin = 1;<br>
> + while (adjMin && findUnderflow(fills, &t0, &t1, 1))<br>
> + {<br>
> + adjMin = fixUnderflow(t0, t1, adjustment, MIN_QPSCALE, MAX_MAX_QPSCALE);<br>
> + t0 = t1;<br>
> + }<br>
> + }<br>
> +<br>
> + fills[-1] = m_bufferSize * (1. - m_param->rc.vbvBufferInit);<br>
> + t0 = 0;<br>
> + /* fix underflows -- should be done after overflow, as we'd better undersize target than underflowing VBV */<br>
> + adjMax = 1;<br>
> + while (adjMax && findUnderflow(fills, &t0, &t1, 0))<br>
> + {<br>
> + adjMax = fixUnderflow(t0, t1, 1.001, MIN_QPSCALE, MAX_MAX_QPSCALE );<br>
> + }<br>
> +<br>
> + expectedBits = countExpectedBits();<br>
> + } while ((expectedBits < .995 * allAvailableBits) && ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)));<br>
> +<br>
> + if (!adjMax)<br>
> + x265_log(m_param, X265_LOG_WARNING, "vbv-maxrate issue, qpmax or vbv-maxrate too low\n");<br>
> +<br>
> + /* store expected vbv filling values for tracking when encoding */<br>
> + for (int i = 0; i < m_numEntries; i++)<br>
> + m_rce2Pass[i].expectedVbv = m_bufferSize - fills[i];<br>
> +<br>
> + X265_FREE(fills - 1);<br>
> + return true;<br>
> +fail:<br>
> + return false;<br>
> +}<br>
> +<br>
> void RateControl::rateControlStart(Frame* pic, Lookahead *l, RateControlEntry* rce, Encoder* enc)<br>
> {<br>
> m_curSlice = pic->getSlice();<br>
> @@ -621,6 +1071,128 @@<br>
> m_accumPQp += m_qp;<br>
> }<br>
><br>
> +double RateControl::getDiffLimitedQScale(RateControlEntry *rce, double q)<br>
> +{<br>
> + // force I/B quants as a function of P quants<br>
> + const double lastPqScale = m_lastQScaleFor[P_SLICE];<br>
> + const double lastNonBqScale= m_lastQScaleFor[m_lastNonBPictType];<br>
> + if (rce->sliceType == I_SLICE)<br>
> + {<br>
> + double iq = q;<br>
> + double pq = x265_qp2qScale(m_accumPQp / m_accumPNorm);<br>
> + double ipFactor = fabs(m_param->rc.ipFactor);<br>
> + /* don't apply ipFactor if the following frame is also I */<br>
> + if (m_accumPNorm <= 0)<br>
> + q = iq;<br>
> + else if (m_param->rc.ipFactor < 0)<br>
> + q = iq / ipFactor;<br>
> + else if (m_accumPNorm >= 1)<br>
> + q = pq / ipFactor;<br>
> + else<br>
> + q = m_accumPNorm * pq / ipFactor + (1 - m_accumPNorm) * iq;<br>
> + }<br>
> + else if (rce->sliceType == B_SLICE)<br>
> + {<br>
> + if (m_param->rc.pbFactor > 0)<br>
> + q = lastNonBqScale;<br>
> + if (!rce->keptAsRef)<br>
> + q *= fabs(m_param->rc.pbFactor);<br>
> + }<br>
> + else if (rce->sliceType == P_SLICE<br>
> + && m_lastNonBPictType == P_SLICE<br>
> + && rce->coeffBits == 0)<br>
> + {<br>
> + q = lastPqScale;<br>
> + }<br>
> +<br>
> + /* last qscale / qdiff stuff */<br>
> + if (m_lastNonBPictType == rce->sliceType &&<br>
> + (rce->sliceType != I_SLICE || m_lastAccumPNorm < 1))<br>
> + {<br>
> + double maxQscale = m_lastQScaleFor[rce->sliceType] * m_lstep;<br>
> + double minQscale = m_lastQScaleFor[rce->sliceType] / m_lstep;<br>
> + q = Clip3(minQscale, maxQscale, q);<br>
> + }<br>
> +<br>
> + m_lastQScaleFor[rce->sliceType] = q;<br>
> + if (rce->sliceType != B_SLICE)<br>
> + m_lastNonBPictType = rce->sliceType;<br>
> + if (rce->sliceType == I_SLICE)<br>
> + {<br>
> + m_lastAccumPNorm = m_accumPNorm;<br>
> + m_accumPNorm = 0;<br>
> + m_accumPQp = 0;<br>
> + }<br>
> + if (rce->sliceType == P_SLICE)<br>
> + {<br>
> + double mask = 1 - pow(rce->iCuCount / m_ncu, 2);<br>
> + m_accumPQp = mask * (x265_qScale2qp(q) + m_accumPQp);<br>
> + m_accumPNorm = mask * (1 + m_accumPNorm);<br>
> + }<br>
> +<br>
> + return q;<br>
> +}<br>
> +<br>
> +double RateControl::countExpectedBits()<br>
> +{<br>
> + double expectedBits = 0;<br>
> + for( int i = 0; i < m_numEntries; i++ )<br>
> + {<br>
> + RateControlEntry *rce = &m_rce2Pass[i];<br>
> + rce->expectedBits = (uint64_t)expectedBits;<br>
> + expectedBits += qScale2bits(rce, rce->newQScale);<br>
> + }<br>
> + return expectedBits;<br>
> +}<br>
> +<br>
> +bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over)<br>
> +{<br>
> + /* find an interval ending on an overflow or underflow (depending on whether<br>
> + * we're adding or removing bits), and starting on the earliest frame that<br>
> + * can influence the buffer fill of that end frame. */<br>
> + const double bufferMin = .1 * m_bufferSize;<br>
> + const double bufferMax = .9 * m_bufferSize;<br>
> + double fill = fills[*t0 - 1];<br>
> + double parity = over ? 1. : -1.;<br>
> + int start = -1, end = -1;<br>
> + for (int i = *t0; i < m_numEntries; i++)<br>
> + {<br>
> + fill += (m_rce2Pass[i].frameDuration * m_vbvMaxRate -<br>
> + qScale2bits(&m_rce2Pass[i], m_rce2Pass[i].newQScale)) * parity;<br>
> + fill = Clip3(0.0, m_bufferSize, fill);<br>
> + fills[i] = fill;<br>
> + if (fill <= bufferMin || i == 0)<br>
> + {<br>
> + if (end >= 0)<br>
> + break;<br>
> + start = i;<br>
> + }<br>
> + else if (fill >= bufferMax && start >= 0)<br>
> + end = i;<br>
> + }<br>
> + *t0 = start;<br>
> + *t1 = end;<br>
> + return start >= 0 && end >= 0;<br>
> +}<br>
> +<br>
> +bool RateControl::fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax)<br>
> +{<br>
> + double qscaleOrig, qscaleNew;<br>
> + bool adjusted = false;<br>
> + if (t0 > 0)<br>
> + t0++;<br>
> + for (int i = t0; i <= t1; i++)<br>
> + {<br>
> + qscaleOrig = m_rce2Pass[i].newQScale;<br>
> + qscaleOrig = Clip3(qscaleMin, qscaleMax, qscaleOrig);<br>
> + qscaleNew = qscaleOrig * adjustment;<br>
> + qscaleNew = Clip3(qscaleMin, qscaleMax, qscaleNew);<br>
> + m_rce2Pass[i].newQScale = qscaleNew;<br>
> + adjusted = adjusted || (qscaleNew != qscaleOrig);<br>
> + }<br>
> + return adjusted;<br>
> +}<br>
> +<br>
> double RateControl::rateEstimateQscale(Frame* pic, RateControlEntry *rce)<br>
> {<br>
> double q;<br>
> @@ -694,7 +1266,7 @@<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 = m_currentSatd;<br>
> + rce->coeffBits = (int)m_currentSatd;<br>
> rce->blurredComplexity = m_shortTermCplxSum / m_shortTermCplxCount;<br>
> rce->mvBits = 0;<br>
> rce->sliceType = m_sliceType;<br>
> @@ -762,9 +1334,7 @@<br>
><br>
> q = Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);<br>
> rce->qpNoVbv = x265_qScale2qp(q);<br>
> -<br>
> - if (m_isVbv && m_currentSatd > 0)<br>
> - q = clipQscale(pic, q);<br>
> + q = clipQscale(pic, q);<br>
><br>
> m_lastQScaleFor[m_sliceType] = q;<br>
><br>
> @@ -846,124 +1416,135 @@<br>
> // since they are controlled by referenced P-frames' QPs.<br>
> double q0 = q;<br>
><br>
> - if (m_param->lookaheadDepth || m_param->rc.cuTree ||<br>
> - m_param->scenecutThreshold ||<br>
> - (m_param->bFrameAdaptive && m_param->bframes))<br>
> + if (m_isVbv && m_currentSatd > 0)<br>
> {<br>
> - /* Lookahead VBV: If lookahead is done, raise the quantizer as necessary<br>
> - * such that no frames in the lookahead overflow and such that the buffer<br>
> - * is in a reasonable state by the end of the lookahead. */<br>
> + if (m_param->lookaheadDepth || m_param->rc.cuTree ||<br>
> + m_param->scenecutThreshold ||<br>
> + (m_param->bFrameAdaptive && m_param->bframes))<br>
> + {<br>
> + /* Lookahead VBV: If lookahead is done, raise the quantizer as necessary<br>
> + * such that no frames in the lookahead overflow and such that the buffer<br>
> + * is in a reasonable state by the end of the lookahead. */<br>
><br>
> - int terminate = 0;<br>
> + int terminate = 0;<br>
><br>
> - /* Avoid an infinite loop. */<br>
> - for (int iterations = 0; iterations < 1000 && terminate != 3; iterations++)<br>
> + /* Avoid an infinite loop. */<br>
> + for (int iterations = 0; iterations < 1000 && terminate != 3; iterations++)<br>
> + {<br>
> + double frameQ[3];<br>
> + double curBits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> + double bufferFillCur = m_bufferFill - curBits;<br>
> + double targetFill;<br>
> + double totalDuration = 0;<br>
> + frameQ[P_SLICE] = m_sliceType == I_SLICE ? q * m_param->rc.ipFactor : q;<br>
> + frameQ[B_SLICE] = frameQ[P_SLICE] * m_param->rc.pbFactor;<br>
> + frameQ[I_SLICE] = frameQ[P_SLICE] / m_param->rc.ipFactor;<br>
> + /* Loop over the planned future frames. */<br>
> + for (int j = 0; bufferFillCur >= 0 && bufferFillCur <= m_bufferSize; j++)<br>
> + {<br>
> + totalDuration += m_frameDuration;<br>
> + bufferFillCur += m_vbvMaxRate * m_frameDuration;<br>
> + int type = pic->m_lowres.plannedType[j];<br>
> + int64_t satd = pic->m_lowres.plannedSatd[j] >> (X265_DEPTH - 8);<br>
> + if (type == X265_TYPE_AUTO)<br>
> + break;<br>
> + type = IS_X265_TYPE_I(type) ? I_SLICE : IS_X265_TYPE_B(type) ? B_SLICE : P_SLICE;<br>
> + curBits = predictSize(&m_pred[type], frameQ[type], (double)satd);<br>
> + bufferFillCur -= curBits;<br>
> + }<br>
> +<br>
> + /* Try to get the buffer at least 50% filled, but don't set an impossible goal. */<br>
> + targetFill = X265_MIN(m_bufferFill + totalDuration * m_vbvMaxRate * 0.5, m_bufferSize * 0.5);<br>
> + if (bufferFillCur < targetFill)<br>
> + {<br>
> + q *= 1.01;<br>
> + terminate |= 1;<br>
> + continue;<br>
> + }<br>
> + /* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */<br>
> + targetFill = Clip3(m_bufferSize * 0.8, m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);<br>
> + if (m_isCbr && bufferFillCur > targetFill)<br>
> + {<br>
> + q /= 1.01;<br>
> + terminate |= 2;<br>
> + continue;<br>
> + }<br>
> + break;<br>
> + }<br>
> + }<br>
> + else<br>
> {<br>
> - double frameQ[3];<br>
> - double curBits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> - double bufferFillCur = m_bufferFill - curBits;<br>
> - double targetFill;<br>
> - double totalDuration = 0;<br>
> - frameQ[P_SLICE] = m_sliceType == I_SLICE ? q * m_param->rc.ipFactor : q;<br>
> - frameQ[B_SLICE] = frameQ[P_SLICE] * m_param->rc.pbFactor;<br>
> - frameQ[I_SLICE] = frameQ[P_SLICE] / m_param->rc.ipFactor;<br>
> - /* Loop over the planned future frames. */<br>
> - for (int j = 0; bufferFillCur >= 0 && bufferFillCur <= m_bufferSize; j++)<br>
> + /* Fallback to old purely-reactive algorithm: no lookahead. */<br>
> + if ((m_sliceType == P_SLICE ||<br>
> + (m_sliceType == I_SLICE && m_lastNonBPictType == I_SLICE)) &&<br>
> + m_bufferFill / m_bufferSize < 0.5)<br>
> {<br>
> - totalDuration += m_frameDuration;<br>
> - bufferFillCur += m_vbvMaxRate * m_frameDuration;<br>
> - int type = pic->m_lowres.plannedType[j];<br>
> - int64_t satd = pic->m_lowres.plannedSatd[j] >> (X265_DEPTH - 8);<br>
> - if (type == X265_TYPE_AUTO)<br>
> - break;<br>
> - type = IS_X265_TYPE_I(type) ? I_SLICE : IS_X265_TYPE_B(type) ? B_SLICE : P_SLICE;<br>
> - curBits = predictSize(&m_pred[type], frameQ[type], (double)satd);<br>
> - bufferFillCur -= curBits;<br>
> + q /= Clip3(0.5, 1.0, 2.0 * m_bufferFill / m_bufferSize);<br>
> }<br>
><br>
> - /* Try to get the buffer at least 50% filled, but don't set an impossible goal. */<br>
> - targetFill = X265_MIN(m_bufferFill + totalDuration * m_vbvMaxRate * 0.5, m_bufferSize * 0.5);<br>
> - if (bufferFillCur < targetFill)<br>
> + // Now a hard threshold to make sure the frame fits in VBV.<br>
> + // This one is mostly for I-frames.<br>
> + double bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> +<br>
> + // For small VBVs, allow the frame to use up the entire VBV.<br>
> + double maxFillFactor;<br>
> + maxFillFactor = m_bufferSize >= 5 * m_bufferRate ? 2 : 1;<br>
> + // For single-frame VBVs, request that the frame use up the entire VBV.<br>
> + double minFillFactor = m_singleFrameVbv ? 1 : 2;<br>
> +<br>
> + for (int iterations = 0; iterations < 10; iterations++)<br>
> {<br>
> - q *= 1.01;<br>
> - terminate |= 1;<br>
> - continue;<br>
> + double qf = 1.0;<br>
> + if (bits > m_bufferFill / maxFillFactor)<br>
> + qf = Clip3(0.2, 1.0, m_bufferFill / (maxFillFactor * bits));<br>
> + q /= qf;<br>
> + bits *= qf;<br>
> + if (bits < m_bufferRate / minFillFactor)<br>
> + q *= bits * minFillFactor / m_bufferRate;<br>
> + bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> }<br>
> - /* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */<br>
> - targetFill = Clip3(m_bufferSize * 0.8, m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5);<br>
> - if (m_isCbr && bufferFillCur > targetFill)<br>
> +<br>
> + q = X265_MAX(q0, q);<br>
> + }<br>
> +<br>
> + // Check B-frame complexity, and use up any bits that would<br>
> + // overflow before the next P-frame.<br>
> + if (m_sliceType == P_SLICE && !m_singleFrameVbv)<br>
> + {<br>
> + int nb = m_bframes;<br>
> + double bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> + double bbits = predictSize(&m_predBfromP, q * m_param->rc.pbFactor, (double)m_currentSatd);<br>
> + double space;<br>
> + if (bbits > m_bufferRate)<br>
> + nb = 0;<br>
> + double pbbits = nb * bbits;<br>
> +<br>
> + space = m_bufferFill + (1 + nb) * m_bufferRate - m_bufferSize;<br>
> + if (pbbits < space)<br>
> {<br>
> - q /= 1.01;<br>
> - terminate |= 2;<br>
> - continue;<br>
> + q *= X265_MAX(pbbits / space, bits / (0.5 * m_bufferSize));<br>
> }<br>
> - break;<br>
> + q = X265_MAX(q0 / 2, q);<br>
> + }<br>
> + if (!m_isCbr)<br>
> + q = X265_MAX(q0, q);<br>
> +<br>
> + if (m_rateFactorMaxIncrement)<br>
> + {<br>
> + double qpNoVbv = x265_qScale2qp(q0);<br>
> + double qmax = X265_MIN(MAX_MAX_QPSCALE,x265_qp2qScale(qpNoVbv + m_rateFactorMaxIncrement));<br>
> + return Clip3(MIN_QPSCALE, qmax, q);<br>
> }<br>
> }<br>
> - else<br>
> + if (m_2pass)<br>
> {<br>
> - /* Fallback to old purely-reactive algorithm: no lookahead. */<br>
> - if ((m_sliceType == P_SLICE ||<br>
> - (m_sliceType == I_SLICE && m_lastNonBPictType == I_SLICE)) &&<br>
> - m_bufferFill / m_bufferSize < 0.5)<br>
> - {<br>
> - q /= Clip3(0.5, 1.0, 2.0 * m_bufferFill / m_bufferSize);<br>
> - }<br>
> -<br>
> - // Now a hard threshold to make sure the frame fits in VBV.<br>
> - // This one is mostly for I-frames.<br>
> - double bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> -<br>
> - // For small VBVs, allow the frame to use up the entire VBV.<br>
> - double maxFillFactor;<br>
> - maxFillFactor = m_bufferSize >= 5 * m_bufferRate ? 2 : 1;<br>
> - // For single-frame VBVs, request that the frame use up the entire VBV.<br>
> - double minFillFactor = m_singleFrameVbv ? 1 : 2;<br>
> -<br>
> - for (int iterations = 0; iterations < 10; iterations++)<br>
> - {<br>
> - double qf = 1.0;<br>
> - if (bits > m_bufferFill / maxFillFactor)<br>
> - qf = Clip3(0.2, 1.0, m_bufferFill / (maxFillFactor * bits));<br>
> - q /= qf;<br>
> - bits *= qf;<br>
> - if (bits < m_bufferRate / minFillFactor)<br>
> - q *= bits * minFillFactor / m_bufferRate;<br>
> - bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> - }<br>
> -<br>
> - q = X265_MAX(q0, q);<br>
> + double min = log(MIN_QPSCALE);<br>
> + double max = log(MAX_MAX_QPSCALE);<br>
> + q = (log(q) - min) / (max - min) - 0.5;<br>
> + q = 1.0 / (1.0 + exp(-4 * q));<br>
> + q = q*(max - min) + min;<br>
> + return exp(q);<br>
> }<br>
> -<br>
> - // Check B-frame complexity, and use up any bits that would<br>
> - // overflow before the next P-frame.<br>
> - if (m_sliceType == P_SLICE && !m_singleFrameVbv)<br>
> - {<br>
> - int nb = m_bframes;<br>
> - double bits = predictSize(&m_pred[m_sliceType], q, (double)m_currentSatd);<br>
> - double bbits = predictSize(&m_predBfromP, q * m_param->rc.pbFactor, (double)m_currentSatd);<br>
> - double space;<br>
> - if (bbits > m_bufferRate)<br>
> - nb = 0;<br>
> - double pbbits = nb * bbits;<br>
> -<br>
> - space = m_bufferFill + (1 + nb) * m_bufferRate - m_bufferSize;<br>
> - if (pbbits < space)<br>
> - {<br>
> - q *= X265_MAX(pbbits / space, bits / (0.5 * m_bufferSize));<br>
> - }<br>
> - q = X265_MAX(q0 / 2, q);<br>
> - }<br>
> - if (!m_isCbr)<br>
> - q = X265_MAX(q0, q);<br>
> -<br>
> - if (m_rateFactorMaxIncrement)<br>
> - {<br>
> - double qpNoVbv = x265_qScale2qp(q0);<br>
> - double qmax = X265_MIN(MAX_MAX_QPSCALE,x265_qp2qScale(qpNoVbv + m_rateFactorMaxIncrement));<br>
> - return Clip3(MIN_QPSCALE, qmax, q);<br>
> - }<br>
> -<br>
> return Clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);<br>
> }<br>
><br>
> @@ -1180,8 +1761,14 @@<br>
> else<br>
> q = pow(rce->blurredComplexity, 1 - m_param->rc.qCompress);<br>
><br>
> - m_lastRceq = q;<br>
> - q /= rateFactor;<br>
> + // avoid NaN's in the Rceq<br>
> + if (rce->coeffBits + rce->mvBits == 0)<br>
> + q = m_lastQScaleFor[rce->sliceType];<br>
> + else<br>
> + {<br>
> + m_lastRceq = q;<br>
> + q /= rateFactor;<br>
> + }<br>
><br>
> return q;<br>
> }<br>
> @@ -1281,16 +1868,16 @@<br>
> : rce->sliceType == P_SLICE ? (pic->getSlice()->isReferenced()? 'P' : 'p')<br>
> : pic->getSlice()->isReferenced()? 'B' : 'b';<br>
> if (fprintf(m_statFileOut,<br>
> - "in:%d out:%d type:%c dur:%.3f q:%.2f q-aq:%.2f tex:%d mv:%d misc:%d imb:%.2f pmb:%.2f smb:%.2f ",<br>
> + "in:%d out:%d type:%c dur:%.3f q:%.2f q-aq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f ",<br>
> rce->poc, rce->encodeOrder,<br>
> cType, m_frameDuration,<br>
> pic->m_avgQpRc, pic->m_avgQpAq,<br>
> stats->coeffBits,<br>
> stats->mvBits,<br>
> stats->miscBits,<br>
> - stats->cuCount_i,<br>
> - stats->cuCount_p,<br>
> - stats->cuCount_skip) < 0)<br>
> + stats->cuCount_i * m_ncu,<br>
> + stats->cuCount_p * m_ncu,<br>
> + stats->cuCount_skip * m_ncu) < 0)<br>
> goto writeFailure;<br>
> if (fprintf(m_statFileOut, ";\n") < 0)<br>
> goto writeFailure;<br>
> @@ -1308,20 +1895,23 @@<br>
> }<br>
> /* amortize part of each I slice over the next several frames, up to<br>
> * keyint-max, to avoid over-compensating for the large I slice cost */<br>
> - if (rce->sliceType == I_SLICE)<br>
> + if (!m_param->rc.bStatWrite && !m_param->rc.bStatRead)<br>
> {<br>
> - /* previous I still had a residual; roll it into the new loan */<br>
> - if (m_residualFrames)<br>
> - bits += m_residualCost * m_residualFrames;<br>
> + if (rce->sliceType == I_SLICE)<br>
> + {<br>
> + /* previous I still had a residual; roll it into the new loan */<br>
> + if (m_residualFrames)<br>
> + bits += m_residualCost * m_residualFrames;<br>
><br>
> - m_residualFrames = X265_MIN(s_amortizeFrames, m_param->keyframeMax);<br>
> - m_residualCost = (int)((bits * s_amortizeFraction) / m_residualFrames);<br>
> - bits -= m_residualCost * m_residualFrames;<br>
> - }<br>
> - else if (m_residualFrames)<br>
> - {<br>
> - bits += m_residualCost;<br>
> - m_residualFrames--;<br>
> + m_residualFrames = X265_MIN(s_amortizeFrames, m_param->keyframeMax);<br>
> + m_residualCost = (int)((bits * s_amortizeFraction) / m_residualFrames);<br>
> + bits -= m_residualCost * m_residualFrames;<br>
> + }<br>
> + else if (m_residualFrames)<br>
> + {<br>
> + bits += m_residualCost;<br>
> + m_residualFrames--;<br>
> + }<br>
> }<br>
><br>
> if (rce->sliceType != B_SLICE)<br>
> @@ -1431,10 +2021,10 @@<br>
> unlink(newFileName);<br>
> bError = rename(tmpFileName, newFileName);<br>
> }<br>
> - if (!bError)<br>
> + if (bError)<br>
> {<br>
> x265_log(m_param, X265_LOG_ERROR, "failed to rename cutree output stats file to \"%s\"\n",<br>
> - m_param->rc.statFileName);<br>
> + newFileName);<br>
> }<br>
> X265_FREE(tmpFileName);<br>
> X265_FREE(newFileName);<br>
> @@ -1446,3 +2036,4 @@<br>
> for (int i = 0; i < 2; i++)<br>
> X265_FREE(m_cuTreeStats.qpBuffer[i]);<br>
> }<br>
> +<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/encoder/ratecontrol.h<br>
> --- a/source/encoder/ratecontrol.h Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/encoder/ratecontrol.h Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -53,10 +53,8 @@<br>
><br>
> struct RateControlEntry<br>
> {<br>
> - int64_t coeffBits; /* Required in 2-pass rate control */<br>
> int64_t lastSatd; /* Contains the picture cost of the previous frame, required for resetAbr and VBV */<br>
> int sliceType;<br>
> - int mvBits;<br>
> int bframes;<br>
> int poc;<br>
> int encodeOrder;<br>
> @@ -64,19 +62,33 @@<br>
> bool bLastMiniGopBFrame;<br>
> double blurredComplexity;<br>
> double qpaRc;<br>
> + double qpAq;<br>
> double qRceq;<br>
> double frameSizePlanned; /* frame Size decided by RateCotrol before encoding the frame */<br>
> double bufferRate;<br>
> double movingAvgSum;<br>
> double qpNoVbv;<br>
> double bufferFill;<br>
> + double frameDuration;<br>
> Predictor rowPreds[3][2];<br>
> Predictor* rowPred[2];<br>
> double frameSizeEstimated; /* hold frameSize, updated from cu level vbv rc */<br>
> bool isActive;<br>
> -<br>
> SEIPictureTiming *picTimingSEI;<br>
> HRDTiming *hrdTiming;<br>
> + /* Required in 2-pass rate control */<br>
> + double iCuCount;<br>
> + double pCuCount;<br>
> + double skipCuCount;<br>
> + bool keptAsRef;<br>
> + double expectedVbv;<br>
> + double qScale;<br>
> + double newQScale;<br>
> + double newQp;<br>
> + int mvBits;<br>
> + int miscBits;<br>
> + int coeffBits;<br>
> + uint64_t expectedBits; /*total expected bits up to the current frame (current one excluded)*/<br>
> };<br>
><br>
> class RateControl<br>
> @@ -134,6 +146,7 @@<br>
><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>
> /* hrd stuff */<br>
> SEIBufferingPeriod m_bufPeriodSEI;<br>
> @@ -145,6 +158,9 @@<br>
> FILE* m_statFileOut;<br>
> FILE* m_cutreeStatFileOut;<br>
> FILE* m_cutreeStatFileIn;<br>
> + int m_numEntries;<br>
> + RateControlEntry *m_rce2Pass;<br>
> + double m_lastAccumPNorm;<br>
><br>
> struct<br>
> {<br>
> @@ -184,6 +200,12 @@<br>
> double predictSize(Predictor *p, double q, double var);<br>
> void checkAndResetABR(RateControlEntry* rce, bool isFrameDone);<br>
> double predictRowsSizeSum(Frame* pic, RateControlEntry* rce, double qpm, int32_t& encodedBits);<br>
> + bool initPass2();<br>
> + double getDiffLimitedQScale(RateControlEntry *rce, double q);<br>
> + double countExpectedBits();<br>
> + bool RateControl::vbv2Pass(uint64_t allAvailableBits);<br>
> + bool findUnderflow(double *fills, int *t0, int *t1, int over);<br>
> + bool fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax);<br>
> };<br>
> }<br>
> #endif // ifndef X265_RATECONTROL_H<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/x265.cpp<br>
> --- a/source/x265.cpp Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/x265.cpp Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -645,6 +645,8 @@<br>
><br>
> if (this->framesToBeEncoded == 0 && info.frameCount > (int)seek)<br>
> this->framesToBeEncoded = info.frameCount - seek;<br>
> + param->totalFrames = this->framesToBeEncoded;<br>
> +<br>
> if (param->logLevel >= X265_LOG_INFO)<br>
> {<br>
> char buf[128];<br>
> diff -r cbfe2ac89d41 -r 418b68734fd8 source/x265.h<br>
> --- a/source/x265.h Thu Jul 10 01:33:35 2014 -0500<br>
> +++ b/source/x265.h Thu Jul 10 00:50:17 2014 +0530<br>
> @@ -480,6 +480,11 @@<br>
> * maximum is 16 */<br>
> int bframes;<br>
><br>
> + /* Total Number of frames to be encoded, caclulated from the user input --frames and<br>
> + -- frames-skip. It is later used in RateControl, hence storing the value in param<br>
> + structure as well. */<br>
> + int totalFrames;<br>
<br>
</div></div>comment style here doesn't match the rest of the header, is it ok to<br>
leave this field as zero? Sometimes x265 is consuming video from a<br>
pipe and it does not know the frame count.<br></blockquote><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
its fine to leave it as 0 in those cases,it checks for greater than 0 before using it to throw error.<br>
param changes require bump in X265_BUILD<br></blockquote><div>ok </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class=""><br>
> +<br>
> /* When enabled, the encoder will use the B frame in the middle of each<br>
> * mini-GOP larger than 2 B frames as a motion reference for the surrounding<br>
> * B frames. This improves compression efficiency for a small performance<br>
<br>
</div>the rest looks ok<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></div>