[x265] [PATCH 2 of 2] rc: fix tune grain to adapt to scene changes and preserve quality

aarthi at multicorewareinc.com aarthi at multicorewareinc.com
Fri Mar 4 14:44:20 CET 2016


# HG changeset patch
# User Aarthi Thirumalai
# Date 1454673880 -19800
#      Fri Feb 05 17:34:40 2016 +0530
# Node ID 811fb256d70db1816f4b011fcac387f9b4498c64
# Parent  e31a161a481e1fb97e06efce4af5886e74308298
rc: fix tune grain to adapt to scene changes and preserve quality

diff -r e31a161a481e -r 811fb256d70d source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp	Fri Mar 04 11:12:38 2016 +0530
+++ b/source/encoder/ratecontrol.cpp	Fri Feb 05 17:34:40 2016 +0530
@@ -297,7 +297,7 @@
     /* Adjust the first frame in order to stabilize the quality level compared to the rest */
 #define ABR_INIT_QP_MIN (24)
 #define ABR_INIT_QP_MAX (40)
-#define ABR_INIT_QP_GRAIN_MAX (32)
+#define ABR_INIT_QP_GRAIN_MAX (33)
 #define ABR_SCENECUT_INIT_QP_MIN (12)
 #define CRF_INIT_QP (int)m_param->rc.rfConstant
     for (int i = 0; i < 3; i++)
@@ -378,9 +378,12 @@
     m_isPatternPresent = false;
     m_numBframesInPattern = 0;
 
-        m_isGrainEnabled = false;
-        if(m_param->rc.bEnableGrain) // tune for grainy content OR equal p-b frame sizes
-        m_isGrainEnabled = true;
+    m_isGrainEnabled = false;
+    if(m_param->rc.bEnableGrain) // tune for grainy content OR equal p-b frame sizes
+    m_isGrainEnabled = true;
+    for (int i = 0; i < 3; i++)
+    m_lastQScaleFor[i] = x265_qp2qScale(m_param->rc.rateControlMode == X265_RC_CRF ? CRF_INIT_QP : ABR_INIT_QP_MIN);
+    m_avgPFrameQp = 0 ;
 
     /* 720p videos seem to be a good cutoff for cplxrSum */
     double tuneCplxFactor = (m_ncu > 3600 && m_param->rc.cuTree) ? 2.5 : m_isGrainEnabled ? 1.9 : 1;
@@ -1493,17 +1496,17 @@
 
 double RateControl::tuneQScaleForGrain(double rcOverflow)
 {
-    double qpstepBy1 = pow(2, 0.5 / 6.0);
+    double qpstep = rcOverflow > 1.1 ? rcOverflow : m_lstep;
     double qScaleAvg = x265_qp2qScale(m_avgPFrameQp);
     double  q = m_lastQScaleFor[P_SLICE];
     int curQp = int (x265_qScale2qp(m_lastQScaleFor[P_SLICE]) + 0.5);
     double curBitrate = m_qpToEncodedBits[curQp] * int(m_fps + 0.5);
-    int newQp = rcOverflow > 1 ? curQp + 1 : curQp - 1 ;
+    int newQp = rcOverflow > 1.1 ? curQp + 2 : rcOverflow > 1 ? curQp + 1 : curQp - 1 ;
     double projectedBitrate =  int(m_fps + 0.5) * m_qpToEncodedBits[newQp];
     if (curBitrate > 0 && projectedBitrate > 0)
         q =  abs(projectedBitrate - m_bitrate) < abs (curBitrate - m_bitrate) ? x265_qp2qScale(newQp) : m_lastQScaleFor[P_SLICE];
     else
-        q = rcOverflow > 1 ? qScaleAvg * qpstepBy1 : rcOverflow < 1 ?  qScaleAvg / qpstepBy1 : m_lastQScaleFor[P_SLICE];
+        q = rcOverflow > 1 ? qScaleAvg * qpstep : rcOverflow < 1 ?  qScaleAvg / qpstep : m_lastQScaleFor[P_SLICE];
     return q;
 }
 
@@ -1651,7 +1654,14 @@
 
         rce->newQScale = qScale;
         if(rce->bLastMiniGopBFrame)
+        {
+            if (m_isFirstMiniGop && m_isGrainEnabled)
+            {
+                m_avgPFrameQp = (m_avgPFrameQp + rce->qpNoVbv) / 2;
+                m_lastQScaleFor[P_SLICE] = x265_qp2qScale(m_avgPFrameQp);
+            }
             m_isFirstMiniGop = false;
+        }
         return qScale;
     }
     else
@@ -1751,10 +1761,13 @@
                 bool isEncodeEnd = (m_param->totalFrames && 
                     m_framesDone > 0.75 * m_param->totalFrames) ? 1 : 0;
                 bool isEncodeBeg = m_framesDone < (int)(m_fps + 0.5);
-                if(m_isGrainEnabled && m_sliceType!= I_SLICE && !isEncodeEnd &&
-                    ((overflow < 1.05 && overflow > 0.95) || isEncodeBeg))
+                if (m_isGrainEnabled)
                 {
-                    q = tuneQScaleForGrain(overflow);
+                    if(m_sliceType!= I_SLICE && m_framesDone && !isEncodeEnd &&
+                        ((overflow < 1.05 && overflow > 0.95) || isEncodeBeg))
+                    {
+                        q = tuneQScaleForGrain(overflow);
+                    }
                 }
             }
             if (m_sliceType == I_SLICE && m_param->keyframeMax > 1
@@ -1771,7 +1784,7 @@
                 {
                     lqmin = m_lastQScaleFor[m_sliceType] / m_lstep;
                     lqmax = m_lastQScaleFor[m_sliceType] * m_lstep;
-                    if (!m_partialResidualFrames)
+                    if (!m_partialResidualFrames || m_isGrainEnabled)
                     {
                         if (overflow > 1.1 && m_framesDone > 3)
                             lqmax *= m_lstep;
@@ -1788,18 +1801,9 @@
             else if (m_framesDone == 0 && !m_isVbv && m_param->rc.rateControlMode == X265_RC_ABR)
             {
                 /* for ABR alone, clip the first I frame qp */
-                if (m_isGrainEnabled)
-                {
-                    /* to maintain grain uniformity, set I frame qp in a fixed range */
-                    lqmax = x265_qp2qScale(ABR_INIT_QP_GRAIN_MAX) * (m_lstep * m_lstep);
-                    lqmin = x265_qp2qScale(ABR_INIT_QP_GRAIN_MAX) / (m_lstep * m_lstep);
-                    q = x265_clip3(lqmin, lqmax, q);
-                }
-                else
-                {
-                    lqmax = x265_qp2qScale(ABR_INIT_QP_MAX) * m_lstep;
+                    lqmax =  m_lstep * m_isGrainEnabled ? x265_qp2qScale(ABR_INIT_QP_GRAIN_MAX) :
+                        x265_qp2qScale(ABR_INIT_QP_MAX);
                     q = X265_MIN(lqmax, q);
-                }
             }
             q = x265_clip3(MIN_QPSCALE, MAX_MAX_QPSCALE, q);
             /* Set a min qp at scenechanges and transitions */


More information about the x265-devel mailing list