Hi Alex, a. The software that uses the x265 library would trigger the re-encode b. For the CRF+VBV 2pass run, it will drop performance on the re-encoding. It will not have an impact on the others c. By default, it is not triggered. And we are not planning to add a command-line option as it just re-encodes some selected gops instead of all the frames. And it will work in a CRF or CRF+VBV mode. Without crf, it will not work
Thanks, Mahesh On Tue, Aug 10, 2021 at 1:55 AM Alex Giladi <alex.gil...@gmail.com> wrote: > Thank you, Mahesh! > Can you please explain (a) what triggers the re-encode, (b) what is > the impact on run time, (c) is it triggered by default or are there > plans to add a command-line option and, lastly, why doesn't it work in > a VBV or CRF+VBV mode? > Best, > Alex. > > On Sun, Aug 8, 2021 at 10:37 PM Mahesh Pittala > <mah...@multicorewareinc.com> wrote: > > > > Hi Alex, > > > > This patch is to re-encode some separated gops to improve the > compression efficiency. > > > > Thanks, > > Mahesh > > > > On Fri, Aug 6, 2021 at 6:30 AM Alex Giladi <alex.gil...@gmail.com> > wrote: > >> > >> Hi Mahesh, > >> What is the actual modification of crf in the patch? > >> Best, > >> Alex > >> > >> > >> On Thu, Aug 5, 2021, 2:15 AM Mahesh Pittala < > mah...@multicorewareinc.com> wrote: > >>> > >>> From 5065d31b4bfe36e05c94dd79db119cd1fd23aa23 Mon Sep 17 00:00:00 2001 > >>> From: lwWang <li...@multicorewareinc.com> > >>> Date: Fri, 25 Jun 2021 17:17:03 +0800 > >>> Subject: [PATCH] Modify the crf 2 pass > >>> > >>> Signed-off-by: lwWang <li...@multicorewareinc.com> > >>> --- > >>> source/common/frame.h | 1 + > >>> source/encoder/encoder.cpp | 1 + > >>> source/encoder/ratecontrol.cpp | 235 ++++++++++++++++----------------- > >>> source/encoder/ratecontrol.h | 3 + > >>> 4 files changed, 119 insertions(+), 121 deletions(-) > >>> > >>> diff --git a/source/common/frame.h b/source/common/frame.h > >>> index dc5bbacf7..ac1185e81 100644 > >>> --- a/source/common/frame.h > >>> +++ b/source/common/frame.h > >>> @@ -70,6 +70,7 @@ struct RcStats > >>> double count[4]; > >>> double offset[4]; > >>> double bufferFillFinal; > >>> + int64_t currentSatd; > >>> }; > >>> > >>> class Frame > >>> diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp > >>> index 003011554..227933e8a 100644 > >>> --- a/source/encoder/encoder.cpp > >>> +++ b/source/encoder/encoder.cpp > >>> @@ -2216,6 +2216,7 @@ int Encoder::encode(const x265_picture* pic_in, > x265_picture* pic_out) > >>> outFrame->m_rcData->iCuCount = > outFrame->m_encData->m_frameStats.percent8x8Intra * m_rateControl->m_ncu; > >>> outFrame->m_rcData->pCuCount = > outFrame->m_encData->m_frameStats.percent8x8Inter * m_rateControl->m_ncu; > >>> outFrame->m_rcData->skipCuCount = > outFrame->m_encData->m_frameStats.percent8x8Skip * m_rateControl->m_ncu; > >>> + outFrame->m_rcData->currentSatd = > curEncoder->m_rce.coeffBits; > >>> } > >>> > >>> /* Allow this frame to be recycled if no frame encoders > are using it for reference */ > >>> diff --git a/source/encoder/ratecontrol.cpp > b/source/encoder/ratecontrol.cpp > >>> index e9ceccc24..28345a1e9 100644 > >>> --- a/source/encoder/ratecontrol.cpp > >>> +++ b/source/encoder/ratecontrol.cpp > >>> @@ -1116,123 +1116,106 @@ bool RateControl::initPass2() > >>> uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. > * m_numEntries * m_frameDuration); > >>> int startIndex, framesCount, endIndex; > >>> int fps = X265_MIN(m_param->keyframeMax, (int)(m_fps + 0.5)); > >>> + int distance = fps << 1; > >>> + distance = distance > m_param->keyframeMax ? > (m_param->keyframeMax << 1) : m_param->keyframeMax; > >>> startIndex = endIndex = framesCount = 0; > >>> - int diffQp = 0; > >>> double targetBits = 0; > >>> double expectedBits = 0; > >>> - for (startIndex = m_start, endIndex = m_start; endIndex < > m_numEntries; endIndex++) > >>> + double targetBits2 = 0; > >>> + double expectedBits2 = 0; > >>> + double cpxSum = 0; > >>> + double cpxSum2 = 0; > >>> + > >>> + if (m_param->rc.rateControlMode == X265_RC_ABR) > >>> { > >>> - allConstBits += m_rce2Pass[endIndex].miscBits; > >>> - allCodedBits += m_rce2Pass[endIndex].coeffBits + > m_rce2Pass[endIndex].mvBits; > >>> - if (m_param->rc.rateControlMode == X265_RC_CRF) > >>> + for (startIndex = m_start, endIndex = m_start; endIndex < > m_numEntries; endIndex++) > >>> { > >>> - framesCount = endIndex - startIndex + 1; > >>> - diffQp += int (m_rce2Pass[endIndex].qpaRc - > m_rce2Pass[endIndex].qpNoVbv); > >>> - if (framesCount > fps) > >>> - diffQp -= int (m_rce2Pass[endIndex - fps].qpaRc - > m_rce2Pass[endIndex - fps].qpNoVbv); > >>> - if (framesCount >= fps) > >>> - { > >>> - if (diffQp >= 1) > >>> - { > >>> - if (!m_isQpModified && endIndex > fps) > >>> - { > >>> - double factor = 2; > >>> - double step = 0; > >>> - if (endIndex + fps >= m_numEntries) > >>> - { > >>> - m_start = endIndex - (endIndex % fps); > >>> - return true; > >>> - } > >>> - for (int start = endIndex + 1; start <= > endIndex + fps && start < m_numEntries; start++) > >>> - { > >>> - RateControlEntry *rce = > &m_rce2Pass[start]; > >>> - targetBits += qScale2bits(rce, > x265_qp2qScale(rce->qpNoVbv)); > >>> - expectedBits += qScale2bits(rce, > rce->qScale); > >>> - } > >>> - if (expectedBits < 0.95 * targetBits) > >>> - { > >>> - m_isQpModified = true; > >>> - m_isGopReEncoded = true; > >>> - while (endIndex + fps < m_numEntries) > >>> - { > >>> - step = pow(2, factor / 6.0); > >>> - expectedBits = 0; > >>> - for (int start = endIndex + 1; start > <= endIndex + fps; start++) > >>> - { > >>> - RateControlEntry *rce = > &m_rce2Pass[start]; > >>> - rce->newQScale = rce->qScale / > step; > >>> - X265_CHECK(rce->newQScale >= 0, > "new Qscale is negative\n"); > >>> - expectedBits += qScale2bits(rce, > rce->newQScale); > >>> - rce->newQp = > x265_qScale2qp(rce->newQScale); > >>> - } > >>> - if (expectedBits >= targetBits && > step > 1) > >>> - factor *= 0.90; > >>> - else > >>> - break; > >>> - } > >>> - > >>> - if (m_isVbv && endIndex + fps < > m_numEntries) > >>> - if (!vbv2Pass((uint64_t)targetBits, > endIndex + fps, endIndex + 1)) > >>> - return false; > >>> - > >>> - targetBits = 0; > >>> - expectedBits = 0; > >>> - > >>> - for (int start = endIndex - fps + 1; > start <= endIndex; start++) > >>> - { > >>> - RateControlEntry *rce = > &m_rce2Pass[start]; > >>> - targetBits += qScale2bits(rce, > x265_qp2qScale(rce->qpNoVbv)); > >>> - } > >>> - while (1) > >>> - { > >>> - step = pow(2, factor / 6.0); > >>> - expectedBits = 0; > >>> - for (int start = endIndex - fps + 1; > start <= endIndex; start++) > >>> - { > >>> - RateControlEntry *rce = > &m_rce2Pass[start]; > >>> - rce->newQScale = rce->qScale * > step; > >>> - X265_CHECK(rce->newQScale >= 0, > "new Qscale is negative\n"); > >>> - expectedBits += qScale2bits(rce, > rce->newQScale); > >>> - rce->newQp = > x265_qScale2qp(rce->newQScale); > >>> - } > >>> - if (expectedBits > targetBits && step > > 1) > >>> - factor *= 1.1; > >>> - else > >>> - break; > >>> - } > >>> - if (m_isVbv) > >>> - if (!vbv2Pass((uint64_t)targetBits, > endIndex, endIndex - fps + 1)) > >>> - return false; > >>> - diffQp = 0; > >>> - m_reencode = endIndex - fps + 1; > >>> - endIndex = endIndex + fps; > >>> - startIndex = endIndex + 1; > >>> - m_start = startIndex; > >>> - targetBits = expectedBits = 0; > >>> - } > >>> - else > >>> - targetBits = expectedBits = 0; > >>> - } > >>> - } > >>> - else > >>> - m_isQpModified = false; > >>> - } > >>> + allConstBits += m_rce2Pass[endIndex].miscBits; > >>> + allCodedBits += m_rce2Pass[endIndex].coeffBits + > m_rce2Pass[endIndex].mvBits; > >>> } > >>> - } > >>> > >>> - if (m_param->rc.rateControlMode == X265_RC_ABR) > >>> - { > >>> if (allAvailableBits < allConstBits) > >>> { > >>> x265_log(m_param, X265_LOG_ERROR, "requested bitrate is > too low. estimated minimum is %d kbps\n", > >>> - (int)(allConstBits * m_fps / framesCount * > 1000.)); > >>> + (int)(allConstBits * m_fps / framesCount * 1000.)); > >>> return false; > >>> } > >>> if (!analyseABR2Pass(allAvailableBits)) > >>> return false; > >>> + > >>> + return true; > >>> } > >>> > >>> - m_start = X265_MAX(m_start, endIndex - fps); > >>> + if (m_param->rc.rateControlMode != X265_RC_CRF) > >>> + { > >>> + return true; > >>> + } > >>> + > >>> + if (m_isQpModified) > >>> + { > >>> + return true; > >>> + } > >>> + > >>> + if (m_start + (fps << 1) > m_numEntries) > >>> + { > >>> + return true; > >>> + } > >>> + > >>> + for (startIndex = m_start, endIndex = m_numEntries - 1; > startIndex < endIndex; startIndex++, endIndex--) > >>> + { > >>> + cpxSum += m_rce2Pass[startIndex].qScale / > m_rce2Pass[startIndex].coeffBits; > >>> + cpxSum2 += m_rce2Pass[endIndex].qScale / > m_rce2Pass[endIndex].coeffBits; > >>> + > >>> + RateControlEntry *rce = &m_rce2Pass[startIndex]; > >>> + targetBits += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv)); > >>> + expectedBits += qScale2bits(rce, rce->qScale); > >>> + > >>> + rce = &m_rce2Pass[endIndex]; > >>> + targetBits2 += qScale2bits(rce, x265_qp2qScale(rce->qpNoVbv)); > >>> + expectedBits2 += qScale2bits(rce, rce->qScale); > >>> + } > >>> + > >>> + if (expectedBits < 0.95 * targetBits || expectedBits2 < 0.95 * > targetBits2) > >>> + { > >>> + if (cpxSum/cpxSum2 < 0.95 || cpxSum2 / cpxSum < 0.95) > >>> + { > >>> + m_isQpModified = true; > >>> + m_isGopReEncoded = true; > >>> + > >>> + m_shortTermCplxSum = 0; > >>> + m_shortTermCplxCount = 0; > >>> + m_framesDone = m_start; > >>> + > >>> + for (startIndex = m_start; startIndex < m_numEntries; > startIndex++) > >>> + { > >>> + m_shortTermCplxSum *= 0.5; > >>> + m_shortTermCplxCount *= 0.5; > >>> + m_shortTermCplxSum += > m_rce2Pass[startIndex].currentSatd / (CLIP_DURATION(m_frameDuration) / > BASE_FRAME_DURATION); > >>> + m_shortTermCplxCount++; > >>> + } > >>> + > >>> + m_bufferFill = m_rce2Pass[m_start - 1].bufferFill; > >>> + m_bufferFillFinal = m_rce2Pass[m_start - > 1].bufferFillFinal; > >>> + m_bufferFillActual = m_rce2Pass[m_start - > 1].bufferFillActual; > >>> + > >>> + m_reencode = m_start; > >>> + m_start = m_numEntries; > >>> + } > >>> + else > >>> + { > >>> + > >>> + m_isQpModified = false; > >>> + m_isGopReEncoded = false; > >>> + } > >>> + } > >>> + else > >>> + { > >>> + > >>> + m_isQpModified = false; > >>> + m_isGopReEncoded = false; > >>> + } > >>> + > >>> + m_start = X265_MAX(m_start, m_numEntries - distance + > m_param->keyframeMax); > >>> > >>> return true; > >>> } > >>> @@ -1505,15 +1488,34 @@ int RateControl::rateControlStart(Frame* > curFrame, RateControlEntry* rce, Encode > >>> rce->frameSizeMaximum *= m_param->maxAUSizeFactor; > >>> } > >>> } > >>> + > >>> + ///< regenerate the qp > >>> if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == > X265_RC_CRF) > >>> { > >>> - rce->qpPrev = x265_qScale2qp(rce->qScale); > >>> - rce->qScale = rce->newQScale; > >>> - rce->qpaRc = curEncData.m_avgQpRc = curEncData.m_avgQpAq = > x265_qScale2qp(rce->newQScale); > >>> - m_qp = int(rce->qpaRc + 0.5); > >>> - rce->frameSizePlanned = qScale2bits(rce, rce->qScale); > >>> - m_framesDone++; > >>> - return m_qp; > >>> + int index = m_encOrder[rce->poc]; > >>> + index++; > >>> + double totalDuration = m_frameDuration; > >>> + for (int j = 0; totalDuration < 1.0; j++) > >>> + { > >>> + switch (m_rce2Pass[index].sliceType) > >>> + { > >>> + case B_SLICE: > >>> + curFrame->m_lowres.plannedType[j] = > m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B; > >>> + break; > >>> + case P_SLICE: > >>> + curFrame->m_lowres.plannedType[j] = X265_TYPE_P; > >>> + break; > >>> + case I_SLICE: > >>> + curFrame->m_lowres.plannedType[j] = m_param->bOpenGOP > ? X265_TYPE_I : X265_TYPE_IDR; > >>> + break; > >>> + default: > >>> + break; > >>> + } > >>> + > >>> + curFrame->m_lowres.plannedSatd[j] = > m_rce2Pass[index].currentSatd; > >>> + totalDuration += m_frameDuration; > >>> + index++; > >>> + } > >>> } > >>> > >>> if (m_isAbr || m_2pass) // ABR,CRF > >>> @@ -2019,7 +2021,7 @@ double RateControl::rateEstimateQscale(Frame* > curFrame, RateControlEntry *rce) > >>> qScale = x265_clip3(lqmin, lqmax, qScale); > >>> } > >>> > >>> - if (!m_2pass || m_param->bliveVBV2pass) > >>> + if (!m_2pass || m_param->bliveVBV2pass || (m_2pass && > m_param->rc.rateControlMode == X265_RC_CRF)) > >>> { > >>> /* clip qp to permissible range after vbv-lookahead > estimation to avoid possible > >>> * mispredictions by initial frame size predictors */ > >>> @@ -2056,7 +2058,7 @@ double RateControl::rateEstimateQscale(Frame* > curFrame, RateControlEntry *rce) > >>> else > >>> { > >>> double abrBuffer = 2 * m_rateTolerance * m_bitrate; > >>> - if (m_2pass) > >>> + if (m_2pass && m_param->rc.rateControlMode != X265_RC_CRF) > >>> { > >>> double lmin = m_lmin[m_sliceType]; > >>> double lmax = m_lmax[m_sliceType]; > >>> @@ -2947,7 +2949,7 @@ int RateControl::rateControlEnd(Frame* curFrame, > int64_t bits, RateControlEntry* > >>> > >>> if (m_param->rc.aqMode || m_isVbv || m_param->bAQMotion || > bEnableDistOffset) > >>> { > >>> - if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode == > X265_RC_CRF)) > >>> + if (m_isVbv) > >>> { > >>> double avgQpRc = 0; > >>> /* determine avg QP decided by VBV rate control */ > >>> @@ -2981,16 +2983,7 @@ int RateControl::rateControlEnd(Frame* > curFrame, int64_t bits, RateControlEntry* > >>> if (m_param->rc.rateControlMode == X265_RC_CRF) > >>> { > >>> double crfVal, qpRef = curEncData.m_avgQpRc; > >>> - bool is2passCrfChange = false; > >>> - if (m_2pass) > >>> - { > >>> - if (fabs(curEncData.m_avgQpRc - rce->qpPrev) > 0.1) > >>> - { > >>> - qpRef = rce->qpPrev; > >>> - is2passCrfChange = true; > >>> - } > >>> - } > >>> - if (is2passCrfChange || fabs(qpRef - rce->qpNoVbv) > 0.5) > >>> + if (fabs(qpRef - rce->qpNoVbv) > 0.5) > >>> { > >>> double crfFactor = rce->qRceq /x265_qp2qScale(qpRef); > >>> double baseCplx = m_ncu * (m_param->bframes ? 120 : 80); > >>> diff --git a/source/encoder/ratecontrol.h > b/source/encoder/ratecontrol.h > >>> index a0b555f8a..666025823 100644 > >>> --- a/source/encoder/ratecontrol.h > >>> +++ b/source/encoder/ratecontrol.h > >>> @@ -74,6 +74,7 @@ struct RateControlEntry > >>> Predictor rowPreds[3][2]; > >>> Predictor* rowPred[2]; > >>> > >>> + int64_t currentSatd; > >>> int64_t lastSatd; /* Contains the picture cost of the > previous frame, required for resetAbr and VBV */ > >>> int64_t leadingNoBSatd; > >>> int64_t rowTotalBits; /* update cplxrsum and totalbits at the > end of 2 rows */ > >>> @@ -88,6 +89,8 @@ struct RateControlEntry > >>> double rowCplxrSum; > >>> double qpNoVbv; > >>> double bufferFill; > >>> + double bufferFillFinal; > >>> + double bufferFillActual; > >>> double targetFill; > >>> bool vbvEndAdj; > >>> double frameDuration; > >>> -- > >>> 2.22.0.windows.1 > >>> > >>> _______________________________________________ > >>> x265-devel mailing list > >>> x265-devel@videolan.org > >>> https://mailman.videolan.org/listinfo/x265-devel > >> > >> _______________________________________________ > >> x265-devel mailing list > >> x265-devel@videolan.org > >> https://mailman.videolan.org/listinfo/x265-devel > > > > _______________________________________________ > > x265-devel mailing list > > x265-devel@videolan.org > > https://mailman.videolan.org/listinfo/x265-devel > _______________________________________________ > x265-devel mailing list > x265-devel@videolan.org > https://mailman.videolan.org/listinfo/x265-devel >
_______________________________________________ x265-devel mailing list x265-devel@videolan.org https://mailman.videolan.org/listinfo/x265-devel