[x265] [PATCH] Modify the crf 2 pass
Mahesh Pittala
mahesh at multicorewareinc.com
Mon Aug 9 04:37:24 UTC 2021
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.giladi at 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 <mahesh at multicorewareinc.com>
> wrote:
>
>> From 5065d31b4bfe36e05c94dd79db119cd1fd23aa23 Mon Sep 17 00:00:00 2001
>> From: lwWang <liwei at multicorewareinc.com>
>> Date: Fri, 25 Jun 2021 17:17:03 +0800
>> Subject: [PATCH] Modify the crf 2 pass
>>
>> Signed-off-by: lwWang <liwei at 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 at videolan.org
>> https://mailman.videolan.org/listinfo/x265-devel
>>
> _______________________________________________
> x265-devel mailing list
> x265-devel at videolan.org
> https://mailman.videolan.org/listinfo/x265-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20210809/069a4435/attachment-0001.html>
More information about the x265-devel
mailing list