[x265] [PATCH EXPERIMENTAL] api: make RDOQ level externally configurable, make two levels visible

Steve Borho steve at borho.org
Thu Feb 26 23:38:16 CET 2015


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1424990270 21600
#      Thu Feb 26 16:37:50 2015 -0600
# Node ID 6ca5304a89371341f5e1cd5888a3119a36e8e8f5
# Parent  394c2f94a2dc5d0e9e6d1c063361b19b86b88cf6
api: make RDOQ level externally configurable, make two levels visible

This commit doesn't change any preset defaults, but it does allow much more
flexibility - a user can chose to enable rdoq and psy-rdoq at fast presets if
they so chose. And in noisy situations a user may decide to lower rdoq level to
1 to reduce decimation (psy-rdoq is a blunt hammer for this purpose)

This commit does change --tune grain to use --rdoqLevel 1 so --tune grain will
be effective at all RD levels and avoids the coding group decimation logic
within RDOQ

diff -r 394c2f94a2dc -r 6ca5304a8937 doc/reST/cli.rst
--- a/doc/reST/cli.rst	Thu Feb 26 15:26:39 2015 -0600
+++ b/doc/reST/cli.rst	Thu Feb 26 16:37:50 2015 -0600
@@ -613,6 +613,28 @@
 Options which affect the transform unit quad-tree, sometimes referred to
 as the residual quad-tree (RQT).
 
+.. option:: --rdoq-level <0|1|2>, --no-rdoq-level
+
+	Specify the amount of rate-distortion analysis to use within
+	quantization::
+
+	At level 0 rate-distortion cost is not considered in quant
+	
+	At level 1 rate-distortion cost is used to find optimal rounding
+	values for each level (and allows psy-rdoq to be effective). It
+	trades-off the signaling cost of the coefficient vs its post-inverse
+	quant distortion from the pre-quant coefficient. When
+	:option:`--psy-rdoq` is enabled, this formula is biased in favor of
+	more energy in the residual (larger coefficient absolute levels)
+	
+	At level 2 rate-distortion cost is used to make decimate decisions
+	on each 4x4 coding group, including the cost of signaling the group
+	within the group bitmap. If the total distortion of not signaling
+	the entire coding group is less than the rate cost, the block is
+	decimated.  Psy-rdoq is less effective at preserving energy when
+	RDOQ is at level 2, since it only has influence over the level
+	distortion costs.
+
 .. option:: --tu-intra-depth <1..4>
 
 	The transform unit (residual) quad-tree begins with the same depth
@@ -829,8 +851,8 @@
 inter prediction.
 
 :option:`--psy-rdoq` will adjust the distortion cost used in
-rate-distortion optimized quantization (RDO quant), enabled in
-:option:`--rd` 4 and above, favoring the preservation of energy in the
+rate-distortion optimized quantization (RDO quant), enabled by
+:option:`--rdoq-level` 1 or 2, favoring the preservation of energy in the
 reconstructed image.  :option:`--psy-rdoq` prevents RDOQ from blurring
 all of the encoding options which psy-rd has to chose from.  At low
 strength levels, psy-rdoq will influence the quantization level
@@ -878,9 +900,8 @@
 	Influence rate distortion optimized quantization by favoring higher
 	energy in the reconstructed image. This generally improves perceived
 	visual quality at the cost of lower quality metric scores.  It only
-	has effect on slower presets which use RDO Quantization
-	(:option:`--rd` 4, 5 and 6). 1.0 is a typical value. High values can 
-	be beneficial in preserving high-frequency detail like film grain. 
+	has effect when :option:`--rdoq-level` is 1 or 2. High values can
+	be beneficial in preserving high-frequency detail like film grain.
 	Default: 1.0
 
 	**Range of values:** 0 .. 50.0
diff -r 394c2f94a2dc -r 6ca5304a8937 doc/reST/presets.rst
--- a/doc/reST/presets.rst	Thu Feb 26 15:26:39 2015 -0600
+++ b/doc/reST/presets.rst	Thu Feb 26 16:37:50 2015 -0600
@@ -66,6 +66,8 @@
 +--------------+-----------+-----------+----------+--------+------+--------+------+--------+----------+---------+
 | rdLevel      |    2      |     2     |    2     |   2    |  2   |    3   |  4   |   6    |    6     |    6    |
 +--------------+-----------+-----------+----------+--------+------+--------+------+--------+----------+---------+
+| rdoq-level   |    0      |     0     |    0     |   0    |  0   |    0   |  2   |   2    |    2     |    2    |
++--------------+-----------+-----------+----------+--------+------+--------+------+--------+----------+---------+
 | tu-intra     |    1      |     1     |    1     |   1    |  1   |    1   |  1   |   2    |    3     |    4    |
 +--------------+-----------+-----------+----------+--------+------+--------+------+--------+----------+---------+
 | tu-inter     |    1      |     1     |    1     |   1    |  1   |    1   |  1   |   2    |    3     |    4    |
@@ -114,13 +116,9 @@
 modes which preserve high frequency noise:
 
     * :option:`--psy-rd` 0.5
+    * :option:`--rdoq-level` 1
     * :option:`--psy-rdoq` 30
 
-.. Note::
-
-    --psy-rdoq is only effective when RDOQuant is enabled, which is at
-    RD levels 4, 5, and 6 (presets slow and below).
-
 It lowers the strength of adaptive quantization, so residual energy can
 be more evenly distributed across the (noisy) picture:
 
diff -r 394c2f94a2dc -r 6ca5304a8937 source/CMakeLists.txt
--- a/source/CMakeLists.txt	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/CMakeLists.txt	Thu Feb 26 16:37:50 2015 -0600
@@ -21,7 +21,7 @@
 include(CheckCXXCompilerFlag)
 
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 47)
+set(X265_BUILD 48)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r 394c2f94a2dc -r 6ca5304a8937 source/common/param.cpp
--- a/source/common/param.cpp	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/common/param.cpp	Thu Feb 26 16:37:50 2015 -0600
@@ -320,6 +320,7 @@
             param->bEnableRectInter = 1;
             param->lookaheadDepth = 25;
             param->rdLevel = 4;
+            param->rdoqLevel = 2;
             param->subpelRefine = 3;
             param->maxNumMergeCand = 3;
             param->searchMethod = X265_STAR_SEARCH;
@@ -334,6 +335,7 @@
             param->tuQTMaxInterDepth = 2;
             param->tuQTMaxIntraDepth = 2;
             param->rdLevel = 6;
+            param->rdoqLevel = 2;
             param->subpelRefine = 3;
             param->maxNumMergeCand = 3;
             param->searchMethod = X265_STAR_SEARCH;
@@ -349,6 +351,7 @@
             param->tuQTMaxInterDepth = 3;
             param->tuQTMaxIntraDepth = 3;
             param->rdLevel = 6;
+            param->rdoqLevel = 2;
             param->subpelRefine = 4;
             param->maxNumMergeCand = 4;
             param->searchMethod = X265_STAR_SEARCH;
@@ -366,6 +369,7 @@
             param->tuQTMaxInterDepth = 4;
             param->tuQTMaxIntraDepth = 4;
             param->rdLevel = 6;
+            param->rdoqLevel = 2;
             param->subpelRefine = 5;
             param->maxNumMergeCand = 5;
             param->searchMethod = X265_STAR_SEARCH;
@@ -416,6 +420,7 @@
             param->deblockingFilterBetaOffset = -2;
             param->deblockingFilterTCOffset = -2;
             param->bIntraInBFrames = 0;
+            param->rdoqLevel = 1;
             param->psyRdoq = 30;
             param->psyRd = 0.5;
             param->rc.ipFactor = 1.1;
@@ -629,6 +634,17 @@
     OPT("cbqpoffs") p->cbQpOffset = atoi(value);
     OPT("crqpoffs") p->crQpOffset = atoi(value);
     OPT("rd") p->rdLevel = atoi(value);
+    OPT2("rdoq", "rdoq-level")
+    {
+        int bval = atobool(value);
+        if (bError || bval)
+        {
+            bError = false;
+            p->rdoqLevel = atoi(value);
+        }
+        else
+            p->rdoqLevel = 0;
+    }
     OPT("psy-rd")
     {
         int bval = atobool(value);
@@ -1034,6 +1050,8 @@
           "Rate control mode is out of range");
     CHECK(param->rdLevel < 0 || param->rdLevel > 6,
           "RD Level is out of range");
+    CHECK(param->rdoqLevel < 0 || param->rdoqLevel > 2,
+        "RDOQ Level is out of range");
     CHECK(param->bframes > param->lookaheadDepth && !param->rc.bStatRead,
           "Lookahead depth must be greater than the max consecutive bframe count");
     CHECK(param->bframes < 0,
@@ -1251,7 +1269,7 @@
 #define TOOLOPT(FLAG, STR) if (FLAG) fprintf(stderr, "%s ", STR)
     TOOLOPT(param->bEnableRectInter, "rect");
     TOOLOPT(param->bEnableAMP, "amp");
-    fprintf(stderr, "rd=%d ", param->rdLevel);
+    fprintf(stderr, "rd=%d rdoq=%d ", param->rdLevel, param->rdoqLevel);
     if (param->psyRd > 0.)
         fprintf(stderr, "psy-rd=%.2lf ", param->psyRd);
     if (param->psyRdoq > 0.)
diff -r 394c2f94a2dc -r 6ca5304a8937 source/common/quant.cpp
--- a/source/common/quant.cpp	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/common/quant.cpp	Thu Feb 26 16:37:50 2015 -0600
@@ -194,12 +194,12 @@
     m_nr           = NULL;
 }
 
-bool Quant::init(bool useRDOQ, double psyScale, const ScalingList& scalingList, Entropy& entropy)
+bool Quant::init(int rdoqLevel, double psyScale, const ScalingList& scalingList, Entropy& entropy)
 {
     m_entropyCoder = &entropy;
-    m_useRDOQ = useRDOQ;
+    m_rdoqLevel    = rdoqLevel;
     m_psyRdoqScale = (int64_t)(psyScale * 256.0);
-    m_scalingList = &scalingList;
+    m_scalingList  = &scalingList;
     m_resiDctCoeff = X265_MALLOC(int16_t, MAX_TR_SIZE * MAX_TR_SIZE * 2);
     m_fencDctCoeff = m_resiDctCoeff + (MAX_TR_SIZE * MAX_TR_SIZE);
     m_fencShortBuf = X265_MALLOC(int16_t, MAX_TR_SIZE * MAX_TR_SIZE);
@@ -416,7 +416,7 @@
         }
     }
 
-    if (m_useRDOQ)
+    if (m_rdoqLevel)
         return rdoQuant(cu, coeff, log2TrSize, ttype, absPartIdx, usePsy);
     else
     {
@@ -825,7 +825,7 @@
             costCoeffGroupSig[cgScanPos] = SIGCOST(estBitsSbac.significantCoeffGroupBits[sigCtx][1]);
             totalRdCost += costCoeffGroupSig[cgScanPos];  /* add the cost of 1 bit in significant CG bitmap */
 
-            if (costZeroCG < totalRdCost)
+            if (costZeroCG < totalRdCost && m_rdoqLevel > 1)
             {
                 sigCoeffGroupFlag64 &= ~cgBlkPosMask;
                 totalRdCost = costZeroCG;
diff -r 394c2f94a2dc -r 6ca5304a8937 source/common/quant.h
--- a/source/common/quant.h	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/common/quant.h	Thu Feb 26 16:37:50 2015 -0600
@@ -81,7 +81,7 @@
 
     QpParam            m_qpParam[3];
 
-    bool               m_useRDOQ;
+    int                m_rdoqLevel;
     int64_t            m_psyRdoqScale;
     int16_t*           m_resiDctCoeff;
     int16_t*           m_fencDctCoeff;
@@ -99,7 +99,7 @@
     ~Quant();
 
     /* one-time setup */
-    bool init(bool useRDOQ, double psyScale, const ScalingList& scalingList, Entropy& entropy);
+    bool init(int rdoqLevel, double psyScale, const ScalingList& scalingList, Entropy& entropy);
     bool allocNoiseReduction(const x265_param& param);
 
     /* CU setup */
diff -r 394c2f94a2dc -r 6ca5304a8937 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/encoder/encoder.cpp	Thu Feb 26 16:37:50 2015 -0600
@@ -1555,12 +1555,12 @@
     }
     p->keyframeMin = X265_MAX(1, X265_MIN(p->keyframeMin, p->keyframeMax / 2 + 1));
 
-    if (p->bBPyramid && !p->bframes)
+    if (!p->bframes)
         p->bBPyramid = 0;
+    if (!p->rdoqLevel)
+        p->psyRdoq = 0;
 
     /* Disable features which are not supported by the current RD level */
-    if (p->rdLevel < 4)
-        p->psyRdoq = 0;                 /* impossible */
     if (p->rdLevel < 3)
     {
         if (p->bCULossless)             /* impossible */
diff -r 394c2f94a2dc -r 6ca5304a8937 source/encoder/search.cpp
--- a/source/encoder/search.cpp	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/encoder/search.cpp	Thu Feb 26 16:37:50 2015 -0600
@@ -72,14 +72,14 @@
 {
     uint32_t maxLog2CUSize = g_log2Size[param.maxCUSize];
     m_param = ¶m;
-    m_bEnableRDOQ = param.rdLevel >= 4;
+    m_bEnableRDOQ = !!param.rdoqLevel;
     m_bFrameParallel = param.frameNumThreads > 1;
     m_numLayers = g_log2Size[param.maxCUSize] - 2;
 
     m_rdCost.setPsyRdScale(param.psyRd);
     m_me.init(param.searchMethod, param.subpelRefine, param.internalCsp);
 
-    bool ok = m_quant.init(m_bEnableRDOQ, param.psyRdoq, scalingList, m_entropyCoder);
+    bool ok = m_quant.init(param.rdoqLevel, param.psyRdoq, scalingList, m_entropyCoder);
     if (m_param->noiseReductionIntra || m_param->noiseReductionInter)
         ok &= m_quant.allocNoiseReduction(param);
 
diff -r 394c2f94a2dc -r 6ca5304a8937 source/x265.h
--- a/source/x265.h	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/x265.h	Thu Feb 26 16:37:50 2015 -0600
@@ -660,6 +660,15 @@
      * compressed by the DCT transforms, at the expense of much more compute */
     uint32_t  tuQTMaxIntraDepth;
 
+    /* Set the amount of rate-distortion analysis to use within quant. 0 implies
+     * no rate-distortion optimization. At level 1 rate-distortion cost is used to
+     * find optimal rounding values for each level (and allows psy-rdoq to be
+     * enabled). At level 2 rate-distortion cost is used to make decimate decisions
+     * on each 4x4 coding group (including the cost of signaling the group within
+     * the group bitmap).  Psy-rdoq is less effective at preserving energy when
+     * RDOQ is at level 2 */
+    int       rdoqLevel;
+
     /* Enable the implicit signaling of the sign bit of the last coefficient of
      * each transform unit. This saves one bit per TU at the expense of figuring
      * out which coefficient can be toggled with the least distortion.
diff -r 394c2f94a2dc -r 6ca5304a8937 source/x265cli.h
--- a/source/x265cli.h	Thu Feb 26 15:26:39 2015 -0600
+++ b/source/x265cli.h	Thu Feb 26 16:37:50 2015 -0600
@@ -139,6 +139,8 @@
     { "cbqpoffs",       required_argument, NULL, 0 },
     { "crqpoffs",       required_argument, NULL, 0 },
     { "rd",             required_argument, NULL, 0 },
+    { "rdoq-level",     required_argument, NULL, 0 },
+    { "no-rdoq-level",        no_argument, NULL, 0 },
     { "psy-rd",         required_argument, NULL, 0 },
     { "psy-rdoq",       required_argument, NULL, 0 },
     { "no-psy-rd",            no_argument, NULL, 0 },
@@ -273,9 +275,10 @@
     H0("   --tu-intra-depth <integer>    Max TU recursive depth for intra CUs. Default %d\n", param->tuQTMaxIntraDepth);
     H0("   --tu-inter-depth <integer>    Max TU recursive depth for inter CUs. Default %d\n", param->tuQTMaxInterDepth);
     H0("\nAnalysis:\n");
-    H0("   --rd <0..6>                   Level of RD in mode decision 0:least....6:full RDO. Default %d\n", param->rdLevel);
+    H0("   --rd <0..6>                   Level of RDO in mode decision 0:least....6:full RDO. Default %d\n", param->rdLevel);
     H0("   --[no-]psy-rd <0..2.0>        Strength of psycho-visual rate distortion optimization, 0 to disable. Default %.1f\n", param->psyRd);
-    H0("   --[no-]psy-rdoq <0..50.0>     Strength of psycho-visual optimization in quantization, 0 to disable. Default %.1f\n", param->psyRdoq);
+    H0("   --[no-]rdoq-level <0|1|2>     Level of RDO in quantization 0:none, 1:levels, 2:levels & coding groups. Default %d\n", param->rdoqLevel);
+    H0("   --[no-]psy-rdoq <0..50.0>     Strength of psycho-visual optimization in RDO quantization, 0 to disable. Default %.1f\n", param->psyRdoq);
     H0("   --[no-]early-skip             Enable early SKIP detection. Default %s\n", OPT(param->bEnableEarlySkip));
     H1("   --[no-]tskip-fast             Enable fast intra transform skipping. Default %s\n", OPT(param->bEnableTSkipFast));
     H1("   --nr-intra <integer>          An integer value in range of 0 to 2000, which denotes strength of noise reduction in intra CUs. Default 0\n");


More information about the x265-devel mailing list