]> git.sesse.net Git - x264/commitdiff
Redo the speedcontrol preset list from scratch.
authorSteinar H. Gunderson <sesse@google.com>
Sat, 23 Apr 2016 01:18:14 +0000 (03:18 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 23 Apr 2016 18:32:32 +0000 (20:32 +0200)
This was primarily motivated by the need for both faster and slower presets
than what were in the list, but it also served to move the presets closer
to the current x264 tunings (the old ones were done before significant new
features, such as weighted P-frames). In particular, we no longer disable psy-rd
or motion estimation based on chroma, since neither is changed by any x264 preset
and I could not get them to give me any speed increase at all.

In general, the strategy was to take x264's existing presets, save for
parameters that we cannot change runtime (we never set --subme to 0 because
you cannot get out of it, and cannot modify --mbtree, --rc-lookahead and
--weightp after initial setup), and then build intermediate steps between
them based on what would give the biggest SSIM gain with the least fps drop.
This gives a significantly expanded range; the old one went from roughly
"superfast" to a bit faster than "slow", while the new goes from about 55%
the speed of "ultrafast" (more than twice as fast as the old fastest preset)
all the way to "veryslow" (requiring four times as much CPU as the old
slowest preset, but with a ~0.7 dB SSIM boost in the reference benchmark,
which is quite a bit), about a 30x range. It also gives more evenly spaced
presets than before, although especially in the faster end, it would have
been nice with even more in-between presets (the lack of them is not for
trying; I just couldn't find more useful knobs to tweak in these ranges).

The presets assume the base is "--preset faster --ref 16" (in particular,
that means --weightp 1 --mbtree --rc-lookahead 20); if you change
other options (including starting at "ultrafast", which does things like
--no-deblock which has only modest speed gains but _eats_ quality), you're on
your own. In particular, using "medium" or something else as base would
change --rc-lookahead, which affects both performance and quality
(invalidating the timings), and choosing a lower value for --ref would mean
the slower presets would not be able to use that many reference frames.
x264 does not warn about this, it just silently refuses to apply your
settings.

All benchmarks (both timing and the SSIM values) were run by encoding the first
1000 frames of “Tears of Steel” in 1080p at 2 Mbit/sec, on a quadcore 3.2 GHz
i5 Haswell, which should be more representative of today's machines than the
Sandy Bridge the old timings were done on. I also verified the general trend of
the results on a much more difficult test, namely a 5 Mbit/sec encode of 2000
frames (starting at 48 seconds) of "Metamorf II" at 720p60 (source:
http://zd3n.com/get.php3?get=files/str_metamorf2_hi.mp4). Despite the
addition of faster presets, there are still sections of Metamorf II that I
cannot encode in realtime on the target machine without dropping frames from
the 50-frame queue I'm using.

The benchmark was run using the x264 command-line tool on said machine (so no
hyperthreading) when it was otherwise idle. Input was y4m on tmpfs, output was to
/dev/null. The x264 process was run with realtime priority, frequency scaling
was off, and results varied generally less than 1% between runs (although
there were some exceptions). --no-psy --ssim was used to get SSIM numbers;
--no-psy did not have any impact on measured performance. All tests were run
ten times with frame times (not frame rates) averaged.

common/common.h
encoder/speed.c

index 8e3123ca352f3b7f7055f8d4ecd29559432d5681..858ee5d3167c199fb764409b31df8731d0c6054d 100644 (file)
@@ -111,7 +111,7 @@ do {\
 #define FILLER_OVERHEAD (NALU_OVERHEAD+1)
 #define SEI_OVERHEAD (NALU_OVERHEAD - (h->param.b_annexb && !h->param.i_avcintra_class && (h->out.i_nal-1)))
 
-#define SC_PRESETS 13
+#define SC_PRESETS 26
 /****************************************************************************
  * Includes
  ****************************************************************************/
index df8e2d8a607bbc10cc464a648f17b01cef30421f..c59f2c7f40c7a84ed6e07dbadf4db0d5febe0fc1 100644 (file)
@@ -94,30 +94,105 @@ typedef struct
     int mix;
     int trellis;
     int partitions;
-    int chromame;
-    float psy_rd;
-    float psy_trellis;
+    int badapt;
+    int bframes;
+    int direct;
+    int merange;
 } sc_preset_t;
 
-static const sc_preset_t presets[SC_PRESETS] =
-{
+// The actual presets, including the equivalent commandline options. Note that
+// all presets are benchmarked with --weightp 1 --mbtree --rc-lookahead 20
+// on top of the given settings (equivalent settings to the "faster" preset).
+// Timings and SSIM measurements were done on a quadcore Haswell i5 3.2 GHz
+// on the first 1000 frames of "Tears of Steel" in 1080p.
+static const sc_preset_t presets[SC_PRESETS] = {
 #define I4 X264_ANALYSE_I4x4
 #define I8 X264_ANALYSE_I8x8
+#define P4 X264_ANALYSE_PSUB8x8
 #define P8 X264_ANALYSE_PSUB16x16
 #define B8 X264_ANALYSE_BSUB16x16
-/*0*/    { .time=1.000, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=0, .psy_rd=0 },
-/*1*/    { .time=1.009, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 },
-/*2*/    { .time=1.843, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=0 },
-/*3*/    { .time=1.984, .subme=5, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 },
-/*4*/    { .time=2.289, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=0, .partitions=I8|I4, .psy_rd=1.0 },
-/*5*/    { .time=3.113, .subme=6, .me=X264_ME_HEX, .refs=1, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 },
-/*6*/    { .time=3.400, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 },
-/*7*/    { .time=3.755, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4, .psy_rd=1.0 },
-/*8*/    { .time=4.592, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 },
-/*9*/    { .time=4.730, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 },
-/*10*/   { .time=5.453, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=0, .chromame=0, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 },
-/*11*/   { .time=8.277, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 },
-/*12*/   { .time=8.410, .subme=8, .me=X264_ME_UMH, .refs=4, .mix=1, .chromame=1, .trellis=1, .partitions=I8|I4|P8|B8, .psy_rd=1.0 }
+  // Preset 0: 14.179db, --preset superfast --b-adapt 0 --bframes 0
+  { .time= 1.000, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .trellis=0, .partitions=I8|I4, .badapt=0, .bframes=0, .direct=0, .merange=16 },
+
+  // Preset 1: 14.459db, --preset superfast
+  { .time= 1.283, .subme=1, .me=X264_ME_DIA, .refs=1, .mix=0, .trellis=0, .partitions=I8|I4, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 2: 14.761db, --preset superfast --subme 2
+  { .time= 1.603, .subme=2, .me=X264_ME_DIA, .refs=1, .mix=0, .trellis=0, .partitions=I8|I4, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 3: 15.543db, --preset veryfast
+  { .time= 1.843, .subme=2, .me=X264_ME_HEX, .refs=1, .mix=0, .trellis=0, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 4: 15.716db, --preset veryfast --subme 3
+  { .time= 2.452, .subme=3, .me=X264_ME_HEX, .refs=1, .mix=0, .trellis=0, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 5: 15.786db, --preset veryfast --subme 3 --ref 2
+  { .time= 2.733, .subme=3, .me=X264_ME_HEX, .refs=2, .mix=0, .trellis=0, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 6: 15.813db, --preset veryfast --subme 4 --ref 2
+  { .time= 3.085, .subme=4, .me=X264_ME_HEX, .refs=2, .mix=0, .trellis=0, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 7: 15.849db, --preset faster
+  { .time= 3.101, .subme=4, .me=X264_ME_HEX, .refs=2, .mix=0, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 8: 15.857db, --preset faster --mixed-refs
+  { .time= 3.284, .subme=4, .me=X264_ME_HEX, .refs=2, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 9: 15.869db, --preset faster --mixed-refs --subme 5
+  { .time= 3.587, .subme=5, .me=X264_ME_HEX, .refs=2, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 10: 16.051db, --preset fast
+  { .time= 3.947, .subme=6, .me=X264_ME_HEX, .refs=2, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 11: 16.356db, --preset fast --subme 7
+  { .time= 4.041, .subme=7, .me=X264_ME_HEX, .refs=2, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 12: 16.418db, --preset fast --subme 7 --ref 3
+  { .time= 4.406, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 13: 16.460db, --preset medium
+  { .time= 4.707, .subme=7, .me=X264_ME_HEX, .refs=3, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 14: 16.517db, --preset medium --subme 8
+  { .time= 5.133, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 15: 16.523db, --preset medium --subme 8 --me umh
+  { .time= 6.050, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=1, .merange=16 },
+
+  // Preset 16: 16.543db, --preset medium --subme 8 --me umh --direct auto --b-adapt 2
+  { .time= 6.849, .subme=8, .me=X264_ME_UMH, .refs=3, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 17: 16.613db, --preset slow
+  { .time= 8.042, .subme=8, .me=X264_ME_UMH, .refs=5, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 18: 16.641db, --preset slow --subme 9
+  { .time= 8.972, .subme=9, .me=X264_ME_UMH, .refs=5, .mix=1, .trellis=1, .partitions=I8|I4|P8|B8, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 19: 16.895db, --preset slow --subme 9 --trellis 2
+  { .time=10.073, .subme=9, .me=X264_ME_UMH, .refs=5, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 20: 16.918db, --preset slow --subme 9 --trellis 2 --ref 6
+  { .time=11.147, .subme=9, .me=X264_ME_UMH, .refs=6, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 21: 16.934db, --preset slow --subme 9 --trellis 2 --ref 7
+  { .time=12.267, .subme=9, .me=X264_ME_UMH, .refs=7, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 22: 16.948db, --preset slower
+  { .time=13.829, .subme=9, .me=X264_ME_UMH, .refs=8, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8|P4, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 23: 17.058db, --preset slower --subme 10
+  { .time=14.831, .subme=10, .me=X264_ME_UMH, .refs=8, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8|P4, .badapt=2, .bframes=3, .direct=3, .merange=16 },
+
+  // Preset 24: 17.268db, --preset slower --subme 10 --bframes 8
+  { .time=18.705, .subme=10, .me=X264_ME_UMH, .refs=8, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8|P4, .badapt=2, .bframes=8, .direct=3, .merange=16 },
+
+  // Preset 25: 17.297db, --preset veryslow
+  { .time=31.419, .subme=10, .me=X264_ME_UMH, .refs=16, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8|P4, .badapt=2, .bframes=8, .direct=3, .merange=24 },
+#undef I4
+#undef I8
+#undef P4
+#undef P8
+#undef B8
 };
 
 static void apply_preset( x264_t *h, int preset )
@@ -130,14 +205,15 @@ static void apply_preset( x264_t *h, int preset )
         x264_param_t p = h->param;
 
         p.i_frame_reference = s->refs;
+        p.i_bframe_adaptive = s->badapt;
+        p.i_bframe = s->bframes;
         p.analyse.inter = s->partitions;
         p.analyse.i_subpel_refine = s->subme;
         p.analyse.i_me_method = s->me;
         p.analyse.i_trellis = s->trellis;
         p.analyse.b_mixed_references = s->mix;
-        p.analyse.b_chroma_me = s->chromame;
-        p.analyse.f_psy_rd = s->psy_rd;
-        p.analyse.f_psy_trellis = s->psy_trellis;
+        p.analyse.i_direct_mv_pred = s->direct;
+        p.analyse.i_me_range = s->merange;
         x264_encoder_reconfig( h, &p );
         sc->preset = preset;
         x264_log( h, X264_LOG_DEBUG, "Applying speedcontrol preset %d.\n", preset );
@@ -235,7 +311,7 @@ void x264_speedcontrol_frame( x264_t *h )
         set = i-1 + (target - t0) / (t1 - t0);
         // Even if our time estimations in the SC_PRESETS array are off
         // this will push us towards our target fullness
-        set += (20 * (filled-0.75));
+        set += (40 * (filled-0.75));
         set = x264_clip3f( set, 0 , h->param.sc.max_preset-1 );
         apply_preset( h, dither( sc, set ) );