[x265] [PATCH 2 of 2] rc: implement 2 pass CRF, when vbv is enabled
aarthi at multicorewareinc.com
aarthi at multicorewareinc.com
Mon Nov 23 09:46:22 CET 2015
# HG changeset patch
# User Divya Manivannan <divya at multicorewareinc.com>
# Date 1448267770 -19800
# Mon Nov 23 14:06:10 2015 +0530
# Branch stable
# Node ID ffb0111298cdfcf6fe77d143089144c23b644b2d
# Parent 6b308775b6f065ea5002a76a40aa6f5d81e8ee50
rc: implement 2 pass CRF, when vbv is enabled.
Allow CRF with VBV in 2nd pass to increase the quality of capped CRF in the first pass.
diff -r 6b308775b6f0 -r ffb0111298cd source/common/param.cpp
--- a/source/common/param.cpp Mon Nov 23 12:26:45 2015 +0530
+++ b/source/common/param.cpp Mon Nov 23 14:06:10 2015 +0530
@@ -1170,7 +1170,7 @@
CHECK(0 > param->noiseReductionIntra || param->noiseReductionIntra > 2000, "Valid noise reduction range 0 - 2000");
if (param->noiseReductionInter)
CHECK(0 > param->noiseReductionInter || param->noiseReductionInter > 2000, "Valid noise reduction range 0 - 2000");
- CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead,
+ CHECK(param->rc.rateControlMode == X265_RC_CRF && param->rc.bStatRead && param->rc.vbvMaxBitrate == 0,
"Constant rate-factor is incompatible with 2pass");
CHECK(param->rc.rateControlMode == X265_RC_CQP && param->rc.bStatRead,
"Constant QP is incompatible with 2pass");
diff -r 6b308775b6f0 -r ffb0111298cd source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Mon Nov 23 12:26:45 2015 +0530
+++ b/source/encoder/ratecontrol.cpp Mon Nov 23 14:06:10 2015 +0530
@@ -142,6 +142,8 @@
rce->expectedVbv = rce2Pass->expectedVbv;
rce->blurredComplexity = rce2Pass->blurredComplexity;
rce->sliceType = rce2Pass->sliceType;
+ rce->qpNoVbv = rce2Pass->qpNoVbv;
+ rce->newQp = rce2Pass->newQp;
}
} // end anonymous namespace
@@ -205,7 +207,7 @@
m_rateFactorMaxDecrement = m_param->rc.rfConstant - m_param->rc.rfConstantMin;
}
m_isAbr = m_param->rc.rateControlMode != X265_RC_CQP && !m_param->rc.bStatRead;
- m_2pass = m_param->rc.rateControlMode == X265_RC_ABR && m_param->rc.bStatRead;
+ m_2pass = (m_param->rc.rateControlMode == X265_RC_ABR || m_param->rc.vbvMaxBitrate > 0) && m_param->rc.bStatRead;
m_bitrate = m_param->rc.bitrate * 1000;
m_frameDuration = (double)m_param->fpsDenom / m_param->fpsNum;
m_qp = m_param->rc.qp;
@@ -488,6 +490,12 @@
x265_log(m_param, X265_LOG_ERROR, "Rce Entries for 2 pass cannot be allocated\n");
return false;
}
+ m_encOrder = X265_MALLOC(int, m_numEntries);
+ if (!m_encOrder)
+ {
+ x265_log(m_param, X265_LOG_ERROR, "Encode order for 2 pass cannot be allocated\n");
+ return false;
+ }
/* init all to skipped p frames */
for (int i = 0; i < m_numEntries; i++)
{
@@ -504,6 +512,7 @@
{
RateControlEntry *rce;
int frameNumber;
+ int encodeOrder;
char picType;
int e;
char *next;
@@ -511,13 +520,14 @@
next = strstr(p, ";");
if (next)
*next++ = 0;
- e = sscanf(p, " in:%d ", &frameNumber);
+ e = sscanf(p, " in:%d out:%d", &frameNumber, &encodeOrder);
if (frameNumber < 0 || frameNumber >= m_numEntries)
{
x265_log(m_param, X265_LOG_ERROR, "bad frame number (%d) at stats line %d\n", frameNumber, i);
return false;
}
- rce = &m_rce2Pass[frameNumber];
+ rce = &m_rce2Pass[encodeOrder];
+ m_encOrder[frameNumber] = encodeOrder;
e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf q-noVbv:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf",
&picType, &qpRc, &qpAq, &qNoVbv, &rce->coeffBits,
&rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount,
@@ -546,8 +556,7 @@
p = next;
}
X265_FREE(statsBuf);
-
- if (m_param->rc.rateControlMode == X265_RC_ABR)
+ if (m_param->rc.rateControlMode == X265_RC_ABR || m_param->rc.vbvMaxBitrate > 0)
{
if (!initPass2())
return false;
@@ -630,11 +639,8 @@
#undef MAX_DURATION
}
-
-bool RateControl::initPass2()
+bool RateControl::analyseABR2Pass(int startIndex, int endIndex, uint64_t allAvailableBits)
{
- uint64_t allConstBits = 0;
- uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * m_numEntries * m_frameDuration);
double rateFactor, stepMult;
double qBlur = m_param->rc.qblur;
double cplxBlur = m_param->rc.complexityBlur;
@@ -643,30 +649,19 @@
double *qScale, *blurredQscale;
double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);
double clippedDuration = CLIP_DURATION(m_frameDuration) / BASE_FRAME_DURATION;
-
- /* find total/average complexity & const_bits */
- for (int i = 0; i < m_numEntries; i++)
- allConstBits += m_rce2Pass[i].miscBits;
-
- 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 / m_numEntries * 1000.));
- return false;
- }
-
+ int framesCount = endIndex - startIndex + 1;
/* Blur complexities, to reduce local fluctuation of QP.
* We don't blur the QPs directly, because then one very simple frame
* could drag down the QP of a nearby complex frame and give it more
* bits than intended. */
- for (int i = 0; i < m_numEntries; i++)
+ for (int i = startIndex; i <= endIndex; i++)
{
double weightSum = 0;
double cplxSum = 0;
double weight = 1.0;
double gaussianWeight;
/* weighted average of cplx of future frames */
- for (int j = 1; j < cplxBlur * 2 && j < m_numEntries - i; j++)
+ for (int j = 1; j < cplxBlur * 2 && j <= endIndex - i; j++)
{
RateControlEntry *rcj = &m_rce2Pass[i + j];
weight *= 1 - pow(rcj->iCuCount / m_ncu, 2);
@@ -690,11 +685,10 @@
}
m_rce2Pass[i].blurredComplexity = cplxSum / weightSum;
}
-
- CHECKED_MALLOC(qScale, double, m_numEntries);
+ CHECKED_MALLOC(qScale, double, framesCount);
if (filterSize > 1)
{
- CHECKED_MALLOC(blurredQscale, double, m_numEntries);
+ CHECKED_MALLOC(blurredQscale, double, framesCount);
}
else
blurredQscale = qScale;
@@ -705,9 +699,8 @@
* because qscale2bits is not invertible, but we can start with the simple
* approximation of scaling the 1st pass by the ratio of bitrates.
* The search range is probably overkill, but speed doesn't matter here. */
-
expectedBits = 1;
- for (int i = 0; i < m_numEntries; i++)
+ for (int i = startIndex; i <= endIndex; i++)
{
RateControlEntry* rce = &m_rce2Pass[i];
double q = getQScale(rce, 1.0);
@@ -784,12 +777,10 @@
X265_FREE(qScale);
if (filterSize > 1)
X265_FREE(blurredQscale);
-
if (m_isVbv)
- if (!vbv2Pass(allAvailableBits))
+ if (!vbv2Pass(allAvailableBits, endIndex, startIndex))
return false;
- expectedBits = countExpectedBits();
-
+ expectedBits = countExpectedBits(startIndex, endIndex);
if (fabs(expectedBits / allAvailableBits - 1.0) > 0.01)
{
double avgq = 0;
@@ -822,7 +813,127 @@
return false;
}
-bool RateControl::vbv2Pass(uint64_t allAvailableBits)
+bool RateControl::initPass2()
+{
+ uint64_t allConstBits = 0, allCodedBits = 0;
+ uint64_t allAvailableBits = uint64_t(m_param->rc.bitrate * 1000. * m_numEntries * m_frameDuration);
+ int startIndex, framesCount, endIndex, cnt;
+ int fps = (int)(m_fps + 0.5);
+ startIndex = endIndex = framesCount = 0;
+ allAvailableBits = uint64_t(m_param->rc.vbvMaxBitrate * 1000. * m_numEntries * m_frameDuration);
+ bool isQpModified = true;
+ int diffQp = 0;
+ int64_t targetBits = 0;
+ int64_t expectedBits = 0;
+ for (startIndex = 0, endIndex = 0; endIndex < m_numEntries; endIndex++)
+ {
+ allConstBits += m_rce2Pass[endIndex].miscBits;
+ allCodedBits += m_rce2Pass[endIndex].coeffBits + m_rce2Pass[endIndex].mvBits;
+ if (m_param->rc.rateControlMode == X265_RC_CRF)
+ {
+ framesCount = endIndex - startIndex + 1;
+ if (m_rce2Pass[endIndex].newQScale < 0)
+ m_rce2Pass[endIndex].newQScale = m_rce2Pass[endIndex].qScale;
+ 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 (!isQpModified && endIndex > fps)
+ {
+ double factor = 2;
+ double step = 0;
+ for (int start = endIndex; start <= endIndex + fps - 1 && 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)
+ {
+ isQpModified = true;
+ while (endIndex + fps < m_numEntries)
+ {
+ step = pow(2, factor / 6.0);
+ expectedBits = 0;
+ for (int start = endIndex; start <= endIndex + fps - 1; 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(targetBits, endIndex + fps - 1, endIndex))
+ return false;
+
+ double prevFactor = factor;
+ targetBits = 0;
+ expectedBits = 0;
+
+ for (int start = endIndex - fps; start <= endIndex - 1; 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; start <= endIndex - 1; 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(targetBits, endIndex - 1, endIndex - fps))
+ return false;
+ diffQp = 0;
+ startIndex = endIndex + 1;
+ targetBits = expectedBits = 0;
+ }
+ else
+ targetBits = expectedBits = 0;
+ }
+ }
+ else
+ isQpModified = false;
+ }
+ }
+ }
+
+ 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.));
+ return false;
+ }
+ if (!analyseABR2Pass(0, m_numEntries - 1, allAvailableBits))
+ return false;
+ }
+ return true;
+}
+
+bool RateControl::vbv2Pass(uint64_t allAvailableBits, int endPos, int startPos)
{
/* for each interval of bufferFull .. underflow, uniformly increase the qp of all
* frames in the interval until either buffer is full at some intermediate frame or the
@@ -848,10 +959,10 @@
{ /* not first iteration */
adjustment = X265_MAX(X265_MIN(expectedBits / allAvailableBits, 0.999), 0.9);
fills[-1] = m_bufferSize * m_param->rc.vbvBufferInit;
- t0 = 0;
+ t0 = startPos;
/* fix overflows */
adjMin = 1;
- while (adjMin && findUnderflow(fills, &t0, &t1, 1))
+ while (adjMin && findUnderflow(fills, &t0, &t1, 1, endPos))
{
adjMin = fixUnderflow(t0, t1, adjustment, MIN_QPSCALE, MAX_MAX_QPSCALE);
t0 = t1;
@@ -862,20 +973,16 @@
t0 = 0;
/* fix underflows -- should be done after overflow, as we'd better undersize target than underflowing VBV */
adjMax = 1;
- while (adjMax && findUnderflow(fills, &t0, &t1, 0))
+ while (adjMax && findUnderflow(fills, &t0, &t1, 0, endPos))
adjMax = fixUnderflow(t0, t1, 1.001, MIN_QPSCALE, MAX_MAX_QPSCALE );
-
- expectedBits = countExpectedBits();
+ expectedBits = countExpectedBits(startPos, endPos);
}
- while ((expectedBits < .995 * allAvailableBits) && ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)));
-
+ while ((expectedBits < .995 * allAvailableBits) && ((int64_t)(expectedBits+.5) > (int64_t)(prevBits+.5)) && !(m_param->rc.rateControlMode == X265_RC_CRF));
if (!adjMax)
x265_log(m_param, X265_LOG_WARNING, "vbv-maxrate issue, qpmax or vbv-maxrate too low\n");
-
/* store expected vbv filling values for tracking when encoding */
- for (int i = 0; i < m_numEntries; i++)
+ for (int i = startPos; i <= endPos; i++)
m_rce2Pass[i].expectedVbv = m_bufferSize - fills[i];
-
X265_FREE(fills - 1);
return true;
@@ -915,9 +1022,10 @@
m_param->bframes = 1;
return X265_TYPE_AUTO;
}
- int frameType = m_rce2Pass[frameNum].sliceType == I_SLICE ? (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR)
- : m_rce2Pass[frameNum].sliceType == P_SLICE ? X265_TYPE_P
- : (m_rce2Pass[frameNum].sliceType == B_SLICE && m_rce2Pass[frameNum].keptAsRef? X265_TYPE_BREF : X265_TYPE_B);
+ int index = m_encOrder[frameNum];
+ int frameType = m_rce2Pass[index].sliceType == I_SLICE ? (frameNum > 0 && m_param->bOpenGOP ? X265_TYPE_I : X265_TYPE_IDR)
+ : m_rce2Pass[index].sliceType == P_SLICE ? X265_TYPE_P
+ : (m_rce2Pass[index].sliceType == B_SLICE && m_rce2Pass[index].keptAsRef ? X265_TYPE_BREF : X265_TYPE_B);
return frameType;
}
else
@@ -968,7 +1076,8 @@
if (m_param->rc.bStatRead)
{
X265_CHECK(rce->poc >= 0 && rce->poc < m_numEntries, "bad encode ordinal\n");
- copyRceData(rce, &m_rce2Pass[rce->poc]);
+ int index = m_encOrder[rce->poc];
+ copyRceData(rce, &m_rce2Pass[index]);
}
rce->isActive = true;
bool isRefFrameScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refPicList[0][0]->m_lowres.bScenecut == 1;
@@ -1032,6 +1141,16 @@
}
}
}
+ if (!m_isAbr && m_2pass && m_param->rc.rateControlMode == X265_RC_CRF)
+ {
+ 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;
+ }
+
if (m_isAbr || m_2pass) // ABR,CRF
{
if (m_isAbr || m_isVbv)
@@ -1203,11 +1322,10 @@
}
return q;
}
-
-double RateControl::countExpectedBits()
+double RateControl::countExpectedBits(int startPos, int endPos)
{
double expectedBits = 0;
- for( int i = 0; i < m_numEntries; i++ )
+ for (int i = startPos; i <= endPos; i++)
{
RateControlEntry *rce = &m_rce2Pass[i];
rce->expectedBits = (uint64_t)expectedBits;
@@ -1215,8 +1333,7 @@
}
return expectedBits;
}
-
-bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over)
+bool RateControl::findUnderflow(double *fills, int *t0, int *t1, int over, int endPos)
{
/* find an interval ending on an overflow or underflow (depending on whether
* we're adding or removing bits), and starting on the earliest frame that
@@ -1226,7 +1343,7 @@
double fill = fills[*t0 - 1];
double parity = over ? 1. : -1.;
int start = -1, end = -1;
- for (int i = *t0; i < m_numEntries; i++)
+ for (int i = *t0; i <= endPos; i++)
{
fill += (m_frameDuration * m_vbvMaxRate -
qScale2bits(&m_rce2Pass[i], m_rce2Pass[i].newQScale)) * parity;
@@ -1263,12 +1380,11 @@
}
return adjusted;
}
-
bool RateControl::cuTreeReadFor2Pass(Frame* frame)
{
- uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[frame->m_poc].sliceType;
-
- if (m_rce2Pass[frame->m_poc].keptAsRef)
+ int index = m_encOrder[frame->m_poc];
+ uint8_t sliceTypeActual = (uint8_t)m_rce2Pass[index].sliceType;
+ if (m_rce2Pass[index].keptAsRef)
{
/* TODO: We don't need pre-lookahead to measure AQ offsets, but there is currently
* no way to signal this */
@@ -1948,6 +2064,8 @@
int RateControl::rowDiagonalVbvRateControl(Frame* curFrame, uint32_t row, RateControlEntry* rce, double& qpVbv)
{
+ if (m_param->rc.bStatRead && m_param->rc.rateControlMode == X265_RC_CRF)
+ return 0;
FrameData& curEncData = *curFrame->m_encData;
double qScaleVbv = x265_qp2qScale(qpVbv);
uint64_t rowSatdCost = curEncData.m_rowStat[row].diagSatd;
@@ -2195,7 +2313,7 @@
if (m_param->rc.aqMode || m_isVbv)
{
- if (m_isVbv)
+ if (m_isVbv && !(m_2pass && m_param->rc.rateControlMode == X265_RC_CRF))
{
/* determine avg QP decided by VBV rate control */
for (uint32_t i = 0; i < slice->m_sps->numCuInHeight; i++)
diff -r 6b308775b6f0 -r ffb0111298cd source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h Mon Nov 23 12:26:45 2015 +0530
+++ b/source/encoder/ratecontrol.h Mon Nov 23 14:06:10 2015 +0530
@@ -205,8 +205,8 @@
double m_lastAccumPNorm;
double m_expectedBitsSum; /* sum of qscale2bits after rceq, ratefactor, and overflow, only includes finished frames */
int64_t m_predictedBits;
+ int *m_encOrder;
RateControlEntry* m_rce2Pass;
-
struct
{
uint16_t *qpBuffer[2]; /* Global buffers for converting MB-tree quantizer data. */
@@ -258,11 +258,12 @@
void checkAndResetABR(RateControlEntry* rce, bool isFrameDone);
double predictRowsSizeSum(Frame* pic, RateControlEntry* rce, double qpm, int32_t& encodedBits);
bool initPass2();
+ bool analyseABR2Pass(int startPoc, int endPoc, uint64_t allAvailableBits);
void initFramePredictors();
double getDiffLimitedQScale(RateControlEntry *rce, double q);
- double countExpectedBits();
- bool vbv2Pass(uint64_t allAvailableBits);
- bool findUnderflow(double *fills, int *t0, int *t1, int over);
+ double countExpectedBits(int startPos, int framesCount);
+ bool vbv2Pass(uint64_t allAvailableBits, int frameCount, int startPos);
+ bool findUnderflow(double *fills, int *t0, int *t1, int over, int framesCount);
bool fixUnderflow(int t0, int t1, double adjustment, double qscaleMin, double qscaleMax);
};
}
More information about the x265-devel
mailing list