[x265] [PATCH] api: allow minimum decoder level to be specified

Steve Borho steve at borho.org
Thu May 22 18:54:25 CEST 2014


# HG changeset patch
# User Steve Borho <steve at borho.org>
# Date 1400147818 -19800
#      Thu May 15 15:26:58 2014 +0530
# Node ID ed0cdcbce1659a0bffcae7a5c9f90006a3ec5bd4
# Parent  73e8188a48cabe3366b14dab97a8da282fb9d02a
api: allow minimum decoder level to be specified

diff -r 73e8188a48ca -r ed0cdcbce165 doc/reST/cli.rst
--- a/doc/reST/cli.rst	Thu May 22 08:51:36 2014 -0500
+++ b/doc/reST/cli.rst	Thu May 15 15:26:58 2014 +0530
@@ -520,6 +520,22 @@
 
 	Use B-frames as references, when possible. Default enabled
 
+.. option:: --level <integer|float>
+
+	Minimum decoder requirement level. Defaults to -1, which implies
+	auto-detection by the encoder. If specified, the encoder will
+	attempt to bring the encode specifications within that specified
+	level. If the encoder is unable to reach the level it issues a
+	warning and emits the actual decoder requirement. If the requested
+	requirement level is higher than the actual level, the actual
+	requirement level is signaled.
+
+	The value is an specified as float or as an integer with the level
+	times 10, for example level **5.1** is specified as "5.1" or "51",
+	and level **5.0** is specified as "5.0" or "50".
+
+	Annex A levels: 1, 2, 2.1, 3, 3.1, 4, 4.1, 5, 5.1, 5.2, 6, 6.1, 6.2
+
 Quality, rate control and rate distortion options
 =================================================
 
diff -r 73e8188a48ca -r ed0cdcbce165 source/common/param.cpp
--- a/source/common/param.cpp	Thu May 22 08:51:36 2014 -0500
+++ b/source/common/param.cpp	Thu May 15 15:26:58 2014 +0530
@@ -107,6 +107,7 @@
     /* Source specifications */
     param->internalBitDepth = x265_max_bit_depth;
     param->internalCsp = X265_CSP_I420;
+    param->levelIdc = -1;
 
     /* CU definitions */
     param->maxCUSize = 64;
@@ -527,6 +528,14 @@
     OPT("csv") p->csvfn = value;
     OPT("threads") p->poolNumThreads = atoi(value);
     OPT("frame-threads") p->frameNumThreads = atoi(value);
+    OPT2("level-idc", "level")
+    {
+        /* allow "5.1" or "51", both converted to integer 51 */
+        if (atof(value) < 7)
+            p->levelIdc = (int)(10*atof(value)+.5);
+        else
+            p->levelIdc = atoi(value);
+    }
     OPT2("log-level", "log")
     {
         p->logLevel = atoi(value);
diff -r 73e8188a48ca -r ed0cdcbce165 source/encoder/api.cpp
--- a/source/encoder/api.cpp	Thu May 22 08:51:36 2014 -0500
+++ b/source/encoder/api.cpp	Thu May 15 15:26:58 2014 +0530
@@ -56,6 +56,7 @@
     {
         // these may change params for auto-detect, etc
         encoder->configure(param);
+        enforceLevel(*param);
         determineLevel(*param, encoder->m_profile, encoder->m_level, encoder->m_levelTier);
 
         x265_print_params(param);
diff -r 73e8188a48ca -r ed0cdcbce165 source/encoder/level.cpp
--- a/source/encoder/level.cpp	Thu May 22 08:51:36 2014 -0500
+++ b/source/encoder/level.cpp	Thu May 15 15:26:58 2014 +0530
@@ -35,25 +35,26 @@
     uint32_t minCompressionRatio;
     Level::Name levelEnum;
     const char* name;
+    int levelIdc;
 } LevelSpec;
 
 LevelSpec levels[] =
 {
-    { MAX_UINT, MAX_UINT,   MAX_UINT, MAX_UINT, 0, Level::NONE,     "none" },
-    { 36864,    552960,     128,      MAX_UINT, 2, Level::LEVEL1,   "1" },
-    { 122880,   3686400,    1500,     MAX_UINT, 2, Level::LEVEL2,   "2" },
-    { 245760,   7372800,    3000,     MAX_UINT, 2, Level::LEVEL2_1, "2.1" },
-    { 552960,   16588800,   6000,     MAX_UINT, 2, Level::LEVEL3,   "3" },
-    { 983040,   33177600,   10000,    MAX_UINT, 2, Level::LEVEL3_1, "3.1" },
-    { 2228224,  66846720,   12000,    30000,    4, Level::LEVEL4,   "4" },
-    { 2228224,  133693440,  20000,    50000,    4, Level::LEVEL4_1, "4.1" },
-    { 8912896,  267386880,  25000,    100000,   6, Level::LEVEL5,   "5" },
-    { 8912896,  534773760,  40000,    160000,   8, Level::LEVEL5_1, "5.1" },
-    { 8912896,  1069547520, 60000,    240000,   8, Level::LEVEL5_2, "5.2" },
-    { 35651584, 1069547520, 60000,    240000,   8, Level::LEVEL6,   "6" },
-    { 35651584, 2139095040, 120000,   480000,   8, Level::LEVEL6_1, "6.1" },
-    { 35651584, 4278190080U, 240000,  800000,   6, Level::LEVEL6_2, "6.2" },
-    { 0, 0, 0, 0, 0, Level::NONE, "\0" }
+    { MAX_UINT, MAX_UINT,   MAX_UINT, MAX_UINT, 0, Level::NONE,     "none", 0 },
+    { 36864,    552960,     128,      MAX_UINT, 2, Level::LEVEL1,   "1",   10 },
+    { 122880,   3686400,    1500,     MAX_UINT, 2, Level::LEVEL2,   "2",   20 },
+    { 245760,   7372800,    3000,     MAX_UINT, 2, Level::LEVEL2_1, "2.1", 21 },
+    { 552960,   16588800,   6000,     MAX_UINT, 2, Level::LEVEL3,   "3",   30 },
+    { 983040,   33177600,   10000,    MAX_UINT, 2, Level::LEVEL3_1, "3.1", 31 },
+    { 2228224,  66846720,   12000,    30000,    4, Level::LEVEL4,   "4",   40 },
+    { 2228224,  133693440,  20000,    50000,    4, Level::LEVEL4_1, "4.1", 41 },
+    { 8912896,  267386880,  25000,    100000,   6, Level::LEVEL5,   "5",   50 },
+    { 8912896,  534773760,  40000,    160000,   8, Level::LEVEL5_1, "5.1", 51 },
+    { 8912896,  1069547520, 60000,    240000,   8, Level::LEVEL5_2, "5.2", 52 },
+    { 35651584, 1069547520, 60000,    240000,   8, Level::LEVEL6,   "6",   60 },
+    { 35651584, 2139095040, 120000,   480000,   8, Level::LEVEL6_1, "6.1", 61 },
+    { 35651584, 4278190080U, 240000,  800000,   6, Level::LEVEL6_2, "6.2", 62 },
+    { 0, 0, 0, 0, 0, Level::NONE, "\0", 0 }
 };
 
 /* determine minimum decoder level requiremented to decode the described video */
@@ -82,7 +83,7 @@
 
     uint32_t lumaSamples = param.sourceWidth * param.sourceHeight;
     uint32_t samplesPerSec = (uint32_t)(lumaSamples * ((double)param.fpsNum / param.fpsDenom));
-    uint32_t bitrate = param.rc.bitrate; /* TODO: vbv-maxrate? */
+    uint32_t bitrate = param.rc.bitrate ? param.rc.bitrate : param.rc.vbvMaxBitrate;
 
     /* TODO; Keep in sync with encoder.cpp, or pass in maxDecPicBuffering */
     int numReorderPics = (param.bBPyramid && param.bframes > 1) ? 2 : 1;
@@ -145,12 +146,26 @@
  * decoder meeting this level of requirement.  Some parameters (resolution and
  * frame rate) are non-negotiable and thus this function may fail. In those
  * circumstances it will be quite noisy */
-void enforceLevel(x265_param& param, int level, bool bHighTier)
+void enforceLevel(x265_param& param)
 {
+    if (param.levelIdc < 0)
+        return;
+
     uint32_t lumaSamples = param.sourceWidth * param.sourceHeight;
     uint32_t samplesPerSec = (uint32_t)(lumaSamples * ((double)param.fpsNum / param.fpsDenom));
+    int level = 1;
+    while (levels[level].levelIdc < param.levelIdc && levels[level].levelIdc)
+        level++;
     LevelSpec& l = levels[level];
 
+    if (!l.levelIdc)
+    {
+        x265_log(&param, X265_LOG_WARNING, "specified level does not exist\n");
+        return;
+    }
+    if (l.levelIdc != param.levelIdc)
+        x265_log(&param, X265_LOG_WARNING, "Using nearest matching level %s\n", l.name);
+
     bool ok = true;
 
     if (lumaSamples > l.maxLumaSamples)
@@ -164,16 +179,11 @@
     else if (samplesPerSec > l.maxLumaSamplesPerSecond)
         x265_log(&param, X265_LOG_WARNING, "frame rate is out of range for specified level\n");
 
-    if (bHighTier && param.rc.bitrate > (int)l.maxBitrateHigh && l.maxBitrateHigh != MAX_UINT)
+    if (param.rc.bitrate > (int)l.maxBitrateHigh && l.maxBitrateHigh != MAX_UINT)
     {
         param.rc.bitrate = l.maxBitrateHigh;
         x265_log(&param, X265_LOG_INFO, "Lowering target bitrate to High tier limit of %dKbps\n", param.rc.bitrate);
     }
-    else if (!bHighTier && param.rc.bitrate > (int)l.maxBitrateMain)
-    {
-        param.rc.bitrate = l.maxBitrateMain;
-        x265_log(&param, X265_LOG_INFO, "Lowering target bitrate to Main tier limit of %dKbps\n", param.rc.bitrate);
-    }
 
     const int MaxDpbPicBuf = 6;
     int maxDpbSize = MaxDpbPicBuf;
@@ -198,7 +208,7 @@
 
     if (param.maxNumReferences != savedRefCount)
     {
-        x265_log(&param, X265_LOG_INFO, "Lowering max references to %d\n", param.maxNumReferences);
+        x265_log(&param, X265_LOG_INFO, "Lowering max references to %d to meet level requirement\n", param.maxNumReferences);
     }
 }
 }
diff -r 73e8188a48ca -r ed0cdcbce165 source/encoder/level.h
--- a/source/encoder/level.h	Thu May 22 08:51:36 2014 -0500
+++ b/source/encoder/level.h	Thu May 15 15:26:58 2014 +0530
@@ -30,7 +30,7 @@
 
 namespace x265 {
 void determineLevel(const x265_param &param, Profile::Name& profile, Level::Name& level, Level::Tier& tier);
-void enforceLevel(x265_param& param, int level, bool bHighTier);
+void enforceLevel(x265_param& param);
 }
 
 #endif // ifndef X265_LEVEL_H
diff -r 73e8188a48ca -r ed0cdcbce165 source/x265.cpp
--- a/source/x265.cpp	Thu May 22 08:51:36 2014 -0500
+++ b/source/x265.cpp	Thu May 15 15:26:58 2014 +0530
@@ -69,6 +69,7 @@
     { "tune",           required_argument, NULL, 't' },
     { "frame-threads",  required_argument, NULL, 'F' },
     { "log-level",      required_argument, NULL, 0 },
+    { "level",          required_argument, NULL, 0 },
     { "csv",            required_argument, NULL, 0 },
     { "y4m",                  no_argument, NULL, 0 },
     { "no-progress",          no_argument, NULL, 0 },
@@ -317,6 +318,7 @@
     H0("   --nr <integer>                An integer value in range of 100 to 1000, which denotes strength of noise reduction. Default disabled\n");
     H0("   --input-res WxH               Source picture size [w x h], auto-detected if Y4M\n");
     H0("   --input-csp <string>          Source color space: i420, i444 or i422, auto-detected if Y4M. Default: i420\n");
+    H0("   --level <integer|float>       Force a minumum required decoder level (as '5.0' or '50')\n");
     H0("   --fps <float|rational>        Source frame rate (float or num/denom), auto-detected if Y4M\n");
     H0("   --[no-]interlace <bff|tff>    Indicate input pictures are interlace fields in temporal order. Default progressive\n");
     H0("   --seek <integer>              First frame to encode\n");
diff -r 73e8188a48ca -r ed0cdcbce165 source/x265.h
--- a/source/x265.h	Thu May 22 08:51:36 2014 -0500
+++ b/source/x265.h	Thu May 15 15:26:58 2014 +0530
@@ -386,6 +386,16 @@
      * minimum requirement. All valid HEVC heights are supported */
     int       sourceHeight;
 
+    /* Minimum decoder requirement level. Defaults to -1, which implies auto-
+     * detection by the encoder. If specified, the encoder will attempt to bring
+     * the encode specifications within that specified level. If the encoder is
+     * unable to reach the level it issues a warning and emits the actual
+     * decoder requirement. If the requested requirement level is higher than
+     * the actual level, the actual requirement level is signaled. The value is
+     * an specified as an integer with the level times 10, for example level
+     * "5.1" is specified as 51, and level "5.0" is specified as 50. */
+    int       levelIdc;
+
     /* Interlace type of source pictures. 0 - progressive pictures (default).
      * 1 - top field first, 2 - bottom field first. HEVC encodes interlaced
      * content as fields, they must be provided to the encoder in the correct


More information about the x265-devel mailing list