<div dir="ltr">Pushed to master.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Oct 6, 2021 at 11:22 AM Dakshinya T R S <<a href="mailto:dakshinya@multicorewareinc.com">dakshinya@multicorewareinc.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">From c2a289d66e51e47f3e0495ca13e9c8729685f280 Mon Sep 17 00:00:00 2001<br>From: lwWang <<a href="mailto:liwei@multicorewareinc.com" target="_blank">liwei@multicorewareinc.com</a>><br>Date: Mon, 27 Sep 2021 11:56:43 +0800<br>Subject: [PATCH] Support encoding only the focused frames in the crf 2pass<br><br>---<br> doc/reST/cli.rst | 8 ++<br> source/CMakeLists.txt | 2 +-<br> source/common/frame.h | 1 +<br> source/common/framedata.cpp | 2 +-<br> source/common/param.cpp | 1 +<br> source/encoder/encoder.cpp | 6 +<br> source/encoder/ratecontrol.cpp | 235 +++++++++++++++++----------------<br> source/encoder/ratecontrol.h | 3 +<br> source/x265.h | 3 +<br> 9 files changed, 147 insertions(+), 114 deletions(-)<br><br>diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst<br>index b24fa72a9..e19774c68 100755<br>--- a/doc/reST/cli.rst<br>+++ b/doc/reST/cli.rst<br>@@ -2059,6 +2059,14 @@ Quality, rate control and rate distortion options<br> rate control mode.<br> <br> Default disabled. **Experimental feature**<br>+ <br>+<br>+.. option:: bEncFocusedFramesOnly<br>+<br>+ Used to trigger encoding of selective GOPs; Disabled by default.<br>+ <br>+ **API ONLY**<br>+ <br> <br> Quantization Options<br> ====================<br>diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt<br>index 23af32111..62afd3610 100755<br>--- a/source/CMakeLists.txt<br>+++ b/source/CMakeLists.txt<br>@@ -29,7 +29,7 @@ option(NATIVE_BUILD "Target the build CPU" OFF)<br> option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF)<br> mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD)<br> # X265_BUILD must be incremented each time the public API is changed<br>-set(X265_BUILD 201)<br>+set(X265_BUILD 202)<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265.def.in" target="_blank">x265.def.in</a>"<br> "${PROJECT_BINARY_DIR}/x265.def")<br> configure_file("${PROJECT_SOURCE_DIR}/<a href="http://x265_config.h.in" target="_blank">x265_config.h.in</a>"<br>diff --git a/source/common/frame.h b/source/common/frame.h<br>index dc5bbacf7..ac1185e81 100644<br>--- a/source/common/frame.h<br>+++ b/source/common/frame.h<br>@@ -70,6 +70,7 @@ struct RcStats<br> double count[4];<br> double offset[4];<br> double bufferFillFinal;<br>+ int64_t currentSatd;<br> };<br> <br> class Frame<br>diff --git a/source/common/framedata.cpp b/source/common/framedata.cpp<br>index c77b017a8..70af8a248 100644<br>--- a/source/common/framedata.cpp<br>+++ b/source/common/framedata.cpp<br>@@ -62,7 +62,7 @@ bool FrameData::create(const x265_param& param, const SPS& sps, int csp)<br> }<br> else<br> return false;<br>- CHECKED_MALLOC_ZERO(m_cuStat, RCStatCU, sps.numCUsInFrame);<br>+ CHECKED_MALLOC_ZERO(m_cuStat, RCStatCU, sps.numCUsInFrame + 1);<br> CHECKED_MALLOC(m_rowStat, RCStatRow, sps.numCuInHeight);<br> reinit(sps);<br> <br>diff --git a/source/common/param.cpp b/source/common/param.cpp<br>index 6751e0aa7..2c1583d93 100755<br>--- a/source/common/param.cpp<br>+++ b/source/common/param.cpp<br>@@ -282,6 +282,7 @@ void x265_param_default(x265_param* param)<br> param->rc.bStatRead = 0;<br> param->rc.bStatWrite = 0;<br> param->rc.statFileName = NULL;<br>+ param->rc.bEncFocusedFramesOnly = 0;<br> param->rc.complexityBlur = 20;<br> param->rc.qblur = 0.5;<br> param->rc.zoneCount = 0;<br>diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp<br>index dee8fd85d..56f0e5433 100644<br>--- a/source/encoder/encoder.cpp<br>+++ b/source/encoder/encoder.cpp<br>@@ -2249,6 +2249,7 @@ int Encoder::encode(const x265_picture* pic_in, x265_picture* pic_out)<br> outFrame->m_rcData->iCuCount = outFrame->m_encData->m_frameStats.percent8x8Intra * m_rateControl->m_ncu;<br> outFrame->m_rcData->pCuCount = outFrame->m_encData->m_frameStats.percent8x8Inter * m_rateControl->m_ncu;<br> outFrame->m_rcData->skipCuCount = outFrame->m_encData->m_frameStats.percent8x8Skip * m_rateControl->m_ncu;<br>+ outFrame->m_rcData->currentSatd = curEncoder->m_rce.coeffBits;<br> }<br> <br> /* Allow this frame to be recycled if no frame encoders are using it for reference */<br>@@ -4018,6 +4019,11 @@ void Encoder::configure(x265_param *p)<br> p->rc.bStatRead = 0;<br> }<br> <br>+ if (!p->rc.bStatRead || p->rc.rateControlMode != X265_RC_CRF)<br>+ {<br>+ p->rc.bEncFocusedFramesOnly = 0;<br>+ }<br>+<br> /* some options make no sense if others are disabled */<br> p->bSaoNonDeblocked &= p->bEnableSAO;<br> p->bEnableTSkipFast &= p->bEnableTransformSkip;<br>diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp<br>index a4756de39..6c59d0c64 100644<br>--- a/source/encoder/ratecontrol.cpp<br>+++ b/source/encoder/ratecontrol.cpp<br>@@ -1002,123 +1002,101 @@ bool RateControl::initPass2()<br> uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * m_numEntries * m_frameDuration);<br> int startIndex, framesCount, endIndex;<br> int fps = X265_MIN(m_param->keyframeMax, (int)(m_fps + 0.5));<br>+ int distance = fps << 1;<br>+ distance = distance > m_param->keyframeMax ? (m_param->keyframeMax << 1) : m_param->keyframeMax;<br> startIndex = endIndex = framesCount = 0;<br>- int diffQp = 0;<br> double targetBits = 0;<br> double expectedBits = 0;<br>- for (startIndex = m_start, endIndex = m_start; endIndex < m_numEntries; endIndex++)<br>+ double targetBits2 = 0;<br>+ double expectedBits2 = 0;<br>+ double cpxSum = 0;<br>+ double cpxSum2 = 0;<br>+<br>+ if (m_param->rc.rateControlMode == X265_RC_ABR)<br> {<br>- allConstBits += m_rce2Pass[endIndex].miscBits;<br>- allCodedBits += m_rce2Pass[endIndex].coeffBits + m_rce2Pass[endIndex].mvBits;<br>- if (m_param->rc.rateControlMode == X265_RC_CRF)<br>+ for (startIndex = m_start, endIndex = m_start; endIndex < m_numEntries; endIndex++)<br> {<br>- framesCount = endIndex - startIndex + 1;<br>- diffQp += int (m_rce2Pass[endIndex].qpaRc - m_rce2Pass[endIndex].qpNoVbv);<br>- if (framesCount > fps)<br>- diffQp -= int (m_rce2Pass[endIndex - fps].qpaRc - m_rce2Pass[endIndex - fps].qpNoVbv);<br>- if (framesCount >= fps)<br>- {<br>- if (diffQp >= 1)<br>- {<br>- if (!m_isQpModified && endIndex > fps)<br>- {<br>- double factor = 2;<br>- double step = 0;<br>- if (endIndex + fps >= m_numEntries)<br>- {<br>- m_start = endIndex - (endIndex % fps);<br>- return true;<br>- }<br>- for (int start = endIndex + 1; start <= endIndex + fps && start < m_numEntries; start++)<br>- {<br>- RateControlEntry *rce = &m_rce2Pass[start];<br>- targetBits += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv));<br>- expectedBits += qScale2bits(rce, rce->qScale);<br>- }<br>- if (expectedBits < 0.95 * targetBits)<br>- {<br>- m_isQpModified = true;<br>- m_isGopReEncoded = true;<br>- while (endIndex + fps < m_numEntries)<br>- {<br>- step = pow(2, factor / 6.0);<br>- expectedBits = 0;<br>- for (int start = endIndex + 1; start <= endIndex + fps; start++)<br>- {<br>- RateControlEntry *rce = &m_rce2Pass[start];<br>- rce->newQScale = rce->qScale / step;<br>- X265_CHECK(rce->newQScale >= 0, "new Qscale is negative\n");<br>- expectedBits += qScale2bits(rce, rce->newQScale);<br>- rce->newQp = x265_qScale2qp(rce->newQScale);<br>- }<br>- if (expectedBits >= targetBits && step > 1)<br>- factor *= 0.90;<br>- else<br>- break;<br>- }<br>-<br>- if (m_isVbv && endIndex + fps < m_numEntries)<br>- if (!vbv2Pass((uint64_t)targetBits, endIndex + fps, endIndex + 1))<br>- return false;<br>-<br>- targetBits = 0;<br>- expectedBits = 0;<br>-<br>- for (int start = endIndex - fps + 1; start <= endIndex; start++)<br>- {<br>- RateControlEntry *rce = &m_rce2Pass[start];<br>- targetBits += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv));<br>- }<br>- while (1)<br>- {<br>- step = pow(2, factor / 6.0);<br>- expectedBits = 0;<br>- for (int start = endIndex - fps + 1; start <= endIndex; start++)<br>- {<br>- RateControlEntry *rce = &m_rce2Pass[start];<br>- rce->newQScale = rce->qScale * step;<br>- X265_CHECK(rce->newQScale >= 0, "new Qscale is negative\n");<br>- expectedBits += qScale2bits(rce, rce->newQScale);<br>- rce->newQp = x265_qScale2qp(rce->newQScale);<br>- }<br>- if (expectedBits > targetBits && step > 1)<br>- factor *= 1.1;<br>- else<br>- break;<br>- }<br>- if (m_isVbv)<br>- if (!vbv2Pass((uint64_t)targetBits, endIndex, endIndex - fps + 1))<br>- return false;<br>- diffQp = 0;<br>- m_reencode = endIndex - fps + 1;<br>- endIndex = endIndex + fps;<br>- startIndex = endIndex + 1;<br>- m_start = startIndex;<br>- targetBits = expectedBits = 0;<br>- }<br>- else<br>- targetBits = expectedBits = 0;<br>- }<br>- }<br>- else<br>- m_isQpModified = false;<br>- }<br>+ allConstBits += m_rce2Pass[endIndex].miscBits;<br>+ allCodedBits += m_rce2Pass[endIndex].coeffBits + m_rce2Pass[endIndex].mvBits;<br> }<br>- }<br> <br>- if (m_param->rc.rateControlMode == X265_RC_ABR)<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 / framesCount * 1000.));<br>+ (int)(allConstBits * m_fps / framesCount * 1000.));<br> return false;<br> }<br> if (!analyseABR2Pass(allAvailableBits))<br> return false;<br>+<br>+ return true;<br>+ }<br>+<br>+ if (m_isQpModified)<br>+ {<br>+ return true;<br>+ }<br>+<br>+ if (m_start + (fps << 1) > m_numEntries)<br>+ {<br>+ return true;<br>+ }<br>+<br>+ for (startIndex = m_start, endIndex = m_numEntries - 1; startIndex < endIndex; startIndex++, endIndex--)<br>+ {<br>+ cpxSum += m_rce2Pass[startIndex].qScale / m_rce2Pass[startIndex].coeffBits;<br>+ cpxSum2 += m_rce2Pass[endIndex].qScale / m_rce2Pass[endIndex].coeffBits;<br>+<br>+ RateControlEntry *rce = &m_rce2Pass[startIndex];<br>+ targetBits += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv));<br>+ expectedBits += qScale2bits(rce, rce->qScale);<br>+<br>+ rce = &m_rce2Pass[endIndex];<br>+ targetBits2 += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv));<br>+ expectedBits2 += qScale2bits(rce, rce->qScale);<br>+ }<br>+<br>+ if (expectedBits < 0.95 * targetBits || expectedBits2 < 0.95 * targetBits2)<br>+ {<br>+ if (cpxSum / cpxSum2 < 0.95 || cpxSum2 / cpxSum < 0.95)<br>+ {<br>+ m_isQpModified = true;<br>+ m_isGopReEncoded = true;<br>+<br>+ m_shortTermCplxSum = 0;<br>+ m_shortTermCplxCount = 0;<br>+ m_framesDone = m_start;<br>+<br>+ for (startIndex = m_start; startIndex < m_numEntries; startIndex++)<br>+ {<br>+ m_shortTermCplxSum *= 0.5;<br>+ m_shortTermCplxCount *= 0.5;<br>+ m_shortTermCplxSum += m_rce2Pass[startIndex].currentSatd / (CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION);<br>+ m_shortTermCplxCount++;<br>+ }<br>+<br>+ m_bufferFill = m_rce2Pass[m_start - 1].bufferFill;<br>+ m_bufferFillFinal = m_rce2Pass[m_start - 1].bufferFillFinal;<br>+ m_bufferFillActual = m_rce2Pass[m_start - 1].bufferFillActual;<br>+<br>+ m_reencode = m_start;<br>+ m_start = m_numEntries;<br>+ }<br>+ else<br>+ {<br>+<br>+ m_isQpModified = false;<br>+ m_isGopReEncoded = false;<br>+ }<br> }<br>+ else<br>+ {<br> <br>- m_start = X265_MAX(m_start, endIndex - fps);<br>+ m_isQpModified = false;<br>+ m_isGopReEncoded = false;<br>+ }<br>+<br>+ m_start = X265_MAX(m_start, m_numEntries - distance + m_param->keyframeMax);<br> <br> return true;<br> }<br>@@ -1391,15 +1369,47 @@ int RateControl::rateControlStart(Frame* curFrame, RateControlEntry* rce, Encode<br> rce->frameSizeMaximum *= m_param->maxAUSizeFactor;<br> }<br> }<br>+<br>+ ///< regenerate the qp<br> if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == X265_RC_CRF)<br> {<br>- rce->qpPrev = x265_qScale2qp(rce->qScale);<br>- rce->qScale = rce->newQScale;<br>- rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = x265_qScale2qp(rce->newQScale);<br>- m_qp = int(rce->qpaRc + 0.5);<br>- rce->frameSizePlanned = qScale2bits(rce, rce->qScale);<br>- m_framesDone++;<br>- return m_qp;<br>+ if (!m_param->rc.bEncFocusedFramesOnly)<br>+ {<br>+ rce->qpPrev = x265_qScale2qp(rce->qScale);<br>+ rce->qScale = rce->newQScale;<br>+ rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = x265_qScale2qp(rce->newQScale);<br>+ m_qp = int(rce->qpaRc + 0.5);<br>+ rce->frameSizePlanned = qScale2bits(rce, rce->qScale);<br>+ m_framesDone++;<br>+ return m_qp;<br>+ }<br>+ else<br>+ { <br>+ int index = m_encOrder[rce->poc];<br>+ index++;<br>+ double totalDuration = m_frameDuration;<br>+ for (int j = 0; totalDuration < 1.0 && index < m_numEntries; j++)<br>+ {<br>+ switch (m_rce2Pass[index].sliceType)<br>+ {<br>+ case B_SLICE:<br>+ curFrame->m_lowres.plannedType[j] = m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B;<br>+ break;<br>+ case P_SLICE:<br>+ curFrame->m_lowres.plannedType[j] = X265_TYPE_P;<br>+ break;<br>+ case I_SLICE:<br>+ curFrame->m_lowres.plannedType[j] = m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR;<br>+ break;<br>+ default:<br>+ break;<br>+ }<br>+<br>+ curFrame->m_lowres.plannedSatd[j] = m_rce2Pass[index].currentSatd;<br>+ totalDuration += m_frameDuration;<br>+ index++;<br>+ }<br>+ }<br> }<br> <br> if (m_isAbr || m_2pass) // ABR,CRF<br>@@ -1890,7 +1900,7 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br> qScale = x265_clip3(lqmin, lqmax, qScale);<br> }<br> <br>- if (!m_2pass || m_param->bliveVBV2pass)<br>+ if (!m_2pass || m_param->bliveVBV2pass || (m_2pass && m_param->rc.rateControlMode == X265_RC_CRF && m_param->rc.bEncFocusedFramesOnly))<br> {<br> /* clip qp to permissible range after vbv-lookahead estimation to avoid possible <br> * mispredictions by initial frame size predictors */<br>@@ -1927,7 +1937,7 @@ double RateControl::rateEstimateQscale(Frame* curFrame, RateControlEntry *rce)<br> else<br> {<br> double abrBuffer = 2 * m_rateTolerance * m_bitrate;<br>- if (m_2pass)<br>+ if (m_2pass && (m_param->rc.rateControlMode != X265_RC_CRF || !m_param->rc.bEncFocusedFramesOnly))<br> {<br> double lmin = m_lmin[m_sliceType];<br> double lmax = m_lmax[m_sliceType];<br>@@ -2828,7 +2838,7 @@ int RateControl::rateControlEnd(Frame* curFrame, int64_t bits, RateControlEntry*<br> <br> if (m_param->rc.aqMode || m_isVbv || m_param->bAQMotion || bEnableDistOffset)<br> {<br>- if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode == X265_RC_CRF))<br>+ if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode == X265_RC_CRF && !m_param->rc.bEncFocusedFramesOnly))<br> {<br> double avgQpRc = 0;<br> /* determine avg QP decided by VBV rate control */<br>@@ -2862,8 +2872,9 @@ int RateControl::rateControlEnd(Frame* curFrame, int64_t bits, RateControlEntry*<br> if (m_param->rc.rateControlMode == X265_RC_CRF)<br> {<br> double crfVal, qpRef = curEncData.m_avgQpRc;<br>+<br> bool is2passCrfChange = false;<br>- if (m_2pass)<br>+ if (m_2pass && !m_param->rc.bEncFocusedFramesOnly)<br> {<br> if (fabs(curEncData.m_avgQpRc - rce->qpPrev) > 0.1)<br> {<br>diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h<br>index 996465eeb..204bd71e1 100644<br>--- a/source/encoder/ratecontrol.h<br>+++ b/source/encoder/ratecontrol.h<br>@@ -73,6 +73,7 @@ struct RateControlEntry<br> Predictor rowPreds[3][2];<br> Predictor* rowPred[2];<br> <br>+ int64_t currentSatd;<br> int64_t lastSatd; /* Contains the picture cost of the previous frame, required for resetAbr and VBV */<br> int64_t leadingNoBSatd;<br> int64_t rowTotalBits; /* update cplxrsum and totalbits at the end of 2 rows */<br>@@ -87,6 +88,8 @@ struct RateControlEntry<br> double rowCplxrSum;<br> double qpNoVbv;<br> double bufferFill;<br>+ double bufferFillFinal;<br>+ double bufferFillActual;<br> double targetFill;<br> bool vbvEndAdj;<br> double frameDuration;<br>diff --git a/source/x265.h b/source/x265.h<br>index 3f3133536..6bb893c98 100644<br>--- a/source/x265.h<br>+++ b/source/x265.h<br>@@ -1443,6 +1443,9 @@ typedef struct x265_param<br> * encoder will default to using x265_2pass.log */<br> const char* statFileName;<br> <br>+ /* if only the focused frames would be re-encode or not */<br>+ int bEncFocusedFramesOnly;<br>+<br> /* temporally blur quants */<br> double qblur;<br> <br>-- <br>2.23.0.windows.1<br><br><div><br></div></div>
_______________________________________________<br>
x265-devel mailing list<br>
<a href="mailto:x265-devel@videolan.org" target="_blank">x265-devel@videolan.org</a><br>
<a href="https://mailman.videolan.org/listinfo/x265-devel" rel="noreferrer" target="_blank">https://mailman.videolan.org/listinfo/x265-devel</a><br>
</blockquote></div><br clear="all"><div><br></div>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><div><div dir="ltr"><font face="georgia, serif">Regards,</font><div><b><font face="georgia, serif">Aruna Matheswaran,</font></b></div><div><font face="georgia, serif">Video Codec Engineer,</font></div><div><font face="georgia, serif">Media & AI analytics BU,</font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" width="96" height="36" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><span><span style="font-size:11pt;font-family:Arial;color:rgb(0,0,0);background-color:transparent;vertical-align:baseline;white-space:pre-wrap"><span style="border:none;display:inline-block;overflow:hidden;width:153px;height:58px"><img src="https://lh5.googleusercontent.com/gjX5cPNIZgwUrhfqkTwQUZWztIKmmo0qs3kbwvkS5H-bDVE2ftte9pMTVnFLSjOcjYWLtfc6_OGpxW4vraLg2r5QAIf1Q3MpldFDgWtzK_gXi8ptw5B3joIbsGL6mxj-JRdjHzT5" style="margin-left: 0px; margin-top: 0px;"></span></span></span><font face="georgia, serif"><br></font></div><div><font face="georgia, serif"><br></font></div></div></div></div></div></div></div></div></div>