[x265] [PATCH 5 of 6] vbv: implement row wise vbvRateControl at each row diagonal
aarthi at multicorewareinc.com
aarthi at multicorewareinc.com
Fri Feb 21 07:08:40 CET 2014
# HG changeset patch
# User Aarthi Thirumalai
# Date 1392962748 -19800
# Fri Feb 21 11:35:48 2014 +0530
# Node ID 22d4811e0676fbec5e8bf96d99be9b98020fc89f
# Parent d058d4dd84a547b9b72a043ed065a94220b2f32b
vbv: implement row wise vbvRateControl at each row diagonal
diff -r d058d4dd84a5 -r 22d4811e0676 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Thu Feb 20 18:09:53 2014 +0530
+++ b/source/encoder/ratecontrol.cpp Fri Feb 21 11:35:48 2014 +0530
@@ -220,6 +220,10 @@
// validate for cfg->param.rc, maybe it is need to add a function like x265_parameters_valiate()
cfg->param.rc.rfConstant = Clip3((double)-QP_BD_OFFSET, (double)51, cfg->param.rc.rfConstant);
+ cfg->param.rc.rfConstantMax = Clip3((double)-QP_BD_OFFSET, (double)51, cfg->param.rc.rfConstantMax);
+ rateFactorMaxIncrement = 0;
+ vbvMinRate = 0;
+
if (cfg->param.rc.rateControlMode == X265_RC_CRF)
{
cfg->param.rc.qp = (int)cfg->param.rc.rfConstant + QP_BD_OFFSET;
@@ -229,6 +233,15 @@
double mbtree_offset = cfg->param.rc.cuTree ? (1.0 - cfg->param.rc.qCompress) * 13.5 : 0;
rateFactorConstant = pow(baseCplx, 1 - qCompress) /
qp2qScale(cfg->param.rc.rfConstant + mbtree_offset + QP_BD_OFFSET);
+ if (cfg->param.rc.rfConstantMax)
+ {
+ rateFactorMaxIncrement = cfg->param.rc.rfConstantMax - cfg->param.rc.rfConstant;
+ if (rateFactorMaxIncrement <= 0)
+ {
+ x265_log(&cfg->param, X265_LOG_WARNING, "CRF max must be greater than CRF\n");
+ rateFactorMaxIncrement = 0;
+ }
+ }
}
isAbr = cfg->param.rc.rateControlMode != X265_RC_CQP; // later add 2pass option
@@ -448,6 +461,7 @@
bool i1 = nextRefSlice->getSliceType() == I_SLICE;
int dt0 = abs(curSlice->getPOC() - prevRefSlice->getPOC());
int dt1 = abs(curSlice->getPOC() - nextRefSlice->getPOC());
+
// Skip taking a reference frame before the Scenecut if ABR has been reset.
if (lastAbrResetPoc >= 0 && !isVbv)
{
@@ -676,7 +690,7 @@
continue;
}
/* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */
- targetFill = Clip3(bufferFill - totalDuration * vbvMaxRate * 0.5, bufferSize * 0.8, bufferSize);
+ targetFill = Clip3(bufferSize * 0.8, bufferSize, bufferFill - totalDuration * vbvMaxRate * 0.5);
if (vbvMinRate && bufferFillCur > targetFill)
{
q /= 1.01;
@@ -748,6 +762,169 @@
return Clip3(lmin1, lmax1, q);
}
+ double RateControl::predictRowsSizeSum(TComPic* pic, double qpVbv, int32_t & encodedBitsSoFar)
+{
+ uint32_t rowSatdCostSoFar = 0 ,totalSatdBits = 0;
+ encodedBitsSoFar = 0;
+ double qScale = qp2qScale(qpVbv);
+ int picType = pic->getSlice()->getSliceType();
+ TComPic* refPic = pic->getSlice()->getRefPic(REF_PIC_LIST_0, 0);
+ int maxRows = pic->getPicSym()->getFrameHeightInCU();
+ for (int row = 0 ; row < maxRows; row++)
+ {
+ encodedBitsSoFar += pic->m_rowEncodedBits[row];
+ rowSatdCostSoFar = pic->m_rowDiagSatd[row];
+ uint32_t satdCostForPendingCus = pic->m_rowSatdForVbv[row] - rowSatdCostSoFar;
+ if (satdCostForPendingCus > 0)
+ {
+ double pred_s = predictSize(rowPred[0], qScale, satdCostForPendingCus);
+ uint32_t refRowSatdCost= 0 , refRowBits = 0;
+ double refQScale=0;
+
+ if (picType != I_SLICE)
+ {
+ uint32_t endCuAddr = pic->getPicSym()->getFrameWidthInCU() * (row + 1);
+ for (uint32_t cuAddr = pic->m_numEncodedCusPerRow[row] + 1; cuAddr < endCuAddr; cuAddr++)
+ {
+ refRowSatdCost += refPic->m_cuCostsForVbv[cuAddr];
+ refRowBits = refPic->getCU(cuAddr)->m_totalBits;
+ }
+ refQScale = row == maxRows - 1 ? refPic->m_rowDiagQScale[row] : refPic->m_rowDiagQScale[row + 1];
+ }
+
+ if (picType == I_SLICE || qScale >= refQScale)
+ {
+ if (picType == P_SLICE
+ && refPic->getSlice()->getSliceType() == picType
+ && refQScale > 0
+ && refRowSatdCost > 0)
+ {
+ if (abs(int32_t(refRowSatdCost - satdCostForPendingCus)) < (int32_t)satdCostForPendingCus / 2)
+ {
+ double pred_t = refRowBits * satdCostForPendingCus / refRowSatdCost
+ * refQScale / qScale;
+ totalSatdBits += int32_t((pred_s + pred_t) * 0.5);
+ }
+ }
+
+ else
+ totalSatdBits += int32_t(pred_s);
+ }
+ else
+ {
+ /* Our QP is lower than the reference! */
+ double pred_intra = predictSize(rowPred[1], qScale, refRowSatdCost);
+ /* Sum: better to overestimate than underestimate by using only one of the two predictors. */
+ totalSatdBits += int32_t(pred_intra + pred_s);
+ }
+ }
+ }
+ return totalSatdBits + encodedBitsSoFar;
+ }
+int RateControl::rowDiagonalVbvRateControl(TComPic* pic, uint32_t row, RateControlEntry* rce, double& qpVbv)
+{
+ double qScaleVbv = qp2qScale(qpVbv);
+ pic->m_rowDiagQp[row] = qpVbv;
+ pic->m_rowDiagQScale[row] = qScaleVbv;
+ //TODO : check whther we gotto update prodictor using whole Row Satd or only satd of blocks upto the diagonal in row.
+ updatePredictor(rowPred[0], qScaleVbv, (double)pic->m_rowDiagSatd[row], (double)pic->m_rowEncodedBits[row]);
+ if (pic->getSlice()->getSliceType() == P_SLICE)
+ {
+ TComPic* refSlice = pic->getSlice()->getRefPic(REF_PIC_LIST_0, 0);
+ if (qpVbv < refSlice->m_rowDiagQp[row])
+ {
+ updatePredictor(rowPred[1], qScaleVbv, refSlice->m_rowDiagSatd[row], refSlice->m_rowEncodedBits[row]);
+ }
+ }
+
+ int canReencodeRow = 1;
+ /* tweak quality based on difference from predicted size */
+ double prevRowQp = qpVbv;
+ double qpAbsoluteMax = MAX_MAX_QP;
+ if (rateFactorMaxIncrement)
+ qpAbsoluteMax = X265_MIN(qpAbsoluteMax, rce->qpNoVbv + rateFactorMaxIncrement);
+ double qpMax = X265_MIN(prevRowQp + cfg->param.rc.qpStep, qpAbsoluteMax );
+ double qpMin = X265_MAX(prevRowQp - cfg->param.rc.qpStep, MIN_QP );
+ double stepSize = 0.5;
+ double bufferLeftPlanned = bufferFill - rce->frameSizePlanned;
+
+ double maxFrameError = X265_MAX(0.05, 1.0 / pic->getFrameHeightInCU());
+
+ if (row < pic->getPicSym()->getFrameHeightInCU() - 1)
+ {
+ /* B-frames shouldn't use lower QP than their reference frames. */
+ if (rce->sliceType == B_SLICE)
+ {
+ TComPic* refSlice1 = pic->getSlice()->getRefPic(REF_PIC_LIST_0, 0);
+ TComPic* refSlice2 = pic->getSlice()->getRefPic(REF_PIC_LIST_1, 0);
+ qpMin = X265_MAX(qpMin, X265_MAX(refSlice1->m_rowDiagQp[row], refSlice2->m_rowDiagQp[row]));
+ qpVbv = X265_MAX(qpVbv, qpMin);
+ }
+ /* More threads means we have to be more cautious in letting ratecontrol use up extra bits. */
+ double rcTol = bufferLeftPlanned / cfg->param.frameNumThreads * cfg->param.rc.rateTolerance;
+ int32_t encodedBitsSoFar = 0;
+ double b1 = predictRowsSizeSum(pic, qpVbv, encodedBitsSoFar);
+
+ /* Don't increase the row QPs until a sufficent amount of the bits of the frame have been processed, in case a flat */
+ /* area at the top of the frame was measured inaccurately. */
+ if (encodedBitsSoFar < 0.05f * rce->frameSizePlanned)
+ qpMax = qpAbsoluteMax = prevRowQp;
+
+ if (rce->sliceType != I_SLICE)
+ rcTol *= 0.5;
+
+ if (!vbvMinRate)
+ qpMin = X265_MAX(qpMin, rce->qpNoVbv);
+
+ while (qpVbv < qpMax
+ && ((b1 > rce->frameSizePlanned + rcTol) ||
+ (bufferFill - b1 < bufferLeftPlanned * 0.5) ||
+ (b1 > rce->frameSizePlanned && qpVbv < rce->qpNoVbv)))
+ {
+ qpVbv += stepSize;
+ b1 = predictRowsSizeSum(pic, qpVbv, encodedBitsSoFar);
+ }
+
+ while (qpVbv > qpMin
+ && (qpVbv > pic->m_rowDiagQp[0] || singleFrameVbv)
+ && ((b1 < rce->frameSizePlanned * 0.8f && qpVbv <= prevRowQp)
+ || b1 < (bufferFill - bufferSize + bufferRate) * 1.1))
+ {
+ qpVbv -= stepSize;
+ b1 = predictRowsSizeSum(pic, qpVbv, encodedBitsSoFar);
+ }
+ /* avoid VBV underflow */
+ while ((qpVbv < qpAbsoluteMax)
+ && (bufferFill - b1 < bufferRate * maxFrameError))
+ {
+ qpVbv += stepSize;
+ b1 = predictRowsSizeSum(pic, qpVbv, encodedBitsSoFar);
+ }
+ frameSizeEstimated = b1;
+
+ /* If the current row was large enough to cause a large QP jump, try re-encoding it. */
+ if (qpVbv > qpMax && prevRowQp < qpMax && canReencodeRow)
+ {
+ /* Bump QP to halfway in between... close enough. */
+ qpVbv = Clip3(prevRowQp + 1.0f, qpMax, (prevRowQp + qpVbv)*0.5);
+ return -1;
+ }
+ }
+ else
+ {
+ int32_t encodedBitsSoFar = 0;
+ frameSizeEstimated = predictRowsSizeSum(pic, qpVbv, encodedBitsSoFar);
+ /* Last-ditch attempt: if the last row of the frame underflowed the VBV,
+ * try again. */
+ if((frameSizeEstimated > (bufferFill - bufferRate * maxFrameError) &&
+ qpVbv < qpMax && canReencodeRow))
+ {
+ qpVbv = qpMax;
+ return -1;
+ }
+ }
+ return 0;
+}
/* modify the bitrate curve from pass1 for one frame */
double RateControl::getQScale(RateControlEntry *rce, double rateFactor)
diff -r d058d4dd84a5 -r 22d4811e0676 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h Thu Feb 20 18:09:53 2014 +0530
+++ b/source/encoder/ratecontrol.h Fri Feb 21 11:35:48 2014 +0530
@@ -91,6 +91,7 @@
double vbvMaxRate; /* in kbps */
double vbvMinRate; /* in kbps */
bool singleFrameVbv;
+ double rateFactorMaxIncrement; /* Don't allow RF above (CRF + this value). */
bool isVbv;
Predictor pred[5];
Predictor predBfromP;
@@ -123,10 +124,13 @@
double qpNoVbv; /* QP for the current frame if 1-pass VBV was disabled. */
double frameSizeEstimated; /* hold synched frameSize, updated from cu level vbv rc */
RateControl(TEncCfg * _cfg);
+
// to be called for each frame to process RateControl and set QP
void rateControlStart(TComPic* pic, Lookahead *, RateControlEntry* rce, Encoder* enc);
void calcAdaptiveQuantFrame(TComPic *pic);
int rateControlEnd(TComPic* pic, int64_t bits, RateControlEntry* rce);
+ int rowDiagonalVbvRateControl(TComPic* pic, uint32_t row, RateControlEntry* rce, double& qpVbv);
+
protected:
double getQScale(RateControlEntry *rce, double rateFactor);
double rateEstimateQscale(TComPic* pic, RateControlEntry *rce); // main logic for calculating QP based on ABR
@@ -139,7 +143,7 @@
void updateVbvPlan(Encoder* enc);
double predictSize(Predictor *p, double q, double var);
void checkAndResetABR(TComPic* pic, RateControlEntry* rce);
+ double predictRowsSizeSum(TComPic* pic, double qpm , int32_t& encodedBits);
};
}
-
#endif // ifndef X265_RATECONTROL_H
More information about the x265-devel
mailing list