]> git.sesse.net Git - x264/commitdiff
Switch to exponential interpolation between presets. speedcontrol
authorSteinar H. Gunderson <sesse@google.com>
Thu, 21 Apr 2016 13:58:20 +0000 (15:58 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 23 Apr 2016 18:32:32 +0000 (20:32 +0200)
The preset timings mostly grow in an exponential fashion, not linear,
and as such, interpolation should be exponential, too. More importantly,
this changes extrapolation to be exponential. This fixes an issue where
the chosen preset goes way out of range: If the picture has been at very low
complexity, we would have a very high target (say, 10000 seconds), which
due to linear interpolation would choose a way too high preset (say, preset
5000 out of 25). This would completely drown out the controller responsible
for turning down the preset based on the queue length alone; even though
it would subtract e.g. 20 levels from the chosen preset, still preset 4980
would we be chosen, and effectively, we'd oscillate between the highest
and the lowest presets all the time.

As an extra precaution, we cap the chosen preset to five levels of
extrapolation. This makes us less sensitive to choosing a max_presets where the
last two entries are not that far apart (throwing the extrapolation off).

encoder/speed.c

index c59f2c7f40c7a84ed6e07dbadf4db0d5febe0fc1..4f67640df8d0f71451d14a889dea7e9e939f203a 100644 (file)
@@ -105,6 +105,10 @@ typedef struct
 // 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.
+//
+// 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
+// they are chosen so that the timings are too close to each other.
 static const sc_preset_t presets[SC_PRESETS] = {
 #define I4 X264_ANALYSE_I4x4
 #define I8 X264_ANALYSE_I8x8
@@ -307,8 +311,9 @@ void x264_speedcontrol_frame( x264_t *h )
                 break;
             t0 = t1;
         }
-        // linear interpolation between states
-        set = i-1 + (target - t0) / (t1 - t0);
+        // exponential interpolation between states
+        set = i-1 + (log(target) - log(t0)) / (log(t1) - log(t0));
+        set = x264_clip3f( set, -5, (SC_PRESETS-1) + 5 );
         // Even if our time estimations in the SC_PRESETS array are off
         // this will push us towards our target fullness
         set += (40 * (filled-0.75));