Merge commit 'cb45553f577f8e0ebfe05d3287e1b6fa5859b967'
[ffmpeg.git] / libavdevice / timefilter.c
index 8b98d33..ba2e54e 100644 (file)
@@ -5,20 +5,20 @@
  * Author: Olivier Guilyardi <olivier samalyse com>
  *         Michael Niedermayer <michaelni gmx at>
  *
- * This file is part of Libav.
+ * This file is part of FFmpeg.
  *
- * Libav is free software; you can redistribute it and/or
+ * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
- * Libav is distributed in the hope that it will be useful,
+ * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with Libav; if not, write to the Free Software
+ * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
@@ -37,14 +37,21 @@ struct TimeFilter {
     int count;
 };
 
-TimeFilter *ff_timefilter_new(double clock_period,
-                              double feedback2_factor,
-                              double feedback3_factor)
+/* 1 - exp(-x) using a 3-order power series */
+static double qexpneg(double x)
+{
+    return 1 - 1 / (1 + x * (1 + x / 2 * (1 + x / 3)));
+}
+
+TimeFilter *ff_timefilter_new(double time_base,
+                              double period,
+                              double bandwidth)
 {
     TimeFilter *self       = av_mallocz(sizeof(TimeFilter));
-    self->clock_period     = clock_period;
-    self->feedback2_factor = feedback2_factor;
-    self->feedback3_factor = feedback3_factor;
+    double o               = 2 * M_PI * bandwidth * period * time_base;
+    self->clock_period     = time_base;
+    self->feedback2_factor = qexpneg(M_SQRT2 * o);
+    self->feedback3_factor = qexpneg(o * o) / period;
     return self;
 }
 
@@ -69,11 +76,16 @@ double ff_timefilter_update(TimeFilter *self, double system_time, double period)
         loop_error = system_time - self->cycle_time;
 
         self->cycle_time   += FFMAX(self->feedback2_factor, 1.0 / self->count) * loop_error;
-        self->clock_period += self->feedback3_factor * loop_error / period;
+        self->clock_period += self->feedback3_factor * loop_error;
     }
     return self->cycle_time;
 }
 
+double ff_timefilter_eval(TimeFilter *self, double delta)
+{
+    return self->cycle_time + self->clock_period * delta;
+}
+
 #ifdef TEST
 #include "libavutil/lfg.h"
 #define LFG_MAX ((1LL << 32) - 1)
@@ -85,17 +97,21 @@ int main(void)
 #define SAMPLES 1000
     double ideal[SAMPLES];
     double samples[SAMPLES];
+    double samplet[SAMPLES];
     for (n0 = 0; n0 < 40; n0 = 2 * n0 + 1) {
         for (n1 = 0; n1 < 10; n1 = 2 * n1 + 1) {
             double best_error = 1000000000;
             double bestpar0   = 1;
-            double bestpar1   = 0.001;
+            double bestpar1   = 1;
             int better, i;
 
             av_lfg_init(&prng, 123);
             for (i = 0; i < SAMPLES; i++) {
-                ideal[i]   = 10 + i + n1 * i / (1000);
+                samplet[i] = 10 + i + (av_lfg_get(&prng) < LFG_MAX/2 ? 0 : 0.999);
+                ideal[i]   = samplet[i] + n1 * i / (1000);
                 samples[i] = ideal[i] + n0 * (av_lfg_get(&prng) - LFG_MAX / 2) / (LFG_MAX * 10LL);
+                if(i && samples[i]<samples[i-1])
+                    samples[i]=samples[i-1]+0.001;
             }
 
             do {
@@ -107,7 +123,9 @@ int main(void)
                         TimeFilter *tf = ff_timefilter_new(1, par0, par1);
                         for (i = 0; i < SAMPLES; i++) {
                             double filtered;
-                            filtered = ff_timefilter_update(tf, samples[i], 1);
+                            filtered = ff_timefilter_update(tf, samples[i], i ? (samplet[i] - samplet[i-1]) : 1);
+                            if(filtered < 0 || filtered > 1000000000)
+                                printf("filter is unstable\n");
                             error   += (filtered - ideal[i]) * (filtered - ideal[i]);
                         }
                         ff_timefilter_destroy(tf);