[x265] [PATCH] api: allow lambda tables to be user-specified via a text file

Steve Borho steve at borho.org
Thu Jul 3 00:22:06 CEST 2014


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1404339662 18000
#      Wed Jul 02 17:21:02 2014 -0500
# Node ID 6da77093c4b2db20dfafa7ff5994294ba3773f24
# Parent  b90fdc3ffb962ddd4baf1309a5d6ffa3908f0486
api: allow lambda tables to be user-specified via a text file

This change allows easy experimentation with the lambda tables. One can
cut-paste the existing tables from TComRom.cpp into a text file and hash(#)
comment the C constructs (variable names and braces) and arrive at a functional
lambda file, then edit to taste.

diff -r b90fdc3ffb96 -r 6da77093c4b2 doc/reST/cli.rst
--- a/doc/reST/cli.rst	Wed Jul 02 14:31:51 2014 -0500
+++ b/doc/reST/cli.rst	Wed Jul 02 17:21:02 2014 -0500
@@ -274,6 +274,26 @@
 	Specifying QP (integer) is optional, and if specified they are
 	clamped within the encoder to qpmin/qpmax.
 
+.. option:: --lambda-file <filename>
+
+	Specify a text file containing values for the x265_lambda_tab and
+	x265_lambda2_tab. Each table requires MAX_MAX_QP (69) float values
+	to be read from the file.
+	
+	The text file syntax is simple. Comma is considered to be
+	white-space. All white-space is ignored. Lines must be less than 2k
+	bytes in length. Content following hash (#) characters are ignored.
+	The values read from the file may are logged at
+	:option:`--log-level` debug.
+
+	Note that the lambda tables are process-global and so the new values
+	affect all encoders running in the same process. 
+	
+	Lambda values affect encoder mode decisions, the lower the lambda
+	the more bits it will try to spend on signaling information (motion
+	vectors and splits) and less on residual. This feature is intended
+	for experimentation.
+
 Quad-Tree analysis
 ==================
 
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/CMakeLists.txt
--- a/source/CMakeLists.txt	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/CMakeLists.txt	Wed Jul 02 17:21:02 2014 -0500
@@ -19,7 +19,7 @@
 include(CheckCXXCompilerFlag)
 
 # X265_BUILD must be incremented each time the public API is changed
-set(X265_BUILD 24)
+set(X265_BUILD 25)
 configure_file("${PROJECT_SOURCE_DIR}/x265.def.in"
                "${PROJECT_BINARY_DIR}/x265.def")
 configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in"
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/Lib/TLibCommon/TComRom.cpp
--- a/source/Lib/TLibCommon/TComRom.cpp	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/Lib/TLibCommon/TComRom.cpp	Wed Jul 02 17:21:02 2014 -0500
@@ -124,7 +124,7 @@
 };
 
 // lambda = pow(2, (double)q / 6 - 2);
-const double x265_lambda_tab[MAX_MAX_QP + 1] =
+double x265_lambda_tab[MAX_MAX_QP + 1] =
 {
     0.2500, 0.2806, 0.3150, 0.3536, 0.3969,
     0.4454, 0.5000, 0.5612, 0.6300, 0.7071,
@@ -143,7 +143,7 @@
 };
 
 // lambda2 = pow(lambda, 2) * scale (0.85);
-const double x265_lambda2_tab[MAX_MAX_QP + 1] =
+double x265_lambda2_tab[MAX_MAX_QP + 1] =
 {
     0.0531, 0.0669, 0.0843, 0.1063, 0.1339,
     0.1687, 0.2125, 0.2677, 0.3373, 0.4250,
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/Lib/TLibCommon/TComRom.h
--- a/source/Lib/TLibCommon/TComRom.h	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/Lib/TLibCommon/TComRom.h	Wed Jul 02 17:21:02 2014 -0500
@@ -270,8 +270,8 @@
 extern const int g_winUnitX[MAX_CHROMA_FORMAT_IDC + 1];
 extern const int g_winUnitY[MAX_CHROMA_FORMAT_IDC + 1];
 
-extern const double x265_lambda_tab[MAX_MAX_QP + 1];
-extern const double x265_lambda2_tab[MAX_MAX_QP + 1];
+extern double x265_lambda_tab[MAX_MAX_QP + 1];
+extern double x265_lambda2_tab[MAX_MAX_QP + 1];
 extern const uint16_t x265_chroma_lambda2_offset_tab[MAX_CHROMA_LAMBDA_OFFSET+1];
 
 // CABAC tables
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/common/param.cpp
--- a/source/common/param.cpp	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/common/param.cpp	Wed Jul 02 17:21:02 2014 -0500
@@ -31,6 +31,7 @@
 #if _MSC_VER
 #pragma warning(disable: 4996) // POSIX functions are just fine, thanks
 #pragma warning(disable: 4706) // assignment within conditional
+#pragma warning(disable: 4127) // conditional expression is constant
 #endif
 
 #if _WIN32
@@ -103,6 +104,7 @@
     param->frameNumThreads = 0;
     param->poolNumThreads = 0;
     param->csvfn = NULL;
+    param->rc.lambdaFileName = NULL;
     param->bLogCuStats = 0;
 
     /* Source specifications */
@@ -541,6 +543,7 @@
         }
     }
     OPT("csv") p->csvfn = value;
+    OPT("lambda-file") p->rc.lambdaFileName = value;
     OPT("threads") p->poolNumThreads = atoi(value);
     OPT("frame-threads") p->frameNumThreads = atoi(value);
     OPT2("level-idc", "level")
@@ -1288,4 +1291,61 @@
 #undef BOOL
     return buf;
 }
+
+void parseLambdaFile(x265_param *param)
+{
+    if (!param->rc.lambdaFileName)
+        return;
+
+    FILE *lfn = fopen(param->rc.lambdaFileName, "r");
+    if (!lfn)
+    {
+        x265_log(param, X265_LOG_WARNING, "unable to read lambda file <%s>\n", param->rc.lambdaFileName);
+        return;
+    }
+
+    char line[2048];
+    char *toksave, *tok = NULL, *buf;
+
+    for (int t = 0; t < 2; t++)
+    {
+        double *table = t ? x265_lambda2_tab : x265_lambda_tab;
+
+        for (int i = 0; i < MAX_MAX_QP + 1; i++)
+        {
+            double value;
+
+            do
+            {
+                if (!tok)
+                {
+                    /* consume a line of text file */
+                    if (!fgets(line, sizeof(line), lfn))
+                    {
+                        x265_log(param, X265_LOG_WARNING, "lambda file is incomplete\n");
+                        fclose(lfn);
+                        return;
+                    }
+
+                    /* truncate at first hash */
+                    char *hash = strchr(line, '#');
+                    if (hash) *hash = 0;
+                    buf = line;
+                }
+
+                tok = strtok_r(buf, " ,", &toksave);
+                buf = NULL;
+                if (tok && sscanf(tok, "%lf", &value) == 1)
+                    break;
+            }
+            while (1);
+
+            x265_log(param, X265_LOG_DEBUG, "lambda%c[%d] = %lf\n", t ? '2' : ' ', i, value);
+            table[i] = value;
+        }
+    }
+
+    fclose(lfn);
 }
+
+}
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/common/param.h
--- a/source/common/param.h	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/common/param.h	Wed Jul 02 17:21:02 2014 -0500
@@ -33,6 +33,7 @@
 int   parseCpuName(const char *value, bool& bError);
 void  setParamAspectRatio(x265_param *p, int width, int height);
 void  getParamAspectRatio(x265_param *p, int& width, int& height);
+void  parseLambdaFile(x265_param *param);
 
 /* this table is kept internal to avoid confusion, since log level indices start at -1 */
 static const char * const logLevelNames[] = { "none", "error", "warning", "info", "debug", "full", 0 };
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/encoder/encoder.cpp
--- a/source/encoder/encoder.cpp	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/encoder/encoder.cpp	Wed Jul 02 17:21:02 2014 -0500
@@ -142,6 +142,8 @@
             }
         }
     }
+
+    parseLambdaFile(m_param);
 }
 
 void Encoder::destroy()
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/x265.cpp
--- a/source/x265.cpp	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/x265.cpp	Wed Jul 02 17:21:02 2014 -0500
@@ -185,6 +185,7 @@
     { "aud",                  no_argument, NULL, 0 },
     { "no-aud",               no_argument, NULL, 0 },
     { "qpfile",         required_argument, NULL, 0 },
+    { "lambda-file",    required_argument, NULL, 0 },
     { "b-intra",              no_argument, NULL, 0 },
     { "no-b-intra",           no_argument, NULL, 0 },
     { "nr",             required_argument, NULL, 0 },
@@ -336,6 +337,10 @@
     H0("                                 Format of each line: framenumber frametype QP\n");
     H0("                                 QP is optional (none lets x265 choose). Frametypes: I,i,P,B,b.\n");
     H0("                                 QPs are restricted by qpmin/qpmax.\n");
+    H0("   --lambda-file <string>        Specify a file containing lambdas to be used by all encoders\n");
+    H0("                                 MAX_MAX_QP+1 floats for lambda table, then again for lambda2 table\n");
+    H0("                                 Blank lines and lines starting with hash(#) are ignored\n");
+    H0("                                 Comma is considered to be white-space\n");
     H0("\nPresets:\n");
     H0("-f/--frames <integer>            Maximum number of frames to encode. Default all\n");
     H0("-p/--preset <string>             Trade off performance for compression efficiency. Default medium\n");
diff -r b90fdc3ffb96 -r 6da77093c4b2 source/x265.h
--- a/source/x265.h	Wed Jul 02 14:31:51 2014 -0500
+++ b/source/x265.h	Wed Jul 02 17:21:02 2014 -0500
@@ -766,6 +766,14 @@
 
         /* temporally blur complexity */
         double    complexityBlur;
+
+        /* 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
+         * MAX_MAX_QP + 1 floating point values for x265_lambda2_tab. All values
+         * are separated by comma, space or newline. Text after a hash (#) is
+         * ignored. The lambda tables are process-global, so these new lambda
+         * values will affect all encoders in the same process */
+        const char* lambdaFileName;
     } rc;
 
     /*== Video Usability Information ==*/


More information about the x265-devel mailing list