[x265] [PATCH] Basic support for tweaking rate control using zones

Adam Marcus adampetermarcus at gmail.com
Mon Dec 22 01:39:54 CET 2014


# HG changeset patch
# User amarcu5 <adampetermarcus at gmail.com>
# Date 1419207231 0
# Node ID 188f80215b37a34289f4124614bf66211fe63314
# Parent  8d2f418829c894c25da79daa861f16c61e5060d7
Support for tweaking rate control using zones

diff --git a/source/common/param.cpp b/source/common/param.cpp
--- a/source/common/param.cpp
+++ b/source/common/param.cpp
@@ -205,6 +205,8 @@
     param->rc.statFileName = NULL;
     param->rc.complexityBlur = 20;
     param->rc.qblur = 0.5;
+    param->rc.zoneCount = 0;
+    param->rc.zones = NULL;
     param->rc.bEnableSlowFirstPass = 0;
 
     /* Video Usability Information (VUI) */
@@ -694,6 +696,35 @@
         p->rc.qp = atoi(value);
         p->rc.rateControlMode = X265_RC_CQP;
     }
+    OPT("zones")
+    {
+        p->rc.zoneCount = 1;
+        const char* c;
+        for (c = value; *c; c++) {
+            p->rc.zoneCount += (*c == '/');
+        }
+        p->rc.zones = X265_MALLOC(x265_zone, p->rc.zoneCount);
+        c = value;
+        for (int i = 0; i < p->rc.zoneCount; i++ )
+        {
+            int len;
+            if (3 == sscanf(c, "%d,%d,q=%d%n", &p->rc.zones[i].startFrame, &p->rc.zones[i].endFrame, &p->rc.zones[i].qp, &len))
+            {
+                p->rc.zones[i].bForceQp = 1;
+            }
+            else if (3 == sscanf(c, "%d,%d,b=%f%n", &p->rc.zones[i].startFrame, &p->rc.zones[i].endFrame, &p->rc.zones[i].bitrateFactor, &len))
+            {
+                p->rc.zones[i].bForceQp = 0;
+            }
+            else
+            {
+                bError = true;
+                break;
+            }
+            c += len + 1;
+        }
+        
+    }
     OPT("input-res") bError |= sscanf(value, "%dx%d", &p->sourceWidth, &p->sourceHeight) != 2;
     OPT("input-csp") p->internalCsp = parseName(value, x265_source_csp_names, bError);
     OPT("me")        p->searchMethod = parseName(value, x265_motion_est_names, bError);
diff --git a/source/encoder/ratecontrol.cpp b/source/encoder/ratecontrol.cpp
--- a/source/encoder/ratecontrol.cpp
+++ b/source/encoder/ratecontrol.cpp
@@ -169,6 +169,18 @@
         return acEnergyVar(curFrame, primitives.var[BLOCK_16x16](src, srcStride), 8, bChroma);
 }
 
+/* Returns the zone for the current frame */
+x265_zone* RateControl::getZone()
+{
+    for (int i = m_param->rc.zoneCount - 1; i >= 0; i--)
+    {
+        x265_zone *z = &m_param->rc.zones[i];
+        if (m_framesDone + 1 >= z->startFrame && m_framesDone < z->endFrame)
+            return z;
+    }
+    return NULL;
+}
+
 /* Find the total AC energy of each block in all planes */
 uint32_t RateControl::acEnergyCu(Frame* curFrame, uint32_t block_x, uint32_t block_y)
 {
@@ -1153,6 +1165,15 @@
         else
             m_qp = m_qpConstant[m_sliceType];
         curEncData.m_avgQpAq = curEncData.m_avgQpRc = m_qp;
+        
+        x265_zone* zone = getZone();
+        if (zone)
+        {
+            if (zone->bForceQp)
+                m_qp += zone->qp - m_qpConstant[P_SLICE];
+            else
+                m_qp -= 6.0 * X265_LOG2(zone->bitrateFactor);
+        }
     }
     if (m_sliceType != B_SLICE)
     {
@@ -1242,6 +1263,14 @@
         m_accumPNorm = mask * (1 + m_accumPNorm);
     }
 
+    x265_zone* zone = getZone();
+    if (zone)
+    {
+        if (zone->bForceQp)
+            q = x265_qp2qScale(zone->qp);
+        else
+            q /= zone->bitrateFactor;
+    }
     return q;
 }
 
@@ -2071,6 +2100,15 @@
         m_lastRceq = q;
         q /= rateFactor;
     }
+    
+    x265_zone* zone = getZone();
+    if (zone)
+    {
+        if (zone->bForceQp)
+            q = x265_qp2qScale(zone->qp);
+        else
+            q /= zone->bitrateFactor;
+    }
     return q;
 }
 
@@ -2361,5 +2399,7 @@
     X265_FREE(m_rce2Pass);
     for (int i = 0; i < 2; i++)
         X265_FREE(m_cuTreeStats.qpBuffer[i]);
+    
+    X265_FREE(m_param->rc.zones);
 }
 
diff --git a/source/encoder/ratecontrol.h b/source/encoder/ratecontrol.h
--- a/source/encoder/ratecontrol.h
+++ b/source/encoder/ratecontrol.h
@@ -247,6 +247,7 @@
     int m_amortizeFrames;
     double m_amortizeFraction;
 
+    x265_zone* getZone();
     double getQScale(RateControlEntry *rce, double rateFactor);
     double rateEstimateQscale(Frame* pic, RateControlEntry *rce); // main logic for calculating QP based on ABR
     void accumPQpUpdate();
diff --git a/source/x265.cpp b/source/x265.cpp
--- a/source/x265.cpp
+++ b/source/x265.cpp
@@ -150,6 +150,7 @@
     { "vbv-init",       required_argument, NULL, 0 },
     { "bitrate",        required_argument, NULL, 0 },
     { "qp",             required_argument, NULL, 'q' },
+    { "zones",          required_argument, NULL, 0 },
     { "aq-mode",        required_argument, NULL, 0 },
     { "aq-strength",    required_argument, NULL, 0 },
     { "ipratio",        required_argument, NULL, 0 },
@@ -435,6 +436,12 @@
     H0("   --b-adapt <0..2>              0 - none, 1 - fast, 2 - full (trellis) adaptive B frame scheduling. Default %d\n", param->bFrameAdaptive);
     H0("   --[no-]b-pyramid              Use B-frames as references. Default %s\n", OPT(param->bBPyramid));
     H0("   --ref <integer>               max number of L0 references to be allowed (1 .. 16) Default %d\n", param->maxNumReferences);
+    H1("   --zones <zone0>/<zone1>/...   Tweak the bitrate of regions of the video\n");
+    H1("                                 Each zone is of the form\n");
+    H1("                                   <start frame>,<end frame>,<option>\n");
+    H1("                                   where <option> is either\n");
+    H1("                                       q=<integer> (force QP)\n");
+    H1("                                   or  b=<float> (bitrate multiplier)\n");
     H1("   --qpfile <string>             Force frametypes and QPs for some or all frames\n");
     H1("                                 Format of each line: framenumber frametype QP\n");
     H1("                                 QP is optional (none lets x265 choose). Frametypes: I,i,P,B,b.\n");
diff --git a/source/x265.h b/source/x265.h
--- a/source/x265.h
+++ b/source/x265.h
@@ -328,6 +328,16 @@
 static const char * const x265_interlace_names[] = { "prog", "tff", "bff", 0 };
 static const char * const x265_analysis_names[] = { "off", "save", "load", 0 };
 
+/* Zones: override ratecontrol for specific sections of the video.
+ * If zones overlap, whichever comes later in the list takes precedence. */
+typedef struct x265_zone
+{
+    int startFrame, endFrame;   /* range of frame numbers */
+    int bForceQp;               /* whether to use qp vs bitrate factor */
+    int qp;
+    float bitrateFactor;
+} x265_zone;
+    
 /* x265 input parameters
  *
  * For version safety you may use x265_param_alloc/free() to manage the
@@ -867,6 +877,10 @@
 
         /* Enable slow and a more detailed first pass encode in multi pass rate control */
         int       bEnableSlowFirstPass;
+        
+        /* ratecontrol overrides */
+        int        zoneCount;
+        x265_zone* zones;
 
         /* specify a text file which contains MAX_MAX_QP + 1 floating point
          * values to be copied into x265_lambda_tab and a second set of

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20141222/ee8bb982/attachment-0001.html>


More information about the x265-devel mailing list