[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