[x265] [PATCH 2 of 2] rc: implement 2 pass CRF, when vbv is enabled
Aarthi Priya Thirumalai
aarthi at multicorewareinc.com
Mon Nov 23 12:37:46 CET 2015
pls ignore the previous patch. It has a few bugs while merging.
here is the fixed one :
# 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 0c49c9cc75e4c1ef9534a28b49b97b9107636f5d
# 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 0c49c9cc75e4 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 0c49c9cc75e4 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,
@@ -538,7 +548,7 @@
x265_log(m_param, X265_LOG_ERROR, "statistics are
damaged at line %d, parser out=%d\n", i, e);
return false;
}
- rce->qScale = x265_qp2qScale(qpRc);
+ rce->qScale = rce->newQScale = x265_qp2qScale(qpRc);
totalQpAq += qpAq;
rce->qpNoVbv = qNoVbv;
rce->qpaRc = qpRc;
@@ -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,125 @@
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;
+ 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 +957,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 +971,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 +1020,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 +1074,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 +1139,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 +1320,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 +1331,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 +1341,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 +1378,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 +2062,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 +2311,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 0c49c9cc75e4 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);
};
}
On Mon, Nov 23, 2015 at 2:16 PM, <aarthi at multicorewareinc.com> wrote:
> # 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);
> };
> }
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20151123/d1b3c8f5/attachment-0001.html>
More information about the x265-devel
mailing list