blob: ad6485d5e7807a29ee33a158c5cd3b3d3fa12b06
1 | /* |
2 | * Delay Locked Loop based time filter |
3 | * Copyright (c) 2009 Samalyse |
4 | * Copyright (c) 2009 Michael Niedermayer |
5 | * Author: Olivier Guilyardi <olivier samalyse com> |
6 | * Michael Niedermayer <michaelni gmx at> |
7 | * |
8 | * This file is part of FFmpeg. |
9 | * |
10 | * FFmpeg is free software; you can redistribute it and/or |
11 | * modify it under the terms of the GNU Lesser General Public |
12 | * License as published by the Free Software Foundation; either |
13 | * version 2.1 of the License, or (at your option) any later version. |
14 | * |
15 | * FFmpeg is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 | * Lesser General Public License for more details. |
19 | * |
20 | * You should have received a copy of the GNU Lesser General Public |
21 | * License along with FFmpeg; if not, write to the Free Software |
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
23 | */ |
24 | |
25 | #include "libavutil/common.h" |
26 | #include "libavutil/mem.h" |
27 | |
28 | #include "timefilter.h" |
29 | |
30 | struct TimeFilter { |
31 | // Delay Locked Loop data. These variables refer to mathematical |
32 | // concepts described in: http://www.kokkinizita.net/papers/usingdll.pdf |
33 | double cycle_time; |
34 | double feedback2_factor; |
35 | double feedback3_factor; |
36 | double clock_period; |
37 | int count; |
38 | }; |
39 | |
40 | /* 1 - exp(-x) using a 3-order power series */ |
41 | static double qexpneg(double x) |
42 | { |
43 | return 1 - 1 / (1 + x * (1 + x / 2 * (1 + x / 3))); |
44 | } |
45 | |
46 | TimeFilter *ff_timefilter_new(double time_base, |
47 | double period, |
48 | double bandwidth) |
49 | { |
50 | TimeFilter *self = av_mallocz(sizeof(TimeFilter)); |
51 | double o = 2 * M_PI * bandwidth * period * time_base; |
52 | |
53 | if (!self) |
54 | return NULL; |
55 | |
56 | self->clock_period = time_base; |
57 | self->feedback2_factor = qexpneg(M_SQRT2 * o); |
58 | self->feedback3_factor = qexpneg(o * o) / period; |
59 | return self; |
60 | } |
61 | |
62 | void ff_timefilter_destroy(TimeFilter *self) |
63 | { |
64 | av_freep(&self); |
65 | } |
66 | |
67 | void ff_timefilter_reset(TimeFilter *self) |
68 | { |
69 | self->count = 0; |
70 | } |
71 | |
72 | double ff_timefilter_update(TimeFilter *self, double system_time, double period) |
73 | { |
74 | self->count++; |
75 | if (self->count == 1) { |
76 | self->cycle_time = system_time; |
77 | } else { |
78 | double loop_error; |
79 | self->cycle_time += self->clock_period * period; |
80 | loop_error = system_time - self->cycle_time; |
81 | |
82 | self->cycle_time += FFMAX(self->feedback2_factor, 1.0 / self->count) * loop_error; |
83 | self->clock_period += self->feedback3_factor * loop_error; |
84 | } |
85 | return self->cycle_time; |
86 | } |
87 | |
88 | double ff_timefilter_eval(TimeFilter *self, double delta) |
89 | { |
90 | return self->cycle_time + self->clock_period * delta; |
91 | } |
92 |