[x265] [PATCH] Add dynamic rate-control reconfiguration

aruna at multicorewareinc.com aruna at multicorewareinc.com
Tue Apr 4 15:04:24 CEST 2017


# HG changeset patch
# User Aruna Matheswaran <aruna at multicorewareinc.com>
# Date 1487757265 -19800
#      Wed Feb 22 15:24:25 2017 +0530
# Node ID 576ad673d9b352c45853b7ffeeacce7d23268bb8
# Parent  08a05ca9fd16c9f5efb1ce4d8389bda8a63f5f7d
Add dynamic rate-control reconfiguration

diff -r 08a05ca9fd16 -r 576ad673d9b3 source/common/frame.cpp
--- a/source/common/frame.cpp	Mon Mar 27 12:35:20 2017 +0530
+++ b/source/common/frame.cpp	Wed Feb 22 15:24:25 2017 +0530
@@ -47,6 +47,7 @@
     memset(&m_lowres, 0, sizeof(m_lowres));
     m_rcData = NULL;
     m_encodeStartTime = 0;
+    m_reconfigureRc = false;
 }
 
 bool Frame::create(x265_param *param, float* quantOffsets)
diff -r 08a05ca9fd16 -r 576ad673d9b3 source/common/frame.h
--- a/source/common/frame.h	Mon Mar 27 12:35:20 2017 +0530
+++ b/source/common/frame.h	Wed Feb 22 15:24:25 2017 +0530
@@ -84,6 +84,7 @@
     Lowres                 m_lowres;
     bool                   m_lowresInit;         // lowres init complete (pre-analysis)
     bool                   m_bChromaExtended;    // orig chroma planes motion extended for weight analysis
+    bool                   m_reconfigureRc;
 
     float*                 m_quantOffsets;       // points to quantOffsets in x265_picture
     x265_sei               m_userSEI;
diff -r 08a05ca9fd16 -r 576ad673d9b3 source/encoder/api.cpp
--- a/source/encoder/api.cpp	Mon Mar 27 12:35:20 2017 +0530
+++ b/source/encoder/api.cpp	Wed Feb 22 15:24:25 2017 +0530
@@ -171,7 +171,7 @@
 
     x265_param save;
     Encoder* encoder = static_cast<Encoder*>(enc);
-    if (encoder->m_reconfigure) /* Reconfigure in progress */
+    if (encoder->m_reconfigure || encoder->m_reconfigureRc) /* Reconfigure in progress */
         return 1;
     memcpy(&save, encoder->m_latestParam, sizeof(x265_param));
     int ret = encoder->reconfigureParam(encoder->m_latestParam, param_in);
@@ -197,7 +197,22 @@
                 return -1;
             }
         }
-        encoder->m_reconfigure = true;
+        if (encoder->m_reconfigureRc)
+        {
+            VPS saveVPS;
+            memcpy(&saveVPS.ptl, &encoder->m_vps.ptl, sizeof(saveVPS.ptl));
+            determineLevel(*encoder->m_latestParam, encoder->m_vps);
+            if (saveVPS.ptl.profileIdc != encoder->m_vps.ptl.profileIdc || saveVPS.ptl.levelIdc != encoder->m_vps.ptl.levelIdc
+                || saveVPS.ptl.tierFlag != encoder->m_vps.ptl.tierFlag)
+            {
+                x265_log(encoder->m_param, X265_LOG_WARNING, "Profile/Level/Tier has changed from %d/%d/%s to %d/%d/%s.Cannot reconfigure rate-control.\n",
+                         saveVPS.ptl.profileIdc, saveVPS.ptl.levelIdc, saveVPS.ptl.tierFlag ? "High" : "Main", encoder->m_vps.ptl.profileIdc,
+                         encoder->m_vps.ptl.levelIdc, encoder->m_vps.ptl.tierFlag ? "High" : "Main");
+                encoder->m_reconfigureRc = false;
+            }
+        }
+        else
+            encoder->m_reconfigure = true;
         encoder->printReconfigureParams();
     }
     return ret;
diff -r 08a05ca9fd16 -r 576ad673d9b3 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Mon Mar 27 12:35:20 2017 +0530
+++ b/source/encoder/encoder.cpp	Wed Feb 22 15:24:25 2017 +0530
@@ -56,6 +56,7 @@
 {
     m_aborted = false;
     m_reconfigure = false;
+    m_reconfigureRc = false;
     m_encodedFrameNum = 0;
     m_pocLast = -1;
     m_curEncoder = 0;
@@ -607,7 +608,7 @@
         {
             inFrame = new Frame;
             inFrame->m_encodeStartTime = x265_mdate();
-            x265_param* p = m_reconfigure ? m_latestParam : m_param;
+            x265_param* p = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;
             if (inFrame->create(p, pic_in->quantOffsets))
             {
                 /* the first PicYuv created is asked to generate the CU and block unit offset
@@ -674,7 +675,7 @@
         inFrame->m_userData  = pic_in->userData;
         inFrame->m_pts       = pic_in->pts;
         inFrame->m_forceqp   = pic_in->forceqp;
-        inFrame->m_param     = m_reconfigure ? m_latestParam : m_param;
+        inFrame->m_param     = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param;
 
         if (pic_in->userSEI.numPayloads)
         {
@@ -740,6 +741,8 @@
             inFrame->m_lowres.bScenecut = !!inFrame->m_analysisData.bScenecut;
             inFrame->m_lowres.satdCost = inFrame->m_analysisData.satdCost;
         }
+        if (m_reconfigureRc)
+            inFrame->m_reconfigureRc = true;
 
         m_lookahead->addPicture(*inFrame, sliceType);
         m_numDelayedPic++;
@@ -940,6 +943,15 @@
                 if (m_param->rc.bStatRead)
                     readAnalysis2PassFile(&frameEnc->m_analysis2Pass, frameEnc->m_poc, frameEnc->m_lowres.sliceType);
              }
+
+            if (frameEnc->m_reconfigureRc && m_reconfigureRc)
+            {
+                memcpy(m_param, m_latestParam, sizeof(x265_param));
+                m_rateControl->reconfigureRC();
+                m_reconfigureRc = false;
+            }
+            if (frameEnc->m_reconfigureRc && !m_reconfigureRc)
+                frameEnc->m_reconfigureRc = false;
             if (curEncoder->m_reconfigure)
             {
                 /* One round robin cycle of FE reconfigure is complete */
@@ -1090,6 +1102,25 @@
     encParam->bIntraInBFrames = param->bIntraInBFrames;
     if (param->scalingLists && !encParam->scalingLists)
         encParam->scalingLists = strdup(param->scalingLists);
+    /* VBV can't be turned ON if it wasn't ON to begin with */
+    if (param->rc.vbvMaxBitrate > 0 && param->rc.vbvBufferSize > 0 &&
+        encParam->rc.vbvMaxBitrate > 0 && encParam->rc.vbvBufferSize > 0)
+    {
+        m_reconfigureRc |= encParam->rc.vbvMaxBitrate != param->rc.vbvMaxBitrate;
+        m_reconfigureRc |= encParam->rc.vbvBufferSize != param->rc.vbvBufferSize;
+        if (m_reconfigureRc && m_param->bEmitHRDSEI)
+            x265_log(m_param, X265_LOG_WARNING, "VBV parameters cannot be changed when HRD is in use.\n");
+        else
+        {
+            encParam->rc.vbvMaxBitrate = param->rc.vbvMaxBitrate;
+            encParam->rc.vbvBufferSize = param->rc.vbvBufferSize;
+        }
+    }
+    m_reconfigureRc |= encParam->rc.bitrate != param->rc.bitrate;
+    encParam->rc.bitrate = param->rc.bitrate;
+    m_reconfigureRc |= encParam->rc.rfConstant != param->rc.rfConstant;
+    encParam->rc.rfConstant = param->rc.rfConstant; 
+
     /* To add: Loop Filter/deblocking controls, transform skip, signhide require PPS to be resent */
     /* To add: SAO, temporal MVP, AMP, TU depths require SPS to be resent, at every CVS boundary */
     return x265_check_params(encParam);
@@ -3090,7 +3121,7 @@
 
 void Encoder::printReconfigureParams()
 {
-    if (!m_reconfigure)
+    if (!(m_reconfigure || m_reconfigureRc))
         return;
     x265_param* oldParam = m_param;
     x265_param* newParam = m_latestParam;
@@ -3112,6 +3143,10 @@
     TOOLCMP(oldParam->maxNumMergeCand, newParam->maxNumMergeCand, "max-merge=%d to %d\n");
     TOOLCMP(oldParam->bIntraInBFrames, newParam->bIntraInBFrames, "b-intra=%d to %d\n");
     TOOLCMP(oldParam->scalingLists, newParam->scalingLists, "scalinglists=%s to %s\n");
+    TOOLCMP(oldParam->rc.vbvMaxBitrate, newParam->rc.vbvMaxBitrate, "vbv-maxrate=%d to %d\n");
+    TOOLCMP(oldParam->rc.vbvBufferSize, newParam->rc.vbvBufferSize, "vbv-bufsize=%d to %d\n");
+    TOOLCMP(oldParam->rc.bitrate, newParam->rc.bitrate, "bitrate=%d to %d\n");
+    TOOLCMP(oldParam->rc.rfConstant, newParam->rc.rfConstant, "crf=%f to %f\n");
 }
 
 bool Encoder::computeSPSRPSIndex()
diff -r 08a05ca9fd16 -r 576ad673d9b3 source/encoder/encoder.h
--- a/source/encoder/encoder.h	Mon Mar 27 12:35:20 2017 +0530
+++ b/source/encoder/encoder.h	Wed Feb 22 15:24:25 2017 +0530
@@ -153,6 +153,7 @@
     bool               m_bZeroLatency;     // x265_encoder_encode() returns NALs for the input picture, zero lag
     bool               m_aborted;          // fatal error detected
     bool               m_reconfigure;      // Encoder reconfigure in progress
+    bool               m_reconfigureRc;
 
     /* Begin intra refresh when one not in progress or else begin one as soon as the current 
      * one is done. Requires bIntraRefresh to be set.*/
diff -r 08a05ca9fd16 -r 576ad673d9b3 source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Mon Mar 27 12:35:20 2017 +0530
+++ b/source/encoder/ratecontrol.cpp	Wed Feb 22 15:24:25 2017 +0530
@@ -683,6 +683,56 @@
     return true;
 }
 
+void RateControl::reconfigureRC()
+{
+    if (m_isVbv)
+    {
+        m_param->rc.vbvBufferSize = x265_clip3(0, 2000000, m_param->rc.vbvBufferSize);
+        m_param->rc.vbvMaxBitrate = x265_clip3(0, 2000000, m_param->rc.vbvMaxBitrate);
+        if (m_param->rc.vbvMaxBitrate < m_param->rc.bitrate &&
+            m_param->rc.rateControlMode == X265_RC_ABR)
+        {
+            x265_log(m_param, X265_LOG_WARNING, "max bitrate less than average bitrate, assuming CBR\n");
+            m_param->rc.bitrate = m_param->rc.vbvMaxBitrate;
+        }
+
+        if (m_param->rc.vbvBufferSize < (int)(m_param->rc.vbvMaxBitrate / m_fps))
+        {
+            m_param->rc.vbvBufferSize = (int)(m_param->rc.vbvMaxBitrate / m_fps);
+            x265_log(m_param, X265_LOG_WARNING, "VBV buffer size cannot be smaller than one frame, using %d kbit\n",
+                m_param->rc.vbvBufferSize);
+        }
+        int vbvBufferSize = m_param->rc.vbvBufferSize * 1000;
+        int vbvMaxBitrate = m_param->rc.vbvMaxBitrate * 1000;
+        m_bufferRate = vbvMaxBitrate / m_fps;
+        m_vbvMaxRate = vbvMaxBitrate;
+        m_bufferSize = vbvBufferSize;
+        m_singleFrameVbv = m_bufferRate * 1.1 > m_bufferSize;
+    }
+    if (m_param->rc.rateControlMode == X265_RC_CRF)
+    {
+        #define CRF_INIT_QP (int)m_param->rc.rfConstant
+        m_param->rc.bitrate = 0;
+        double baseCplx = m_ncu * (m_param->bframes ? 120 : 80);
+        double mbtree_offset = m_param->rc.cuTree ? (1.0 - m_param->rc.qCompress) * 13.5 : 0;
+        m_rateFactorConstant = pow(baseCplx, 1 - m_qCompress) /
+            x265_qp2qScale(m_param->rc.rfConstant + mbtree_offset);
+        if (m_param->rc.rfConstantMax)
+        {
+            m_rateFactorMaxIncrement = m_param->rc.rfConstantMax - m_param->rc.rfConstant;
+            if (m_rateFactorMaxIncrement <= 0)
+            {
+                x265_log(m_param, X265_LOG_WARNING, "CRF max must be greater than CRF\n");
+                m_rateFactorMaxIncrement = 0;
+            }
+        }
+        if (m_param->rc.rfConstantMin)
+            m_rateFactorMaxDecrement = m_param->rc.rfConstant - m_param->rc.rfConstantMin;
+    }
+    m_bitrate = m_param->rc.bitrate * 1000;
+}
+
+
 void RateControl::initHRD(SPS& sps)
 {
     int vbvBufferSize = m_param->rc.vbvBufferSize * 1000;
diff -r 08a05ca9fd16 -r 576ad673d9b3 source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h	Mon Mar 27 12:35:20 2017 +0530
+++ b/source/encoder/ratecontrol.h	Wed Feb 22 15:24:25 2017 +0530
@@ -234,6 +234,7 @@
     RateControl(x265_param& p);
     bool init(const SPS& sps);
     void initHRD(SPS& sps);
+    void reconfigureRC();
 
     void setFinalFrameCount(int count);
     void terminate();          /* un-block all waiting functions so encoder may close */


More information about the x265-devel mailing list