]> git.sesse.net Git - nageru/commitdiff
Rework the x264 speedcontrol presets.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 21 Jul 2017 11:11:36 +0000 (13:11 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Fri, 21 Jul 2017 11:15:05 +0000 (13:15 +0200)
Since speedcontrol was made, x264 has adjusted its “slower” preset,
so follow suit. This influences some of the other presets as well.

Unfortunately, I couldn't reproduce my previous results using
“Tears of Steel”, and the original scripts to do so have been lost;
when testing, the SSIM improves way too slowly. Switch to
“Elephants Dream” instead, even though --trellis 1 seems to yield
a slight SSIM _decrease_ for this clip, and check in the new scripts
to increase reproducibility of results. The measurements are on the
same machine. The timings have shifted around a bit (it looks like
the two fastest modes are faster, relatively speaking); potentially
due to x264 optimizations, but more likely due to differing content
and bitrate flags.

This is measured at the x264 version which is in Debian stretch,
which is r2748 (git 97eaef2).

experiments/measure-x264.pl [new file with mode: 0644]
experiments/presets.txt [new file with mode: 0644]
x264_speed_control.cpp

diff --git a/experiments/measure-x264.pl b/experiments/measure-x264.pl
new file mode 100644 (file)
index 0000000..94f8715
--- /dev/null
@@ -0,0 +1,131 @@
+#! /usr/bin/perl
+
+#
+# A script to measure the quality and speed of the x264 presets used in speed control.
+#
+
+use strict;
+use warnings;
+use Time::HiRes;
+
+my $ssim_mode = 1;
+my $output_cpp = 1;
+my $flags = "--bitrate 4000 --frames 1000";
+my $override_flags = "--weightp 1 --mbtree --rc-lookahead 20";
+my $file = "elephants_dream_1080p24.y4m";  # https://media.xiph.org/video/derf/y4m/elephants_dream_1080p24.y4m
+
+if ($ssim_mode) {
+       # This can be run on a faster machine if you want to. It just measures SSIM;
+       # don't trust the timings, not even which modes are faster than others.
+       # The mode where $output_cpp=0 is just meant as a quick way to test new presets
+       # to see if they are good candidates.
+       $flags .= " --threads 40 --ssim";
+       $override_flags .= " --tune ssim";
+       open my $fh, "<", "presets.txt"
+               or die "presets.txt: $!";
+       my $preset_num = 0;
+       for my $preset (<$fh>) {
+               chomp $preset;
+               my ($ssim, $elapsed) = measure_preset($file, $flags, $override_flags, $preset);
+               if ($output_cpp) {
+                       output_cpp($file, $flags, $override_flags, $preset, $ssim, $preset_num++);
+               } else {
+                       printf "%sdb %.3f %s\n", $ssim, $elapsed, $preset;
+               }
+       }
+       close $fh;
+} else {
+       # Actual benchmarking.
+       my $repeat = 1;
+       $flags .= " --threads 4";
+       open my $fh, "<", "presets.txt"
+               or die "presets.txt: $!";
+       my $base = undef;
+       for my $preset (<$fh>) {
+               chomp $preset;
+               my $sum_elapsed = 0.0;
+               for my $i (1..$repeat) {
+                       my (undef, $elapsed) = measure_preset($file, $flags, $override_flags, $preset);
+                       $sum_elapsed += $elapsed;
+               }
+               my $avg = $sum_elapsed / $repeat;
+               $base //= $avg;
+               printf "%.3f %s\n", $avg / $base, $preset;
+       }
+       close $fh;
+}
+
+sub measure_preset {
+       my ($file, $flags, $override_flags, $preset) = @_;
+
+       my $now = [Time::HiRes::gettimeofday];
+       my $ssim;
+       open my $x264, "-|", "/usr/bin/x264 $flags $preset $override_flags -o /dev/null $file 2>&1";
+       for my $line (<$x264>) {
+               $line =~ /SSIM Mean.*\((\d+\.\d+)db\)/ and $ssim = $1;
+       }
+       close $x264;
+       my $elapsed = Time::HiRes::tv_interval($now);
+       return ($ssim, $elapsed);
+}
+
+sub output_cpp {
+       my ($file, $flags, $override_flags, $preset, $ssim, $preset_num) = @_;
+       unlink("tmp.h264");
+       system("/usr/bin/x264 $flags $preset $override_flags --frames 1 -o tmp.h264 $file >/dev/null 2>&1");
+       open my $fh, "<", "tmp.h264"
+               or die "tmp.h264: $!";
+       my $raw;
+       {
+               local $/ = undef;
+               $raw = <$fh>;
+       }
+       close $fh;
+
+       $raw =~ /subme=(\d+)/ or die;
+       my $subme = $1;
+
+       $raw =~ /me=(\S+)/ or die;
+       my $me = "X264_ME_" . uc($1);
+
+       $raw =~ /ref=(\d+)/ or die;
+       my $refs = $1;
+
+       $raw =~ /mixed_ref=(\d+)/ or die;
+       my $mix = $1;
+
+       $raw =~ /trellis=(\d+)/ or die;
+       my $trellis = $1;
+
+       $raw =~ /analyse=0x[0-9a-f]+:(0x[0-9a-f]+)/ or die;
+       my $partitions_hex = oct($1);
+       my @partitions = ();
+       push @partitions, 'I8' if ($partitions_hex & 0x0002);
+       push @partitions, 'I4' if ($partitions_hex & 0x0001);
+       push @partitions, 'P8' if ($partitions_hex & 0x0010);
+       push @partitions, 'B8' if ($partitions_hex & 0x0100);
+       push @partitions, 'P4' if ($partitions_hex & 0x0020);
+       my $partitions = join('|', @partitions);
+
+       $raw =~ /bframes=(\d+)/ or die;
+       my $bframes = $1;
+
+       my ($badapt, $direct);
+       if ($bframes > 0) {
+               $raw =~ /b_adapt=(\d+)/ or die;
+               $badapt = $1;
+               $raw =~ /direct=(\d+)/ or die;
+               $direct = $1;
+       } else {
+               $badapt = $direct = 0;
+       }
+
+       $raw =~ /me_range=(\d+)/ or die;
+       my $merange = $1;
+
+       print "\n";
+       print "\t// Preset $preset_num: ${ssim}db, $preset\n";
+       print "\t{ .time= 0.000, .subme=$subme, .me=$me, .refs=$refs, .mix=$mix, .trellis=$trellis, .partitions=$partitions, .badapt=$badapt, .bframes=$bframes, .direct=$direct, .merange=$merange },\n";
+
+#x264 - core 148 r2705 3f5ed56 - H.264/MPEG-4 AVC codec - Copyleft 2003-2016 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=34 lookahead_threads=5 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=24 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
+}
diff --git a/experiments/presets.txt b/experiments/presets.txt
new file mode 100644 (file)
index 0000000..91fee58
--- /dev/null
@@ -0,0 +1,25 @@
+--preset superfast --b-adapt 0 --bframes 0
+--preset superfast
+--preset superfast --subme 2
+--preset veryfast
+--preset veryfast --subme 3
+--preset veryfast --subme 3 --ref 2
+--preset veryfast --subme 4 --ref 2
+--preset faster
+--preset faster --mixed-refs
+--preset faster --mixed-refs --subme 5
+--preset fast
+--preset fast --subme 7
+--preset medium
+--preset medium --subme 8
+--preset medium --subme 8 --trellis 2
+--preset medium --subme 8 --trellis 2 --direct auto
+--preset slow
+--preset slow --b-adapt 2 --subme 9
+--preset slow --b-adapt 2 --subme 9 --me umh
+--preset slow --b-adapt 2 --subme 9 --me umh --ref 6
+--preset slow --b-adapt 2 --subme 9 --me umh --ref 7
+--preset slower
+--preset slower --subme 10
+--preset slower --subme 10 --bframes 8
+--preset veryslow
index 08aa9fcd3bf87039664e6b5a82b7fde20d1a6c6c..ca9f52a6003def7f29209aad08a51629b7bb8727 100644 (file)
@@ -16,7 +16,7 @@
 using namespace std;
 using namespace std::chrono;
 
-#define SC_PRESETS 26
+#define SC_PRESETS 25
 
 X264SpeedControl::X264SpeedControl(x264_t *x264, float f_speed, int i_buffer_size, float f_buffer_init)
        : dyn(load_x264_for_bit_depth(global_flags.x264_bit_depth)),
@@ -81,7 +81,8 @@ typedef struct
 // 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.
+// on the first 1000 frames of "Elephants Dream" in 1080p.
+// See experiments/measure-x264.pl for a way to reproduce.
 //
 // Note that the two first and the two last are also used for extrapolation
 // should the desired time be outside the range. Thus, it is disadvantageous if
@@ -92,83 +93,80 @@ static const sc_preset_t presets[SC_PRESETS] = {
 #define P4 X264_ANALYSE_PSUB8x8
 #define P8 X264_ANALYSE_PSUB16x16
 #define B8 X264_ANALYSE_BSUB16x16
-       // Preset 0: 14.179db, --preset superfast --b-adapt 0 --bframes 0
+       // Preset 0: 16.583db, --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 1: 17.386db, --preset superfast
+       { .time= 1.288, .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 2: 17.919db, --preset superfast --subme 2
+       { .time= 2.231, .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 3: 18.051db, --preset veryfast
+       { .time= 2.403, .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 4: 18.422db, --preset veryfast --subme 3
+       { .time= 2.636, .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 5: 18.514db, --preset veryfast --subme 3 --ref 2
+       { .time= 2.844, .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 6: 18.564db, --preset veryfast --subme 4 --ref 2
+       { .time= 3.366, .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 7: 18.411db, --preset faster
+       { .time= 3.450, .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 8: 18.429db, --preset faster --mixed-refs
+       { .time= 3.701, .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 9: 18.454db, --preset faster --mixed-refs --subme 5
+       { .time= 4.297, .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 10: 18.528db, --preset fast
+       { .time= 5.181, .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 11: 18.762db, --preset fast --subme 7
+       { .time= 5.357, .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 12: 18.819db, --preset medium
+       { .time= 6.040, .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 13: 18.889db, --preset medium --subme 8
+       { .time= 7.408, .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 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 14: 19.127db, --preset medium --subme 8 --trellis 2
+       { .time=10.124, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=1, .trellis=2, .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 15: 19.118db, --preset medium --subme 8 --trellis 2 --direct auto
+       { .time=10.144, .subme=8, .me=X264_ME_HEX, .refs=3, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8, .badapt=1, .bframes=3, .direct=3, .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 16: 19.172db, --preset slow
+       { .time=11.142, .subme=8, .me=X264_ME_HEX, .refs=5, .mix=1, .trellis=2, .partitions=I8|I4|P8|B8, .badapt=1, .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 17: 19.309db, --preset slow --b-adapt 2 --subme 9
+       { .time=11.168, .subme=9, .me=X264_ME_HEX, .refs=5, .mix=1, .trellis=2, .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 18: 19.316db, --preset slow --b-adapt 2 --subme 9 --me umh
+       { .time=12.942, .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 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 19: 19.342db, --preset slow --b-adapt 2 --subme 9 --me umh --ref 6
+       { .time=14.302, .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 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 20: 19.365db, --preset slow --b-adapt 2 --subme 9 --me umh --ref 7
+       { .time=15.554, .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 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 21: 19.396db, --preset slower
+       { .time=17.551, .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 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 22: 19.491db, --preset slower --subme 10
+       { .time=21.321, .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 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 23: 19.764db, --preset slower --subme 10 --bframes 8
+       { .time=23.200, .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 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 },
+       // Preset 24: 19.807db, --preset veryslow
+       { .time=36.922, .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