[x265] [PATCH 5 of 6] vbv: implement row wise vbvRateControl at each row diagonal

aarthi at multicorewareinc.com aarthi at multicorewareinc.com
Thu Feb 20 14:25:47 CET 2014


# HG changeset patch
# User Aarthi Thirumalai
# Date 1392900828 -19800
#      Thu Feb 20 18:23:48 2014 +0530
# Node ID 49b90667f050a7dd9c28b5017f389f5c29a1c191
# Parent  c5c07a3ee7fcf0f331f06f83b7b3bc0b1bcc1668
vbv: implement row wise vbvRateControl at each row diagonal.

diff -r c5c07a3ee7fc -r 49b90667f050 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Thu Feb 20 18:09:53 2014 +0530
+++ b/source/encoder/ratecontrol.cpp	Thu Feb 20 18:23:48 2014 +0530
@@ -221,6 +221,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;
@@ -230,6 +234,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
@@ -760,6 +773,181 @@
     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 sliceType = 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 (sliceType != I_SLICE)
+            {
+                for (uint32_t cuAddr = pic->m_numEncodedCusPerRow[row] + 1; cuAddr < pic->getPicSym()->getFrameWidthInCU() * (row + 1); 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 (sliceType == I_SLICE || qScale >= refQScale)
+            {
+                if (sliceType == P_SLICE
+                    && refPic->getSlice()->getSliceType() == sliceType
+                    && 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)
+{
+    fprintf(fp,"\n poc :%d , type : %d , slice Qp : %d , row : %d , startvbv : %f ", pic->getPOC(), rce->sliceType, pic->getSlice()->getSliceQp(), row, qpVbv);
+    if (rce->poc == 24)
+    {
+        int i=0; i++;
+    }
+    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;
+    if (bufferLeftPlanned < 0 )
+    { int i=0; i ++;
+    }
+    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);
+            fprintf(fp,", endvbv : %f ", qpVbv);
+            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;
+            fprintf(fp,", endvbv : %f ", qpVbv);
+            return -1;
+        }
+    }
+    fprintf(fp,", endvbv : %f ", qpVbv);
+    return 0;
+}
+
+
 /* modify the bitrate curve from pass1 for one frame */
 double RateControl::getQScale(RateControlEntry *rce, double rateFactor)
 {
diff -r c5c07a3ee7fc -r 49b90667f050 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h	Thu Feb 20 18:09:53 2014 +0530
+++ b/source/encoder/ratecontrol.h	Thu Feb 20 18:23:48 2014 +0530
@@ -92,6 +92,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;
@@ -129,6 +130,7 @@
     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:
 
@@ -143,6 +145,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);
 };
 }
 


More information about the x265-devel mailing list