[x265] [PATCH] vbv: lookahead
santhoshini at multicorewareinc.com
santhoshini at multicorewareinc.com
Wed Feb 12 08:33:59 CET 2014
# HG changeset patch
# User Santhoshini Sekar <santhoshini at multicorewareinc.com>
# Date 1392189204 -19800
# Wed Feb 12 12:43:24 2014 +0530
# Node ID e83af58ed0f3a9308dacf64f79b9ddad47cd0170
# Parent 699f2aa335e9995e32a07181eb70bd1ed1dfb7e9
vbv: lookahead
diff -r 699f2aa335e9 -r e83af58ed0f3 source/common/lowres.h
--- a/source/common/lowres.h Tue Feb 11 13:06:43 2014 +0530
+++ b/source/common/lowres.h Wed Feb 12 12:43:24 2014 +0530
@@ -121,6 +121,8 @@
uint16_t(*lowresCosts[X265_BFRAME_MAX + 2][X265_BFRAME_MAX + 2]);
int32_t* lowresMvCosts[2][X265_BFRAME_MAX + 1];
MV* lowresMvs[2][X265_BFRAME_MAX + 1];
+ int plannedType[X265_LOOKAHEAD_MAX+1];
+ int64_t plannedSatd[X265_LOOKAHEAD_MAX+1];
/* rate control / adaptive quant data */
double* qpAqOffset; // qp Aq offset values for each Cu
diff -r 699f2aa335e9 -r e83af58ed0f3 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/ratecontrol.cpp Wed Feb 12 12:43:24 2014 +0530
@@ -384,7 +384,7 @@
{
lastSatd = l->getEstimatedPictureCost(pic);
rce->lastSatd = lastSatd;
- double q = qScale2qp(rateEstimateQscale(rce));
+ double q = qScale2qp(rateEstimateQscale(pic, rce));
qp = Clip3(MIN_QP, MAX_MAX_QP, (int)(q + 0.5));
rce->qpaRc = q;
/* copy value of lastRceq into thread local rce struct *to be used in RateControlEnd() */
@@ -416,7 +416,7 @@
accumPQp += qp;
}
-double RateControl::rateEstimateQscale(RateControlEntry *rce)
+double RateControl::rateEstimateQscale(TComPic* pic, RateControlEntry *rce)
{
double q;
@@ -558,7 +558,7 @@
double lmax1 = lmax[sliceType];
q = Clip3(lmin1, lmax1, q);
- q = clipQscale(q);
+ q = clipQscale(pic, q);
lastQScaleFor[sliceType] = q;
@@ -614,7 +614,7 @@
return (p->coeff * var + p->offset) / (q * p->count);
}
-double RateControl::clipQscale(double q)
+double RateControl::clipQscale(TComPic* pic, double q)
{
double lmin1 = lmin[sliceType];
double lmax1 = lmax[sliceType];
@@ -624,8 +624,55 @@
// since they are controlled by the P-frames' QPs.
if (isVbv && lastSatd > 0)
{
- //if (lookahead){} //for lookahead
- //else
+ if (cfg->param.lookaheadDepth)
+ {
+ int terminate = 0;
+
+ /* Avoid an infinite loop. */
+ for (int iterations = 0; iterations < 1000 && terminate != 3; iterations++)
+ {
+ double frameQ[3];
+ double curBits = predictSize(&pred[sliceType], q, (double)lastSatd);
+ double bufferFillCur = bufferFill - curBits;
+ double targetFill;
+ double totalDuration = 0;
+ frameQ[0] = sliceType == I_SLICE ? q * cfg->param.rc.ipFactor : q;
+ frameQ[1] = frameQ[0] * cfg->param.rc.pbFactor;
+ frameQ[2] = frameQ[0] / cfg->param.rc.ipFactor;
+
+ /* Loop over the planned future frames. */
+ for (int j = 0; bufferFillCur >= 0 && bufferFillCur <= bufferSize; j++)
+ {
+ totalDuration += frameDuration;
+ bufferFillCur += vbvMaxRate * frameDuration;
+ int type = pic->m_lowres.plannedType[j];
+ int64_t satd = pic->m_lowres.plannedSatd[j];
+ if (type == X265_TYPE_AUTO)
+ break;
+ type = IS_X265_TYPE_I(type) ? I_SLICE : IS_X265_TYPE_B(type) ? B_SLICE : P_SLICE;
+ curBits = predictSize(&pred[type], frameQ[type], (double)satd);
+ bufferFillCur -= curBits;
+ }
+ /* Try to get the buffer at least 50% filled, but don't set an impossible goal. */
+ targetFill = X265_MIN(bufferFill + totalDuration * vbvMaxRate * 0.5, bufferSize * 0.5);
+ if (bufferFillCur < targetFill)
+ {
+ q *= 1.01;
+ terminate |= 1;
+ 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);
+ if (vbvMinRate && bufferFillCur > targetFill)
+ {
+ q /= 1.01;
+ terminate |= 2;
+ continue;
+ }
+ break;
+ }
+ }
+ else
{
if ((sliceType == P_SLICE ||
(sliceType == I_SLICE && lastNonBPictType == I_SLICE)) &&
diff -r 699f2aa335e9 -r e83af58ed0f3 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/ratecontrol.h Wed Feb 12 12:43:24 2014 +0530
@@ -129,13 +129,13 @@
protected:
double getQScale(RateControlEntry *rce, double rateFactor);
- double rateEstimateQscale(RateControlEntry *rce); // main logic for calculating QP based on ABR
+ double rateEstimateQscale(TComPic* pic, RateControlEntry *rce); // main logic for calculating QP based on ABR
void accumPQpUpdate();
uint32_t acEnergyCu(TComPic* pic, uint32_t block_x, uint32_t block_y);
void updateVbv(int64_t bits, RateControlEntry* rce);
void updatePredictor(Predictor *p, double q, double var, double bits);
- double clipQscale(double q);
+ double clipQscale(TComPic* pic, double q);
void updateVbvPlan(Encoder* enc);
double predictSize(Predictor *p, double q, double var);
void checkAndResetABR(RateControlEntry* rce);
diff -r 699f2aa335e9 -r e83af58ed0f3 source/encoder/slicetype.cpp
--- a/source/encoder/slicetype.cpp Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/slicetype.cpp Wed Feb 12 12:43:24 2014 +0530
@@ -373,13 +373,57 @@
}
}
+void Lookahead::vbvLookahead(Lowres **frames, int numFrames, int keyframe)
+{
+ int prevNonB = 0, curNonB = 1, idx = 0;
+ while (curNonB < numFrames && frames[curNonB]->sliceType == X265_TYPE_B)
+ curNonB++;
+ int nextNonB = keyframe ? prevNonB : curNonB;
+
+ while (curNonB < numFrames)
+ {
+ /* P/I cost: This shouldn't include the cost of nextNonB */
+ if (nextNonB != curNonB)
+ {
+ int p0 = IS_X265_TYPE_I(frames[curNonB]->sliceType) ? curNonB : prevNonB;
+ frames[nextNonB]->plannedSatd[idx] = vbvFrameCost(frames, p0, curNonB, curNonB);
+ frames[nextNonB]->plannedType[idx] = frames[curNonB]->sliceType;
+ idx++;
+ }
+ /* Handle the B-frames: coded order */
+ for (int i = prevNonB+1; i < curNonB; i++, idx++)
+ {
+ frames[nextNonB]->plannedSatd[idx] = vbvFrameCost(frames, prevNonB, curNonB, i);
+ frames[nextNonB]->plannedType[idx] = X265_TYPE_B;
+ }
+ prevNonB = curNonB;
+ curNonB++;
+ while (curNonB <= numFrames && frames[curNonB]->sliceType == X265_TYPE_B)
+ curNonB++;
+ }
+ frames[nextNonB]->plannedType[idx] = X265_TYPE_AUTO;
+}
+
+int64_t Lookahead::vbvFrameCost(Lowres **frames, int p0, int p1, int b)
+{
+ int64_t cost = est.estimateFrameCost(frames, p0, p1, b, 0);
+ if (cfg->param.rc.aqMode)
+ {
+ if (cfg->param.rc.cuTree)
+ return frameCostRecalculate(frames, p0, p1, b);
+ else
+ return frames[b]->costEstAq[b-p0][p1-b];
+ }
+ return cost;
+}
+
void Lookahead::slicetypeAnalyse(Lowres **frames, bool bKeyframe)
{
int numFrames, origNumFrames, keyintLimit, framecnt;
int maxSearch = X265_MIN(cfg->param.lookaheadDepth, X265_LOOKAHEAD_MAX);
int cuCount = NUM_CUS;
int resetStart;
-
+ int isVbvLookahead = cfg->param.rc.vbvBufferSize && cfg->param.lookaheadDepth;
if (!lastNonB)
return;
@@ -403,7 +447,9 @@
keyintLimit = cfg->param.keyframeMax - frames[0]->frameNum + lastKeyframe - 1;
origNumFrames = numFrames = X265_MIN(framecnt, keyintLimit);
- if (cfg->param.bOpenGOP && numFrames < framecnt)
+ if (isVbvLookahead)
+ numFrames = framecnt;
+ else if (cfg->param.bOpenGOP && numFrames < framecnt)
numFrames++;
else if (numFrames == 0)
{
@@ -538,6 +584,9 @@
resetStart = X265_MIN(resetStart, j + 1);
}
+ if (isVbvLookahead)
+ vbvLookahead(frames, numFrames, bKeyframe);
+
/* Restore frametypes for all frames that haven't actually been decided yet. */
for (int j = resetStart; j <= numFrames; j++)
{
diff -r 699f2aa335e9 -r e83af58ed0f3 source/encoder/slicetype.h
--- a/source/encoder/slicetype.h Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/slicetype.h Wed Feb 12 12:43:24 2014 +0530
@@ -151,6 +151,8 @@
bool scenecutInternal(Lowres **frames, int p0, int p1, bool bRealScenecut);
void slicetypePath(Lowres **frames, int length, char(*best_paths)[X265_LOOKAHEAD_MAX + 1]);
int64_t slicetypePathCost(Lowres **frames, char *path, int64_t threshold);
+ int64_t vbvFrameCost(Lowres **frames, int p0, int p1, int b);
+ void vbvLookahead(Lowres **frames, int numFrames, int keyframes);
/* called by slicetypeAnalyse() to effect cuTree adjustments to adaptive
* quant offsets */
More information about the x265-devel
mailing list