[x265] [PATCH] Modify the crf 2 pass
Mahesh Pittala
mahesh at multicorewareinc.com
Thu Aug 5 08:15:40 UTC 2021
>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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20210805/2a317abe/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-x265-Modify-the-crf-2-pass.patch
Type: application/octet-stream
Size: 15193 bytes
Desc: not available
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20210805/2a317abe/attachment-0001.obj>
More information about the x265-devel
mailing list