[x265] [PATCH] vbv: lookahead

santhoshini at multicorewareinc.com santhoshini at multicorewareinc.com
Tue Feb 11 11:21:17 CET 2014


# HG changeset patch
# User Santhoshini Sekar <santhoshini at multicorewareinc.com>
# Date 1392114033 -19800
#      Tue Feb 11 15:50:33 2014 +0530
# Node ID 49ef320ebb35713beca0ae1da8b928b8dc806343
# Parent  cd078d0dc0278dfca6e13e8f210cb6dda707e306
vbv: lookahead

diff -r cd078d0dc027 -r 49ef320ebb35 source/common/lowres.h
--- a/source/common/lowres.h	Tue Feb 11 13:06:43 2014 +0530
+++ b/source/common/lowres.h	Tue Feb 11 15:50:33 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 cd078d0dc027 -r 49ef320ebb35 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/ratecontrol.cpp	Tue Feb 11 15:50:33 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 cd078d0dc027 -r 49ef320ebb35 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h	Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/ratecontrol.h	Tue Feb 11 15:50:33 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 cd078d0dc027 -r 49ef320ebb35 source/encoder/slicetype.cpp
--- a/source/encoder/slicetype.cpp	Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/slicetype.cpp	Tue Feb 11 15:50:33 2014 +0530
@@ -373,13 +373,65 @@
     }
 }
 
+void Lookahead::x265VbvLookahead(Lowres **frames, int numFrames, int keyframe)
+{
+    int lastNonB = 0, curNonB = 1, idx = 0;
+    Lowres *prevFrame = NULL;
+    int prevFrameIdx = 0;
+    while (curNonB < numFrames && frames[curNonB]->sliceType == X265_TYPE_B)
+        curNonB++;
+    int nextNonB = keyframe ? lastNonB : 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 : lastNonB;
+            frames[nextNonB]->plannedSatd[idx] = x265VbvFrameCost(frames, p0, curNonB, curNonB);
+            frames[nextNonB]->plannedType[idx] = frames[curNonB]->sliceType;
+            /*Use plannedCpbDuration instead of frameduration in ratecontrol if planning to use pulldown and initialise it here*/
+            prevFrame = frames[curNonB];
+            prevFrameIdx = idx;
+            idx++;
+        }
+        /* Handle the B-frames: coded order */
+        for (int i = lastNonB+1; i < curNonB; i++, idx++)
+        {
+            frames[nextNonB]->plannedSatd[idx] = x265VbvFrameCost(frames, lastNonB, curNonB, i);
+            frames[nextNonB]->plannedType[idx] = X265_TYPE_B;
+
+            prevFrame = frames[i];
+            prevFrameIdx = idx;
+        }
+        lastNonB = curNonB;
+        curNonB++;
+        while (curNonB <= numFrames && frames[curNonB]->sliceType == X265_TYPE_B)
+            curNonB++;
+    }
+    frames[nextNonB]->plannedType[idx] = X265_TYPE_AUTO;
+}
+
+int64_t Lookahead::x265VbvFrameCost(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 vbvLookahead = cfg->param.rc.vbvBufferSize && cfg->param.rc.lookahead;
     if (!lastNonB)
         return;
 
@@ -403,7 +455,9 @@
     keyintLimit = cfg->param.keyframeMax - frames[0]->frameNum + lastKeyframe - 1;
     origNumFrames = numFrames = X265_MIN(framecnt, keyintLimit);
 
-    if (cfg->param.bOpenGOP && numFrames < framecnt)
+    if (vbvLookahead)
+        numFrames = framecnt;
+    else if (cfg->param.bOpenGOP && numFrames < framecnt)
         numFrames++;
     else if (numFrames == 0)
     {
@@ -538,6 +592,9 @@
         resetStart = X265_MIN(resetStart, j + 1);
     }
 
+        if (vbvLookahead)
+        x265VbvLookahead(frames, numFrames, bKeyframe);
+
     /* Restore frametypes for all frames that haven't actually been decided yet. */
     for (int j = resetStart; j <= numFrames; j++)
     {
diff -r cd078d0dc027 -r 49ef320ebb35 source/encoder/slicetype.h
--- a/source/encoder/slicetype.h	Tue Feb 11 13:06:43 2014 +0530
+++ b/source/encoder/slicetype.h	Tue Feb 11 15:50:33 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 x265VbvFrameCost(Lowres **frames, int p0, int p1, int b);
+    void x265VbvLookahead(Lowres **frames, int numFrames, int keyframes);
 
     /* called by slicetypeAnalyse() to effect cuTree adjustments to adaptive
      * quant offsets */
diff -r cd078d0dc027 -r 49ef320ebb35 source/x265.h
--- a/source/x265.h	Tue Feb 11 13:06:43 2014 +0530
+++ b/source/x265.h	Tue Feb 11 15:50:33 2014 +0530
@@ -622,6 +622,8 @@
          * across frames and assigns more bits to these CUs. Improves encode efficiency.
          * Default: OFF (0) */
         int       cuTree;
+
+        int       lookahead;
     } rc;
 } x265_param;
 


More information about the x265-devel mailing list